Merge "Let InputReader handle its own thread"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 4f7cdf3..3fa5430 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -5,6 +5,7 @@
 # Only turn on clang-format check for the following subfolders.
 clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
                include/input/
+               libs/binder/fuzzer/
                libs/binder/ndk/
                libs/graphicsenv/
                libs/gui/
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 09aee89..be7e3e1 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -66,7 +66,6 @@
     name: "dumpstate_aidl",
     srcs: [
         "binder/android/os/IDumpstateListener.aidl",
-        "binder/android/os/IDumpstateToken.aidl",
         "binder/android/os/IDumpstate.aidl",
     ],
     path: "binder",
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index f98df99..ccd74db 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -58,8 +58,6 @@
     exit(0);
 }
 
-class DumpstateToken : public BnDumpstateToken {};
-
 }  // namespace
 
 DumpstateService::DumpstateService() : ds_(nullptr) {
@@ -81,38 +79,6 @@
     return android::OK;
 }
 
-// Note: this method is part of the old flow and is not expected to be used in combination
-// with startBugreport.
-binder::Status DumpstateService::setListener(const std::string& name,
-                                             const sp<IDumpstateListener>& listener,
-                                             bool getSectionDetails,
-                                             sp<IDumpstateToken>* returned_token) {
-    *returned_token = nullptr;
-    if (name.empty()) {
-        MYLOGE("setListener(): name not set\n");
-        return binder::Status::ok();
-    }
-    if (listener == nullptr) {
-        MYLOGE("setListener(): listener not set\n");
-        return binder::Status::ok();
-    }
-    std::lock_guard<std::mutex> lock(lock_);
-    if (ds_ == nullptr) {
-        ds_ = &(Dumpstate::GetInstance());
-    }
-    if (ds_->listener_ != nullptr) {
-        MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_->listener_name_.c_str());
-        return binder::Status::ok();
-    }
-
-    ds_->listener_name_ = name;
-    ds_->listener_ = listener;
-    ds_->report_section_ = getSectionDetails;
-    *returned_token = new DumpstateToken();
-
-    return binder::Status::ok();
-}
-
 binder::Status DumpstateService::startBugreport(int32_t calling_uid,
                                                 const std::string& calling_package,
                                                 const android::base::unique_fd& bugreport_fd,
@@ -121,8 +87,7 @@
                                                 const sp<IDumpstateListener>& listener) {
     MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
 
-    // This is the bugreporting API flow, so ensure there is only one bugreport in progress at a
-    // time.
+    // Ensure there is only one bugreport in progress at a time.
     std::lock_guard<std::mutex> lock(lock_);
     if (ds_ != nullptr) {
         MYLOGE("Error! There is already a bugreport in progress. Returning.");
@@ -204,19 +169,17 @@
     dprintf(fd, "progress:\n");
     ds_->progress_->Dump(fd, "  ");
     dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
-    dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
+    dprintf(fd, "bugreport_mode: %s\n", ds_->options_->bugreport_mode.c_str());
     dprintf(fd, "version: %s\n", ds_->version_.c_str());
     dprintf(fd, "bugreport_dir: %s\n", destination.c_str());
     dprintf(fd, "screenshot_path: %s\n", ds_->screenshot_path_.c_str());
     dprintf(fd, "log_path: %s\n", ds_->log_path_.c_str());
     dprintf(fd, "tmp_path: %s\n", ds_->tmp_path_.c_str());
     dprintf(fd, "path: %s\n", ds_->path_.c_str());
-    dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
     dprintf(fd, "base_name: %s\n", ds_->base_name_.c_str());
     dprintf(fd, "name: %s\n", ds_->name_.c_str());
     dprintf(fd, "now: %ld\n", ds_->now_);
     dprintf(fd, "is_zipping: %s\n", ds_->IsZipping() ? "true" : "false");
-    dprintf(fd, "listener: %s\n", ds_->listener_name_.c_str());
     dprintf(fd, "notification title: %s\n", ds_->options_->notification_title.c_str());
     dprintf(fd, "notification description: %s\n", ds_->options_->notification_description.c_str());
 
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 68eda47..27954ad 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -24,7 +24,6 @@
 #include <binder/BinderService.h>
 
 #include "android/os/BnDumpstate.h"
-#include "android/os/BnDumpstateToken.h"
 #include "dumpstate.h"
 
 namespace android {
@@ -38,9 +37,6 @@
     static char const* getServiceName();
 
     status_t dump(int fd, const Vector<String16>& args) override;
-    binder::Status setListener(const std::string& name, const sp<IDumpstateListener>& listener,
-                               bool getSectionDetails,
-                               sp<IDumpstateToken>* returned_token) override;
 
     binder::Status startBugreport(int32_t calling_uid, const std::string& calling_package,
                                   const android::base::unique_fd& bugreport_fd,
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index cb2d8b8..3f359c8 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -17,24 +17,12 @@
 package android.os;
 
 import android.os.IDumpstateListener;
-import android.os.IDumpstateToken;
 
 /**
   * Binder interface for the currently running dumpstate process.
   * {@hide}
   */
 interface IDumpstate {
-    // TODO: remove method once startBugReport is used by Shell.
-    /*
-     * Sets the listener for this dumpstate progress.
-     *
-     * Returns a token used to monitor dumpstate death, or `nullptr` if the listener was already
-     * set (the listener behaves like a Highlander: There Can be Only One).
-     * Set {@code getSectionDetails} to true in order to receive callbacks with per section
-     * progress details
-     */
-    IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener,
-                                boolean getSectionDetails);
 
     // NOTE: If you add to or change these modes, please also change the corresponding enums
     // in system server, in BugreportParams.java.
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl b/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
deleted file mode 100644
index 7f74ceb..0000000
--- a/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Copyright (c) 2016, 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.
- */
-
-package android.os;
-
-/**
-  * Token used by the IDumpstateListener to watch for dumpstate death.
-  * {@hide}
-  */
-interface IDumpstateToken {
-}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 0a91a07..5469d0c 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -231,14 +231,6 @@
     return true;
 }
 
-static bool IsFileEmpty(const std::string& file_path) {
-    std::ifstream file(file_path, std::ios::binary | std::ios::ate);
-    if(file.bad()) {
-        MYLOGE("Cannot open file: %s\n", file_path.c_str());
-        return true;
-    }
-    return file.tellg() <= 0;
-}
 
 int64_t GetModuleMetadataVersion() {
     auto binder = defaultServiceManager()->getService(android::String16("package_native"));
@@ -253,7 +245,7 @@
         MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
         return 0L;
     }
-    MYLOGD("Module metadata package name: %s", package_name.c_str());
+    MYLOGD("Module metadata package name: %s\n", package_name.c_str());
     int64_t version_code;
     status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
                                                        &version_code);
@@ -288,11 +280,8 @@
 };
 static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
 
-static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
 static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
 static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
-static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title";
-static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description";
 
 static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
 
@@ -696,8 +685,8 @@
     RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
                    CommandOptions::WithTimeout(1).Always().Build());
     printf("Bugreport format version: %s\n", version_.c_str());
-    printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
-           PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
+    printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s bugreport_mode=%s\n", id_, pid_,
+           PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->bugreport_mode.c_str());
     printf("\n");
 }
 
@@ -876,6 +865,17 @@
         CommandOptions::WithTimeoutInMs(timeout_ms).Build());
 }
 
+static void DoSystemLogcat(time_t since) {
+    char since_str[80];
+    strftime(since_str, sizeof(since_str), "%Y-%m-%d %H:%M:%S.000", localtime(&since));
+
+    unsigned long timeout_ms = logcat_timeout({"main", "system", "crash"});
+    RunCommand("SYSTEM LOG",
+               {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v", "-T",
+                since_str},
+               CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+}
+
 static void DoLogcat() {
     unsigned long timeout_ms;
     // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
@@ -949,6 +949,7 @@
     }
 
     RunCommand("LPDUMP", {"lpdump", "--all"});
+    RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"});
 }
 
 static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
@@ -1071,7 +1072,7 @@
         std::string path(title);
         path.append(" - ").append(String8(service).c_str());
         size_t bytes_written = 0;
-        status_t status = dumpsys.startDumpThread(service, args);
+        status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
         if (status == OK) {
             dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
             std::chrono::duration<double> elapsed_seconds;
@@ -1143,7 +1144,7 @@
             path.append("_HIGH");
         }
         path.append(kProtoExt);
-        status_t status = dumpsys.startDumpThread(service, args);
+        status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
         if (status == OK) {
             status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
             bool dumpTerminated = (status == OK);
@@ -1365,8 +1366,6 @@
         ds.TakeScreenshot();
     }
 
-    DoLogcat();
-
     AddAnrTraceFiles();
 
     // NOTE: tombstones are always added as separate entries in the zip archive
@@ -1523,6 +1522,12 @@
     // keep the system stats as close to its initial state as possible.
     RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
 
+    // Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the
+    // buffer.
+    DoLogcat();
+    // Capture timestamp after first logcat to use in next logcat
+    time_t logcat_ts = time(nullptr);
+
     /* collect stack traces from Dalvik and native processes (needs root) */
     RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
 
@@ -1560,12 +1565,19 @@
         RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
     }
 
+    DumpFile("PSI cpu", "/proc/pressure/cpu");
+    DumpFile("PSI memory", "/proc/pressure/memory");
+    DumpFile("PSI io", "/proc/pressure/io");
+
     if (!DropRootUser()) {
         return Dumpstate::RunStatus::ERROR;
     }
 
     RETURN_IF_USER_DENIED_CONSENT();
-    return dumpstate();
+    Dumpstate::RunStatus status = dumpstate();
+    // Capture logcat since the last time we did it.
+    DoSystemLogcat(logcat_ts);
+    return status;
 }
 
 // This method collects common dumpsys for telephony and wifi
@@ -1883,7 +1895,7 @@
 static void ShowUsage() {
     fprintf(stderr,
             "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
-            "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
+            "[-z]] [-s] [-S] [-q] [-P] [-R] [-V version]\n"
             "  -h: display this help message\n"
             "  -b: play sound file instead of vibrate, at beginning of job\n"
             "  -e: play sound file instead of vibrate, at end of job\n"
@@ -1893,11 +1905,8 @@
             "  -s: write output to control socket (for init)\n"
             "  -S: write file location to control socket (for init; requires -z)\n"
             "  -q: disable vibrate\n"
-            "  -B: send broadcast when finished\n"
-            "  -P: send broadcast when started and update system properties on "
-            "progress (requires -B)\n"
-            "  -R: take bugreport in remote mode (requires -z, -d and -B, "
-            "shouldn't be used with -P)\n"
+            "  -P: send broadcast when started and do progress updates\n"
+            "  -R: take bugreport in remote mode (requires -z and -d, shouldn't be used with -P)\n"
             "  -w: start binder service and make it wait for a call to startBugreport\n"
             "  -v: prints the dumpstate header and exit\n");
 }
@@ -1954,41 +1963,6 @@
     return true;
 }
 
-static std::string SHA256_file_hash(const std::string& filepath) {
-    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
-            | O_CLOEXEC | O_NOFOLLOW)));
-    if (fd == -1) {
-        MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
-        return nullptr;
-    }
-
-    SHA256_CTX ctx;
-    SHA256_Init(&ctx);
-
-    std::vector<uint8_t> buffer(65536);
-    while (1) {
-        ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
-        if (bytes_read == 0) {
-            break;
-        } else if (bytes_read == -1) {
-            MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
-            return nullptr;
-        }
-
-        SHA256_Update(&ctx, buffer.data(), bytes_read);
-    }
-
-    uint8_t hash[SHA256_DIGEST_LENGTH];
-    SHA256_Final(hash, &ctx);
-
-    char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
-    for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
-        sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
-    }
-    hash_buffer[sizeof(hash_buffer) - 1] = 0;
-    return std::string(hash_buffer);
-}
-
 static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
     // clang-format off
     std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
@@ -2081,37 +2055,10 @@
 }
 
 /*
- * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
+ * Finalizes writing to the file by zipping the tmp file to the final location,
  * printing zipped file status, etc.
  */
 static void FinalizeFile() {
-    /* check if user changed the suffix using system properties */
-    std::string name =
-        android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
-    bool change_suffix = false;
-    if (!name.empty()) {
-        /* must whitelist which characters are allowed, otherwise it could cross directories */
-        std::regex valid_regex("^[-_a-zA-Z0-9]+$");
-        if (std::regex_match(name.c_str(), valid_regex)) {
-            change_suffix = true;
-        } else {
-            MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
-        }
-    }
-    if (change_suffix) {
-        MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
-        ds.name_ = name;
-        if (!ds.screenshot_path_.empty()) {
-            std::string new_screenshot_path = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
-            if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
-                MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
-                       new_screenshot_path.c_str(), strerror(errno));
-            } else {
-                ds.screenshot_path_ = new_screenshot_path;
-            }
-        }
-    }
-
     bool do_text_file = true;
     if (ds.options_->do_zip_file) {
         if (!ds.FinishZipFile()) {
@@ -2119,25 +2066,6 @@
             do_text_file = true;
         } else {
             do_text_file = false;
-            // If the user has changed the suffix, we need to change the zip file name.
-            std::string new_path = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
-            if (ds.path_ != new_path) {
-                MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
-                if (rename(ds.path_.c_str(), new_path.c_str())) {
-                    MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
-                           strerror(errno));
-                } else {
-                    ds.path_ = new_path;
-                }
-            }
-        }
-    }
-    if (do_text_file) {
-        ds.path_ = ds.GetPath(".txt");
-        MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
-        if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
-            MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
-            ds.path_.clear();
         }
     }
     if (ds.options_->use_control_socket) {
@@ -2152,49 +2080,6 @@
     }
 }
 
-/* Broadcasts that we are done with the bugreport */
-static void SendBugreportFinishedBroadcast() {
-    // TODO(b/111441001): use callback instead of broadcast.
-    if (!ds.path_.empty()) {
-        MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
-        // clang-format off
-
-        std::vector<std::string> am_args = {
-             "--receiver-permission", "android.permission.DUMP",
-             "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
-             "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
-             "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
-             "--es", "android.intent.extra.BUGREPORT", ds.path_,
-             "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
-        };
-        // clang-format on
-        if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
-            am_args.push_back("--es");
-            am_args.push_back("android.intent.extra.SCREENSHOT");
-            am_args.push_back(ds.screenshot_path_);
-        }
-        if (!ds.options_->notification_title.empty()) {
-            am_args.push_back("--es");
-            am_args.push_back("android.intent.extra.TITLE");
-            am_args.push_back(ds.options_->notification_title);
-            if (!ds.options_->notification_description.empty()) {
-                am_args.push_back("--es");
-                am_args.push_back("android.intent.extra.DESCRIPTION");
-                am_args.push_back(ds.options_->notification_description);
-            }
-        }
-        if (ds.options_->is_remote_mode) {
-            am_args.push_back("--es");
-            am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
-            am_args.push_back(SHA256_file_hash(ds.path_));
-            SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
-        } else {
-            SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
-        }
-    } else {
-        MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
-    }
-}
 
 static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
     switch (mode) {
@@ -2216,10 +2101,9 @@
 }
 
 static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
-    options->extra_options = ModeToString(mode);
+    options->bugreport_mode = ModeToString(mode);
     switch (mode) {
         case Dumpstate::BugreportMode::BUGREPORT_FULL:
-            options->do_broadcast = true;
             options->do_fb = true;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
@@ -2227,88 +2111,32 @@
             options->do_start_service = true;
             options->do_progress_updates = true;
             options->do_fb = false;
-            options->do_broadcast = true;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
             options->do_vibrate = false;
             options->is_remote_mode = true;
             options->do_fb = false;
-            options->do_broadcast = true;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_WEAR:
             options->do_start_service = true;
             options->do_progress_updates = true;
             options->do_zip_file = true;
             options->do_fb = true;
-            options->do_broadcast = true;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
             options->telephony_only = true;
             options->do_fb = false;
-            options->do_broadcast = true;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_WIFI:
             options->wifi_only = true;
             options->do_zip_file = true;
             options->do_fb = false;
-            options->do_broadcast = true;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
             break;
     }
 }
 
-static Dumpstate::BugreportMode getBugreportModeFromProperty() {
-    // If the system property is not set, it's assumed to be a default bugreport.
-    Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
-
-    std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
-    if (!extra_options.empty()) {
-        // Framework uses a system property to override some command-line args.
-        // Currently, it contains the type of the requested bugreport.
-        if (extra_options == "bugreportplus") {
-            mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
-        } else if (extra_options == "bugreportfull") {
-            mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
-        } else if (extra_options == "bugreportremote") {
-            mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
-        } else if (extra_options == "bugreportwear") {
-            mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
-        } else if (extra_options == "bugreporttelephony") {
-            mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
-        } else if (extra_options == "bugreportwifi") {
-            mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
-        } else {
-            MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
-        }
-        // Reset the property
-        android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
-    }
-    return mode;
-}
-
-// TODO: Move away from system properties when we have options passed via binder calls.
-/* Sets runtime options from the system properties and then clears those properties. */
-static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
-    Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
-    SetOptionsFromMode(mode, options);
-
-    options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
-    if (!options->notification_title.empty()) {
-        // Reset the property
-        android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
-
-        options->notification_description =
-            android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
-        if (!options->notification_description.empty()) {
-            // Reset the property
-            android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
-        }
-        MYLOGD("notification (title:  %s, description: %s)\n", options->notification_title.c_str(),
-               options->notification_description.c_str());
-    }
-}
-
 static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
     MYLOGI("do_zip_file: %d\n", options.do_zip_file);
     MYLOGI("do_add_date: %d\n", options.do_add_date);
@@ -2316,7 +2144,6 @@
     MYLOGI("use_socket: %d\n", options.use_socket);
     MYLOGI("use_control_socket: %d\n", options.use_control_socket);
     MYLOGI("do_fb: %d\n", options.do_fb);
-    MYLOGI("do_broadcast: %d\n", options.do_broadcast);
     MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
     MYLOGI("show_header_only: %d\n", options.show_header_only);
     MYLOGI("do_start_service: %d\n", options.do_start_service);
@@ -2324,10 +2151,8 @@
     MYLOGI("wifi_only: %d\n", options.wifi_only);
     MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
     MYLOGI("fd: %d\n", options.bugreport_fd.get());
-    MYLOGI("extra_options: %s\n", options.extra_options.c_str());
+    MYLOGI("bugreport_mode: %s\n", options.bugreport_mode.c_str());
     MYLOGI("args: %s\n", options.args.c_str());
-    MYLOGI("notification_title: %s\n", options.notification_title.c_str());
-    MYLOGI("notification_description: %s\n", options.notification_description.c_str());
 }
 
 void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
@@ -2342,7 +2167,6 @@
     bugreport_fd.reset(dup(bugreport_fd_in.get()));
     screenshot_fd.reset(dup(screenshot_fd_in.get()));
 
-    extra_options = ModeToString(bugreport_mode);
     SetOptionsFromMode(bugreport_mode, this);
 }
 
@@ -2361,7 +2185,6 @@
             case 'p': do_fb = true;                  break;
             case 'P': do_progress_updates = true;    break;
             case 'R': is_remote_mode = true;         break;
-            case 'B': do_broadcast = true;           break;
             case 'V':                                break;  // compatibility no-op
             case 'w':
                 // This was already processed
@@ -2387,7 +2210,6 @@
     // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
     optind = 1;
 
-    SetOptionsFromProperties(this);
     return status;
 }
 
@@ -2396,7 +2218,7 @@
         return false;
     }
 
-    if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
+    if ((do_zip_file || do_add_date || do_progress_updates) && !OutputToFile()) {
         return false;
     }
 
@@ -2404,11 +2226,7 @@
         return false;
     }
 
-    if (do_progress_updates && !do_broadcast) {
-        return false;
-    }
-
-    if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
+    if (is_remote_mode && (do_progress_updates || !do_zip_file || !do_add_date)) {
         return false;
     }
     return true;
@@ -2504,7 +2322,9 @@
         return RunStatus::OK;
     }
 
-    if (options_->bugreport_fd.get() != -1) {
+    MYLOGD("dumpstate calling_uid = %d ; calling package = %s \n",
+            calling_uid, calling_package.c_str());
+    if (CalledByApi()) {
         // If the output needs to be copied over to the caller's fd, get user consent.
         android::String16 package(calling_package.c_str());
         CheckUserConsent(calling_uid, package);
@@ -2549,8 +2369,8 @@
         MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
     }
 
-    MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
-           options_->extra_options.c_str());
+    MYLOGI("dumpstate info: id=%d, args='%s', bugreport_mode= %s)\n", id_, options_->args.c_str(),
+           options_->bugreport_mode.c_str());
 
     MYLOGI("bugreport format version: %s\n", version_.c_str());
 
@@ -2577,18 +2397,13 @@
         PrepareToWriteToFile();
 
         if (options_->do_progress_updates) {
-            if (options_->do_broadcast) {
-                // clang-format off
-                std::vector<std::string> am_args = {
-                     "--receiver-permission", "android.permission.DUMP",
-                     "--es", "android.intent.extra.NAME", name_,
-                     "--ei", "android.intent.extra.ID", std::to_string(id_),
-                     "--ei", "android.intent.extra.PID", std::to_string(pid_),
-                     "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
-                };
-                // clang-format on
-                SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
-            }
+            // clang-format off
+            std::vector<std::string> am_args = {
+                 "--receiver-permission", "android.permission.DUMP",
+            };
+            // clang-format on
+            // Send STARTED broadcast for apps that listen to bugreport generation events
+            SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
             if (options_->use_control_socket) {
                 dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
             }
@@ -2676,15 +2491,15 @@
         TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
     }
 
-    // Rename, and/or zip the (now complete) .tmp file within the internal directory.
+    // Zip the (now complete) .tmp file within the internal directory.
     if (options_->OutputToFile()) {
         FinalizeFile();
     }
 
-    // Share the final file with the caller if the user has consented.
+    // Share the final file with the caller if the user has consented or Shell is the caller.
     Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
-    if (options_->bugreport_fd.get() != -1) {
-        status = CopyBugreportIfUserConsented();
+    if (CalledByApi()) {
+        status = CopyBugreportIfUserConsented(calling_uid);
         if (status != Dumpstate::RunStatus::OK &&
             status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
             // Do an early return if there were errors. We make an exception for consent
@@ -2724,12 +2539,6 @@
         }
     }
 
-    /* tell activity manager we're done */
-    if (options_->do_broadcast && !CalledByApi()) {
-        SendBugreportFinishedBroadcast();
-        // Note that listener_ is notified in Run();
-    }
-
     MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
            progress_->GetInitialMax());
     progress_->Save();
@@ -2754,6 +2563,9 @@
 }
 
 void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
+    if (calling_uid == AID_SHELL) {
+        return;
+    }
     consent_callback_ = new ConsentCallback();
     const String16 incidentcompanion("incidentcompanion");
     sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
@@ -2788,10 +2600,15 @@
     return USER_CONSENT_DENIED;
 }
 
-Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
+Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented(int32_t calling_uid) {
     // If the caller has asked to copy the bugreport over to their directory, we need explicit
-    // user consent.
-    UserConsentResult consent_result = consent_callback_->getResult();
+    // user consent (unless the caller is Shell).
+    UserConsentResult consent_result;
+    if (calling_uid == AID_SHELL) {
+        consent_result = UserConsentResult::APPROVED;
+    } else {
+        consent_result = consent_callback_->getResult();
+    }
     if (consent_result == UserConsentResult::UNAVAILABLE) {
         // User has not responded yet.
         uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
@@ -3654,13 +3471,11 @@
     if (listener_ != nullptr) {
         if (percent % 5 == 0) {
             // We don't want to spam logcat, so only log multiples of 5.
-            MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
-                   percent);
+            MYLOGD("Setting progress: %d/%d (%d%%)\n", progress, max, percent);
         } else {
             // stderr is ignored on normal invocations, but useful when calling
             // /system/bin/dumpstate directly for debuggging.
-            fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
-                    progress, max, percent);
+            fprintf(stderr, "Setting progress: %d/%d (%d%%)\n", progress, max, percent);
         }
 
         listener_->onProgress(percent);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 5ba84ca..831574d 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -359,7 +359,6 @@
         bool use_socket = false;
         bool use_control_socket = false;
         bool do_fb = false;
-        bool do_broadcast = false;
         bool is_remote_mode = false;
         bool show_header_only = false;
         bool do_start_service = false;
@@ -371,16 +370,15 @@
         android::base::unique_fd bugreport_fd;
         // File descriptor to screenshot file.
         android::base::unique_fd screenshot_fd;
-        // TODO: rename to MODE.
-        // Extra options passed as system property.
-        std::string extra_options;
+        // Bugreport mode of the bugreport.
+        std::string bugreport_mode;
         // Command-line arguments as string
         std::string args;
         // Notification title and description
         std::string notification_title;
         std::string notification_description;
 
-        /* Initializes options from commandline arguments and system properties. */
+        /* Initializes options from commandline arguments. */
         RunStatus Initialize(int argc, char* argv[]);
 
         /* Initializes options from the requested mode. */
@@ -456,8 +454,6 @@
 
     // Binder object listening to progress.
     android::sp<android::os::IDumpstateListener> listener_;
-    std::string listener_name_;
-    bool report_section_;
 
     // List of open tombstone dump files.
     std::vector<DumpData> tombstone_data_;
@@ -498,8 +494,9 @@
 
     RunStatus HandleUserConsentDenied();
 
-    // Copies bugreport artifacts over to the caller's directories provided there is user consent.
-    RunStatus CopyBugreportIfUserConsented();
+    // Copies bugreport artifacts over to the caller's directories provided there is user consent or
+    // called by Shell.
+    RunStatus CopyBugreportIfUserConsented(int32_t calling_uid);
 
     // Used by GetInstance() only.
     explicit Dumpstate(const std::string& version = VERSION_CURRENT);
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index dbbcdff..f1884f8 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -195,7 +195,6 @@
     static Dumpstate& ds;
     static std::chrono::milliseconds duration;
     static void SetUpTestCase() {
-        property_set("dumpstate.options", "bugreportplus");
         // clang-format off
         char* argv[] = {
             (char*)"dumpstate",
@@ -206,16 +205,14 @@
         // clang-format on
         sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
         ds.listener_ = listener;
-        ds.listener_name_ = "Smokey";
-        ds.report_section_ = true;
         auto start = std::chrono::steady_clock::now();
         ds.ParseCommandlineAndRun(ARRAY_SIZE(argv), argv);
         auto end = std::chrono::steady_clock::now();
         duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
     }
 
-    static const char* getZipFilePath() {
-        return ds.GetPath(".zip").c_str();
+    static const std::string getZipFilePath() {
+        return ds.GetPath(".zip");
     }
 };
 std::shared_ptr<std::vector<SectionInfo>> ZippedBugreportGenerationTest::sections =
@@ -224,12 +221,12 @@
 std::chrono::milliseconds ZippedBugreportGenerationTest::duration = 0s;
 
 TEST_F(ZippedBugreportGenerationTest, IsGeneratedWithoutErrors) {
-    EXPECT_EQ(access(getZipFilePath(), F_OK), 0);
+    EXPECT_EQ(access(getZipFilePath().c_str(), F_OK), 0);
 }
 
 TEST_F(ZippedBugreportGenerationTest, Is3MBto30MBinSize) {
     struct stat st;
-    EXPECT_EQ(stat(getZipFilePath(), &st), 0);
+    EXPECT_EQ(stat(getZipFilePath().c_str(), &st), 0);
     EXPECT_GE(st.st_size, 3000000 /* 3MB */);
     EXPECT_LE(st.st_size, 30000000 /* 30MB */);
 }
@@ -248,7 +245,7 @@
   public:
     ZipArchiveHandle handle;
     void SetUp() {
-        ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath(), &handle), 0);
+        ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath().c_str(), &handle), 0);
     }
     void TearDown() {
         CloseArchive(handle);
@@ -312,7 +309,7 @@
 class BugreportSectionTest : public Test {
   public:
     static void SetUpTestCase() {
-        ParseSections(ZippedBugreportGenerationTest::getZipFilePath(),
+        ParseSections(ZippedBugreportGenerationTest::getZipFilePath().c_str(),
                       ZippedBugreportGenerationTest::sections.get());
     }
 
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index cff1d43..1ae073c 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -37,6 +37,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <cutils/properties.h>
+#include <android-base/unique_fd.h>
 
 namespace android {
 namespace os {
@@ -148,10 +149,9 @@
         options_ = Dumpstate::DumpOptions();
     }
     void TearDown() {
-        // Reset the property
-        property_set("dumpstate.options", "");
     }
     Dumpstate::DumpOptions options_;
+    android::base::unique_fd fd;
 };
 
 TEST_F(DumpOptionsTest, InitializeNone) {
@@ -174,7 +174,6 @@
     EXPECT_FALSE(options_.do_fb);
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
-    EXPECT_FALSE(options_.do_broadcast);
 }
 
 TEST_F(DumpOptionsTest, InitializeAdbBugreport) {
@@ -200,7 +199,6 @@
     EXPECT_FALSE(options_.do_fb);
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
-    EXPECT_FALSE(options_.do_broadcast);
     EXPECT_FALSE(options_.use_socket);
 }
 
@@ -226,28 +224,13 @@
     EXPECT_FALSE(options_.do_fb);
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
-    EXPECT_FALSE(options_.do_broadcast);
 }
 
 TEST_F(DumpOptionsTest, InitializeFullBugReport) {
-    // clang-format off
-    char* argv[] = {
-        const_cast<char*>("bugreport"),
-        const_cast<char*>("-d"),
-        const_cast<char*>("-p"),
-        const_cast<char*>("-B"),
-        const_cast<char*>("-z"),
-    };
-    // clang-format on
-    property_set("dumpstate.options", "bugreportfull");
-
-    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
-
-    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd);
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_fb);
     EXPECT_TRUE(options_.do_zip_file);
-    EXPECT_TRUE(options_.do_broadcast);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -260,23 +243,8 @@
 }
 
 TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) {
-    // clang-format off
-    char* argv[] = {
-        const_cast<char*>("bugreport"),
-        const_cast<char*>("-d"),
-        const_cast<char*>("-p"),
-        const_cast<char*>("-B"),
-        const_cast<char*>("-z"),
-    };
-    // clang-format on
-
-    property_set("dumpstate.options", "bugreportplus");
-
-    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
-
-    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd);
     EXPECT_TRUE(options_.do_add_date);
-    EXPECT_TRUE(options_.do_broadcast);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.do_progress_updates);
     EXPECT_TRUE(options_.do_start_service);
@@ -291,23 +259,8 @@
 }
 
 TEST_F(DumpOptionsTest, InitializeRemoteBugReport) {
-    // clang-format off
-    char* argv[] = {
-        const_cast<char*>("bugreport"),
-        const_cast<char*>("-d"),
-        const_cast<char*>("-p"),
-        const_cast<char*>("-B"),
-        const_cast<char*>("-z"),
-    };
-    // clang-format on
-
-    property_set("dumpstate.options", "bugreportremote");
-
-    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
-
-    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd);
     EXPECT_TRUE(options_.do_add_date);
-    EXPECT_TRUE(options_.do_broadcast);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.is_remote_mode);
     EXPECT_FALSE(options_.do_vibrate);
@@ -321,24 +274,9 @@
 }
 
 TEST_F(DumpOptionsTest, InitializeWearBugReport) {
-    // clang-format off
-    char* argv[] = {
-        const_cast<char*>("bugreport"),
-        const_cast<char*>("-d"),
-        const_cast<char*>("-p"),
-        const_cast<char*>("-B"),
-        const_cast<char*>("-z"),
-    };
-    // clang-format on
-
-    property_set("dumpstate.options", "bugreportwear");
-
-    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
-
-    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd);
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_fb);
-    EXPECT_TRUE(options_.do_broadcast);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.do_progress_updates);
     EXPECT_TRUE(options_.do_start_service);
@@ -352,24 +290,9 @@
 }
 
 TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) {
-    // clang-format off
-    char* argv[] = {
-        const_cast<char*>("bugreport"),
-        const_cast<char*>("-d"),
-        const_cast<char*>("-p"),
-        const_cast<char*>("-B"),
-        const_cast<char*>("-z"),
-    };
-    // clang-format on
-
-    property_set("dumpstate.options", "bugreporttelephony");
-
-    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
-
-    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd);
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_FALSE(options_.do_fb);
-    EXPECT_TRUE(options_.do_broadcast);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.telephony_only);
 
@@ -383,24 +306,9 @@
 }
 
 TEST_F(DumpOptionsTest, InitializeWifiBugReport) {
-    // clang-format off
-    char* argv[] = {
-        const_cast<char*>("bugreport"),
-        const_cast<char*>("-d"),
-        const_cast<char*>("-p"),
-        const_cast<char*>("-B"),
-        const_cast<char*>("-z"),
-    };
-    // clang-format on
-
-    property_set("dumpstate.options", "bugreportwifi");
-
-    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
-
-    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd);
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_FALSE(options_.do_fb);
-    EXPECT_TRUE(options_.do_broadcast);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.wifi_only);
 
@@ -420,20 +328,15 @@
         const_cast<char*>("bugreport"),
         const_cast<char*>("-d"),
         const_cast<char*>("-p"),
-        const_cast<char*>("-B"),
         const_cast<char*>("-z"),
     };
     // clang-format on
-
-    property_set("dumpstate.options", "");
-
     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
 
     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_fb);
     EXPECT_TRUE(options_.do_zip_file);
-    EXPECT_TRUE(options_.do_broadcast);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -472,7 +375,6 @@
     EXPECT_FALSE(options_.do_fb);
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
-    EXPECT_FALSE(options_.do_broadcast);
 }
 
 TEST_F(DumpOptionsTest, InitializePartial2) {
@@ -484,7 +386,6 @@
         const_cast<char*>("-p"),
         const_cast<char*>("-P"),
         const_cast<char*>("-R"),
-        const_cast<char*>("-B"),
     };
     // clang-format on
 
@@ -496,7 +397,6 @@
     EXPECT_TRUE(options_.do_fb);
     EXPECT_TRUE(options_.do_progress_updates);
     EXPECT_TRUE(options_.is_remote_mode);
-    EXPECT_TRUE(options_.do_broadcast);
 
     // Other options retain default values
     EXPECT_FALSE(options_.do_add_date);
@@ -544,7 +444,7 @@
 }
 
 TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) {
-    options_.do_broadcast = true;
+    options_.do_progress_updates = true;
     // Writing to socket = !writing to file.
     options_.use_socket = true;
     EXPECT_FALSE(options_.ValidateOptions());
@@ -561,19 +461,10 @@
     EXPECT_TRUE(options_.ValidateOptions());
 }
 
-TEST_F(DumpOptionsTest, ValidateOptionsUpdateProgressNeedsBroadcast) {
-    options_.do_progress_updates = true;
-    EXPECT_FALSE(options_.ValidateOptions());
-
-    options_.do_broadcast = true;
-    EXPECT_TRUE(options_.ValidateOptions());
-}
-
 TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) {
     options_.is_remote_mode = true;
     EXPECT_FALSE(options_.ValidateOptions());
 
-    options_.do_broadcast = true;
     options_.do_zip_file = true;
     options_.do_add_date = true;
     EXPECT_TRUE(options_.ValidateOptions());
@@ -616,8 +507,8 @@
         ds.progress_.reset(new Progress(initial_max, progress, 1.2));
     }
 
-    std::string GetProgressMessage(const std::string& listener_name, int progress, int max,
-                                   int old_max = 0, bool update_progress = true) {
+    std::string GetProgressMessage(int progress, int max,
+            int old_max = 0, bool update_progress = true) {
         EXPECT_EQ(progress, ds.progress_->Get()) << "invalid progress";
         EXPECT_EQ(max, ds.progress_->GetMax()) << "invalid max";
 
@@ -630,9 +521,8 @@
         }
 
         if (update_progress) {
-            message += android::base::StringPrintf("Setting progress (%s): %d/%d (%d%%)\n",
-                                                   listener_name.c_str(), progress, max,
-                                                   (100 * progress / max));
+            message += android::base::StringPrintf("Setting progress: %d/%d (%d%%)\n",
+                                                   progress, max, (100 * progress / max));
         }
 
         return message;
@@ -787,18 +677,17 @@
 TEST_F(DumpstateTest, RunCommandProgress) {
     sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
     ds.listener_ = listener;
-    ds.listener_name_ = "FoxMulder";
     SetProgress(0, 30);
 
     EXPECT_CALL(*listener, onProgress(66));  // 20/30 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
-    std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30);
+    std::string progress_message = GetProgressMessage(20, 30);
     EXPECT_THAT(out, StrEq("stdout\n"));
     EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
 
     EXPECT_CALL(*listener, onProgress(80));  // 24/30 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
-    progress_message = GetProgressMessage(ds.listener_name_, 24, 30);
+    progress_message = GetProgressMessage(24, 30);
     EXPECT_THAT(out, StrEq("stdout\n"));
     EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
 
@@ -806,20 +695,20 @@
     SetDryRun(true);
     EXPECT_CALL(*listener, onProgress(90));  // 27/30 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build()));
-    progress_message = GetProgressMessage(ds.listener_name_, 27, 30);
+    progress_message = GetProgressMessage(27, 30);
     EXPECT_THAT(out, IsEmpty());
     EXPECT_THAT(err, StrEq(progress_message));
 
     SetDryRun(false);
     EXPECT_CALL(*listener, onProgress(96));  // 29/30 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(2).Build()));
-    progress_message = GetProgressMessage(ds.listener_name_, 29, 30);
+    progress_message = GetProgressMessage(29, 30);
     EXPECT_THAT(out, StrEq("stdout\n"));
     EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
 
     EXPECT_CALL(*listener, onProgress(100));  // 30/30 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
-    progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
+    progress_message = GetProgressMessage(30, 30);
     EXPECT_THAT(out, StrEq("stdout\n"));
     EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
 
@@ -1044,14 +933,12 @@
 TEST_F(DumpstateTest, DumpFileUpdateProgress) {
     sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
     ds.listener_ = listener;
-    ds.listener_name_ = "FoxMulder";
     SetProgress(0, 30);
 
     EXPECT_CALL(*listener, onProgress(16));  // 5/30 %
     EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
 
-    std::string progress_message =
-        GetProgressMessage(ds.listener_name_, 5, 30);  // TODO: unhardcode WEIGHT_FILE (5)?
+    std::string progress_message = GetProgressMessage(5, 30);  // TODO: unhardcode WEIGHT_FILE (5)?
     EXPECT_THAT(err, StrEq(progress_message));
     EXPECT_THAT(out, StrEq("I AM LINE1\n"));  // dumpstate adds missing newline
 
@@ -1063,48 +950,6 @@
     DumpstateService dss;
 };
 
-TEST_F(DumpstateServiceTest, SetListenerNoName) {
-    sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
-    sp<IDumpstateToken> token;
-    EXPECT_TRUE(dss.setListener("", listener, /* getSectionDetails = */ false, &token).isOk());
-    ASSERT_THAT(token, IsNull());
-}
-
-TEST_F(DumpstateServiceTest, SetListenerNoPointer) {
-    sp<IDumpstateToken> token;
-    EXPECT_TRUE(
-        dss.setListener("whatever", nullptr, /* getSectionDetails = */ false, &token).isOk());
-    ASSERT_THAT(token, IsNull());
-}
-
-TEST_F(DumpstateServiceTest, SetListenerTwice) {
-    sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
-    sp<IDumpstateToken> token;
-    EXPECT_TRUE(
-        dss.setListener("whatever", listener, /* getSectionDetails = */ false, &token).isOk());
-    ASSERT_THAT(token, NotNull());
-    EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
-    EXPECT_FALSE(Dumpstate::GetInstance().report_section_);
-
-    token.clear();
-    EXPECT_TRUE(
-        dss.setListener("whatsoever", listener, /* getSectionDetails = */ false, &token).isOk());
-    ASSERT_THAT(token, IsNull());
-    EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
-    EXPECT_FALSE(Dumpstate::GetInstance().report_section_);
-}
-
-TEST_F(DumpstateServiceTest, SetListenerWithSectionDetails) {
-    sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
-    sp<IDumpstateToken> token;
-    Dumpstate::GetInstance().listener_ = nullptr;
-    EXPECT_TRUE(
-        dss.setListener("whatever", listener, /* getSectionDetails = */ true, &token).isOk());
-    ASSERT_THAT(token, NotNull());
-    EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
-    EXPECT_TRUE(Dumpstate::GetInstance().report_section_);
-}
-
 class ProgressTest : public DumpstateBaseTest {
   public:
     Progress GetInstance(int32_t max, double growth_factor, const std::string& path = "") {
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 9f65425..abdf168 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -59,12 +59,13 @@
             "usage: dumpsys\n"
             "         To dump all services.\n"
             "or:\n"
-            "       dumpsys [-t TIMEOUT] [--priority LEVEL] [--help | -l | --skip SERVICES | "
-            "SERVICE [ARGS]]\n"
+            "       dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--help | -l | --skip SERVICES "
+            "| SERVICE [ARGS]]\n"
             "         --help: shows this help\n"
             "         -l: only list services, do not dump them\n"
             "         -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
             "         -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
+            "         --pid: dump PID instead of usual dump\n"
             "         --proto: filter services that support dumping data in proto format. Dumps\n"
             "               will be in proto format.\n"
             "         --priority LEVEL: filter services based on specified priority\n"
@@ -120,9 +121,11 @@
     bool showListOnly = false;
     bool skipServices = false;
     bool asProto = false;
+    Type type = Type::DUMP;
     int timeoutArgMs = 10000;
     int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
-    static struct option longOptions[] = {{"priority", required_argument, 0, 0},
+    static struct option longOptions[] = {{"pid", no_argument, 0, 0},
+                                          {"priority", required_argument, 0, 0},
                                           {"proto", no_argument, 0, 0},
                                           {"skip", no_argument, 0, 0},
                                           {"help", no_argument, 0, 0},
@@ -157,6 +160,8 @@
                     usage();
                     return -1;
                 }
+            } else if (!strcmp(longOptions[optionIndex].name, "pid")) {
+                type = Type::PID;
             }
             break;
 
@@ -246,7 +251,7 @@
         const String16& serviceName = services[i];
         if (IsSkipped(skippedServices, serviceName)) continue;
 
-        if (startDumpThread(serviceName, args) == OK) {
+        if (startDumpThread(type, serviceName, args) == OK) {
             bool addSeparator = (N > 1);
             if (addSeparator) {
                 writeDumpHeader(STDOUT_FILENO, serviceName, priorityFlags);
@@ -313,7 +318,18 @@
     }
 }
 
-status_t Dumpsys::startDumpThread(const String16& serviceName, const Vector<String16>& args) {
+static status_t dumpPidToFd(const sp<IBinder>& service, const unique_fd& fd) {
+     pid_t pid;
+     status_t status = service->getDebugPid(&pid);
+     if (status != OK) {
+         return status;
+     }
+     WriteStringToFd(std::to_string(pid) + "\n", fd.get());
+     return OK;
+}
+
+status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
+                                  const Vector<String16>& args) {
     sp<IBinder> service = sm_->checkService(serviceName);
     if (service == nullptr) {
         aerr << "Can't find service: " << serviceName << endl;
@@ -333,16 +349,22 @@
 
     // dump blocks until completion, so spawn a thread..
     activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable {
-        int err = service->dump(remote_end.get(), args);
+        status_t err = 0;
 
-        // It'd be nice to be able to close the remote end of the socketpair before the dump
-        // call returns, to terminate our reads if the other end closes their copy of the
-        // file descriptor, but then hangs for some reason. There doesn't seem to be a good
-        // way to do this, though.
-        remote_end.reset();
+        switch (type) {
+        case Type::DUMP:
+            err = service->dump(remote_end.get(), args);
+            break;
+        case Type::PID:
+            err = dumpPidToFd(service, remote_end);
+            break;
+        default:
+            aerr << "Unknown dump type" << static_cast<int>(type) << endl;
+            return;
+        }
 
-        if (err != 0) {
-            aerr << "Error dumping service info: (" << strerror(err) << ") "
+        if (err != OK) {
+            aerr << "Error dumping service info status_t: (" << err << ") "
                  << serviceName << endl;
         }
     });
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index c48a1e9..929c55c 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -51,6 +51,11 @@
      */
     static void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags);
 
+    enum class Type {
+        DUMP,  // dump using `dump` function
+        PID,   // dump pid of server only
+    };
+
     /**
      * Starts a thread to connect to a service and get its dump output. The thread redirects
      * the output to a pipe. Thread must be stopped by a subsequent callto {@code
@@ -61,7 +66,8 @@
      *         {@code NAME_NOT_FOUND} service could not be found.
      *         {@code != OK} error
      */
-    status_t startDumpThread(const String16& serviceName, const Vector<String16>& args);
+    status_t startDumpThread(Type type, const String16& serviceName,
+                             const Vector<String16>& args);
 
     /**
      * Writes a section header to a file descriptor.
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index cbac839..b9395ba 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -54,6 +54,7 @@
     MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int));
     MOCK_METHOD1(listServices, Vector<String16>(int));
     MOCK_METHOD1(waitForService, sp<IBinder>(const String16&));
+    MOCK_METHOD1(isDeclared, bool(const String16&));
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
 };
@@ -194,7 +195,7 @@
         CaptureStdout();
         CaptureStderr();
         dump_.setServiceArgs(args, supportsProto, priorityFlags);
-        status_t status = dump_.startDumpThread(serviceName, args);
+        status_t status = dump_.startDumpThread(Dumpsys::Type::DUMP, serviceName, args);
         EXPECT_THAT(status, Eq(0));
         status = dump_.writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(500), false,
                                  elapsedDuration, bytesWritten);
@@ -539,6 +540,27 @@
     AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH);
 }
 
+// Tests 'dumpsys --pid'
+TEST_F(DumpsysTest, ListAllServicesWithPid) {
+    ExpectListServices({"Locksmith", "Valet"});
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet");
+
+    CallMain({"--pid"});
+
+    AssertRunningServices({"Locksmith", "Valet"});
+    AssertOutputContains(std::to_string(getpid()));
+}
+
+// Tests 'dumpsys --pid service_name'
+TEST_F(DumpsysTest, ListServiceWithPid) {
+    ExpectCheckService("Locksmith");
+
+    CallMain({"--pid", "Locksmith"});
+
+    AssertOutput(std::to_string(getpid()) + "\n");
+}
+
 TEST_F(DumpsysTest, GetBytesWritten) {
     const char* serviceName = "service2";
     const char* dumpContents = "dump1";
@@ -563,4 +585,4 @@
         dump_.writeDump(STDOUT_FILENO, String16("service"), std::chrono::milliseconds(500),
                         /* as_proto = */ false, elapsedDuration, bytesWritten);
     EXPECT_THAT(status, Eq(INVALID_OPERATION));
-}
\ No newline at end of file
+}
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index db09070..5a5cb53 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -67,29 +67,29 @@
 }
 
 static void mkdir(const char* path) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    ::mkdir(fullPath, 0755);
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
+    ::mkdir(fullPath.c_str(), 0755);
 }
 
 static void touch(const char* path, int len, int time) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    int fd = ::open(fullPath, O_RDWR | O_CREAT, 0644);
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
+    int fd = ::open(fullPath.c_str(), O_RDWR | O_CREAT, 0644);
     ::fallocate(fd, 0, 0, len);
     ::close(fd);
     struct utimbuf times;
     times.actime = times.modtime = std::time(0) + time;
-    ::utime(fullPath, &times);
+    ::utime(fullPath.c_str(), &times);
 }
 
 static int exists(const char* path) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    return ::access(fullPath, F_OK);
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
+    return ::access(fullPath.c_str(), F_OK);
 }
 
 static int64_t size(const char* path) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
     struct stat buf;
-    if (!stat(fullPath, &buf)) {
+    if (!stat(fullPath.c_str(), &buf)) {
         return buf.st_size;
     } else {
         return -1;
@@ -107,8 +107,8 @@
 }
 
 static void setxattr(const char* path, const char* key) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    ::setxattr(fullPath, key, "", 0, 0);
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
+    ::setxattr(fullPath.c_str(), key, "", 0, 0);
 }
 
 class CacheTest : public testing::Test {
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp
index 606477f..b7e520f 100644
--- a/cmds/servicemanager/Access.cpp
+++ b/cmds/servicemanager/Access.cpp
@@ -137,7 +137,7 @@
 
 bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) {
     char *tctx = nullptr;
-    if (selabel_lookup(getSehandle(), &tctx, name.c_str(), 0) != 0) {
+    if (selabel_lookup(getSehandle(), &tctx, name.c_str(), SELABEL_CTX_ANDROID_SERVICE) != 0) {
         LOG(ERROR) << "SELinux: No match for " << name << " in service_contexts.\n";
         return false;
     }
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 9344368..91e89ae 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -34,11 +34,7 @@
 namespace android {
 
 #ifndef VENDORSERVICEMANAGER
-static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) {
-    if (!Stability::requiresVintfDeclaration(binder)) {
-        return true;
-    }
-
+static bool isVintfDeclared(const std::string& name) {
     size_t firstSlash = name.find('/');
     size_t lastDot = name.rfind('.', firstSlash);
     if (firstSlash == std::string::npos || lastDot == std::string::npos) {
@@ -62,6 +58,14 @@
                << " in the VINTF manifest.";
     return false;
 }
+
+static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) {
+    if (!Stability::requiresVintfDeclaration(binder)) {
+        return true;
+    }
+
+    return isVintfDeclared(name);
+}
 #endif  // !VENDORSERVICEMANAGER
 
 ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {}
@@ -165,7 +169,7 @@
 #endif  // !VENDORSERVICEMANAGER
 
     // implicitly unlinked when the binder is removed
-    if (OK != binder->linkToDeath(this)) {
+    if (binder->remoteBinder() != nullptr && binder->linkToDeath(this) != OK) {
         LOG(ERROR) << "Could not linkToDeath when adding " << name;
         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
     }
@@ -270,6 +274,21 @@
     return Status::ok();
 }
 
+Status ServiceManager::isDeclared(const std::string& name, bool* outReturn) {
+    auto ctx = mAccess->getCallingContext();
+
+    if (!mAccess->canFind(ctx, name)) {
+        return Status::fromExceptionCode(Status::EX_SECURITY);
+    }
+
+    *outReturn = false;
+
+#ifndef VENDORSERVICEMANAGER
+    *outReturn = isVintfDeclared(name);
+#endif
+    return Status::ok();
+}
+
 void ServiceManager::removeCallback(const wp<IBinder>& who,
                                     CallbackMap::iterator* it,
                                     bool* found) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 006e519..7dcdaa4 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -40,6 +40,7 @@
                                             const sp<IServiceCallback>& callback) override;
     binder::Status unregisterForNotifications(const std::string& name,
                                               const sp<IServiceCallback>& callback) override;
+    binder::Status isDeclared(const std::string& name, bool* outReturn) override;
 
     void binderDied(const wp<IBinder>& who) override;
 
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index 11d43a6..4b12fc6 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -23,11 +23,12 @@
 #include "Access.h"
 #include "ServiceManager.h"
 
-using ::android::sp;
-using ::android::ProcessState;
-using ::android::IPCThreadState;
-using ::android::ServiceManager;
 using ::android::Access;
+using ::android::IPCThreadState;
+using ::android::ProcessState;
+using ::android::ServiceManager;
+using ::android::os::IServiceManager;
+using ::android::sp;
 
 int main(int argc, char** argv) {
     if (argc > 2) {
@@ -41,6 +42,10 @@
     ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
 
     sp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>());
+    if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
+        LOG(ERROR) << "Could not self register servicemanager";
+    }
+
     IPCThreadState::self()->setTheContextObject(manager);
     ps->becomeContextManager(nullptr, nullptr);
 
diff --git a/headers/media_plugin/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h
index c87ee56..8cc9d36 100644
--- a/headers/media_plugin/media/cas/CasAPI.h
+++ b/headers/media_plugin/media/cas/CasAPI.h
@@ -56,6 +56,11 @@
         size_t size,
         const CasSessionId *sessionId);
 
+typedef void (*CasPluginStatusCallback)(
+        void *appData,
+        int32_t event,
+        int32_t arg);
+
 struct CasFactory {
     CasFactory() {}
     virtual ~CasFactory() {}
@@ -91,6 +96,10 @@
     CasPlugin() {}
     virtual ~CasPlugin() {}
 
+    // Provide a callback to report plugin status
+    virtual status_t setStatusCallback(
+            CasPluginStatusCallback callback) = 0;
+
     // Provide the CA private data from a CA_descriptor in the conditional
     // access table to a CasPlugin.
     virtual status_t setPrivateData(
@@ -100,6 +109,11 @@
     // streams.
     virtual status_t openSession(CasSessionId *sessionId) = 0;
 
+    // Open a session with intend and mode for descrambling a program, or one
+    // or more elementary streams.
+    virtual status_t openSession(uint32_t intent, uint32_t mode,
+                                     CasSessionId *sessionId) = 0;
+
     // Close a previously opened session.
     virtual status_t closeSession(const CasSessionId &sessionId) = 0;
 
diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
index 479e9b8..bbb3193 100644
--- a/headers/media_plugin/media/openmax/OMX_IndexExt.h
+++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h
@@ -101,6 +101,7 @@
     OMX_IndexConfigOperatingRate,                   /**< reference: OMX_PARAM_U32TYPE in Q16 format for video and in Hz for audio */
     OMX_IndexParamConsumerUsageBits,                /**< reference: OMX_PARAM_U32TYPE */
     OMX_IndexConfigLatency,                         /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigLowLatency,                      /**< reference: OMX_CONFIG_BOOLEANTYPE */
     OMX_IndexExtOtherEndUnused,
 
     /* Time configurations */
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index 435fcc8..dc37bbd 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -291,18 +291,19 @@
 
 /** Dolby Vision Profile enum type */
 typedef enum OMX_VIDEO_DOLBYVISIONPROFILETYPE {
-    OMX_VIDEO_DolbyVisionProfileUnknown = 0x0,
-    OMX_VIDEO_DolbyVisionProfileDvavPer = 0x1,
-    OMX_VIDEO_DolbyVisionProfileDvavPen = 0x2,
-    OMX_VIDEO_DolbyVisionProfileDvheDer = 0x4,
-    OMX_VIDEO_DolbyVisionProfileDvheDen = 0x8,
-    OMX_VIDEO_DolbyVisionProfileDvheDtr = 0x10,
-    OMX_VIDEO_DolbyVisionProfileDvheStn = 0x20,
-    OMX_VIDEO_DolbyVisionProfileDvheDth = 0x40,
-    OMX_VIDEO_DolbyVisionProfileDvheDtb = 0x80,
-    OMX_VIDEO_DolbyVisionProfileDvheSt  = 0x100,
-    OMX_VIDEO_DolbyVisionProfileDvavSe  = 0x200,
-    OMX_VIDEO_DolbyVisionProfileMax     = 0x7FFFFFFF
+    OMX_VIDEO_DolbyVisionProfileUnknown  = 0x0,
+    OMX_VIDEO_DolbyVisionProfileDvavPer  = 0x1,
+    OMX_VIDEO_DolbyVisionProfileDvavPen  = 0x2,
+    OMX_VIDEO_DolbyVisionProfileDvheDer  = 0x4,
+    OMX_VIDEO_DolbyVisionProfileDvheDen  = 0x8,
+    OMX_VIDEO_DolbyVisionProfileDvheDtr  = 0x10,
+    OMX_VIDEO_DolbyVisionProfileDvheStn  = 0x20,
+    OMX_VIDEO_DolbyVisionProfileDvheDth  = 0x40,
+    OMX_VIDEO_DolbyVisionProfileDvheDtb  = 0x80,
+    OMX_VIDEO_DolbyVisionProfileDvheSt   = 0x100,
+    OMX_VIDEO_DolbyVisionProfileDvavSe   = 0x200,
+    OMX_VIDEO_DolbyVisionProfileDvav110  = 0x400,
+    OMX_VIDEO_DolbyVisionProfileMax      = 0x7FFFFFFF
 } OMX_VIDEO_DOLBYVISIONPROFILETYPE;
 
 /** Dolby Vision Level enum type */
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 1b589bc..0d97e8c 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -59,6 +59,8 @@
 /**
  * Get the AChoreographer instance for the current thread. This must be called
  * on an ALooper thread.
+ *
+ * Available since API level 24.
  */
 AChoreographer* AChoreographer_getInstance() __INTRODUCED_IN(24);
 
@@ -82,6 +84,8 @@
 /**
  * Power a callback to be run on the next frame.  The data pointer provided will
  * be passed to the callback function when it's called.
+ *
+ * Available since API level 29.
  */
 void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
                 AChoreographer_frameCallback64 callback, void* data) __INTRODUCED_IN(29);
@@ -90,6 +94,8 @@
  * Post a callback to be run on the frame following the specified delay.  The
  * data pointer provided will be passed to the callback function when it's
  * called.
+ *
+ * Available since API level 29.
  */
 void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
                 AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) __INTRODUCED_IN(29);
diff --git a/include/android/configuration.h b/include/android/configuration.h
index ef6c5a2..3310722 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -675,50 +675,52 @@
  */
 void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight);
 
-#if __ANDROID_API__ >= 13
 /**
  * Return the current configuration screen width in dp units, or
  * ACONFIGURATION_SCREEN_WIDTH_DP_ANY if not set.
  */
-int32_t AConfiguration_getScreenWidthDp(AConfiguration* config) __INTRODUCED_IN(13);
+int32_t AConfiguration_getScreenWidthDp(AConfiguration* config);
 
 /**
  * Set the configuration's current screen width in dp units.
  */
-void AConfiguration_setScreenWidthDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13);
+void AConfiguration_setScreenWidthDp(AConfiguration* config, int32_t value);
 
 /**
  * Return the current configuration screen height in dp units, or
  * ACONFIGURATION_SCREEN_HEIGHT_DP_ANY if not set.
  */
-int32_t AConfiguration_getScreenHeightDp(AConfiguration* config) __INTRODUCED_IN(13);
+int32_t AConfiguration_getScreenHeightDp(AConfiguration* config);
 
 /**
  * Set the configuration's current screen width in dp units.
  */
-void AConfiguration_setScreenHeightDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13);
+void AConfiguration_setScreenHeightDp(AConfiguration* config, int32_t value);
 
 /**
  * Return the configuration's smallest screen width in dp units, or
  * ACONFIGURATION_SMALLEST_SCREEN_WIDTH_DP_ANY if not set.
  */
-int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config) __INTRODUCED_IN(13);
+int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config);
 
 /**
  * Set the configuration's smallest screen width in dp units.
  */
-void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13);
-#endif /* __ANDROID_API__ >= 13 */
+void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value);
 
 #if __ANDROID_API__ >= 17
 /**
  * Return the configuration's layout direction, or
  * ACONFIGURATION_LAYOUTDIR_ANY if not set.
+ *
+ * Available since API level 17.
  */
 int32_t AConfiguration_getLayoutDirection(AConfiguration* config) __INTRODUCED_IN(17);
 
 /**
  * Set the configuration's layout direction.
+ *
+ * Available since API level 17.
  */
 void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value) __INTRODUCED_IN(17);
 #endif /* __ANDROID_API__ >= 17 */
diff --git a/include/android/font.h b/include/android/font.h
index 8001ee1..1618096 100644
--- a/include/android/font.h
+++ b/include/android/font.h
@@ -96,6 +96,8 @@
 /**
  * Close an AFont.
  *
+ * Available since API level 29.
+ *
  * \param font a font returned by ASystemFontIterator_next or AFontMatchert_match.
  *        Do nothing if NULL is passed.
  */
@@ -116,6 +118,8 @@
  * The font file returned is guaranteed to be opend with O_RDONLY.
  * Note that the returned pointer is valid until AFont_close() is called for the given font.
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \return a string of the font file path.
  */
@@ -184,6 +188,8 @@
  *
  * For more information about font weight, read [OpenType usWeightClass](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass)
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned.
  */
@@ -192,6 +198,8 @@
 /**
  * Return true if the current font is italic, otherwise returns false.
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \return true if italic, otherwise false.
  */
@@ -204,6 +212,8 @@
  *
  * Note that the returned pointer is valid until AFont_close() is called.
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \return a IETF BCP47 compliant language tag or nullptr if not available.
  */
@@ -216,6 +226,8 @@
  * 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.
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \return a font collection index.
  */
@@ -247,6 +259,8 @@
  *
  * For more information about font variation settings, read [Font Variations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/fvar)
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \return a number of font variation settings.
  */
@@ -258,6 +272,8 @@
  *
  * See AFont_getAxisCount for more details.
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \param axisIndex an index to the font variation settings. Passing value larger than or
  *        equal to {@link AFont_getAxisCount} is not allowed.
@@ -271,6 +287,8 @@
  *
  * See AFont_getAxisCount for more details.
  *
+ * Available since API level 29.
+ *
  * \param font a font object. Passing NULL is not allowed.
  * \param axisIndex an index to the font variation settings. Passing value larger than or
  *         equal to {@link ASYstemFont_getAxisCount} is not allwed.
diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h
index 0b8f892..d4bd892 100644
--- a/include/android/font_matcher.h
+++ b/include/android/font_matcher.h
@@ -130,13 +130,17 @@
  */
 
 /**
- * Creates a new AFontMatcher object
+ * Creates a new AFontMatcher object.
+ *
+ * Available since API level 29.
  */
 AFontMatcher* _Nonnull AFontMatcher_create() __INTRODUCED_IN(29);
 
 /**
  * Destroy the matcher object.
  *
+ * Available since API level 29.
+ *
  * \param matcher a matcher object. Passing NULL is not allowed.
  */
 void AFontMatcher_destroy(AFontMatcher* _Nonnull matcher) __INTRODUCED_IN(29);
@@ -147,6 +151,8 @@
  * If this function is not called, the matcher performs with {@link ASYSTEM_FONT_WEIGHT_NORMAL}
  * with non-italic style.
  *
+ * Available since API level 29.
+ *
  * \param matcher a matcher object. Passing NULL is not allowed.
  * \param weight a font weight value. Only from 0 to 1000 value is valid
  * \param italic true if italic, otherwise false.
@@ -161,6 +167,8 @@
  *
  * If this function is not called, the matcher performs with empty locale list.
  *
+ * Available since API level 29.
+ *
  * \param matcher a matcher object. Passing NULL is not allowed.
  * \param languageTags a null character terminated comma separated IETF BCP47 compliant language
  *                     tags.
@@ -174,6 +182,8 @@
  *
  * If this function is not called, the matcher performs with {@link AFAMILY_VARIANT_DEFAULT}.
  *
+ * Available since API level 29.
+ *
  * \param matcher a matcher object. Passing NULL is not allowed.
  * \param familyVariant Must be one of {@link AFAMILY_VARIANT_DEFAULT},
  *                      {@link AFAMILY_VARIANT_COMPACT} or {@link AFAMILY_VARIANT_ELEGANT} is valid.
@@ -190,6 +200,8 @@
  * Even if no font can render the given text, this function will return a non-null result for
  * drawing Tofu character.
  *
+ * Available since API level 29.
+ *
  * \param matcher a matcher object. Passing NULL is not allowed.
  * \param familyName a null character terminated font family name
  * \param text a UTF-16 encoded text buffer to be rendered. Do not pass empty string.
diff --git a/include/android/hardware_buffer_jni.h b/include/android/hardware_buffer_jni.h
index aedf369..293e5ac 100644
--- a/include/android/hardware_buffer_jni.h
+++ b/include/android/hardware_buffer_jni.h
@@ -42,6 +42,8 @@
  * that is returned. To keep the AHardwareBuffer live after the Java
  * HardwareBuffer object got garbage collected, be sure to use AHardwareBuffer_acquire()
  * to acquire an additional reference.
+ *
+ * Available since API level 26.
  */
 AHardwareBuffer* AHardwareBuffer_fromHardwareBuffer(JNIEnv* env,
         jobject hardwareBufferObj) __INTRODUCED_IN(26);
@@ -49,6 +51,8 @@
 /**
  * Return a new Java HardwareBuffer object that wraps the passed native
  * AHardwareBuffer object.
+ *
+ * Available since API level 26.
  */
 jobject AHardwareBuffer_toHardwareBuffer(JNIEnv* env,
         AHardwareBuffer* hardwareBuffer) __INTRODUCED_IN(26);
diff --git a/include/android/input.h b/include/android/input.h
index cfade6c..ce439c6 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -986,10 +986,8 @@
  */
 int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event);
 
-#if __ANDROID_API__ >= 14
 /** Get the button state of all buttons that are pressed. */
-int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event) __INTRODUCED_IN(14);
-#endif
+int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event);
 
 /**
  * Get a bitfield indicating which edges, if any, were touched by this motion event.
@@ -1054,14 +1052,12 @@
  */
 int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index);
 
-#if __ANDROID_API__ >= 14
 /**
  * Get the tool type of a pointer for the given pointer index.
  * The tool type indicates the type of tool used to make contact such as a
  * finger or stylus, if known.
  */
-int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index) __INTRODUCED_IN(14);
-#endif
+int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index);
 
 /**
  * Get the original raw X coordinate of this event.
@@ -1151,11 +1147,9 @@
  */
 float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index);
 
-#if __ANDROID_API__ >= 13
 /** Get the value of the request axis for the given pointer index. */
 float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
-        int32_t axis, size_t pointer_index) __INTRODUCED_IN(13);
-#endif
+        int32_t axis, size_t pointer_index);
 
 /**
  * Get the number of historical points in this event.  These are movements that
@@ -1286,14 +1280,12 @@
 float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index,
         size_t history_index);
 
-#if __ANDROID_API__ >= 13
 /**
  * Get the historical value of the request axis for the given pointer index
  * that occurred between this event and the previous motion event.
  */
 float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event,
-        int32_t axis, size_t pointer_index, size_t history_index) __INTRODUCED_IN(13);
-#endif
+        int32_t axis, size_t pointer_index, size_t history_index);
 
 
 struct AInputQueue;
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index d31d1f1..59b1deb 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -69,6 +69,7 @@
  *
  * This is the equivalent of: [android.net.Network#bindSocket()](https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket))
  *
+ * Available since API level 23.
  */
 int android_setsocknetwork(net_handle_t network, int fd) __INTRODUCED_IN(23);
 
@@ -86,6 +87,7 @@
  *
  * This is the equivalent of: [android.net.ConnectivityManager#setProcessDefaultNetwork()](https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network))
  *
+ * Available since API level 23.
  */
 int android_setprocnetwork(net_handle_t network) __INTRODUCED_IN(23);
 
@@ -103,6 +105,7 @@
  *
  * This is the equivalent of: [android.net.Network#getAllByName()](https://developer.android.com/reference/android/net/Network.html#getAllByName(java.lang.String))
  *
+ * Available since API level 23.
  */
 int android_getaddrinfofornetwork(net_handle_t network,
         const char *node, const char *service,
@@ -144,6 +147,8 @@
  *
  * Returns a file descriptor to watch for read events, or a negative
  * POSIX error code (see errno.h) if an immediate error occurs.
+ *
+ * Available since API level 29.
  */
 int android_res_nquery(net_handle_t network,
         const char *dname, int ns_class, int ns_type, uint32_t flags) __INTRODUCED_IN(29);
@@ -155,6 +160,8 @@
  *
  * Returns a file descriptor to watch for read events, or a negative
  * POSIX error code (see errno.h) if an immediate error occurs.
+ *
+ * Available since API level 29.
  */
 int android_res_nsend(net_handle_t network,
         const uint8_t *msg, size_t msglen, uint32_t flags) __INTRODUCED_IN(29);
@@ -163,6 +170,8 @@
  * Read a result for the query associated with the |fd| descriptor.
  * Closes |fd| before returning.
  *
+ * Available since 29.
+ *
  * Returns:
  *     < 0: negative POSIX error code (see errno.h for possible values). |rcode| is not set.
  *     >= 0: length of |answer|. |rcode| is the resolver return code (e.g., ns_r_nxdomain)
@@ -173,6 +182,8 @@
 /**
  * Attempts to cancel the in-progress query associated with the |nsend_fd|
  * descriptor.
+ *
+ * Available since API level 29.
  */
 void android_res_cancel(int nsend_fd) __INTRODUCED_IN(29);
 
diff --git a/include/android/native_window_jni.h b/include/android/native_window_jni.h
index 0c196b9..3a77ffe 100644
--- a/include/android/native_window_jni.h
+++ b/include/android/native_window_jni.h
@@ -51,6 +51,8 @@
  * the ANativeWindow; maintains it through general Java object's life cycle;
  * and will automatically release the reference when the Java object gets garbage
  * collected.
+ *
+ * Available since API level 26.
  */
 jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window) __INTRODUCED_IN(26);
 #endif
diff --git a/include/android/sensor.h b/include/android/sensor.h
index e9d5c16..3ebe79f 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -564,6 +564,7 @@
  *
  *     ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz");
  *
+ * Available since API level 26.
  */
 ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName) __INTRODUCED_IN(26);
 #endif
@@ -583,6 +584,8 @@
 /**
  * Returns the default sensor with the given type and wakeUp properties or NULL if no sensor
  * of this type and wakeUp properties exists.
+ *
+ * Available since API level 21.
  */
 ASensor const* ASensorManager_getDefaultSensorEx(ASensorManager* manager, int type, bool wakeUp) __INTRODUCED_IN(21);
 #endif
@@ -609,6 +612,8 @@
  * Create a direct channel of {@link ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY} to be used
  * for configuring sensor direct report.
  *
+ * Available since API level 26.
+ *
  * \param manager the {@link ASensorManager} instance obtained from
  *                {@link ASensorManager_getInstanceForPackage}.
  * \param fd      file descriptor representing a shared memory created by
@@ -627,6 +632,8 @@
  * Create a direct channel of {@link ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER} type to be used
  * for configuring sensor direct report.
  *
+ * Available since API level 26.
+ *
  * \param manager the {@link ASensorManager} instance obtained from
  *                {@link ASensorManager_getInstanceForPackage}.
  * \param buffer  {@link AHardwareBuffer} instance created by {@link AHardwareBuffer_allocate}.
@@ -646,6 +653,8 @@
  * The buffer used for creating direct channel does not get destroyed with
  * {@link ASensorManager_destroy} and has to be close or released separately.
  *
+ * Available since API level 26.
+ *
  * \param manager the {@link ASensorManager} instance obtained from
  *                {@link ASensorManager_getInstanceForPackage}.
  * \param channelId channel id (a positive integer) returned from
@@ -678,6 +687,8 @@
  *
  *     ASensorManager_configureDirectReport(manager, sensor, channel_id, ASENSOR_DIRECT_RATE_FAST);
  *
+ * Available since API level 26.
+ *
  * \param manager   the {@link ASensorManager} instance obtained from
  *                  {@link ASensorManager_getInstanceForPackage}.
  * \param sensor    a {@link ASensor} to denote which sensor to be operate. It can be NULL if rate
@@ -780,7 +791,7 @@
  */
 ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count);
 
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 /**
  * Request that {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to be delivered on
  * the given {@link ASensorEventQueue}.
@@ -796,13 +807,15 @@
  * {@link AAdditionalInfoEvent#type}, as new values may be defined in the future
  * and may delivered to the client.
  *
+ * Available since API level 29.
+ *
  * \param queue {@link ASensorEventQueue} to configure
  * \param enable true to request {@link ASENSOR_TYPE_ADDITIONAL_INFO} events,
  *        false to stop receiving events
  * \return 0 on success or a negative error code on failure
  */
-int ASensorEventQueue_requestAdditionalInfoEvents(ASensorEventQueue* queue, bool enable);
-#endif /* __ANDROID_API__ >= __ANDRDOID_API_Q__ */
+int ASensorEventQueue_requestAdditionalInfoEvents(ASensorEventQueue* queue, bool enable) __INTRODUCED_IN(29);
+#endif /* __ANDROID_API__ >= 29 */
 
 /*****************************************************************************/
 
@@ -837,26 +850,36 @@
 /**
  * Returns the maximum size of batches for this sensor. Batches will often be
  * smaller, as the hardware fifo might be used for other sensors.
+ *
+ * Available since API level 21.
  */
 int ASensor_getFifoMaxEventCount(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns the hardware batch fifo size reserved to this sensor.
+ *
+ * Available since API level 21.
  */
 int ASensor_getFifoReservedEventCount(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns this sensor's string type.
+ *
+ * Available since API level 21.
  */
 const char* ASensor_getStringType(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns the reporting mode for this sensor. One of AREPORTING_MODE_* constants.
+ *
+ * Available since API level 21.
  */
 int ASensor_getReportingMode(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns true if this is a wake up sensor, false otherwise.
+ *
+ * Available since API level 21.
  */
 bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21);
 #endif /* __ANDROID_API__ >= 21 */
@@ -865,6 +888,8 @@
 /**
  * Test if sensor supports a certain type of direct channel.
  *
+ * Available since API level 26.
+ *
  * \param sensor  a {@link ASensor} to denote the sensor to be checked.
  * \param channelType  Channel type constant, either
  *                     {@ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY}
@@ -874,7 +899,9 @@
 bool ASensor_isDirectChannelTypeSupported(ASensor const* sensor, int channelType) __INTRODUCED_IN(26);
 
 /**
- * Get the highest direct rate level that a sensor support.
+ * Get the highest direct rate level that a sensor supports.
+ *
+ * Available since API level 26.
  *
  * \param sensor  a {@link ASensor} to denote the sensor to be checked.
  *
@@ -885,7 +912,7 @@
 int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_IN(26);
 #endif /* __ANDROID_API__ >= 26 */
 
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 /**
  * Returns the sensor's handle.
  *
@@ -899,9 +926,11 @@
  * It is important to note that the value returned by {@link ASensor_getHandle} is not the same as
  * the value returned by the Java API {@link android.hardware.Sensor#getId} and no mapping exists
  * between the values.
+ *
+ * Available since API level 29.
  */
-int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(__ANDROID_API_Q__);
-#endif /* __ANDROID_API__ >= ANDROID_API_Q__ */
+int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(29);
+#endif /* __ANDROID_API__ >= 29 */
 
 #ifdef __cplusplus
 };
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index abb8368..31abb66 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -46,7 +46,7 @@
  */
 typedef struct ASurfaceControl ASurfaceControl;
 
-/*
+/**
  * Creates an ASurfaceControl with either ANativeWindow or an ASurfaceControl as its parent.
  * |debug_name| is a debug name associated with this surface. It can be used to
  * identify this surface in the SurfaceFlinger's layer tree. It must not be
@@ -54,10 +54,17 @@
  *
  * The caller takes ownership of the ASurfaceControl returned and must release it
  * using ASurfaceControl_release below.
+ *
+ * Available since API level 29.
  */
 ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* parent, const char* debug_name)
                                                   __INTRODUCED_IN(29);
 
+/**
+ * See ASurfaceControl_createFromWindow.
+ *
+ * Available since API level 29.
+ */
 ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name)
                                         __INTRODUCED_IN(29);
 
@@ -65,6 +72,8 @@
  * Releases the |surface_control| object. After releasing the ASurfaceControl the caller no longer
  * has ownership of the AsurfaceControl. The surface and it's children may remain on display as long
  * as their parent remains on display.
+ *
+ * Available since API level 29.
  */
 void ASurfaceControl_release(ASurfaceControl* surface_control) __INTRODUCED_IN(29);
 
@@ -79,11 +88,15 @@
 /**
  * The caller takes ownership of the transaction and must release it using
  * ASurfaceControl_delete below.
+ *
+ * Available since API level 29.
  */
 ASurfaceTransaction* ASurfaceTransaction_create() __INTRODUCED_IN(29);
 
 /**
  * Destroys the |transaction| object.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_delete(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
 
@@ -93,6 +106,8 @@
  * Note that the transaction is guaranteed to be applied atomically. The
  * transactions which are applied on the same thread are also guaranteed to be
  * applied in order.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_apply(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
 
@@ -116,6 +131,8 @@
  *
  * THREADING
  * The transaction completed callback can be invoked on any thread.
+ *
+ * Available since API level 29.
  */
 typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactionStats* stats)
                                                __INTRODUCED_IN(29);
@@ -123,6 +140,8 @@
 /**
  * Returns the timestamp of when the frame was latched by the framework. Once a frame is
  * latched by the framework, it is presented at the following hardware vsync.
+ *
+ * Available since API level 29.
  */
 int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_transaction_stats)
                                               __INTRODUCED_IN(29);
@@ -131,6 +150,8 @@
  * Returns a sync fence that signals when the transaction has been presented.
  * The recipient of the callback takes ownership of the fence and is responsible for closing
  * it. If a device does not support present fences, a -1 will be returned.
+ *
+ * Available since API level 29.
  */
 int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats)
                                                __INTRODUCED_IN(29);
@@ -141,6 +162,8 @@
  * When the client is done using the array, it must release it by calling
  * ASurfaceTransactionStats_releaseASurfaceControls.
  *
+ * Available since API level 29.
+ *
  * |outASurfaceControlsSize| returns the size of the ASurfaceControls array.
  */
 void ASurfaceTransactionStats_getASurfaceControls(ASurfaceTransactionStats* surface_transaction_stats,
@@ -150,6 +173,8 @@
 /**
  * Releases the array of ASurfaceControls that were returned by
  * ASurfaceTransactionStats_getASurfaceControls.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransactionStats_releaseASurfaceControls(ASurfaceControl** surface_controls)
                                                       __INTRODUCED_IN(29);
@@ -158,6 +183,8 @@
  * Returns the timestamp of when the CURRENT buffer was acquired. A buffer is considered
  * acquired when its acquire_fence_fd has signaled. A buffer cannot be latched or presented until
  * it is acquired. If no acquire_fence_fd was provided, this timestamp will be set to -1.
+ *
+ * Available since API level 29.
  */
 int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surface_transaction_stats,
                                                 ASurfaceControl* surface_control)
@@ -180,6 +207,8 @@
  *
  * The client must ensure that all pending refs on a buffer are released before attempting to reuse
  * this buffer, otherwise synchronization errors may occur.
+ *
+ * Available since API level 29.
  */
 int ASurfaceTransactionStats_getPreviousReleaseFenceFd(
                                                 ASurfaceTransactionStats* surface_transaction_stats,
@@ -190,6 +219,8 @@
  * Sets the callback that will be invoked when the updates from this transaction
  * are presented. For details on the callback semantics and data, see the
  * comments on the ASurfaceTransaction_OnComplete declaration above.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* context,
                                        ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29);
@@ -199,6 +230,8 @@
  * Any children of the* reparented |surface_control| will remain children of the |surface_control|.
  *
  * The |new_parent| can be null. Surface controls with a null parent do not appear on the display.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_reparent(ASurfaceTransaction* transaction,
                                   ASurfaceControl* surface_control, ASurfaceControl* new_parent)
@@ -213,6 +246,8 @@
  * Updates the visibility of |surface_control|. If show is set to
  * ASURFACE_TRANSACTION_VISIBILITY_HIDE, the |surface_control| and all surfaces in its subtree will
  * be hidden.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setVisibility(ASurfaceTransaction* transaction,
                                        ASurfaceControl* surface_control, int8_t visibility)
@@ -224,6 +259,8 @@
  * the same z order is undefined.
  *
  * Z orders may be from MIN_INT32 to MAX_INT32. A layer's default z order index is 0.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setZOrder(ASurfaceTransaction* transaction,
                                    ASurfaceControl* surface_control, int32_t z_order)
@@ -236,6 +273,8 @@
  *
  * The frameworks takes ownership of the |acquire_fence_fd| passed and is responsible
  * for closing it.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction,
                                    ASurfaceControl* surface_control, AHardwareBuffer* buffer,
@@ -246,6 +285,8 @@
  * ASurfaceControl visible in transparent regions of the surface.  Colors |r|, |g|,
  * and |b| must be within the range that is valid for |dataspace|.  |dataspace| and |alpha|
  * will be the dataspace and alpha set for the background color layer.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setColor(ASurfaceTransaction* transaction,
                                   ASurfaceControl* surface_control, float r, float g, float b,
@@ -264,6 +305,8 @@
  * |transform| the transform applied after the source rect is applied to the buffer. This parameter
  * should be set to 0 for no transform. To specify a transfrom use the NATIVE_WINDOW_TRANSFORM_*
  * enum.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction,
                                      ASurfaceControl* surface_control, const ARect& source,
@@ -281,6 +324,8 @@
  * Updates whether the content for the buffer associated with this surface is
  * completely opaque. If true, every pixel of content inside the buffer must be
  * opaque or visual errors can occur.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* transaction,
                                                ASurfaceControl* surface_control,
@@ -290,6 +335,8 @@
 /**
  * Updates the region for the content on this surface updated in this
  * transaction. If unspecified, the complete surface is assumed to be damaged.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* transaction,
                                          ASurfaceControl* surface_control, const ARect rects[],
@@ -304,6 +351,8 @@
  *
  * If an earlier transaction has a desired present time of x, and a later transaction has a desired
  * present time that is before x, the later transaction will not preempt the earlier transaction.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setDesiredPresentTime(ASurfaceTransaction* transaction,
                                                int64_t desiredPresentTime) __INTRODUCED_IN(29);
@@ -312,6 +361,8 @@
  * Sets the alpha for the buffer. It uses a premultiplied blending.
  *
  * The |alpha| must be between 0.0 and 1.0.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* transaction,
                                         ASurfaceControl* surface_control, float alpha)
@@ -321,6 +372,8 @@
  * Sets the data space of the surface_control's buffers.
  *
  * If no data space is set, the surface control defaults to ADATASPACE_SRGB.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* transaction,
                                             ASurfaceControl* surface_control, ADataSpace data_space)
@@ -331,6 +384,8 @@
  *
  * When |metadata| is set to null, the framework does not use any smpte2086 metadata when rendering
  * the surface's buffer.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* transaction,
                                                   ASurfaceControl* surface_control,
@@ -342,6 +397,8 @@
  *
  * When |metadata| is set to null, the framework does not use any cta861.3 metadata when rendering
  * the surface's buffer.
+ *
+ * Available since API level 29.
  */
 void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transaction,
                                                  ASurfaceControl* surface_control,
diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h
index 540d23a..dde7eaa 100644
--- a/include/android/surface_texture.h
+++ b/include/android/surface_texture.h
@@ -65,6 +65,9 @@
  * Release the reference to the native ASurfaceTexture acquired with
  * ASurfaceTexture_fromSurfaceTexture().
  * Failing to do so will result in leaked memory and graphic resources.
+ *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  */
 void ASurfaceTexture_release(ASurfaceTexture* st) __INTRODUCED_IN(28);
@@ -73,6 +76,8 @@
  * Returns a reference to an ANativeWindow (i.e. the Producer) for this SurfaceTexture.
  * This is equivalent to Java's: Surface sur = new Surface(surfaceTexture);
  *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * @return A reference to an ANativeWindow. This reference MUST BE released when no longer needed
  * using ANativeWindow_release(). Failing to do so will result in leaked resources. nullptr is
@@ -90,6 +95,8 @@
  * contexts.  Note, however, that the image contents are only accessible from one OpenGL ES
  * context at a time.
  *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * \param texName The name of the OpenGL ES texture that will be created.  This texture name
  * must be unusued in the OpenGL ES context that is current on the calling thread.
@@ -108,6 +115,8 @@
  * contexts.  Note, however, that the image contents are only accessible from one OpenGL ES
  * context at a time.
  *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * \return 0 on success, negative posix error code otherwise (see <errno.h>)
  */
@@ -118,6 +127,8 @@
  * called while the OpenGL ES context that owns the texture is current on the calling thread.
  * It will implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
  *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * \return 0 on success, negative posix error code otherwise (see <errno.h>)
  */
@@ -135,6 +146,8 @@
  * The matrix is stored in column-major order so that it may be passed directly to OpenGL ES via
  * the glLoadMatrixf or glUniformMatrix4fv functions.
  *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * \param mtx the array into which the 4x4 matrix will be stored.  The array must have exactly
  *     16 elements.
@@ -156,6 +169,8 @@
  * For EGL/Vulkan producers, this timestamp is the desired present time set with the
  * EGL_ANDROID_presentation_time or VK_GOOGLE_display_timing extensions
  *
+ * Available since API level 28.
+ *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  */
 int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) __INTRODUCED_IN(28);
diff --git a/include/android/surface_texture_jni.h b/include/android/surface_texture_jni.h
index b0e1edd..2266d54 100644
--- a/include/android/surface_texture_jni.h
+++ b/include/android/surface_texture_jni.h
@@ -32,6 +32,8 @@
 
 __BEGIN_DECLS
 
+#if __ANDROID_API__ >= 28
+
 /**
  * Get a reference to the native ASurfaceTexture from the corresponding java object.
  *
@@ -40,13 +42,17 @@
  * properly once the Java object gets finalized.
  * However, this will not result in program termination.
  *
+ * Available since API level 28.
+ *
  * \param env JNI environment
  * \param surfacetexture Instance of Java SurfaceTexture object
  * \return native ASurfaceTexture reference or nullptr if the java object is not a SurfaceTexture.
  *         The returned reference MUST BE released when it's no longer needed using
  *         ASurfaceTexture_release().
  */
-ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture);
+ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) __INTRODUCED_IN(28);
+
+#endif
 
 __END_DECLS
 
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
index f0485a1..6fd7d2c 100644
--- a/include/android/system_fonts.h
+++ b/include/android/system_fonts.h
@@ -102,6 +102,8 @@
  *
  * Use ASystemFont_close() to close the iterator.
  *
+ * Available since API level 29.
+ *
  * \return a pointer for a newly allocated iterator, nullptr on failure.
  */
 ASystemFontIterator* _Nullable ASystemFontIterator_open() __INTRODUCED_IN(29);
@@ -109,6 +111,8 @@
 /**
  * Close an opened system font iterator, freeing any related resources.
  *
+ * Available since API level 29.
+ *
  * \param iterator a pointer of an iterator for the system fonts. Do nothing if NULL is passed.
  */
 void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTRODUCED_IN(29);
@@ -116,6 +120,8 @@
 /**
  * Move to the next system font.
  *
+ * Available since API level 29.
+ *
  * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
  * \return a font. If no more font is available, returns nullptr. You need to release the returned
  *         font by ASystemFont_close when it is no longer needed.
diff --git a/include/android/trace.h b/include/android/trace.h
index bb7ff28..d59690a 100644
--- a/include/android/trace.h
+++ b/include/android/trace.h
@@ -74,7 +74,7 @@
 
 #endif /* __ANDROID_API__ >= 23 */
 
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 
 /**
  * Writes a trace message to indicate that a given section of code has
@@ -83,6 +83,8 @@
  * asynchronous events do not need to be nested. The name and cookie used to
  * begin an event must be used to end it.
  *
+ * Available since API level 29.
+ *
  * \param sectionName The method name to appear in the trace.
  * \param cookie Unique identifier for distinguishing simultaneous events
  */
@@ -93,6 +95,8 @@
  * Must be called exactly once for each call to {@link ATrace_beginAsyncSection}
  * using the same name and cookie.
  *
+ * Available since API level 29.
+ *
  * \param methodName The method name to appear in the trace.
  * \param cookie Unique identifier for distinguishing simultaneous events
  */
@@ -101,6 +105,8 @@
 /**
  * Writes trace message to indicate the value of a given counter.
  *
+ * Available since API level 29.
+ *
  * \param counterName The counter name to appear in the trace.
  * \param counterValue The counter value.
  */
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index c056c97..1822e4a 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -60,14 +60,14 @@
  * in StructLayout_test should be made.
  */
 struct InputMessage {
-    enum {
-        TYPE_KEY = 1,
-        TYPE_MOTION = 2,
-        TYPE_FINISHED = 3,
+    enum class Type : uint32_t {
+        KEY,
+        MOTION,
+        FINISHED,
     };
 
     struct Header {
-        uint32_t type;
+        Type type; // 4 bytes
         // We don't need this field in order to align the body below but we
         // leave it here because InputMessage::size() and other functions
         // compute the size of this structure as sizeof(Header) + sizeof(Body).
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
index 2d6292c..09a5f39 100644
--- a/libs/android_runtime_lazy/Android.bp
+++ b/libs/android_runtime_lazy/Android.bp
@@ -52,10 +52,6 @@
         "libutils",
     ],
 
-    required: [
-        "libandroid_runtime",
-    ],
-
     export_include_dirs: [
         "include",
     ],
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 296e3f6..7ee4882 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -71,7 +71,13 @@
     // libbinder does not offer a stable wire protocol.
     // if a second copy of it is installed, then it may break after security
     // or dessert updates. Instead, apex users should use libbinder_ndk.
-    no_apex: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.vndk.current",
+        // TODO(b/139016109) remove these three
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
 
     srcs: [
         "Binder.cpp",
@@ -159,3 +165,16 @@
     ],
     path: "aidl",
 }
+
+aidl_interface {
+    name: "libbinder_aidl_test_stub",
+    local_include_dir: "aidl",
+    srcs: [":libbinder_aidl"],
+    visibility: [":__subpackages__"],
+    vendor_available: true,
+    backend: {
+        java: {
+            enabled: false,
+        },
+    },
+}
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 9da9c13..60f047f 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -115,18 +115,23 @@
 }
 
 int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) {
-    return noteOp(op, uid, callingPackage, String16("noteOp from native code"));
+    return noteOp(op, uid, callingPackage, String16(), String16());
 }
 
 int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage,
-        const String16& message) {
+        const String16& featureId, const String16& message) {
     sp<IAppOpsService> service = getService();
     int32_t mode = service != nullptr
             ? service->noteOperation(op, uid, callingPackage)
             : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 
     if (mode == AppOpsManager::MODE_ALLOWED) {
-        markAppOpNoted(uid, callingPackage, op, message);
+        if (message.size() == 0) {
+            markAppOpNoted(uid, callingPackage, op, featureId,
+                    String16("noteOp from native code"));
+        } else {
+            markAppOpNoted(uid, callingPackage, op, featureId, message);
+        }
     }
 
     return mode;
@@ -134,19 +139,23 @@
 
 int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
         bool startIfModeDefault) {
-    return startOpNoThrow(op, uid, callingPackage, startIfModeDefault,
-            String16("startOpNoThrow from native code"));
+    return startOpNoThrow(op, uid, callingPackage, startIfModeDefault, String16(), String16());
 }
 
 int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
-        bool startIfModeDefault, const String16& message) {
+        bool startIfModeDefault, const String16& featureId, const String16& message) {
     sp<IAppOpsService> service = getService();
     int32_t mode = service != nullptr
             ? service->startOperation(getToken(service), op, uid, callingPackage,
                     startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 
     if (mode == AppOpsManager::MODE_ALLOWED) {
-        markAppOpNoted(uid, callingPackage, op, message);
+        if (message.size() == 0) {
+            markAppOpNoted(uid, callingPackage, op, featureId,
+                    String16("startOp from native code"));
+        } else {
+            markAppOpNoted(uid, callingPackage, op, featureId, message);
+        }
     }
 
     return mode;
@@ -198,7 +207,7 @@
 }
 
 void AppOpsManager::markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
-         const String16& message) {
+         const String16& featureId, const String16& message) {
     // check it the appops needs to be collected and cache result
     if (appOpsToNote[opCode] == 0) {
         if (shouldCollectNotes(opCode)) {
@@ -212,14 +221,16 @@
         return;
     }
 
-    noteAsyncOp(String16(), uid, packageName, opCode, message);
+    noteAsyncOp(String16(), uid, packageName, opCode, featureId, message);
 }
 
 void AppOpsManager::noteAsyncOp(const String16& callingPackageName, int32_t uid,
-         const String16& packageName, int32_t opCode, const String16& message) {
+         const String16& packageName, int32_t opCode, const String16& featureId,
+         const String16& message) {
     sp<IAppOpsService> service = getService();
     if (service != nullptr) {
-        return service->noteAsyncOp(callingPackageName, uid, packageName, opCode, message);
+        return service->noteAsyncOp(callingPackageName, uid, packageName, opCode, featureId,
+                message);
     }
 }
 
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 50c7053..238c9dc 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -214,16 +214,21 @@
 {
     // Once a binder has died, it will never come back to life.
     if (mAlive) {
+        bool privateVendor = flags & FLAG_PRIVATE_VENDOR;
+        // don't send userspace flags to the kernel
+        flags = flags & ~FLAG_PRIVATE_VENDOR;
+
         // user transactions require a given stability level
         if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
             using android::internal::Stability;
 
             auto stability = Stability::get(this);
+            auto required = privateVendor ? Stability::VENDOR : Stability::kLocalStability;
 
-            if (CC_UNLIKELY(!Stability::check(stability, Stability::kLocalStability))) {
+            if (CC_UNLIKELY(!Stability::check(stability, required))) {
                 ALOGE("Cannot do a user transaction on a %s binder in a %s context.",
                     Stability::stabilityString(stability).c_str(),
-                    Stability::stabilityString(Stability::kLocalStability).c_str());
+                    Stability::stabilityString(required).c_str());
                 return BAD_TYPE;
             }
         }
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 6c16c2d..9760e13 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -145,7 +145,8 @@
     }
 
     virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid,
-            const String16& packageName, int32_t opCode, const String16& message) {
+            const String16& packageName, int32_t opCode, const String16& featureId,
+            const String16& message) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
 
@@ -166,6 +167,14 @@
         }
 
         data.writeInt32(opCode);
+
+        // Convert empty featureId into null string
+        if (featureId.size() != 0) {
+            data.writeString16(featureId);
+        } else {
+            data.writeString16(nullptr, 0);
+        }
+
         data.writeString16(message);
         remote()->transact(NOTE_ASYNC_OP_TRANSACTION, data, &reply);
     }
@@ -291,8 +300,9 @@
             int32_t uid = data.readInt32();
             String16 packageName = data.readString16();
             int32_t opCode = data.readInt32();
+            String16 featureId = data.readString16();
             String16 message = data.readString16();
-            noteAsyncOp(callingPackageName, uid, packageName, opCode, message);
+            noteAsyncOp(callingPackageName, uid, packageName, opCode, featureId, message);
             reply->writeNoException();
             return NO_ERROR;
         } break;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index ee637e2..4f47db1 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -43,6 +43,48 @@
 using AidlServiceManager = android::os::IServiceManager;
 using android::binder::Status;
 
+// libbinder's IServiceManager.h can't rely on the values generated by AIDL
+// because many places use its headers via include_dirs (meaning, without
+// declaring the dependency in the build system). So, for now, we can just check
+// the values here.
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_CRITICAL == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_HIGH == IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_NORMAL == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL);
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_DEFAULT == IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_ALL == IServiceManager::DUMP_FLAG_PRIORITY_ALL);
+static_assert(AidlServiceManager::DUMP_FLAG_PROTO == IServiceManager::DUMP_FLAG_PROTO);
+
+const String16& IServiceManager::getInterfaceDescriptor() const {
+    return AidlServiceManager::descriptor;
+}
+IServiceManager::IServiceManager() {}
+IServiceManager::~IServiceManager() {}
+
+// From the old libbinder IServiceManager interface to IServiceManager.
+class ServiceManagerShim : public IServiceManager
+{
+public:
+    explicit ServiceManagerShim (const sp<AidlServiceManager>& impl);
+
+    sp<IBinder> getService(const String16& name) const override;
+    sp<IBinder> checkService(const String16& name) const override;
+    status_t addService(const String16& name, const sp<IBinder>& service,
+                        bool allowIsolated, int dumpsysPriority) override;
+    Vector<String16> listServices(int dumpsysPriority) override;
+    sp<IBinder> waitForService(const String16& name16) override;
+    bool isDeclared(const String16& name) override;
+
+    // for legacy ABI
+    const String16& getInterfaceDescriptor() const override {
+        return mTheRealServiceManager->getInterfaceDescriptor();
+    }
+    IBinder* onAsBinder() override {
+        return IInterface::asBinder(mTheRealServiceManager).get();
+    }
+private:
+    sp<AidlServiceManager> mTheRealServiceManager;
+};
+
 sp<IServiceManager> defaultServiceManager()
 {
     static Mutex gDefaultServiceManagerLock;
@@ -53,8 +95,9 @@
     {
         AutoMutex _l(gDefaultServiceManagerLock);
         while (gDefaultServiceManager == nullptr) {
-            gDefaultServiceManager = interface_cast<IServiceManager>(
-                ProcessState::self()->getContextObject(nullptr));
+            gDefaultServiceManager = new ServiceManagerShim(
+                interface_cast<AidlServiceManager>(
+                    ProcessState::self()->getContextObject(nullptr)));
             if (gDefaultServiceManager == nullptr)
                 sleep(1);
         }
@@ -147,142 +190,144 @@
 
 // ----------------------------------------------------------------------
 
-class BpServiceManager : public BpInterface<IServiceManager>
-{
-public:
-    explicit BpServiceManager(const sp<IBinder>& impl)
-        : BpInterface<IServiceManager>(impl),
-          mTheRealServiceManager(interface_cast<AidlServiceManager>(impl))
-    {
-    }
+ServiceManagerShim::ServiceManagerShim(const sp<AidlServiceManager>& impl)
+ : mTheRealServiceManager(impl)
+{}
 
-    sp<IBinder> getService(const String16& name) const override
-    {
-        static bool gSystemBootCompleted = false;
+sp<IBinder> ServiceManagerShim::getService(const String16& name) const
+{
+    static bool gSystemBootCompleted = false;
+
+    sp<IBinder> svc = checkService(name);
+    if (svc != nullptr) return svc;
+
+    const bool isVendorService =
+        strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
+    const long timeout = uptimeMillis() + 5000;
+    // Vendor code can't access system properties
+    if (!gSystemBootCompleted && !isVendorService) {
+#ifdef __ANDROID__
+        char bootCompleted[PROPERTY_VALUE_MAX];
+        property_get("sys.boot_completed", bootCompleted, "0");
+        gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false;
+#else
+        gSystemBootCompleted = true;
+#endif
+    }
+    // retry interval in millisecond; note that vendor services stay at 100ms
+    const long sleepTime = gSystemBootCompleted ? 1000 : 100;
+
+    int n = 0;
+    while (uptimeMillis() < timeout) {
+        n++;
+        ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
+            ProcessState::self()->getDriverName().c_str());
+        usleep(1000*sleepTime);
 
         sp<IBinder> svc = checkService(name);
         if (svc != nullptr) return svc;
+    }
+    ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
+    return nullptr;
+}
 
-        const bool isVendorService =
-            strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
-        const long timeout = uptimeMillis() + 5000;
-        // Vendor code can't access system properties
-        if (!gSystemBootCompleted && !isVendorService) {
-#ifdef __ANDROID__
-            char bootCompleted[PROPERTY_VALUE_MAX];
-            property_get("sys.boot_completed", bootCompleted, "0");
-            gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false;
-#else
-            gSystemBootCompleted = true;
-#endif
+sp<IBinder> ServiceManagerShim::checkService(const String16& name) const
+{
+    sp<IBinder> ret;
+    if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
+        return nullptr;
+    }
+    return ret;
+}
+
+status_t ServiceManagerShim::addService(const String16& name, const sp<IBinder>& service,
+                                        bool allowIsolated, int dumpsysPriority)
+{
+    Status status = mTheRealServiceManager->addService(
+        String8(name).c_str(), service, allowIsolated, dumpsysPriority);
+    return status.exceptionCode();
+}
+
+Vector<String16> ServiceManagerShim::listServices(int dumpsysPriority)
+{
+    std::vector<std::string> ret;
+    if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) {
+        return {};
+    }
+
+    Vector<String16> res;
+    res.setCapacity(ret.size());
+    for (const std::string& name : ret) {
+        res.push(String16(name.c_str()));
+    }
+    return res;
+}
+
+sp<IBinder> ServiceManagerShim::waitForService(const String16& name16)
+{
+    class Waiter : public android::os::BnServiceCallback {
+        Status onRegistration(const std::string& /*name*/,
+                              const sp<IBinder>& binder) override {
+            std::unique_lock<std::mutex> lock(mMutex);
+            mBinder = binder;
+            lock.unlock();
+            mCv.notify_one();
+            return Status::ok();
         }
-        // retry interval in millisecond; note that vendor services stay at 100ms
-        const long sleepTime = gSystemBootCompleted ? 1000 : 100;
+    public:
+        sp<IBinder> mBinder;
+        std::mutex mMutex;
+        std::condition_variable mCv;
+    };
 
-        int n = 0;
-        while (uptimeMillis() < timeout) {
-            n++;
-            ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
-                ProcessState::self()->getDriverName().c_str());
-            usleep(1000*sleepTime);
+    const std::string name = String8(name16).c_str();
 
-            sp<IBinder> svc = checkService(name);
-            if (svc != nullptr) return svc;
-        }
-        ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
+    sp<IBinder> out;
+    if (!mTheRealServiceManager->getService(name, &out).isOk()) {
+        return nullptr;
+    }
+    if(out != nullptr) return out;
+
+    sp<Waiter> waiter = new Waiter;
+    if (!mTheRealServiceManager->registerForNotifications(
+            name, waiter).isOk()) {
         return nullptr;
     }
 
-    sp<IBinder> checkService(const String16& name) const override {
-        sp<IBinder> ret;
-        if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
-            return nullptr;
-        }
-        return ret;
-    }
-
-    status_t addService(const String16& name, const sp<IBinder>& service,
-                        bool allowIsolated, int dumpsysPriority) override {
-        Status status = mTheRealServiceManager->addService(String8(name).c_str(), service, allowIsolated, dumpsysPriority);
-        return status.exceptionCode();
-    }
-
-    virtual Vector<String16> listServices(int dumpsysPriority) {
-        std::vector<std::string> ret;
-        if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) {
-            return {};
+    while(true) {
+        {
+            std::unique_lock<std::mutex> lock(waiter->mMutex);
+            using std::literals::chrono_literals::operator""s;
+            waiter->mCv.wait_for(lock, 1s, [&] {
+                return waiter->mBinder != nullptr;
+            });
+            if (waiter->mBinder != nullptr) return waiter->mBinder;
         }
 
-        Vector<String16> res;
-        res.setCapacity(ret.size());
-        for (const std::string& name : ret) {
-            res.push(String16(name.c_str()));
-        }
-        return res;
-    }
-
-    sp<IBinder> waitForService(const String16& name16) override {
-        class Waiter : public android::os::BnServiceCallback {
-            Status onRegistration(const std::string& /*name*/,
-                                  const sp<IBinder>& binder) override {
-                std::unique_lock<std::mutex> lock(mMutex);
-                mBinder = binder;
-                lock.unlock();
-                mCv.notify_one();
-                return Status::ok();
-            }
-        public:
-            sp<IBinder> mBinder;
-            std::mutex mMutex;
-            std::condition_variable mCv;
-        };
-
-        const std::string name = String8(name16).c_str();
-
-        sp<IBinder> out;
+        // Handle race condition for lazy services. Here is what can happen:
+        // - the service dies (not processed by init yet).
+        // - sm processes death notification.
+        // - sm gets getService and calls init to start service.
+        // - init gets the start signal, but the service already appears
+        //   started, so it does nothing.
+        // - init gets death signal, but doesn't know it needs to restart
+        //   the service
+        // - we need to request service again to get it to start
         if (!mTheRealServiceManager->getService(name, &out).isOk()) {
             return nullptr;
         }
         if(out != nullptr) return out;
 
-        sp<Waiter> waiter = new Waiter;
-        if (!mTheRealServiceManager->registerForNotifications(
-                name, waiter).isOk()) {
-            return nullptr;
-        }
-
-        while(true) {
-            {
-                std::unique_lock<std::mutex> lock(waiter->mMutex);
-                using std::literals::chrono_literals::operator""s;
-                waiter->mCv.wait_for(lock, 1s, [&] {
-                    return waiter->mBinder != nullptr;
-                });
-                if (waiter->mBinder != nullptr) return waiter->mBinder;
-            }
-
-            // Handle race condition for lazy services. Here is what can happen:
-            // - the service dies (not processed by init yet).
-            // - sm processes death notification.
-            // - sm gets getService and calls init to start service.
-            // - init gets the start signal, but the service already appears
-            //   started, so it does nothing.
-            // - init gets death signal, but doesn't know it needs to restart
-            //   the service
-            // - we need to request service again to get it to start
-            if (!mTheRealServiceManager->getService(name, &out).isOk()) {
-                return nullptr;
-            }
-            if(out != nullptr) return out;
-
-            ALOGW("Waited one second for %s", name.c_str());
-        }
+        ALOGW("Waited one second for %s", name.c_str());
     }
+}
 
-private:
-    sp<AidlServiceManager> mTheRealServiceManager;
-};
-
-IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
+bool ServiceManagerShim::isDeclared(const String16& name) {
+    bool declared;
+    if (!mTheRealServiceManager->isDeclared(String8(name).c_str(), &declared).isOk()) {
+        return false;
+    }
+    return declared;
+}
 
 } // namespace android
diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp
index 038e6bf..b21af96 100644
--- a/libs/binder/IUidObserver.cpp
+++ b/libs/binder/IUidObserver.cpp
@@ -56,13 +56,15 @@
         remote()->transact(ON_UID_IDLE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
-    virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq)
+    virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
+            int32_t capability)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
         data.writeInt32((int32_t) uid);
         data.writeInt32(procState);
         data.writeInt64(procStateSeq);
+        data.writeInt32(capability);
         remote()->transact(ON_UID_STATE_CHANGED_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
     }
 };
@@ -104,7 +106,8 @@
             uid_t uid = data.readInt32();
             int32_t procState = data.readInt32();
             int64_t procStateSeq = data.readInt64();
-            onUidStateChanged(uid, procState, procStateSeq);
+            int32_t capability = data.readInt32();
+            onUidStateChanged(uid, procState, procStateSeq, capability);
             return NO_ERROR;
         } break;
         default:
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 573a038..7219b47 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -50,10 +50,6 @@
 #include <private/binder/binder_module.h>
 #include "Static.h"
 
-#ifndef INT32_MAX
-#define INT32_MAX ((int32_t)(2147483647))
-#endif
-
 #define LOG_REFS(...)
 //#define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 #define LOG_ALLOC(...)
@@ -509,7 +505,7 @@
     }
 }
 
-#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
 constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
 #else
 constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
@@ -750,61 +746,37 @@
   return writeUtf8AsUtf16(*str);
 }
 
-namespace {
-
-template<typename T>
-status_t writeByteVectorInternal(Parcel* parcel, const std::vector<T>& val)
-{
-    status_t status;
-    if (val.size() > std::numeric_limits<int32_t>::max()) {
-        status = BAD_VALUE;
-        return status;
+status_t Parcel::writeByteVectorInternal(const int8_t* data, size_t size) {
+    if (size > std::numeric_limits<int32_t>::max()) {
+        return BAD_VALUE;
     }
 
-    status = parcel->writeInt32(val.size());
+    status_t status = writeInt32(size);
     if (status != OK) {
         return status;
     }
 
-    void* data = parcel->writeInplace(val.size());
-    if (!data) {
-        status = BAD_VALUE;
-        return status;
-    }
-
-    memcpy(data, val.data(), val.size());
-    return status;
+    return write(data, size);
 }
 
-template<typename T>
-status_t writeByteVectorInternalPtr(Parcel* parcel,
-                                    const std::unique_ptr<std::vector<T>>& val)
-{
-    if (!val) {
-        return parcel->writeInt32(-1);
-    }
-
-    return writeByteVectorInternal(parcel, *val);
-}
-
-}  // namespace
-
 status_t Parcel::writeByteVector(const std::vector<int8_t>& val) {
-    return writeByteVectorInternal(this, val);
+    return writeByteVectorInternal(val.data(), val.size());
 }
 
 status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val)
 {
-    return writeByteVectorInternalPtr(this, val);
+    if (!val) return writeInt32(-1);
+    return writeByteVectorInternal(val->data(), val->size());
 }
 
 status_t Parcel::writeByteVector(const std::vector<uint8_t>& val) {
-    return writeByteVectorInternal(this, val);
+    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
 }
 
 status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val)
 {
-    return writeByteVectorInternalPtr(this, val);
+    if (!val) return writeInt32(-1);
+    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
 }
 
 status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val)
@@ -1477,81 +1449,41 @@
     return err;
 }
 
-namespace {
-
-template<typename T>
-status_t readByteVectorInternal(const Parcel* parcel,
-                                std::vector<T>* val) {
-    val->clear();
-
-    int32_t size;
-    status_t status = parcel->readInt32(&size);
-
-    if (status != OK) {
-        return status;
+status_t Parcel::readByteVectorInternal(int8_t* data, size_t size) const {
+    if (size_t(size) > dataAvail()) {
+      return BAD_VALUE;
     }
-
-    if (size < 0) {
-        status = UNEXPECTED_NULL;
-        return status;
-    }
-    if (size_t(size) > parcel->dataAvail()) {
-        status = BAD_VALUE;
-        return status;
-    }
-
-    T* data = const_cast<T*>(reinterpret_cast<const T*>(parcel->readInplace(size)));
-    if (!data) {
-        status = BAD_VALUE;
-        return status;
-    }
-    val->reserve(size);
-    val->insert(val->end(), data, data + size);
-
-    return status;
+    return read(data, size);
 }
 
-template<typename T>
-status_t readByteVectorInternalPtr(
-        const Parcel* parcel,
-        std::unique_ptr<std::vector<T>>* val) {
-    const int32_t start = parcel->dataPosition();
-    int32_t size;
-    status_t status = parcel->readInt32(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    parcel->setDataPosition(start);
-    val->reset(new (std::nothrow) std::vector<T>());
-
-    status = readByteVectorInternal(parcel, val->get());
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-}  // namespace
-
 status_t Parcel::readByteVector(std::vector<int8_t>* val) const {
-    return readByteVectorInternal(this, val);
+    if (status_t status = resizeOutVector(val); status != OK) return status;
+    return readByteVectorInternal(val->data(), val->size());
 }
 
 status_t Parcel::readByteVector(std::vector<uint8_t>* val) const {
-    return readByteVectorInternal(this, val);
+    if (status_t status = resizeOutVector(val); status != OK) return status;
+    return readByteVectorInternal(reinterpret_cast<int8_t*>(val->data()), val->size());
 }
 
 status_t Parcel::readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const {
-    return readByteVectorInternalPtr(this, val);
+    if (status_t status = resizeOutVector(val); status != OK) return status;
+    if (val->get() == nullptr) {
+        // resizeOutVector does not create the out vector if size is < 0.
+        // This occurs when writing a null byte vector.
+        return OK;
+    }
+    return readByteVectorInternal((*val)->data(), (*val)->size());
 }
 
 status_t Parcel::readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const {
-    return readByteVectorInternalPtr(this, val);
+    if (status_t status = resizeOutVector(val); status != OK) return status;
+    if (val->get() == nullptr) {
+        // resizeOutVector does not create the out vector if size is < 0.
+        // This occurs when writing a null byte vector.
+        return OK;
+    }
+    return readByteVectorInternal(reinterpret_cast<int8_t*>((*val)->data()), (*val)->size());
 }
 
 status_t Parcel::readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const {
@@ -2630,11 +2562,13 @@
             if (objectsSize == 0) {
                 free(mObjects);
                 mObjects = nullptr;
+                mObjectsCapacity = 0;
             } else {
                 binder_size_t* objects =
                     (binder_size_t*)realloc(mObjects, objectsSize*sizeof(binder_size_t));
                 if (objects) {
                     mObjects = objects;
+                    mObjectsCapacity = objectsSize;
                 }
             }
             mObjectsSize = objectsSize;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 0336d3e..3f47f3b 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -188,6 +188,30 @@
     return count;
 }
 
+// Queries the driver for the current strong reference count of the node
+// that the handle points to. Can only be used by the servicemanager.
+//
+// Returns -1 in case of failure, otherwise the strong reference count.
+ssize_t ProcessState::getStrongRefCountForNodeByHandle(int32_t handle) {
+    binder_node_info_for_ref info;
+    memset(&info, 0, sizeof(binder_node_info_for_ref));
+
+    info.handle = handle;
+
+    status_t result = ioctl(mDriverFD, BINDER_GET_NODE_INFO_FOR_REF, &info);
+
+    if (result != OK) {
+        static bool logged = false;
+        if (!logged) {
+          ALOGW("Kernel does not support BINDER_GET_NODE_INFO_FOR_REF.");
+          logged = true;
+        }
+        return -1;
+    }
+
+    return info.strong_count;
+}
+
 void ProcessState::setCallRestriction(CallRestriction restriction) {
     LOG_ALWAYS_FATAL_IF(IPCThreadState::selfOrNull() != nullptr,
         "Call restrictions must be set before the threadpool is started.");
@@ -373,7 +397,9 @@
         }
     }
 
+#ifdef __ANDROID__
     LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver '%s' could not be opened.  Terminating.", driver);
+#endif
 }
 
 ProcessState::~ProcessState()
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 136bdb0..b3afd81 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -4,6 +4,9 @@
       "name": "binderSafeInterfaceTest"
     },
     {
+      "name": "binderVendorDoubleLoadTest"
+    },
+    {
       "name": "binderDriverInterfaceTest"
     },
     {
@@ -14,6 +17,9 @@
     },
     {
       "name": "binderStabilityTest"
+    },
+    {
+      "name": "CtsNdkBinderTestCases"
     }
   ]
 }
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 60c2cce..8c7ebba 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -31,22 +31,22 @@
      * Must update values in IServiceManager.h
      */
     /* Allows services to dump sections according to priorities. */
-    const int DUMP_FLAG_PRIORITY_CRITICAL = 1; // 1 << 0
-    const int DUMP_FLAG_PRIORITY_HIGH = 2; // 1 << 1
-    const int DUMP_FLAG_PRIORITY_NORMAL = 4; // 1 << 2
+    const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
+    const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1;
+    const int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2;
     /**
      * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the
      * same priority as NORMAL priority but the services are not called with dump priority
      * arguments.
      */
-    const int DUMP_FLAG_PRIORITY_DEFAULT = 8; // 1 << 3
+    const int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3;
 
     const int DUMP_FLAG_PRIORITY_ALL = 15;
              // DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
              // | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
 
     /* Allows services to dump sections in protobuf format. */
-    const int DUMP_FLAG_PROTO = 16; // 1 << 4
+    const int DUMP_FLAG_PROTO = 1 << 4;
 
     /**
      * Retrieve an existing service called @a name from the
@@ -89,4 +89,11 @@
      * Unregisters all requests for notifications for a specific callback.
      */
     void unregisterForNotifications(@utf8InCpp String name, IServiceCallback callback);
+
+    /**
+     * Returns whether a given interface is declared on the device, even if it
+     * is not started yet. For instance, this could be a service declared in the VINTF
+     * manifest.
+     */
+    boolean isDeclared(@utf8InCpp String name);
 }
diff --git a/libs/binder/fuzzer/Android.bp b/libs/binder/fuzzer/Android.bp
index f3e4229..a9d2b75 100644
--- a/libs/binder/fuzzer/Android.bp
+++ b/libs/binder/fuzzer/Android.bp
@@ -1,8 +1,10 @@
 cc_fuzz {
     name: "binder_parcel_fuzzer",
+    defaults: ["libbinder_ndk_host_user"],
     host_supported: true,
     srcs: [
         "binder.cpp",
+        "binder_ndk.cpp",
         "hwbinder.cpp",
         "main.cpp",
         "util.cpp",
@@ -22,10 +24,20 @@
 
     target: {
         android: {
-            shared_libs: ["libbinder"],
+            shared_libs: [
+                "libbinder_ndk",
+                "libbinder",
+            ],
         },
         host: {
-            static_libs: ["libbinder"],
+            static_libs: [
+                "libbinder_ndk",
+                "libbinder",
+            ],
         },
     },
+    // This flag enables verbose output in the fuzz target, and is very useful
+    // for debugging a failure. If you are trying to diagnose how a crash was
+    // produced, you may find uncommenting the below line very useful.
+    // cflags: ["-DENABLE_LOG_FUZZ"],
 }
diff --git a/libs/binder/fuzzer/binder.cpp b/libs/binder/fuzzer/binder.cpp
index 86264db..52c730c 100644
--- a/libs/binder/fuzzer/binder.cpp
+++ b/libs/binder/fuzzer/binder.cpp
@@ -22,6 +22,10 @@
 
 using ::android::status_t;
 
+enum ByteEnum : int8_t {};
+enum IntEnum : int32_t {};
+enum LongEnum : int64_t {};
+
 class ExampleParcelable : public android::Parcelable {
 public:
     status_t writeToParcel(android::Parcel* /*parcel*/) const override {
@@ -80,6 +84,7 @@
     PARCEL_READ_WITH_STATUS(T, FUN), \
     PARCEL_READ_NO_STATUS(T, FUN)
 
+// clang-format off
 std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
     PARCEL_READ_NO_STATUS(size_t, dataSize),
     PARCEL_READ_NO_STATUS(size_t, dataAvail),
@@ -93,26 +98,16 @@
     PARCEL_READ_NO_STATUS(size_t, allowFds),
     PARCEL_READ_NO_STATUS(size_t, hasFileDescriptors),
     [] (const ::android::Parcel& p, uint8_t len) {
-#ifdef __ANDROID__
         std::string interface(len, 'a');
         FUZZ_LOG() << "about to enforceInterface: " << interface;
         bool b = p.enforceInterface(::android::String16(interface.c_str()));
         FUZZ_LOG() << "enforced interface: " << b;
-#else
-        FUZZ_LOG() << "skipping enforceInterface";
-        (void)p;
-        (void)len;
-#endif // __ANDROID__
     },
     [] (const ::android::Parcel& p, uint8_t /*len*/) {
-#ifdef __ANDROID__
         FUZZ_LOG() << "about to checkInterface";
-        bool b = p.checkInterface(new android::BBinder());
+        android::sp<android::IBinder> aBinder = new android::BBinder();
+        bool b = p.checkInterface(aBinder.get());
         FUZZ_LOG() << "checked interface: " << b;
-#else
-        FUZZ_LOG() << "skipping checkInterface";
-        (void)p;
-#endif // __ANDROID__
     },
     PARCEL_READ_NO_STATUS(size_t, objectsCount),
     PARCEL_READ_NO_STATUS(status_t, errorCheck),
@@ -158,6 +153,14 @@
     PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readStrongBinder),
     PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readNullableStrongBinder),
 
+    // TODO(b/131868573): can force read of arbitrarily sized vector
+    // PARCEL_READ_WITH_STATUS(std::vector<ByteEnum>, readEnumVector),
+    // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<ByteEnum>>, readEnumVector),
+    // PARCEL_READ_WITH_STATUS(std::vector<IntEnum>, readEnumVector),
+    // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<IntEnum>>, readEnumVector),
+    // PARCEL_READ_WITH_STATUS(std::vector<LongEnum>, readEnumVector),
+    // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<LongEnum>>, readEnumVector),
+
     // only reading one parcelable type for now
     // TODO(b/131868573): can force read of arbitrarily sized vector
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<ExampleParcelable>>>, readParcelableVector),
@@ -249,3 +252,4 @@
     PARCEL_READ_NO_STATUS(size_t, getBlobAshmemSize),
     PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),
 };
+// clang-format on
diff --git a/libs/binder/fuzzer/binder.h b/libs/binder/fuzzer/binder.h
index 32dcc79..b224ef4 100644
--- a/libs/binder/fuzzer/binder.h
+++ b/libs/binder/fuzzer/binder.h
@@ -17,6 +17,6 @@
 #include <binder/Parcel.h>
 #include <vector>
 
-#include "parcel.h"
+#include "parcel_fuzzer.h"
 
 extern std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS;
diff --git a/libs/binder/fuzzer/binder_ndk.cpp b/libs/binder/fuzzer/binder_ndk.cpp
new file mode 100644
index 0000000..29da8f7
--- /dev/null
+++ b/libs/binder/fuzzer/binder_ndk.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define FUZZ_LOG_TAG "binder_ndk"
+
+#include "binder_ndk.h"
+
+#include <android/binder_parcel_utils.h>
+
+#include "util.h"
+
+// TODO(b/142061461): parent class
+class SomeParcelable {
+public:
+    binder_status_t readFromParcel(const AParcel* parcel) {
+        return AParcel_readInt32(parcel, &mValue);
+    }
+
+private:
+    int32_t mValue = 0;
+};
+
+#define PARCEL_READ(T, FUN)                                              \
+    [](const NdkParcelAdapter& p, uint8_t /*data*/) {                    \
+        FUZZ_LOG() << "about to read " #T " using " #FUN " with status"; \
+        T t{};                                                           \
+        binder_status_t status = FUN(p.aParcel(), &t);                   \
+        FUZZ_LOG() << #T " status: " << status /* << " value: " << t*/;  \
+    }
+
+// clang-format off
+std::vector<ParcelRead<NdkParcelAdapter>> BINDER_NDK_PARCEL_READ_FUNCTIONS{
+        // methods from binder_parcel.h
+        [](const NdkParcelAdapter& p, uint8_t pos) {
+            FUZZ_LOG() << "about to set data position to " << pos;
+            binder_status_t status = AParcel_setDataPosition(p.aParcel(), pos);
+            FUZZ_LOG() << "set data position: " << status;
+        },
+        [](const NdkParcelAdapter& p, uint8_t /*data*/) {
+            FUZZ_LOG() << "about to read status header";
+            ndk::ScopedAStatus t;
+            binder_status_t status = AParcel_readStatusHeader(p.aParcel(), t.getR());
+            FUZZ_LOG() << "read status header: " << status;
+        },
+        PARCEL_READ(int32_t, AParcel_readInt32),
+        PARCEL_READ(uint32_t, AParcel_readUint32),
+        PARCEL_READ(int64_t, AParcel_readInt64),
+        PARCEL_READ(uint64_t, AParcel_readUint64),
+        PARCEL_READ(float, AParcel_readFloat),
+        PARCEL_READ(double, AParcel_readDouble),
+        PARCEL_READ(bool, AParcel_readBool),
+        PARCEL_READ(char16_t, AParcel_readChar),
+        PARCEL_READ(int8_t, AParcel_readByte),
+
+        // methods from binder_parcel_utils.h
+        PARCEL_READ(ndk::SpAIBinder, ndk::AParcel_readNullableStrongBinder),
+        PARCEL_READ(ndk::SpAIBinder, ndk::AParcel_readRequiredStrongBinder),
+        PARCEL_READ(ndk::ScopedFileDescriptor, ndk::AParcel_readNullableParcelFileDescriptor),
+        PARCEL_READ(ndk::ScopedFileDescriptor, ndk::AParcel_readRequiredParcelFileDescriptor),
+        PARCEL_READ(std::string, ndk::AParcel_readString),
+        PARCEL_READ(std::optional<std::string>, ndk::AParcel_readString),
+        // TODO(b/131868573): can force process to allocate arbitrary amount of
+        // memory
+        // PARCEL_READ(std::vector<std::string>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<std::optional<std::string>>>,
+        // ndk::AParcel_readVector), PARCEL_READ(std::vector<SomeParcelable>,
+        // ndk::AParcel_readVector), PARCEL_READ(std::vector<int32_t>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<int32_t>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<uint32_t>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<uint32_t>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<int64_t>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<int64_t>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<uint64_t>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<uint64_t>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<float>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<float>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<double>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<double>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<bool>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<bool>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<char16_t>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<char16_t>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<int32_t>, ndk::AParcel_resizeVector),
+        // PARCEL_READ(std::optional<std::vector<int32_t>>, ndk::AParcel_resizeVector),
+};
+// clang-format on
diff --git a/libs/binder/fuzzer/binder_ndk.h b/libs/binder/fuzzer/binder_ndk.h
new file mode 100644
index 0000000..622cafc
--- /dev/null
+++ b/libs/binder/fuzzer/binder_ndk.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_auto_utils.h>
+#include <vector>
+
+#include <android/binder_parcel.h>
+#include "parcel_fuzzer.h"
+
+// libbinder_ndk doesn't export this header which breaks down its API for NDK
+// and APEX users, but we need access to it to fuzz.
+#include "../ndk/parcel_internal.h"
+
+class NdkParcelAdapter {
+public:
+    NdkParcelAdapter() : mParcel(new AParcel(nullptr /*binder*/)) {}
+
+    const AParcel* aParcel() const { return mParcel.get(); }
+    AParcel* aParcel() { return mParcel.get(); }
+
+    size_t dataSize() const { return aParcel()->get()->dataSize(); }
+    size_t dataAvail() const { return aParcel()->get()->dataAvail(); }
+    size_t dataPosition() const { return aParcel()->get()->dataPosition(); }
+    size_t dataCapacity() const { return aParcel()->get()->dataCapacity(); }
+    android::status_t setData(const uint8_t* buffer, size_t len) {
+        return aParcel()->get()->setData(buffer, len);
+    }
+
+private:
+    ndk::ScopedAParcel mParcel;
+};
+
+extern std::vector<ParcelRead<NdkParcelAdapter>> BINDER_NDK_PARCEL_READ_FUNCTIONS;
diff --git a/libs/binder/fuzzer/hwbinder.cpp b/libs/binder/fuzzer/hwbinder.cpp
index b8cce72..0fec393 100644
--- a/libs/binder/fuzzer/hwbinder.cpp
+++ b/libs/binder/fuzzer/hwbinder.cpp
@@ -30,6 +30,9 @@
     return os;
 }
 
+#define PARCEL_READ_OPT_STATUS(T, FUN) \
+    PARCEL_READ_NO_STATUS(T, FUN), PARCEL_READ_WITH_STATUS(T, FUN)
+
 #define PARCEL_READ_NO_STATUS(T, FUN) \
     [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {\
         FUZZ_LOG() << "about to read " #T " using " #FUN " with no status";\
@@ -45,6 +48,7 @@
         FUZZ_LOG() << #T " status: " << status << " value: " << t;\
     }
 
+// clang-format off
 std::vector<ParcelRead<::android::hardware::Parcel>> HWBINDER_PARCEL_READ_FUNCTIONS {
     PARCEL_READ_NO_STATUS(size_t, dataSize),
     PARCEL_READ_NO_STATUS(size_t, dataAvail),
@@ -62,30 +66,44 @@
         FUZZ_LOG() << "enforceInterface status: " << okay;
     },
     PARCEL_READ_NO_STATUS(size_t, objectsCount),
+    [] (const ::android::hardware::Parcel& p, uint8_t length) {
+        FUZZ_LOG() << "about to read";
+        std::vector<uint8_t> data (length);
+        status_t status = p.read(data.data(), length);
+        FUZZ_LOG() << "read status: " << status << " data: " << hexString(data.data(), data.size());
+    },
+    [] (const ::android::hardware::Parcel& p, uint8_t length) {
+        FUZZ_LOG() << "about to read";
+        std::vector<uint8_t> data (length);
+        const void* inplace = p.readInplace(length);
+        FUZZ_LOG() << "read status: " << hexString(inplace, length);
+    },
     PARCEL_READ_WITH_STATUS(int8_t, readInt8),
     PARCEL_READ_WITH_STATUS(uint8_t, readUint8),
     PARCEL_READ_WITH_STATUS(int16_t, readInt16),
     PARCEL_READ_WITH_STATUS(uint16_t, readUint16),
-    PARCEL_READ_WITH_STATUS(int32_t, readInt32),
-    PARCEL_READ_WITH_STATUS(uint32_t, readUint32),
-    PARCEL_READ_WITH_STATUS(int64_t, readInt64),
-    PARCEL_READ_WITH_STATUS(uint64_t, readUint64),
-    PARCEL_READ_WITH_STATUS(float, readFloat),
-    PARCEL_READ_WITH_STATUS(double, readDouble),
-    PARCEL_READ_WITH_STATUS(bool, readBool),
-    PARCEL_READ_WITH_STATUS(::android::String16, readString16),
-    PARCEL_READ_WITH_STATUS(::android::sp<::android::hardware::IBinder>, readStrongBinder),
-    PARCEL_READ_WITH_STATUS(::android::sp<::android::hardware::IBinder>, readNullableStrongBinder),
-    [] (const ::android::hardware::Parcel& p, uint8_t amount) {
-        FUZZ_LOG() << "about to readInPlace " << amount;
-        const uint8_t* data = (const uint8_t*)p.readInplace(amount);
-        if (data) {
-            std::vector<uint8_t> vdata(data, data + amount);
-            FUZZ_LOG() << "readInPlace " << amount << " data: " << hexString(vdata);
-        } else {
-            FUZZ_LOG() << "readInPlace " << amount << " no data";
-        }
+    PARCEL_READ_OPT_STATUS(int32_t, readInt32),
+    PARCEL_READ_OPT_STATUS(uint32_t, readUint32),
+    PARCEL_READ_OPT_STATUS(int64_t, readInt64),
+    PARCEL_READ_OPT_STATUS(uint64_t, readUint64),
+    PARCEL_READ_OPT_STATUS(float, readFloat),
+    PARCEL_READ_OPT_STATUS(double, readDouble),
+    PARCEL_READ_OPT_STATUS(bool, readBool),
+    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
+        FUZZ_LOG() << "about to readCString";
+        const char* str = p.readCString();
+        FUZZ_LOG() << "readCString " << (str ? str : "<null>");
     },
+    PARCEL_READ_OPT_STATUS(::android::String16, readString16),
+    PARCEL_READ_WITH_STATUS(std::unique_ptr<::android::String16>, readString16),
+    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
+        FUZZ_LOG() << "about to readString16Inplace";
+        size_t outSize = 0;
+        const char16_t* str = p.readString16Inplace(&outSize);
+        FUZZ_LOG() << "readString16Inplace: " << hexString(str, sizeof(char16_t) * outSize);
+    },
+    PARCEL_READ_OPT_STATUS(::android::sp<::android::hardware::IBinder>, readStrongBinder),
+    PARCEL_READ_WITH_STATUS(::android::sp<::android::hardware::IBinder>, readNullableStrongBinder),
     [] (const ::android::hardware::Parcel& p, uint8_t size) {
         FUZZ_LOG() << "about to readBuffer";
         size_t handle = 0;
@@ -130,6 +148,28 @@
         // should be null since we don't create any IPC objects
         CHECK(data == nullptr) << data;
     },
+    [] (const ::android::hardware::Parcel& p, uint8_t size) {
+        FUZZ_LOG() << "about to readEmbeddedNativeHandle";
+        size_t parent_buffer_handle = size & 0xf;
+        size_t parent_offset = size >> 4;
+        const native_handle_t* handle = nullptr;
+        status_t status = p.readEmbeddedNativeHandle(parent_buffer_handle, parent_offset, &handle);
+        FUZZ_LOG() << "readEmbeddedNativeHandle status: " << status << " handle: " << handle << " handle: " << handle;
+
+        // should be null since we don't create any IPC objects
+        CHECK(handle == nullptr) << handle;
+    },
+    [] (const ::android::hardware::Parcel& p, uint8_t size) {
+        FUZZ_LOG() << "about to readNullableEmbeddedNativeHandle";
+        size_t parent_buffer_handle = size & 0xf;
+        size_t parent_offset = size >> 4;
+        const native_handle_t* handle = nullptr;
+        status_t status = p.readNullableEmbeddedNativeHandle(parent_buffer_handle, parent_offset, &handle);
+        FUZZ_LOG() << "readNullableEmbeddedNativeHandle status: " << status << " handle: " << handle << " handle: " << handle;
+
+        // should be null since we don't create any IPC objects
+        CHECK(handle == nullptr) << handle;
+    },
     [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
         FUZZ_LOG() << "about to readNativeHandleNoDup";
         const native_handle_t* handle = nullptr;
@@ -150,3 +190,4 @@
         CHECK(handle == nullptr) << handle;
     },
 };
+// clang-format on
diff --git a/libs/binder/fuzzer/hwbinder.h b/libs/binder/fuzzer/hwbinder.h
index 03ab510..a6c66be 100644
--- a/libs/binder/fuzzer/hwbinder.h
+++ b/libs/binder/fuzzer/hwbinder.h
@@ -17,6 +17,6 @@
 #include <hwbinder/Parcel.h>
 #include <vector>
 
-#include "parcel.h"
+#include "parcel_fuzzer.h"
 
 extern std::vector<ParcelRead<::android::hardware::Parcel>> HWBINDER_PARCEL_READ_FUNCTIONS;
diff --git a/libs/binder/fuzzer/main.cpp b/libs/binder/fuzzer/main.cpp
index 03fde3a..6657edb 100644
--- a/libs/binder/fuzzer/main.cpp
+++ b/libs/binder/fuzzer/main.cpp
@@ -16,6 +16,7 @@
 #define FUZZ_LOG_TAG "main"
 
 #include "binder.h"
+#include "binder_ndk.h"
 #include "hwbinder.h"
 #include "util.h"
 
@@ -33,27 +34,53 @@
     P p;
     p.setData(input.data(), input.size());
 
+    // since we are only using a byte to index
+    CHECK(reads.size() <= 255) << reads.size();
+
     for (size_t i = 0; i < instructions.size() - 1; i += 2) {
         uint8_t a = instructions[i];
+        uint8_t readIdx = a % reads.size();
+
         uint8_t b = instructions[i + 1];
 
-        FUZZ_LOG() << "size: " << p.dataSize() << " avail: " << p.dataAvail()
-                   << " pos: " << p.dataPosition() << " cap: " << p.dataCapacity();
+        FUZZ_LOG() << "Instruction: " << (i / 2) + 1 << "/" << instructions.size() / 2
+                   << " cmd: " << static_cast<size_t>(a) << " (" << static_cast<size_t>(readIdx)
+                   << ") arg: " << static_cast<size_t>(b) << " size: " << p.dataSize()
+                   << " avail: " << p.dataAvail() << " pos: " << p.dataPosition()
+                   << " cap: " << p.dataCapacity();
 
-        reads[a % reads.size()](p, b);
+        reads[readIdx](p, b);
     }
 }
 
 void fuzz(uint8_t options, const std::vector<uint8_t>& input, const std::vector<uint8_t>& instructions) {
-    (void) options;
+    uint8_t parcelType = options & 0x3;
 
-    // although they will do completely different things, might as well fuzz both
-    doFuzz<::android::hardware::Parcel>(HWBINDER_PARCEL_READ_FUNCTIONS, input, instructions);
-    doFuzz<::android::Parcel>(BINDER_PARCEL_READ_FUNCTIONS, input, instructions);
+    switch (parcelType) {
+        case 0x0:
+            doFuzz<::android::hardware::Parcel>(HWBINDER_PARCEL_READ_FUNCTIONS, input,
+                                                instructions);
+            break;
+        case 0x1:
+            doFuzz<::android::Parcel>(BINDER_PARCEL_READ_FUNCTIONS, input, instructions);
+            break;
+        case 0x2:
+            doFuzz<NdkParcelAdapter>(BINDER_NDK_PARCEL_READ_FUNCTIONS, input, instructions);
+            break;
+        case 0x3:
+            /*reserved for future use*/
+            break;
+        default:
+            LOG_ALWAYS_FATAL("unknown parcel type %d", static_cast<int>(parcelType));
+    }
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     if (size <= 1) return 0;  // no use
+
+    // avoid timeouts, see b/142617274, b/142473153
+    if (size > 50000) return 0;
+
     uint8_t options = *data;
     data++;
     size--;
diff --git a/libs/binder/fuzzer/parcel.h b/libs/binder/fuzzer/parcel_fuzzer.h
similarity index 99%
rename from libs/binder/fuzzer/parcel.h
rename to libs/binder/fuzzer/parcel_fuzzer.h
index 5f05335..10cf17c 100644
--- a/libs/binder/fuzzer/parcel.h
+++ b/libs/binder/fuzzer/parcel_fuzzer.h
@@ -16,5 +16,3 @@
 
 template <typename P>
 using ParcelRead = std::function<void(const P& p, uint8_t data)>;
-
-
diff --git a/libs/binder/fuzzer/util.cpp b/libs/binder/fuzzer/util.cpp
index b1213e9..479f406 100644
--- a/libs/binder/fuzzer/util.cpp
+++ b/libs/binder/fuzzer/util.cpp
@@ -24,13 +24,17 @@
 std::string hexString(const void* bytes, size_t len) {
     if (bytes == nullptr) return "<null>";
 
-    std::ostringstream s;
-    s << std::hex << std::setfill('0');
+    const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
+    char chars[] = "0123456789abcdef";
+    std::string result;
+    result.resize(len * 2);
+
     for (size_t i = 0; i < len; i++) {
-        s << std::setw(2) << static_cast<int>(
-            static_cast<const uint8_t*>(bytes)[i]);
+        result[2 * i] = chars[bytes8[i] >> 4];
+        result[2 * i + 1] = chars[bytes8[i] & 0xf];
     }
-    return s.str();
+
+    return result;
 }
 std::string hexString(const std::vector<uint8_t>& bytes) {
     return hexString(bytes.data(), bytes.size());
diff --git a/libs/binder/fuzzer/util.h b/libs/binder/fuzzer/util.h
index 416c3a7..aa504d2 100644
--- a/libs/binder/fuzzer/util.h
+++ b/libs/binder/fuzzer/util.h
@@ -23,27 +23,31 @@
 #error "Must define FUZZ_LOG_TAG"
 #endif
 
-#define ENABLE_LOG_FUZZ 1
-#define FUZZ_LOG() FuzzLog(FUZZ_LOG_TAG, ENABLE_LOG_FUZZ).log()
+#define FUZZ_LOG() FuzzLog(FUZZ_LOG_TAG).log()
 
+#ifdef ENABLE_LOG_FUZZ
 class FuzzLog {
 public:
-    FuzzLog(const std::string& tag, bool log) : mTag(tag), mLog(log) {}
-    ~FuzzLog() {
-        if (mLog) {
-            std::cout << mTag << ": " << mOs.str() << std::endl;
-        }
-    }
+    FuzzLog(const char* tag) : mTag(tag) {}
+    ~FuzzLog() { std::cout << mTag << ": " << mOs.str() << std::endl; }
 
-    std::stringstream& log() {
-        return mOs;
-    }
+    std::stringstream& log() { return mOs; }
 
 private:
-    std::string mTag;
-    bool mLog;
+    const char* mTag = nullptr;
     std::stringstream mOs;
 };
+#else
+class FuzzLog {
+public:
+    FuzzLog(const char* /*tag*/) {}
+    template <typename T>
+    FuzzLog& operator<<(const T& /*t*/) {
+        return *this;
+    }
+    FuzzLog& log() { return *this; }
+};
+#endif
 
 std::string hexString(const void* bytes, size_t len);
 std::string hexString(const std::vector<uint8_t>& bytes);
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 0ab40b8..2744ce1 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -130,16 +130,17 @@
     int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
     int32_t checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid,
             const String16& callingPackage);
-    // @Deprecated, use noteOp(int32_t, int32_t uid, const String16&, const String16&) instead
+    // @Deprecated, use noteOp(int32_t, int32_t uid, const String16&, const String16&,
+    //              const String16&) instead
     int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
     int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage,
-            const String16& message);
-    // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&)
-    // instead
+            const String16& featureId, const String16& message);
+    // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&,
+    //              const String16&) instead
     int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
             bool startIfModeDefault);
     int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
-            bool startIfModeDefault, const String16& message);
+            bool startIfModeDefault, const String16& featureId, const String16& message);
     void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
     void startWatchingMode(int32_t op, const String16& packageName,
             const sp<IAppOpsCallback>& callback);
@@ -147,7 +148,7 @@
     int32_t permissionToOpCode(const String16& permission);
     void setCameraAudioRestriction(int32_t mode);
     void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName,
-            int32_t opCode, const String16& message);
+            int32_t opCode, const String16& featureId, const String16& message);
 
 private:
     Mutex mLock;
@@ -155,7 +156,7 @@
 
     sp<IAppOpsService> getService();
     void markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
-            const String16& message);
+            const String16& featureId, const String16& message);
     bool shouldCollectNotes(int32_t opCode);
 };
 
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index 8b8a3c2..ad34bc5 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -49,7 +49,8 @@
             const String16& packageName) = 0;
     virtual void setCameraAudioRestriction(int32_t mode) = 0;
     virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid,
-            const String16& packageName, int32_t opCode, const String16& message) = 0;
+            const String16& packageName, int32_t opCode, const String16& featureId,
+            const String16& message) = 0;
     virtual bool shouldCollectNotes(int32_t opCode) = 0;
 
     enum {
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 64f3052..64604b7 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -62,7 +62,11 @@
         DEBUG_PID_TRANSACTION   = B_PACK_CHARS('_', 'P', 'I', 'D'),
 
         // Corresponds to TF_ONE_WAY -- an asynchronous call.
-        FLAG_ONEWAY             = 0x00000001
+        FLAG_ONEWAY             = 0x00000001,
+
+        // Private userspace flag for transaction which is being requested from
+        // a vendor context.
+        FLAG_PRIVATE_VENDOR     = 0x10000000,
     };
 
                           IBinder();
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 5793a1c..28ffa48 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -88,8 +88,12 @@
 public:                                                                 \
 
 
+#define __IINTF_CONCAT(x, y) (x ## y)
 #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
-    const ::android::String16 I##INTERFACE::descriptor(NAME);           \
+    const ::android::StaticString16                                     \
+        I##INTERFACE##_descriptor_static_str16(__IINTF_CONCAT(u, NAME));\
+    const ::android::String16 I##INTERFACE::descriptor(                 \
+        I##INTERFACE##_descriptor_static_str16);                        \
     const ::android::String16&                                          \
             I##INTERFACE::getInterfaceDescriptor() const {              \
         return I##INTERFACE::descriptor;                                \
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index def1bea..4a44c5a 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -26,12 +26,22 @@
 
 // ----------------------------------------------------------------------
 
+/**
+ * Service manager for C++ services.
+ *
+ * IInterface is only for legacy ABI compatibility
+ */
 class IServiceManager : public IInterface
 {
 public:
-    DECLARE_META_INTERFACE(ServiceManager)
+    // for ABI compatibility
+    virtual const String16& getInterfaceDescriptor() const;
+
+    IServiceManager();
+    virtual ~IServiceManager();
+
     /**
-     * Must match values in IServiceManager.java
+     * Must match values in IServiceManager.aidl
      */
     /* Allows services to dump sections according to priorities. */
     static const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
@@ -78,6 +88,14 @@
      * Returns nullptr only for permission problem or fatal error.
      */
     virtual sp<IBinder> waitForService(const String16& name) = 0;
+
+    /**
+     * Check if a service is declared (e.g. VINTF manifest).
+     *
+     * If this returns true, waitForService should always be able to return the
+     * service.
+     */
+    virtual bool isDeclared(const String16& name) = 0;
 };
 
 sp<IServiceManager> defaultServiceManager();
@@ -89,6 +107,13 @@
 }
 
 template<typename INTERFACE>
+sp<INTERFACE> waitForDeclaredService(const String16& name) {
+    const sp<IServiceManager> sm = defaultServiceManager();
+    if (!sm->isDeclared(name)) return nullptr;
+    return interface_cast<INTERFACE>(sm->waitForService(name));
+}
+
+template<typename INTERFACE>
 status_t getService(const String16& name, sp<INTERFACE>* outService)
 {
     const sp<IServiceManager> sm = defaultServiceManager();
diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h
index 09e50a9..d070390 100644
--- a/libs/binder/include/binder/IUidObserver.h
+++ b/libs/binder/include/binder/IUidObserver.h
@@ -34,7 +34,8 @@
     virtual void onUidGone(uid_t uid, bool disabled) = 0;
     virtual void onUidActive(uid_t uid) = 0;
     virtual void onUidIdle(uid_t uid, bool disabled) = 0;
-    virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq) = 0;
+    virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
+            int32_t capability) = 0;
 
     enum {
         ON_UID_GONE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 8726681..0f8abab 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -19,6 +19,7 @@
 
 #include <map> // for legacy reasons
 #include <string>
+#include <type_traits>
 #include <vector>
 
 #include <android-base/unique_fd.h>
@@ -157,6 +158,18 @@
     status_t            writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val);
     status_t            writeStrongBinderVector(const std::vector<sp<IBinder>>& val);
 
+    // Write an Enum vector with underlying type int8_t.
+    // Does not use padding; each byte is contiguous.
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            writeEnumVector(const std::vector<T>& val);
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val);
+    // Write an Enum vector with underlying type != int8_t.
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            writeEnumVector(const std::vector<T>& val);
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val);
+
     template<typename T>
     status_t            writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val);
     template<typename T>
@@ -275,6 +288,19 @@
     status_t            readStrongBinder(sp<IBinder>* val) const;
     status_t            readNullableStrongBinder(sp<IBinder>* val) const;
 
+
+    // Read an Enum vector with underlying type int8_t.
+    // Does not use padding; each byte is contiguous.
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            readEnumVector(std::vector<T>* val) const;
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const;
+    // Read an Enum vector with underlying type != int8_t.
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            readEnumVector(std::vector<T>* val) const;
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const;
+
     template<typename T>
     status_t            readParcelableVector(
                             std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const;
@@ -438,6 +464,19 @@
     status_t            writeRawNullableParcelable(const Parcelable*
                                                    parcelable);
 
+    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0>
+    status_t            writeEnum(const T& val);
+    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0>
+    status_t            writeEnum(const T& val);
+
+    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0>
+    status_t            readEnum(T* pArg) const;
+    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0>
+    status_t            readEnum(T* pArg) const;
+
+    status_t writeByteVectorInternal(const int8_t* data, size_t size);
+    status_t readByteVectorInternal(int8_t* data, size_t size) const;
+
     template<typename T, typename U>
     status_t            unsafeReadTypedVector(std::vector<T>* val,
                                               status_t(Parcel::*read_func)(U*) const) const;
@@ -913,6 +952,66 @@
     return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable<T>);
 }
 
+template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
+status_t Parcel::writeEnum(const T& val) {
+    return writeInt32(static_cast<int32_t>(val));
+}
+template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>>
+status_t Parcel::writeEnum(const T& val) {
+    return writeInt64(static_cast<int64_t>(val));
+}
+
+template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::writeEnumVector(const std::vector<T>& val) {
+    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
+    if (!val) return writeInt32(-1);
+    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::writeEnumVector(const std::vector<T>& val) {
+    return writeTypedVector(val, &Parcel::writeEnum);
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
+    return writeNullableTypedVector(val, &Parcel::writeEnum);
+}
+
+template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
+status_t Parcel::readEnum(T* pArg) const {
+    return readInt32(reinterpret_cast<int32_t *>(pArg));
+}
+template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>>
+status_t Parcel::readEnum(T* pArg) const {
+    return readInt64(reinterpret_cast<int64_t *>(pArg));
+}
+
+template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::readEnumVector(std::vector<T>* val) const {
+    if (status_t status = resizeOutVector(val); status != OK) return status;
+    return readByteVectorInternal(reinterpret_cast<int8_t*>(val->data()), val->size());
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
+    if (status_t status = resizeOutVector(val); status != OK) return status;
+    if (val->get() == nullptr) {
+        // resizeOutVector does not create the out vector if size is < 0.
+        // This occurs when writing a null Enum vector.
+        return OK;
+    }
+    return readByteVectorInternal(reinterpret_cast<int8_t*>((*val)->data()), (*val)->size());
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::readEnumVector(std::vector<T>* val) const {
+    return readTypedVector(val, &Parcel::readEnum);
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readEnum);
+}
+
 // ---------------------------------------------------------------------------
 
 inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index f7c38f4..e57ff1c 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -69,6 +69,14 @@
 
             ssize_t             getKernelReferences(size_t count, uintptr_t* buf);
 
+                                // Only usable by the context manager.
+                                // This refcount includes:
+                                // 1. Strong references to the node by this and other processes
+                                // 2. Temporary strong references held by the kernel during a
+                                //    transaction on the node.
+                                // It does NOT include local strong references to the node
+            ssize_t             getStrongRefCountForNodeByHandle(int32_t handle);
+
             enum class CallRestriction {
                 // all calls okay
                 NONE,
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index 2894482..b2f51d3 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -81,7 +81,7 @@
         VINTF = 0b111111,
     };
 
-#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
     static constexpr Level kLocalStability = Level::VENDOR;
 #else
     static constexpr Level kLocalStability = Level::SYSTEM;
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 62a0f9f..fa07d04 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -22,12 +22,14 @@
             cflags: [
                 "-D__INTRODUCED_IN(n)=",
                 "-D__assert(a,b,c)=",
+                // We want all the APIs to be available on the host.
+                "-D__ANDROID_API__=10000",
             ],
         },
     },
 }
 
-cc_library_shared {
+cc_library {
     name: "libbinder_ndk",
 
     defaults: ["libbinder_ndk_host_user"],
@@ -69,6 +71,12 @@
     ],
 
     target: {
+        android: {
+            // Only one copy of this library on an Android device
+            static: {
+                enabled: false,
+            },
+        },
         linux: {
             version_script: "libbinder_ndk.map.txt",
         },
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index b06ca86..e752c45 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -17,6 +17,7 @@
 #include <android/binder_ibinder.h>
 #include "ibinder_internal.h"
 
+#include <android/binder_stability.h>
 #include <android/binder_status.h>
 #include "parcel_internal.h"
 #include "status_internal.h"
@@ -542,7 +543,8 @@
         return STATUS_UNKNOWN_TRANSACTION;
     }
 
-    if ((flags & ~FLAG_ONEWAY) != 0) {
+    constexpr binder_flags_t kAllFlags = FLAG_PRIVATE_VENDOR | FLAG_ONEWAY;
+    if ((flags & ~kAllFlags) != 0) {
         LOG(ERROR) << __func__ << ": Unrecognized flags sent: " << flags;
         return STATUS_BAD_VALUE;
     }
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
index c6868b0..8f37c5e 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -21,7 +21,7 @@
 
 /**
  * @file binder_auto_utils.h
- * @brief These objects provide a more C++-like thin interface to the .
+ * @brief These objects provide a more C++-like thin interface to the binder.
  */
 
 #pragma once
@@ -201,12 +201,49 @@
     /**
      * See AStatus_isOk.
      */
-    bool isOk() { return get() != nullptr && AStatus_isOk(get()); }
+    bool isOk() const { return get() != nullptr && AStatus_isOk(get()); }
 
     /**
-     * Convenience method for okay status.
+     * See AStatus_getExceptionCode
+     */
+    binder_exception_t getExceptionCode() const { return AStatus_getExceptionCode(get()); }
+
+    /**
+     * See AStatus_getServiceSpecificError
+     */
+    int32_t getServiceSpecificError() const { return AStatus_getServiceSpecificError(get()); }
+
+    /**
+     * See AStatus_getStatus
+     */
+    binder_status_t getStatus() const { return AStatus_getStatus(get()); }
+
+    /**
+     * See AStatus_getMessage
+     */
+    const char* getMessage() const { return AStatus_getMessage(get()); }
+
+    /**
+     * Convenience methods for creating scoped statuses.
      */
     static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); }
+    static ScopedAStatus fromExceptionCode(binder_exception_t exception) {
+        return ScopedAStatus(AStatus_fromExceptionCode(exception));
+    }
+    static ScopedAStatus fromExceptionCodeWithMessage(binder_exception_t exception,
+                                                      const char* message) {
+        return ScopedAStatus(AStatus_fromExceptionCodeWithMessage(exception, message));
+    }
+    static ScopedAStatus fromServiceSpecificError(int32_t serviceSpecific) {
+        return ScopedAStatus(AStatus_fromServiceSpecificError(serviceSpecific));
+    }
+    static ScopedAStatus fromServiceSpecificErrorWithMessage(int32_t serviceSpecific,
+                                                             const char* message) {
+        return ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(serviceSpecific, message));
+    }
+    static ScopedAStatus fromStatus(binder_status_t status) {
+        return ScopedAStatus(AStatus_fromStatus(status));
+    }
 };
 
 /**
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 160739b..4d5c044 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -34,7 +34,7 @@
 #include <android/binder_status.h>
 
 __BEGIN_DECLS
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 
 // Also see TF_* in kernel's binder.h
 typedef uint32_t binder_flags_t;
@@ -165,6 +165,8 @@
  *
  * None of these parameters can be null.
  *
+ * Available since API level 29.
+ *
  * \param interfaceDescriptor this is a unique identifier for the class. This is used internally for
  * sanity checks on transactions.
  * \param onCreate see AIBinder_Class_onCreate.
@@ -199,6 +201,8 @@
  * If this isn't set, nothing will be dumped when dump is called (for instance with
  * android.os.Binder#dump). Must be called before any instance of the class is created.
  *
+ * Available since API level 29.
+ *
  * \param dump function to call when an instance of this binder class is being dumped.
  */
 void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29);
@@ -220,6 +224,8 @@
  * 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.
  *
+ * Available since API level 29.
+ *
  * \param clazz the type of the object to be created.
  * \param args the args to pass to AIBinder_onCreate for that class.
  *
@@ -231,6 +237,8 @@
 /**
  * If this is hosted in a process other than the current one.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder being queried.
  *
  * \return true if the AIBinder represents an object in another process.
@@ -244,6 +252,8 @@
  * updated as the result of a transaction made using AIBinder_transact, but it will also be updated
  * based on the results of bookkeeping or other transactions made internally.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder being queried.
  *
  * \return true if the binder is alive.
@@ -255,6 +265,8 @@
  * return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a
  * sanity check.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder being queried.
  *
  * \return STATUS_OK if the ping succeeds.
@@ -264,7 +276,9 @@
 /**
  * Built-in transaction for all binder objects. This dumps information about a given binder.
  *
- * See also AIBinder_Class_setOnDump, AIBinder_onDump
+ * See also AIBinder_Class_setOnDump, AIBinder_onDump.
+ *
+ * Available since API level 29.
  *
  * \param binder the binder to dump information about
  * \param fd where information should be dumped to
@@ -287,6 +301,8 @@
  *
  * If binder is local, this will return STATUS_INVALID_OPERATION.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object you want to receive death notifications from.
  * \param recipient the callback that will receive notifications when/if the binder dies.
  * \param cookie the value that will be passed to the death recipient on death.
@@ -306,6 +322,8 @@
  * If the binder dies, it will automatically unlink. If the binder is deleted, it will be
  * automatically unlinked.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object to remove a previously linked death recipient from.
  * \param recipient the callback to remove.
  * \param cookie the cookie used to link to death.
@@ -322,9 +340,11 @@
  * This can be used with higher-level system services to determine the caller's identity and check
  * permissions.
  *
+ * Available since API level 29.
+ *
  * \return calling uid or the current process's UID if this thread isn't processing a transaction.
  */
-uid_t AIBinder_getCallingUid();
+uid_t AIBinder_getCallingUid() __INTRODUCED_IN(29);
 
 /**
  * This returns the calling PID assuming that this thread is called from a thread that is processing
@@ -335,14 +355,18 @@
  * calling process dies and is replaced with another process with elevated permissions and the same
  * PID.
  *
+ * Available since API level 29.
+ *
  * \return calling pid or the current process's PID if this thread isn't processing a transaction.
  * If the transaction being processed is a oneway transaction, then this method will return 0.
  */
-pid_t AIBinder_getCallingPid();
+pid_t AIBinder_getCallingPid() __INTRODUCED_IN(29);
 
 /**
  * This can only be called if a strong reference to this object already exists in process.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object to add a refcount to.
  */
 void AIBinder_incStrong(AIBinder* binder) __INTRODUCED_IN(29);
@@ -350,6 +374,8 @@
 /**
  * This will delete the object and call onDestroy once the refcount reaches zero.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object to remove a refcount from.
  */
 void AIBinder_decStrong(AIBinder* binder) __INTRODUCED_IN(29);
@@ -357,6 +383,8 @@
 /**
  * For debugging only!
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object to retrieve the refcount of.
  *
  * \return the number of strong-refs on this binder in this process. If binder is null, this will be
@@ -373,6 +401,8 @@
  * This returns true if the class association succeeds. If it fails, no change is made to the
  * binder object.
  *
+ * Available since API level 29.
+ *
  * \param binder the object to attach the class to.
  * \param clazz the clazz to attach to binder.
  *
@@ -383,6 +413,8 @@
 /**
  * Returns the class that this binder was constructed with or associated with.
  *
+ * Available since API level 29.
+ *
  * \param binder the object that is being queried.
  *
  * \return the class that this binder is associated with. If this binder wasn't created with
@@ -394,6 +426,8 @@
  * Value returned by onCreate for a local binder. For stateless classes (if onCreate returns
  * null), this also returns null. For a remote binder, this will always return null.
  *
+ * Available since API level 29.
+ *
  * \param binder the object that is being queried.
  *
  * \return the userdata returned from AIBinder_onCreate when this object was created. This may be
@@ -422,6 +456,8 @@
  * AIBinder_transact. Alternatively, if there is an error while filling out the parcel, it can be
  * deleted with AParcel_delete.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object to start a transaction on.
  * \param in out parameter for input data to the transaction.
  *
@@ -442,6 +478,8 @@
  * This does not affect the ownership of binder. The out parcel's ownership is passed to the caller
  * and must be released with AParcel_delete when finished reading.
  *
+ * Available since API level 29.
+ *
  * \param binder the binder object to transact on.
  * \param code the implementation-specific code representing which transaction should be taken.
  * \param in the implementation-specific input data to this transaction.
@@ -459,6 +497,8 @@
  * This does not take any ownership of the input binder, but it can be used to retrieve it if
  * something else in some process still holds a reference to it.
  *
+ * Available since API level 29.
+ *
  * \param binder object to create a weak pointer to.
  *
  * \return object representing a weak pointer to binder (or null if binder is null).
@@ -469,6 +509,8 @@
 /**
  * Deletes the weak reference. This will have no impact on the lifetime of the binder.
  *
+ * Available since API level 29.
+ *
  * \param weakBinder object created with AIBinder_Weak_new.
  */
 void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29);
@@ -477,6 +519,8 @@
  * If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns
  * null.
  *
+ * Available since API level 29.
+ *
  * \param weakBinder weak pointer to attempt retrieving the original object from.
  *
  * \return an AIBinder object with one refcount given to the caller or null.
@@ -487,6 +531,8 @@
 /**
  * This function is executed on death receipt. See AIBinder_linkToDeath/AIBinder_unlinkToDeath.
  *
+ * Available since API level 29.
+ *
  * \param cookie the cookie passed to AIBinder_linkToDeath.
  */
 typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29);
@@ -494,6 +540,8 @@
 /**
  * Creates a new binder death recipient. This can be attached to multiple different binder objects.
  *
+ * Available since API level 29.
+ *
  * \param onBinderDied the callback to call when this death recipient is invoked.
  *
  * \return the newly constructed object (or null if onBinderDied is null).
@@ -505,19 +553,23 @@
  * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before
  * calling this as these will all be automatically unlinked.
  *
+ * Available since API level 29.
+ *
  * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new).
  */
 void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) __INTRODUCED_IN(29);
 
-#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= 29
 
-#if __ANDROID_API__ >= __ANDROID_API_R__
+#if __ANDROID_API__ >= 30
 
 /**
  * Gets the extension registered with AIBinder_setExtension.
  *
  * See AIBinder_setExtension.
  *
+ * Available since API level 30.
+ *
  * \param binder the object to get the extension of.
  * \param outExt the returned extension object. Will be null if there is no extension set or
  * non-null with one strong ref count.
@@ -570,6 +622,8 @@
  *         // if bar is null, then there is no extension or a different
  *         // type of extension
  *
+ * Available since API level 30.
+ *
  * \param binder the object to get the extension on. Must be local.
  * \param ext the extension to set (binder will hold a strong reference to this)
  *
@@ -578,7 +632,7 @@
  */
 binder_status_t AIBinder_setExtension(AIBinder* binder, AIBinder* ext) __INTRODUCED_IN(30);
 
-#endif  //__ANDROID_API__ >= __ANDROID_API_R__
+#endif  //__ANDROID_API__ >= 30
 
 __END_DECLS
 
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
index 124f36c..be3029c 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -31,7 +31,7 @@
 #include <jni.h>
 
 __BEGIN_DECLS
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 
 /**
  * Converts an android.os.IBinder object into an AIBinder* object.
@@ -40,6 +40,8 @@
  * AIBinder object, the original object is returned. The returned object has one refcount
  * associated with it, and so this should be accompanied with an AIBinder_decStrong call.
  *
+ * Available since API level 29.
+ *
  * \param env Java environment.
  * \param binder android.os.IBinder java object.
  *
@@ -55,6 +57,8 @@
  * If either env or the binder is null, null is returned. If this binder object was originally an
  * IBinder object, the original java object will be returned.
  *
+ * Available since API level 29.
+ *
  * \param env Java environment.
  * \param binder the object to convert.
  *
@@ -63,7 +67,7 @@
 __attribute__((warn_unused_result)) jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder)
         __INTRODUCED_IN(29);
 
-#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= 29
 __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 8c41707..86b75b8 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -35,7 +35,7 @@
 typedef struct AIBinder AIBinder;
 
 __BEGIN_DECLS
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 
 /**
  * This object represents a package of data that can be sent between processes. When transacting, an
@@ -49,6 +49,8 @@
 /**
  * Cleans up a parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel A parcel returned by AIBinder_prepareTransaction or AIBinder_transact when a
  * transaction is being aborted.
  */
@@ -57,6 +59,8 @@
 /**
  * Sets the position within the parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel The parcel of which to set the position.
  * \param position Position of the parcel to set. This must be a value returned by
  * AParcel_getDataPosition. Positions are constant for a given parcel between processes.
@@ -69,6 +73,8 @@
 /**
  * Gets the current position within the parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel The parcel of which to get the position.
  *
  * \return The size of the parcel. This will always be greater than 0. The values returned by this
@@ -389,6 +395,8 @@
  * Writes an AIBinder to the next location in a non-null parcel. Can be null. This does not take any
  * refcounts of ownership of the binder from the client.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param binder the value to write to the parcel.
  *
@@ -400,6 +408,8 @@
  * Reads an AIBinder from the next location in a non-null parcel. One strong ref-count of ownership
  * is passed to the caller of this function.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param binder the out parameter for what is read from the parcel. This may be null.
  *
@@ -414,12 +424,14 @@
  *
  * This corresponds to the SDK's android.os.ParcelFileDescriptor.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param fd the value to write to the parcel (-1 to represent a null ParcelFileDescriptor).
  *
  * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd);
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) __INTRODUCED_IN(29);
 
 /**
  * Reads an int from the next location in a non-null parcel.
@@ -428,13 +440,16 @@
  *
  * This corresponds to the SDK's android.os.ParcelFileDescriptor.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param fd the out parameter for what is read from the parcel (or -1 to represent a null
  * ParcelFileDescriptor)
  *
  * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd);
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd)
+        __INTRODUCED_IN(29);
 
 /**
  * Writes an AStatus object to the next location in a non-null parcel.
@@ -445,6 +460,8 @@
  * this happens or if writing the status object itself fails, the return value from this function
  * should be propagated to the client, and AParcel_readStatusHeader shouldn't be called.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param status the value to write to the parcel.
  *
@@ -457,6 +474,8 @@
  * Reads an AStatus from the next location in a non-null parcel. Ownership is passed to the caller
  * of this function.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param status the out parameter for what is read from the parcel.
  *
@@ -470,6 +489,8 @@
  *
  * If length is -1, and string is nullptr, this will write a 'null' string to the parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param string the null-terminated string to write to the parcel, at least of size 'length'.
  * \param length the length of the string to be written.
@@ -487,6 +508,8 @@
  * the output buffer from this read. If there is a 'null' string on the binder buffer, the allocator
  * will be called with length -1.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param stringData some external representation of a string.
  * \param allocator allocator that will be called once the size of the string is known.
@@ -504,6 +527,8 @@
  * returned from this function will be used to fill out the data from the parcel. If length is -1,
  * this will write a 'null' string array to the binder buffer.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData some external representation of an array.
  * \param length the length of the array to be written.
@@ -526,6 +551,8 @@
  * the contents of the string that is read. If the string array being read is 'null', this will
  * instead just pass -1 to AParcel_stringArrayAllocator.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called with arrayData once the size of the output
@@ -543,6 +570,8 @@
 /**
  * Writes an array of parcelables (user-defined types) to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -562,6 +591,8 @@
  * length is greater than zero, elementReader will be called for every index to read the
  * corresponding parcelable.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -578,6 +609,8 @@
 /**
  * Writes int32_t value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -588,6 +621,8 @@
 /**
  * Writes uint32_t value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -598,6 +633,8 @@
 /**
  * Writes int64_t value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -608,6 +645,8 @@
 /**
  * Writes uint64_t value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -618,6 +657,8 @@
 /**
  * Writes float value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -628,6 +669,8 @@
 /**
  * Writes double value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -638,6 +681,8 @@
 /**
  * Writes bool value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -648,6 +693,8 @@
 /**
  * Writes char16_t value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -658,6 +705,8 @@
 /**
  * Writes int8_t value to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param value the value to write to the parcel.
  *
@@ -668,6 +717,8 @@
 /**
  * Reads into int32_t value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -678,6 +729,8 @@
 /**
  * Reads into uint32_t value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -688,6 +741,8 @@
 /**
  * Reads into int64_t value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -698,6 +753,8 @@
 /**
  * Reads into uint64_t value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -708,6 +765,8 @@
 /**
  * Reads into float value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -718,6 +777,8 @@
 /**
  * Reads into double value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -728,6 +789,8 @@
 /**
  * Reads into bool value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -738,6 +801,8 @@
 /**
  * Reads into char16_t value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -748,6 +813,8 @@
 /**
  * Reads into int8_t value from the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param value the value to read from the parcel.
  *
@@ -758,6 +825,8 @@
 /**
  * Writes an array of int32_t to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -770,6 +839,8 @@
 /**
  * Writes an array of uint32_t to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -782,6 +853,8 @@
 /**
  * Writes an array of int64_t to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -794,6 +867,8 @@
 /**
  * Writes an array of uint64_t to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -806,6 +881,8 @@
 /**
  * Writes an array of float to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -818,6 +895,8 @@
 /**
  * Writes an array of double to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -833,6 +912,8 @@
  * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying
  * values to write to the parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData some external representation of an array.
  * \param length the length of arrayData (or -1 if this represents a null array).
@@ -846,6 +927,8 @@
 /**
  * Writes an array of char16_t to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -858,6 +941,8 @@
 /**
  * Writes an array of int8_t to the next location in a non-null parcel.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to write to.
  * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
  * \param length the length of arrayData or -1 if this represents a null array.
@@ -874,6 +959,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -890,6 +977,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -906,6 +995,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -922,6 +1013,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -938,6 +1031,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -954,6 +1049,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -969,6 +1066,8 @@
  * First, allocator will be called with the length of the array. Then, for every i in [0, length),
  * setter(arrayData, i, x) will be called where x is the value at the associated index.
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -988,6 +1087,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -1004,6 +1105,8 @@
  * length is greater than zero, the buffer returned by the allocator will be filled with the
  * corresponding data
  *
+ * Available since API level 29.
+ *
  * \param parcel the parcel to read from.
  * \param arrayData some external representation of an array.
  * \param allocator the callback that will be called to allocate the array.
@@ -1015,7 +1118,7 @@
 
 // @END-PRIMITIVE-READ-WRITE
 
-#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= 29
 __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 2671b9b..78d70f8 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -30,7 +30,7 @@
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
-#if __ANDROID_API__ >= __ANDROID_API_Q__
+#if __ANDROID_API__ >= 29
 
 enum {
     STATUS_OK = 0,
@@ -105,6 +105,8 @@
 /**
  * New status which is considered a success.
  *
+ * Available since API level 29.
+ *
  * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_newOk() __INTRODUCED_IN(29);
@@ -112,6 +114,8 @@
 /**
  * New status with exception code.
  *
+ * Available since API level 29.
+ *
  * \param exception the code that this status should represent. If this is EX_NONE, then this
  * constructs an non-error status object.
  *
@@ -123,6 +127,8 @@
 /**
  * New status with exception code and message.
  *
+ * Available since API level 29.
+ *
  * \param exception the code that this status should represent. If this is EX_NONE, then this
  * constructs an non-error status object.
  * \param message the error message to associate with this status object.
@@ -137,6 +143,8 @@
  *
  * This is considered to be EX_TRANSACTION_FAILED with extra information.
  *
+ * Available since API level 29.
+ *
  * \param serviceSpecific an implementation defined error code.
  *
  * \return a newly constructed status object that the caller owns.
@@ -149,6 +157,8 @@
  *
  * This is considered to be EX_TRANSACTION_FAILED with extra information.
  *
+ * Available since API level 29.
+ *
  * \param serviceSpecific an implementation defined error code.
  * \param message the error message to associate with this status object.
  *
@@ -162,6 +172,8 @@
  * is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning
  * an AStatus instance.
  *
+ * Available since API level 29.
+ *
  * \param a low-level error to associate with this status object.
  *
  * \return a newly constructed status object that the caller owns.
@@ -173,6 +185,8 @@
  * Whether this object represents a successful transaction. If this function returns true, then
  * AStatus_getExceptionCode will return EX_NONE.
  *
+ * Available since API level 29.
+ *
  * \param status the status being queried.
  *
  * \return whether the status represents a successful transaction. For more details, see below.
@@ -182,6 +196,8 @@
 /**
  * The exception that this status object represents.
  *
+ * Available since API level 29.
+ *
  * \param status the status being queried.
  *
  * \return the exception code that this object represents.
@@ -194,6 +210,8 @@
  * 0, the status object may still represent a different exception or status. To find out if this
  * transaction as a whole is okay, use AStatus_isOk instead.
  *
+ * Available since API level 29.
+ *
  * \param status the status being queried.
  *
  * \return the service-specific error code if the exception code is EX_SERVICE_SPECIFIC or 0.
@@ -206,6 +224,8 @@
  * object may represent a different exception or a service specific error. To find out if this
  * transaction as a whole is okay, use AStatus_isOk instead.
  *
+ * Available since API level 29.
+ *
  * \param status the status being queried.
  *
  * \return the status code if the exception code is EX_TRANSACTION_FAILED or 0.
@@ -218,6 +238,8 @@
  *
  * The returned string has the lifetime of the status object passed into this function.
  *
+ * Available since API level 29.
+ *
  * \param status the status being queried.
  *
  * \return the message associated with this error.
@@ -227,11 +249,13 @@
 /**
  * Deletes memory associated with the status instance.
  *
+ * Available since API level 29.
+ *
  * \param status the status to delete, returned from AStatus_newOk or one of the AStatus_from* APIs.
  */
 void AStatus_delete(AStatus* status) __INTRODUCED_IN(29);
 
-#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= 29
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index b03fce1..2a4ded8 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -20,7 +20,22 @@
 
 __BEGIN_DECLS
 
-#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+/**
+ * Private addition to binder_flag_t.
+ */
+enum {
+    /**
+     * Indicates that this transaction is coupled w/ vendor.img
+     */
+    FLAG_PRIVATE_VENDOR = 0x10000000,
+};
+
+#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || \
+        (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
+
+enum {
+    FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_VENDOR,
+};
 
 /**
  * This interface has the stability of the vendor image.
@@ -31,7 +46,12 @@
     AIBinder_markVendorStability(binder);
 }
 
-#else  // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#else  // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) &&
+       // !defined(__ANDROID_APEX__))
+
+enum {
+    FLAG_PRIVATE_LOCAL = 0,
+};
 
 /**
  * This interface has the stability of the system image.
@@ -42,7 +62,8 @@
     AIBinder_markSystemStability(binder);
 }
 
-#endif  // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#endif  // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) &&
+        // !defined(__ANDROID_APEX__))
 
 /**
  * This interface has system<->vendor stability
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index ae2276e..f18e118 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -50,7 +50,7 @@
     if (length < -1) return STATUS_BAD_VALUE;
 
     if (!isNullArray && length < 0) {
-        LOG(ERROR) << __func__ << ": null array must be used with length == -1.";
+        LOG(ERROR) << __func__ << ": non-null array but length is " << length;
         return STATUS_BAD_VALUE;
     }
     if (isNullArray && length > 0) {
diff --git a/libs/binder/ndk/scripts/format.sh b/libs/binder/ndk/scripts/format.sh
deleted file mode 100755
index 698d291..0000000
--- a/libs/binder/ndk/scripts/format.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-
-# 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.
-
-set -e
-
-echo "Formatting code"
-
-bpfmt -w $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -name "Android.bp")
-clang-format -i $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -\( -name "*.cpp" -o -name "*.h" -\))
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index bb1fe2f..ebd08b2 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -67,3 +67,32 @@
     srcs: ["main_server.cpp"],
     gtest: false,
 }
+
+cc_test {
+    name: "binderVendorDoubleLoadTest",
+    vendor: true,
+    srcs: [
+        "binderVendorDoubleLoadTest.cpp",
+    ],
+    static_libs: [
+        "IBinderVendorDoubleLoadTest-cpp",
+        "IBinderVendorDoubleLoadTest-ndk_platform",
+        "libbinder_aidl_test_stub-ndk_platform",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libbinder_ndk",
+        "libutils",
+    ],
+    test_suites: ["device-tests"],
+}
+
+aidl_interface {
+    name: "IBinderVendorDoubleLoadTest",
+    // TODO(b/119771576): only vendor is needed
+    vendor_available: true,
+    srcs: [
+        "IBinderVendorDoubleLoadTest.aidl",
+    ],
+}
diff --git a/libs/binder/ndk/test/AndroidTest.xml b/libs/binder/ndk/test/AndroidTest.xml
new file mode 100644
index 0000000..89646f7
--- /dev/null
+++ b/libs/binder/ndk/test/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs binderVendorDoubleLoadTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="binderVendorDoubleLoadTest->/data/nativetest/vendor/binderVendorDoubleLoadTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/nativetest/vendor" />
+        <option name="module-name" value="binderVendorDoubleLoadTest" />
+    </test>
+</configuration>
+
diff --git a/libs/binder/fuzzer/parcel.h b/libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl
similarity index 84%
copy from libs/binder/fuzzer/parcel.h
copy to libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl
index 5f05335..3a5bd9c 100644
--- a/libs/binder/fuzzer/parcel.h
+++ b/libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-template <typename P>
-using ParcelRead = std::function<void(const P& p, uint8_t data)>;
-
-
+interface IBinderVendorDoubleLoadTest {
+    @utf8InCpp String RepeatString(@utf8InCpp String toRepeat);
+}
diff --git a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
new file mode 100644
index 0000000..d3ccdc2
--- /dev/null
+++ b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <BnBinderVendorDoubleLoadTest.h>
+#include <aidl/BnBinderVendorDoubleLoadTest.h>
+#include <aidl/android/os/IServiceManager.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_stability.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/Stability.h>
+#include <binder/Status.h>
+#include <gtest/gtest.h>
+
+#include <sys/prctl.h>
+
+using namespace android;
+using ::android::base::EndsWith;
+using ::android::base::GetProperty;
+using ::android::base::Split;
+using ::android::binder::Status;
+using ::android::internal::Stability;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
+using ::ndk::SpAIBinder;
+
+static const std::string kLocalNdkServerName = "NdkServer-local-IBinderVendorDoubleLoadTest";
+static const std::string kRemoteNdkServerName = "NdkServer-remote-IBinderVendorDoubleLoadTest";
+
+class NdkServer : public aidl::BnBinderVendorDoubleLoadTest {
+    ScopedAStatus RepeatString(const std::string& in, std::string* out) override {
+        *out = in;
+        return ScopedAStatus::ok();
+    }
+};
+class CppServer : public BnBinderVendorDoubleLoadTest {
+    Status RepeatString(const std::string& in, std::string* out) override {
+        *out = in;
+        return Status::ok();
+    }
+};
+
+TEST(DoubleBinder, VendorCppCantCallIntoSystem) {
+    Vector<String16> services = defaultServiceManager()->listServices();
+    EXPECT_TRUE(services.empty());
+}
+
+TEST(DoubleBinder, VendorCppCantRegisterService) {
+    sp<CppServer> cppServer = new CppServer;
+    status_t status = defaultServiceManager()->addService(String16("anything"), cppServer);
+    EXPECT_EQ(EX_TRANSACTION_FAILED, status);
+}
+
+TEST(DoubleBinder, CppVendorCantManuallyMarkVintfStability) {
+    // this test also implies that stability logic is turned on in vendor
+    ASSERT_DEATH(
+            {
+                sp<IBinder> binder = new CppServer();
+                Stability::markVintf(binder.get());
+            },
+            "Should only mark known object.");
+}
+
+TEST(DoubleBinder, NdkVendorCantManuallyMarkVintfStability) {
+    // this test also implies that stability logic is turned on in vendor
+    ASSERT_DEATH(
+            {
+                std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>();
+                AIBinder_markVintfStability(ndkServer->asBinder().get());
+            },
+            "Should only mark known object.");
+}
+
+TEST(DoubleBinder, CallIntoNdk) {
+    for (const std::string& serviceName : {kLocalNdkServerName, kRemoteNdkServerName}) {
+        SpAIBinder binder = SpAIBinder(AServiceManager_checkService(serviceName.c_str()));
+        ASSERT_NE(nullptr, binder.get()) << serviceName;
+        EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get())) << serviceName;
+
+        std::shared_ptr<aidl::IBinderVendorDoubleLoadTest> server =
+                aidl::IBinderVendorDoubleLoadTest::fromBinder(binder);
+
+        ASSERT_NE(nullptr, server.get()) << serviceName;
+
+        EXPECT_EQ(STATUS_OK, AIBinder_ping(server->asBinder().get()));
+
+        std::string outString;
+        ScopedAStatus status = server->RepeatString("foo", &outString);
+        EXPECT_EQ(STATUS_OK, AStatus_getExceptionCode(status.get())) << serviceName;
+        EXPECT_EQ("foo", outString) << serviceName;
+    }
+}
+
+TEST(DoubleBinder, CallIntoSystemStabilityNdk) {
+    // picking an arbitrary system service
+    SpAIBinder binder = SpAIBinder(AServiceManager_checkService("manager"));
+    ASSERT_NE(nullptr, binder.get());
+
+    // can make stable transaction to system server
+    EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+
+    using aidl::android::os::IServiceManager;
+    std::shared_ptr<IServiceManager> manager = IServiceManager::fromBinder(binder);
+    ASSERT_NE(nullptr, manager.get());
+
+    std::vector<std::string> services;
+    ASSERT_EQ(
+            STATUS_BAD_TYPE,
+            manager->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &services).getStatus());
+}
+
+void initDrivers() {
+    // Explicitly instantiated with the same driver that system would use.
+    // __ANDROID_VNDK__ right now uses /dev/vndbinder by default.
+    ProcessState::initWithDriver("/dev/binder");
+    ProcessState::self()->startThreadPool();
+    ABinderProcess_startThreadPool();
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    if (fork() == 0) {
+        // child process
+
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+        initDrivers();
+
+        // REMOTE SERVERS
+        std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>();
+        CHECK(STATUS_OK == AServiceManager_addService(ndkServer->asBinder().get(),
+                                                      kRemoteNdkServerName.c_str()));
+
+        // OR sleep forever or whatever, it doesn't matter
+        IPCThreadState::self()->joinThreadPool(true);
+        exit(1);  // should not reach
+    }
+
+    sleep(1);
+
+    initDrivers();
+
+    // LOCAL SERVERS
+    std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>();
+    AServiceManager_addService(ndkServer->asBinder().get(), kLocalNdkServerName.c_str());
+
+    return RUN_ALL_TESTS();
+}
diff --git a/libs/binder/ndk/update.sh b/libs/binder/ndk/update.sh
deleted file mode 100755
index 1eba892..0000000
--- a/libs/binder/ndk/update.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-
-# 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.
-
-
-set -ex
-
-# This script makes sure that the source code is in sync with the various scripts
-./scripts/gen_parcel_helper.py
-./scripts/format.sh
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index 0bee56c..1f2779a 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -134,18 +134,15 @@
 TEST(BinderStability, VintfStabilityServerMustBeDeclaredInManifest) {
     sp<IBinder> vintfServer = BadStableBinder::vintf();
 
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-        android::defaultServiceManager()->addService(String16("."), vintfServer));
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-        android::defaultServiceManager()->addService(String16("/"), vintfServer));
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-        android::defaultServiceManager()->addService(String16("/."), vintfServer));
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-        android::defaultServiceManager()->addService(String16("a.d.IFoo"), vintfServer));
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-        android::defaultServiceManager()->addService(String16("foo"), vintfServer));
-    EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
-        android::defaultServiceManager()->addService(String16("a.d.IFoo/foo"), vintfServer));
+    for (const char* instance8 : {
+        ".", "/", "/.", "a.d.IFoo", "foo", "a.d.IFoo/foo"
+    }) {
+        String16 instance (instance8);
+
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+            android::defaultServiceManager()->addService(String16("."), vintfServer)) << instance8;
+        EXPECT_FALSE(android::defaultServiceManager()->isDeclared(instance)) << instance8;
+    }
 }
 
 TEST(BinderStability, CantCallVendorBinderInSystemContext) {
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index 9080ce1..a8f7d92 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -8,6 +8,7 @@
         "liblog",
         "libnetdutils"
     ],
+    header_libs: ["bpf_prog_headers"],
     cflags: [
         "-Werror",
         "-Wall",
@@ -25,6 +26,7 @@
         "libtimeinstate",
         "libnetdutils",
     ],
+    header_libs: ["bpf_prog_headers"],
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index f255512..45fea85 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -17,7 +17,7 @@
 #define LOG_TAG "libtimeinstate"
 
 #include "cputimeinstate.h"
-#include "timeinstate.h"
+#include <bpf_timeinstate.h>
 
 #include <dirent.h>
 #include <errno.h>
@@ -110,9 +110,10 @@
             std::string path =
                     StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name);
             auto nums = readNumbersFromFile(path);
-            if (!nums) return false;
+            if (!nums) continue;
             freqs.insert(freqs.end(), nums->begin(), nums->end());
         }
+        if (freqs.empty()) return false;
         std::sort(freqs.begin(), freqs.end());
         gPolicyFreqs.emplace_back(freqs);
 
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 15f6214..c0cd3e0 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -1,5 +1,5 @@
 
-#include "timeinstate.h"
+#include <bpf_timeinstate.h>
 
 #include <sys/sysinfo.h>
 
diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h
deleted file mode 100644
index 6d4f913..0000000
--- a/libs/cputimeinstate/timeinstate.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-
-#define BPF_FS_PATH "/sys/fs/bpf/"
-
-#define FREQS_PER_ENTRY 32
-#define CPUS_PER_ENTRY 8
-
-struct time_key_t {
-    uint32_t uid;
-    uint32_t bucket;
-};
-
-struct tis_val_t {
-    uint64_t ar[FREQS_PER_ENTRY];
-};
-
-struct concurrent_val_t {
-    uint64_t active[CPUS_PER_ENTRY];
-    uint64_t policy[CPUS_PER_ENTRY];
-};
-
-struct freq_idx_key_t {
-    uint32_t policy;
-    uint32_t freq;
-};
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 30f5f73..2859111 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -307,6 +307,13 @@
     }
 }
 
+bool GraphicsEnv::setInjectLayersPrSetDumpable() {
+    if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
+        return false;
+    }
+    return true;
+}
+
 void* GraphicsEnv::loadLibrary(std::string name) {
     const android_dlextinfo dlextinfo = {
             .flags = ANDROID_DLEXT_USE_NAMESPACE,
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index a47f468..83448d4 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -68,6 +68,14 @@
     void setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime);
 
     /*
+     * Api for Vk/GL layer injection.  Presently, drivers enable certain
+     * profiling features when prctl(PR_GET_DUMPABLE) returns true.
+     * Calling this when layer injection metadata is present allows the driver
+     * to enable profiling even when in a non-debuggable app
+     */
+    bool setInjectLayersPrSetDumpable();
+
+    /*
      * Apis for ANGLE
      */
     // Check if the requested app should use ANGLE.
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 3f8b436..b360a26 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -17,8 +17,16 @@
     export_include_dirs: ["include"],
 
     // we must build this module to get the required header as that is generated
-    export_shared_lib_headers: [ "android.hidl.token@1.0-utils" ],
-    shared_libs: [ "android.hidl.token@1.0-utils" ],
+    export_shared_lib_headers: [
+        "android.hidl.token@1.0-utils",
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+    ],
+    shared_libs: [
+        "android.hidl.token@1.0-utils",
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+    ],
 }
 
 cc_library_shared {
@@ -32,7 +40,10 @@
     defaults: ["libgui_bufferqueue-defaults"],
 
     srcs: [
+        ":libgui_bufferqueue_sources",
+
         "BitTube.cpp",
+        "BLASTBufferQueue.cpp",
         "BufferHubConsumer.cpp",
         "BufferHubProducer.cpp",
         "BufferItemConsumer.cpp",
@@ -104,32 +115,14 @@
     ],
 
     defaults: ["libgui_bufferqueue-defaults"],
+
+    srcs: [
+        ":libgui_bufferqueue_sources",
+    ],
 }
 
-// Common build config shared by libgui and libgui_bufferqueue_static.
-cc_defaults {
-    name: "libgui_bufferqueue-defaults",
-
-    clang: true,
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-
-    cppflags: [
-        "-Wextra",
-        "-DDEBUG_ONLY_CODE=0",
-    ],
-
-    product_variables: {
-        eng: {
-            cppflags: [
-                "-UDEBUG_ONLY_CODE",
-                "-DDEBUG_ONLY_CODE=1",
-            ],
-        },
-    },
-
+filegroup {
+    name: "libgui_bufferqueue_sources",
     srcs: [
         "BufferItem.cpp",
         "BufferQueue.cpp",
@@ -157,6 +150,31 @@
         "bufferqueue/2.0/H2BProducerListener.cpp",
         "bufferqueue/2.0/types.cpp",
     ],
+}
+
+// Common build config shared by libgui and libgui_bufferqueue_static.
+cc_defaults {
+    name: "libgui_bufferqueue-defaults",
+
+    clang: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    cppflags: [
+        "-Wextra",
+        "-DDEBUG_ONLY_CODE=0",
+    ],
+
+    product_variables: {
+        eng: {
+            cppflags: [
+                "-UDEBUG_ONLY_CODE",
+                "-DDEBUG_ONLY_CODE=1",
+            ],
+        },
+    },
 
     shared_libs: [
         "android.hardware.graphics.bufferqueue@1.0",
@@ -204,4 +222,21 @@
     ],
 }
 
+// GMocks for use by external code
+cc_library_static {
+    name: "libgui_mocks",
+    vendor_available: false,
+
+    defaults: ["libgui_bufferqueue-defaults"],
+    static_libs: [
+        "libgtest",
+        "libgmock",
+    ],
+
+    srcs: [
+        "mock/GraphicBufferConsumer.cpp",
+        "mock/GraphicBufferProducer.cpp",
+    ],
+}
+
 subdirs = ["tests"]
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
new file mode 100644
index 0000000..9a50175
--- /dev/null
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/BLASTBufferQueue.h>
+#include <gui/BufferItemConsumer.h>
+
+#include <chrono>
+
+using namespace std::chrono_literals;
+
+namespace android {
+
+BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height)
+      : mSurfaceControl(surface), mWidth(width), mHeight(height) {
+    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+    mBufferItemConsumer =
+            new BufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
+    mBufferItemConsumer->setName(String8("BLAST Consumer"));
+    mBufferItemConsumer->setFrameAvailableListener(this);
+    mBufferItemConsumer->setBufferFreedListener(this);
+    mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
+    mBufferItemConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888);
+}
+
+void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, int width, int height) {
+    std::unique_lock _lock{mMutex};
+    mSurfaceControl = surface;
+    mWidth = width;
+    mHeight = height;
+    mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
+}
+
+static void transactionCallbackThunk(void* context, nsecs_t latchTime,
+                                     const sp<Fence>& presentFence,
+                                     const std::vector<SurfaceControlStats>& stats) {
+    if (context == nullptr) {
+        return;
+    }
+    BLASTBufferQueue* bq = static_cast<BLASTBufferQueue*>(context);
+    bq->transactionCallback(latchTime, presentFence, stats);
+}
+
+void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/,
+                                           const std::vector<SurfaceControlStats>& stats) {
+    std::unique_lock _lock{mMutex};
+
+    if (stats.size() > 0 && mNextCallbackBufferItem.mGraphicBuffer != nullptr) {
+        mBufferItemConsumer->releaseBuffer(mNextCallbackBufferItem,
+                                           stats[0].previousReleaseFence
+                                                   ? stats[0].previousReleaseFence
+                                                   : Fence::NO_FENCE);
+        mNextCallbackBufferItem = BufferItem();
+    }
+    mDequeueWaitCV.notify_all();
+    decStrong((void*)transactionCallbackThunk);
+}
+
+void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
+    std::unique_lock _lock{mMutex};
+
+    SurfaceComposerClient::Transaction localTransaction;
+    bool applyTransaction = true;
+    SurfaceComposerClient::Transaction* t = &localTransaction;
+    if (mNextTransaction != nullptr) {
+        t = mNextTransaction;
+        mNextTransaction = nullptr;
+        applyTransaction = false;
+    }
+
+    int status = OK;
+    mNextCallbackBufferItem = mLastSubmittedBufferItem;
+
+    mLastSubmittedBufferItem = BufferItem();
+    status = mBufferItemConsumer->acquireBuffer(&mLastSubmittedBufferItem, -1, false);
+    if (status != OK) {
+        ALOGE("Failed to acquire?");
+    }
+
+    auto buffer = mLastSubmittedBufferItem.mGraphicBuffer;
+
+    if (buffer == nullptr) {
+        ALOGE("Null buffer");
+        return;
+    }
+
+
+    // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
+    incStrong((void*)transactionCallbackThunk);
+
+    t->setBuffer(mSurfaceControl, buffer);
+    t->setAcquireFence(mSurfaceControl,
+                       item.mFence ? new Fence(item.mFence->dup()) : Fence::NO_FENCE);
+    t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
+
+    t->setFrame(mSurfaceControl, {0, 0, (int32_t)buffer->getWidth(), (int32_t)buffer->getHeight()});
+    t->setCrop(mSurfaceControl, {0, 0, (int32_t)buffer->getWidth(), (int32_t)buffer->getHeight()});
+
+    if (applyTransaction) {
+        ALOGE("Apply transaction");
+        t->apply();
+
+        if (mNextCallbackBufferItem.mGraphicBuffer != nullptr) {
+            mDequeueWaitCV.wait_for(_lock, 5000ms);
+        }
+    }
+}
+
+void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) {
+    std::unique_lock _lock{mMutex};
+    mNextTransaction = t;
+}
+
+} // namespace android
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 5fb3f0b..c1d92a2 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -43,6 +43,27 @@
     }
 }
 
+void BufferQueue::ProxyConsumerListener::onFrameDequeued(const uint64_t bufferId) {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != nullptr) {
+        listener->onFrameDequeued(bufferId);
+    }
+}
+
+void BufferQueue::ProxyConsumerListener::onFrameCancelled(const uint64_t bufferId) {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != nullptr) {
+        listener->onFrameCancelled(bufferId);
+    }
+}
+
+void BufferQueue::ProxyConsumerListener::onFrameDetached(const uint64_t bufferId) {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != nullptr) {
+        listener->onFrameDetached(bufferId);
+    }
+}
+
 void BufferQueue::ProxyConsumerListener::onFrameAvailable(
         const BufferItem& item) {
     sp<ConsumerListener> listener(mConsumerListener.promote());
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 5674674..09c74de 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -580,6 +580,11 @@
     }
     addAndGetFrameTimestamps(nullptr, outTimestamps);
 
+    { // Autolock scope
+        std::lock_guard<std::mutex> lock(mCore->mMutex);
+        mCore->mConsumerListener->onFrameDequeued(mSlots[*outSlot].mGraphicBuffer->getId());
+    }
+
     return returnFlags;
 }
 
@@ -621,13 +626,16 @@
             return BAD_VALUE;
         }
 
+        listener = mCore->mConsumerListener;
+        if (listener != nullptr) {
+            listener->onFrameDetached(mSlots[slot].mGraphicBuffer->getId());
+        }
         mSlots[slot].mBufferState.detachProducer();
         mCore->mActiveBuffers.erase(slot);
         mCore->mFreeSlots.insert(slot);
         mCore->clearBufferSlotLocked(slot);
         mCore->mDequeueCondition.notify_all();
         VALIDATE_CONSISTENCY();
-        listener = mCore->mConsumerListener;
     }
 
     if (listener != nullptr) {
@@ -1083,6 +1091,9 @@
         mCore->mFreeBuffers.push_back(slot);
     }
 
+    if (mCore->mConsumerListener != nullptr) {
+        mCore->mConsumerListener->onFrameCancelled(mSlots[slot].mGraphicBuffer->getId());
+    }
     mSlots[slot].mFence = fence;
     mCore->mDequeueCondition.notify_all();
     VALIDATE_CONSISTENCY();
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index abd9921..9f91d9d 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -101,6 +101,48 @@
     mSlots[slotIndex].mFrameNumber = 0;
 }
 
+void ConsumerBase::onFrameDequeued(const uint64_t bufferId) {
+    CB_LOGV("onFrameDequeued");
+
+    sp<FrameAvailableListener> listener;
+    {
+        Mutex::Autolock lock(mFrameAvailableMutex);
+        listener = mFrameAvailableListener.promote();
+    }
+
+    if (listener != nullptr) {
+        listener->onFrameDequeued(bufferId);
+    }
+}
+
+void ConsumerBase::onFrameCancelled(const uint64_t bufferId) {
+    CB_LOGV("onFrameCancelled");
+
+    sp<FrameAvailableListener> listener;
+    {
+        Mutex::Autolock lock(mFrameAvailableMutex);
+        listener = mFrameAvailableListener.promote();
+    }
+
+    if (listener != nullptr) {
+        listener->onFrameCancelled(bufferId);
+    }
+}
+
+void ConsumerBase::onFrameDetached(const uint64_t bufferId) {
+    CB_LOGV("onFrameDetached");
+
+    sp<FrameAvailableListener> listener;
+    {
+        Mutex::Autolock lock(mFrameAvailableMutex);
+        listener = mFrameAvailableListener.promote();
+    }
+
+    if (listener != nullptr) {
+        listener->onFrameDetached(bufferId);
+    }
+}
+
 void ConsumerBase::onFrameAvailable(const BufferItem& item) {
     CB_LOGV("onFrameAvailable");
 
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index 85ac304..48cb4b9 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -28,7 +28,10 @@
     ON_FRAME_REPLACED,
     ON_BUFFERS_RELEASED,
     ON_SIDEBAND_STREAM_CHANGED,
-    LAST = ON_SIDEBAND_STREAM_CHANGED,
+    ON_FRAME_DEQUEUED,
+    ON_FRAME_CANCELLED,
+    ON_FRAME_DETACHED,
+    LAST = ON_FRAME_DETACHED,
 };
 
 } // Anonymous namespace
@@ -44,6 +47,21 @@
         callRemoteAsync<decltype(&IConsumerListener::onDisconnect)>(Tag::ON_DISCONNECT);
     }
 
+    void onFrameDequeued(const uint64_t bufferId) override {
+        callRemoteAsync<decltype(&IConsumerListener::onFrameDequeued)>(Tag::ON_FRAME_DEQUEUED,
+                                                                       bufferId);
+    }
+
+    void onFrameDetached(const uint64_t bufferId) override {
+        callRemoteAsync<decltype(&IConsumerListener::onFrameDetached)>(Tag::ON_FRAME_DETACHED,
+                                                                       bufferId);
+    }
+
+    void onFrameCancelled(const uint64_t bufferId) override {
+        callRemoteAsync<decltype(&IConsumerListener::onFrameCancelled)>(Tag::ON_FRAME_CANCELLED,
+                                                                        bufferId);
+    }
+
     void onFrameAvailable(const BufferItem& item) override {
         callRemoteAsync<decltype(&IConsumerListener::onFrameAvailable)>(Tag::ON_FRAME_AVAILABLE,
                                                                         item);
@@ -93,6 +111,12 @@
             return callLocalAsync(data, reply, &IConsumerListener::onBuffersReleased);
         case Tag::ON_SIDEBAND_STREAM_CHANGED:
             return callLocalAsync(data, reply, &IConsumerListener::onSidebandStreamChanged);
+        case Tag::ON_FRAME_DEQUEUED:
+            return callLocalAsync(data, reply, &IConsumerListener::onFrameDequeued);
+        case Tag::ON_FRAME_CANCELLED:
+            return callLocalAsync(data, reply, &IConsumerListener::onFrameCancelled);
+        case Tag::ON_FRAME_DETACHED:
+            return callLocalAsync(data, reply, &IConsumerListener::onFrameDetached);
     }
 }
 
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index acda600..e5e25aa 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -48,6 +48,7 @@
     } else {
         err = output->writeBool(false);
     }
+    err = output->writeUint32(transformHint);
     return err;
 }
 
@@ -72,7 +73,8 @@
             return err;
         }
     }
-    return NO_ERROR;
+    err = input->readUint32(&transformHint);
+    return err;
 }
 
 status_t TransactionStats::writeToParcel(Parcel* output) const {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7b256f5..e9079ef 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -222,7 +222,8 @@
             for (const auto& surfaceStats : transactionStats.surfaceStats) {
                 surfaceControlStats.emplace_back(surfaceControls[surfaceStats.surfaceControl],
                                                  surfaceStats.acquireTime,
-                                                 surfaceStats.previousReleaseFence);
+                                                 surfaceStats.previousReleaseFence,
+                                                 surfaceStats.transformHint);
             }
 
             callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
new file mode 100644
index 0000000..6320556
--- /dev/null
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BLAST_BUFFER_QUEUE_H
+#define ANDROID_GUI_BLAST_BUFFER_QUEUE_H
+
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/BufferItem.h>
+#include <gui/SurfaceComposerClient.h>
+
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+#include <system/window.h>
+
+namespace android {
+
+class BufferItemConsumer;
+
+class BLASTBufferQueue
+    : public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener
+{
+public:
+    BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height);
+    sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
+        return mProducer;
+    }
+
+    void onBufferFreed(const wp<GraphicBuffer>&/* graphicBuffer*/) override { /* TODO */ }
+    void onFrameReplaced(const BufferItem& item) override {onFrameAvailable(item);}
+    void onFrameAvailable(const BufferItem& item) override;
+
+    void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
+            const std::vector<SurfaceControlStats>& stats);
+    void setNextTransaction(SurfaceComposerClient::Transaction *t);
+
+    void update(const sp<SurfaceControl>& surface, int width, int height);
+    
+
+    virtual ~BLASTBufferQueue() = default;
+
+private:
+    friend class BLASTBufferQueueHelper;
+
+    // can't be copied
+    BLASTBufferQueue& operator = (const BLASTBufferQueue& rhs);
+    BLASTBufferQueue(const BLASTBufferQueue& rhs);
+
+    sp<SurfaceControl> mSurfaceControl;
+    
+    mutable std::mutex mMutex;
+
+    static const int MAX_BUFFERS = 2;
+    struct BufferInfo {
+        sp<GraphicBuffer> buffer;
+        int fence;
+    };
+    
+    int mDequeuedBuffers = 0;
+
+    int mWidth;
+    int mHeight;
+
+    BufferItem mLastSubmittedBufferItem;
+    BufferItem mNextCallbackBufferItem;
+    sp<Fence> mLastFence;
+
+    std::condition_variable mDequeueWaitCV;
+
+    sp<IGraphicBufferConsumer> mConsumer;
+    sp<IGraphicBufferProducer> mProducer;
+    sp<BufferItemConsumer> mBufferItemConsumer;
+
+    SurfaceComposerClient::Transaction* mNextTransaction = nullptr;
+};
+
+} // namespace android
+
+#endif  // ANDROID_GUI_SURFACE_H
diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
index da95274..91f80d2 100644
--- a/libs/gui/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -63,6 +63,9 @@
         void onFrameReplaced(const BufferItem& item) override;
         void onBuffersReleased() override;
         void onSidebandStreamChanged() override;
+        void onFrameDequeued(const uint64_t bufferId) override;
+        void onFrameCancelled(const uint64_t bufferId) override;
+        void onFrameDetached(const uint64_t bufferID) override;
         void addAndGetFrameTimestamps(
                 const NewFrameEventsEntry* newTimestamps,
                 FrameEventHistoryDelta* outDelta) override;
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index 366ced3..8ff0cd0 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -45,6 +45,9 @@
         // See IConsumerListener::onFrame{Available,Replaced}
         virtual void onFrameAvailable(const BufferItem& item) = 0;
         virtual void onFrameReplaced(const BufferItem& /* item */) {}
+        virtual void onFrameDequeued(const uint64_t){};
+        virtual void onFrameCancelled(const uint64_t){};
+        virtual void onFrameDetached(const uint64_t){};
     };
 
     ~ConsumerBase() override;
@@ -141,6 +144,9 @@
     // classes if they want the notification.
     virtual void onFrameAvailable(const BufferItem& item) override;
     virtual void onFrameReplaced(const BufferItem& item) override;
+    virtual void onFrameDequeued(const uint64_t bufferId) override;
+    virtual void onFrameCancelled(const uint64_t bufferId) override;
+    virtual void onFrameDetached(const uint64_t bufferId) override;
     virtual void onBuffersReleased() override;
     virtual void onSidebandStreamChanged() override;
 
diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h
index c082882..046f6e1 100644
--- a/libs/gui/include/gui/IConsumerListener.h
+++ b/libs/gui/include/gui/IConsumerListener.h
@@ -43,6 +43,17 @@
     // onDisconnect is called when a producer disconnects from the BufferQueue.
     virtual void onDisconnect() {} /* Asynchronous */
 
+    // onFrameDequeued is called when a call to the BufferQueueProducer::dequeueBuffer successfully
+    // returns a slot from the BufferQueue.
+    virtual void onFrameDequeued(const uint64_t) {}
+
+    // onFrameCancelled is called when the client calls cancelBuffer, thereby releasing the slot
+    // back to the BufferQueue.
+    virtual void onFrameCancelled(const uint64_t) {}
+
+    // onFrameDetached is called after a successful detachBuffer() call while in asynchronous mode.
+    virtual void onFrameDetached(const uint64_t) {}
+
     // onFrameAvailable is called from queueBuffer each time an additional frame becomes available
     // for consumption. This means that frames that are queued while in asynchronous mode only
     // trigger the callback if no previous frames are pending. Frames queued while in synchronous
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 178ca2d..9c15225 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -41,12 +41,17 @@
     status_t readFromParcel(const Parcel* input) override;
 
     SurfaceStats() = default;
-    SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence)
-          : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {}
+    SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
+                 uint32_t hint)
+          : surfaceControl(sc),
+            acquireTime(time),
+            previousReleaseFence(prevReleaseFence),
+            transformHint(hint) {}
 
     sp<IBinder> surfaceControl;
     nsecs_t acquireTime = -1;
     sp<Fence> previousReleaseFence;
+    uint32_t transformHint = 0;
 };
 
 class TransactionStats : public Parcelable {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 6676be4..08f4e9e 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -58,12 +58,16 @@
 
 struct SurfaceControlStats {
     SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t time,
-                        const sp<Fence>& prevReleaseFence)
-          : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {}
+                        const sp<Fence>& prevReleaseFence, uint32_t hint)
+          : surfaceControl(sc),
+            acquireTime(time),
+            previousReleaseFence(prevReleaseFence),
+            transformHint(hint) {}
 
     sp<SurfaceControl> surfaceControl;
     nsecs_t acquireTime = -1;
     sp<Fence> previousReleaseFence;
+    uint32_t transformHint = 0;
 };
 
 using TransactionCompletedCallbackTakesContext =
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.h b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
similarity index 100%
rename from services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.h
rename to libs/gui/include/gui/mock/GraphicBufferConsumer.h
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.h b/libs/gui/include/gui/mock/GraphicBufferProducer.h
similarity index 100%
rename from services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.h
rename to libs/gui/include/gui/mock/GraphicBufferProducer.h
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp b/libs/gui/mock/GraphicBufferConsumer.cpp
similarity index 94%
rename from services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp
rename to libs/gui/mock/GraphicBufferConsumer.cpp
index a17b73f..4a6c081 100644
--- a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp
+++ b/libs/gui/mock/GraphicBufferConsumer.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "mock/gui/MockGraphicBufferConsumer.h"
+#include <gui/mock/GraphicBufferConsumer.h>
 
 namespace android {
 namespace mock {
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp b/libs/gui/mock/GraphicBufferProducer.cpp
similarity index 94%
rename from services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp
rename to libs/gui/mock/GraphicBufferProducer.cpp
index a7fd667..239a80a 100644
--- a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp
+++ b/libs/gui/mock/GraphicBufferProducer.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "mock/gui/MockGraphicBufferProducer.h"
+#include <gui/mock/GraphicBufferProducer.h>
 
 namespace android {
 namespace mock {
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index cbda6b2..7f960ab 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -13,7 +13,8 @@
     ],
 
     srcs: [
-        "BufferItemConsumer_test.cpp",
+        "BLASTBufferQueue_test.cpp",
+	"BufferItemConsumer_test.cpp",
         "BufferQueue_test.cpp",
         "CpuConsumer_test.cpp",
         "EndToEndNativeInputTest.cpp",
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
new file mode 100644
index 0000000..db1ac24
--- /dev/null
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BLASTBufferQueue_test"
+
+#include <gui/BLASTBufferQueue.h>
+
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <ui/DisplayInfo.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
+
+#include <gtest/gtest.h>
+
+using namespace std::chrono_literals;
+
+namespace android {
+
+using Transaction = SurfaceComposerClient::Transaction;
+using android::hardware::graphics::common::V1_2::BufferUsage;
+
+class BLASTBufferQueueHelper {
+public:
+    BLASTBufferQueueHelper(const sp<SurfaceControl>& sc, int width, int height) {
+        mBlastBufferQueueAdapter = new BLASTBufferQueue(sc, width, height);
+    }
+
+    void update(const sp<SurfaceControl>& sc, int width, int height) {
+        mBlastBufferQueueAdapter->update(sc, width, height);
+    }
+
+    void setNextTransaction(Transaction* next) {
+        mBlastBufferQueueAdapter->setNextTransaction(next);
+    }
+
+    int getWidth() { return mBlastBufferQueueAdapter->mWidth; }
+
+    int getHeight() { return mBlastBufferQueueAdapter->mHeight; }
+
+    Transaction* getNextTransaction() { return mBlastBufferQueueAdapter->mNextTransaction; }
+
+    sp<IGraphicBufferProducer> getIGraphicBufferProducer() {
+        return mBlastBufferQueueAdapter->getIGraphicBufferProducer();
+    }
+
+    const sp<SurfaceControl> getSurfaceControl() {
+        return mBlastBufferQueueAdapter->mSurfaceControl;
+    }
+
+    void waitForCallback() {
+        std::unique_lock lock{mBlastBufferQueueAdapter->mMutex};
+        mBlastBufferQueueAdapter->mDequeueWaitCV.wait_for(lock, 1s);
+    }
+
+private:
+    sp<BLASTBufferQueue> mBlastBufferQueueAdapter;
+};
+
+class BLASTBufferQueueTest : public ::testing::Test {
+public:
+protected:
+    BLASTBufferQueueTest() {
+        const ::testing::TestInfo* const testInfo =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGV("Begin test: %s.%s", testInfo->test_case_name(), testInfo->name());
+    }
+
+    ~BLASTBufferQueueTest() {
+        const ::testing::TestInfo* const testInfo =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGV("End test:   %s.%s", testInfo->test_case_name(), testInfo->name());
+    }
+
+    void SetUp() {
+        mComposer = ComposerService::getComposerService();
+        mClient = new SurfaceComposerClient();
+        mDisplayToken = mClient->getInternalDisplayToken();
+        ASSERT_NE(nullptr, mDisplayToken.get());
+        Transaction t;
+        t.setDisplayLayerStack(mDisplayToken, 0);
+        t.apply();
+        t.clear();
+
+        DisplayInfo info;
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplayToken, &info));
+        mDisplayWidth = info.w;
+        mDisplayHeight = info.h;
+
+        mSurfaceControl = mClient->createSurface(String8("TestSurface"), mDisplayWidth,
+                                                 mDisplayHeight, PIXEL_FORMAT_RGBA_8888,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState,
+                                                 /*parent*/ nullptr);
+        t.setLayerStack(mSurfaceControl, 0)
+                .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
+                .setFrame(mSurfaceControl, Rect(0, 0, mDisplayWidth, mDisplayHeight))
+                .show(mSurfaceControl)
+                .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB)
+                .apply();
+    }
+
+    void fillBuffer(uint32_t* bufData, uint32_t width, uint32_t height, uint32_t stride, uint8_t r,
+                    uint8_t g, uint8_t b) {
+        for (uint32_t row = 0; row < height; row++) {
+            for (uint32_t col = 0; col < width; col++) {
+                uint8_t* pixel = (uint8_t*)(bufData + (row * stride) + col);
+                *pixel = r;
+                *(pixel + 1) = g;
+                *(pixel + 2) = b;
+                *(pixel + 3) = 255;
+            }
+        }
+    }
+
+    void checkScreenCapture(uint8_t r, uint8_t g, uint8_t b) {
+        const auto width = mScreenCaptureBuf->getWidth();
+        const auto height = mScreenCaptureBuf->getHeight();
+        const auto stride = mScreenCaptureBuf->getStride();
+
+        uint32_t* bufData;
+        mScreenCaptureBuf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_READ_OFTEN),
+                                reinterpret_cast<void**>(&bufData));
+
+        for (uint32_t row = 0; row < height; row++) {
+            for (uint32_t col = 0; col < width; col++) {
+                uint8_t* pixel = (uint8_t*)(bufData + (row * stride) + col);
+                EXPECT_EQ(r, *(pixel));
+                EXPECT_EQ(g, *(pixel + 1));
+                EXPECT_EQ(b, *(pixel + 2));
+            }
+        }
+        mScreenCaptureBuf->unlock();
+        ASSERT_EQ(false, ::testing::Test::HasFailure());
+    }
+
+    sp<SurfaceComposerClient> mClient;
+    sp<ISurfaceComposer> mComposer;
+
+    sp<IBinder> mDisplayToken;
+
+    sp<SurfaceControl> mSurfaceControl;
+    sp<GraphicBuffer> mScreenCaptureBuf;
+
+    uint32_t mDisplayWidth;
+    uint32_t mDisplayHeight;
+};
+
+TEST_F(BLASTBufferQueueTest, CreateBLASTBufferQueue) {
+    // create BLASTBufferQueue adapter associated with this surface
+    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+    ASSERT_EQ(mSurfaceControl, adapter.getSurfaceControl());
+    ASSERT_EQ(mDisplayWidth, adapter.getWidth());
+    ASSERT_EQ(mDisplayHeight, adapter.getHeight());
+    ASSERT_EQ(nullptr, adapter.getNextTransaction());
+}
+
+TEST_F(BLASTBufferQueueTest, Update) {
+    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+    sp<SurfaceControl> updateSurface =
+            mClient->createSurface(String8("UpdateTest"), mDisplayWidth / 2, mDisplayHeight / 2,
+                                   PIXEL_FORMAT_RGBA_8888);
+    adapter.update(updateSurface, mDisplayWidth / 2, mDisplayHeight / 2);
+    ASSERT_EQ(updateSurface, adapter.getSurfaceControl());
+    ASSERT_EQ(mDisplayWidth / 2, adapter.getWidth());
+    ASSERT_EQ(mDisplayHeight / 2, adapter.getHeight());
+}
+
+TEST_F(BLASTBufferQueueTest, SetNextTransaction) {
+    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+    Transaction next;
+    adapter.setNextTransaction(&next);
+    ASSERT_EQ(&next, adapter.getNextTransaction());
+}
+
+TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) {
+    uint8_t r = 255;
+    uint8_t g = 0;
+    uint8_t b = 0;
+
+    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+    auto igbProducer = adapter.getIGraphicBufferProducer();
+    ASSERT_NE(nullptr, igbProducer.get());
+    IGraphicBufferProducer::QueueBufferOutput qbOutput;
+    ASSERT_EQ(NO_ERROR,
+              igbProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
+                                   &qbOutput));
+    ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(3));
+
+    int slot;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buf;
+    auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight,
+                                          PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                          nullptr, nullptr);
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
+    ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
+
+    uint32_t* bufData;
+    buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN),
+              reinterpret_cast<void**>(&bufData));
+    fillBuffer(bufData, buf->getWidth(), buf->getHeight(), buf->getStride(), r, g, b);
+    buf->unlock();
+
+    IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN,
+                                                   Rect(mDisplayWidth, mDisplayHeight),
+                                                   NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
+                                                   Fence::NO_FENCE);
+    igbProducer->queueBuffer(slot, input, &qbOutput);
+
+    adapter.waitForCallback();
+
+    // capture screen and verify that it is red
+    bool capturedSecureLayers;
+    ASSERT_EQ(NO_ERROR,
+              mComposer->captureScreen(mDisplayToken, &mScreenCaptureBuf, capturedSecureLayers,
+                                       ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(),
+                                       mDisplayWidth, mDisplayHeight,
+                                       /*useIdentityTransform*/ false));
+    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b));
+}
+} // namespace android
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 09eeaea..03b9cd7 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -405,12 +405,11 @@
     surface->expectTap(1, 1);
 }
 
-/**
- * TODO(b/139494112) fix tests once we define expected behavior
- *
-// Ensure we send the input to the right surface when the surface visibility changes due to the
-// first buffer being submitted. ref: b/120839715
-TEST_F(InputSurfacesTest, input_respects_buffer_layer_buffer) {
+// TODO(b/139494112) update tests once we define expected behavior
+// Ensure we still send input to the surface regardless of surface visibility changes due to the
+// first buffer being submitted or alpha changes.
+// Original bug ref: b/120839715
+TEST_F(InputSurfacesTest, input_ignores_buffer_layer_buffer) {
     std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
     std::unique_ptr<InputSurface> bufferSurface =
             InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
@@ -419,14 +418,14 @@
     bufferSurface->showAt(10, 10);
 
     injectTap(11, 11);
-    bgSurface->expectTap(1, 1);
+    bufferSurface->expectTap(1, 1);
 
     postBuffer(bufferSurface->mSurfaceControl);
     injectTap(11, 11);
     bufferSurface->expectTap(1, 1);
 }
 
-TEST_F(InputSurfacesTest, input_respects_buffer_layer_alpha) {
+TEST_F(InputSurfacesTest, input_ignores_buffer_layer_alpha) {
     std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
     std::unique_ptr<InputSurface> bufferSurface =
             InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
@@ -441,10 +440,10 @@
     bufferSurface->doTransaction([](auto &t, auto &sc) { t.setAlpha(sc, 0.0); });
 
     injectTap(11, 11);
-    bgSurface->expectTap(1, 1);
+    bufferSurface->expectTap(1, 1);
 }
 
-TEST_F(InputSurfacesTest, input_respects_color_layer_alpha) {
+TEST_F(InputSurfacesTest, input_ignores_color_layer_alpha) {
     std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
     std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
 
@@ -457,9 +456,8 @@
     fgSurface->doTransaction([](auto &t, auto &sc) { t.setAlpha(sc, 0.0); });
 
     injectTap(11, 11);
-    bgSurface->expectTap(1, 1);
+    fgSurface->expectTap(1, 1);
 }
-*/
 
 TEST_F(InputSurfacesTest, input_respects_container_layer_visiblity) {
     std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 366c93c..c4f7fe0 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -93,13 +93,12 @@
 bool InputMessage::isValid(size_t actualSize) const {
     if (size() == actualSize) {
         switch (header.type) {
-        case TYPE_KEY:
-            return true;
-        case TYPE_MOTION:
-            return body.motion.pointerCount > 0
-                    && body.motion.pointerCount <= MAX_POINTERS;
-        case TYPE_FINISHED:
-            return true;
+            case Type::KEY:
+                return true;
+            case Type::MOTION:
+                return body.motion.pointerCount > 0 && body.motion.pointerCount <= MAX_POINTERS;
+            case Type::FINISHED:
+                return true;
         }
     }
     return false;
@@ -107,12 +106,12 @@
 
 size_t InputMessage::size() const {
     switch (header.type) {
-    case TYPE_KEY:
-        return sizeof(Header) + body.key.size();
-    case TYPE_MOTION:
-        return sizeof(Header) + body.motion.size();
-    case TYPE_FINISHED:
-        return sizeof(Header) + body.finished.size();
+        case Type::KEY:
+            return sizeof(Header) + body.key.size();
+        case Type::MOTION:
+            return sizeof(Header) + body.motion.size();
+        case Type::FINISHED:
+            return sizeof(Header) + body.finished.size();
     }
     return sizeof(Header);
 }
@@ -129,7 +128,7 @@
 
     // Write the body
     switch(header.type) {
-        case InputMessage::TYPE_KEY: {
+        case InputMessage::Type::KEY: {
             // uint32_t seq
             msg->body.key.seq = body.key.seq;
             // nsecs_t eventTime
@@ -156,7 +155,7 @@
             msg->body.key.downTime = body.key.downTime;
             break;
         }
-        case InputMessage::TYPE_MOTION: {
+        case InputMessage::Type::MOTION: {
             // uint32_t seq
             msg->body.motion.seq = body.motion.seq;
             // nsecs_t eventTime
@@ -212,7 +211,7 @@
             }
             break;
         }
-        case InputMessage::TYPE_FINISHED: {
+        case InputMessage::Type::FINISHED: {
             msg->body.finished.seq = body.finished.seq;
             msg->body.finished.handled = body.finished.handled;
             break;
@@ -457,7 +456,7 @@
     }
 
     InputMessage msg;
-    msg.header.type = InputMessage::TYPE_KEY;
+    msg.header.type = InputMessage::Type::KEY;
     msg.body.key.seq = seq;
     msg.body.key.deviceId = deviceId;
     msg.body.key.source = source;
@@ -511,7 +510,7 @@
     }
 
     InputMessage msg;
-    msg.header.type = InputMessage::TYPE_MOTION;
+    msg.header.type = InputMessage::Type::MOTION;
     msg.body.motion.seq = seq;
     msg.body.motion.deviceId = deviceId;
     msg.body.motion.source = source;
@@ -553,7 +552,7 @@
         *outHandled = false;
         return result;
     }
-    if (msg.header.type != InputMessage::TYPE_FINISHED) {
+    if (msg.header.type != InputMessage::Type::FINISHED) {
         ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
                 mChannel->getName().c_str(), msg.header.type);
         return UNKNOWN_ERROR;
@@ -614,59 +613,59 @@
         }
 
         switch (mMsg.header.type) {
-        case InputMessage::TYPE_KEY: {
-            KeyEvent* keyEvent = factory->createKeyEvent();
-            if (!keyEvent) return NO_MEMORY;
+            case InputMessage::Type::KEY: {
+                KeyEvent* keyEvent = factory->createKeyEvent();
+                if (!keyEvent) return NO_MEMORY;
 
-            initializeKeyEvent(keyEvent, &mMsg);
-            *outSeq = mMsg.body.key.seq;
-            *outEvent = keyEvent;
+                initializeKeyEvent(keyEvent, &mMsg);
+                *outSeq = mMsg.body.key.seq;
+                *outEvent = keyEvent;
 #if DEBUG_TRANSPORT_ACTIONS
             ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
                     mChannel->getName().c_str(), *outSeq);
 #endif
             break;
-        }
+            }
 
-        case InputMessage::TYPE_MOTION: {
-            ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
-            if (batchIndex >= 0) {
-                Batch& batch = mBatches.editItemAt(batchIndex);
-                if (canAddSample(batch, &mMsg)) {
-                    batch.samples.push(mMsg);
+            case InputMessage::Type::MOTION: {
+                ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
+                if (batchIndex >= 0) {
+                    Batch& batch = mBatches.editItemAt(batchIndex);
+                    if (canAddSample(batch, &mMsg)) {
+                        batch.samples.push(mMsg);
 #if DEBUG_TRANSPORT_ACTIONS
                     ALOGD("channel '%s' consumer ~ appended to batch event",
                             mChannel->getName().c_str());
 #endif
                     break;
-                } else if (isPointerEvent(mMsg.body.motion.source) &&
-                        mMsg.body.motion.action == AMOTION_EVENT_ACTION_CANCEL) {
-                    // No need to process events that we are going to cancel anyways
-                    const size_t count = batch.samples.size();
-                    for (size_t i = 0; i < count; i++) {
-                        const InputMessage& msg = batch.samples.itemAt(i);
-                        sendFinishedSignal(msg.body.motion.seq, false);
-                    }
-                    batch.samples.removeItemsAt(0, count);
-                    mBatches.removeAt(batchIndex);
-                } else {
-                    // We cannot append to the batch in progress, so we need to consume
-                    // the previous batch right now and defer the new message until later.
-                    mMsgDeferred = true;
-                    status_t result = consumeSamples(factory,
-                            batch, batch.samples.size(), outSeq, outEvent);
-                    mBatches.removeAt(batchIndex);
-                    if (result) {
-                        return result;
-                    }
+                    } else if (isPointerEvent(mMsg.body.motion.source) &&
+                               mMsg.body.motion.action == AMOTION_EVENT_ACTION_CANCEL) {
+                        // No need to process events that we are going to cancel anyways
+                        const size_t count = batch.samples.size();
+                        for (size_t i = 0; i < count; i++) {
+                            const InputMessage& msg = batch.samples.itemAt(i);
+                            sendFinishedSignal(msg.body.motion.seq, false);
+                        }
+                        batch.samples.removeItemsAt(0, count);
+                        mBatches.removeAt(batchIndex);
+                    } else {
+                        // We cannot append to the batch in progress, so we need to consume
+                        // the previous batch right now and defer the new message until later.
+                        mMsgDeferred = true;
+                        status_t result = consumeSamples(factory, batch, batch.samples.size(),
+                                                         outSeq, outEvent);
+                        mBatches.removeAt(batchIndex);
+                        if (result) {
+                            return result;
+                        }
 #if DEBUG_TRANSPORT_ACTIONS
                     ALOGD("channel '%s' consumer ~ consumed batch event and "
                             "deferred current event, seq=%u",
                             mChannel->getName().c_str(), *outSeq);
 #endif
                     break;
+                    }
                 }
-            }
 
             // Start a new batch if needed.
             if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE
@@ -694,7 +693,7 @@
                     mChannel->getName().c_str(), *outSeq);
 #endif
             break;
-        }
+            }
 
         default:
             ALOGE("channel '%s' consumer ~ Received unexpected message of type %d",
@@ -1074,7 +1073,7 @@
 
 status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
     InputMessage msg;
-    msg.header.type = InputMessage::TYPE_FINISHED;
+    msg.header.type = InputMessage::Type::FINISHED;
     msg.body.finished.seq = seq;
     msg.body.finished.handled = handled;
     return mChannel->sendMessage(&msg);
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index af74edd..7c331e1 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -86,7 +86,7 @@
     // Server->Client communication
     InputMessage serverMsg;
     memset(&serverMsg, 0, sizeof(InputMessage));
-    serverMsg.header.type = InputMessage::TYPE_KEY;
+    serverMsg.header.type = InputMessage::Type::KEY;
     serverMsg.body.key.action = AKEY_EVENT_ACTION_DOWN;
     EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
             << "server channel should be able to send message to client channel";
@@ -102,7 +102,7 @@
     // Client->Server communication
     InputMessage clientReply;
     memset(&clientReply, 0, sizeof(InputMessage));
-    clientReply.header.type = InputMessage::TYPE_FINISHED;
+    clientReply.header.type = InputMessage::Type::FINISHED;
     clientReply.body.finished.seq = 0x11223344;
     clientReply.body.finished.handled = true;
     EXPECT_EQ(OK, clientChannel->sendMessage(&clientReply))
@@ -161,7 +161,7 @@
     serverChannel.clear(); // close server channel
 
     InputMessage msg;
-    msg.header.type = InputMessage::TYPE_KEY;
+    msg.header.type = InputMessage::Type::KEY;
     EXPECT_EQ(DEAD_OBJECT, clientChannel->sendMessage(&msg))
             << "sendMessage should have returned DEAD_OBJECT";
 }
@@ -180,7 +180,7 @@
     };
 
     InputMessage serverMsg = {}, clientMsg;
-    serverMsg.header.type = InputMessage::TYPE_MOTION;
+    serverMsg.header.type = InputMessage::Type::MOTION;
     serverMsg.body.motion.seq = 1;
     serverMsg.body.motion.pointerCount = 1;
 
diff --git a/libs/math/include/math/quat.h b/libs/math/include/math/quat.h
index 1936a2b..07573c5 100644
--- a/libs/math/include/math/quat.h
+++ b/libs/math/include/math/quat.h
@@ -109,7 +109,7 @@
 
     // initialize from 4 values to w + xi + yj + zk
     template<typename A, typename B, typename C, typename D>
-    constexpr TQuaternion(A w, B x, C y, D z) : x(x), y(y), z(z), w(w) { }
+    constexpr TQuaternion(A w, B x, C y, D z) : x(static_cast<T>(x)), y(static_cast<T>(y)), z(static_cast<T>(z)), w(static_cast<T>(w)) { }
 
     // initialize from a vec3 + a value to : v.xi + v.yj + v.zk + w
     template<typename A, typename B>
diff --git a/libs/math/include/math/vec2.h b/libs/math/include/math/vec2.h
index a347633..e0adb7f 100644
--- a/libs/math/include/math/vec2.h
+++ b/libs/math/include/math/vec2.h
@@ -89,7 +89,7 @@
     constexpr TVec2(A v) : x(v), y(v) { }
 
     template<typename A, typename B>
-    constexpr TVec2(A x, B y) : x(x), y(y) { }
+    constexpr TVec2(A x, B y) : x(static_cast<T>(x)), y(static_cast<T>(y)) { }
 
     template<typename A>
     explicit
diff --git a/libs/math/include/math/vec3.h b/libs/math/include/math/vec3.h
index 009fd84..21fb684 100644
--- a/libs/math/include/math/vec3.h
+++ b/libs/math/include/math/vec3.h
@@ -86,13 +86,13 @@
 
     // handles implicit conversion to a tvec4. must not be explicit.
     template<typename A, typename = typename std::enable_if<std::is_arithmetic<A>::value >::type>
-    constexpr TVec3(A v) : x(v), y(v), z(v) { }
+    constexpr TVec3(A v) : x(static_cast<T>(v)), y(static_cast<T>(v)), z(static_cast<T>(v)) { }
 
     template<typename A, typename B, typename C>
-    constexpr TVec3(A x, B y, C z) : x(x), y(y), z(z) { }
+    constexpr TVec3(A x, B y, C z) : x(static_cast<T>(x)), y(static_cast<T>(y)), z(static_cast<T>(z)) { }
 
     template<typename A, typename B>
-    constexpr TVec3(const TVec2<A>& v, B z) : x(v.x), y(v.y), z(z) { }
+    constexpr TVec3(const TVec2<A>& v, B z) : x(v.x), y(v.y), z(static_cast<T>(z)) { }
 
     template<typename A>
     explicit
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 9bd3095..1ec73ce 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -266,10 +266,10 @@
 
     char buf[CMSG_SPACE(kFdBufferSize)];
     struct msghdr msg = {
-            .msg_control = buf,
-            .msg_controllen = sizeof(buf),
             .msg_iov = &iov[0],
             .msg_iovlen = 1,
+            .msg_control = buf,
+            .msg_controllen = sizeof(buf),
     };
 
     struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
@@ -306,10 +306,10 @@
     iov[0].iov_len = kMessageBufferSize;
 
     struct msghdr msg = {
-            .msg_control = fdBuf,
-            .msg_controllen = sizeof(fdBuf),
             .msg_iov = &iov[0],
             .msg_iovlen = 1,
+            .msg_control = fdBuf,
+            .msg_controllen = sizeof(fdBuf),
     };
 
     int result;
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index da959e3..ae5e47b 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -342,6 +342,8 @@
  * not compatible with its usage flags, the results are undefined and
  * may include program termination.
  *
+ * Available since API level 26.
+ *
  * \return 0 on success, or an error number of the allocation fails for
  * any reason. The returned buffer has a reference count of 1.
  */
@@ -352,18 +354,24 @@
  *
  * This prevents the object from being deleted until the last reference
  * is removed.
+ *
+ * Available since API level 26.
  */
 void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
 
 /**
  * Remove a reference that was previously acquired with
  * AHardwareBuffer_acquire() or AHardwareBuffer_allocate().
+ *
+ * Available since API level 26.
  */
 void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
 
 /**
  * Return a description of the AHardwareBuffer in the passed
  * AHardwareBuffer_Desc struct.
+ *
+ * Available since API level 26.
  */
 void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
         AHardwareBuffer_Desc* outDesc) __INTRODUCED_IN(26);
@@ -413,6 +421,8 @@
  * simultaneously, and the contents of the buffer behave like shared
  * memory.
  *
+ * Available since API level 26.
+ *
  * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags
  * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer
  * has more than one layer. Error number if the lock fails for any other
@@ -441,6 +451,8 @@
  *
  * See the AHardwareBuffer_lock documentation for all other locking semantics.
  *
+ * Available since API level 29.
+ *
  * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags
  * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer
  * has more than one layer. Error number if the lock fails for any other
@@ -462,6 +474,8 @@
  * completed before the function returned and no further operations are
  * necessary.
  *
+ * Available since API level 26.
+ *
  * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if
  * the unlock fails for any reason.
  */
@@ -470,6 +484,8 @@
 /**
  * Send the AHardwareBuffer to an AF_UNIX socket.
  *
+ * Available since API level 26.
+ *
  * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
  * number if the operation fails for any reason.
  */
@@ -478,6 +494,8 @@
 /**
  * Receive an AHardwareBuffer from an AF_UNIX socket.
  *
+ * Available since API level 26.
+ *
  * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error
  * number if the operation fails for any reason.
  */
@@ -501,6 +519,8 @@
  * some implementations have implementation-defined limits on texture
  * size and layer count.
  *
+ * Available since API level 29.
+ *
  * \return 1 if the format and usage flag combination is allocatable,
  *     0 otherwise.
  */
@@ -514,6 +534,8 @@
  * of the locked buffer.  If the bytes per pixel or bytes per stride are unknown
  * or variable, or if the underlying mapper implementation does not support returning
  * additional information, then this call will fail with INVALID_OPERATION
+ *
+ * Available since API level 29.
  */
 int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage,
         int32_t fence, const ARect* rect, void** outVirtualAddress,
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 6730596..3e436e3 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -189,6 +189,8 @@
 /**
  * Set a transform that will be applied to future buffers posted to the window.
  *
+ * Available since API level 26.
+ *
  * \param transform combination of {@link ANativeWindowTransform} flags
  * \return 0 for success, or -EINVAL if \p transform is invalid
  */
@@ -208,6 +210,8 @@
  * measurement data instead of color images. The default dataSpace is 0,
  * ADATASPACE_UNKNOWN, unless it has been overridden by the producer.
  *
+ * Available since API level 28.
+ *
  * \param dataSpace data space of all buffers queued after this call.
  * \return 0 for success, -EINVAL if window is invalid or the dataspace is not
  * supported.
@@ -216,6 +220,9 @@
 
 /**
  * Get the dataspace of the buffers in window.
+ *
+ * Available since API level 28.
+ *
  * \return the dataspace of buffers in window, ADATASPACE_UNKNOWN is returned if
  * dataspace is unknown, or -EINVAL if window is invalid.
  */
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 166c267..0fdf093 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -24,23 +24,22 @@
 namespace android {
 namespace renderengine {
 
-std::unique_ptr<impl::RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags,
-                                                         uint32_t imageCacheSize) {
+std::unique_ptr<impl::RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
     char prop[PROPERTY_VALUE_MAX];
     property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "gles");
     if (strcmp(prop, "gles") == 0) {
         ALOGD("RenderEngine GLES Backend");
-        return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags, imageCacheSize);
+        return renderengine::gl::GLESRenderEngine::create(args);
     }
     ALOGE("UNKNOWN BackendType: %s, create GLES RenderEngine.", prop);
-    return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags, imageCacheSize);
+    return renderengine::gl::GLESRenderEngine::create(args);
 }
 
 RenderEngine::~RenderEngine() = default;
 
 namespace impl {
 
-RenderEngine::RenderEngine(uint32_t featureFlags) : mFeatureFlags(featureFlags) {}
+RenderEngine::RenderEngine(const RenderEngineCreationArgs& args) : mArgs(args) {}
 
 RenderEngine::~RenderEngine() = default;
 
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index f39f066..15d025b 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -227,8 +227,7 @@
     return err;
 }
 
-std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(int hwcFormat, uint32_t featureFlags,
-                                                           uint32_t imageCacheSize) {
+std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(const RenderEngineCreationArgs& args) {
     // initialize EGL for the default display
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     if (!eglInitialize(display, nullptr, nullptr)) {
@@ -243,14 +242,13 @@
     // supported.
     EGLConfig config = EGL_NO_CONFIG;
     if (!extensions.hasNoConfigContext()) {
-        config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+        config = chooseEglConfig(display, args.pixelFormat, /*logConfig*/ true);
     }
 
-    bool useContextPriority = extensions.hasContextPriority() &&
-            (featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
+    bool useContextPriority =
+            extensions.hasContextPriority() && args.contextPriority == ContextPriority::HIGH;
     EGLContext protectedContext = EGL_NO_CONTEXT;
-    if ((featureFlags & RenderEngine::ENABLE_PROTECTED_CONTEXT) &&
-        extensions.hasProtectedContent()) {
+    if (args.enableProtectedContext && extensions.hasProtectedContent()) {
         protectedContext = createEglContext(display, config, nullptr, useContextPriority,
                                             Protection::PROTECTED);
         ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context");
@@ -264,7 +262,8 @@
 
     EGLSurface dummy = EGL_NO_SURFACE;
     if (!extensions.hasSurfacelessContext()) {
-        dummy = createDummyEglPbufferSurface(display, config, hwcFormat, Protection::UNPROTECTED);
+        dummy = createDummyEglPbufferSurface(display, config, args.pixelFormat,
+                                             Protection::UNPROTECTED);
         LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
     }
     EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
@@ -274,8 +273,8 @@
 
     EGLSurface protectedDummy = EGL_NO_SURFACE;
     if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) {
-        protectedDummy =
-                createDummyEglPbufferSurface(display, config, hwcFormat, Protection::PROTECTED);
+        protectedDummy = createDummyEglPbufferSurface(display, config, args.pixelFormat,
+                                                      Protection::PROTECTED);
         ALOGE_IF(protectedDummy == EGL_NO_SURFACE, "can't create protected dummy pbuffer");
     }
 
@@ -291,9 +290,8 @@
             break;
         case GLES_VERSION_2_0:
         case GLES_VERSION_3_0:
-            engine = std::make_unique<GLESRenderEngine>(featureFlags, display, config, ctxt, dummy,
-                                                        protectedContext, protectedDummy,
-                                                        imageCacheSize);
+            engine = std::make_unique<GLESRenderEngine>(args, display, config, ctxt, dummy,
+                                                        protectedContext, protectedDummy);
             break;
     }
 
@@ -347,10 +345,10 @@
     return config;
 }
 
-GLESRenderEngine::GLESRenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config,
-                                   EGLContext ctxt, EGLSurface dummy, EGLContext protectedContext,
-                                   EGLSurface protectedDummy, uint32_t imageCacheSize)
-      : renderengine::impl::RenderEngine(featureFlags),
+GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
+                                   EGLConfig config, EGLContext ctxt, EGLSurface dummy,
+                                   EGLContext protectedContext, EGLSurface protectedDummy)
+      : renderengine::impl::RenderEngine(args),
         mEGLDisplay(display),
         mEGLConfig(config),
         mEGLContext(ctxt),
@@ -359,8 +357,8 @@
         mProtectedDummySurface(protectedDummy),
         mVpWidth(0),
         mVpHeight(0),
-        mFramebufferImageCacheSize(imageCacheSize),
-        mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
+        mFramebufferImageCacheSize(args.imageCacheSize),
+        mUseColorManagement(args.useColorManagement) {
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
 
@@ -458,7 +456,8 @@
 
 void GLESRenderEngine::primeCache() const {
     ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext,
-                                           mFeatureFlags & USE_COLOR_MANAGEMENT);
+                                           mArgs.useColorManagement,
+                                           mArgs.precacheToneMapperShaderOnly);
 }
 
 base::unique_fd GLESRenderEngine::flush() {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 501b044..397bc16 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -49,13 +49,11 @@
 
 class GLESRenderEngine : public impl::RenderEngine {
 public:
-    static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags,
-                                                    uint32_t imageCacheSize);
+    static std::unique_ptr<GLESRenderEngine> create(const RenderEngineCreationArgs& args);
 
-    GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
-                     EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy,
-                     EGLContext protectedContext, EGLSurface protectedDummy,
-                     uint32_t imageCacheSize);
+    GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLConfig config,
+                     EGLContext ctxt, EGLSurface dummy, EGLContext protectedContext,
+                     EGLSurface protectedDummy);
     ~GLESRenderEngine() override EXCLUDES(mRenderingMutex);
 
     void primeCache() const override;
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index d242677..494623e 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -77,9 +77,38 @@
     return f;
 }
 
-void ProgramCache::primeCache(EGLContext context, bool useColorManagement) {
+void ProgramCache::primeCache(
+        EGLContext context, bool useColorManagement, bool toneMapperShaderOnly) {
     auto& cache = mCaches[context];
     uint32_t shaderCount = 0;
+
+    if (toneMapperShaderOnly) {
+        Key shaderKey;
+        // base settings used by HDR->SDR tonemap only
+        shaderKey.set(Key::BLEND_MASK | Key::INPUT_TRANSFORM_MATRIX_MASK |
+                      Key::OUTPUT_TRANSFORM_MATRIX_MASK | Key::OUTPUT_TF_MASK |
+                      Key::OPACITY_MASK | Key::ALPHA_MASK |
+                      Key::ROUNDED_CORNERS_MASK | Key::TEXTURE_MASK,
+                      Key::BLEND_NORMAL | Key::INPUT_TRANSFORM_MATRIX_ON |
+                      Key::OUTPUT_TRANSFORM_MATRIX_ON | Key::OUTPUT_TF_SRGB |
+                      Key::OPACITY_OPAQUE | Key::ALPHA_EQ_ONE |
+                      Key::ROUNDED_CORNERS_OFF | Key::TEXTURE_EXT);
+        for (int i = 0; i < 4; i++) {
+            // Cache input transfer for HLG & ST2084
+            shaderKey.set(Key::INPUT_TF_MASK, (i & 1) ?
+                    Key::INPUT_TF_HLG : Key::INPUT_TF_ST2084);
+
+            // Cache Y410 input on or off
+            shaderKey.set(Key::Y410_BT2020_MASK, (i & 2) ?
+                    Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF);
+            if (cache.count(shaderKey) == 0) {
+                cache.emplace(shaderKey, generateProgram(shaderKey));
+                shaderCount++;
+            }
+        }
+        return;
+    }
+
     uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK
         | Key::ROUNDED_CORNERS_MASK;
     // Prime the cache for all combinations of the above masks,
diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h
index 400ad74..175c6e8 100644
--- a/libs/renderengine/gl/ProgramCache.h
+++ b/libs/renderengine/gl/ProgramCache.h
@@ -179,7 +179,7 @@
     ~ProgramCache() = default;
 
     // Generate shaders to populate the cache
-    void primeCache(const EGLContext context, bool useColorManagement);
+    void primeCache(const EGLContext context, bool useColorManagement, bool toneMapperShaderOnly);
 
     size_t getSize(const EGLContext context) { return mCaches[context].size(); }
 
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 205782b..4db5c57 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -48,6 +48,7 @@
 class Image;
 class Mesh;
 class Texture;
+struct RenderEngineCreationArgs;
 
 namespace impl {
 class RenderEngine;
@@ -60,16 +61,13 @@
 
 class RenderEngine {
 public:
-    enum FeatureFlag {
-        USE_COLOR_MANAGEMENT = 1 << 0,      // Device manages color
-        USE_HIGH_PRIORITY_CONTEXT = 1 << 1, // Use high priority context
-
-        // Create a protected context when if possible
-        ENABLE_PROTECTED_CONTEXT = 1 << 2,
+    enum class ContextPriority {
+        LOW = 1,
+        MEDIUM = 2,
+        HIGH = 3,
     };
 
-    static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags,
-                                                      uint32_t imageCacheSize);
+    static std::unique_ptr<impl::RenderEngine> create(const RenderEngineCreationArgs& args);
 
     virtual ~RenderEngine() = 0;
 
@@ -170,6 +168,76 @@
     friend class BindNativeBufferAsFramebuffer;
 };
 
+struct RenderEngineCreationArgs {
+    int pixelFormat;
+    uint32_t imageCacheSize;
+    bool useColorManagement;
+    bool enableProtectedContext;
+    bool precacheToneMapperShaderOnly;
+    RenderEngine::ContextPriority contextPriority;
+
+    struct Builder;
+
+private:
+    // must be created by Builder via constructor with full argument list
+    RenderEngineCreationArgs(
+            int _pixelFormat,
+            uint32_t _imageCacheSize,
+            bool _useColorManagement,
+            bool _enableProtectedContext,
+            bool _precacheToneMapperShaderOnly,
+            RenderEngine::ContextPriority _contextPriority)
+        : pixelFormat(_pixelFormat)
+        , imageCacheSize(_imageCacheSize)
+        , useColorManagement(_useColorManagement)
+        , enableProtectedContext(_enableProtectedContext)
+        , precacheToneMapperShaderOnly(_precacheToneMapperShaderOnly)
+        , contextPriority(_contextPriority) {}
+    RenderEngineCreationArgs() = delete;
+};
+
+struct RenderEngineCreationArgs::Builder {
+    Builder() {}
+
+    Builder& setPixelFormat(int pixelFormat) {
+        this->pixelFormat = pixelFormat;
+        return *this;
+    }
+    Builder& setImageCacheSize(uint32_t imageCacheSize) {
+        this->imageCacheSize = imageCacheSize;
+        return *this;
+    }
+    Builder& setUseColorManagerment(bool useColorManagement) {
+        this->useColorManagement = useColorManagement;
+        return *this;
+    }
+    Builder& setEnableProtectedContext(bool enableProtectedContext) {
+        this->enableProtectedContext = enableProtectedContext;
+        return *this;
+    }
+    Builder& setPrecacheToneMapperShaderOnly(bool precacheToneMapperShaderOnly) {
+        this->precacheToneMapperShaderOnly = precacheToneMapperShaderOnly;
+        return *this;
+    }
+    Builder& setContextPriority(RenderEngine::ContextPriority contextPriority) {
+        this->contextPriority = contextPriority;
+        return *this;
+    }
+    RenderEngineCreationArgs build() const {
+        return RenderEngineCreationArgs(pixelFormat, imageCacheSize, useColorManagement,
+                enableProtectedContext, precacheToneMapperShaderOnly, contextPriority);
+    }
+
+private:
+    // 1 means RGBA_8888
+    int pixelFormat = 1;
+    uint32_t imageCacheSize = 0;
+    bool useColorManagement = true;
+    bool enableProtectedContext = false;
+    bool precacheToneMapperShaderOnly = false;
+    RenderEngine::ContextPriority contextPriority = RenderEngine::ContextPriority::MEDIUM;
+};
+
 class BindNativeBufferAsFramebuffer {
 public:
     BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer,
@@ -203,8 +271,8 @@
     bool useWaitSync() const override;
 
 protected:
-    RenderEngine(uint32_t featureFlags);
-    const uint32_t mFeatureFlags;
+    RenderEngine(const RenderEngineCreationArgs& args);
+    const RenderEngineCreationArgs mArgs;
 };
 
 } // namespace impl
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index f47c7fd..d01c740 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -31,9 +31,15 @@
 
 struct RenderEngineTest : public ::testing::Test {
     static void SetUpTestSuite() {
-        sRE = renderengine::gl::GLESRenderEngine::create(static_cast<int32_t>(
-                                                                 ui::PixelFormat::RGBA_8888),
-                                                         0, 1);
+        sRE = renderengine::gl::GLESRenderEngine::create(
+                renderengine::RenderEngineCreationArgs::Builder()
+                    .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+                    .setImageCacheSize(1)
+                    .setUseColorManagerment(false)
+                    .setEnableProtectedContext(false)
+                    .setPrecacheToneMapperShaderOnly(false)
+                    .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
+        .build());
     }
 
     static void TearDownTestSuite() {
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index 139987e..abc9103 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -577,7 +577,8 @@
     uint32_t len = static_cast<uint32_t>(string8.length());
     FlattenableUtils::write(buffer, size, len);
     memcpy(static_cast<char*>(buffer), string8.string(), len);
-    FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len));
+    FlattenableUtils::advance(buffer, size, len);
+    size -= FlattenableUtils::align<4>(buffer);
 }
 
 bool Sensor::unflattenString8(void const*& buffer, size_t& size, String8& outputString8) {
diff --git a/libs/ui/ColorSpace.cpp b/libs/ui/ColorSpace.cpp
index 7a14af1..df390e2 100644
--- a/libs/ui/ColorSpace.cpp
+++ b/libs/ui/ColorSpace.cpp
@@ -364,7 +364,11 @@
     for (uint32_t z = 0; z < size; z++) {
         for (int32_t y = int32_t(size - 1); y >= 0; y--) {
             for (uint32_t x = 0; x < size; x++) {
-                *data++ = connector.transform({x * m, y * m, z * m});
+                *data++ = connector.transform({
+                    static_cast<float>(x) * m,
+                    static_cast<float>(y) * m,
+                    static_cast<float>(z) * m,
+                });
             }
         }
     }
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index eb787a2..fcc2547 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -89,7 +89,7 @@
         if (rec.size) {
             StringAppendF(&result,
                           "%10p: %7.2f KiB | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64 " | %s\n",
-                          list.keyAt(i), rec.size / 1024.0, rec.width, rec.stride, rec.height,
+                          list.keyAt(i), static_cast<double>(rec.size) / 1024.0, rec.width, rec.stride, rec.height,
                           rec.layerCount, rec.format, rec.usage, rec.requestorName.c_str());
         } else {
             StringAppendF(&result,
@@ -99,7 +99,7 @@
         }
         total += rec.size;
     }
-    StringAppendF(&result, "Total allocated (estimate): %.2f KB\n", total / 1024.0);
+    StringAppendF(&result, "Total allocated (estimate): %.2f KB\n", static_cast<double>(total) / 1024.0);
 
     result.append(mAllocator->dumpDebugInfo());
 }
@@ -140,6 +140,17 @@
 
     status_t error =
             mAllocator->allocate(width, height, format, layerCount, usage, 1, stride, handle);
+    size_t bufSize;
+
+    // if stride has no meaning or is too large,
+    // approximate size with the input width instead
+    if ((*stride) != 0 &&
+        std::numeric_limits<size_t>::max() / height / (*stride) < static_cast<size_t>(bpp)) {
+        bufSize = static_cast<size_t>(width) * height * bpp;
+    } else {
+        bufSize = static_cast<size_t>((*stride)) * height * bpp;
+    }
+
     if (error == NO_ERROR) {
         Mutex::Autolock _l(sLock);
         KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
@@ -150,7 +161,7 @@
         rec.format = format;
         rec.layerCount = layerCount;
         rec.usage = usage;
-        rec.size = static_cast<size_t>(height * (*stride) * bpp);
+        rec.size = bufSize;
         rec.requestorName = std::move(requestorName);
         list.add(*handle, rec);
 
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 55e3b99..1222cd6 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -339,10 +339,10 @@
     size_t count = mStorage.size();
     Rect* rects = mStorage.editArray();
     while (count) {
-        rects->left = static_cast<int32_t>(rects->left * sx + 0.5f);
-        rects->right = static_cast<int32_t>(rects->right * sx + 0.5f);
-        rects->top = static_cast<int32_t>(rects->top * sy + 0.5f);
-        rects->bottom = static_cast<int32_t>(rects->bottom * sy + 0.5f);
+        rects->left = static_cast<int32_t>(static_cast<float>(rects->left) * sx + 0.5f);
+        rects->right = static_cast<int32_t>(static_cast<float>(rects->right) * sx + 0.5f);
+        rects->top = static_cast<int32_t>(static_cast<float>(rects->top) * sy + 0.5f);
+        rects->bottom = static_cast<int32_t>(static_cast<float>(rects->bottom) * sy + 0.5f);
         rects++;
         count--;
     }
diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
index 25d4512..324d9e1 100644
--- a/libs/ui/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -54,7 +54,7 @@
     void dump(std::string& res) const;
     static void dumpToSystemLog();
 
-private:
+protected:
     struct alloc_rec_t {
         uint32_t width;
         uint32_t height;
diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h
index c39d8af..d9b713d 100644
--- a/libs/ui/include/ui/Size.h
+++ b/libs/ui/include/ui/Size.h
@@ -132,7 +132,7 @@
         // Otherwise we leverage implicit conversion to safely compare values of
         // different types, to ensure we return a value clamped to the range of
         // ToType.
-        return v < toLowest ? toLowest : (v > toHighest ? toHighest : static_cast<ToType>(v));
+        return v < toLowest ? toLowest : (static_cast<ToType>(v) > toHighest ? toHighest : static_cast<ToType>(v));
     }
 };
 
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 0452f84..d2ad242 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -29,6 +29,26 @@
 }
 
 cc_test {
+    name: "GraphicBufferAllocator_test",
+    header_libs: [
+        "libdvr_headers",
+        "libnativewindow_headers",
+    ],
+    static_libs: [
+        "libgmock",
+    ],
+    shared_libs: [
+        "liblog",
+	"libui",
+    ],
+    srcs: [
+        "GraphicBufferAllocator_test.cpp",
+        "mock/MockGrallocAllocator.cpp",
+    ],
+    cflags: ["-Wall", "-Werror"],
+}
+
+cc_test {
     name: "GraphicBuffer_test",
     header_libs: [
         "libdvr_headers",
diff --git a/libs/ui/tests/GraphicBufferAllocator_test.cpp b/libs/ui/tests/GraphicBufferAllocator_test.cpp
new file mode 100644
index 0000000..efca083
--- /dev/null
+++ b/libs/ui/tests/GraphicBufferAllocator_test.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GraphicBufferAllocatorTest"
+
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+
+#include <gtest/gtest.h>
+
+#include "mock/MockGrallocAllocator.h"
+
+#include <algorithm>
+#include <limits>
+
+namespace android {
+
+namespace {
+
+constexpr uint32_t kTestWidth = 1024;
+constexpr uint32_t kTestHeight = 1;
+constexpr uint32_t kTestLayerCount = 1;
+constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN;
+
+} // namespace
+
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+
+class TestableGraphicBufferAllocator : public GraphicBufferAllocator {
+public:
+    TestableGraphicBufferAllocator() {
+        mAllocator = std::make_unique<const mock::MockGrallocAllocator>();
+    }
+    void setUpAllocateExpectations(status_t err, uint32_t stride) {
+        std::cout << "Setting expected stride to " << stride << std::endl;
+        EXPECT_CALL(*(reinterpret_cast<const mock::MockGrallocAllocator*>(mAllocator.get())),
+                    allocate)
+                .WillOnce(DoAll(SetArgPointee<6>(stride), Return(err)));
+    }
+    std::unique_ptr<const GrallocAllocator>& getAllocator() { return mAllocator; }
+};
+
+class GraphicBufferAllocatorTest : public testing::Test {
+public:
+    GraphicBufferAllocatorTest() : mAllocator() {}
+    const TestableGraphicBufferAllocator& getAllocator() { return mAllocator; }
+
+protected:
+    TestableGraphicBufferAllocator mAllocator;
+};
+
+TEST_F(GraphicBufferAllocatorTest, AllocateNoError) {
+    mAllocator.setUpAllocateExpectations(NO_ERROR, kTestWidth);
+    android::PixelFormat format = PIXEL_FORMAT_RGBA_8888;
+    uint32_t stride = 0;
+    buffer_handle_t handle;
+    status_t err = mAllocator.allocate(kTestWidth, kTestHeight, format, kTestLayerCount, kTestUsage,
+                                       &handle, &stride, 0, "GraphicBufferAllocatorTest");
+    ASSERT_EQ(NO_ERROR, err);
+    ASSERT_EQ(kTestWidth, stride);
+}
+
+TEST_F(GraphicBufferAllocatorTest, AllocateZeroStride) {
+    android::PixelFormat format = PIXEL_FORMAT_RGBA_8888;
+    uint32_t expectedStride = 0;
+
+    mAllocator.setUpAllocateExpectations(NO_ERROR, expectedStride);
+    uint32_t stride = 0;
+    buffer_handle_t handle;
+    // a divide by zero would cause a crash
+    status_t err = mAllocator.allocate(kTestWidth, kTestHeight, format, kTestLayerCount, kTestUsage,
+                                       &handle, &stride, 0, "GraphicBufferAllocatorTest");
+    ASSERT_EQ(NO_ERROR, err);
+    ASSERT_EQ(expectedStride, stride);
+}
+
+TEST_F(GraphicBufferAllocatorTest, AllocateLargeStride) {
+    uint32_t height = std::numeric_limits<uint32_t>::max();
+    uint32_t bpp = 4;
+    android::PixelFormat format = PIXEL_FORMAT_RGBA_8888;
+
+    if (std::numeric_limits<size_t>::max() / height / bpp >= std::numeric_limits<uint32_t>::max()) {
+        std::cout << "stride cannot cause overflow" << std::endl;
+        GTEST_SUCCEED() << "stride cannot cause overflow";
+        return;
+    }
+    uint32_t width = std::numeric_limits<size_t>::max() / height / bpp;
+
+    uint32_t expectedStride = std::numeric_limits<uint32_t>::max();
+
+    mAllocator.setUpAllocateExpectations(NO_ERROR, expectedStride);
+    uint32_t stride = 0;
+    buffer_handle_t handle;
+    // an overflow would cause a crash
+    status_t err = mAllocator.allocate(width, height, format, kTestLayerCount, kTestUsage, &handle,
+                                       &stride, 0, "GraphicBufferAllocatorTest");
+    ASSERT_EQ(NO_ERROR, err);
+    ASSERT_EQ(expectedStride, stride);
+}
+} // namespace android
diff --git a/libs/binder/fuzzer/parcel.h b/libs/ui/tests/mock/MockGrallocAllocator.cpp
similarity index 72%
copy from libs/binder/fuzzer/parcel.h
copy to libs/ui/tests/mock/MockGrallocAllocator.cpp
index 5f05335..d71e25f 100644
--- a/libs/binder/fuzzer/parcel.h
+++ b/libs/ui/tests/mock/MockGrallocAllocator.cpp
@@ -14,7 +14,14 @@
  * limitations under the License.
  */
 
-template <typename P>
-using ParcelRead = std::function<void(const P& p, uint8_t data)>;
+#include "MockGrallocAllocator.h"
 
+namespace android {
 
+namespace mock {
+
+MockGrallocAllocator::MockGrallocAllocator() = default;
+MockGrallocAllocator::~MockGrallocAllocator() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/libs/ui/tests/mock/MockGrallocAllocator.h b/libs/ui/tests/mock/MockGrallocAllocator.h
new file mode 100644
index 0000000..22c80a4
--- /dev/null
+++ b/libs/ui/tests/mock/MockGrallocAllocator.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include <ui/Gralloc.h>
+
+namespace android {
+
+class GraphicBuffer;
+
+namespace mock {
+
+class MockGrallocAllocator : public GrallocAllocator {
+public:
+    MockGrallocAllocator();
+    ~MockGrallocAllocator() override;
+
+    MOCK_METHOD(bool, isLoaded, (), (const, override));
+    MOCK_METHOD(std::string, dumpDebugInfo, (), (const, override));
+    MOCK_METHOD(status_t, allocate,
+                (uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
+                 uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+                 buffer_handle_t* outBufferHandles),
+                (const, override));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 6d202ae..2fcee7b 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -29,11 +29,9 @@
 sharedLibraries = [
     "libbase",
     "libcutils",
-    "libhardware",
     "liblog",
     "libui",
     "libutils",
-    "libnativewindow",
     "libpdx_default_transport",
 ]
 
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 2053344..04493f0 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -40,6 +40,7 @@
     "android.hardware.graphics.composer@2.1",
     "android.hardware.graphics.composer@2.2",
     "android.hardware.graphics.composer@2.3",
+    "android.hardware.graphics.composer@2.4",
     "libbinder",
     "libbase",
     "libbufferhubqueue",
diff --git a/opengl/tests/gl_perf/fill_common.cpp b/opengl/tests/gl_perf/fill_common.cpp
index fefedc0..613f1c6 100644
--- a/opengl/tests/gl_perf/fill_common.cpp
+++ b/opengl/tests/gl_perf/fill_common.cpp
@@ -191,10 +191,10 @@
 static void randUniform(int pgm, const char *var) {
     GLint loc = glGetUniformLocation(pgm, var);
     if (loc >= 0) {
-        float x = ((float)rand()) / RAND_MAX;
-        float y = ((float)rand()) / RAND_MAX;
-        float z = ((float)rand()) / RAND_MAX;
-        float w = ((float)rand()) / RAND_MAX;
+        float x = ((float)rand()) / (float)RAND_MAX;
+        float y = ((float)rand()) / (float)RAND_MAX;
+        float z = ((float)rand()) / (float)RAND_MAX;
+        float w = ((float)rand()) / (float)RAND_MAX;
         glUniform4f(loc, x, y, z, w);
     }
 }
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 34a04df..1043390 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -127,7 +127,7 @@
                 "from non shell/root entity (PID: %d)", ipc->getCallingPid());
         return;
     }
-    mDispatcher->registerInputChannel(channel, false);
+    mDispatcher->registerInputChannel(channel);
 }
 
 void InputManager::unregisterInputChannel(const sp<InputChannel>& channel) {
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 640a69a..930c7c7 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -18,10 +18,12 @@
 
 #include "Connection.h"
 
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <cutils/atomic.h>
 #include <inttypes.h>
 
+using android::base::GetBoolProperty;
 using android::base::StringPrintf;
 
 namespace android::inputdispatcher {
@@ -133,7 +135,11 @@
 KeyEntry::~KeyEntry() {}
 
 void KeyEntry::appendDescription(std::string& msg) const {
-    msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32 ", action=%s, "
+    msg += StringPrintf("KeyEvent");
+    if (!GetBoolProperty("ro.debuggable", false)) {
+        return;
+    }
+    msg += StringPrintf("(deviceId=%d, source=0x%08x, displayId=%" PRId32 ", action=%s, "
                         "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
                         "repeatCount=%d), policyFlags=0x%08x",
                         deviceId, source, displayId, keyActionToString(action).c_str(), flags,
@@ -189,7 +195,11 @@
 MotionEntry::~MotionEntry() {}
 
 void MotionEntry::appendDescription(std::string& msg) const {
-    msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32
+    msg += StringPrintf("MotionEvent");
+    if (!GetBoolProperty("ro.debuggable", false)) {
+        return;
+    }
+    msg += StringPrintf("(deviceId=%d, source=0x%08x, displayId=%" PRId32
                         ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, "
                         "buttonState=0x%08x, "
                         "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, "
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 4db9ae2..9e5f5f7 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -17,7 +17,7 @@
 #define LOG_TAG "InputDispatcher"
 #define ATRACE_TAG ATRACE_TAG_INPUT
 
-#define LOG_NDEBUG 0
+#define LOG_NDEBUG 1
 
 // Log detailed debug messages about each inbound event notification to the dispatcher.
 #define DEBUG_INBOUND_EVENT_DETAILS 0
@@ -245,7 +245,7 @@
 InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
       : mPolicy(policy),
         mPendingEvent(nullptr),
-        mLastDropReason(DROP_REASON_NOT_DROPPED),
+        mLastDropReason(DropReason::NOT_DROPPED),
         mAppSwitchSawKeyDown(false),
         mAppSwitchDueTime(LONG_LONG_MAX),
         mNextUnblockedEvent(nullptr),
@@ -363,7 +363,7 @@
 
         // Poke user activity for this event.
         if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
-            pokeUserActivityLocked(mPendingEvent);
+            pokeUserActivityLocked(*mPendingEvent);
         }
 
         // Get ready to dispatch the event.
@@ -374,11 +374,11 @@
     // All events are eventually dequeued and processed this way, even if we intend to drop them.
     ALOG_ASSERT(mPendingEvent != nullptr);
     bool done = false;
-    DropReason dropReason = DROP_REASON_NOT_DROPPED;
+    DropReason dropReason = DropReason::NOT_DROPPED;
     if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
-        dropReason = DROP_REASON_POLICY;
+        dropReason = DropReason::POLICY;
     } else if (!mDispatchEnabled) {
-        dropReason = DROP_REASON_DISABLED;
+        dropReason = DropReason::DISABLED;
     }
 
     if (mNextUnblockedEvent == mPendingEvent) {
@@ -390,32 +390,32 @@
             ConfigurationChangedEntry* typedEntry =
                     static_cast<ConfigurationChangedEntry*>(mPendingEvent);
             done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
-            dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
+            dropReason = DropReason::NOT_DROPPED; // configuration changes are never dropped
             break;
         }
 
         case EventEntry::TYPE_DEVICE_RESET: {
             DeviceResetEntry* typedEntry = static_cast<DeviceResetEntry*>(mPendingEvent);
             done = dispatchDeviceResetLocked(currentTime, typedEntry);
-            dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped
+            dropReason = DropReason::NOT_DROPPED; // device resets are never dropped
             break;
         }
 
         case EventEntry::TYPE_KEY: {
             KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
             if (isAppSwitchDue) {
-                if (isAppSwitchKeyEvent(typedEntry)) {
+                if (isAppSwitchKeyEvent(*typedEntry)) {
                     resetPendingAppSwitchLocked(true);
                     isAppSwitchDue = false;
-                } else if (dropReason == DROP_REASON_NOT_DROPPED) {
-                    dropReason = DROP_REASON_APP_SWITCH;
+                } else if (dropReason == DropReason::NOT_DROPPED) {
+                    dropReason = DropReason::APP_SWITCH;
                 }
             }
-            if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) {
-                dropReason = DROP_REASON_STALE;
+            if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
+                dropReason = DropReason::STALE;
             }
-            if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
-                dropReason = DROP_REASON_BLOCKED;
+            if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
+                dropReason = DropReason::BLOCKED;
             }
             done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
             break;
@@ -423,14 +423,14 @@
 
         case EventEntry::TYPE_MOTION: {
             MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
-            if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
-                dropReason = DROP_REASON_APP_SWITCH;
+            if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
+                dropReason = DropReason::APP_SWITCH;
             }
-            if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) {
-                dropReason = DROP_REASON_STALE;
+            if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
+                dropReason = DropReason::STALE;
             }
-            if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
-                dropReason = DROP_REASON_BLOCKED;
+            if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
+                dropReason = DropReason::BLOCKED;
             }
             done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
             break;
@@ -442,8 +442,8 @@
     }
 
     if (done) {
-        if (dropReason != DROP_REASON_NOT_DROPPED) {
-            dropInboundEventLocked(mPendingEvent, dropReason);
+        if (dropReason != DropReason::NOT_DROPPED) {
+            dropInboundEventLocked(*mPendingEvent, dropReason);
         }
         mLastDropReason = dropReason;
 
@@ -462,16 +462,16 @@
             // Optimize app switch latency.
             // If the application takes too long to catch up then we drop all events preceding
             // the app switch key.
-            KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
+            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*entry);
             if (isAppSwitchKeyEvent(keyEntry)) {
-                if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
+                if (keyEntry.action == AKEY_EVENT_ACTION_DOWN) {
                     mAppSwitchSawKeyDown = true;
-                } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
+                } else if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
                     if (mAppSwitchSawKeyDown) {
 #if DEBUG_APP_SWITCH
                         ALOGD("App switch is pending!");
 #endif
-                        mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
+                        mAppSwitchDueTime = keyEntry.eventTime + APP_SWITCH_TIMEOUT;
                         mAppSwitchSawKeyDown = false;
                         needWake = true;
                     }
@@ -591,49 +591,50 @@
     }
 }
 
-void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) {
+void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) {
     const char* reason;
     switch (dropReason) {
-        case DROP_REASON_POLICY:
+        case DropReason::POLICY:
 #if DEBUG_INBOUND_EVENT_DETAILS
             ALOGD("Dropped event because policy consumed it.");
 #endif
             reason = "inbound event was dropped because the policy consumed it";
             break;
-        case DROP_REASON_DISABLED:
-            if (mLastDropReason != DROP_REASON_DISABLED) {
+        case DropReason::DISABLED:
+            if (mLastDropReason != DropReason::DISABLED) {
                 ALOGI("Dropped event because input dispatch is disabled.");
             }
             reason = "inbound event was dropped because input dispatch is disabled";
             break;
-        case DROP_REASON_APP_SWITCH:
+        case DropReason::APP_SWITCH:
             ALOGI("Dropped event because of pending overdue app switch.");
             reason = "inbound event was dropped because of pending overdue app switch";
             break;
-        case DROP_REASON_BLOCKED:
+        case DropReason::BLOCKED:
             ALOGI("Dropped event because the current application is not responding and the user "
                   "has started interacting with a different application.");
             reason = "inbound event was dropped because the current application is not responding "
                      "and the user has started interacting with a different application";
             break;
-        case DROP_REASON_STALE:
+        case DropReason::STALE:
             ALOGI("Dropped event because it is stale.");
             reason = "inbound event was dropped because it is stale";
             break;
-        default:
-            ALOG_ASSERT(false);
+        case DropReason::NOT_DROPPED: {
+            LOG_ALWAYS_FATAL("Should not be dropping a NOT_DROPPED event");
             return;
+        }
     }
 
-    switch (entry->type) {
+    switch (entry.type) {
         case EventEntry::TYPE_KEY: {
             CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason);
             synthesizeCancelationEventsForAllConnectionsLocked(options);
             break;
         }
         case EventEntry::TYPE_MOTION: {
-            MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
-            if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
+            const MotionEntry& motionEntry = static_cast<const MotionEntry&>(entry);
+            if (motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) {
                 CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason);
                 synthesizeCancelationEventsForAllConnectionsLocked(options);
             } else {
@@ -650,10 +651,10 @@
             keyCode == AKEYCODE_APP_SWITCH;
 }
 
-bool InputDispatcher::isAppSwitchKeyEvent(KeyEntry* keyEntry) {
-    return !(keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) && isAppSwitchKeyCode(keyEntry->keyCode) &&
-            (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) &&
-            (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER);
+bool InputDispatcher::isAppSwitchKeyEvent(const KeyEntry& keyEntry) {
+    return !(keyEntry.flags & AKEY_EVENT_FLAG_CANCELED) && isAppSwitchKeyCode(keyEntry.keyCode) &&
+            (keyEntry.policyFlags & POLICY_FLAG_TRUSTED) &&
+            (keyEntry.policyFlags & POLICY_FLAG_PASS_TO_USER);
 }
 
 bool InputDispatcher::isAppSwitchPendingLocked() {
@@ -672,8 +673,8 @@
 #endif
 }
 
-bool InputDispatcher::isStaleEvent(nsecs_t currentTime, EventEntry* entry) {
-    return currentTime - entry->eventTime >= STALE_EVENT_TIMEOUT;
+bool InputDispatcher::isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
+    return currentTime - entry.eventTime >= STALE_EVENT_TIMEOUT;
 }
 
 bool InputDispatcher::haveCommandsLocked() const {
@@ -836,7 +837,7 @@
 
         entry->dispatchInProgress = true;
 
-        logOutboundKeyDetails("dispatchKey - ", entry);
+        logOutboundKeyDetails("dispatchKey - ", *entry);
     }
 
     // Handle case where the policy asked us to try again later last time.
@@ -857,7 +858,7 @@
             std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
                     &InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
             sp<InputWindowHandle> focusedWindowHandle =
-                    getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
+                    getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(*entry));
             if (focusedWindowHandle != nullptr) {
                 commandEntry->inputChannel = getInputChannelLocked(focusedWindowHandle->getToken());
             }
@@ -869,15 +870,15 @@
             entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
         }
     } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
-        if (*dropReason == DROP_REASON_NOT_DROPPED) {
-            *dropReason = DROP_REASON_POLICY;
+        if (*dropReason == DropReason::NOT_DROPPED) {
+            *dropReason = DropReason::POLICY;
         }
     }
 
     // Clean up if dropping the event.
-    if (*dropReason != DROP_REASON_NOT_DROPPED) {
+    if (*dropReason != DropReason::NOT_DROPPED) {
         setInjectionResult(entry,
-                           *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED
+                           *dropReason == DropReason::POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED
                                                              : INPUT_EVENT_INJECTION_FAILED);
         mReporter->reportDroppedKey(entry->sequenceNum);
         return true;
@@ -886,7 +887,7 @@
     // Identify targets.
     std::vector<InputTarget> inputTargets;
     int32_t injectionResult =
-            findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime);
+            findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);
     if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
         return false;
     }
@@ -897,21 +898,21 @@
     }
 
     // Add monitor channels from event's or focused display.
-    addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
+    addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));
 
     // Dispatch the key.
     dispatchEventLocked(currentTime, entry, inputTargets);
     return true;
 }
 
-void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry* entry) {
+void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry& entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
     ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", "
           "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, "
           "metaState=0x%x, repeatCount=%d, downTime=%" PRId64,
-          prefix, entry->eventTime, entry->deviceId, entry->source, entry->displayId,
-          entry->policyFlags, entry->action, entry->flags, entry->keyCode, entry->scanCode,
-          entry->metaState, entry->repeatCount, entry->downTime);
+          prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId, entry.policyFlags,
+          entry.action, entry.flags, entry.keyCode, entry.scanCode, entry.metaState,
+          entry.repeatCount, entry.downTime);
 #endif
 }
 
@@ -922,13 +923,13 @@
     if (!entry->dispatchInProgress) {
         entry->dispatchInProgress = true;
 
-        logOutboundMotionDetails("dispatchMotion - ", entry);
+        logOutboundMotionDetails("dispatchMotion - ", *entry);
     }
 
     // Clean up if dropping the event.
-    if (*dropReason != DROP_REASON_NOT_DROPPED) {
+    if (*dropReason != DropReason::NOT_DROPPED) {
         setInjectionResult(entry,
-                           *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED
+                           *dropReason == DropReason::POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED
                                                              : INPUT_EVENT_INJECTION_FAILED);
         return true;
     }
@@ -943,12 +944,12 @@
     if (isPointerEvent) {
         // Pointer event.  (eg. touchscreen)
         injectionResult =
-                findTouchedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime,
+                findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,
                                                &conflictingPointerActions);
     } else {
         // Non touch event.  (eg. trackball)
         injectionResult =
-                findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime);
+                findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);
     }
     if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
         return false;
@@ -967,7 +968,7 @@
     }
 
     // Add monitor channels from event's or focused display.
-    addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
+    addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));
 
     if (isPointerEvent) {
         ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(entry->displayId);
@@ -995,33 +996,32 @@
     return true;
 }
 
-void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionEntry* entry) {
+void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionEntry& entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
     ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
           ", policyFlags=0x%x, "
           "action=0x%x, actionButton=0x%x, flags=0x%x, "
           "metaState=0x%x, buttonState=0x%x,"
           "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
-          prefix, entry->eventTime, entry->deviceId, entry->source, entry->displayId,
-          entry->policyFlags, entry->action, entry->actionButton, entry->flags, entry->metaState,
-          entry->buttonState, entry->edgeFlags, entry->xPrecision, entry->yPrecision,
-          entry->downTime);
+          prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId, entry.policyFlags,
+          entry.action, entry.actionButton, entry.flags, entry.metaState, entry.buttonState,
+          entry.edgeFlags, entry.xPrecision, entry.yPrecision, entry.downTime);
 
-    for (uint32_t i = 0; i < entry->pointerCount; i++) {
+    for (uint32_t i = 0; i < entry.pointerCount; i++) {
         ALOGD("  Pointer %d: id=%d, toolType=%d, "
               "x=%f, y=%f, pressure=%f, size=%f, "
               "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
               "orientation=%f",
-              i, entry->pointerProperties[i].id, entry->pointerProperties[i].toolType,
-              entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
-              entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
-              entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
-              entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
-              entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
-              entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
-              entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
-              entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
-              entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
+              i, entry.pointerProperties[i].id, entry.pointerProperties[i].toolType,
+              entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
+              entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
+              entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+              entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
+              entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
+              entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
+              entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
+              entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
+              entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
     }
 #endif
 }
@@ -1035,7 +1035,7 @@
 
     ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
 
-    pokeUserActivityLocked(eventEntry);
+    pokeUserActivityLocked(*eventEntry);
 
     for (const InputTarget& inputTarget : inputTargets) {
         sp<Connection> connection = getConnectionLocked(inputTarget.inputChannel);
@@ -1052,7 +1052,7 @@
 }
 
 int32_t InputDispatcher::handleTargetsNotReadyLocked(
-        nsecs_t currentTime, const EventEntry* entry,
+        nsecs_t currentTime, const EventEntry& entry,
         const sp<InputApplicationHandle>& applicationHandle,
         const sp<InputWindowHandle>& windowHandle, nsecs_t* nextWakeupTime, const char* reason) {
     if (applicationHandle == nullptr && windowHandle == nullptr) {
@@ -1102,7 +1102,7 @@
     }
 
     if (currentTime >= mInputTargetWaitTimeoutTime) {
-        onANRLocked(currentTime, applicationHandle, windowHandle, entry->eventTime,
+        onANRLocked(currentTime, applicationHandle, windowHandle, entry.eventTime,
                     mInputTargetWaitStartTime, reason);
 
         // Force poll loop to wake up immediately on next iteration once we get the
@@ -1174,21 +1174,21 @@
  * then it should be dispatched to that display. Otherwise, the event goes to the focused display.
  * Focused display is the display that the user most recently interacted with.
  */
-int32_t InputDispatcher::getTargetDisplayId(const EventEntry* entry) {
+int32_t InputDispatcher::getTargetDisplayId(const EventEntry& entry) {
     int32_t displayId;
-    switch (entry->type) {
+    switch (entry.type) {
         case EventEntry::TYPE_KEY: {
-            const KeyEntry* typedEntry = static_cast<const KeyEntry*>(entry);
-            displayId = typedEntry->displayId;
+            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);
+            displayId = keyEntry.displayId;
             break;
         }
         case EventEntry::TYPE_MOTION: {
-            const MotionEntry* typedEntry = static_cast<const MotionEntry*>(entry);
-            displayId = typedEntry->displayId;
+            const MotionEntry& motionEntry = static_cast<const MotionEntry&>(entry);
+            displayId = motionEntry.displayId;
             break;
         }
         default: {
-            ALOGE("Unsupported event type '%" PRId32 "' for target display.", entry->type);
+            ALOGE("Unsupported event type '%" PRId32 "' for target display.", entry.type);
             return ADISPLAY_ID_NONE;
         }
     }
@@ -1196,7 +1196,7 @@
 }
 
 int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
-                                                        const EventEntry* entry,
+                                                        const EventEntry& entry,
                                                         std::vector<InputTarget>& inputTargets,
                                                         nsecs_t* nextWakeupTime) {
     int32_t injectionResult;
@@ -1229,7 +1229,7 @@
     }
 
     // Check permissions.
-    if (!checkInjectionPermission(focusedWindowHandle, entry->injectionState)) {
+    if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) {
         injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
         goto Failed;
     }
@@ -1263,7 +1263,7 @@
 }
 
 int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
-                                                        const MotionEntry* entry,
+                                                        const MotionEntry& entry,
                                                         std::vector<InputTarget>& inputTargets,
                                                         nsecs_t* nextWakeupTime,
                                                         bool* outConflictingPointerActions) {
@@ -1276,8 +1276,8 @@
 
     // For security reasons, we defer updating the touch state until we are sure that
     // event injection will be allowed.
-    int32_t displayId = entry->displayId;
-    int32_t action = entry->action;
+    int32_t displayId = entry.displayId;
+    int32_t action = entry.action;
     int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
 
     // Update the touch state as needed based on the properties of the touch event.
@@ -1297,14 +1297,14 @@
 
     bool isSplit = mTempTouchState.split;
     bool switchedDevice = mTempTouchState.deviceId >= 0 && mTempTouchState.displayId >= 0 &&
-            (mTempTouchState.deviceId != entry->deviceId ||
-             mTempTouchState.source != entry->source || mTempTouchState.displayId != displayId);
+            (mTempTouchState.deviceId != entry.deviceId || mTempTouchState.source != entry.source ||
+             mTempTouchState.displayId != displayId);
     bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE ||
                           maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||
                           maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT);
     bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN ||
                        maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction);
-    const bool isFromMouse = entry->source == AINPUT_SOURCE_MOUSE;
+    const bool isFromMouse = entry.source == AINPUT_SOURCE_MOUSE;
     bool wrongDevice = false;
     if (newGesture) {
         bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
@@ -1322,8 +1322,8 @@
         }
         mTempTouchState.reset();
         mTempTouchState.down = down;
-        mTempTouchState.deviceId = entry->deviceId;
-        mTempTouchState.source = entry->source;
+        mTempTouchState.deviceId = entry.deviceId;
+        mTempTouchState.source = entry.source;
         mTempTouchState.displayId = displayId;
         isSplit = false;
     } else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) {
@@ -1347,11 +1347,11 @@
         int32_t pointerIndex = getMotionEventActionPointerIndex(action);
         // Always dispatch mouse events to cursor position.
         if (isFromMouse) {
-            x = int32_t(entry->xCursorPosition);
-            y = int32_t(entry->yCursorPosition);
+            x = int32_t(entry.xCursorPosition);
+            y = int32_t(entry.yCursorPosition);
         } else {
-            x = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));
-            y = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));
+            x = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));
+            y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));
         }
         bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;
         sp<InputWindowHandle> newTouchedWindowHandle =
@@ -1409,7 +1409,7 @@
             // Update the temporary touch state.
             BitSet32 pointerIds;
             if (isSplit) {
-                uint32_t pointerId = entry->pointerProperties[pointerIndex].id;
+                uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
                 pointerIds.markBit(pointerId);
             }
             mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
@@ -1431,10 +1431,10 @@
         }
 
         // Check whether touches should slip outside of the current foreground window.
-        if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry->pointerCount == 1 &&
+        if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry.pointerCount == 1 &&
             mTempTouchState.isSlippery()) {
-            int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
-            int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
+            int32_t x = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
+            int32_t y = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
 
             sp<InputWindowHandle> oldTouchedWindowHandle =
                     mTempTouchState.getFirstForegroundWindowHandle();
@@ -1468,7 +1468,7 @@
 
                 BitSet32 pointerIds;
                 if (isSplit) {
-                    pointerIds.markBit(entry->pointerProperties[0].id);
+                    pointerIds.markBit(entry.pointerProperties[0].id);
                 }
                 mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
             }
@@ -1506,7 +1506,7 @@
         for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {
             if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
                 haveForegroundWindow = true;
-                if (!checkInjectionPermission(touchedWindow.windowHandle, entry->injectionState)) {
+                if (!checkInjectionPermission(touchedWindow.windowHandle, entry.injectionState)) {
                     injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
                     injectionPermission = INJECTION_PERMISSION_DENIED;
                     goto Failed;
@@ -1612,7 +1612,7 @@
 Failed:
     // Check injection permission once and for all.
     if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {
-        if (checkInjectionPermission(nullptr, entry->injectionState)) {
+        if (checkInjectionPermission(nullptr, entry.injectionState)) {
             injectionPermission = INJECTION_PERMISSION_GRANTED;
         } else {
             injectionPermission = INJECTION_PERMISSION_DENIED;
@@ -1641,8 +1641,8 @@
                 mTempTouchState.reset();
                 if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||
                     maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
-                    mTempTouchState.deviceId = entry->deviceId;
-                    mTempTouchState.source = entry->source;
+                    mTempTouchState.deviceId = entry.deviceId;
+                    mTempTouchState.source = entry.source;
                     mTempTouchState.displayId = displayId;
                 }
             } else if (maskedAction == AMOTION_EVENT_ACTION_UP ||
@@ -1661,7 +1661,7 @@
                 // One pointer went up.
                 if (isSplit) {
                     int32_t pointerIndex = getMotionEventActionPointerIndex(action);
-                    uint32_t pointerId = entry->pointerProperties[pointerIndex].id;
+                    uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
 
                     for (size_t i = 0; i < mTempTouchState.windows.size();) {
                         TouchedWindow& touchedWindow = mTempTouchState.windows[i];
@@ -1821,7 +1821,7 @@
 
 std::string InputDispatcher::checkWindowReadyForMoreInputLocked(
         nsecs_t currentTime, const sp<InputWindowHandle>& windowHandle,
-        const EventEntry* eventEntry, const char* targetType) {
+        const EventEntry& eventEntry, const char* targetType) {
     // If the window is paused then keep waiting.
     if (windowHandle->getInfo()->paused) {
         return StringPrintf("Waiting because the %s window is paused.", targetType);
@@ -1853,7 +1853,7 @@
     }
 
     // Ensure that the dispatch queues aren't too far backed up for this event.
-    if (eventEntry->type == EventEntry::TYPE_KEY) {
+    if (eventEntry.type == EventEntry::TYPE_KEY) {
         // If the event is a key event, then we must wait for all previous events to
         // complete before delivering it because previous events may have the
         // side-effect of transferring focus to a different window and we want to
@@ -1925,7 +1925,7 @@
     }
 }
 
-void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
+void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) {
     int32_t displayId = getTargetDisplayId(eventEntry);
     sp<InputWindowHandle> focusedWindowHandle =
             getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
@@ -1940,21 +1940,21 @@
     }
 
     int32_t eventType = USER_ACTIVITY_EVENT_OTHER;
-    switch (eventEntry->type) {
+    switch (eventEntry.type) {
         case EventEntry::TYPE_MOTION: {
-            const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry);
-            if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) {
+            const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
+            if (motionEntry.action == AMOTION_EVENT_ACTION_CANCEL) {
                 return;
             }
 
-            if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) {
+            if (MotionEvent::isTouchEvent(motionEntry.source, motionEntry.action)) {
                 eventType = USER_ACTIVITY_EVENT_TOUCH;
             }
             break;
         }
         case EventEntry::TYPE_KEY: {
-            const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry);
-            if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) {
+            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(eventEntry);
+            if (keyEntry.flags & AKEY_EVENT_FLAG_CANCELED) {
                 return;
             }
             eventType = USER_ACTIVITY_EVENT_BUTTON;
@@ -1964,7 +1964,7 @@
 
     std::unique_ptr<CommandEntry> commandEntry =
             std::make_unique<CommandEntry>(&InputDispatcher::doPokeUserActivityLockedInterruptible);
-    commandEntry->eventTime = eventEntry->eventTime;
+    commandEntry->eventTime = eventEntry.eventTime;
     commandEntry->userActivityEventType = eventType;
     postCommandLocked(std::move(commandEntry));
 }
@@ -2002,8 +2002,8 @@
     if (inputTarget->flags & InputTarget::FLAG_SPLIT) {
         ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION);
 
-        MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry);
-        if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) {
+        const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
+        if (inputTarget->pointerIds.count() != originalMotionEntry.pointerCount) {
             MotionEntry* splitMotionEntry =
                     splitMotionEvent(originalMotionEntry, inputTarget->pointerIds);
             if (!splitMotionEntry) {
@@ -2012,7 +2012,7 @@
             if (DEBUG_FOCUS) {
                 ALOGD("channel '%s' ~ Split motion event.",
                       connection->getInputChannelName().c_str());
-                logOutboundMotionDetails("  ", splitMotionEntry);
+                logOutboundMotionDetails("  ", *splitMotionEntry);
             }
             enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget);
             splitMotionEntry->release();
@@ -2085,9 +2085,9 @@
     // Apply target flags and update the connection's input state.
     switch (eventEntry->type) {
         case EventEntry::TYPE_KEY: {
-            KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
-            dispatchEntry->resolvedAction = keyEntry->action;
-            dispatchEntry->resolvedFlags = keyEntry->flags;
+            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*eventEntry);
+            dispatchEntry->resolvedAction = keyEntry.action;
+            dispatchEntry->resolvedFlags = keyEntry.flags;
 
             if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction,
                                                  dispatchEntry->resolvedFlags)) {
@@ -2102,7 +2102,7 @@
         }
 
         case EventEntry::TYPE_MOTION: {
-            MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
+            const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
             if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
                 dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
             } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
@@ -2114,11 +2114,11 @@
             } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) {
                 dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
             } else {
-                dispatchEntry->resolvedAction = motionEntry->action;
+                dispatchEntry->resolvedAction = motionEntry.action;
             }
             if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE &&
-                !connection->inputState.isHovering(motionEntry->deviceId, motionEntry->source,
-                                                   motionEntry->displayId)) {
+                !connection->inputState.isHovering(motionEntry.deviceId, motionEntry.source,
+                                                   motionEntry.displayId)) {
 #if DEBUG_DISPATCH_CYCLE
                 ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter "
                       "event",
@@ -2127,7 +2127,7 @@
                 dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
             }
 
-            dispatchEntry->resolvedFlags = motionEntry->flags;
+            dispatchEntry->resolvedFlags = motionEntry.flags;
             if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
                 dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
             }
@@ -2146,7 +2146,7 @@
                 return; // skip the inconsistent event
             }
 
-            dispatchPointerDownOutsideFocus(motionEntry->source, dispatchEntry->resolvedAction,
+            dispatchPointerDownOutsideFocus(motionEntry.source, dispatchEntry->resolvedAction,
                                             inputTarget->inputChannel->getToken());
 
             break;
@@ -2508,11 +2508,12 @@
             switch (cancelationEventEntry->type) {
                 case EventEntry::TYPE_KEY:
                     logOutboundKeyDetails("cancel - ",
-                                          static_cast<KeyEntry*>(cancelationEventEntry));
+                                          static_cast<const KeyEntry&>(*cancelationEventEntry));
                     break;
                 case EventEntry::TYPE_MOTION:
                     logOutboundMotionDetails("cancel - ",
-                                             static_cast<MotionEntry*>(cancelationEventEntry));
+                                             static_cast<const MotionEntry&>(
+                                                     *cancelationEventEntry));
                     break;
             }
 
@@ -2544,7 +2545,7 @@
     }
 }
 
-MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry,
+MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry& originalMotionEntry,
                                                BitSet32 pointerIds) {
     ALOG_ASSERT(pointerIds.value != 0);
 
@@ -2552,19 +2553,19 @@
     PointerProperties splitPointerProperties[MAX_POINTERS];
     PointerCoords splitPointerCoords[MAX_POINTERS];
 
-    uint32_t originalPointerCount = originalMotionEntry->pointerCount;
+    uint32_t originalPointerCount = originalMotionEntry.pointerCount;
     uint32_t splitPointerCount = 0;
 
     for (uint32_t originalPointerIndex = 0; originalPointerIndex < originalPointerCount;
          originalPointerIndex++) {
         const PointerProperties& pointerProperties =
-                originalMotionEntry->pointerProperties[originalPointerIndex];
+                originalMotionEntry.pointerProperties[originalPointerIndex];
         uint32_t pointerId = uint32_t(pointerProperties.id);
         if (pointerIds.hasBit(pointerId)) {
             splitPointerIndexMap[splitPointerCount] = originalPointerIndex;
             splitPointerProperties[splitPointerCount].copyFrom(pointerProperties);
             splitPointerCoords[splitPointerCount].copyFrom(
-                    originalMotionEntry->pointerCoords[originalPointerIndex]);
+                    originalMotionEntry.pointerCoords[originalPointerIndex]);
             splitPointerCount += 1;
         }
     }
@@ -2582,13 +2583,13 @@
         return nullptr;
     }
 
-    int32_t action = originalMotionEntry->action;
+    int32_t action = originalMotionEntry.action;
     int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
     if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN ||
         maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
         int32_t originalPointerIndex = getMotionEventActionPointerIndex(action);
         const PointerProperties& pointerProperties =
-                originalMotionEntry->pointerProperties[originalPointerIndex];
+                originalMotionEntry.pointerProperties[originalPointerIndex];
         uint32_t pointerId = uint32_t(pointerProperties.id);
         if (pointerIds.hasBit(pointerId)) {
             if (pointerIds.count() == 1) {
@@ -2612,19 +2613,19 @@
     }
 
     MotionEntry* splitMotionEntry =
-            new MotionEntry(originalMotionEntry->sequenceNum, originalMotionEntry->eventTime,
-                            originalMotionEntry->deviceId, originalMotionEntry->source,
-                            originalMotionEntry->displayId, originalMotionEntry->policyFlags,
-                            action, originalMotionEntry->actionButton, originalMotionEntry->flags,
-                            originalMotionEntry->metaState, originalMotionEntry->buttonState,
-                            originalMotionEntry->classification, originalMotionEntry->edgeFlags,
-                            originalMotionEntry->xPrecision, originalMotionEntry->yPrecision,
-                            originalMotionEntry->xCursorPosition,
-                            originalMotionEntry->yCursorPosition, originalMotionEntry->downTime,
+            new MotionEntry(originalMotionEntry.sequenceNum, originalMotionEntry.eventTime,
+                            originalMotionEntry.deviceId, originalMotionEntry.source,
+                            originalMotionEntry.displayId, originalMotionEntry.policyFlags, action,
+                            originalMotionEntry.actionButton, originalMotionEntry.flags,
+                            originalMotionEntry.metaState, originalMotionEntry.buttonState,
+                            originalMotionEntry.classification, originalMotionEntry.edgeFlags,
+                            originalMotionEntry.xPrecision, originalMotionEntry.yPrecision,
+                            originalMotionEntry.xCursorPosition,
+                            originalMotionEntry.yCursorPosition, originalMotionEntry.downTime,
                             splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0);
 
-    if (originalMotionEntry->injectionState) {
-        splitMotionEntry->injectionState = originalMotionEntry->injectionState;
+    if (originalMotionEntry.injectionState) {
+        splitMotionEntry->injectionState = originalMotionEntry.injectionState;
         splitMotionEntry->injectionState->refCount += 1;
     }
 
@@ -3221,7 +3222,7 @@
                     !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_TOUCHABLE) ||
                     !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_FOCUSABLE);
             if (canReceiveInput && !noInputChannel) {
-                ALOGE("Window handle %s has no registered input channel",
+                ALOGV("Window handle %s has no registered input channel",
                       handle->getName().c_str());
             }
             continue;
@@ -3865,11 +3866,9 @@
     }
 }
 
-status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
-                                               int32_t displayId) {
+status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
 #if DEBUG_REGISTRATION
-    ALOGD("channel '%s' ~ registerInputChannel - displayId=%" PRId32,
-          inputChannel->getName().c_str(), displayId);
+    ALOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().c_str());
 #endif
 
     { // acquire lock
@@ -3956,7 +3955,7 @@
         return BAD_VALUE;
     }
 
-    const bool removed = removeByValue(mConnectionsByFd, connection);
+    [[maybe_unused]] const bool removed = removeByValue(mConnectionsByFd, connection);
     ALOG_ASSERT(removed);
     mInputChannelsByToken.erase(inputChannel->getToken());
 
@@ -4189,8 +4188,7 @@
         CommandEntry* commandEntry) {
     KeyEntry* entry = commandEntry->keyEntry;
 
-    KeyEvent event;
-    initializeKeyEvent(&event, entry);
+    KeyEvent event = createKeyEvent(*entry);
 
     mLock.unlock();
 
@@ -4310,8 +4308,7 @@
                   keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount,
                   keyEntry->policyFlags);
 #endif
-            KeyEvent event;
-            initializeKeyEvent(&event, keyEntry);
+            KeyEvent event = createKeyEvent(*keyEntry);
             event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED);
 
             mLock.unlock();
@@ -4353,8 +4350,7 @@
               "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
               keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags);
 #endif
-        KeyEvent event;
-        initializeKeyEvent(&event, keyEntry);
+        KeyEvent event = createKeyEvent(*keyEntry);
 
         mLock.unlock();
 
@@ -4471,13 +4467,15 @@
     mLock.lock();
 }
 
-void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) {
-    event->initialize(entry->deviceId, entry->source, entry->displayId, entry->action, entry->flags,
-                      entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount,
-                      entry->downTime, entry->eventTime);
+KeyEvent InputDispatcher::createKeyEvent(const KeyEntry& entry) {
+    KeyEvent event;
+    event.initialize(entry.deviceId, entry.source, entry.displayId, entry.action, entry.flags,
+                     entry.keyCode, entry.scanCode, entry.metaState, entry.repeatCount,
+                     entry.downTime, entry.eventTime);
+    return event;
 }
 
-void InputDispatcher::updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry,
+void InputDispatcher::updateDispatchStatistics(nsecs_t currentTime, const EventEntry& entry,
                                                int32_t injectionResult,
                                                nsecs_t timeSpentWaitingForApplication) {
     // TODO Write some statistics about how long we spend waiting.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 0d9d6b0..923d0e9 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -106,22 +106,20 @@
     virtual bool transferTouchFocus(const sp<IBinder>& fromToken,
                                     const sp<IBinder>& toToken) override;
 
-    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
-                                          int32_t displayId) override;
+    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel) override;
     virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel, int32_t displayId,
                                           bool isGestureMonitor) override;
     virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) override;
     virtual status_t pilferPointers(const sp<IBinder>& token) override;
 
 private:
-
-    enum DropReason {
-        DROP_REASON_NOT_DROPPED = 0,
-        DROP_REASON_POLICY = 1,
-        DROP_REASON_APP_SWITCH = 2,
-        DROP_REASON_DISABLED = 3,
-        DROP_REASON_BLOCKED = 4,
-        DROP_REASON_STALE = 5,
+    enum class DropReason {
+        NOT_DROPPED,
+        POLICY,
+        APP_SWITCH,
+        DISABLED,
+        BLOCKED,
+        STALE,
     };
 
     sp<InputDispatcherPolicyInterface> mPolicy;
@@ -146,7 +144,7 @@
     bool enqueueInboundEventLocked(EventEntry* entry) REQUIRES(mLock);
 
     // Cleans up input state when dropping an inbound event.
-    void dropInboundEventLocked(EventEntry* entry, DropReason dropReason) REQUIRES(mLock);
+    void dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) REQUIRES(mLock);
 
     // Adds an event to a queue of recent events for debugging purposes.
     void addRecentEventLocked(EventEntry* entry) REQUIRES(mLock);
@@ -155,12 +153,12 @@
     bool mAppSwitchSawKeyDown GUARDED_BY(mLock);
     nsecs_t mAppSwitchDueTime GUARDED_BY(mLock);
 
-    bool isAppSwitchKeyEvent(KeyEntry* keyEntry);
+    bool isAppSwitchKeyEvent(const KeyEntry& keyEntry);
     bool isAppSwitchPendingLocked() REQUIRES(mLock);
     void resetPendingAppSwitchLocked(bool handled) REQUIRES(mLock);
 
     // Stale event latency optimization.
-    static bool isStaleEvent(nsecs_t currentTime, EventEntry* entry);
+    static bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry);
 
     // Blocked event latency optimization.  Drops old events when the user intends
     // to transfer focus to a new application.
@@ -295,8 +293,8 @@
     void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry,
                              const std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
 
-    void logOutboundKeyDetails(const char* prefix, const KeyEntry* entry);
-    void logOutboundMotionDetails(const char* prefix, const MotionEntry* entry);
+    void logOutboundKeyDetails(const char* prefix, const KeyEntry& entry);
+    void logOutboundMotionDetails(const char* prefix, const MotionEntry& entry);
 
     // Keeping track of ANR timeouts.
     enum InputTargetWaitCause {
@@ -315,7 +313,7 @@
     sp<InputWindowHandle> mLastHoverWindowHandle GUARDED_BY(mLock);
 
     // Finding targets for input events.
-    int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
+    int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry& entry,
                                         const sp<InputApplicationHandle>& applicationHandle,
                                         const sp<InputWindowHandle>& windowHandle,
                                         nsecs_t* nextWakeupTime, const char* reason)
@@ -329,11 +327,11 @@
     nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) REQUIRES(mLock);
     void resetANRTimeoutsLocked() REQUIRES(mLock);
 
-    int32_t getTargetDisplayId(const EventEntry* entry);
-    int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
+    int32_t getTargetDisplayId(const EventEntry& entry);
+    int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry& entry,
                                            std::vector<InputTarget>& inputTargets,
                                            nsecs_t* nextWakeupTime) REQUIRES(mLock);
-    int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
+    int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry& entry,
                                            std::vector<InputTarget>& inputTargets,
                                            nsecs_t* nextWakeupTime,
                                            bool* outConflictingPointerActions) REQUIRES(mLock);
@@ -352,7 +350,7 @@
     void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId,
                                           float xOffset = 0, float yOffset = 0) REQUIRES(mLock);
 
-    void pokeUserActivityLocked(const EventEntry* eventEntry) REQUIRES(mLock);
+    void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock);
     bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
                                   const InjectionState* injectionState);
     bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, int32_t x,
@@ -363,7 +361,7 @@
 
     std::string checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
                                                    const sp<InputWindowHandle>& windowHandle,
-                                                   const EventEntry* eventEntry,
+                                                   const EventEntry& eventEntry,
                                                    const char* targetType) REQUIRES(mLock);
 
     // Manage the dispatch cycle for a single connection.
@@ -407,7 +405,7 @@
             REQUIRES(mLock);
 
     // Splitting motion events across windows.
-    MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds);
+    MotionEntry* splitMotionEvent(const MotionEntry& originalMotionEntry, BitSet32 pointerIds);
 
     // Reset and drop everything the dispatcher is doing.
     void resetAndDropEverythingLocked(const char* reason) REQUIRES(mLock);
@@ -452,7 +450,7 @@
                                              DispatchEntry* dispatchEntry, MotionEntry* motionEntry,
                                              bool handled) REQUIRES(mLock);
     void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
-    void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry);
+    KeyEvent createKeyEvent(const KeyEntry& entry);
     void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
 
     // Statistics gathering.
@@ -460,7 +458,7 @@
     LatencyStatistics mTouchStatistics{TOUCH_STATS_REPORT_PERIOD};
 
     void reportTouchEventForStatistics(const MotionEntry& entry);
-    void updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry,
+    void updateDispatchStatistics(nsecs_t currentTime, const EventEntry& entry,
                                   int32_t injectionResult, nsecs_t timeSpentWaitingForApplication);
     void traceInboundQueueLengthLocked() REQUIRES(mLock);
     void traceOutboundQueueLength(const sp<Connection>& connection);
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index c60700e..603c257 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -36,12 +36,12 @@
     return false;
 }
 
-bool InputState::trackKey(const KeyEntry* entry, int32_t action, int32_t flags) {
+bool InputState::trackKey(const KeyEntry& entry, int32_t action, int32_t flags) {
     switch (action) {
         case AKEY_EVENT_ACTION_UP: {
-            if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) {
+            if (entry.flags & AKEY_EVENT_FLAG_FALLBACK) {
                 for (size_t i = 0; i < mFallbackKeys.size();) {
-                    if (mFallbackKeys.valueAt(i) == entry->keyCode) {
+                    if (mFallbackKeys.valueAt(i) == entry.keyCode) {
                         mFallbackKeys.removeItemsAt(i);
                     } else {
                         i += 1;
@@ -65,7 +65,7 @@
     #if DEBUG_OUTBOUND_EVENT_DETAILS
             ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, "
                     "keyCode=%d, scanCode=%d",
-                    entry->deviceId, entry->source, entry->keyCode, entry->scanCode);
+                    entry.deviceId, entry.source, entry.keyCode, entry.scanCode);
     #endif
             return false;
             */
@@ -86,7 +86,7 @@
     }
 }
 
-bool InputState::trackMotion(const MotionEntry* entry, int32_t action, int32_t flags) {
+bool InputState::trackMotion(const MotionEntry& entry, int32_t action, int32_t flags) {
     int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK;
     switch (actionMasked) {
         case AMOTION_EVENT_ACTION_UP:
@@ -99,7 +99,7 @@
 #if DEBUG_OUTBOUND_EVENT_DETAILS
             ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
                   "displayId=%" PRId32 ", actionMasked=%d",
-                  entry->deviceId, entry->source, entry->displayId, actionMasked);
+                  entry.deviceId, entry.source, entry.displayId, actionMasked);
 #endif
             return false;
         }
@@ -116,7 +116,7 @@
         case AMOTION_EVENT_ACTION_POINTER_UP:
         case AMOTION_EVENT_ACTION_POINTER_DOWN:
         case AMOTION_EVENT_ACTION_MOVE: {
-            if (entry->source & AINPUT_SOURCE_CLASS_NAVIGATION) {
+            if (entry.source & AINPUT_SOURCE_CLASS_NAVIGATION) {
                 // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need
                 // to generate cancellation events for these since they're based in relative rather
                 // than absolute units.
@@ -125,20 +125,20 @@
 
             ssize_t index = findMotionMemento(entry, false /*hovering*/);
 
-            if (entry->source & AINPUT_SOURCE_CLASS_JOYSTICK) {
+            if (entry.source & AINPUT_SOURCE_CLASS_JOYSTICK) {
                 // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all
                 // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral.
                 // Any other value and we need to track the motion so we can send cancellation
                 // events for anything generating fallback events (e.g. DPad keys for joystick
                 // movements).
                 if (index >= 0) {
-                    if (entry->pointerCoords[0].isEmpty()) {
+                    if (entry.pointerCoords[0].isEmpty()) {
                         mMotionMementos.erase(mMotionMementos.begin() + index);
                     } else {
                         MotionMemento& memento = mMotionMementos[index];
                         memento.setPointers(entry);
                     }
-                } else if (!entry->pointerCoords[0].isEmpty()) {
+                } else if (!entry.pointerCoords[0].isEmpty()) {
                     addMotionMemento(entry, flags, false /*hovering*/);
                 }
 
@@ -153,7 +153,7 @@
 #if DEBUG_OUTBOUND_EVENT_DETAILS
             ALOGD("Dropping inconsistent motion pointer up/down or move event: "
                   "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d",
-                  entry->deviceId, entry->source, entry->displayId, actionMasked);
+                  entry.deviceId, entry.source, entry.displayId, actionMasked);
 #endif
             return false;
         }
@@ -167,7 +167,7 @@
 #if DEBUG_OUTBOUND_EVENT_DETAILS
             ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, "
                   "displayId=%" PRId32,
-                  entry->deviceId, entry->source, entry->displayId);
+                  entry.deviceId, entry.source, entry.displayId);
 #endif
             return false;
         }
@@ -187,65 +187,65 @@
     }
 }
 
-ssize_t InputState::findKeyMemento(const KeyEntry* entry) const {
+ssize_t InputState::findKeyMemento(const KeyEntry& entry) const {
     for (size_t i = 0; i < mKeyMementos.size(); i++) {
         const KeyMemento& memento = mKeyMementos[i];
-        if (memento.deviceId == entry->deviceId && memento.source == entry->source &&
-            memento.displayId == entry->displayId && memento.keyCode == entry->keyCode &&
-            memento.scanCode == entry->scanCode) {
+        if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
+            memento.displayId == entry.displayId && memento.keyCode == entry.keyCode &&
+            memento.scanCode == entry.scanCode) {
             return i;
         }
     }
     return -1;
 }
 
-ssize_t InputState::findMotionMemento(const MotionEntry* entry, bool hovering) const {
+ssize_t InputState::findMotionMemento(const MotionEntry& entry, bool hovering) const {
     for (size_t i = 0; i < mMotionMementos.size(); i++) {
         const MotionMemento& memento = mMotionMementos[i];
-        if (memento.deviceId == entry->deviceId && memento.source == entry->source &&
-            memento.displayId == entry->displayId && memento.hovering == hovering) {
+        if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
+            memento.displayId == entry.displayId && memento.hovering == hovering) {
             return i;
         }
     }
     return -1;
 }
 
-void InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) {
+void InputState::addKeyMemento(const KeyEntry& entry, int32_t flags) {
     KeyMemento memento;
-    memento.deviceId = entry->deviceId;
-    memento.source = entry->source;
-    memento.displayId = entry->displayId;
-    memento.keyCode = entry->keyCode;
-    memento.scanCode = entry->scanCode;
-    memento.metaState = entry->metaState;
+    memento.deviceId = entry.deviceId;
+    memento.source = entry.source;
+    memento.displayId = entry.displayId;
+    memento.keyCode = entry.keyCode;
+    memento.scanCode = entry.scanCode;
+    memento.metaState = entry.metaState;
     memento.flags = flags;
-    memento.downTime = entry->downTime;
-    memento.policyFlags = entry->policyFlags;
+    memento.downTime = entry.downTime;
+    memento.policyFlags = entry.policyFlags;
     mKeyMementos.push_back(memento);
 }
 
-void InputState::addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering) {
+void InputState::addMotionMemento(const MotionEntry& entry, int32_t flags, bool hovering) {
     MotionMemento memento;
-    memento.deviceId = entry->deviceId;
-    memento.source = entry->source;
-    memento.displayId = entry->displayId;
+    memento.deviceId = entry.deviceId;
+    memento.source = entry.source;
+    memento.displayId = entry.displayId;
     memento.flags = flags;
-    memento.xPrecision = entry->xPrecision;
-    memento.yPrecision = entry->yPrecision;
-    memento.xCursorPosition = entry->xCursorPosition;
-    memento.yCursorPosition = entry->yCursorPosition;
-    memento.downTime = entry->downTime;
+    memento.xPrecision = entry.xPrecision;
+    memento.yPrecision = entry.yPrecision;
+    memento.xCursorPosition = entry.xCursorPosition;
+    memento.yCursorPosition = entry.yCursorPosition;
+    memento.downTime = entry.downTime;
     memento.setPointers(entry);
     memento.hovering = hovering;
-    memento.policyFlags = entry->policyFlags;
+    memento.policyFlags = entry.policyFlags;
     mMotionMementos.push_back(memento);
 }
 
-void InputState::MotionMemento::setPointers(const MotionEntry* entry) {
-    pointerCount = entry->pointerCount;
-    for (uint32_t i = 0; i < entry->pointerCount; i++) {
-        pointerProperties[i].copyFrom(entry->pointerProperties[i]);
-        pointerCoords[i].copyFrom(entry->pointerCoords[i]);
+void InputState::MotionMemento::setPointers(const MotionEntry& entry) {
+    pointerCount = entry.pointerCount;
+    for (uint32_t i = 0; i < entry.pointerCount; i++) {
+        pointerProperties[i].copyFrom(entry.pointerProperties[i]);
+        pointerCoords[i].copyFrom(entry.pointerCoords[i]);
     }
 }
 
diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h
index 47e9b36..cc72152 100644
--- a/services/inputflinger/dispatcher/InputState.h
+++ b/services/inputflinger/dispatcher/InputState.h
@@ -41,12 +41,12 @@
     // Records tracking information for a key event that has just been published.
     // Returns true if the event should be delivered, false if it is inconsistent
     // and should be skipped.
-    bool trackKey(const KeyEntry* entry, int32_t action, int32_t flags);
+    bool trackKey(const KeyEntry& entry, int32_t action, int32_t flags);
 
     // Records tracking information for a motion event that has just been published.
     // Returns true if the event should be delivered, false if it is inconsistent
     // and should be skipped.
-    bool trackMotion(const MotionEntry* entry, int32_t action, int32_t flags);
+    bool trackMotion(const MotionEntry& entry, int32_t action, int32_t flags);
 
     // Synthesizes cancelation events for the current state and resets the tracked state.
     void synthesizeCancelationEvents(nsecs_t currentTime, std::vector<EventEntry*>& outEvents,
@@ -100,18 +100,18 @@
         bool hovering;
         uint32_t policyFlags;
 
-        void setPointers(const MotionEntry* entry);
+        void setPointers(const MotionEntry& entry);
     };
 
     std::vector<KeyMemento> mKeyMementos;
     std::vector<MotionMemento> mMotionMementos;
     KeyedVector<int32_t, int32_t> mFallbackKeys;
 
-    ssize_t findKeyMemento(const KeyEntry* entry) const;
-    ssize_t findMotionMemento(const MotionEntry* entry, bool hovering) const;
+    ssize_t findKeyMemento(const KeyEntry& entry) const;
+    ssize_t findMotionMemento(const MotionEntry& entry, bool hovering) const;
 
-    void addKeyMemento(const KeyEntry* entry, int32_t flags);
-    void addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering);
+    void addKeyMemento(const KeyEntry& entry, int32_t flags);
+    void addMotionMemento(const MotionEntry& entry, int32_t flags, bool hovering);
 
     static bool shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options);
     static bool shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options);
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index 18848a0..2baceba 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -93,15 +93,6 @@
                            std::end(newMonitors));
 }
 
-void TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) {
-    for (size_t i = 0; i < windows.size(); i++) {
-        if (windows[i].windowHandle == windowHandle) {
-            windows.erase(windows.begin() + i);
-            return;
-        }
-    }
-}
-
 void TouchState::removeWindowByToken(const sp<IBinder>& token) {
     for (size_t i = 0; i < windows.size(); i++) {
         if (windows[i].windowHandle->getToken() == token) {
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index 3e0e0eb..623c6a8 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -49,7 +49,6 @@
                            BitSet32 pointerIds);
     void addPortalWindow(const sp<android::InputWindowHandle>& windowHandle);
     void addGestureMonitors(const std::vector<TouchedMonitor>& monitors);
-    void removeWindow(const sp<android::InputWindowHandle>& windowHandle);
     void removeWindowByToken(const sp<IBinder>& token);
     void filterNonAsIsTouchWindows();
     void filterNonMonitors();
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 9329ca6..ce7366f 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -126,8 +126,7 @@
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
-                                          int32_t displayId) = 0;
+    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel) = 0;
 
     /* Registers input channels to be used to monitor input events.
      *
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
index 2f046c3..683c05d 100644
--- a/services/inputflinger/host/InputDriver.cpp
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -127,10 +127,10 @@
             input_bus_t bus, const char* uniqueId) {
     auto identifier = new ::input_device_identifier {
         .name = name,
-        .productId = productId,
-        .vendorId = vendorId,
-        .bus = bus,
         .uniqueId = uniqueId,
+        .bus = bus,
+        .vendorId = vendorId,
+        .productId = productId,
     };
     // TODO: store this identifier somewhere
     return identifier;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 34603b9..c80a2dc 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -668,7 +668,7 @@
                     naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
                     naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
                     naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
-                    naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom;
+                    naturalPhysicalLeft = mViewport.deviceHeight - naturalPhysicalWidth;
                     naturalPhysicalTop = mViewport.physicalLeft;
                     naturalDeviceWidth = mViewport.deviceHeight;
                     naturalDeviceHeight = mViewport.deviceWidth;
@@ -689,7 +689,7 @@
                     naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
                     naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
                     naturalPhysicalLeft = mViewport.physicalTop;
-                    naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight;
+                    naturalPhysicalTop = mViewport.deviceWidth - naturalPhysicalHeight;
                     naturalDeviceWidth = mViewport.deviceHeight;
                     naturalDeviceHeight = mViewport.deviceWidth;
                     break;
@@ -2173,6 +2173,7 @@
         // TODO: Adjust coverage coords?
         float xTransformed = in.x, yTransformed = in.y;
         mAffineTransform.applyTo(xTransformed, yTransformed);
+        rotateAndScale(xTransformed, yTransformed);
 
         // Adjust X, Y, and coverage coords for surface orientation.
         float x, y;
@@ -2180,8 +2181,8 @@
 
         switch (mSurfaceOrientation) {
             case DISPLAY_ORIENTATION_90:
-                x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
-                y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;
+                x = yTransformed + mYTranslate;
+                y = xTransformed + mXTranslate;
                 left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
                 right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
                 bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
@@ -2194,8 +2195,8 @@
                 }
                 break;
             case DISPLAY_ORIENTATION_180:
-                x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale;
-                y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;
+                x = xTransformed + mXTranslate;
+                y = yTransformed + mYTranslate;
                 left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
                 right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
                 bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
@@ -2208,8 +2209,8 @@
                 }
                 break;
             case DISPLAY_ORIENTATION_270:
-                x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale;
-                y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
+                x = yTransformed + mYTranslate;
+                y = xTransformed + mXTranslate;
                 left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
                 right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
                 bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
@@ -2222,8 +2223,8 @@
                 }
                 break;
             default:
-                x = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-                y = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
+                x = xTransformed + mXTranslate;
+                y = yTransformed + mYTranslate;
                 left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
                 right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
                 bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
@@ -3617,13 +3618,34 @@
     abortTouches(when, 0 /* policyFlags*/);
 }
 
+void TouchInputMapper::rotateAndScale(float& x, float& y) {
+    switch (mSurfaceOrientation) {
+        case DISPLAY_ORIENTATION_90:
+            x = float(mRawPointerAxes.x.maxValue - x) * mXScale;
+            y = float(y - mRawPointerAxes.y.minValue) * mYScale;
+            break;
+        case DISPLAY_ORIENTATION_180:
+            x = float(mRawPointerAxes.x.maxValue - x) * mXScale;
+            y = float(mRawPointerAxes.y.maxValue - y) * mYScale;
+            break;
+        case DISPLAY_ORIENTATION_270:
+            x = float(x - mRawPointerAxes.x.minValue) * mXScale;
+            y = float(mRawPointerAxes.y.maxValue - y) * mYScale;
+            break;
+        default:
+            x = float(x - mRawPointerAxes.x.minValue) * mXScale;
+            y = float(y - mRawPointerAxes.y.minValue) * mYScale;
+            break;
+    }
+}
+
 bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
-    const float scaledX = x * mXScale;
-    const float scaledY = y * mYScale;
+    float xTransformed = x, yTransformed = y;
+    rotateAndScale(xTransformed, yTransformed);
     return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue &&
-            scaledX >= mSurfaceLeft && scaledX <= mSurfaceLeft + mSurfaceWidth &&
+            xTransformed >= mSurfaceLeft && xTransformed <= mSurfaceLeft + mSurfaceWidth &&
             y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue &&
-            scaledY >= mSurfaceTop && scaledY <= mSurfaceTop + mSurfaceHeight;
+            yTransformed >= mSurfaceTop && yTransformed <= mSurfaceTop + mSurfaceHeight;
 }
 
 const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) {
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 89c017d..4b1c0cb 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -758,6 +758,7 @@
     static void assignPointerIds(const RawState* last, RawState* current);
 
     const char* modeToString(DeviceMode deviceMode);
+    void rotateAndScale(float& x, float& y);
 };
 
 } // namespace android
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index aa98ef7..7d69854 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -471,7 +471,7 @@
             FakeInputReceiver(dispatcher, name, displayId),
             mFocused(false), mFrame(Rect(0, 0, WIDTH, HEIGHT)), mLayoutParamFlags(0) {
             mServerChannel->setToken(new BBinder());
-            mDispatcher->registerInputChannel(mServerChannel, displayId);
+            mDispatcher->registerInputChannel(mServerChannel);
 
             inputApplicationHandle->updateInfo();
             mInfo.applicationInfo = *inputApplicationHandle->getInfo();
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 59f275f..a5c226a 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -6669,20 +6669,41 @@
     MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
     addConfigurationProperty("touch.deviceType", "touchScreen");
     prepareDisplay(DISPLAY_ORIENTATION_0);
-    // Let surface be different from physical display.
-    std::optional<DisplayViewport> internalViewport =
-            mFakePolicy->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
-    internalViewport->logicalLeft = internalViewport->physicalTop + 20;
-    internalViewport->logicalTop = internalViewport->physicalRight + 20;
-    internalViewport->logicalRight = internalViewport->physicalRight - 20;
-    internalViewport->logicalBottom = internalViewport->physicalBottom - 20;
-    mFakePolicy->updateViewport(internalViewport.value());
-
     prepareAxes(POSITION);
     addMapperAndConfigure(mapper);
 
-    int32_t rawX = 10;
-    int32_t rawY = 10;
+    // Touch on left-top area should work.
+    int32_t rawX = DISPLAY_WIDTH / 2 - 1;
+    int32_t rawY = DISPLAY_HEIGHT / 2 - 1;
+    processPosition(mapper, rawX, rawY);
+    processSync(mapper);
+
+    NotifyMotionArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+
+    // Reset.
+    mapper->reset(ARBITRARY_TIME);
+
+    // Let logical display be different to physical display and rotate 90-degrees.
+    std::optional<DisplayViewport> internalViewport =
+            mFakePolicy->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+    internalViewport->orientation = DISPLAY_ORIENTATION_90;
+    internalViewport->logicalLeft = 0;
+    internalViewport->logicalTop = 0;
+    internalViewport->logicalRight = DISPLAY_HEIGHT;
+    internalViewport->logicalBottom = DISPLAY_WIDTH / 2;
+
+    internalViewport->physicalLeft = DISPLAY_HEIGHT;
+    internalViewport->physicalTop = DISPLAY_WIDTH / 2;
+    internalViewport->physicalRight = DISPLAY_HEIGHT;
+    internalViewport->physicalBottom = DISPLAY_WIDTH;
+
+    internalViewport->deviceWidth = DISPLAY_HEIGHT;
+    internalViewport->deviceHeight = DISPLAY_WIDTH;
+    mFakePolicy->updateViewport(internalViewport.value());
+    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+    // Display align to right-top after rotate 90-degrees, touch on left-top area should not work.
     processPosition(mapper, rawX, rawY);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 060b5eb..fa23da0 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -180,7 +180,7 @@
             void onUidActive(uid_t uid);
             void onUidIdle(uid_t uid, bool disabled);
             void onUidStateChanged(uid_t uid __unused, int32_t procState __unused,
-                                   int64_t procStateSeq __unused) {}
+                                   int64_t procStateSeq __unused, int32_t capability __unused) {}
 
             void addOverrideUid(uid_t uid, bool active);
             void removeOverrideUid(uid_t uid);
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index b404836..e5d23d0 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -29,6 +29,7 @@
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.composer@2.4",
         "android.hardware.power@1.0",
         "android.hardware.power@1.3",
         "libbase",
@@ -92,6 +93,7 @@
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.composer@2.4",
         "android.hardware.power@1.3",
         "libhidlbase",
     ],
@@ -166,6 +168,7 @@
         "Scheduler/VSyncModulator.cpp",
         "StartPropertySetThread.cpp",
         "SurfaceFlinger.cpp",
+        "SurfaceFlingerDefaultFactory.cpp",
         "SurfaceInterceptor.cpp",
         "SurfaceTracing.cpp",
         "TransactionCompletedThread.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index b500ad3..a25709c 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -61,7 +61,7 @@
         mTextureName(args.textureName),
         mCompositionLayer{mFlinger->getCompositionEngine().createLayer(
                 compositionengine::LayerCreationArgs{this})} {
-    ALOGV("Creating Layer %s", args.name.string());
+    ALOGV("Creating Layer %s", getDebugName());
 
     mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
 
@@ -107,11 +107,8 @@
 }
 
 bool BufferLayer::isVisible() const {
-    bool visible = !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
+    return !isHiddenByPolicy() && getAlpha() > 0.0f &&
             (mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr);
-    mFlinger->mScheduler->setLayerVisibility(mSchedulerLayerHandle, visible);
-
-    return visible;
 }
 
 bool BufferLayer::isFixedSize() const {
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index eb13f65..dc61e49 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -62,7 +62,7 @@
     std::vector<OccupancyTracker::Segment> history;
     status_t result = mConsumer->getOccupancyHistory(forceFlush, &history);
     if (result != NO_ERROR) {
-        ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(), result);
+        ALOGW("[%s] Failed to obtain occupancy history (%d)", getDebugName(), result);
         return {};
     }
     return history;
@@ -110,7 +110,7 @@
     ALOGW_IF(!isPlausible,
              "[%s] Timestamp %" PRId64 " seems implausible "
              "relative to expectedPresent %" PRId64,
-             mName.string(), addedTime, expectedPresentTime);
+             getDebugName(), addedTime, expectedPresentTime);
 
     const bool isDue = addedTime < expectedPresentTime;
     return isDue || !isPlausible;
@@ -225,7 +225,7 @@
     bool queuedBuffer = false;
     const int32_t layerID = getSequence();
     LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
-                    getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
+                    getProducerStickyTransform() != 0, mName, mOverrideScalingMode,
                     getTransformToDisplayInverse());
 
     if (isRemovedFromCurrentState()) {
@@ -372,19 +372,38 @@
 // Interface implementation for BufferLayerConsumer::ContentsChangedListener
 // -----------------------------------------------------------------------
 
-void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
+void BufferQueueLayer::onFrameDequeued(const uint64_t bufferId) {
     const int32_t layerID = getSequence();
     mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str());
+    mFlinger->mFrameTracer->traceTimestamp(layerID, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER,
+                                           systemTime(), FrameTracer::FrameEvent::DEQUEUE);
+}
+
+void BufferQueueLayer::onFrameDetached(const uint64_t bufferId) {
+    const int32_t layerID = getSequence();
+    mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str());
+    mFlinger->mFrameTracer->traceTimestamp(layerID, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER,
+                                           systemTime(), FrameTracer::FrameEvent::DETACH);
+}
+
+void BufferQueueLayer::onFrameCancelled(const uint64_t bufferId) {
+    const int32_t layerID = getSequence();
+    mFlinger->mFrameTracer->traceTimestamp(layerID, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER,
+                                           systemTime(), FrameTracer::FrameEvent::CANCEL);
+}
+
+void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
+    const int32_t layerID = getSequence();
     mFlinger->mFrameTracer->traceTimestamp(layerID, item.mGraphicBuffer->getId(), item.mFrameNumber,
-                                           systemTime(), FrameTracer::FrameEvent::POST);
+                                           systemTime(), FrameTracer::FrameEvent::QUEUE);
 
     ATRACE_CALL();
     // Add this buffer from our internal queue tracker
     { // Autolock scope
         if (mFlinger->mUseSmart90ForVideo) {
             const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp;
-            mFlinger->mScheduler->addLayerPresentTimeAndHDR(mSchedulerLayerHandle, presentTime,
-                                                            item.mHdrMetadata.validTypes != 0);
+            mFlinger->mScheduler->recordLayerHistory(this, presentTime,
+                                                     item.mHdrMetadata.validTypes != 0);
         }
 
         Mutex::Autolock lock(mQueueItemLock);
@@ -398,7 +417,7 @@
         while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
             status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
             if (result != NO_ERROR) {
-                ALOGE("[%s] Timed out waiting on callback", mName.string());
+                ALOGE("[%s] Timed out waiting on callback", getDebugName());
             }
         }
 
@@ -426,7 +445,7 @@
         while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
             status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
             if (result != NO_ERROR) {
-                ALOGE("[%s] Timed out waiting on callback", mName.string());
+                ALOGE("[%s] Timed out waiting on callback", getDebugName());
             }
         }
 
@@ -459,12 +478,14 @@
     // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
-    BufferQueue::createBufferQueue(&producer, &consumer, true);
-    mProducer = new MonitoredProducer(producer, mFlinger, this);
-    mConsumer = new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName, this);
+    mFlinger->getFactory().createBufferQueue(&producer, &consumer, true);
+    mProducer = mFlinger->getFactory().createMonitoredProducer(producer, mFlinger, this);
+    mConsumer =
+            mFlinger->getFactory().createBufferLayerConsumer(consumer, mFlinger->getRenderEngine(),
+                                                             mTextureName, this);
     mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
     mConsumer->setContentsChangedListener(this);
-    mConsumer->setName(mName);
+    mConsumer->setName(String8(mName.data(), mName.size()));
 
     // BufferQueueCore::mMaxDequeuedBufferCount is default to 1
     if (!mFlinger->isLayerTripleBufferingDisabled()) {
@@ -527,11 +548,9 @@
 }
 
 sp<Layer> BufferQueueLayer::createClone() {
-    const String8 name = mName + " (Mirror)";
-    LayerCreationArgs args =
-            LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata());
+    LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, LayerMetadata());
     args.textureName = mTextureName;
-    sp<BufferQueueLayer> layer = new BufferQueueLayer(args);
+    sp<BufferQueueLayer> layer = mFlinger->getFactory().createBufferQueueLayer(args);
     layer->setInitialValuesForClone(this);
 
     return layer;
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index f3e8a19..1b1fccd 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -93,6 +93,9 @@
     void onFrameAvailable(const BufferItem& item) override;
     void onFrameReplaced(const BufferItem& item) override;
     void onSidebandStreamChanged() override;
+    void onFrameDequeued(const uint64_t bufferId) override;
+    void onFrameDetached(const uint64_t bufferId) override;
+    void onFrameCancelled(const uint64_t bufferId) override;
     // -----------------------------------------------------------------------
 
 public:
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index fa4539a..5768edd 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -103,12 +103,15 @@
     }
 }
 
-void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
-    // TODO(marissaw): send the transform hint to buffer owner
-    return;
+void BufferStateLayer::setTransformHint(uint32_t orientation) const {
+    mTransformHint = orientation;
 }
 
 void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
+    for (const auto& handle : mDrawingState.callbackHandles) {
+        handle->transformHint = mTransformHint;
+    }
+
     mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
             mDrawingState.callbackHandles);
 
@@ -136,7 +139,7 @@
         return;
     }
     mPendingStates.push_back(mCurrentState);
-    ATRACE_INT(mTransactionName.string(), mPendingStates.size());
+    ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
 }
 
 bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
@@ -246,8 +249,8 @@
 
     if (mFlinger->mUseSmart90ForVideo) {
         const nsecs_t presentTime = (desiredPresentTime == -1) ? 0 : desiredPresentTime;
-        mFlinger->mScheduler->addLayerPresentTimeAndHDR(mSchedulerLayerHandle, presentTime,
-                                                        mCurrentState.hdrMetadata.validTypes != 0);
+        mFlinger->mScheduler->recordLayerHistory(this, presentTime,
+                                                 mCurrentState.hdrMetadata.validTypes != 0);
     }
 
     return true;
@@ -479,7 +482,7 @@
         (s.active.w != bufferWidth || s.active.h != bufferHeight)) {
         ALOGE("[%s] rejecting buffer: "
               "bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
-              mName.string(), bufferWidth, bufferHeight, s.active.w, s.active.h);
+              getDebugName(), bufferWidth, bufferHeight, s.active.w, s.active.h);
         mFlinger->mTimeStats->removeTimeRecord(layerID, mFrameNumber);
         return BAD_VALUE;
     }
@@ -669,11 +672,9 @@
 }
 
 sp<Layer> BufferStateLayer::createClone() {
-    const String8 name = mName + " (Mirror)";
-    LayerCreationArgs args =
-            LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata());
+    LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, LayerMetadata());
     args.textureName = mTextureName;
-    sp<BufferStateLayer> layer = new BufferStateLayer(args);
+    sp<BufferStateLayer> layer = mFlinger->getFactory().createBufferStateLayer(args);
     layer->mHwcSlotGenerator = mHwcSlotGenerator;
     layer->setInitialValuesForClone(this);
     return layer;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 3dfe76c..289bb17 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -149,6 +149,8 @@
     bool mReleasePreviousBuffer = false;
     nsecs_t mCallbackHandleAcquireTime = -1;
 
+    mutable uint32_t mTransformHint = 0;
+
     // TODO(marissaw): support sticky transform for LEGACY camera mode
 
     class HwcSlotGenerator : public ClientCache::ErasedRecipient {
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 5b62054..8bfa569 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -108,13 +108,11 @@
 }
 
 sp<Layer> ColorLayer::createClone() {
-    String8 name = mName + " (Mirror)";
-    sp<ColorLayer> layer = new ColorLayer(
-            LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata()));
+    sp<ColorLayer> layer = mFlinger->getFactory().createColorLayer(
+            LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0,
+                              LayerMetadata()));
     layer->setInitialValuesForClone(this);
     return layer;
 }
 
-// ---------------------------------------------------------------------------
-
-}; // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 1407ef7..738a2a4 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -11,6 +11,7 @@
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.composer@2.4",
         "android.hardware.power@1.0",
         "android.hardware.power@1.3",
         "libbase",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index 389b605..a9a95cd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -74,7 +74,7 @@
 
     // Recalculates the state of the output layer from the output-independent
     // layer. If includeGeometry is false, the geometry state can be skipped.
-    virtual void updateCompositionState(bool includeGeometry) = 0;
+    virtual void updateCompositionState(bool includeGeometry, bool forceClientComposition) = 0;
 
     // Writes the geometry state to the HWC, or does nothing if this layer does
     // not use the HWC. If includeGeometry is false, the geometry state can be
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 34dbfb7..95c8afb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -39,7 +39,7 @@
 
     void setHwcLayer(std::shared_ptr<HWC2::Layer>) override;
 
-    void updateCompositionState(bool) override;
+    void updateCompositionState(bool includeGeometry, bool forceClientComposition) override;
     void writeStateToHWC(bool) override;
     void writeCursorPositionToHWC() const override;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 4f2afac..631760a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -40,7 +40,7 @@
     MOCK_CONST_METHOD0(getState, const impl::OutputLayerCompositionState&());
     MOCK_METHOD0(editState, impl::OutputLayerCompositionState&());
 
-    MOCK_METHOD1(updateCompositionState, void(bool));
+    MOCK_METHOD2(updateCompositionState, void(bool, bool));
     MOCK_METHOD1(writeStateToHWC, void(bool));
     MOCK_CONST_METHOD0(writeCursorPositionToHWC, void());
 
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 2007ea3..aa638b7 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -552,11 +552,8 @@
     ALOGV(__FUNCTION__);
 
     for (auto* layer : getOutputLayersOrderedByZ()) {
-        if (refreshArgs.devOptForceClientComposition) {
-            layer->editState().forceClientComposition = true;
-        }
-
-        layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame);
+        layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame,
+                                      refreshArgs.devOptForceClientComposition);
 
         // Send the updated state to the HWC, if appropriate.
         layer->writeStateToHWC(refreshArgs.updatingGeometryThisFrame);
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 0124e5b..ce0222c 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -259,7 +259,7 @@
     return transform.getOrientation();
 } // namespace impl
 
-void OutputLayer::updateCompositionState(bool includeGeometry) {
+void OutputLayer::updateCompositionState(bool includeGeometry, bool forceClientComposition) {
     const auto& layerFEState = getLayer().getFEState();
     const auto& outputState = getOutput().getState();
     const auto& profile = *getOutput().getDisplayColorProfile();
@@ -294,7 +294,8 @@
 
     // These are evaluated every frame as they can potentially change at any
     // time.
-    if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(state.dataspace)) {
+    if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(state.dataspace) ||
+        forceClientComposition) {
         state.forceClientComposition = true;
     }
 }
@@ -325,6 +326,9 @@
     writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), outputIndependentState);
 
     writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType);
+
+    // Always set the layer color after setting the composition type.
+    writeSolidColorStateToHWC(hwcLayer.get(), outputIndependentState);
 }
 
 void OutputLayer::writeOutputDependentGeometryStateToHWC(
@@ -434,7 +438,7 @@
     // Content-specific per-frame state
     switch (outputIndependentState.compositionType) {
         case Hwc2::IComposerClient::Composition::SOLID_COLOR:
-            writeSolidColorStateToHWC(hwcLayer, outputIndependentState);
+            // For compatibility, should be written AFTER the composition type.
             break;
         case Hwc2::IComposerClient::Composition::SIDEBAND:
             writeSidebandStateToHWC(hwcLayer, outputIndependentState);
@@ -452,6 +456,10 @@
 
 void OutputLayer::writeSolidColorStateToHWC(HWC2::Layer* hwcLayer,
                                             const LayerFECompositionState& outputIndependentState) {
+    if (outputIndependentState.compositionType != Hwc2::IComposerClient::Composition::SOLID_COLOR) {
+        return;
+    }
+
     hwc_color_t color = {static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.r)),
                          static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.g)),
                          static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.b)),
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 0347f75..88acd04 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -33,6 +33,7 @@
 namespace {
 
 using testing::_;
+using testing::InSequence;
 using testing::Return;
 using testing::ReturnRef;
 using testing::StrictMock;
@@ -501,7 +502,7 @@
 
     setupGeometryChildCallValues();
 
-    mOutputLayer.updateCompositionState(true);
+    mOutputLayer.updateCompositionState(true, false);
 
     validateComputedGeometryState();
 
@@ -515,7 +516,7 @@
 
     setupGeometryChildCallValues();
 
-    mOutputLayer.updateCompositionState(true);
+    mOutputLayer.updateCompositionState(true, false);
 
     validateComputedGeometryState();
 
@@ -531,7 +532,7 @@
 
     setupGeometryChildCallValues();
 
-    mOutputLayer.updateCompositionState(true);
+    mOutputLayer.updateCompositionState(true, false);
 
     validateComputedGeometryState();
 
@@ -546,7 +547,7 @@
     // should use the layers requested colorspace.
     mLayerFEState.isColorspaceAgnostic = false;
 
-    mOutputLayer.updateCompositionState(false);
+    mOutputLayer.updateCompositionState(false, false);
 
     EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutputLayer.getState().dataspace);
 
@@ -554,7 +555,7 @@
     // should use the colorspace chosen for the whole output.
     mLayerFEState.isColorspaceAgnostic = true;
 
-    mOutputLayer.updateCompositionState(false);
+    mOutputLayer.updateCompositionState(false, false);
 
     EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace);
 }
@@ -562,7 +563,7 @@
 TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) {
     mOutputLayer.editState().forceClientComposition = false;
 
-    mOutputLayer.updateCompositionState(false);
+    mOutputLayer.updateCompositionState(false, false);
 
     EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition);
 }
@@ -571,7 +572,7 @@
        doesNotClearForceClientCompositionIfNotDoingGeometry) {
     mOutputLayer.editState().forceClientComposition = true;
 
-    mOutputLayer.updateCompositionState(false);
+    mOutputLayer.updateCompositionState(false, false);
 
     EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
 }
@@ -580,7 +581,7 @@
     mLayerFEState.forceClientComposition = true;
     mOutputLayer.editState().forceClientComposition = false;
 
-    mOutputLayer.updateCompositionState(false);
+    mOutputLayer.updateCompositionState(false, false);
 
     EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
 }
@@ -590,7 +591,24 @@
     mOutputLayer.editState().forceClientComposition = false;
     EXPECT_CALL(mDisplayColorProfile, isDataspaceSupported(_)).WillRepeatedly(Return(false));
 
-    mOutputLayer.updateCompositionState(false);
+    mOutputLayer.updateCompositionState(false, false);
+
+    EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+}
+
+TEST_F(OutputLayerUpdateCompositionStateTest, clientCompositionForcedFromArgumentFlag) {
+    mLayerFEState.forceClientComposition = false;
+    mOutputLayer.editState().forceClientComposition = false;
+
+    mOutputLayer.updateCompositionState(false, true);
+
+    EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+
+    mOutputLayer.editState().forceClientComposition = false;
+
+    setupGeometryChildCallValues();
+
+    mOutputLayer.updateCompositionState(true, true);
 
     EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
 }
@@ -752,8 +770,13 @@
     mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
 
     expectPerFrameCommonCalls();
-    expectSetColorCall();
+
+    // Setting the composition type should happen before setting the color. We
+    // check this in this test only by setting up an testing::InSeqeuence
+    // instance before setting up the two expectations.
+    InSequence s;
     expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SOLID_COLOR);
+    expectSetColorCall();
 
     mOutputLayer.writeStateToHWC(false);
 }
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index cb50d9f..ab664be 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -31,10 +31,11 @@
 }
 
 sp<Layer> ContainerLayer::createClone() {
-    String8 name = mName + " (Mirror)";
-    sp<ContainerLayer> layer = new ContainerLayer(
-            LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata()));
+    sp<ContainerLayer> layer = mFlinger->getFactory().createContainerLayer(
+            LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0,
+                              LayerMetadata()));
     layer->setInitialValuesForClone(this);
     return layer;
 }
+
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index e53d099..aef1c75 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -17,9 +17,11 @@
 #undef LOG_TAG
 #define LOG_TAG "HwcComposer"
 
-#include <inttypes.h>
 #include <log/log.h>
 
+#include <algorithm>
+#include <cinttypes>
+
 #include "ComposerHal.h"
 
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
@@ -93,6 +95,7 @@
 
 // assume NO_RESOURCES when Status::isOk returns false
 constexpr Error kDefaultError = Error::NO_RESOURCES;
+constexpr V2_4::Error kDefaultError_2_4 = V2_4::Error::NO_RESOURCES;
 
 template<typename T, typename U>
 T unwrapRet(Return<T>& ret, const U& default_val)
@@ -173,7 +176,16 @@
         LOG_ALWAYS_FATAL("failed to get hwcomposer service");
     }
 
-    if (sp<IComposer> composer_2_3 = IComposer::castFrom(mComposer)) {
+    if (sp<IComposer> composer_2_4 = IComposer::castFrom(mComposer)) {
+        composer_2_4->createClient_2_4([&](const auto& tmpError, const auto& tmpClient) {
+            if (tmpError == V2_4::Error::NONE) {
+                mClient = tmpClient;
+                mClient_2_2 = tmpClient;
+                mClient_2_3 = tmpClient;
+                mClient_2_4 = tmpClient;
+            }
+        });
+    } else if (sp<V2_3::IComposer> composer_2_3 = V2_3::IComposer::castFrom(mComposer)) {
         composer_2_3->createClient_2_3([&](const auto& tmpError, const auto& tmpClient) {
             if (tmpError == Error::NONE) {
                 mClient = tmpClient;
@@ -456,23 +468,6 @@
     return Error::NONE;
 }
 
-Error Composer::getDisplayType(Display display,
-        IComposerClient::DisplayType* outType)
-{
-    Error error = kDefaultError;
-    mClient->getDisplayType(display,
-            [&](const auto& tmpError, const auto& tmpType) {
-                error = tmpError;
-                if (error != Error::NONE) {
-                    return;
-                }
-
-                *outType = tmpType;
-            });
-
-    return error;
-}
-
 Error Composer::getDozeSupport(Display display, bool* outSupport)
 {
     Error error = kDefaultError;
@@ -1113,23 +1108,6 @@
     return error;
 }
 
-Error Composer::getDisplayCapabilities(Display display,
-                                       std::vector<DisplayCapability>* outCapabilities) {
-    if (!mClient_2_3) {
-        return Error::UNSUPPORTED;
-    }
-    Error error = kDefaultError;
-    mClient_2_3->getDisplayCapabilities(display,
-                                        [&](const auto& tmpError, const auto& tmpCapabilities) {
-                                            error = tmpError;
-                                            if (error != Error::NONE) {
-                                                return;
-                                            }
-                                            *outCapabilities = tmpCapabilities;
-                                        });
-    return error;
-}
-
 Error Composer::setDisplayContentSamplingEnabled(Display display, bool enabled,
                                                  uint8_t componentMask, uint64_t maxFrames) {
     if (!mClient_2_3) {
@@ -1187,6 +1165,60 @@
     return mClient_2_3->setDisplayBrightness(display, brightness);
 }
 
+// Composer HAL 2.4
+
+Error Composer::getDisplayCapabilities(Display display,
+                                       std::vector<DisplayCapability>* outCapabilities) {
+    if (!mClient_2_3) {
+        return Error::UNSUPPORTED;
+    }
+
+    V2_4::Error error = kDefaultError_2_4;
+    if (mClient_2_4) {
+        mClient_2_4->getDisplayCapabilities_2_4(display,
+                                                [&](const auto& tmpError, const auto& tmpCaps) {
+                                                    error = tmpError;
+                                                    if (error != V2_4::Error::NONE) {
+                                                        return;
+                                                    }
+                                                    *outCapabilities = tmpCaps;
+                                                });
+    } else {
+        mClient_2_3
+                ->getDisplayCapabilities(display, [&](const auto& tmpError, const auto& tmpCaps) {
+                    error = static_cast<V2_4::Error>(tmpError);
+                    if (error != V2_4::Error::NONE) {
+                        return;
+                    }
+
+                    outCapabilities->resize(tmpCaps.size());
+                    std::transform(tmpCaps.begin(), tmpCaps.end(), outCapabilities->begin(),
+                                   [](auto cap) { return static_cast<DisplayCapability>(cap); });
+                });
+    }
+
+    return static_cast<Error>(error);
+}
+
+Error Composer::getDisplayConnectionType(Display display,
+                                         IComposerClient::DisplayConnectionType* outType) {
+    if (!mClient_2_4) {
+        return Error::UNSUPPORTED;
+    }
+
+    V2_4::Error error = kDefaultError_2_4;
+    mClient_2_4->getDisplayConnectionType(display, [&](const auto& tmpError, const auto& tmpType) {
+        error = tmpError;
+        if (error != V2_4::Error::NONE) {
+            return;
+        }
+
+        *outType = tmpType;
+    });
+
+    return static_cast<V2_1::Error>(error);
+}
+
 CommandReader::~CommandReader()
 {
     resetData();
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 9f6cac2..e743e59 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -27,8 +27,8 @@
 #include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
 #endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
 #include <android/hardware/graphics/common/1.1/types.h>
-#include <android/hardware/graphics/composer/2.3/IComposer.h>
-#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
 #include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
@@ -49,6 +49,7 @@
 namespace V2_1 = hardware::graphics::composer::V2_1;
 namespace V2_2 = hardware::graphics::composer::V2_2;
 namespace V2_3 = hardware::graphics::composer::V2_3;
+namespace V2_4 = hardware::graphics::composer::V2_4;
 
 using types::V1_0::ColorTransform;
 using types::V1_0::Transform;
@@ -65,8 +66,8 @@
 using V2_1::Layer;
 using V2_3::CommandReaderBase;
 using V2_3::CommandWriterBase;
-using V2_3::IComposer;
-using V2_3::IComposerClient;
+using V2_4::IComposer;
+using V2_4::IComposerClient;
 using DisplayCapability = IComposerClient::DisplayCapability;
 using PerFrameMetadata = IComposerClient::PerFrameMetadata;
 using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey;
@@ -118,7 +119,6 @@
                                      std::vector<Layer>* outLayers,
                                      std::vector<uint32_t>* outLayerRequestMasks) = 0;
 
-    virtual Error getDisplayType(Display display, IComposerClient::DisplayType* outType) = 0;
     virtual Error getDozeSupport(Display display, bool* outSupport) = 0;
     virtual Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes,
                                      float* outMaxLuminance, float* outMaxAverageLuminance,
@@ -203,11 +203,15 @@
                                                    uint8_t componentMask, uint64_t maxFrames) = 0;
     virtual Error getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp,
                                             DisplayedFrameStats* outStats) = 0;
-    virtual Error getDisplayCapabilities(Display display,
-                                         std::vector<DisplayCapability>* outCapabilities) = 0;
     virtual Error setLayerPerFrameMetadataBlobs(
             Display display, Layer layer, const std::vector<PerFrameMetadataBlob>& metadata) = 0;
     virtual Error setDisplayBrightness(Display display, float brightness) = 0;
+
+    // Composer HAL 2.4
+    virtual Error getDisplayCapabilities(Display display,
+                                         std::vector<DisplayCapability>* outCapabilities) = 0;
+    virtual Error getDisplayConnectionType(Display display,
+                                           IComposerClient::DisplayConnectionType* outType) = 0;
 };
 
 namespace impl {
@@ -334,7 +338,6 @@
                              std::vector<Layer>* outLayers,
                              std::vector<uint32_t>* outLayerRequestMasks) override;
 
-    Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override;
     Error getDozeSupport(Display display, bool* outSupport) override;
     Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes, float* outMaxLuminance,
                              float* outMaxAverageLuminance, float* outMinLuminance) override;
@@ -414,13 +417,17 @@
                                            uint64_t maxFrames) override;
     Error getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp,
                                     DisplayedFrameStats* outStats) override;
-    Error getDisplayCapabilities(Display display,
-                                 std::vector<DisplayCapability>* outCapabilities) override;
     Error setLayerPerFrameMetadataBlobs(
             Display display, Layer layer,
             const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
     Error setDisplayBrightness(Display display, float brightness) override;
 
+    // Composer HAL 2.4
+    Error getDisplayCapabilities(Display display,
+                                 std::vector<DisplayCapability>* outCapabilities) override;
+    Error getDisplayConnectionType(Display display,
+                                   IComposerClient::DisplayConnectionType* outType) override;
+
 private:
 #if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
     class CommandWriter : public CommandWriterBase {
@@ -455,7 +462,8 @@
 
     sp<V2_1::IComposerClient> mClient;
     sp<V2_2::IComposerClient> mClient_2_2;
-    sp<IComposerClient> mClient_2_3;
+    sp<V2_3::IComposerClient> mClient_2_3;
+    sp<IComposerClient> mClient_2_4;
 
     // 64KiB minus a small space for metadata such as read/write pointers
     static constexpr size_t kWriterInitialSize =
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index c463c4e..6f7428a 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -169,20 +169,8 @@
         }
         mDisplays.erase(displayId);
 
-        DisplayType displayType;
-        auto intError = mComposer->getDisplayType(displayId,
-                reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(
-                        &displayType));
-        auto error = static_cast<Error>(intError);
-        if (error != Error::None) {
-            ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d). "
-                    "Aborting hotplug attempt.",
-                    displayId, to_string(error).c_str(), intError);
-            return;
-        }
-
         auto newDisplay = std::make_unique<impl::Display>(*mComposer.get(), mCapabilities,
-                                                          displayId, displayType);
+                                                          displayId, DisplayType::Physical);
         newDisplay->setConnected(true);
         mDisplays.emplace(displayId, std::move(newDisplay));
     } else if (connection == Connection::Disconnected) {
diff --git a/services/surfaceflinger/EventLog/EventLog.cpp b/services/surfaceflinger/EventLog/EventLog.cpp
index 365a0bd..a532fc1 100644
--- a/services/surfaceflinger/EventLog/EventLog.cpp
+++ b/services/surfaceflinger/EventLog/EventLog.cpp
@@ -17,13 +17,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <log/log.h>
-#include <utils/String8.h>
 
 #include "EventLog.h"
 
-// ---------------------------------------------------------------------------
 namespace android {
-// ---------------------------------------------------------------------------
 
 ANDROID_SINGLETON_STATIC_INSTANCE(EventLog)
 
@@ -31,11 +28,11 @@
 EventLog::EventLog() {
 }
 
-void EventLog::doLogFrameDurations(const String8& window,
-        const int32_t* durations, size_t numDurations) {
+void EventLog::doLogFrameDurations(const std::string_view& name, const int32_t* durations,
+                                   size_t numDurations) {
     EventLog::TagBuffer buffer(LOGTAG_SF_FRAME_DUR);
     buffer.startList(1 + numDurations);
-    buffer.writeString8(window);
+    buffer.writeString(name);
     for (size_t i = 0; i < numDurations; i++) {
         buffer.writeInt32(durations[i]);
     }
@@ -43,10 +40,9 @@
     buffer.log();
 }
 
-void EventLog::logFrameDurations(const String8& window,
-        const int32_t* durations, size_t numDurations) {
-    EventLog::getInstance().doLogFrameDurations(window, durations,
-            numDurations);
+void EventLog::logFrameDurations(const std::string_view& name, const int32_t* durations,
+                                 size_t numDurations) {
+    EventLog::getInstance().doLogFrameDurations(name, durations, numDurations);
 }
 
 // ---------------------------------------------------------------------------
@@ -113,9 +109,9 @@
     mPos += needed;
 }
 
-void EventLog::TagBuffer::writeString8(const String8& value) {
+void EventLog::TagBuffer::writeString(const std::string_view& value) {
     if (mOverflow) return;
-    const int32_t stringLen = value.length();
+    const size_t stringLen = value.length();
     const size_t needed = 1 + sizeof(int32_t) + stringLen;
     if (mPos + needed > STORAGE_MAX_SIZE) {
         mOverflow = true;
@@ -123,11 +119,8 @@
     }
     mStorage[mPos + 0] = EVENT_TYPE_STRING;
     memcpy(&mStorage[mPos + 1], &stringLen, sizeof(int32_t));
-    memcpy(&mStorage[mPos + 5], value.string(), stringLen);
+    memcpy(&mStorage[mPos + 5], value.data(), stringLen);
     mPos += needed;
 }
 
-// ---------------------------------------------------------------------------
-}// namespace android
-
-// ---------------------------------------------------------------------------
+} // namespace android
diff --git a/services/surfaceflinger/EventLog/EventLog.h b/services/surfaceflinger/EventLog/EventLog.h
index efc5d70..ee3587e 100644
--- a/services/surfaceflinger/EventLog/EventLog.h
+++ b/services/surfaceflinger/EventLog/EventLog.h
@@ -14,24 +14,21 @@
  * limitations under the License.
  */
 
-#include <stdint.h>
+#pragma once
+
 #include <utils/Errors.h>
 #include <utils/Singleton.h>
 
-#ifndef ANDROID_SF_EVENTLOG_H
-#define ANDROID_SF_EVENTLOG_H
+#include <cstdint>
+#include <string_view>
 
-// ---------------------------------------------------------------------------
 namespace android {
-// ---------------------------------------------------------------------------
-
-class String8;
 
 class EventLog : public Singleton<EventLog> {
 
 public:
-    static void logFrameDurations(const String8& window,
-            const int32_t* durations, size_t numDurations);
+    static void logFrameDurations(const std::string_view& name, const int32_t* durations,
+                                  size_t numDurations);
 
 protected:
     EventLog();
@@ -54,18 +51,13 @@
     public:
         explicit TagBuffer(int32_t tag);
 
-        // starts list of items
         void startList(int8_t count);
-        // terminates the list
         void endList();
-        // write a 32-bit integer
-        void writeInt32(int32_t value);
-        // write a 64-bit integer
-        void writeInt64(int64_t value);
-        // write a C string
-        void writeString8(const String8& value);
 
-        // outputs the the buffer to the log
+        void writeInt32(int32_t);
+        void writeInt64(int64_t);
+        void writeString(const std::string_view&);
+
         void log();
     };
 
@@ -74,12 +66,8 @@
     EventLog& operator =(const EventLog&);
 
     enum { LOGTAG_SF_FRAME_DUR = 60100 };
-    void doLogFrameDurations(const String8& window, const int32_t* durations,
-            size_t numDurations);
+    void doLogFrameDurations(const std::string_view& name, const int32_t* durations,
+                             size_t numDurations);
 };
 
-// ---------------------------------------------------------------------------
-}// namespace android
-// ---------------------------------------------------------------------------
-
-#endif /* ANDROID_SF_EVENTLOG_H */
+} // namespace android
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.cpp b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
index 006dbfe..3a0408e 100644
--- a/services/surfaceflinger/FrameTracer/FrameTracer.cpp
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
@@ -133,7 +133,9 @@
     packet->set_timestamp(timestamp);
     auto* event = packet->set_graphics_frame_event()->set_buffer_event();
     event->set_buffer_id(static_cast<uint32_t>(bufferID));
-    event->set_frame_number(frameNumber);
+    if (frameNumber != UNSPECIFIED_FRAME_NUMBER) {
+        event->set_frame_number(frameNumber);
+    }
     event->set_type(type);
 
     if (mTraceTracker.find(layerID) != mTraceTracker.end() &&
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.h b/services/surfaceflinger/FrameTracer/FrameTracer.h
index d4dfab9..e91a750 100644
--- a/services/surfaceflinger/FrameTracer/FrameTracer.h
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.h
@@ -33,6 +33,8 @@
         virtual void OnStop(const StopArgs&) override{};
     };
 
+    static const uint64_t UNSPECIFIED_FRAME_NUMBER = std::numeric_limits<uint64_t>::max();
+
     using FrameEvent = perfetto::protos::pbzero::GraphicsFrameEvent;
 
     ~FrameTracer() = default;
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index f4cc49b..a6e511e 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -21,7 +21,6 @@
 
 #include <android-base/stringprintf.h>
 #include <android/log.h>
-#include <utils/String8.h>
 
 #include <ui/FrameStats.h>
 
@@ -139,7 +138,7 @@
     }
 }
 
-void FrameTracker::logAndResetStats(const String8& name) {
+void FrameTracker::logAndResetStats(const std::string_view& name) {
     Mutex::Autolock lock(mMutex);
     logStatsLocked(name);
     resetFrameCountersLocked();
@@ -217,7 +216,7 @@
     }
 }
 
-void FrameTracker::logStatsLocked(const String8& name) const {
+void FrameTracker::logStatsLocked(const std::string_view& name) const {
     for (int i = 0; i < NUM_FRAME_BUCKETS; i++) {
         if (mNumFrames[i] > 0) {
             EventLog::logFrameDurations(name, mNumFrames, NUM_FRAME_BUCKETS);
diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h
index 555dcc1..35382be 100644
--- a/services/surfaceflinger/FrameTracker.h
+++ b/services/surfaceflinger/FrameTracker.h
@@ -14,21 +14,18 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_FRAMETRACKER_H
-#define ANDROID_FRAMETRACKER_H
+#pragma once
 
 #include <ui/FenceTime.h>
-
-#include <stddef.h>
-
 #include <utils/Mutex.h>
-#include <utils/Timers.h>
 #include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+#include <cstddef>
+#include <string_view>
 
 namespace android {
 
-class String8;
-
 // FrameTracker tracks information about the most recently rendered frames. It
 // uses a circular buffer of frame records, and is *NOT* thread-safe -
 // mutexing must be done at a higher level if multi-threaded access is
@@ -87,7 +84,7 @@
 
     // logAndResetStats dumps the current statistics to the binary event log
     // and then resets the accumulated statistics to their initial values.
-    void logAndResetStats(const String8& name);
+    void logAndResetStats(const std::string_view& name);
 
     // dumpStats dump appends the current frame display time history to the result string.
     void dumpStats(std::string& result) const;
@@ -123,7 +120,7 @@
     void resetFrameCountersLocked();
 
     // logStatsLocked dumps the current statistics to the binary event log.
-    void logStatsLocked(const String8& name) const;
+    void logStatsLocked(const std::string_view& name) const;
 
     // isFrameValidLocked returns true if the data for the given frame index is
     // valid and has all arrived (i.e. there are no oustanding fences).
@@ -160,6 +157,4 @@
     mutable Mutex mMutex;
 };
 
-}
-
-#endif // ANDROID_FRAMETRACKER_H
+} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6a45625..e19b79b 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -83,8 +83,6 @@
     if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
     if (args.flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure;
 
-    mTransactionName = String8("TX - ") + mName;
-
     mCurrentState.active_legacy.w = args.w;
     mCurrentState.active_legacy.h = args.h;
     mCurrentState.flags = layerFlags;
@@ -120,10 +118,9 @@
     mFrameEventHistory.initializeCompositorTiming(compositorTiming);
     mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval);
 
-    mSchedulerLayerHandle = mFlinger->mScheduler->registerLayer(mName.c_str(), mWindowType);
     mCallingPid = args.callingPid;
     mCallingUid = args.callingUid;
-    mFlinger->onLayerCreated();
+    mFlinger->onLayerCreated(this);
 }
 
 Layer::~Layer() {
@@ -137,11 +134,11 @@
 }
 
 LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client,
-                                     const String8& name, uint32_t w, uint32_t h, uint32_t flags,
+                                     std::string name, uint32_t w, uint32_t h, uint32_t flags,
                                      LayerMetadata metadata)
       : flinger(flinger),
         client(client),
-        name(name),
+        name(std::move(name)),
         w(w),
         h(h),
         flags(flags),
@@ -235,10 +232,6 @@
 // set-up
 // ---------------------------------------------------------------------------
 
-const String8& Layer::getName() const {
-    return mName;
-}
-
 bool Layer::getPremultipledAlpha() const {
     return mPremultipliedAlpha;
 }
@@ -523,7 +516,7 @@
 }
 
 const char* Layer::getDebugName() const {
-    return mName.string();
+    return mName.c_str();
 }
 
 // ---------------------------------------------------------------------------
@@ -614,7 +607,7 @@
     if (mCurrentState.barrierLayer_legacy != nullptr && !isRemovedFromCurrentState()) {
         sp<Layer> barrierLayer = mCurrentState.barrierLayer_legacy.promote();
         if (barrierLayer == nullptr) {
-            ALOGE("[%s] Unable to promote barrier Layer.", mName.string());
+            ALOGE("[%s] Unable to promote barrier Layer.", getDebugName());
             // If we can't promote the layer we are intended to wait on,
             // then it is expired or otherwise invalid. Allow this transaction
             // to be applied as per normal (no synchronization).
@@ -638,7 +631,7 @@
         mFlinger->setTransactionFlags(eTraversalNeeded);
     }
     mPendingStates.push_back(mCurrentState);
-    ATRACE_INT(mTransactionName.string(), mPendingStates.size());
+    ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
 }
 
 void Layer::popPendingState(State* stateToCommit) {
@@ -646,7 +639,7 @@
     *stateToCommit = mPendingStates[0];
 
     mPendingStates.removeAt(0);
-    ATRACE_INT(mTransactionName.string(), mPendingStates.size());
+    ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
 }
 
 bool Layer::applyPendingStates(State* stateToCommit) {
@@ -657,7 +650,7 @@
                 // If we don't have a sync point for this, apply it anyway. It
                 // will be visually wrong, but it should keep us from getting
                 // into too much trouble.
-                ALOGE("[%s] No local sync point found", mName.string());
+                ALOGE("[%s] No local sync point found", getDebugName());
                 popPendingState(stateToCommit);
                 stateUpdateAvailable = true;
                 continue;
@@ -665,7 +658,7 @@
 
             if (mRemoteSyncPoints.front()->getFrameNumber() !=
                 mPendingStates[0].frameNumber_legacy) {
-                ALOGE("[%s] Unexpected sync point frame number found", mName.string());
+                ALOGE("[%s] Unexpected sync point frame number found", getDebugName());
 
                 // Signal our end of the sync point and then dispose of it
                 mRemoteSyncPoints.front()->setTransactionApplied();
@@ -717,7 +710,7 @@
                  "            requested={ wh={%4u,%4u} }}\n"
                  "  drawing={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
                  "            requested={ wh={%4u,%4u} }}\n",
-                 this, getName().string(), getBufferTransform(), getEffectiveScalingMode(),
+                 this, getName().c_str(), getBufferTransform(), getEffectiveScalingMode(),
                  stateToCommit->active_legacy.w, stateToCommit->active_legacy.h,
                  stateToCommit->crop_legacy.left, stateToCommit->crop_legacy.top,
                  stateToCommit->crop_legacy.right, stateToCommit->crop_legacy.bottom,
@@ -908,7 +901,6 @@
         }
         setZOrderRelativeOf(nullptr);
     }
-    mCurrentState.isRelativeOf = false;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -931,6 +923,8 @@
     mCurrentState.zOrderRelativeOf = relativeOf;
     mCurrentState.sequence++;
     mCurrentState.modified = true;
+    mCurrentState.isRelativeOf = relativeOf != nullptr;
+
     setTransactionFlags(eTransactionNeeded);
 }
 
@@ -952,7 +946,6 @@
     mCurrentState.sequence++;
     mCurrentState.modified = true;
     mCurrentState.z = relativeZ;
-    mCurrentState.isRelativeOf = true;
 
     auto oldZOrderRelativeOf = mCurrentState.zOrderRelativeOf.promote();
     if (oldZOrderRelativeOf != nullptr) {
@@ -999,9 +992,10 @@
     if (!mCurrentState.bgColorLayer && alpha != 0) {
         // create background color layer if one does not yet exist
         uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor;
-        const String8& name = mName + "BackgroundColorLayer";
+        std::string name = mName + "BackgroundColorLayer";
         mCurrentState.bgColorLayer = mFlinger->getFactory().createColorLayer(
-                LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, flags, LayerMetadata()));
+                LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), 0, 0, flags,
+                                  LayerMetadata()));
 
         // add to child list
         addChild(mCurrentState.bgColorLayer);
@@ -1196,11 +1190,13 @@
 
 // TODO(marissaw): add new layer state info to layer debugging
 LayerDebugInfo Layer::getLayerDebugInfo() const {
+    using namespace std::string_literals;
+
     LayerDebugInfo info;
     const State& ds = getDrawingState();
     info.mName = getName();
     sp<Layer> parent = getParent();
-    info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string());
+    info.mParentName = parent ? parent->getName() : "none"s;
     info.mType = getType();
     info.mTransparentRegion = ds.activeTransparentRegion_legacy;
 
@@ -1267,12 +1263,12 @@
     std::string name;
     if (mName.length() > 77) {
         std::string shortened;
-        shortened.append(mName.string(), 36);
+        shortened.append(mName, 0, 36);
         shortened.append("[...]");
-        shortened.append(mName.string() + (mName.length() - 36), 36);
-        name = shortened;
+        shortened.append(mName, mName.length() - 36);
+        name = std::move(shortened);
     } else {
-        name = std::string(mName.string(), mName.size());
+        name = mName;
     }
 
     StringAppendF(&result, " %s\n", name.c_str());
@@ -1319,14 +1315,14 @@
 }
 
 void Layer::dumpFrameEvents(std::string& result) {
-    StringAppendF(&result, "- Layer %s (%s, %p)\n", getName().string(), getType(), this);
+    StringAppendF(&result, "- Layer %s (%s, %p)\n", getName().c_str(), getType(), this);
     Mutex::Autolock lock(mFrameEventHistoryMutex);
     mFrameEventHistory.checkFencesForCompletion();
     mFrameEventHistory.dump(result);
 }
 
 void Layer::dumpCallingUidPid(std::string& result) const {
-    StringAppendF(&result, "Layer %s (%s) pid:%d uid:%d\n", getName().string(), getType(),
+    StringAppendF(&result, "Layer %s (%s) pid:%d uid:%d\n", getName().c_str(), getType(),
                   mCallingPid, mCallingUid);
 }
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3023cf5..fdac98f 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -34,7 +34,6 @@
 #include <ui/Region.h>
 #include <ui/Transform.h>
 #include <utils/RefBase.h>
-#include <utils/String8.h>
 #include <utils/Timers.h>
 
 #include <cstdint>
@@ -79,12 +78,12 @@
 // ---------------------------------------------------------------------------
 
 struct LayerCreationArgs {
-    LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+    LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client, std::string name,
                       uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata);
 
     SurfaceFlinger* flinger;
     const sp<Client>& client;
-    const String8& name;
+    std::string name;
     uint32_t w;
     uint32_t h;
     uint32_t flags;
@@ -222,6 +221,8 @@
     explicit Layer(const LayerCreationArgs& args);
     virtual ~Layer();
 
+    int getWindowType() const { return mWindowType; }
+
     void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; }
     bool getPrimaryDisplayOnly() const { return mPrimaryDisplayOnly; }
 
@@ -804,7 +805,7 @@
     // Creates a new handle each time, so we only expect
     // this to be called once.
     sp<IBinder> getHandle();
-    const String8& getName() const;
+    const std::string& getName() const { return mName; }
     virtual void notifyAvailableFrames(nsecs_t /*expectedPresentTime*/) {}
     virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
     bool getPremultipledAlpha() const;
@@ -820,8 +821,8 @@
     bool usingRelativeZ(LayerVector::StateSet stateSet) const;
 
     bool mPremultipliedAlpha{true};
-    String8 mName;
-    String8 mTransactionName; // A cached version of "TX - " + mName for systraces
+    const std::string mName;
+    const std::string mTransactionName{"TX - " + mName};
 
     bool mPrimaryDisplayOnly = false;
 
@@ -887,9 +888,6 @@
     // Window types from WindowManager.LayoutParams
     const int mWindowType;
 
-    // This is populated if the layer is registered with Scheduler for tracking purposes.
-    std::unique_ptr<scheduler::LayerHistory::LayerHandle> mSchedulerLayerHandle;
-
 private:
     /**
      * Returns an unsorted vector of all layers that are part of this tree.
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 8a22183..1a60f1e 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -24,7 +24,7 @@
 namespace android {
 
 LayerRejecter::LayerRejecter(Layer::State& front, Layer::State& current,
-                             bool& recomputeVisibleRegions, bool stickySet, const char* name,
+                             bool& recomputeVisibleRegions, bool stickySet, const std::string& name,
                              int32_t overrideScalingMode, bool transformToDisplayInverse)
       : mFront(front),
         mCurrent(current),
@@ -90,7 +90,7 @@
                  "(%4d,%4d) "
                  "}\n"
                  "            requested_legacy={ wh={%4u,%4u} }}\n",
-                 mName, bufWidth, bufHeight, item.mTransform, item.mScalingMode,
+                 mName.c_str(), bufWidth, bufHeight, item.mTransform, item.mScalingMode,
                  mFront.active_legacy.w, mFront.active_legacy.h, mFront.crop_legacy.left,
                  mFront.crop_legacy.top, mFront.crop_legacy.right, mFront.crop_legacy.bottom,
                  mFront.crop_legacy.getWidth(), mFront.crop_legacy.getHeight(),
@@ -102,7 +102,8 @@
             // reject this buffer
             ALOGE("[%s] rejecting buffer: "
                   "bufWidth=%d, bufHeight=%d, front.active_legacy.{w=%d, h=%d}",
-                  mName, bufWidth, bufHeight, mFront.active_legacy.w, mFront.active_legacy.h);
+                  mName.c_str(), bufWidth, bufHeight, mFront.active_legacy.w,
+                  mFront.active_legacy.h);
             return true;
         }
     }
diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h
index 1bd0c26..fb5c750 100644
--- a/services/surfaceflinger/LayerRejecter.h
+++ b/services/surfaceflinger/LayerRejecter.h
@@ -14,30 +14,29 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_LAYER_REJECTER_H
-#define ANDROID_LAYER_REJECTER_H
+#pragma once
 
 #include "Layer.h"
 #include "BufferLayerConsumer.h"
 
 namespace android {
-    class LayerRejecter : public BufferLayerConsumer::BufferRejecter {
-    public:
-        LayerRejecter(Layer::State &front, Layer::State &current, bool &recomputeVisibleRegions,
-                      bool stickySet, const char *name, int32_t overrideScalingMode,
-                      bool transformToDisplayInverse);
 
-        virtual bool reject(const sp<GraphicBuffer> &buf, const BufferItem &item);
+class LayerRejecter : public BufferLayerConsumer::BufferRejecter {
+public:
+    LayerRejecter(Layer::State& front, Layer::State& current, bool& recomputeVisibleRegions,
+                  bool stickySet, const std::string& name, int32_t overrideScalingMode,
+                  bool transformToDisplayInverse);
 
-    private:
-        Layer::State &mFront;
-        Layer::State &mCurrent;
-        bool &mRecomputeVisibleRegions;
-        bool mStickyTransformSet;
-        const char *mName;
-        int32_t mOverrideScalingMode;
-        bool mTransformToDisplayInverse;
-    };
-}  // namespace android
+    virtual bool reject(const sp<GraphicBuffer>&, const BufferItem&);
 
-#endif  // ANDROID_LAYER_REJECTER_H
+private:
+    Layer::State& mFront;
+    Layer::State& mCurrent;
+    bool& mRecomputeVisibleRegions;
+    const bool mStickyTransformSet;
+    const std::string& mName;
+    const int32_t mOverrideScalingMode;
+    const bool mTransformToDisplayInverse;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 1c1367c..a484373 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -268,16 +268,6 @@
     mDescriptors.erase(who);
 }
 
-namespace {
-// Using Rec. 709 primaries
-inline float getLuma(float r, float g, float b) {
-    constexpr auto rec709_red_primary = 0.2126f;
-    constexpr auto rec709_green_primary = 0.7152f;
-    constexpr auto rec709_blue_primary = 0.0722f;
-    return rec709_red_primary * r + rec709_green_primary * g + rec709_blue_primary * b;
-}
-} // anonymous namespace
-
 float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t stride,
                  uint32_t orientation, const Rect& sample_area) {
     if (!sample_area.isValid() || (sample_area.getWidth() > width) ||
@@ -298,30 +288,23 @@
         std::swap(area.left, area.right);
     }
 
-    std::array<int32_t, 256> brightnessBuckets = {};
-    const int32_t majoritySampleNum = area.getWidth() * area.getHeight() / 2;
+    const uint32_t pixelCount = (area.bottom - area.top) * (area.right - area.left);
+    uint32_t accumulatedLuma = 0;
 
+    // Calculates luma with approximation of Rec. 709 primaries
     for (int32_t row = area.top; row < area.bottom; ++row) {
         const uint32_t* rowBase = data + row * stride;
         for (int32_t column = area.left; column < area.right; ++column) {
             uint32_t pixel = rowBase[column];
-            const float r = pixel & 0xFF;
-            const float g = (pixel >> 8) & 0xFF;
-            const float b = (pixel >> 16) & 0xFF;
-            const uint8_t luma = std::round(getLuma(r, g, b));
-            ++brightnessBuckets[luma];
-            if (brightnessBuckets[luma] > majoritySampleNum) return luma / 255.0f;
+            const uint32_t r = pixel & 0xFF;
+            const uint32_t g = (pixel >> 8) & 0xFF;
+            const uint32_t b = (pixel >> 16) & 0xFF;
+            const uint32_t luma = (r * 7 + b * 2 + g * 23) >> 5;
+            accumulatedLuma += luma;
         }
     }
 
-    int32_t accumulated = 0;
-    size_t bucket = 0;
-    for (; bucket < brightnessBuckets.size(); bucket++) {
-        accumulated += brightnessBuckets[bucket];
-        if (accumulated > majoritySampleNum) break;
-    }
-
-    return bucket / 255.0f;
+    return accumulatedLuma / (255.0f * pixelCount);
 }
 
 std::vector<float> RegionSamplingThread::sampleBuffer(
@@ -436,7 +419,7 @@
             }
             if (!intersectsAnyArea) return;
 
-            ALOGV("Traversing [%s] [%d, %d, %d, %d]", layer->getName().string(), bounds.left,
+            ALOGV("Traversing [%s] [%d, %d, %d, %d]", layer->getDebugName(), bounds.left,
                   bounds.top, bounds.right, bounds.bottom);
             visitor(layer);
         };
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index f80c233..8b71728 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -14,179 +14,150 @@
  * limitations under the License.
  */
 
+#undef LOG_TAG
+#define LOG_TAG "LayerHistory"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include "LayerHistory.h"
 
-#include <cinttypes>
-#include <cstdint>
-#include <limits>
-#include <numeric>
-#include <string>
-#include <unordered_map>
-
 #include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/Timers.h>
 #include <utils/Trace.h>
 
+#include <algorithm>
+#include <cmath>
+#include <string>
+#include <utility>
+
+#include "../Layer.h"
+#include "LayerInfo.h"
 #include "SchedulerUtils.h"
 
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
 
-std::atomic<int64_t> LayerHistory::sNextId = 0;
+namespace {
 
-LayerHistory::LayerHistory() {
+bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) {
+    return layer.isVisible() && (info.isHDR() || info.getLastUpdatedTime() >= threshold);
+}
+
+bool traceEnabled() {
     char value[PROPERTY_VALUE_MAX];
     property_get("debug.sf.layer_history_trace", value, "0");
-    mTraceEnabled = bool(atoi(value));
+    return atoi(value);
 }
 
+void trace(const wp<Layer>& weak, int fps) {
+    const auto layer = weak.promote();
+    if (!layer) return;
+
+    const auto& name = layer->getName();
+    const auto tag = "LFPS " + name;
+    ATRACE_INT(tag.c_str(), fps);
+    ALOGD("%s: %s @ %d Hz", __FUNCTION__, name.c_str(), fps);
+}
+
+} // namespace
+
+LayerHistory::LayerHistory() : mTraceEnabled(traceEnabled()) {}
 LayerHistory::~LayerHistory() = default;
 
-std::unique_ptr<LayerHistory::LayerHandle> LayerHistory::createLayer(const std::string name,
-                                                                     float minRefreshRate,
-                                                                     float maxRefreshRate) {
-    const int64_t id = sNextId++;
-
+void LayerHistory::registerLayer(Layer* layer, float lowRefreshRate, float highRefreshRate) {
+    auto info = std::make_unique<LayerInfo>(lowRefreshRate, highRefreshRate);
     std::lock_guard lock(mLock);
-    mInactiveLayerInfos.emplace(id,
-                                std::make_shared<LayerInfo>(name, minRefreshRate, maxRefreshRate));
-    return std::make_unique<LayerHistory::LayerHandle>(*this, id);
+    mLayerInfos.emplace_back(layer, std::move(info));
 }
 
-void LayerHistory::destroyLayer(const int64_t id) {
+void LayerHistory::record(Layer* layer, nsecs_t presentTime, bool isHDR, nsecs_t now) {
     std::lock_guard lock(mLock);
-    auto it = mActiveLayerInfos.find(id);
-    if (it != mActiveLayerInfos.end()) {
-        mActiveLayerInfos.erase(it);
-    }
 
-    it = mInactiveLayerInfos.find(id);
-    if (it != mInactiveLayerInfos.end()) {
-        mInactiveLayerInfos.erase(it);
+    const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
+                                 [layer](const auto& pair) { return pair.first == layer; });
+    LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
+
+    const auto& info = it->second;
+    info->setLastPresentTime(presentTime, now);
+    info->setIsHDR(isHDR);
+
+    // Activate layer if inactive.
+    if (const auto end = activeLayers().end(); it >= end) {
+        std::iter_swap(it, end);
+        mActiveLayersEnd++;
     }
 }
 
-void LayerHistory::insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime,
-                          bool isHdr) {
-    std::shared_ptr<LayerInfo> layerInfo;
-    {
-        std::lock_guard lock(mLock);
-        auto layerInfoIterator = mInactiveLayerInfos.find(layerHandle->mId);
-        if (layerInfoIterator != mInactiveLayerInfos.end()) {
-            layerInfo = layerInfoIterator->second;
-            mInactiveLayerInfos.erase(layerInfoIterator);
-            mActiveLayerInfos.insert({layerHandle->mId, layerInfo});
-        } else {
-            layerInfoIterator = mActiveLayerInfos.find(layerHandle->mId);
-            if (layerInfoIterator != mActiveLayerInfos.end()) {
-                layerInfo = layerInfoIterator->second;
-            } else {
-                ALOGW("Inserting information about layer that is not registered: %" PRId64,
-                      layerHandle->mId);
-                return;
-            }
-        }
-    }
-    layerInfo->setLastPresentTime(presentTime);
-    layerInfo->setHDRContent(isHdr);
-}
-
-void LayerHistory::setVisibility(const std::unique_ptr<LayerHandle>& layerHandle, bool visible) {
-    std::shared_ptr<LayerInfo> layerInfo;
-    {
-        std::lock_guard lock(mLock);
-        auto layerInfoIterator = mInactiveLayerInfos.find(layerHandle->mId);
-        if (layerInfoIterator != mInactiveLayerInfos.end()) {
-            layerInfo = layerInfoIterator->second;
-            if (visible) {
-                mInactiveLayerInfos.erase(layerInfoIterator);
-                mActiveLayerInfos.insert({layerHandle->mId, layerInfo});
-            }
-        } else {
-            layerInfoIterator = mActiveLayerInfos.find(layerHandle->mId);
-            if (layerInfoIterator != mActiveLayerInfos.end()) {
-                layerInfo = layerInfoIterator->second;
-            } else {
-                ALOGW("Inserting information about layer that is not registered: %" PRId64,
-                      layerHandle->mId);
-                return;
-            }
-        }
-    }
-    layerInfo->setVisibility(visible);
-}
-
-std::pair<float, bool> LayerHistory::getDesiredRefreshRateAndHDR() {
+LayerHistory::Summary LayerHistory::summarize(nsecs_t now) {
+    float maxRefreshRate = 0;
     bool isHDR = false;
-    float newRefreshRate = 0.f;
+
     std::lock_guard lock(mLock);
 
-    removeIrrelevantLayers();
+    partitionLayers(now);
 
-    // Iterate through all layers that have been recently updated, and find the max refresh rate.
-    for (const auto& [layerId, layerInfo] : mActiveLayerInfos) {
-        const float layerRefreshRate = layerInfo->getDesiredRefreshRate();
-        if (mTraceEnabled) {
-            // Store the refresh rate in traces for easy debugging.
-            std::string layerName = "LFPS " + layerInfo->getName();
-            ATRACE_INT(layerName.c_str(), std::round(layerRefreshRate));
-            ALOGD("%s: %f", layerName.c_str(), std::round(layerRefreshRate));
-        }
-        if (layerInfo->isRecentlyActive() && layerRefreshRate > newRefreshRate) {
-            newRefreshRate = layerRefreshRate;
-        }
-        isHDR |= layerInfo->getHDRContent();
-    }
-    if (mTraceEnabled) {
-        ALOGD("LayerHistory DesiredRefreshRate: %.2f", newRefreshRate);
-    }
-
-    return {newRefreshRate, isHDR};
-}
-
-void LayerHistory::removeIrrelevantLayers() {
-    const int64_t obsoleteEpsilon = systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count();
-    // Iterator pointing to first element in map
-    auto it = mActiveLayerInfos.begin();
-    while (it != mActiveLayerInfos.end()) {
-        // If last updated was before the obsolete time, remove it.
-        // Keep HDR layer around as long as they are visible.
-        if (!it->second->isVisible() ||
-            (!it->second->getHDRContent() && it->second->getLastUpdatedTime() < obsoleteEpsilon)) {
-            // erase() function returns the iterator of the next
-            // to last deleted element.
-            if (mTraceEnabled) {
-                ALOGD("Layer %s obsolete", it->second->getName().c_str());
-                // Make sure to update systrace to indicate that the layer was erased.
-                std::string layerName = "LFPS " + it->second->getName();
-                ATRACE_INT(layerName.c_str(), 0);
+    // Find the maximum refresh rate among recently active layers.
+    for (const auto& [layer, info] : activeLayers()) {
+        const bool recent = info->isRecentlyActive(now);
+        if (recent || CC_UNLIKELY(mTraceEnabled)) {
+            const float refreshRate = info->getRefreshRate(now);
+            if (recent && refreshRate > maxRefreshRate) {
+                maxRefreshRate = refreshRate;
             }
-            auto id = it->first;
-            auto layerInfo = it->second;
-            layerInfo->clearHistory();
-            mInactiveLayerInfos.insert({id, layerInfo});
-            it = mActiveLayerInfos.erase(it);
+
+            if (CC_UNLIKELY(mTraceEnabled)) {
+                trace(layer, std::round(refreshRate));
+            }
+        }
+        isHDR |= info->isHDR();
+    }
+    if (CC_UNLIKELY(mTraceEnabled)) {
+        ALOGD("%s: maxRefreshRate=%.2f, isHDR=%d", __FUNCTION__, maxRefreshRate, isHDR);
+    }
+
+    return {maxRefreshRate, isHDR};
+}
+
+void LayerHistory::partitionLayers(nsecs_t now) {
+    const nsecs_t threshold = getActiveLayerThreshold(now);
+
+    // Collect expired and inactive layers after active layers.
+    size_t i = 0;
+    while (i < mActiveLayersEnd) {
+        auto& [weak, info] = mLayerInfos[i];
+        if (const auto layer = weak.promote(); layer && isLayerActive(*layer, *info, threshold)) {
+            i++;
+            continue;
+        }
+
+        if (CC_UNLIKELY(mTraceEnabled)) {
+            trace(weak, 0);
+        }
+
+        info->clearHistory();
+        std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]);
+    }
+
+    // Collect expired layers after inactive layers.
+    size_t end = mLayerInfos.size();
+    while (i < end) {
+        if (mLayerInfos[i].first.promote()) {
+            i++;
         } else {
-            ++it;
+            std::swap(mLayerInfos[i], mLayerInfos[--end]);
         }
     }
+
+    mLayerInfos.erase(mLayerInfos.begin() + end, mLayerInfos.end());
 }
 
-void LayerHistory::clearHistory() {
+void LayerHistory::clear() {
     std::lock_guard lock(mLock);
 
-    auto it = mActiveLayerInfos.begin();
-    while (it != mActiveLayerInfos.end()) {
-        auto id = it->first;
-        auto layerInfo = it->second;
-        layerInfo->clearHistory();
-        mInactiveLayerInfos.insert({id, layerInfo});
-        it = mActiveLayerInfos.erase(it);
+    for (const auto& [layer, info] : activeLayers()) {
+        info->clearHistory();
     }
+
+    mActiveLayersEnd = 0;
 }
 
-} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 5598cc1..15ac8ca 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -16,76 +16,78 @@
 
 #pragma once
 
-#include <array>
-#include <cinttypes>
-#include <cstdint>
-#include <numeric>
-#include <string>
-#include <unordered_map>
-
+#include <android-base/thread_annotations.h>
+#include <utils/RefBase.h>
 #include <utils/Timers.h>
 
-#include "LayerInfo.h"
-#include "SchedulerUtils.h"
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
 
 namespace android {
+
+class Layer;
+
 namespace scheduler {
 
-/*
- * This class represents information about layers that are considered current. We keep an
- * unordered map between layer name and LayerInfo.
- */
+class LayerInfo;
+
+// Records per-layer history of scheduling-related information (primarily present time),
+// heuristically categorizes layers as active or inactive, and summarizes stats about
+// active layers (primarily maximum refresh rate). See go/content-fps-detection-in-scheduler.
 class LayerHistory {
 public:
-    // Handle for each layer we keep track of.
-    class LayerHandle {
-    public:
-        LayerHandle(LayerHistory& lh, int64_t id) : mId(id), mLayerHistory(lh) {}
-        ~LayerHandle() { mLayerHistory.destroyLayer(mId); }
-
-        const int64_t mId;
-
-    private:
-        LayerHistory& mLayerHistory;
-    };
-
     LayerHistory();
     ~LayerHistory();
 
-    // When the layer is first created, register it.
-    std::unique_ptr<LayerHandle> createLayer(const std::string name, float minRefreshRate,
-                                             float maxRefreshRate);
+    // Layers are unregistered when the weak reference expires.
+    void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate);
 
-    // Method for inserting layers and their requested present time into the unordered map.
-    void insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime, bool isHdr);
-    // Method for setting layer visibility
-    void setVisibility(const std::unique_ptr<LayerHandle>& layerHandle, bool visible);
+    // Marks the layer as active, and records the given state to its history.
+    void record(Layer*, nsecs_t presentTime, bool isHDR, nsecs_t now);
 
-    // Returns the desired refresh rate, which is a max refresh rate of all the current
-    // layers. See go/content-fps-detection-in-scheduler for more information.
-    std::pair<float, bool> getDesiredRefreshRateAndHDR();
+    struct Summary {
+        float maxRefreshRate; // Maximum refresh rate among recently active layers.
+        bool isHDR;           // True if any recently active layer has HDR content.
+    };
 
-    // Clears all layer history.
-    void clearHistory();
+    // Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
+    Summary summarize(nsecs_t now);
 
-    // Removes the handle and the object from the map.
-    void destroyLayer(const int64_t id);
+    void clear();
 
 private:
-    // Removes the layers that have been idle for a given amount of time from mLayerInfos.
-    void removeIrrelevantLayers() REQUIRES(mLock);
+    friend class LayerHistoryTest;
 
-    // Information about currently active layers.
-    std::mutex mLock;
-    std::unordered_map<int64_t, std::shared_ptr<LayerInfo>> mActiveLayerInfos GUARDED_BY(mLock);
-    std::unordered_map<int64_t, std::shared_ptr<LayerInfo>> mInactiveLayerInfos GUARDED_BY(mLock);
+    using LayerPair = std::pair<wp<Layer>, std::unique_ptr<LayerInfo>>;
+    using LayerInfos = std::vector<LayerPair>;
 
-    // Each layer has it's own ID. This variable keeps track of the count.
-    static std::atomic<int64_t> sNextId;
+    struct ActiveLayers {
+        LayerInfos& infos;
+        const size_t index;
 
-    // Flag whether to log layer FPS in systrace
-    bool mTraceEnabled = false;
+        auto begin() { return infos.begin(); }
+        auto end() { return begin() + index; }
+    };
+
+    ActiveLayers activeLayers() REQUIRES(mLock) { return {mLayerInfos, mActiveLayersEnd}; }
+
+    // Iterates over layers in a single pass, swapping pairs such that active layers precede
+    // inactive layers, and inactive layers precede expired layers. Removes expired layers by
+    // truncating after inactive layers.
+    void partitionLayers(nsecs_t now) REQUIRES(mLock);
+
+    mutable std::mutex mLock;
+
+    // Partitioned such that active layers precede inactive layers. For fast lookup, the few active
+    // layers are at the front, and weak pointers are stored in contiguous memory to hit the cache.
+    LayerInfos mLayerInfos GUARDED_BY(mLock);
+    size_t mActiveLayersEnd GUARDED_BY(mLock) = 0;
+
+    // Whether to emit systrace output and debug logs.
+    const bool mTraceEnabled;
 };
 
 } // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 723d71f..f3b0d56 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -16,27 +16,17 @@
 
 #include "LayerInfo.h"
 
-#include <cinttypes>
-#include <cstdint>
-#include <numeric>
-#include <string>
+#include <algorithm>
+#include <utility>
 
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
 
-LayerInfo::LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate)
-      : mName(name),
-        mMinRefreshDuration(1e9f / maxRefreshRate),
-        mLowActivityRefreshDuration(1e9f / minRefreshRate),
-        mRefreshRateHistory(mMinRefreshDuration) {}
+LayerInfo::LayerInfo(float lowRefreshRate, float highRefreshRate)
+      : mLowRefreshRate(lowRefreshRate), mHighRefreshRate(highRefreshRate) {}
 
-LayerInfo::~LayerInfo() = default;
-
-void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime) {
-    std::lock_guard lock(mLock);
-
+void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) {
     // Buffers can come with a present time far in the future. That keeps them relevant.
-    mLastUpdatedTime = std::max(lastPresentTime, systemTime());
+    mLastUpdatedTime = std::max(lastPresentTime, now);
     mPresentTimeHistory.insertPresentTime(mLastUpdatedTime);
 
     if (mLastPresentTime == 0) {
@@ -45,14 +35,13 @@
         return;
     }
 
-    const nsecs_t timeDiff = lastPresentTime - mLastPresentTime;
+    const nsecs_t period = lastPresentTime - mLastPresentTime;
     mLastPresentTime = lastPresentTime;
     // Ignore time diff that are too high - those are stale values
-    if (timeDiff > OBSOLETE_TIME_EPSILON_NS.count()) return;
-    const nsecs_t refreshDuration = std::max(timeDiff, mMinRefreshDuration);
-    const int fps = 1e9f / refreshDuration;
+    if (period > MAX_ACTIVE_LAYER_PERIOD_NS.count()) return;
+
+    const float fps = std::min(1e9f / period, mHighRefreshRate);
     mRefreshRateHistory.insertRefreshRate(fps);
 }
 
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 17afdda..b86709f 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -16,27 +16,37 @@
 
 #pragma once
 
-#include <cinttypes>
-#include <cstdint>
-#include <deque>
-#include <mutex>
-#include <numeric>
-#include <string>
-
-#include <log/log.h>
-
-#include <utils/Mutex.h>
 #include <utils/Timers.h>
 
+#include <chrono>
+#include <deque>
+
 #include "SchedulerUtils.h"
 
 namespace android {
+
+class Layer;
+
 namespace scheduler {
 
-/*
- * This class represents information about individial layers.
- */
+using namespace std::chrono_literals;
+
+// Maximum period between presents for a layer to be considered active.
+constexpr std::chrono::nanoseconds MAX_ACTIVE_LAYER_PERIOD_NS = 1200ms;
+
+// Earliest present time for a layer to be considered active.
+constexpr nsecs_t getActiveLayerThreshold(nsecs_t now) {
+    return now - MAX_ACTIVE_LAYER_PERIOD_NS.count();
+}
+
+// Stores history of present times and refresh rates for a layer.
 class LayerInfo {
+    // Layer is considered frequent if the earliest value in the window of most recent present times
+    // is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
+    // favor of a low refresh rate.
+    static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3;
+    static constexpr std::chrono::nanoseconds MAX_FREQUENT_LAYER_PERIOD_NS = 250ms;
+
     /**
      * Struct that keeps the information about the refresh rate for last
      * HISTORY_SIZE frames. This is used to better determine the refresh rate
@@ -44,9 +54,9 @@
      */
     class RefreshRateHistory {
     public:
-        explicit RefreshRateHistory(nsecs_t minRefreshDuration)
-              : mMinRefreshDuration(minRefreshDuration) {}
-        void insertRefreshRate(int refreshRate) {
+        explicit RefreshRateHistory(float highRefreshRate) : mHighRefreshRate(highRefreshRate) {}
+
+        void insertRefreshRate(float refreshRate) {
             mElements.push_back(refreshRate);
             if (mElements.size() > HISTORY_SIZE) {
                 mElements.pop_front();
@@ -54,19 +64,16 @@
         }
 
         float getRefreshRateAvg() const {
-            if (mElements.empty()) {
-                return 1e9f / mMinRefreshDuration;
-            }
-
-            return scheduler::calculate_mean(mElements);
+            return mElements.empty() ? mHighRefreshRate : calculate_mean(mElements);
         }
 
         void clearHistory() { mElements.clear(); }
 
     private:
-        std::deque<nsecs_t> mElements;
+        const float mHighRefreshRate;
+
         static constexpr size_t HISTORY_SIZE = 30;
-        const nsecs_t mMinRefreshDuration;
+        std::deque<float> mElements;
     };
 
     /**
@@ -76,6 +83,8 @@
      */
     class PresentTimeHistory {
     public:
+        static constexpr size_t HISTORY_SIZE = 90;
+
         void insertPresentTime(nsecs_t presentTime) {
             mElements.push_back(presentTime);
             if (mElements.size() > HISTORY_SIZE) {
@@ -83,60 +92,45 @@
             }
         }
 
-        // Checks whether the present time that was inserted HISTORY_SIZE ago is within a
-        // certain threshold: TIME_EPSILON_NS.
-        bool isRelevant() const {
+        // Returns whether the earliest present time is within the active threshold.
+        bool isRecentlyActive(nsecs_t now) const {
             if (mElements.size() < 2) {
                 return false;
             }
 
             // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
-            if (mElements.size() != HISTORY_SIZE &&
-                mElements.at(mElements.size() - 1) - mElements.at(0) < HISTORY_TIME.count()) {
+            if (mElements.size() < HISTORY_SIZE &&
+                mElements.back() - mElements.front() < HISTORY_TIME.count()) {
                 return false;
             }
 
-            // The last update should not be older than OBSOLETE_TIME_EPSILON_NS nanoseconds.
-            const int64_t obsoleteEpsilon =
-                    systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count();
-            if (mElements.at(mElements.size() - 1) < obsoleteEpsilon) {
-                return false;
-            }
-
-            return true;
+            return mElements.back() >= getActiveLayerThreshold(now);
         }
 
-        bool isLowActivityLayer() const {
-            // We want to make sure that we received more than two frames from the layer
-            // in order to check low activity.
-            if (mElements.size() < scheduler::LOW_ACTIVITY_BUFFERS + 1) {
+        bool isFrequent(nsecs_t now) const {
+            // Assume layer is infrequent if too few present times have been recorded.
+            if (mElements.size() < FREQUENT_LAYER_WINDOW_SIZE) {
                 return false;
             }
 
-            const int64_t obsoleteEpsilon =
-                    systemTime() - scheduler::LOW_ACTIVITY_EPSILON_NS.count();
-            // Check the frame before last to determine whether there is low activity.
-            // If that frame is older than LOW_ACTIVITY_EPSILON_NS, the layer is sending
-            // infrequent updates.
-            if (mElements.at(mElements.size() - (scheduler::LOW_ACTIVITY_BUFFERS + 1)) <
-                obsoleteEpsilon) {
-                return true;
-            }
-
-            return false;
+            // Layer is frequent if the earliest value in the window of most recent present times is
+            // within threshold.
+            const auto it = mElements.end() - FREQUENT_LAYER_WINDOW_SIZE;
+            const nsecs_t threshold = now - MAX_FREQUENT_LAYER_PERIOD_NS.count();
+            return *it >= threshold;
         }
 
         void clearHistory() { mElements.clear(); }
 
     private:
         std::deque<nsecs_t> mElements;
-        static constexpr size_t HISTORY_SIZE = 90;
         static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
     };
 
+    friend class LayerHistoryTest;
+
 public:
-    LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate);
-    ~LayerInfo();
+    LayerInfo(float lowRefreshRate, float highRefreshRate);
 
     LayerInfo(const LayerInfo&) = delete;
     LayerInfo& operator=(const LayerInfo&) = delete;
@@ -144,71 +138,37 @@
     // Records the last requested oresent time. It also stores information about when
     // the layer was last updated. If the present time is farther in the future than the
     // updated time, the updated time is the present time.
-    void setLastPresentTime(nsecs_t lastPresentTime);
+    void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now);
 
-    void setHDRContent(bool isHdr) {
-        std::lock_guard lock(mLock);
-        mIsHDR = isHdr;
-    }
+    bool isHDR() const { return mIsHDR; }
+    void setIsHDR(bool isHDR) { mIsHDR = isHDR; }
 
-    void setVisibility(bool visible) {
-        std::lock_guard lock(mLock);
-        mIsVisible = visible;
-    }
+    bool isRecentlyActive(nsecs_t now) const { return mPresentTimeHistory.isRecentlyActive(now); }
+    bool isFrequent(nsecs_t now) const { return mPresentTimeHistory.isFrequent(now); }
 
-    // Checks the present time history to see whether the layer is relevant.
-    bool isRecentlyActive() const {
-        std::lock_guard lock(mLock);
-        return mPresentTimeHistory.isRelevant();
-    }
-
-    // Calculate the average refresh rate.
-    float getDesiredRefreshRate() const {
-        std::lock_guard lock(mLock);
-
-        if (mPresentTimeHistory.isLowActivityLayer()) {
-            return 1e9f / mLowActivityRefreshDuration;
-        }
-        return mRefreshRateHistory.getRefreshRateAvg();
-    }
-
-    bool getHDRContent() {
-        std::lock_guard lock(mLock);
-        return mIsHDR;
-    }
-
-    bool isVisible() {
-        std::lock_guard lock(mLock);
-        return mIsVisible;
+    float getRefreshRate(nsecs_t now) const {
+        return isFrequent(now) ? mRefreshRateHistory.getRefreshRateAvg() : mLowRefreshRate;
     }
 
     // Return the last updated time. If the present time is farther in the future than the
     // updated time, the updated time is the present time.
-    nsecs_t getLastUpdatedTime() {
-        std::lock_guard lock(mLock);
-        return mLastUpdatedTime;
-    }
-
-    std::string getName() const { return mName; }
+    nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; }
 
     void clearHistory() {
-        std::lock_guard lock(mLock);
         mRefreshRateHistory.clearHistory();
         mPresentTimeHistory.clearHistory();
     }
 
 private:
-    const std::string mName;
-    const nsecs_t mMinRefreshDuration;
-    const nsecs_t mLowActivityRefreshDuration;
-    mutable std::mutex mLock;
-    nsecs_t mLastUpdatedTime GUARDED_BY(mLock) = 0;
-    nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0;
-    RefreshRateHistory mRefreshRateHistory GUARDED_BY(mLock);
-    PresentTimeHistory mPresentTimeHistory GUARDED_BY(mLock);
-    bool mIsHDR GUARDED_BY(mLock) = false;
-    bool mIsVisible GUARDED_BY(mLock) = false;
+    const float mLowRefreshRate;
+    const float mHighRefreshRate;
+
+    nsecs_t mLastUpdatedTime = 0;
+    nsecs_t mLastPresentTime = 0;
+    RefreshRateHistory mRefreshRateHistory{mHighRefreshRate};
+    PresentTimeHistory mPresentTimeHistory;
+    bool mIsHDR = false;
 };
 
 } // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index d60e101..71b3500 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -20,13 +20,6 @@
 
 #include "Scheduler.h"
 
-#include <algorithm>
-#include <cinttypes>
-#include <cstdint>
-#include <functional>
-#include <memory>
-#include <numeric>
-
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
@@ -37,6 +30,14 @@
 #include <utils/Timers.h>
 #include <utils/Trace.h>
 
+#include <algorithm>
+#include <cinttypes>
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <numeric>
+
+#include "../Layer.h"
 #include "DispSync.h"
 #include "DispSyncSource.h"
 #include "EventControlThread.h"
@@ -325,37 +326,27 @@
     return mPrimaryDispSync->expectedPresentTime();
 }
 
-std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
-        std::string const& name, int windowType) {
+void Scheduler::registerLayer(Layer* layer) {
     uint32_t defaultFps, performanceFps;
     if (mRefreshRateConfigs.refreshRateSwitchingSupported()) {
         defaultFps = mRefreshRateConfigs.getRefreshRateFromType(RefreshRateType::DEFAULT).fps;
-        performanceFps =
-                mRefreshRateConfigs
-                        .getRefreshRateFromType((windowType == InputWindowInfo::TYPE_WALLPAPER)
-                                                        ? RefreshRateType::DEFAULT
-                                                        : RefreshRateType::PERFORMANCE)
-                        .fps;
+        const auto type = layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER
+                ? RefreshRateType::DEFAULT
+                : RefreshRateType::PERFORMANCE;
+        performanceFps = mRefreshRateConfigs.getRefreshRateFromType(type).fps;
     } else {
         defaultFps = mRefreshRateConfigs.getCurrentRefreshRate().second.fps;
         performanceFps = defaultFps;
     }
-    return mLayerHistory.createLayer(name, defaultFps, performanceFps);
+    mLayerHistory.registerLayer(layer, defaultFps, performanceFps);
 }
 
-void Scheduler::addLayerPresentTimeAndHDR(
-        const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
-        nsecs_t presentTime, bool isHDR) {
-    mLayerHistory.insert(layerHandle, presentTime, isHDR);
-}
-
-void Scheduler::setLayerVisibility(
-        const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible) {
-    mLayerHistory.setVisibility(layerHandle, visible);
+void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime, bool isHDR) {
+    mLayerHistory.record(layer, presentTime, isHDR, systemTime());
 }
 
 void Scheduler::updateFpsBasedOnContent() {
-    auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR();
+    auto [refreshRate, isHDR] = mLayerHistory.summarize(systemTime());
     const uint32_t refreshRateRound = std::round(refreshRate);
     RefreshRateType newRefreshRateType;
     {
@@ -402,7 +393,7 @@
 
     // Touch event will boost the refresh rate to performance.
     // Clear Layer History to get fresh FPS detection
-    mLayerHistory.clearHistory();
+    mLayerHistory.clear();
 }
 
 void Scheduler::setDisplayPowerState(bool normal) {
@@ -417,7 +408,7 @@
 
     // Display Power event will boost the refresh rate to performance.
     // Clear Layer History to get fresh FPS detection
-    mLayerHistory.clearHistory();
+    mLayerHistory.clear();
 }
 
 void Scheduler::kernelIdleTimerCallback(TimerState state) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index a5971fe..c983475 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -100,17 +100,11 @@
     void addPresentFence(const std::shared_ptr<FenceTime>&);
     void setIgnorePresentFences(bool ignore);
     nsecs_t getDispSyncExpectedPresentTime();
-    // Registers the layer in the scheduler, and returns the handle for future references.
-    std::unique_ptr<scheduler::LayerHistory::LayerHandle> registerLayer(std::string const& name,
-                                                                        int windowType);
 
-    // Stores present time for a layer.
-    void addLayerPresentTimeAndHDR(
-            const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
-            nsecs_t presentTime, bool isHDR);
-    // Stores visibility for a layer.
-    void setLayerVisibility(
-            const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible);
+    // Layers are registered on creation, and unregistered when the weak reference expires.
+    void registerLayer(Layer*);
+    void recordLayerHistory(Layer*, nsecs_t presentTime, bool isHDR);
+
     // Updates FPS based on the most content presented.
     void updateFpsBasedOnContent();
 
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index 3b7567c..d301b99 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#include <chrono>
 #include <cinttypes>
 #include <numeric>
 #include <unordered_map>
@@ -38,21 +37,6 @@
     return lhs.id == rhs.id;
 }
 
-using namespace std::chrono_literals;
-
-// This number is used when we try to determine how long do we keep layer information around
-// before we remove it. It is also used to determine how long the layer stays relevant.
-// This time period captures infrequent updates when playing YouTube video with static image,
-// or waiting idle in messaging app, when cursor is blinking.
-static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 1200ms;
-
-// Layer is considered low activity if the LOW_ACTIVITY_BUFFERS buffers come more than
-// LOW_ACTIVITY_EPSILON_NS  apart.
-// This is helping SF to vote for lower refresh rates when there is not activity
-// in screen.
-static constexpr int LOW_ACTIVITY_BUFFERS = 2;
-static constexpr std::chrono::nanoseconds LOW_ACTIVITY_EPSILON_NS = 250ms;
-
 // Calculates the statistical mean (average) in the data structure (array, vector). The
 // function does not modify the contents of the array.
 template <typename T>
diff --git a/services/surfaceflinger/Scheduler/StrongTyping.h b/services/surfaceflinger/Scheduler/StrongTyping.h
new file mode 100644
index 0000000..02db022
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/StrongTyping.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+namespace android {
+
+template <typename T, template <typename> class AbilityType>
+struct Ability {
+    T& base() { return static_cast<T&>(*this); }
+    T const& base() const { return static_cast<T const&>(*this); }
+};
+
+template <typename T>
+struct Add : Ability<T, Add> {
+    inline T operator+(T const& other) const { return T(this->base().value() + other.value()); }
+    inline T& operator++() {
+        ++this->base().value();
+        return this->base();
+    };
+    inline T operator++(int) {
+        T tmp(this->base());
+        operator++();
+        return tmp;
+    };
+    inline T& operator+=(T const& other) {
+        this->base().value() += other.value();
+        return this->base();
+    };
+};
+
+template <typename T>
+struct Compare : Ability<T, Compare> {
+    inline bool operator==(T const& other) const { return this->base().value() == other.value(); };
+    inline bool operator<(T const& other) const { return this->base().value() < other.value(); }
+    inline bool operator<=(T const& other) const { return (*this < other) || (*this == other); }
+    inline bool operator!=(T const& other) const { return !(*this == other); }
+    inline bool operator>=(T const& other) const { return !(*this < other); }
+    inline bool operator>(T const& other) const { return !(*this < other || *this == other); }
+};
+
+template <typename T, typename W, template <typename> class... Ability>
+struct StrongTyping : Ability<StrongTyping<T, W, Ability...>>... {
+    StrongTyping() : mValue(0) {}
+    explicit StrongTyping(T const& value) : mValue(value) {}
+    StrongTyping(StrongTyping const&) = default;
+    StrongTyping& operator=(StrongTyping const&) = default;
+    inline operator T() const { return mValue; }
+    T const& value() const { return mValue; }
+    T& value() { return mValue; }
+
+private:
+    T mValue;
+};
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b9e95a6..1acb2da 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -122,6 +122,8 @@
 
 namespace android {
 
+using namespace std::string_literals;
+
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
 using namespace android::sysprop;
@@ -258,7 +260,8 @@
         mFrameTracer(std::make_unique<FrameTracer>()),
         mEventQueue(mFactory.createMessageQueue()),
         mCompositionEngine(mFactory.createCompositionEngine()),
-        mPhaseOffsets(mFactory.createPhaseOffsets()) {}
+        mPhaseOffsets(mFactory.createPhaseOffsets()),
+        mPendingSyncInputWindows(false) {}
 
 SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
     ALOGI("SurfaceFlinger is starting");
@@ -598,20 +601,19 @@
     Mutex::Autolock _l(mStateLock);
 
     // Get a RenderEngine for the given display / config (can't fail)
-    int32_t renderEngineFeature = 0;
-    renderEngineFeature |= (useColorManagement ?
-                            renderengine::RenderEngine::USE_COLOR_MANAGEMENT : 0);
-    renderEngineFeature |= (useContextPriority ?
-                            renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0);
-    renderEngineFeature |=
-            (enable_protected_contents(false) ? renderengine::RenderEngine::ENABLE_PROTECTED_CONTEXT
-                                              : 0);
-
     // TODO(b/77156734): We need to stop casting and use HAL types when possible.
     // Sending maxFrameBufferAcquiredBuffers as the cache size is tightly tuned to single-display.
-    mCompositionEngine->setRenderEngine(
-            renderengine::RenderEngine::create(static_cast<int32_t>(defaultCompositionPixelFormat),
-                                               renderEngineFeature, maxFrameBufferAcquiredBuffers));
+    mCompositionEngine->setRenderEngine(renderengine::RenderEngine::create(
+            renderengine::RenderEngineCreationArgs::Builder()
+                .setPixelFormat(static_cast<int32_t>(defaultCompositionPixelFormat))
+                .setImageCacheSize(maxFrameBufferAcquiredBuffers)
+                .setUseColorManagerment(useColorManagement)
+                .setEnableProtectedContext(enable_protected_contents(false))
+                .setPrecacheToneMapperShaderOnly(false)
+                .setContextPriority(useContextPriority
+                        ? renderengine::RenderEngine::ContextPriority::HIGH
+                        : renderengine::RenderEngine::ContextPriority::MEDIUM)
+                .build()));
 
     LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
             "Starting with vr flinger active is not currently supported.");
@@ -1910,8 +1912,7 @@
                 layer->onPostComposition(displayDevice->getId(), glCompositionDoneFenceTime,
                                          presentFenceTime, compositorTiming);
         if (frameLatched) {
-            recordBufferingStats(layer->getName().string(),
-                    layer->getOccupancyHistory(false));
+            recordBufferingStats(layer->getName(), layer->getOccupancyHistory(false));
         }
     });
 
@@ -2573,7 +2574,7 @@
     if (!mLayersPendingRemoval.isEmpty()) {
         // Notify removed layers now that they can't be drawn from
         for (const auto& l : mLayersPendingRemoval) {
-            recordBufferingStats(l->getName().string(), l->getOccupancyHistory(true));
+            recordBufferingStats(l->getName(), l->getOccupancyHistory(true));
 
             // Ensure any buffers set to display on any children are released.
             if (l->isRemovedFromCurrentState()) {
@@ -3243,11 +3244,12 @@
         // everything else inherits layer stack from its parent.
         if (layer->hasParent()) {
             ALOGE("Attempt to set layer stack on layer with parent (%s) is invalid",
-                    layer->getName().string());
+                  layer->getDebugName());
         } else if (idx < 0) {
             ALOGE("Attempt to set layer stack on layer without parent (%s) that "
-                    "that also does not appear in the top level layer list. Something"
-                    " has gone wrong.", layer->getName().string());
+                  "that also does not appear in the top level layer list. Something"
+                  " has gone wrong.",
+                  layer->getDebugName());
         } else if (layer->setLayerStack(s.layerStack)) {
             mCurrentState.layersSortedByZ.removeAt(idx);
             mCurrentState.layersSortedByZ.add(layer);
@@ -3405,7 +3407,7 @@
 
     sp<Layer> mirrorLayer;
     sp<Layer> mirrorFrom;
-    String8 uniqueName = getUniqueLayerName(String8("MirrorRoot"));
+    std::string uniqueName = getUniqueLayerName("MirrorRoot");
 
     {
         Mutex::Autolock _l(mStateLock);
@@ -3414,8 +3416,8 @@
             return NAME_NOT_FOUND;
         }
 
-        status_t result = createContainerLayer(client, uniqueName, -1, -1, 0, LayerMetadata(),
-                                               outHandle, &mirrorLayer);
+        status_t result = createContainerLayer(client, std::move(uniqueName), -1, -1, 0,
+                                               LayerMetadata(), outHandle, &mirrorLayer);
         if (result != NO_ERROR) {
             return result;
         }
@@ -3446,7 +3448,7 @@
 
     sp<Layer> layer;
 
-    String8 uniqueName = getUniqueLayerName(name);
+    std::string uniqueName = getUniqueLayerName(name.string());
 
     bool primaryDisplayOnly = false;
 
@@ -3462,13 +3464,13 @@
 
     switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
         case ISurfaceComposerClient::eFXSurfaceBufferQueue:
-            result = createBufferQueueLayer(client, uniqueName, w, h, flags, std::move(metadata),
-                                            format, handle, gbp, &layer);
+            result = createBufferQueueLayer(client, std::move(uniqueName), w, h, flags,
+                                            std::move(metadata), format, handle, gbp, &layer);
 
             break;
         case ISurfaceComposerClient::eFXSurfaceBufferState:
-            result = createBufferStateLayer(client, uniqueName, w, h, flags, std::move(metadata),
-                                            handle, &layer);
+            result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags,
+                                            std::move(metadata), handle, &layer);
             break;
         case ISurfaceComposerClient::eFXSurfaceColor:
             // check if buffer size is set for color layer.
@@ -3478,8 +3480,8 @@
                 return BAD_VALUE;
             }
 
-            result = createColorLayer(client, uniqueName, w, h, flags, std::move(metadata), handle,
-                                      &layer);
+            result = createColorLayer(client, std::move(uniqueName), w, h, flags,
+                                      std::move(metadata), handle, &layer);
             break;
         case ISurfaceComposerClient::eFXSurfaceContainer:
             // check if buffer size is set for container layer.
@@ -3488,8 +3490,8 @@
                       int(w), int(h));
                 return BAD_VALUE;
             }
-            result = createContainerLayer(client, uniqueName, w, h, flags, std::move(metadata),
-                                          handle, &layer);
+            result = createContainerLayer(client, std::move(uniqueName), w, h, flags,
+                                          std::move(metadata), handle, &layer);
             break;
         default:
             result = BAD_VALUE;
@@ -3516,35 +3518,32 @@
     return result;
 }
 
-String8 SurfaceFlinger::getUniqueLayerName(const String8& name)
-{
-    bool matchFound = true;
-    uint32_t dupeCounter = 0;
+std::string SurfaceFlinger::getUniqueLayerName(const char* name) {
+    unsigned dupeCounter = 0;
 
     // Tack on our counter whether there is a hit or not, so everyone gets a tag
-    String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str());
+    std::string uniqueName = base::StringPrintf("%s#%u", name, dupeCounter);
 
     // Grab the state lock since we're accessing mCurrentState
     Mutex::Autolock lock(mStateLock);
 
     // Loop over layers until we're sure there is no matching name
+    bool matchFound = true;
     while (matchFound) {
         matchFound = false;
         mCurrentState.traverseInZOrder([&](Layer* layer) {
             if (layer->getName() == uniqueName) {
                 matchFound = true;
-                uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str());
+                uniqueName = base::StringPrintf("%s#%u", name, ++dupeCounter);
             }
         });
     }
 
-    ALOGV_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(),
-             uniqueName.c_str());
-
+    ALOGV_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name, uniqueName.c_str());
     return uniqueName;
 }
 
-status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, const String8& name,
+status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, std::string name,
                                                 uint32_t w, uint32_t h, uint32_t flags,
                                                 LayerMetadata metadata, PixelFormat& format,
                                                 sp<IBinder>* handle,
@@ -3562,8 +3561,7 @@
     }
 
     sp<BufferQueueLayer> layer;
-    LayerCreationArgs args =
-            LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata));
+    LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata));
     args.textureName = getNewTexture();
     {
         // Grab the SF state lock during this since it's the only safe way to access
@@ -3584,12 +3582,11 @@
     return err;
 }
 
-status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, const String8& name,
+status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, std::string name,
                                                 uint32_t w, uint32_t h, uint32_t flags,
                                                 LayerMetadata metadata, sp<IBinder>* handle,
                                                 sp<Layer>* outLayer) {
-    LayerCreationArgs args =
-            LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata));
+    LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata));
     args.displayDevice = getDefaultDisplayDevice();
     args.textureName = getNewTexture();
     sp<BufferStateLayer> layer = getFactory().createBufferStateLayer(args);
@@ -3599,26 +3596,25 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::createColorLayer(const sp<Client>& client, const String8& name, uint32_t w,
+status_t SurfaceFlinger::createColorLayer(const sp<Client>& client, std::string name, uint32_t w,
                                           uint32_t h, uint32_t flags, LayerMetadata metadata,
                                           sp<IBinder>* handle, sp<Layer>* outLayer) {
     *outLayer = getFactory().createColorLayer(
-            LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata)));
+            {this, client, std::move(name), w, h, flags, std::move(metadata)});
     *handle = (*outLayer)->getHandle();
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::createContainerLayer(const sp<Client>& client, const String8& name,
+status_t SurfaceFlinger::createContainerLayer(const sp<Client>& client, std::string name,
                                               uint32_t w, uint32_t h, uint32_t flags,
                                               LayerMetadata metadata, sp<IBinder>* handle,
                                               sp<Layer>* outLayer) {
     *outLayer = getFactory().createContainerLayer(
-            LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata)));
+            {this, client, std::move(name), w, h, flags, std::move(metadata)});
     *handle = (*outLayer)->getHandle();
     return NO_ERROR;
 }
 
-
 void SurfaceFlinger::markLayerPendingRemovalLocked(const sp<Layer>& layer) {
     mLayersPendingRemoval.add(layer);
     mLayersRemoved = true;
@@ -3827,8 +3823,6 @@
                           strerror(-err), err);
         }
 
-        using namespace std::string_literals;
-
         static const std::unordered_map<std::string, Dumper> dumpers = {
                 {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
                 {"--dispsync"s,
@@ -3884,7 +3878,7 @@
 
 void SurfaceFlinger::listLayersLocked(std::string& result) const {
     mCurrentState.traverseInZOrder(
-            [&](Layer* layer) { StringAppendF(&result, "%s\n", layer->getName().string()); });
+            [&](Layer* layer) { StringAppendF(&result, "%s\n", layer->getDebugName()); });
 }
 
 void SurfaceFlinger::dumpStatsLocked(const DumpArgs& args, std::string& result) const {
@@ -3893,7 +3887,7 @@
     if (args.size() > 1) {
         const auto name = String8(args[1]);
         mCurrentState.traverseInZOrder([&](Layer* layer) {
-            if (name == layer->getName()) {
+            if (layer->getName() == name.string()) {
                 layer->dumpFrameStats(result);
             }
         });
@@ -3903,8 +3897,11 @@
 }
 
 void SurfaceFlinger::clearStatsLocked(const DumpArgs& args, std::string&) {
+    const bool clearAll = args.size() < 2;
+    const auto name = clearAll ? String8() : String8(args[1]);
+
     mCurrentState.traverseInZOrder([&](Layer* layer) {
-        if (args.size() < 2 || String8(args[1]) == layer->getName()) {
+        if (clearAll || layer->getName() == name.string()) {
             layer->clearFrameStats();
         }
     });
@@ -3923,7 +3920,7 @@
         layer->logFrameStats();
     });
 
-    mAnimFrameTracker.logAndResetStats(String8("<win-anim>"));
+    mAnimFrameTracker.logAndResetStats("<win-anim>");
 }
 
 void SurfaceFlinger::appendSfConfigString(std::string& result) const {
@@ -3981,8 +3978,8 @@
                   bucketTimeSec, percent);
 }
 
-void SurfaceFlinger::recordBufferingStats(const char* layerName,
-        std::vector<OccupancyTracker::Segment>&& history) {
+void SurfaceFlinger::recordBufferingStats(const std::string& layerName,
+                                          std::vector<OccupancyTracker::Segment>&& history) {
     Mutex::Autolock lock(getBE().mBufferingStatsMutex);
     auto& stats = getBE().mBufferingStats[layerName];
     for (const auto& segment : history) {
@@ -5030,13 +5027,14 @@
                 drawLayers();
             } else {
                 Rect bounds = getBounds();
+                uint32_t w = static_cast<uint32_t>(bounds.getWidth());
+                uint32_t h = static_cast<uint32_t>(bounds.getHeight());
                 // In the "childrenOnly" case we reparent the children to a screenshot
                 // layer which has no properties set and which does not draw.
                 sp<ContainerLayer> screenshotParentLayer =
-                        mFlinger->getFactory().createContainerLayer(
-                                LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
-                                                  bounds.getWidth(), bounds.getHeight(), 0,
-                                                  LayerMetadata()));
+                        mFlinger->getFactory().createContainerLayer({mFlinger, nullptr,
+                                                                     "Screenshot Parent"s, w, h, 0,
+                                                                     LayerMetadata()});
 
                 ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
                 drawLayers();
@@ -5453,7 +5451,7 @@
         return NO_ERROR;
     }
 
-    postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS {
+    postMessageSync(new LambdaMessage([&]() {
         const auto display = getDisplayDeviceLocked(displayToken);
         if (!display) {
             ALOGE("Attempt to set allowed display configs for invalid display token %p",
@@ -5461,6 +5459,7 @@
         } else if (display->isVirtual()) {
             ALOGW("Attempt to set allowed display configs for virtual display");
         } else {
+            Mutex::Autolock lock(mStateLock);
             setAllowedDisplayConfigsInternal(display, allowedConfigs);
         }
     }));
@@ -5506,6 +5505,16 @@
     return nullptr;
 }
 
+void SurfaceFlinger::onLayerCreated(Layer* layer) {
+    mNumLayers++;
+    mScheduler->registerLayer(layer);
+}
+
+void SurfaceFlinger::onLayerDestroyed(Layer* layer) {
+    mNumLayers--;
+    mOffscreenLayers.erase(layer);
+}
+
 void SurfaceFlinger::bufferErased(const client_cache_t& clientCacheId) {
     getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id);
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a9a4276..abb8b82 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -310,11 +310,8 @@
     bool authenticateSurfaceTextureLocked(
         const sp<IGraphicBufferProducer>& bufferProducer) const;
 
-    inline void onLayerCreated() { mNumLayers++; }
-    inline void onLayerDestroyed(Layer* layer) {
-        mNumLayers--;
-        mOffscreenLayers.erase(layer);
-    }
+    void onLayerCreated(Layer*);
+    void onLayerDestroyed(Layer*);
 
     TransactionCompletedThread& getTransactionCompletedThread() {
         return mTransactionCompletedThread;
@@ -338,6 +335,7 @@
 
     // For unit tests
     friend class TestableSurfaceFlinger;
+    friend class TransactionApplicationTest;
 
     // This value is specified in number of frames.  Log frame stats at most
     // every half hour.
@@ -606,27 +604,27 @@
                          sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp,
                          const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer = nullptr);
 
-    status_t createBufferQueueLayer(const sp<Client>& client, const String8& name, uint32_t w,
+    status_t createBufferQueueLayer(const sp<Client>& client, std::string name, uint32_t w,
                                     uint32_t h, uint32_t flags, LayerMetadata metadata,
                                     PixelFormat& format, sp<IBinder>* outHandle,
                                     sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
 
-    status_t createBufferStateLayer(const sp<Client>& client, const String8& name, uint32_t w,
+    status_t createBufferStateLayer(const sp<Client>& client, std::string name, uint32_t w,
                                     uint32_t h, uint32_t flags, LayerMetadata metadata,
                                     sp<IBinder>* outHandle, sp<Layer>* outLayer);
 
-    status_t createColorLayer(const sp<Client>& client, const String8& name, uint32_t w, uint32_t h,
+    status_t createColorLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h,
                               uint32_t flags, LayerMetadata metadata, sp<IBinder>* outHandle,
                               sp<Layer>* outLayer);
 
-    status_t createContainerLayer(const sp<Client>& client, const String8& name, uint32_t w,
+    status_t createContainerLayer(const sp<Client>& client, std::string name, uint32_t w,
                                   uint32_t h, uint32_t flags, LayerMetadata metadata,
                                   sp<IBinder>* outHandle, sp<Layer>* outLayer);
 
     status_t mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
                          sp<IBinder>* outHandle);
 
-    String8 getUniqueLayerName(const String8& name);
+    std::string getUniqueLayerName(const char* name);
 
     // called when all clients have released all their references to
     // this layer meaning it is entirely safe to destroy all
@@ -865,8 +863,8 @@
     // Not const because each Layer needs to query Fences and cache timestamps.
     void dumpFrameEventsLocked(std::string& result);
 
-    void recordBufferingStats(const char* layerName,
-            std::vector<OccupancyTracker::Segment>&& history);
+    void recordBufferingStats(const std::string& layerName,
+                              std::vector<OccupancyTracker::Segment>&& history);
     void dumpBufferingStats(std::string& result) const;
     void dumpDisplayIdentificationData(std::string& result) const;
     void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const;
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
new file mode 100644
index 0000000..4f439da
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <compositionengine/impl/CompositionEngine.h>
+#include <ui/GraphicBuffer.h>
+
+#include "BufferLayerConsumer.h"
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "ColorLayer.h"
+#include "ContainerLayer.h"
+#include "DisplayDevice.h"
+#include "Layer.h"
+#include "MonitoredProducer.h"
+#include "NativeWindowSurface.h"
+#include "StartPropertySetThread.h"
+#include "SurfaceFlingerDefaultFactory.h"
+#include "SurfaceInterceptor.h"
+
+#include "DisplayHardware/ComposerHal.h"
+#include "Scheduler/DispSync.h"
+#include "Scheduler/EventControlThread.h"
+#include "Scheduler/MessageQueue.h"
+#include "Scheduler/PhaseOffsets.h"
+#include "Scheduler/Scheduler.h"
+
+namespace android::surfaceflinger {
+
+DefaultFactory::~DefaultFactory() = default;
+
+std::unique_ptr<DispSync> DefaultFactory::createDispSync(const char* name, bool hasSyncFramework) {
+    return std::make_unique<android::impl::DispSync>(name, hasSyncFramework);
+}
+
+std::unique_ptr<EventControlThread> DefaultFactory::createEventControlThread(
+        SetVSyncEnabled setVSyncEnabled) {
+    return std::make_unique<android::impl::EventControlThread>(std::move(setVSyncEnabled));
+}
+
+std::unique_ptr<HWComposer> DefaultFactory::createHWComposer(const std::string& serviceName) {
+    return std::make_unique<android::impl::HWComposer>(
+            std::make_unique<Hwc2::impl::Composer>(serviceName));
+}
+
+std::unique_ptr<MessageQueue> DefaultFactory::createMessageQueue() {
+    return std::make_unique<android::impl::MessageQueue>();
+}
+
+std::unique_ptr<scheduler::PhaseOffsets> DefaultFactory::createPhaseOffsets() {
+    return std::make_unique<scheduler::impl::PhaseOffsets>();
+}
+
+std::unique_ptr<Scheduler> DefaultFactory::createScheduler(
+        SetVSyncEnabled setVSyncEnabled, const scheduler::RefreshRateConfigs& configs) {
+    return std::make_unique<Scheduler>(std::move(setVSyncEnabled), configs);
+}
+
+std::unique_ptr<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor(
+        SurfaceFlinger* flinger) {
+    return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
+}
+
+sp<StartPropertySetThread> DefaultFactory::createStartPropertySetThread(
+        bool timestampPropertyValue) {
+    return new StartPropertySetThread(timestampPropertyValue);
+}
+
+sp<DisplayDevice> DefaultFactory::createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) {
+    return new DisplayDevice(std::move(creationArgs));
+}
+
+sp<GraphicBuffer> DefaultFactory::createGraphicBuffer(uint32_t width, uint32_t height,
+                                                      PixelFormat format, uint32_t layerCount,
+                                                      uint64_t usage, std::string requestorName) {
+    return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
+}
+
+void DefaultFactory::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+                                       sp<IGraphicBufferConsumer>* outConsumer,
+                                       bool consumerIsSurfaceFlinger) {
+    BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
+}
+
+sp<IGraphicBufferProducer> DefaultFactory::createMonitoredProducer(
+        const sp<IGraphicBufferProducer>& producer, const sp<SurfaceFlinger>& flinger,
+        const wp<Layer>& layer) {
+    return new MonitoredProducer(producer, flinger, layer);
+}
+
+sp<BufferLayerConsumer> DefaultFactory::createBufferLayerConsumer(
+        const sp<IGraphicBufferConsumer>& consumer, renderengine::RenderEngine& renderEngine,
+        uint32_t textureName, Layer* layer) {
+    return new BufferLayerConsumer(consumer, renderEngine, textureName, layer);
+}
+
+std::unique_ptr<surfaceflinger::NativeWindowSurface> DefaultFactory::createNativeWindowSurface(
+        const sp<IGraphicBufferProducer>& producer) {
+    return surfaceflinger::impl::createNativeWindowSurface(producer);
+}
+
+std::unique_ptr<compositionengine::CompositionEngine> DefaultFactory::createCompositionEngine() {
+    return compositionengine::impl::createCompositionEngine();
+}
+
+sp<ContainerLayer> DefaultFactory::createContainerLayer(const LayerCreationArgs& args) {
+    return new ContainerLayer(args);
+}
+
+sp<BufferQueueLayer> DefaultFactory::createBufferQueueLayer(const LayerCreationArgs& args) {
+    return new BufferQueueLayer(args);
+}
+
+sp<BufferStateLayer> DefaultFactory::createBufferStateLayer(const LayerCreationArgs& args) {
+    return new BufferStateLayer(args);
+}
+
+sp<ColorLayer> DefaultFactory::createColorLayer(const LayerCreationArgs& args) {
+    return new ColorLayer(args);
+}
+
+} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
new file mode 100644
index 0000000..42bb177
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "SurfaceFlingerFactory.h"
+
+namespace android::surfaceflinger {
+
+// A default implementation of the factory which creates the standard
+// implementation types for each interface.
+class DefaultFactory : public surfaceflinger::Factory {
+public:
+    virtual ~DefaultFactory();
+
+    std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework) override;
+    std::unique_ptr<EventControlThread> createEventControlThread(SetVSyncEnabled) override;
+    std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override;
+    std::unique_ptr<MessageQueue> createMessageQueue() override;
+    std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override;
+    std::unique_ptr<Scheduler> createScheduler(SetVSyncEnabled,
+                                               const scheduler::RefreshRateConfigs&) override;
+    std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) override;
+    sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override;
+    sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&&) override;
+    sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
+                                          uint32_t layerCount, uint64_t usage,
+                                          std::string requestorName) override;
+    void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+                           sp<IGraphicBufferConsumer>* outConsumer,
+                           bool consumerIsSurfaceFlinger) override;
+    sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>&,
+                                                       const sp<SurfaceFlinger>&,
+                                                       const wp<Layer>&) override;
+    sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>&,
+                                                      renderengine::RenderEngine&, uint32_t tex,
+                                                      Layer*) override;
+    std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
+            const sp<IGraphicBufferProducer>&) override;
+    std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override;
+    sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) override;
+    sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override;
+    sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) override;
+    sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override;
+};
+
+} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index 4ddc132..9b1f658 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -14,116 +14,13 @@
  * limitations under the License.
  */
 
-#include <compositionengine/impl/CompositionEngine.h>
-#include <ui/GraphicBuffer.h>
-
-#include "BufferQueueLayer.h"
-#include "BufferStateLayer.h"
-#include "ColorLayer.h"
-#include "ContainerLayer.h"
-#include "DisplayDevice.h"
-#include "Layer.h"
-#include "NativeWindowSurface.h"
-#include "StartPropertySetThread.h"
 #include "SurfaceFlinger.h"
-#include "SurfaceFlingerFactory.h"
-#include "SurfaceInterceptor.h"
-
-#include "DisplayHardware/ComposerHal.h"
-#include "Scheduler/DispSync.h"
-#include "Scheduler/EventControlThread.h"
-#include "Scheduler/MessageQueue.h"
-#include "Scheduler/PhaseOffsets.h"
-#include "Scheduler/Scheduler.h"
+#include "SurfaceFlingerDefaultFactory.h"
 
 namespace android::surfaceflinger {
 
 sp<SurfaceFlinger> createSurfaceFlinger() {
-    class Factory final : public surfaceflinger::Factory {
-    public:
-        Factory() = default;
-        ~Factory() = default;
-
-        std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework) override {
-            return std::make_unique<android::impl::DispSync>(name, hasSyncFramework);
-        }
-
-        std::unique_ptr<EventControlThread> createEventControlThread(
-                SetVSyncEnabled setVSyncEnabled) override {
-            return std::make_unique<android::impl::EventControlThread>(std::move(setVSyncEnabled));
-        }
-
-        std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override {
-            return std::make_unique<android::impl::HWComposer>(
-                    std::make_unique<Hwc2::impl::Composer>(serviceName));
-        }
-
-        std::unique_ptr<MessageQueue> createMessageQueue() override {
-            return std::make_unique<android::impl::MessageQueue>();
-        }
-
-        std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override {
-            return std::make_unique<scheduler::impl::PhaseOffsets>();
-        }
-
-        std::unique_ptr<Scheduler> createScheduler(
-                SetVSyncEnabled setVSyncEnabled,
-                const scheduler::RefreshRateConfigs& configs) override {
-            return std::make_unique<Scheduler>(std::move(setVSyncEnabled), configs);
-        }
-
-        std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(
-                SurfaceFlinger* flinger) override {
-            return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
-        }
-
-        sp<StartPropertySetThread> createStartPropertySetThread(
-                bool timestampPropertyValue) override {
-            return new StartPropertySetThread(timestampPropertyValue);
-        }
-
-        sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) override {
-            return new DisplayDevice(std::move(creationArgs));
-        }
-
-        sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
-                                              uint32_t layerCount, uint64_t usage,
-                                              std::string requestorName) override {
-            return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
-        }
-
-        void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
-                               sp<IGraphicBufferConsumer>* outConsumer,
-                               bool consumerIsSurfaceFlinger) override {
-            BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
-        }
-
-        std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
-                const sp<IGraphicBufferProducer>& producer) override {
-            return surfaceflinger::impl::createNativeWindowSurface(producer);
-        }
-
-        std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override {
-            return compositionengine::impl::createCompositionEngine();
-        }
-
-        sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override {
-            return new ContainerLayer(args);
-        }
-
-        sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) override {
-            return new BufferQueueLayer(args);
-        }
-
-        sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override {
-            return new BufferStateLayer(args);
-        }
-
-        sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) override {
-            return new ColorLayer(args);
-        }
-    };
-    static Factory factory;
+    static DefaultFactory factory;
 
     return new SurfaceFlinger(factory);
 }
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 3fd4de8..20784d2 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -30,6 +30,7 @@
 
 class BufferQueueLayer;
 class BufferStateLayer;
+class BufferLayerConsumer;
 class ColorLayer;
 class ContainerLayer;
 class DisplayDevice;
@@ -39,6 +40,7 @@
 class HWComposer;
 class IGraphicBufferConsumer;
 class IGraphicBufferProducer;
+class Layer;
 class MessageQueue;
 class Scheduler;
 class StartPropertySetThread;
@@ -85,6 +87,13 @@
     virtual void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
                                    sp<IGraphicBufferConsumer>* outConsumer,
                                    bool consumerIsSurfaceFlinger) = 0;
+    virtual sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>&,
+                                                               const sp<SurfaceFlinger>&,
+                                                               const wp<Layer>&) = 0;
+    virtual sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>&,
+                                                              renderengine::RenderEngine&,
+                                                              uint32_t tex, Layer*) = 0;
+
     virtual std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
             const sp<IGraphicBufferProducer>&) = 0;
 
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index a02d14c..7e6c472 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -165,10 +165,6 @@
     return layer;
 }
 
-const std::string SurfaceInterceptor::getLayerName(const sp<const Layer>& layer) const {
-    return layer->getName().string();
-}
-
 int32_t SurfaceInterceptor::getLayerId(const sp<const Layer>& layer) const {
     return layer->sequence;
 }
@@ -490,7 +486,7 @@
 {
     SurfaceCreation* creation(increment->mutable_surface_creation());
     creation->set_id(getLayerId(layer));
-    creation->set_name(getLayerName(layer));
+    creation->set_name(layer->getName());
     creation->set_w(layer->mCurrentState.active_legacy.w);
     creation->set_h(layer->mCurrentState.active_legacy.h);
 }
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 6858c4d..72b734b 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -123,7 +123,6 @@
 
     status_t writeProtoFileLocked();
     const sp<const Layer> getLayer(const wp<const IBinder>& weakHandle) const;
-    const std::string getLayerName(const sp<const Layer>& layer) const;
     int32_t getLayerId(const sp<const Layer>& layer) const;
     int32_t getLayerIdFromWeakRef(const wp<const Layer>& layer) const;
     int32_t getLayerIdFromHandle(const sp<const IBinder>& weakHandle) const;
diff --git a/services/surfaceflinger/TimeStats/OWNERS b/services/surfaceflinger/TimeStats/OWNERS
index ac02d12..1441f91 100644
--- a/services/surfaceflinger/TimeStats/OWNERS
+++ b/services/surfaceflinger/TimeStats/OWNERS
@@ -1 +1,2 @@
-zzyiwei@google.com
\ No newline at end of file
+alecmouri@google.com
+zzyiwei@google.com
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 3df8360..3e47ec6 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -28,7 +28,6 @@
 #include <utils/Trace.h>
 
 #include <algorithm>
-#include <regex>
 
 namespace android {
 
@@ -156,22 +155,6 @@
     return static_cast<int32_t>(delta);
 }
 
-// This regular expression captures the following for instance:
-// StatusBar in StatusBar#0
-// com.appname in com.appname/com.appname.activity#0
-// com.appname in SurfaceView - com.appname/com.appname.activity#0
-static const std::regex packageNameRegex("(?:SurfaceView[-\\s\\t]+)?([^/]+).*#\\d+");
-
-static std::string getPackageName(const std::string& layerName) {
-    std::smatch match;
-    if (std::regex_match(layerName.begin(), layerName.end(), match, packageNameRegex)) {
-        // There must be a match for group 1 otherwise the whole string is not
-        // matched and the above will return false
-        return match[1];
-    }
-    return "";
-}
-
 void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerID) {
     ATRACE_CALL();
 
@@ -187,7 +170,6 @@
             const std::string& layerName = layerRecord.layerName;
             if (!mTimeStats.stats.count(layerName)) {
                 mTimeStats.stats[layerName].layerName = layerName;
-                mTimeStats.stats[layerName].packageName = getPackageName(layerName);
             }
             TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[layerName];
             timeStatsLayer.totalFrames++;
@@ -236,19 +218,13 @@
     }
 }
 
-// This regular expression captures the following layer names for instance:
-// 1) StatusBat#0
-// 2) NavigationBar#1
-// 3) co(m).*#0
-// 4) SurfaceView - co(m).*#0
-// Using [-\\s\t]+ for the conjunction part between SurfaceView and co(m).*
-// is a bit more robust in case there's a slight change.
-// The layer name would only consist of . / $ _ 0-9 a-z A-Z in most cases.
-static const std::regex layerNameRegex(
-        "(((SurfaceView[-\\s\\t]+)?com?\\.[./$\\w]+)|((Status|Navigation)Bar))#\\d+");
+static constexpr const char* kPopupWindowPrefix = "PopupWindow";
+static const size_t kMinLenLayerName = std::strlen(kPopupWindowPrefix);
 
+// Avoid tracking the "PopupWindow:<random hash>#<number>" layers
 static bool layerNameIsValid(const std::string& layerName) {
-    return std::regex_match(layerName.begin(), layerName.end(), layerNameRegex);
+    return layerName.length() >= kMinLenLayerName &&
+            layerName.compare(0, kMinLenLayerName, kPopupWindowPrefix) != 0;
 }
 
 void TimeStats::setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index 92e59d7..8db03db 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -234,7 +234,8 @@
     sp<IBinder> surfaceControl = handle->surfaceControl.promote();
     if (surfaceControl) {
         transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
-                                                    handle->previousReleaseFence);
+                                                    handle->previousReleaseFence,
+                                                    handle->transformHint);
     }
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index a85ad1e..12ea8fe 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -44,6 +44,7 @@
     sp<Fence> previousReleaseFence;
     nsecs_t acquireTime = -1;
     nsecs_t latchTime = -1;
+    uint32_t transformHint = 0;
 };
 
 class TransactionCompletedThread {
diff --git a/services/surfaceflinger/tests/RelativeZ_test.cpp b/services/surfaceflinger/tests/RelativeZ_test.cpp
index 8549db2..8c56d27 100644
--- a/services/surfaceflinger/tests/RelativeZ_test.cpp
+++ b/services/surfaceflinger/tests/RelativeZ_test.cpp
@@ -144,4 +144,63 @@
         sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
     }
 }
+
+TEST_F(RelativeZTest, LayerAndRelativeRemoved) {
+    std::unique_ptr<ScreenCapture> sc;
+
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    //   Child layer (BLUE) (relative to relativeToLayer layer)
+    //   Relative layer (WHITE)
+    sp<SurfaceControl> childLayer =
+            createColorLayer("Child layer", Color::BLUE, mForegroundLayer.get());
+    sp<SurfaceControl> relativeToLayer =
+            createColorLayer("Relative layer", Color::WHITE, mForegroundLayer.get());
+
+    Transaction{}
+            .setRelativeLayer(childLayer, relativeToLayer->getHandle(), 1)
+            .show(childLayer)
+            .show(relativeToLayer)
+            .apply();
+
+    {
+        // The childLayer should be in front of relativeToLayer.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(1, 1, Color::BLUE.r, Color::BLUE.g, Color::BLUE.b);
+    }
+
+    // Remove layer that childLayer is relative to
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    //   Child layer (BLUE) (relative to relativeToLayer layer)
+    Transaction{}.reparent(relativeToLayer, nullptr).apply();
+    relativeToLayer = 0;
+
+    {
+        // The child layer is relative to an deleted layer so it won't be drawn.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+    }
+
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    Transaction{}.reparent(childLayer, nullptr).apply();
+
+    {
+        // The child layer is offscreen, so it won't be drawn.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+    }
+
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    //   Child layer (BLUE)
+    Transaction{}.reparent(childLayer, mForegroundLayer->getHandle()).apply();
+
+    {
+        // The relative z info for child layer should be reset, leaving the child layer on top.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(1, 1, Color::BLUE.r, Color::BLUE.g, Color::BLUE.b);
+    }
+}
 } // namespace android
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index c949d7c..67faa57 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -127,7 +127,6 @@
 public:
     class MockComposerClient : public FakeComposerClient {
     public:
-        MOCK_METHOD2(getDisplayType, Error(Display display, ComposerClient::DisplayType* outType));
         MOCK_METHOD4(getDisplayAttribute,
                      Error(Display display, Config config, IComposerClient::Attribute attribute,
                            int32_t* outValue));
@@ -176,9 +175,6 @@
     android::hardware::ProcessState::self()->startThreadPool();
     android::ProcessState::self()->startThreadPool();
 
-    EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
-            .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
-                            Return(Error::NONE)));
     // Primary display will be queried twice for all 5 attributes. One
     // set of queries comes from the SurfaceFlinger proper an the
     // other set from the VR composer.
@@ -270,10 +266,6 @@
 TEST_F(DisplayTest, Hotplug) {
     ALOGD("DisplayTest::Hotplug");
 
-    EXPECT_CALL(*mMockComposer, getDisplayType(EXTERNAL_DISPLAY, _))
-            .Times(2)
-            .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
-                                  Return(Error::NONE)));
     // The attribute queries will get done twice. This is for defaults
     EXPECT_CALL(*mMockComposer, getDisplayAttribute(EXTERNAL_DISPLAY, 1, _, _))
             .Times(2 * 3)
@@ -381,10 +373,6 @@
 
     mMockComposer->clearFrames();
 
-    EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
-            .Times(2)
-            .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
-                                  Return(Error::NONE)));
     // The attribute queries will get done twice. This is for defaults
     EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _))
             .Times(2 * 3)
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 8d98af6..f85da20 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -52,11 +52,11 @@
         "RegionSamplingTest.cpp",
         "TimeStatsTest.cpp",
         "FrameTracerTest.cpp",
+        "TransactionApplicationTest.cpp",
+        "StrongTypingTest.cpp",
         "mock/DisplayHardware/MockComposer.cpp",
         "mock/DisplayHardware/MockDisplay.cpp",
         "mock/DisplayHardware/MockPowerAdvisor.cpp",
-        "mock/gui/MockGraphicBufferConsumer.cpp",
-        "mock/gui/MockGraphicBufferProducer.cpp",
         "mock/MockDispSync.cpp",
         "mock/MockEventControlThread.cpp",
         "mock/MockEventThread.cpp",
@@ -71,6 +71,7 @@
         "libgmock",
         "libcompositionengine",
         "libcompositionengine_mocks",
+        "libgui_mocks",
         "libperfetto_client_experimental",
         "librenderengine_mocks",
         "libtimestats",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index b6fa2a6..60da70f 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -839,7 +839,7 @@
     static FlingerLayerType createLayer(CompositionTest* test) {
         FlingerLayerType layer = Base::template createLayerWithFactory<ColorLayer>(test, [test]() {
             return new ColorLayer(LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(),
-                                                    String8("test-layer"), LayerProperties::WIDTH,
+                                                    "test-layer", LayerProperties::WIDTH,
                                                     LayerProperties::HEIGHT,
                                                     LayerProperties::LAYER_FLAGS, LayerMetadata()));
         });
@@ -879,11 +879,9 @@
         FlingerLayerType layer =
                 Base::template createLayerWithFactory<BufferQueueLayer>(test, [test]() {
                     sp<Client> client;
-                    String8 name("test-layer");
-                    LayerCreationArgs args =
-                            LayerCreationArgs(test->mFlinger.mFlinger.get(), client, name,
-                                              LayerProperties::WIDTH, LayerProperties::HEIGHT,
-                                              LayerProperties::LAYER_FLAGS, LayerMetadata());
+                    LayerCreationArgs args(test->mFlinger.mFlinger.get(), client, "test-layer",
+                                           LayerProperties::WIDTH, LayerProperties::HEIGHT,
+                                           LayerProperties::LAYER_FLAGS, LayerMetadata());
                     args.textureName = test->mFlinger.mutableTexturePool().back();
                     return new BufferQueueLayer(args);
                 });
@@ -1039,6 +1037,26 @@
     static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
 };
 
+struct ForcedClientCompositionViaDebugOptionResultVariant : public CompositionResultBaseVariant {
+    static void setupLayerState(CompositionTest* test, sp<Layer>) {
+        test->mFlinger.mutableDebugDisableHWC() = true;
+    }
+
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest* test) {
+        Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+        Case::Display::setupHwcForcedClientCompositionCallExpectations(test);
+        Case::Display::setupRECompositionCallExpectations(test);
+        Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
+    }
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
+};
+
 struct EmptyScreenshotResultVariant {
     static void setupLayerState(CompositionTest*, sp<Layer>) {}
 
@@ -1350,5 +1368,23 @@
             NoCompositionTypeVariant, REScreenshotResultVariant>>();
 }
 
+/* ------------------------------------------------------------------------
+ *  Client composition forced through debug/developer settings
+ */
+
+TEST_F(CompositionTest, DebugOptionForcingClientCompositionOfBufferLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+                            ForcedClientCompositionViaDebugOptionResultVariant>>();
+}
+
+TEST_F(CompositionTest, DebugOptionForcingClientCompositionOfBufferLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+                            ForcedClientCompositionViaDebugOptionResultVariant>>();
+}
+
 } // namespace
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index fcce57b..b1a4951 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -24,6 +24,8 @@
 #include <compositionengine/mock/DisplaySurface.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <gui/mock/GraphicBufferConsumer.h>
+#include <gui/mock/GraphicBufferProducer.h>
 #include <log/log.h>
 #include <renderengine/mock/RenderEngine.h>
 #include <ui/DebugUtils.h>
@@ -38,8 +40,6 @@
 #include "mock/MockMessageQueue.h"
 #include "mock/MockNativeWindowSurface.h"
 #include "mock/MockSurfaceInterceptor.h"
-#include "mock/gui/MockGraphicBufferConsumer.h"
-#include "mock/gui/MockGraphicBufferProducer.h"
 #include "mock/system/window/MockNativeWindow.h"
 
 namespace android {
@@ -445,10 +445,6 @@
     }
 
     static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getDisplayType(HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(static_cast<IComposerClient::DisplayType>(
-                                        HWC_DISPLAY_TYPE)),
-                                Return(Error::NONE)));
         EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
         EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
                 .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 8e7440c..9a962bc 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -1,140 +1,243 @@
 #undef LOG_TAG
-#define LOG_TAG "LayerHistoryUnittests"
+#define LOG_TAG "LayerHistoryTest"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-
 #include <log/log.h>
 
-#include <mutex>
-#include <thread>
-
 #include "Scheduler/LayerHistory.h"
+#include "Scheduler/LayerInfo.h"
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/MockLayer.h"
 
 using testing::_;
 using testing::Return;
 
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
 
 class LayerHistoryTest : public testing::Test {
-public:
-    LayerHistoryTest();
-    ~LayerHistoryTest() override;
-
 protected:
-    std::unique_ptr<LayerHistory> mLayerHistory;
+    static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfo::PresentTimeHistory::HISTORY_SIZE;
+    static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfo::MAX_FREQUENT_LAYER_PERIOD_NS;
 
-    static constexpr float MIN_REFRESH_RATE = 30.f;
-    static constexpr float MAX_REFRESH_RATE = 90.f;
-    static constexpr auto RELEVANT_FRAME_THRESHOLD = 90u;
-    static constexpr uint64_t THIRTY_FPS_INTERVAL = 33'333'333;
+    static constexpr float LO_FPS = 30.f;
+    static constexpr nsecs_t LO_FPS_PERIOD = 33'333'333;
 
-    void forceRelevancy(const std::unique_ptr<LayerHistory::LayerHandle>& testLayer) {
-        mLayerHistory->setVisibility(testLayer, true);
-        for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) {
-            mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
-        }
-    };
-};
+    static constexpr float HI_FPS = 90.f;
+    static constexpr nsecs_t HI_FPS_PERIOD = 11'111'111;
 
-LayerHistoryTest::LayerHistoryTest() {
-    mLayerHistory = std::make_unique<LayerHistory>();
-}
-LayerHistoryTest::~LayerHistoryTest() {}
+    LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); }
 
-namespace {
-TEST_F(LayerHistoryTest, oneLayer) {
-    std::unique_ptr<LayerHistory::LayerHandle> testLayer =
-            mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
-    mLayerHistory->setVisibility(testLayer, true);
-    for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) {
-        EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
-        mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+    LayerHistory& history() { return mScheduler->mutableLayerHistory(); }
+    const LayerHistory& history() const { return mScheduler->mutableLayerHistory(); }
+
+    size_t layerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mLayerInfos.size(); }
+    size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; }
+
+    size_t frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
+        const auto& infos = history().mLayerInfos;
+        return std::count_if(infos.begin(), infos.begin() + history().mActiveLayersEnd,
+                             [now](const auto& pair) { return pair.second->isFrequent(now); });
     }
 
-    // Add a few more. This time we should get MAX refresh rate as the layer
-    // becomes relevant
-    static constexpr auto A_FEW = 10;
-    for (auto i = 0u; i < A_FEW; i++) {
-        EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
-        mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+    auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); }
+
+    RefreshRateConfigs mConfigs{true,
+                                {RefreshRateConfigs::InputConfig{0, LO_FPS_PERIOD},
+                                 RefreshRateConfigs::InputConfig{1, HI_FPS_PERIOD}},
+                                0};
+    TestableScheduler* const mScheduler{new TestableScheduler(mConfigs)};
+    TestableSurfaceFlinger mFlinger;
+
+    const nsecs_t mTime = systemTime();
+};
+
+namespace {
+
+TEST_F(LayerHistoryTest, oneLayer) {
+    const auto layer = createLayer();
+    constexpr bool isHDR = false;
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    // 0 FPS is returned if no layers are active.
+    EXPECT_FLOAT_EQ(0, history().summarize(mTime).maxRefreshRate);
+    EXPECT_EQ(0, activeLayerCount());
+
+    // 0 FPS is returned if active layers have insufficient history.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+        history().record(layer.get(), 0, isHDR, mTime);
+        EXPECT_FLOAT_EQ(0, history().summarize(mTime).maxRefreshRate);
+        EXPECT_EQ(1, activeLayerCount());
+    }
+
+    // High FPS is returned once enough history has been recorded.
+    for (int i = 0; i < 10; i++) {
+        history().record(layer.get(), 0, isHDR, mTime);
+        EXPECT_FLOAT_EQ(HI_FPS, history().summarize(mTime).maxRefreshRate);
+        EXPECT_EQ(1, activeLayerCount());
     }
 }
 
 TEST_F(LayerHistoryTest, oneHDRLayer) {
-    std::unique_ptr<LayerHistory::LayerHandle> testLayer =
-            mLayerHistory->createLayer("TestHDRLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
-    mLayerHistory->setVisibility(testLayer, true);
+    const auto layer = createLayer();
+    constexpr bool isHDR = true;
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
 
-    mLayerHistory->insert(testLayer, 0, true /*isHDR*/);
-    EXPECT_FLOAT_EQ(0.0f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
-    EXPECT_EQ(true, mLayerHistory->getDesiredRefreshRateAndHDR().second);
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
 
-    mLayerHistory->setVisibility(testLayer, false);
-    EXPECT_FLOAT_EQ(0.0f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
-    EXPECT_EQ(false, mLayerHistory->getDesiredRefreshRateAndHDR().second);
+    history().record(layer.get(), 0, isHDR, mTime);
+    auto summary = history().summarize(mTime);
+    EXPECT_FLOAT_EQ(0, summary.maxRefreshRate);
+    EXPECT_TRUE(summary.isHDR);
+    EXPECT_EQ(1, activeLayerCount());
+
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
+
+    summary = history().summarize(mTime);
+    EXPECT_FLOAT_EQ(0, summary.maxRefreshRate);
+    EXPECT_FALSE(summary.isHDR);
+    EXPECT_EQ(0, activeLayerCount());
 }
 
 TEST_F(LayerHistoryTest, explicitTimestamp) {
-    std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
-            mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
-    mLayerHistory->setVisibility(test30FpsLayer, true);
+    const auto layer = createLayer();
+    constexpr bool isHDR = false;
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
 
-    nsecs_t startTime = systemTime();
-    for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
-        mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
-                              false /*isHDR*/);
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    nsecs_t time = mTime;
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer.get(), time, isHDR, time);
+        time += LO_FPS_PERIOD;
     }
 
-    EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(mTime).maxRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
 }
 
 TEST_F(LayerHistoryTest, multipleLayers) {
-    std::unique_ptr<LayerHistory::LayerHandle> testLayer =
-            mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
-    mLayerHistory->setVisibility(testLayer, true);
-    std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
-            mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
-    mLayerHistory->setVisibility(test30FpsLayer, true);
-    std::unique_ptr<LayerHistory::LayerHandle> testLayer2 =
-            mLayerHistory->createLayer("TestLayer2", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
-    mLayerHistory->setVisibility(testLayer2, true);
+    auto layer1 = createLayer();
+    auto layer2 = createLayer();
+    auto layer3 = createLayer();
+    constexpr bool isHDR = false;
 
-    nsecs_t startTime = systemTime();
-    for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
-        mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+    EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
+
+    nsecs_t time = mTime;
+
+    EXPECT_EQ(3, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+
+    // layer1 is active but infrequent.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer1.get(), time, isHDR, time);
+        time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
     }
-    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
 
-    startTime = systemTime();
-    for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
-        mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
-                              false /*isHDR*/);
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time).maxRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+
+    // layer2 is frequent and has high refresh rate.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer2.get(), time, isHDR, time);
+        time += HI_FPS_PERIOD;
     }
-    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
 
-    for (int i = 10; i < RELEVANT_FRAME_THRESHOLD; i++) {
-        mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
-                              false /*isHDR*/);
+    // layer1 is still active but infrequent.
+    history().record(layer1.get(), time, isHDR, time);
+
+    EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate);
+    EXPECT_EQ(2, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer1 is no longer active.
+    // layer2 is frequent and has low refresh rate.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer2.get(), time, isHDR, time);
+        time += LO_FPS_PERIOD;
     }
-    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
 
-    // This frame is only around for 9 occurrences, so it doesn't throw
-    // anything off.
-    for (int i = 0; i < 9; i++) {
-        mLayerHistory->insert(testLayer2, 0, false /*isHDR*/);
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time).maxRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer2 still has low refresh rate.
+    // layer3 has high refresh rate but not enough history.
+    constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD;
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+        if (i % RATIO == 0) {
+            history().record(layer2.get(), time, isHDR, time);
+        }
+
+        history().record(layer3.get(), time, isHDR, time);
+        time += HI_FPS_PERIOD;
     }
-    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
-    // After 1200 ms frames become obsolete.
-    std::this_thread::sleep_for(std::chrono::milliseconds(1500));
 
-    mLayerHistory->insert(test30FpsLayer,
-                          startTime + (RELEVANT_FRAME_THRESHOLD * THIRTY_FPS_INTERVAL),
-                          false /*isHDR*/);
-    EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time).maxRefreshRate);
+    EXPECT_EQ(2, activeLayerCount());
+    EXPECT_EQ(2, frequentLayerCount(time));
+
+    // layer3 becomes recently active.
+    history().record(layer3.get(), time, isHDR, time);
+    EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate);
+    EXPECT_EQ(2, activeLayerCount());
+    EXPECT_EQ(2, frequentLayerCount(time));
+
+    // layer1 expires.
+    layer1.clear();
+    EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate);
+    EXPECT_EQ(2, layerCount());
+    EXPECT_EQ(2, activeLayerCount());
+    EXPECT_EQ(2, frequentLayerCount(time));
+
+    // layer2 still has low refresh rate.
+    // layer3 becomes inactive.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer2.get(), time, isHDR, time);
+        time += LO_FPS_PERIOD;
+    }
+
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time).maxRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer2 expires.
+    layer2.clear();
+    EXPECT_FLOAT_EQ(0, history().summarize(time).maxRefreshRate);
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+
+    // layer3 becomes active and has high refresh rate.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer3.get(), time, isHDR, time);
+        time += HI_FPS_PERIOD;
+    }
+
+    EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate);
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer3 expires.
+    layer3.clear();
+    EXPECT_FLOAT_EQ(0, history().summarize(time).maxRefreshRate);
+    EXPECT_EQ(0, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
 }
 
 } // namespace
-} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
index 160f041..d8de804 100644
--- a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
@@ -69,16 +69,16 @@
         n++;
         return pixel;
     });
+
     EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
-                testing::FloatNear(0.083f, 0.01f));
+                testing::FloatNear(0.16f, 0.01f));
 }
 
 TEST_F(RegionSamplingTest, bimodal_tiebreaker) {
     std::generate(buffer.begin(), buffer.end(),
                   [n = 0]() mutable { return (n++ % 2) ? kBlack : kWhite; });
-    // presently there's no tiebreaking strategy in place, accept either of the means
     EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
-                testing::AnyOf(testing::FloatEq(1.0), testing::FloatEq(0.0f)));
+                testing::FloatEq(0.5f));
 }
 
 TEST_F(RegionSamplingTest, bounds_checking) {
diff --git a/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp
new file mode 100644
index 0000000..b9ddcd7
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include "Scheduler/StrongTyping.h"
+
+using namespace testing;
+
+namespace android {
+
+TEST(StrongTypeTest, comparison) {
+    using SpunkyType = StrongTyping<int, struct SpunkyTypeTag, Compare>;
+    SpunkyType f2(22);
+    SpunkyType f1(10);
+
+    EXPECT_TRUE(f1 == f1);
+    EXPECT_TRUE(SpunkyType(10) != SpunkyType(11));
+    EXPECT_FALSE(SpunkyType(31) != SpunkyType(31));
+
+    EXPECT_TRUE(SpunkyType(10) < SpunkyType(11));
+    EXPECT_TRUE(SpunkyType(-1) < SpunkyType(0));
+    EXPECT_FALSE(SpunkyType(-10) < SpunkyType(-20));
+
+    EXPECT_TRUE(SpunkyType(10) <= SpunkyType(11));
+    EXPECT_TRUE(SpunkyType(10) <= SpunkyType(10));
+    EXPECT_TRUE(SpunkyType(-10) <= SpunkyType(1));
+    EXPECT_FALSE(SpunkyType(10) <= SpunkyType(9));
+
+    EXPECT_TRUE(SpunkyType(11) >= SpunkyType(11));
+    EXPECT_TRUE(SpunkyType(12) >= SpunkyType(11));
+    EXPECT_FALSE(SpunkyType(11) >= SpunkyType(12));
+
+    EXPECT_FALSE(SpunkyType(11) > SpunkyType(12));
+    EXPECT_TRUE(SpunkyType(-11) < SpunkyType(7));
+}
+
+TEST(StrongTypeTest, addition) {
+    using FunkyType = StrongTyping<int, struct FunkyTypeTag, Compare, Add>;
+    FunkyType f2(22);
+    FunkyType f1(10);
+
+    EXPECT_THAT(f1 + f2, Eq(FunkyType(32)));
+    EXPECT_THAT(f2 + f1, Eq(FunkyType(32)));
+
+    EXPECT_THAT(++f1, Eq(11));
+    EXPECT_THAT(f1, Eq(11));
+    EXPECT_THAT(f1++, Eq(11));
+    EXPECT_THAT(f1++, Eq(12));
+    EXPECT_THAT(f1, Eq(13));
+
+    auto f3 = f1;
+    EXPECT_THAT(f1, Eq(f3));
+    EXPECT_THAT(f1, Lt(f2));
+
+    f3 += f1;
+    EXPECT_THAT(f1, Eq(13));
+    EXPECT_THAT(f3, Eq(26));
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index ae72467..ae6aa89 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -48,6 +48,7 @@
     auto& mutableEventControlThread() { return mEventControlThread; }
     auto& mutablePrimaryDispSync() { return mPrimaryDispSync; }
     auto& mutableHWVsyncAvailable() { return mHWVsyncAvailable; }
+    auto& mutableLayerHistory() { return mLayerHistory; }
 
     ~TestableScheduler() {
         // All these pointer and container clears help ensure that GMock does
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index b77f82a..94fc5f7 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -22,6 +22,7 @@
 #include <compositionengine/OutputLayer.h>
 #include <compositionengine/impl/CompositionEngine.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <compositionengine/mock/DisplaySurface.h>
 
 #include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
@@ -35,7 +36,7 @@
 #include "Scheduler/RefreshRateConfigs.h"
 #include "StartPropertySetThread.h"
 #include "SurfaceFlinger.h"
-#include "SurfaceFlingerFactory.h"
+#include "SurfaceFlingerDefaultFactory.h"
 #include "SurfaceInterceptor.h"
 #include "TestableScheduler.h"
 
@@ -62,23 +63,19 @@
     ~Factory() = default;
 
     std::unique_ptr<DispSync> createDispSync(const char*, bool) override {
-        // TODO: Use test-fixture controlled factory
         return nullptr;
     }
 
     std::unique_ptr<EventControlThread> createEventControlThread(
             std::function<void(bool)>) override {
-        // TODO: Use test-fixture controlled factory
         return nullptr;
     }
 
     std::unique_ptr<HWComposer> createHWComposer(const std::string&) override {
-        // TODO: Use test-fixture controlled factory
         return nullptr;
     }
 
     std::unique_ptr<MessageQueue> createMessageQueue() override {
-        // TODO: Use test-fixture controlled factory
         return std::make_unique<android::impl::MessageQueue>();
     }
 
@@ -88,39 +85,49 @@
 
     std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>,
                                                const scheduler::RefreshRateConfigs&) override {
-        // TODO: Use test-fixture controlled factory
         return nullptr;
     }
 
     std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger* flinger) override {
-        // TODO: Use test-fixture controlled factory
         return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
     }
 
     sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
-        // TODO: Use test-fixture controlled factory
         return new StartPropertySetThread(timestampPropertyValue);
     }
 
     sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) override {
-        // TODO: Use test-fixture controlled factory
         return new DisplayDevice(std::move(creationArgs));
     }
 
     sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
                                           uint32_t layerCount, uint64_t usage,
                                           std::string requestorName) override {
-        // TODO: Use test-fixture controlled factory
         return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
     }
 
     void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
                            sp<IGraphicBufferConsumer>* outConsumer,
                            bool consumerIsSurfaceFlinger) override {
-        if (!mCreateBufferQueue) return;
+        if (!mCreateBufferQueue) {
+            BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
+            return;
+        }
         mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
     }
 
+    sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>& producer,
+                                                       const sp<SurfaceFlinger>& flinger,
+                                                       const wp<Layer>& layer) override {
+        return new MonitoredProducer(producer, flinger, layer);
+    }
+
+    sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>& consumer,
+                                                      renderengine::RenderEngine& renderEngine,
+                                                      uint32_t textureName, Layer* layer) override {
+        return new BufferLayerConsumer(consumer, renderEngine, textureName, layer);
+    }
+
     std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
             const sp<IGraphicBufferProducer>& producer) override {
         if (!mCreateNativeWindowSurface) return nullptr;
@@ -132,22 +139,18 @@
     }
 
     sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
-        // TODO: Use test-fixture controlled factory
         return nullptr;
     }
 
     sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs&) override {
-        // TODO: Use test-fixture controlled factory
         return nullptr;
     }
 
     sp<ColorLayer> createColorLayer(const LayerCreationArgs&) override {
-        // TODO: Use test-fixture controlled factory
         return nullptr;
     }
 
     sp<ContainerLayer> createContainerLayer(const LayerCreationArgs&) override {
-        // TODO: Use test-fixture controlled factory
         return nullptr;
     }
 
@@ -171,6 +174,7 @@
 
 class TestableSurfaceFlinger {
 public:
+    SurfaceFlinger* flinger() { return mFlinger.get(); }
     TestableScheduler* scheduler() { return mScheduler; }
 
     // Extend this as needed for accessing SurfaceFlinger private (and public)
@@ -205,13 +209,15 @@
 
         mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
         mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
+        resetScheduler(mScheduler);
 
-        mFlinger->mScheduler.reset(mScheduler);
         mFlinger->mVSyncModulator.emplace(*mScheduler, mFlinger->mAppConnectionHandle,
                                           mFlinger->mSfConnectionHandle,
                                           mFlinger->mPhaseOffsets->getCurrentOffsets());
     }
 
+    void resetScheduler(Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); }
+
     using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
     void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
         mFactory.mCreateBufferQueue = f;
@@ -232,6 +238,8 @@
     auto& mutableLayerCurrentState(sp<Layer> layer) { return layer->mCurrentState; }
     auto& mutableLayerDrawingState(sp<Layer> layer) { return layer->mDrawingState; }
 
+    auto& mutableStateLock() { return mFlinger->mStateLock; }
+
     void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
         layer->mDrawingState.sidebandStream = sidebandStream;
         layer->mSidebandStream = sidebandStream;
@@ -320,6 +328,22 @@
         return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
     }
 
+    auto& getTransactionQueue() { return mFlinger->mTransactionQueues; }
+
+    auto setTransactionState(const Vector<ComposerState>& states,
+                             const Vector<DisplayState>& displays, uint32_t flags,
+                             const sp<IBinder>& applyToken,
+                             const InputWindowCommands& inputWindowCommands,
+                             int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
+                             bool hasListenerCallbacks,
+                             std::vector<ListenerCallbacks>& listenerCallbacks) {
+        return mFlinger->setTransactionState(states, displays, flags, applyToken,
+                                             inputWindowCommands, desiredPresentTime, uncacheBuffer,
+                                             hasListenerCallbacks, listenerCallbacks);
+    }
+
+    auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); };
+
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */
@@ -356,6 +380,7 @@
     auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
     auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
     auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
+    auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
 
     auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; }
     auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index dee2cae..4eb9ec3 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -171,7 +171,7 @@
 }
 
 static std::string genLayerName(int32_t layerID) {
-    return (layerID < 0 ? "invalid.dummy" : "com.dummy#") + std::to_string(layerID);
+    return (layerID < 0 ? "PopupWindow:b54fcd1#0" : "com.dummy#") + std::to_string(layerID);
 }
 
 void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts) {
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
new file mode 100644
index 0000000..a465388
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "CompositionTest"
+
+#include <compositionengine/Display.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/SurfaceComposerClient.h>
+#include <log/log.h>
+#include <utils/String8.h>
+
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+
+namespace android {
+
+using testing::_;
+using testing::Return;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+class TransactionApplicationTest : public testing::Test {
+public:
+    TransactionApplicationTest() {
+        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.mutableEventQueue().reset(mMessageQueue);
+        setupScheduler();
+    }
+
+    ~TransactionApplicationTest() {
+        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 setupScheduler() {
+        auto eventThread = std::make_unique<mock::EventThread>();
+        auto sfEventThread = std::make_unique<mock::EventThread>();
+
+        EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*eventThread, createEventConnection(_, _))
+                .WillOnce(Return(
+                        new EventThreadConnection(eventThread.get(), ResyncCallback(),
+                                                  ISurfaceComposer::eConfigChangedSuppress)));
+
+        EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+                .WillOnce(Return(
+                        new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+                                                  ISurfaceComposer::eConfigChangedSuppress)));
+
+        EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
+        EXPECT_CALL(*mPrimaryDispSync, getPeriod())
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+
+        mFlinger.setupScheduler(std::unique_ptr<mock::DispSync>(mPrimaryDispSync),
+                                std::make_unique<mock::EventControlThread>(),
+                                std::move(eventThread), std::move(sfEventThread));
+    }
+
+    TestableScheduler* mScheduler;
+    TestableSurfaceFlinger mFlinger;
+
+    std::unique_ptr<mock::EventThread> mEventThread = std::make_unique<mock::EventThread>();
+    mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
+
+    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+    mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+
+    struct TransactionInfo {
+        Vector<ComposerState> states;
+        Vector<DisplayState> displays;
+        uint32_t flags = 0;
+        sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+        InputWindowCommands inputWindowCommands;
+        int64_t desiredPresentTime = -1;
+        client_cache_t uncacheBuffer;
+    };
+
+    void checkEqual(TransactionInfo info, SurfaceFlinger::TransactionState state) {
+        EXPECT_EQ(0, info.states.size());
+        EXPECT_EQ(0, state.states.size());
+
+        EXPECT_EQ(0, info.displays.size());
+        EXPECT_EQ(0, state.displays.size());
+        EXPECT_EQ(info.flags, state.flags);
+        EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime);
+    }
+
+    void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows,
+                     int64_t desiredPresentTime) {
+        mTransactionNumber++;
+        transaction.flags |= flags; // ISurfaceComposer::eSynchronous;
+        transaction.inputWindowCommands.syncInputWindows = syncInputWindows;
+        transaction.desiredPresentTime = desiredPresentTime;
+    }
+
+    void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
+        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+        // called in SurfaceFlinger::signalTransaction
+        EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+        EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillOnce(Return(systemTime()));
+        TransactionInfo transaction;
+        setupSingle(transaction, flags, syncInputWindows,
+                    /*desiredPresentTime*/ -1);
+        nsecs_t applicationTime = systemTime();
+        mFlinger.setTransactionState(transaction.states, transaction.displays, transaction.flags,
+                                     transaction.applyToken, transaction.inputWindowCommands,
+                                     transaction.desiredPresentTime, transaction.uncacheBuffer,
+                                     mHasListenerCallbacks, mCallbacks);
+
+        // This transaction should not have been placed on the transaction queue.
+        // If transaction is synchronous or syncs input windows, SF
+        // applyTransactionState should time out (5s) wating for SF to commit
+        // the transaction or to receive a signal that syncInputWindows has
+        // completed.  If this is animation, it should not time out waiting.
+        nsecs_t returnedTime = systemTime();
+        if (flags & ISurfaceComposer::eSynchronous || syncInputWindows) {
+            EXPECT_GE(returnedTime, applicationTime + s2ns(5));
+        } else {
+            EXPECT_LE(returnedTime, applicationTime + s2ns(5));
+        }
+        auto transactionQueue = mFlinger.getTransactionQueue();
+        EXPECT_EQ(0, transactionQueue.size());
+    }
+
+    void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
+        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+        // called in SurfaceFlinger::signalTransaction
+        EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+        // first check will see desired present time has not passed,
+        // but afterwards it will look like the desired present time has passed
+        nsecs_t time = systemTime();
+        EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime())
+                .WillOnce(Return(time + nsecs_t(5 * 1e8)));
+        TransactionInfo transaction;
+        setupSingle(transaction, flags, syncInputWindows,
+                    /*desiredPresentTime*/ time + s2ns(1));
+        nsecs_t applicationSentTime = systemTime();
+        mFlinger.setTransactionState(transaction.states, transaction.displays, transaction.flags,
+                                     transaction.applyToken, transaction.inputWindowCommands,
+                                     transaction.desiredPresentTime, transaction.uncacheBuffer,
+                                     mHasListenerCallbacks, mCallbacks);
+
+        nsecs_t returnedTime = systemTime();
+        EXPECT_LE(returnedTime, applicationSentTime + s2ns(5));
+        // This transaction should have been placed on the transaction queue
+        auto transactionQueue = mFlinger.getTransactionQueue();
+        EXPECT_EQ(1, transactionQueue.size());
+    }
+
+    void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
+        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+        // called in SurfaceFlinger::signalTransaction
+        nsecs_t time = systemTime();
+        EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+        EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime())
+                .WillOnce(Return(time + nsecs_t(5 * 1e8)));
+        // transaction that should go on the pending thread
+        TransactionInfo transactionA;
+        setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
+                    /*desiredPresentTime*/ time + s2ns(1));
+
+        // transaction that would not have gone on the pending thread if not
+        // blocked
+        TransactionInfo transactionB;
+        setupSingle(transactionB, flags, syncInputWindows,
+                    /*desiredPresentTime*/ -1);
+
+        nsecs_t applicationSentTime = systemTime();
+        mFlinger.setTransactionState(transactionA.states, transactionA.displays, transactionA.flags,
+                                     transactionA.applyToken, transactionA.inputWindowCommands,
+                                     transactionA.desiredPresentTime, transactionA.uncacheBuffer,
+                                     mHasListenerCallbacks, mCallbacks);
+
+        // This thread should not have been blocked by the above transaction
+        // (5s is the timeout period that applyTransactionState waits for SF to
+        // commit the transaction)
+        EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
+
+        applicationSentTime = systemTime();
+        mFlinger.setTransactionState(transactionB.states, transactionB.displays, transactionB.flags,
+                                     transactionB.applyToken, transactionB.inputWindowCommands,
+                                     transactionB.desiredPresentTime, transactionB.uncacheBuffer,
+                                     mHasListenerCallbacks, mCallbacks);
+
+        // this thread should have been blocked by the above transaction
+        // if this is an animation, this thread should be blocked for 5s
+        // in setTransactionState waiting for transactionA to flush.  Otherwise,
+        // the transaction should be placed on the pending queue
+        if (flags & ISurfaceComposer::eAnimation) {
+            EXPECT_GE(systemTime(), applicationSentTime + s2ns(5));
+        } else {
+            EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
+        }
+
+        // check that there is one binder on the pending queue.
+        auto transactionQueue = mFlinger.getTransactionQueue();
+        EXPECT_EQ(1, transactionQueue.size());
+
+        auto& [applyToken, transactionStates] = *(transactionQueue.begin());
+        EXPECT_EQ(2, transactionStates.size());
+
+        auto& transactionStateA = transactionStates.front();
+        transactionStates.pop();
+        checkEqual(transactionA, transactionStateA);
+        auto& transactionStateB = transactionStates.front();
+        checkEqual(transactionB, transactionStateB);
+    }
+
+    bool mHasListenerCallbacks = false;
+    std::vector<ListenerCallbacks> mCallbacks;
+    int mTransactionNumber = 0;
+};
+
+TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
+    ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+    // called in SurfaceFlinger::signalTransaction
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    // nsecs_t time = systemTime();
+    EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime())
+            .WillOnce(Return(nsecs_t(5 * 1e8)))
+            .WillOnce(Return(s2ns(2)));
+    TransactionInfo transactionA; // transaction to go on pending queue
+    setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
+                /*desiredPresentTime*/ s2ns(1));
+    mFlinger.setTransactionState(transactionA.states, transactionA.displays, transactionA.flags,
+                                 transactionA.applyToken, transactionA.inputWindowCommands,
+                                 transactionA.desiredPresentTime, transactionA.uncacheBuffer,
+                                 mHasListenerCallbacks, mCallbacks);
+
+    auto& transactionQueue = mFlinger.getTransactionQueue();
+    ASSERT_EQ(1, transactionQueue.size());
+
+    auto& [applyToken, transactionStates] = *(transactionQueue.begin());
+    ASSERT_EQ(1, transactionStates.size());
+
+    auto& transactionState = transactionStates.front();
+    checkEqual(transactionA, transactionState);
+
+    // because flushing uses the cached expected present time, we send an empty
+    // transaction here (sending a null applyToken to fake it as from a
+    // different process) to re-query and reset the cached expected present time
+    TransactionInfo empty;
+    empty.applyToken = sp<IBinder>();
+    mFlinger.setTransactionState(empty.states, empty.displays, empty.flags, empty.applyToken,
+                                 empty.inputWindowCommands, empty.desiredPresentTime,
+                                 empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks);
+
+    // flush transaction queue should flush as desiredPresentTime has
+    // passed
+    mFlinger.flushTransactionQueues();
+
+    EXPECT_EQ(0, transactionQueue.size());
+}
+
+TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) {
+    NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Animation) {
+    NotPlacedOnTransactionQueue(ISurfaceComposer::eAnimation, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_SyncInputWindows) {
+    NotPlacedOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true);
+}
+
+TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Synchronous) {
+    PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Animation) {
+    PlaceOnTransactionQueue(ISurfaceComposer::eAnimation, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_SyncInputWindows) {
+    PlaceOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true);
+}
+
+TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Synchronous) {
+    BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Animation) {
+    BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_SyncInputWindows) {
+    BlockedByPriorTransaction(/*flags*/ 0, /*syncInputWindows*/ true);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 3c7e1da..98c6aa0 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -41,7 +41,7 @@
 using android::hardware::graphics::composer::V2_1::IComposer;
 using android::hardware::graphics::composer::V2_1::IComposerCallback;
 using android::hardware::graphics::composer::V2_1::Layer;
-using android::hardware::graphics::composer::V2_3::IComposerClient;
+using android::hardware::graphics::composer::V2_4::IComposerClient;
 
 class Composer : public Hwc2::Composer {
 public:
@@ -71,7 +71,6 @@
     MOCK_METHOD2(getDisplayName, Error(Display, std::string*));
     MOCK_METHOD4(getDisplayRequests,
                  Error(Display, uint32_t*, std::vector<Layer>*, std::vector<uint32_t>*));
-    MOCK_METHOD2(getDisplayType, Error(Display, IComposerClient::DisplayType*));
     MOCK_METHOD2(getDozeSupport, Error(Display, bool*));
     MOCK_METHOD5(getHdrCapabilities, Error(Display, std::vector<Hdr>*, float*, float*, float*));
     MOCK_METHOD1(getPerFrameMetadataKeys,
@@ -118,10 +117,11 @@
     MOCK_METHOD4(setDisplayContentSamplingEnabled, Error(Display, bool, uint8_t, uint64_t));
     MOCK_METHOD4(getDisplayedContentSample,
                  Error(Display, uint64_t, uint64_t, DisplayedFrameStats*));
-    MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector<DisplayCapability>*));
     MOCK_METHOD3(setLayerPerFrameMetadataBlobs,
                  Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadataBlob>&));
     MOCK_METHOD2(setDisplayBrightness, Error(Display, float));
+    MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector<DisplayCapability>*));
+    MOCK_METHOD2(getDisplayConnectionType, Error(Display, IComposerClient::DisplayConnectionType*));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
new file mode 100644
index 0000000..f375e23
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "Layer.h"
+
+namespace android::mock {
+
+class MockLayer : public Layer {
+public:
+    explicit MockLayer(SurfaceFlinger* flinger)
+          : Layer(LayerCreationArgs(flinger, nullptr, "TestLayer", 800, 600, 0, {})) {}
+
+    MOCK_CONST_METHOD0(getType, const char*());
+    MOCK_CONST_METHOD0(isVisible, bool());
+    MOCK_METHOD0(createClone, sp<Layer>());
+};
+
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/utils/CallbackUtils.h b/services/surfaceflinger/tests/utils/CallbackUtils.h
index 51ae8c4..4e2b7c3 100644
--- a/services/surfaceflinger/tests/utils/CallbackUtils.h
+++ b/services/surfaceflinger/tests/utils/CallbackUtils.h
@@ -121,7 +121,8 @@
 
         void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
                                        nsecs_t latchTime) const {
-            const auto& [surfaceControl, acquireTime, previousReleaseFence] = surfaceControlStats;
+            const auto& [surfaceControl, acquireTime, previousReleaseFence, transformHint] =
+                    surfaceControlStats;
 
             ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
                     << "bad acquire time";
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 48f26e7..24039b1 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -519,7 +519,11 @@
       get_device_proc_addr_(nullptr),
       driver_extensions_(nullptr),
       driver_extension_count_(0) {
-    enabled_extensions_.set(driver::ProcHook::EXTENSION_CORE);
+    // advertise the loader supported core Vulkan API version at vulkan::api
+    for (uint32_t i = driver::ProcHook::EXTENSION_CORE_1_0;
+         i != driver::ProcHook::EXTENSION_COUNT; ++i) {
+        enabled_extensions_.set(i);
+    }
 }
 
 LayerChain::~LayerChain() {
@@ -1275,7 +1279,7 @@
         return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS;
     }
 
-    // TODO how about extensions from implicitly enabled layers?
+    // TODO(b/143293104): expose extensions from implicitly enabled layers
     return vulkan::driver::EnumerateInstanceExtensionProperties(
         nullptr, pPropertyCount, pProperties);
 }
@@ -1329,7 +1333,7 @@
         return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS;
     }
 
-    // TODO how about extensions from implicitly enabled layers?
+    // TODO(b/143293104): expose extensions from implicitly enabled layers
     const InstanceData& data = GetData(physicalDevice);
     return data.dispatch.EnumerateDeviceExtensionProperties(
         physicalDevice, nullptr, pPropertyCount, pProperties);
diff --git a/vulkan/libvulkan/debug_report.h b/vulkan/libvulkan/debug_report.h
index 3d8bd50..e5b1587 100644
--- a/vulkan/libvulkan/debug_report.h
+++ b/vulkan/libvulkan/debug_report.h
@@ -78,7 +78,7 @@
         VkDebugReportCallbackEXT driver_handle;
     };
 
-    // TODO(jessehall): replace with std::shared_mutex when available in libc++
+    // TODO(b/143295577): use std::shared_mutex when available in libc++
     mutable std::shared_timed_mutex rwmutex_;
     Node head_;
 };
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index b413ac9..d92f35a 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -37,7 +37,10 @@
 
 #include <algorithm>
 #include <array>
+#include <climits>
 #include <new>
+#include <string_view>
+#include <sstream>
 #include <vector>
 
 #include "stubhal.h"
@@ -99,6 +102,7 @@
 
     VkResult Validate();
     void DowngradeApiVersion();
+    void UpgradeDeviceCoreApiVersion(uint32_t api_version);
 
     const std::bitset<ProcHook::EXTENSION_COUNT>& GetHookExtensions() const;
     const std::bitset<ProcHook::EXTENSION_COUNT>& GetHalExtensions() const;
@@ -147,15 +151,12 @@
 Hal Hal::hal_;
 
 void* LoadLibrary(const android_dlextinfo& dlextinfo,
-                  const char* subname,
-                  int subname_len) {
+                  const std::string_view subname) {
     ATRACE_CALL();
 
-    const char kLibFormat[] = "vulkan.%*s.so";
-    char* name = static_cast<char*>(
-        alloca(sizeof(kLibFormat) + static_cast<size_t>(subname_len)));
-    sprintf(name, kLibFormat, subname_len, subname);
-    return android_dlopen_ext(name, RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+    std::stringstream ss;
+    ss << "vulkan." << subname << ".so";
+    return android_dlopen_ext(ss.str().c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
 }
 
 const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{
@@ -175,8 +176,9 @@
     char prop[PROPERTY_VALUE_MAX];
     for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
         int prop_len = property_get(key, prop, nullptr);
-        if (prop_len > 0) {
-            so = LoadLibrary(dlextinfo, prop, prop_len);
+        if (prop_len > 0 && prop_len <= UINT_MAX) {
+            std::string_view lib_name(prop, static_cast<unsigned int>(prop_len));
+            so = LoadLibrary(dlextinfo, lib_name);
             if (so)
                 break;
         }
@@ -328,8 +330,12 @@
       physical_dev_(VK_NULL_HANDLE),
       instance_info_(create_info),
       extension_filter_() {
-    hook_extensions_.set(ProcHook::EXTENSION_CORE);
-    hal_extensions_.set(ProcHook::EXTENSION_CORE);
+    // instance core versions need to match the loader api version
+    for (uint32_t i = ProcHook::EXTENSION_CORE_1_0;
+         i != ProcHook::EXTENSION_COUNT; ++i) {
+        hook_extensions_.set(i);
+        hal_extensions_.set(i);
+    }
 }
 
 CreateInfoWrapper::CreateInfoWrapper(VkPhysicalDevice physical_dev,
@@ -340,8 +346,9 @@
       physical_dev_(physical_dev),
       dev_info_(create_info),
       extension_filter_() {
-    hook_extensions_.set(ProcHook::EXTENSION_CORE);
-    hal_extensions_.set(ProcHook::EXTENSION_CORE);
+    // initialize with baseline core API version
+    hook_extensions_.set(ProcHook::EXTENSION_CORE_1_0);
+    hal_extensions_.set(ProcHook::EXTENSION_CORE_1_0);
 }
 
 CreateInfoWrapper::~CreateInfoWrapper() {
@@ -540,7 +547,8 @@
             case ProcHook::ANDROID_external_memory_android_hardware_buffer:
             case ProcHook::ANDROID_native_buffer:
             case ProcHook::GOOGLE_display_timing:
-            case ProcHook::EXTENSION_CORE:
+            case ProcHook::EXTENSION_CORE_1_0:
+            case ProcHook::EXTENSION_CORE_1_1:
             case ProcHook::EXTENSION_COUNT:
                 // Device and meta extensions. If we ever get here it's a bug in
                 // our code. But enumerating them lets us avoid having a default
@@ -588,7 +596,8 @@
             case ProcHook::EXT_debug_report:
             case ProcHook::EXT_swapchain_colorspace:
             case ProcHook::ANDROID_native_buffer:
-            case ProcHook::EXTENSION_CORE:
+            case ProcHook::EXTENSION_CORE_1_0:
+            case ProcHook::EXTENSION_CORE_1_1:
             case ProcHook::EXTENSION_COUNT:
                 // Instance and meta extensions. If we ever get here it's a bug
                 // in our code. But enumerating them lets us avoid having a
@@ -636,6 +645,31 @@
     }
 }
 
+void CreateInfoWrapper::UpgradeDeviceCoreApiVersion(uint32_t api_version) {
+    ALOG_ASSERT(!is_instance_, "Device only API called by instance wrapper.");
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+    api_version ^= VK_VERSION_PATCH(api_version);
+#pragma clang diagnostic pop
+
+    // cap the API version to the loader supported highest version
+    if (api_version > VK_API_VERSION_1_1)
+        api_version = VK_API_VERSION_1_1;
+
+    switch (api_version) {
+        case VK_API_VERSION_1_1:
+            hook_extensions_.set(ProcHook::EXTENSION_CORE_1_1);
+            hal_extensions_.set(ProcHook::EXTENSION_CORE_1_1);
+            [[clang::fallthrough]];
+        case VK_API_VERSION_1_0:
+            break;
+        default:
+            ALOGD("Unknown upgrade API version[%u]", api_version);
+            break;
+    }
+}
+
 VKAPI_ATTR void* DefaultAllocate(void*,
                                  size_t size,
                                  size_t alignment,
@@ -659,7 +693,7 @@
         return nullptr;
     }
 
-    // TODO(jessehall): Right now we never shrink allocations; if the new
+    // TODO(b/143295633): Right now we never shrink allocations; if the new
     // request is smaller than the existing chunk, we just continue using it.
     // Right now the loader never reallocs, so this doesn't matter. If that
     // changes, or if this code is copied into some other project, this should
@@ -771,7 +805,7 @@
                        : nullptr;
             break;
         case ProcHook::DEVICE:
-            proc = (hook->extension == ProcHook::EXTENSION_CORE)
+            proc = (hook->extension == ProcHook::EXTENSION_CORE_1_0)
                        ? hook->proc
                        : hook->checked_proc;
             break;
@@ -1117,6 +1151,13 @@
     if (!data)
         return VK_ERROR_OUT_OF_HOST_MEMORY;
 
+    VkPhysicalDeviceProperties properties;
+    ATRACE_BEGIN("driver.GetPhysicalDeviceProperties");
+    instance_data.driver.GetPhysicalDeviceProperties(physicalDevice,
+                                                     &properties);
+    ATRACE_END();
+
+    wrapper.UpgradeDeviceCoreApiVersion(properties.apiVersion);
     data->hook_extensions |= wrapper.GetHookExtensions();
 
     // call into the driver
@@ -1161,12 +1202,6 @@
         return VK_ERROR_INCOMPATIBLE_DRIVER;
     }
 
-    VkPhysicalDeviceProperties properties;
-    ATRACE_BEGIN("driver.GetPhysicalDeviceProperties");
-    instance_data.driver.GetPhysicalDeviceProperties(physicalDevice,
-                                                     &properties);
-    ATRACE_END();
-
     if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
         // Log that the app is hitting software Vulkan implementation
         android::GraphicsEnv::getInstance().setTargetStats(
@@ -1174,7 +1209,6 @@
     }
 
     data->driver_device = dev;
-    data->driver_version = properties.driverVersion;
 
     *pDevice = dev;
 
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index f058c47..7edadea 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -67,9 +67,7 @@
         : opaque_api_data(),
           allocator(alloc),
           driver(),
-          get_device_proc_addr(nullptr) {
-        hook_extensions.set(ProcHook::EXTENSION_CORE);
-    }
+          get_device_proc_addr(nullptr) {}
 
     api::InstanceData opaque_api_data;
 
@@ -89,9 +87,7 @@
         : opaque_api_data(),
           allocator(alloc),
           debug_report_callbacks(debug_report_callbacks_),
-          driver() {
-        hook_extensions.set(ProcHook::EXTENSION_CORE);
-    }
+          driver() {}
 
     api::DeviceData opaque_api_data;
 
@@ -102,7 +98,6 @@
 
     VkDevice driver_device;
     DeviceDriverTable driver;
-    uint32_t driver_version;
 };
 
 bool Debuggable();
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index d829e41..52205e9 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -74,6 +74,15 @@
     }
 }
 
+VKAPI_ATTR VkResult checkedBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
+    if (GetData(device).hook_extensions[ProcHook::EXTENSION_CORE_1_1]) {
+        return BindImageMemory2(device, bindInfoCount, pBindInfos);
+    } else {
+        Logger(device).Err(device, "VK_VERSION_1_1 not enabled. vkBindImageMemory2 not executed.");
+        return VK_SUCCESS;
+    }
+}
+
 VKAPI_ATTR VkResult checkedBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
     if (GetData(device).hook_extensions[ProcHook::KHR_bind_memory2]) {
         return BindImageMemory2KHR(device, bindInfoCount, pBindInfos);
@@ -145,6 +154,14 @@
     }
 }
 
+VKAPI_ATTR void checkedGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) {
+    if (GetData(device).hook_extensions[ProcHook::EXTENSION_CORE_1_1]) {
+        GetDeviceQueue2(device, pQueueInfo, pQueue);
+    } else {
+        Logger(device).Err(device, "VK_VERSION_1_1 not enabled. vkGetDeviceQueue2 not executed.");
+    }
+}
+
 // clang-format on
 
 const ProcHook g_proc_hooks[] = {
@@ -173,16 +190,16 @@
     {
         "vkAllocateCommandBuffers",
         ProcHook::DEVICE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers),
         nullptr,
     },
     {
         "vkBindImageMemory2",
         ProcHook::DEVICE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_1,
         reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory2),
-        nullptr,
+        reinterpret_cast<PFN_vkVoidFunction>(checkedBindImageMemory2),
     },
     {
         "vkBindImageMemory2KHR",
@@ -208,14 +225,14 @@
     {
         "vkCreateDevice",
         ProcHook::INSTANCE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(CreateDevice),
         nullptr,
     },
     {
         "vkCreateInstance",
         ProcHook::GLOBAL,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(CreateInstance),
         nullptr,
     },
@@ -243,14 +260,14 @@
     {
         "vkDestroyDevice",
         ProcHook::DEVICE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice),
         nullptr,
     },
     {
         "vkDestroyInstance",
         ProcHook::INSTANCE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance),
         nullptr,
     },
@@ -271,28 +288,28 @@
     {
         "vkEnumerateDeviceExtensionProperties",
         ProcHook::INSTANCE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties),
         nullptr,
     },
     {
         "vkEnumerateInstanceExtensionProperties",
         ProcHook::GLOBAL,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties),
         nullptr,
     },
     {
         "vkEnumeratePhysicalDeviceGroups",
         ProcHook::INSTANCE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_1,
         reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDeviceGroups),
         nullptr,
     },
     {
         "vkEnumeratePhysicalDevices",
         ProcHook::INSTANCE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices),
         nullptr,
     },
@@ -313,28 +330,28 @@
     {
         "vkGetDeviceProcAddr",
         ProcHook::DEVICE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr),
         nullptr,
     },
     {
         "vkGetDeviceQueue",
         ProcHook::DEVICE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue),
         nullptr,
     },
     {
         "vkGetDeviceQueue2",
         ProcHook::DEVICE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_1,
         reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2),
-        nullptr,
+        reinterpret_cast<PFN_vkVoidFunction>(checkedGetDeviceQueue2),
     },
     {
         "vkGetInstanceProcAddr",
         ProcHook::INSTANCE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr),
         nullptr,
     },
@@ -446,7 +463,7 @@
     {
         "vkQueueSubmit",
         ProcHook::DEVICE,
-        ProcHook::EXTENSION_CORE,
+        ProcHook::EXTENSION_CORE_1_0,
         reinterpret_cast<PFN_vkVoidFunction>(QueueSubmit),
         nullptr,
     },
@@ -480,14 +497,14 @@
     if (strcmp(name, "VK_EXT_swapchain_colorspace") == 0) return ProcHook::EXT_swapchain_colorspace;
     if (strcmp(name, "VK_GOOGLE_display_timing") == 0) return ProcHook::GOOGLE_display_timing;
     if (strcmp(name, "VK_KHR_android_surface") == 0) return ProcHook::KHR_android_surface;
+    if (strcmp(name, "VK_KHR_get_surface_capabilities2") == 0) return ProcHook::KHR_get_surface_capabilities2;
     if (strcmp(name, "VK_KHR_incremental_present") == 0) return ProcHook::KHR_incremental_present;
     if (strcmp(name, "VK_KHR_shared_presentable_image") == 0) return ProcHook::KHR_shared_presentable_image;
     if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface;
     if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain;
-    if (strcmp(name, "VK_KHR_get_surface_capabilities2") == 0) return ProcHook::KHR_get_surface_capabilities2;
-    if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2;
     if (strcmp(name, "VK_ANDROID_external_memory_android_hardware_buffer") == 0) return ProcHook::ANDROID_external_memory_android_hardware_buffer;
     if (strcmp(name, "VK_KHR_bind_memory2") == 0) return ProcHook::KHR_bind_memory2;
+    if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2;
     // clang-format on
     return ProcHook::EXTENSION_UNKNOWN;
 }
@@ -562,5 +579,3 @@
 
 }  // namespace driver
 }  // namespace vulkan
-
-// clang-format on
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index fb2f257..43c4d14 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -40,16 +40,17 @@
         EXT_swapchain_colorspace,
         GOOGLE_display_timing,
         KHR_android_surface,
+        KHR_get_surface_capabilities2,
         KHR_incremental_present,
         KHR_shared_presentable_image,
         KHR_surface,
         KHR_swapchain,
-        KHR_get_surface_capabilities2,
-        KHR_get_physical_device_properties2,
         ANDROID_external_memory_android_hardware_buffer,
         KHR_bind_memory2,
+        KHR_get_physical_device_properties2,
 
-        EXTENSION_CORE,  // valid bit
+        EXTENSION_CORE_1_0,
+        EXTENSION_CORE_1_1,
         EXTENSION_COUNT,
         EXTENSION_UNKNOWN,
     };
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 5679412..22f92d6 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -38,13 +38,7 @@
 #include <utils/Trace.h>
 #include <ziparchive/zip_archive.h>
 
-// TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
-// not a good long-term solution. Having a hard-coded enum of extensions is
-// bad, of course. Representing sets of extensions (requested, supported, etc.)
-// as a bitset isn't necessarily bad, if the mapping from extension to bit were
-// dynamic. Need to rethink this completely when there's a little more time.
-
-// TODO(jessehall): This file currently builds up global data structures as it
+// TODO(b/143296676): This file currently builds up global data structures as it
 // loads, and never cleans them up. This means we're doing heap allocations
 // without going through an app-provided allocator, but worse, we'll leak those
 // allocations if the loader is unloaded.
@@ -101,9 +95,7 @@
     bool EnumerateLayers(size_t library_idx,
                          std::vector<Layer>& instance_layers) const;
 
-    void* GetGPA(const Layer& layer,
-                 const char* gpa_name,
-                 size_t gpa_name_len) const;
+    void* GetGPA(const Layer& layer, const std::string_view gpa_name) const;
 
     const std::string GetFilename() { return filename_; }
 
@@ -226,9 +218,8 @@
     }
 
     // get layer properties
-    VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca(
-        (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties)));
-    result = enumerate_instance_layers(&num_instance_layers, properties);
+    std::vector<VkLayerProperties> properties(num_instance_layers + num_device_layers);
+    result = enumerate_instance_layers(&num_instance_layers, properties.data());
     if (result != VK_SUCCESS) {
         ALOGE("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
               path_.c_str(), result);
@@ -236,7 +227,7 @@
     }
     if (num_device_layers > 0) {
         result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
-                                         properties + num_instance_layers);
+                                         &properties[num_instance_layers]);
         if (result != VK_SUCCESS) {
             ALOGE(
                 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
@@ -321,21 +312,11 @@
     return true;
 }
 
-void* LayerLibrary::GetGPA(const Layer& layer,
-                           const char* gpa_name,
-                           size_t gpa_name_len) const {
-    void* gpa;
-    size_t layer_name_len =
-        std::max(size_t{2}, strlen(layer.properties.layerName));
-    char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
-    strcpy(name, layer.properties.layerName);
-    strcpy(name + layer_name_len, gpa_name);
-    if (!(gpa = GetTrampoline(name))) {
-        strcpy(name, "vk");
-        strcpy(name + 2, gpa_name);
-        gpa = GetTrampoline(name);
-    }
-    return gpa;
+void* LayerLibrary::GetGPA(const Layer& layer, const std::string_view gpa_name) const {
+    std::string layer_name { layer.properties.layerName };
+    if (void* gpa = GetTrampoline((layer_name.append(gpa_name).c_str())))
+        return gpa;
+    return GetTrampoline((std::string {"vk"}.append(gpa_name)).c_str());
 }
 
 // ----------------------------------------------------------------------------
@@ -470,10 +451,9 @@
 }
 
 void* GetLayerGetProcAddr(const Layer& layer,
-                          const char* gpa_name,
-                          size_t gpa_name_len) {
+                          const std::string_view gpa_name) {
     const LayerLibrary& library = g_layer_libraries[layer.library_idx];
-    return library.GetGPA(layer, gpa_name, gpa_name_len);
+    return library.GetGPA(layer, gpa_name);
 }
 
 }  // anonymous namespace
@@ -556,13 +536,13 @@
 
 PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const {
     return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>(
-                        GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19))
+                        GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr"))
                   : nullptr;
 }
 
 PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const {
     return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>(
-                        GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17))
+                        GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr"))
                   : nullptr;
 }
 
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index d60eaa7..8f4667e 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -694,8 +694,8 @@
 
     const InstanceData& instance_data = GetData(pdev);
 
-    // TODO(jessehall): Fill out the set of supported formats. Longer term, add
-    // a new gralloc method to query whether a (format, usage) pair is
+    // TODO(b/143296550): Fill out the set of supported formats. Longer term,
+    // add a new gralloc method to query whether a (format, usage) pair is
     // supported, and check that for each gralloc format that corresponds to a
     // Vulkan format. Shorter term, just add a few more formats to the ones
     // hardcoded below.
@@ -704,8 +704,6 @@
         {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
         {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
         {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-        {VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-        {VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
     };
     const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
     uint32_t total_num_formats = kNumFormats;
@@ -953,7 +951,7 @@
                   strerror(-err), err);
         }
 
-        // TODO: Return something better than "whole window"
+        // TODO(b/143294545): Return something better than "whole window"
         pRects[0].offset.x = 0;
         pRects[0].offset.y = 0;
         pRects[0].extent = VkExtent2D{static_cast<uint32_t>(width),
@@ -1291,6 +1289,7 @@
     VkImageCreateInfo image_create = {
         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
         .pNext = &image_native_buffer,
+        .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
         .imageType = VK_IMAGE_TYPE_2D,
         .format = create_info->imageFormat,
         .extent = {0, 0, 1},
@@ -1299,7 +1298,6 @@
         .samples = VK_SAMPLE_COUNT_1_BIT,
         .tiling = VK_IMAGE_TILING_OPTIMAL,
         .usage = create_info->imageUsage,
-        .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
         .sharingMode = create_info->imageSharingMode,
         .queueFamilyIndexCount = create_info->queueFamilyIndexCount,
         .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
@@ -1812,7 +1810,7 @@
         return VK_ERROR_OUT_OF_DATE_KHR;
     }
 
-    // TODO(chrisforbes): Implement this function properly
+    // TODO(b/143296009): Implement this function properly
 
     return result;
 }
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 668dc7d..0d3f688 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -207,9 +207,6 @@
 VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
 VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
 VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
-VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
-VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
-VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
 // clang-format on
 
 }  // namespace null_driver
diff --git a/vulkan/scripts/api_generator.py b/vulkan/scripts/api_generator.py
index a0c648c..7c39075 100644
--- a/vulkan/scripts/api_generator.py
+++ b/vulkan/scripts/api_generator.py
@@ -13,28 +13,46 @@
 # 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.
-#
-# This script provides the functions required for generating the
-# vulkan api framework directly from the vulkan registry (vk.xml)
+
+"""Generates the api_gen.h and api_gen.cpp.
+"""
 
 import os
 import generator_common as gencom
 
-def isInstanceDispatchTableEntry(functionName):
-  if functionName == 'vkEnumerateDeviceLayerProperties': # deprecated, unused internally - @dbd33bc
-    return False
-  if gencom.gencom.isFunctionExported(functionName) and gencom.isInstanceDispatched(functionName):
-    return True
-  return False
+# Functions intercepted at vulkan::api level.
+_INTERCEPTED_COMMANDS = [
+    'vkCreateDevice',
+    'vkDestroyDevice',
+    'vkDestroyInstance',
+    'vkEnumerateDeviceExtensionProperties',
+    'vkEnumerateDeviceLayerProperties',
+]
 
-def isDeviceDispatchTableEntry(functionName):
-  if gencom.gencom.isFunctionExported(functionName) and gencom.gencom.isDeviceDispatched(functionName):
-    return True
-  return False
 
-def api_genh():
+def gen_h():
+  """Generates the api_gen.h file.
+  """
+  genfile = os.path.join(os.path.dirname(__file__),
+                         '..', 'libvulkan', 'api_gen.h')
 
-  header = """#ifndef LIBVULKAN_API_GEN_H
+  with open(genfile, 'w') as f:
+    instance_dispatch_table_entries = []
+    device_dispatch_table_entries = []
+
+    for cmd in gencom.command_list:
+      if cmd not in gencom.alias_dict:
+        if gencom.is_instance_dispatch_table_entry(cmd):
+          instance_dispatch_table_entries.append(
+              'PFN_' + cmd + ' ' + gencom.base_name(cmd) + ';')
+        elif gencom.is_device_dispatch_table_entry(cmd):
+          device_dispatch_table_entries.append(
+              'PFN_' + cmd + ' ' + gencom.base_name(cmd) + ';')
+
+    f.write(gencom.copyright_and_warning(2016))
+
+    f.write("""\
+#ifndef LIBVULKAN_API_GEN_H
 #define LIBVULKAN_API_GEN_H
 
 #include <vulkan/vulkan.h>
@@ -46,9 +64,26 @@
 namespace vulkan {
 namespace api {
 
-"""
+struct InstanceDispatchTable {
+    // clang-format off\n""")
 
-  tail = """
+    for entry in instance_dispatch_table_entries:
+      f.write(gencom.indent(1) + entry + '\n')
+
+    f.write("""\
+    // clang-format on
+};
+
+struct DeviceDispatchTable {
+    // clang-format off\n""")
+
+    for entry in device_dispatch_table_entries:
+      f.write(gencom.indent(1) + entry + '\n')
+
+    f.write("""\
+    // clang-format on
+};
+
 bool InitDispatchTable(
     VkInstance instance,
     PFN_vkGetInstanceProcAddr get_proc,
@@ -61,105 +96,70 @@
 }  // namespace api
 }  // namespace vulkan
 
-#endif  // LIBVULKAN_API_GEN_H
-"""
-  genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen.h')
-  with open(genfile, 'w') as f:
-    instanceDispatchTableEntries = []
-    deviceDispatchTableEntries = []
-    for commands in gencom.allCommandsList:
-      if commands not in gencom.aliasDict:
-        if gencom.isInstanceDispatchTableEntry(commands):
-          instanceDispatchTableEntries.append('PFN_'+commands+' '+commands[2:]+';')
-        elif gencom.isDeviceDispatchTableEntry(commands):
-          deviceDispatchTableEntries.append('PFN_'+commands+' '+commands[2:]+';')
+#endif  // LIBVULKAN_API_GEN_H\n""")
 
-    f.write (gencom.copyright)
-    f.write (gencom.warning)
-    f.write (header)
-    f.write ('struct InstanceDispatchTable {\n')
-    gencom.clang_off(f,1)
-    for functions in instanceDispatchTableEntries:
-      f.write(gencom.clang_off_spaces + functions + '\n')
-    gencom.clang_on(f,1)
-    f.write ('};\n\n')
-
-    f.write ('struct DeviceDispatchTable {\n')
-    gencom.clang_off(f,1)
-    for functions in deviceDispatchTableEntries:
-      f.write(gencom.clang_off_spaces + functions + '\n')
-    gencom.clang_on(f,1)
-    f.write ('};\n')
-
-    f.write (tail)
     f.close()
-  gencom.runClangFormat(genfile)
+  gencom.run_clang_format(genfile)
 
-def defineInitProc(name, f):
-  f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n')
-  f.write ('\n')
-  f.write ("""#define INIT_PROC(required, obj, proc)                                 \\
-    do {                                                               \\
-        data.""" + name + """.proc =                                           \\
-            reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
-        if (UNLIKELY(required && !data.""" + name + """.proc)) {               \\
-            ALOGE("missing " #obj " proc: vk" #proc);                  \\
-            success = false;                                           \\
-        }                                                              \\
-    } while (0)\n\n""")
 
-def defineInitProcExt(f):
-  f.write ('// Exported extension functions may be invoked even when their extensions\n')
-  f.write ('// are disabled.  Dispatch to stubs when that happens.\n')
-  f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc)  \\
-    do {                                         \\
-        if (extensions[driver::ProcHook::ext])   \\
-            INIT_PROC(required, obj, proc);      \\
-        else                                     \\
-            data.dispatch.proc = disabled##proc; \\
-    } while (0)\n\n""")
+def _define_extension_stub(cmd, f):
+  """Emits a stub for an exported extension function.
 
-def defineExtensionStub(functionName, f):
-  if functionName in gencom.extensionsDict and gencom.isFunctionExported(functionName):
-    extname = gencom.extensionsDict[functionName]
-    base_name = functionName[2:]
-    pList = gencom.paramDict[functionName]
-    firstParam = pList[0][0] + pList[0][1]
-    tailParams = [x[0][:-1] for x in pList[1:]]
-    tailP = ', '.join(tailParams)
-    f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' disabled' + base_name + '(' + firstParam + ', ' + tailP + ') {\n')
-    f.write (gencom.clang_off_spaces)
-    f.write ('driver::Logger(' + pList[0][1] + ').Err(' + pList[0][1] + ', \"' + extname + ' not enabled. Exported ' + functionName + ' not executed.\");\n')
-    if gencom.returnTypeDict[functionName] != 'void':
-      f.write(gencom.clang_off_spaces + 'return VK_SUCCESS;\n')
-    f.write ('}\n\n')
+  Args:
+    cmd: Vulkan function name.
+    f: Output file handle.
+  """
+  if (cmd in gencom.extension_dict and gencom.is_function_exported(cmd)):
+    ext_name = gencom.extension_dict[cmd]
+    ret = gencom.return_type_dict[cmd]
+    params = gencom.param_dict[cmd]
+    first_param = params[0][0] + params[0][1]
+    tail_params = ', '.join([i[0][:-1] for i in params[1:]])
 
-def isIntercepted(functionName):
-  if gencom.isFunctionSupported(functionName):
-    if gencom.isGloballyDispatched(functionName):
-      return True
-    elif functionName == 'vkCreateDevice':
-      return True
-    elif functionName == 'vkEnumerateDeviceLayerProperties':
-      return True
-    elif functionName == 'vkEnumerateDeviceExtensionProperties':
-      return True
-    elif functionName == 'vkDestroyInstance':
-      return True
-    elif functionName == 'vkDestroyDevice':
+    f.write('VKAPI_ATTR ' + ret + ' disabled' + gencom.base_name(cmd) +
+            '(' + first_param + ', ' + tail_params + ') {\n')
+
+    f.write(gencom.indent(1) + 'driver::Logger(' + params[0][1] +
+            ').Err(' + params[0][1] + ', \"' + ext_name +
+            ' not enabled. Exported ' + cmd + ' not executed.\");\n')
+
+    if gencom.return_type_dict[cmd] != 'void':
+      f.write(gencom.indent(1) + 'return VK_SUCCESS;\n')
+
+    f.write('}\n\n')
+
+
+def _is_intercepted(cmd):
+  """Returns true if a function is intercepted by vulkan::api.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  if gencom.is_function_supported(cmd):
+    if gencom.is_globally_dispatched(cmd) or cmd in _INTERCEPTED_COMMANDS:
       return True
   return False
 
-def interceptInstanceProcAddr(functionName, f):
-  indent = 1
-  f.write (gencom.clang_off_spaces*indent + '// global functions\n' + gencom.clang_off_spaces*indent+ 'if (instance == VK_NULL_HANDLE) {\n')
-  indent = indent + 1
-  for cmds in gencom.allCommandsList:
-    if gencom.isGloballyDispatched(cmds):
-      f.write(gencom.clang_off_spaces*indent + 'if (strcmp(pName, \"' + cmds + '\") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ');\n')
 
-  f.write ('\n')
-  f.write ("""        ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \\\"%s\\\") call", pName);
+def _intercept_instance_proc_addr(f):
+  """Emits code for vkGetInstanceProcAddr for function interception.
+
+  Args:
+    f: Output file handle.
+  """
+  f.write("""\
+    // global functions
+    if (instance == VK_NULL_HANDLE) {\n""")
+
+  for cmd in gencom.command_list:
+    if gencom.is_globally_dispatched(cmd):
+      f.write(gencom.indent(2) +
+              'if (strcmp(pName, \"' + cmd +
+              '\") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' +
+              gencom.base_name(cmd) + ');\n')
+
+  f.write("""
+        ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \\\"%s\\\") call", pName);
         return nullptr;
     }
 
@@ -167,14 +167,21 @@
         const char* name;
         PFN_vkVoidFunction proc;
     } hooks[] = {\n""")
-  sortedCommandsList = sorted(gencom.allCommandsList)
-  for cmds in sortedCommandsList:
-    if gencom.isFunctionExported(cmds):
-      if gencom.isGloballyDispatched(cmds):
-        f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", nullptr },\n')
-      elif isIntercepted(cmds) or cmds == 'vkGetInstanceProcAddr' or gencom.isDeviceDispatched(cmds):
-        f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ') },\n')
-  f.write (gencom.clang_off_spaces + """};
+
+  sorted_command_list = sorted(gencom.command_list)
+  for cmd in sorted_command_list:
+    if gencom.is_function_exported(cmd):
+      if gencom.is_globally_dispatched(cmd):
+        f.write(gencom.indent(2) + '{ \"' + cmd + '\", nullptr },\n')
+      elif (_is_intercepted(cmd) or
+            cmd == 'vkGetInstanceProcAddr' or
+            gencom.is_device_dispatched(cmd)):
+        f.write(gencom.indent(2) + '{ \"' + cmd +
+                '\", reinterpret_cast<PFN_vkVoidFunction>(' +
+                gencom.base_name(cmd) + ') },\n')
+
+  f.write("""\
+    };
     // clang-format on
     constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
     auto hook = std::lower_bound(
@@ -190,19 +197,30 @@
     }
     // clang-format off\n\n""")
 
-def interceptDeviceProcAddr(functionName, f):
-  f.write (gencom.clang_off_spaces + """if (device == VK_NULL_HANDLE) {
+
+def _intercept_device_proc_addr(f):
+  """Emits code for vkGetDeviceProcAddr for function interception.
+
+  Args:
+    f: Output file handle.
+  """
+  f.write("""\
+    if (device == VK_NULL_HANDLE) {
         ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call");
         return nullptr;
-    }\n\n""")
-  f.write (gencom.clang_off_spaces + 'static const char* const known_non_device_names[] = {\n')
-  sortedCommandsList = sorted(gencom.allCommandsList)
-  for cmds in sortedCommandsList:
-    if gencom.isFunctionSupported(cmds):
-      if not gencom.isDeviceDispatched(cmds):
-        f.write(gencom.clang_off_spaces*2 + '\"' + cmds + '\",\n')
-  f.write(gencom.clang_off_spaces + '};\n')
-  f.write(gencom.clang_off_spaces + """// clang-format on
+    }
+
+    static const char* const known_non_device_names[] = {\n""")
+
+  sorted_command_list = sorted(gencom.command_list)
+  for cmd in sorted_command_list:
+    if gencom.is_function_supported(cmd):
+      if not gencom.is_device_dispatched(cmd):
+        f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
+
+  f.write("""\
+    };
+    // clang-format on
     constexpr size_t count =
         sizeof(known_non_device_names) / sizeof(known_non_device_names[0]);
     if (!pName ||
@@ -215,27 +233,46 @@
         return nullptr;
     }
     // clang-format off\n\n""")
-  for cmds in gencom.allCommandsList:
-    if gencom.isDeviceDispatched(cmds):
-      if isIntercepted(cmds) or cmds == 'vkGetDeviceProcAddr':
-        f.write (gencom.clang_off_spaces + 'if (strcmp(pName, "' + cmds + '") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ');\n')
-  f.write ('\n')
 
-def apiDispatch(functionName, f):
-  assert not isIntercepted(functionName)
-
-  f.write (gencom.clang_off_spaces)
-  if gencom.returnTypeDict[functionName] != 'void':
-    f.write ('return ')
-
-  paramList = gencom.paramDict[functionName]
-  p0 = paramList[0][1]
-  f.write('GetData(' + p0 + ').dispatch.' + functionName[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n')
+  for cmd in gencom.command_list:
+    if gencom.is_device_dispatched(cmd):
+      if _is_intercepted(cmd) or cmd == 'vkGetDeviceProcAddr':
+        f.write(gencom.indent(1) + 'if (strcmp(pName, "' + cmd +
+                '") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' +
+                gencom.base_name(cmd) + ');\n')
+  f.write('\n')
 
 
-def api_gencpp():
-  genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen.cpp')
-  header = """#include <log/log.h>
+def _api_dispatch(cmd, f):
+  """Emits code to dispatch a function.
+
+  Args:
+    cmd: Vulkan function name.
+    f: Output file handle.
+  """
+  assert not _is_intercepted(cmd)
+
+  f.write(gencom.indent(1))
+  if gencom.return_type_dict[cmd] != 'void':
+    f.write('return ')
+
+  param_list = gencom.param_dict[cmd]
+  handle = param_list[0][1]
+  f.write('GetData(' + handle + ').dispatch.' + gencom.base_name(cmd) +
+          '(' + ', '.join(i[1] for i in param_list) + ');\n')
+
+
+def gen_cpp():
+  """Generates the api_gen.cpp file.
+  """
+  genfile = os.path.join(os.path.dirname(__file__),
+                         '..', 'libvulkan', 'api_gen.cpp')
+
+  with open(genfile, 'w') as f:
+    f.write(gencom.copyright_and_warning(2016))
+
+    f.write("""\
+#include <log/log.h>
 #include <string.h>
 
 #include <algorithm>
@@ -247,80 +284,106 @@
 namespace vulkan {
 namespace api {
 
-"""
-  with open(genfile, 'w') as f:
-    f.write (gencom.copyright)
-    f.write (gencom.warning)
-    f.write ("""#include <log/log.h>
-#include <string.h>
+#define UNLIKELY(expr) __builtin_expect((expr), 0)
 
-#include <algorithm>
+#define INIT_PROC(required, obj, proc)                                 \\
+    do {                                                               \\
+        data.dispatch.proc =                                           \\
+            reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
+        if (UNLIKELY(required && !data.dispatch.proc)) {               \\
+            ALOGE("missing " #obj " proc: vk" #proc);                  \\
+            success = false;                                           \\
+        }                                                              \\
+    } while (0)
 
-// to catch mismatches between vulkan.h and this file
-#undef VK_NO_PROTOTYPES
-#include "api.h"
+// Exported extension functions may be invoked even when their extensions
+// are disabled.  Dispatch to stubs when that happens.
+#define INIT_PROC_EXT(ext, required, obj, proc)  \\
+    do {                                         \\
+        if (extensions[driver::ProcHook::ext])   \\
+            INIT_PROC(required, obj, proc);      \\
+        else                                     \\
+            data.dispatch.proc = disabled##proc; \\
+    } while (0)
 
-namespace vulkan {
-namespace api {\n\n""")
-    defineInitProc('dispatch',f)
-    defineInitProcExt(f)
-    f.write ('namespace {\n\n')
-    gencom.clang_off(f,0)
-    f.write ('\n')
-    for cmds in gencom.allCommandsList:
-      defineExtensionStub(cmds,f)
-    gencom.clang_on(f,0)
-    f.write ('\n}  // namespace\n\n')
-    f.write ("""bool InitDispatchTable(
+namespace {
+
+// clang-format off\n\n""")
+
+    for cmd in gencom.command_list:
+      _define_extension_stub(cmd, f)
+
+    f.write("""\
+// clang-format on
+
+}  // namespace
+
+bool InitDispatchTable(
     VkInstance instance,
     PFN_vkGetInstanceProcAddr get_proc,
     const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
     auto& data = GetData(instance);
-    bool success = true;\n\n""")
-    gencom.clang_off(f,1)
-    for cmds in gencom.allCommandsList:
-      if gencom.isInstanceDispatchTableEntry(cmds):
-        gencom.initProc(cmds, f)
-    gencom.clang_on(f,1)
-    f.write ('\n')
-    f.write ('    return success;\n}\n\n')
-    f.write ("""bool InitDispatchTable(
+    bool success = true;
+
+    // clang-format off\n""")
+
+    for cmd in gencom.command_list:
+      if gencom.is_instance_dispatch_table_entry(cmd):
+        gencom.init_proc(cmd, f)
+
+    f.write("""\
+    // clang-format on
+
+    return success;
+}
+
+bool InitDispatchTable(
     VkDevice dev,
     PFN_vkGetDeviceProcAddr get_proc,
     const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
     auto& data = GetData(dev);
-    bool success = true;\n\n""")
+    bool success = true;
 
-    gencom.clang_off(f,1)
-    for cmds in gencom.allCommandsList:
-      if gencom.isDeviceDispatchTableEntry(cmds):
-        gencom.initProc(cmds, f)
-    gencom.clang_on(f,1)
-    f.write ('\n')
-    f.write ('    return success;\n}\n\n')
+    // clang-format off\n""")
 
-    gencom.clang_off(f,0)
+    for cmd in gencom.command_list:
+      if gencom.is_device_dispatch_table_entry(cmd):
+        gencom.init_proc(cmd, f)
 
-    f.write ('\nnamespace {\n\n')
-    f.write('// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr\n')
-    for cmds in gencom.allCommandsList:
-      if gencom.isFunctionExported(cmds) and not isIntercepted(cmds):
-        paramList = [''.join(i) for i in gencom.paramDict[cmds]]
-        f.write ('VKAPI_ATTR '+gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ');\n')
+    f.write("""\
+    // clang-format on
 
-    f.write ('\n')
+    return success;
+}
 
-    for cmds in gencom.allCommandsList:
-      if gencom.isFunctionExported(cmds) and not isIntercepted(cmds):
-        paramList = [''.join(i) for i in gencom.paramDict[cmds]]
-        f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ') {\n')
-        if cmds == 'vkGetInstanceProcAddr':
-          interceptInstanceProcAddr(cmds, f)
-        elif cmds == 'vkGetDeviceProcAddr':
-          interceptDeviceProcAddr(cmds, f)
-        apiDispatch(cmds, f)
+// clang-format off
+
+namespace {
+
+// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr
+""")
+
+    for cmd in gencom.command_list:
+      if gencom.is_function_exported(cmd) and not _is_intercepted(cmd):
+        param_list = [''.join(i) for i in gencom.param_dict[cmd]]
+        f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
+                gencom.base_name(cmd) + '(' + ', '.join(param_list) + ');\n')
+
+    f.write('\n')
+    for cmd in gencom.command_list:
+      if gencom.is_function_exported(cmd) and not _is_intercepted(cmd):
+        param_list = [''.join(i) for i in gencom.param_dict[cmd]]
+        f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
+                gencom.base_name(cmd) + '(' + ', '.join(param_list) + ') {\n')
+        if cmd == 'vkGetInstanceProcAddr':
+          _intercept_instance_proc_addr(f)
+        elif cmd == 'vkGetDeviceProcAddr':
+          _intercept_device_proc_addr(f)
+        _api_dispatch(cmd, f)
         f.write('}\n\n')
-    f.write ("""\n}  // anonymous namespace
+
+    f.write("""
+}  // anonymous namespace
 
 // clang-format on
 
@@ -329,18 +392,19 @@
 
 // clang-format off\n\n""")
 
-    for cmds in gencom.allCommandsList:
-      if gencom.isFunctionExported(cmds):
-        paramList = [''.join(i) for i in gencom.paramDict[cmds]]
-        f.write ('__attribute__((visibility("default")))\n')
-        f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds + '(' + ', '.join(paramList) + ') {\n')
-        f.write (gencom.clang_off_spaces)
-        if gencom.returnTypeDict[cmds] != 'void':
-          f.write ('return ')
-        paramList = gencom.paramDict[cmds]
-        f.write ('vulkan::api::' + cmds[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n')
-        f.write ('}\n\n')
+    for cmd in gencom.command_list:
+      if gencom.is_function_exported(cmd):
+        param_list = [''.join(i) for i in gencom.param_dict[cmd]]
+        f.write('__attribute__((visibility("default")))\n')
+        f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
+                cmd + '(' + ', '.join(param_list) + ') {\n')
+        f.write(gencom.indent(1))
+        if gencom.return_type_dict[cmd] != 'void':
+          f.write('return ')
+        param_list = gencom.param_dict[cmd]
+        f.write('vulkan::api::' + gencom.base_name(cmd) +
+                '(' + ', '.join(i[1] for i in param_list) + ');\n}\n\n')
 
-    gencom.clang_on(f, 0)
+    f.write('// clang-format on\n')
     f.close()
-  gencom.runClangFormat(genfile)
+  gencom.run_clang_format(genfile)
diff --git a/vulkan/scripts/code_generator.py b/vulkan/scripts/code_generator.py
index 39fedf4..2a017d2 100755
--- a/vulkan/scripts/code_generator.py
+++ b/vulkan/scripts/code_generator.py
@@ -13,20 +13,20 @@
 # 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.
-#
-# This script provides the main function for generating
-# vulkan framework directly from the vulkan registry (vk.xml).
 
-import generator_common as gencom
-import api_generator as apigen
-import driver_generator as drivergen
-import null_generator as nullgen
+"""Generates vulkan framework directly from the vulkan registry (vk.xml).
+"""
+
+import api_generator
+import driver_generator
+import generator_common
+import null_generator
 
 if __name__ == '__main__':
-  gencom.parseVulkanRegistry()
-  apigen.api_genh()
-  apigen.api_gencpp()
-  drivergen.driver_genh()
-  drivergen.driver_gencpp()
-  nullgen.null_driver_genh()
-  nullgen.null_driver_gencpp()
+  generator_common.parse_vulkan_registry()
+  api_generator.gen_h()
+  api_generator.gen_cpp()
+  driver_generator.gen_h()
+  driver_generator.gen_cpp()
+  null_generator.gen_h()
+  null_generator.gen_cpp()
diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py
index ef36f8c..a64a702 100644
--- a/vulkan/scripts/driver_generator.py
+++ b/vulkan/scripts/driver_generator.py
@@ -13,45 +13,176 @@
 # 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.
-#
-# This script provides the functions for generating the
-# vulkan driver framework directly from the vulkan registry (vk.xml).
 
-import generator_common as gencom
+"""Generates the driver_gen.h and driver_gen.cpp.
+"""
+
 import os
+import generator_common as gencom
 
-interceptedExtensions = [
-  'VK_ANDROID_native_buffer',
-  'VK_EXT_debug_report',
-  'VK_EXT_hdr_metadata',
-  'VK_EXT_swapchain_colorspace',
-  'VK_GOOGLE_display_timing',
-  'VK_KHR_android_surface',
-  'VK_KHR_incremental_present',
-  'VK_KHR_shared_presentable_image',
-  'VK_KHR_surface',
-  'VK_KHR_swapchain',
-  'VK_KHR_get_surface_capabilities2'
+# Extensions intercepted at vulkan::driver level.
+_INTERCEPTED_EXTENSIONS = [
+    'VK_ANDROID_native_buffer',
+    'VK_EXT_debug_report',
+    'VK_EXT_hdr_metadata',
+    'VK_EXT_swapchain_colorspace',
+    'VK_GOOGLE_display_timing',
+    'VK_KHR_android_surface',
+    'VK_KHR_get_surface_capabilities2',
+    'VK_KHR_incremental_present',
+    'VK_KHR_shared_presentable_image',
+    'VK_KHR_surface',
+    'VK_KHR_swapchain',
 ]
 
-knownExtensions = interceptedExtensions + [
-  'VK_KHR_get_physical_device_properties2',
-  'VK_ANDROID_external_memory_android_hardware_buffer',
-  'VK_KHR_bind_memory2'
+# Extensions known to vulkan::driver level.
+_KNOWN_EXTENSIONS = _INTERCEPTED_EXTENSIONS + [
+    'VK_ANDROID_external_memory_android_hardware_buffer',
+    'VK_KHR_bind_memory2',
+    'VK_KHR_get_physical_device_properties2',
 ]
 
-def defineProcHookType(f):
-  f.write ("""struct ProcHook {
+# Functions needed at vulkan::driver level.
+_NEEDED_COMMANDS = [
+    # Create functions of dispatchable objects
+    'vkCreateDevice',
+    'vkGetDeviceQueue',
+    'vkGetDeviceQueue2',
+    'vkAllocateCommandBuffers',
+
+    # Destroy functions of dispatchable objects
+    'vkDestroyInstance',
+    'vkDestroyDevice',
+
+    # Enumeration of extensions
+    'vkEnumerateDeviceExtensionProperties',
+
+    # We cache physical devices in loader.cpp
+    'vkEnumeratePhysicalDevices',
+    'vkEnumeratePhysicalDeviceGroups',
+
+    'vkGetInstanceProcAddr',
+    'vkGetDeviceProcAddr',
+
+    'vkQueueSubmit',
+
+    # VK_KHR_swapchain->VK_ANDROID_native_buffer translation
+    'vkCreateImage',
+    'vkDestroyImage',
+
+    'vkGetPhysicalDeviceProperties',
+    'vkGetPhysicalDeviceProperties2',
+    'vkGetPhysicalDeviceProperties2KHR',
+
+    # VK_KHR_swapchain v69 requirement
+    'vkBindImageMemory2',
+    'vkBindImageMemory2KHR',
+]
+
+# Functions intercepted at vulkan::driver level.
+_INTERCEPTED_COMMANDS = [
+    # Create functions of dispatchable objects
+    'vkCreateInstance',
+    'vkCreateDevice',
+    'vkEnumeratePhysicalDevices',
+    'vkEnumeratePhysicalDeviceGroups',
+    'vkGetDeviceQueue',
+    'vkGetDeviceQueue2',
+    'vkAllocateCommandBuffers',
+
+    # Destroy functions of dispatchable objects
+    'vkDestroyInstance',
+    'vkDestroyDevice',
+
+    # Enumeration of extensions
+    'vkEnumerateInstanceExtensionProperties',
+    'vkEnumerateDeviceExtensionProperties',
+
+    'vkGetInstanceProcAddr',
+    'vkGetDeviceProcAddr',
+
+    'vkQueueSubmit',
+
+    # VK_KHR_swapchain v69 requirement
+    'vkBindImageMemory2',
+    'vkBindImageMemory2KHR',
+]
+
+
+def _is_driver_table_entry(cmd):
+  """Returns true if a function is needed by vulkan::driver.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  if gencom.is_function_supported(cmd):
+    if cmd in _NEEDED_COMMANDS:
+      return True
+    if cmd in gencom.extension_dict:
+      if (gencom.extension_dict[cmd] == 'VK_ANDROID_native_buffer' or
+          gencom.extension_dict[cmd] == 'VK_EXT_debug_report'):
+        return True
+  return False
+
+
+def _is_instance_driver_table_entry(cmd):
+  """Returns true if a instance-dispatched function is needed by vulkan::driver.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  return (_is_driver_table_entry(cmd) and
+          gencom.is_instance_dispatched(cmd))
+
+
+def _is_device_driver_table_entry(cmd):
+  """Returns true if a device-dispatched function is needed by vulkan::driver.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  return (_is_driver_table_entry(cmd) and
+          gencom.is_device_dispatched(cmd))
+
+
+def gen_h():
+  """Generates the driver_gen.h file.
+  """
+  genfile = os.path.join(os.path.dirname(__file__),
+                         '..', 'libvulkan', 'driver_gen.h')
+
+  with open(genfile, 'w') as f:
+    f.write(gencom.copyright_and_warning(2016))
+
+    f.write("""\
+#ifndef LIBVULKAN_DRIVER_GEN_H
+#define LIBVULKAN_DRIVER_GEN_H
+
+#include <vulkan/vk_android_native_buffer.h>
+#include <vulkan/vulkan.h>
+
+#include <bitset>
+
+namespace vulkan {
+namespace driver {
+
+struct ProcHook {
     enum Type {
         GLOBAL,
         INSTANCE,
         DEVICE,
     };
     enum Extension {\n""")
-  for exts in knownExtensions:
-    f.write (gencom.clang_off_spaces*2 + exts[3:] + ',\n')
-  f.write ('\n')
-  f.write (gencom.clang_off_spaces*2 + """EXTENSION_CORE,  // valid bit
+
+    for ext in _KNOWN_EXTENSIONS:
+      f.write(gencom.indent(2) + gencom.base_ext_name(ext) + ',\n')
+
+    f.write('\n')
+    for version in gencom.version_code_list:
+      f.write(gencom.indent(2) + 'EXTENSION_CORE_' + version + ',\n')
+
+    # EXTENSION_COUNT must be the next enum after the highest API version.
+    f.write("""\
         EXTENSION_COUNT,
         EXTENSION_UNKNOWN,
     };
@@ -62,99 +193,33 @@
 
     PFN_vkVoidFunction proc;
     PFN_vkVoidFunction checked_proc;  // always nullptr for non-device hooks
-};\n\n""")
+};
 
-def isExtensionIntercepted(extensionName):
-  if extensionName in interceptedExtensions:
-    return True
-  return False
+struct InstanceDriverTable {
+    // clang-format off\n""")
 
-def isDriverTableEntry(functionName):
-  switchCase = {
-    # Create functions of dispatchable objects
-    'vkCreateDevice' : True,
-    'vkGetDeviceQueue' : True,
-    'vkGetDeviceQueue2' : True,
-    'vkAllocateCommandBuffers' : True,
+    for cmd in gencom.command_list:
+      if _is_instance_driver_table_entry(cmd):
+        f.write(gencom.indent(1) + 'PFN_' + cmd + ' ' +
+                gencom.base_name(cmd) + ';\n')
 
-    # Destroy functions of dispatchable objects
-    'vkDestroyInstance' : True,
-    'vkDestroyDevice' : True,
+    f.write("""\
+    // clang-format on
+};
 
-    # Enumeration of extensions
-    'vkEnumerateDeviceExtensionProperties' : True,
+struct DeviceDriverTable {
+    // clang-format off\n""")
 
-    # We cache physical devices in loader.cpp
-    'vkEnumeratePhysicalDevices' : True,
-    'vkEnumeratePhysicalDeviceGroups' : True,
+    for cmd in gencom.command_list:
+      if _is_device_driver_table_entry(cmd):
+        f.write(gencom.indent(1) + 'PFN_' + cmd + ' ' +
+                gencom.base_name(cmd) + ';\n')
 
-    'vkGetInstanceProcAddr' : True,
-    'vkGetDeviceProcAddr' : True,
+    f.write("""\
+    // clang-format on
+};
 
-    'vkQueueSubmit' : True,
-
-    # VK_KHR_swapchain->VK_ANDROID_native_buffer translation
-    'vkCreateImage' : True,
-    'vkDestroyImage' : True,
-
-    'vkGetPhysicalDeviceProperties' : True,
-    'vkGetPhysicalDeviceProperties2' : True,
-    'vkGetPhysicalDeviceProperties2KHR' : True,
-
-    # VK_KHR_swapchain v69 requirement
-    'vkBindImageMemory2' : True,
-    'vkBindImageMemory2KHR' : True
-  }
-  if gencom.isFunctionSupported(functionName):
-    if functionName in switchCase:
-      return True
-    if functionName in gencom.extensionsDict:
-      if gencom.extensionsDict[functionName] == 'VK_ANDROID_native_buffer' or gencom.extensionsDict[functionName] == 'VK_EXT_debug_report':
-        return True
-  return False
-
-def isInstanceDriverTableEntry(functionName):
-  if isDriverTableEntry(functionName) and gencom.isInstanceDispatched(functionName):
-    return True
-  return False
-
-def isDeviceDriverTableEntry(functionName):
-  if isDriverTableEntry(functionName) and gencom.isDeviceDispatched(functionName):
-    return True
-  return False
-
-def driver_genh():
-  header = """#ifndef LIBVULKAN_DRIVER_GEN_H
-#define LIBVULKAN_DRIVER_GEN_H
-
-#include <vulkan/vk_android_native_buffer.h>
-#include <vulkan/vulkan.h>
-
-#include <bitset>
-
-namespace vulkan {
-namespace driver {\n\n"""
-  genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen.h')
-  with open(genfile, 'w') as f:
-    f.write (gencom.copyright)
-    f.write (gencom.warning)
-    f.write (header)
-    defineProcHookType(f)
-    f.write ('struct InstanceDriverTable {\n')
-    gencom.clang_off(f, 1)
-    for cmds in gencom.allCommandsList:
-      if isInstanceDriverTableEntry(cmds):
-        f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n')
-    gencom.clang_on(f, 1)
-    f.write ('};\n\n')
-    f.write ('struct DeviceDriverTable {\n')
-    gencom.clang_off(f,1)
-    for cmds in gencom.allCommandsList:
-      if isDeviceDriverTableEntry(cmds):
-        f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n')
-    gencom.clang_on(f,1)
-    f.write ('};\n\n')
-    f.write ("""const ProcHook* GetProcHook(const char* name);
+const ProcHook* GetProcHook(const char* name);
 ProcHook::Extension GetProcHookExtension(const char* name);
 
 bool InitDriverTable(VkInstance instance,
@@ -168,148 +233,198 @@
 }  // namespace vulkan
 
 #endif  // LIBVULKAN_DRIVER_TABLE_H\n""")
+
     f.close()
-  gencom.runClangFormat(genfile)
+  gencom.run_clang_format(genfile)
 
-def isIntercepted(functionName):
-  switchCase = {
-    # Create functions of dispatchable objects
-    'vkCreateInstance' : True,
-    'vkCreateDevice' : True,
-    'vkEnumeratePhysicalDevices' : True,
-    'vkEnumeratePhysicalDeviceGroups' : True,
-    'vkGetDeviceQueue' : True,
-    'vkGetDeviceQueue2' : True,
-    'vkAllocateCommandBuffers' : True,
 
-    # Destroy functions of dispatchable objects
-    'vkDestroyInstance' : True,
-    'vkDestroyDevice' : True,
+def _is_intercepted(cmd):
+  """Returns true if a function is intercepted by vulkan::driver.
 
-    # Enumeration of extensions
-    'vkEnumerateInstanceExtensionProperties' : True,
-    'vkEnumerateDeviceExtensionProperties' : True,
+  Args:
+    cmd: Vulkan function name.
+  """
+  if gencom.is_function_supported(cmd):
+    if cmd in _INTERCEPTED_COMMANDS:
+      return True
 
-    'vkGetInstanceProcAddr' : True,
-    'vkGetDeviceProcAddr' : True,
-
-    'vkQueueSubmit' : True,
-
-    # VK_KHR_swapchain v69 requirement
-    'vkBindImageMemory2' : True,
-    'vkBindImageMemory2KHR' : True
-  }
-  if gencom.isFunctionSupported(functionName):
-    if functionName in switchCase:
-      return switchCase[functionName]
-
-    if functionName in gencom.extensionsDict:
-      return isExtensionIntercepted(gencom.extensionsDict[functionName])
+    if cmd in gencom.extension_dict:
+      return gencom.extension_dict[cmd] in _INTERCEPTED_EXTENSIONS
   return False
 
-def needProcHookStub(functionName):
-  if isIntercepted(functionName) and gencom.isDeviceDispatched(functionName):
-    if functionName in gencom.extensionsDict:
-      if not gencom.isExtensionInternal(gencom.extensionsDict[functionName]):
+
+def _get_proc_hook_enum(cmd):
+  """Returns the ProcHook enumeration for the corresponding core function.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  assert cmd in gencom.version_dict
+  for version in gencom.version_code_list:
+    if gencom.version_dict[cmd] == 'VK_VERSION_' + version:
+      return 'ProcHook::EXTENSION_CORE_' + version
+
+
+def _need_proc_hook_stub(cmd):
+  """Returns true if a function needs a ProcHook stub.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  if _is_intercepted(cmd) and gencom.is_device_dispatched(cmd):
+    if cmd in gencom.extension_dict:
+      if not gencom.is_extension_internal(gencom.extension_dict[cmd]):
         return True
+    elif gencom.version_dict[cmd] != 'VK_VERSION_1_0':
+      return True
   return False
 
-def defineInitProc(name, f):
-  f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n')
-  f.write ('\n')
-  f.write ("""#define INIT_PROC(required, obj, proc)                                 \\
-    do {                                                               \\
-        data.""" + name + """.proc =                                             \\
-            reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
-        if (UNLIKELY(required && !data.""" + name + """.proc)) {                 \\
-            ALOGE("missing " #obj " proc: vk" #proc);                  \\
-            success = false;                                           \\
-        }                                                              \\
-    } while (0)\n\n""")
 
-def defineInitProcExt(f):
-  f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc) \\
-    do {                                        \\
-        if (extensions[ProcHook::ext])          \\
-            INIT_PROC(required, obj, proc);     \\
-    } while (0)\n\n""")
+def _define_proc_hook_stub(cmd, f):
+  """Emits a stub for ProcHook::checked_proc.
 
-def defineProcHookStub(functionName, f):
-  if needProcHookStub(functionName):
-    ext_name = gencom.extensionsDict[functionName]
-    base_name = functionName[2:]
-    paramList = [''.join(i) for i in gencom.paramDict[functionName]]
-    p0 = gencom.paramDict[functionName][0][1]
-    f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' checked' + base_name + '(' + ', '.join(paramList) + ') {\n')
-    ext_hook = 'ProcHook::' + ext_name[3:]
+  Args:
+    cmd: Vulkan function name.
+    f: Output file handle.
+  """
+  if _need_proc_hook_stub(cmd):
+    return_type = gencom.return_type_dict[cmd]
 
-    f.write (gencom.clang_off_spaces + 'if (GetData(' + p0 + ').hook_extensions[' + ext_hook + ']) {\n')
-    f.write (gencom.clang_off_spaces *2)
-    if gencom.returnTypeDict[functionName] != 'void':
-      f.write ('return ')
-    paramNames = [''.join(i[1]) for i in gencom.paramDict[functionName]]
-    f.write (base_name + '(' + ', '.join(paramNames) + ');\n')
-    f.write (gencom.clang_off_spaces + '} else {\n')
-    f.write (gencom.clang_off_spaces*2 + 'Logger(' + p0 + ').Err(' + p0 + ', \"' + ext_name + ' not enabled. ' + functionName + ' not executed.\");\n')
-    if gencom.returnTypeDict[functionName] != 'void':
-      f.write (gencom.clang_off_spaces*2 + 'return VK_SUCCESS;\n')
-    f.write (gencom.clang_off_spaces + '}\n')
-    f.write ('}\n\n')
+    ext_name = ''
+    ext_hook = ''
+    if cmd in gencom.extension_dict:
+      ext_name = gencom.extension_dict[cmd]
+      ext_hook = 'ProcHook::' + gencom.base_ext_name(ext_name)
+    else:
+      ext_name = gencom.version_dict[cmd]
+      ext_hook = _get_proc_hook_enum(cmd)
 
-def defineGlobalProcHook(functionName, f):
-  base_name = functionName[2:]
-  assert (functionName not in gencom.extensionsDict)
-  f.write (gencom.clang_off_spaces + '{\n' + gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n' + gencom.clang_off_spaces*2)
-  f.write ("""ProcHook::GLOBAL,
-        ProcHook::EXTENSION_CORE,
-        reinterpret_cast<PFN_vkVoidFunction>(""" + base_name  + """),
+    handle = gencom.param_dict[cmd][0][1]
+    param_types = ', '.join([''.join(i) for i in gencom.param_dict[cmd]])
+    param_names = ', '.join([''.join(i[1]) for i in gencom.param_dict[cmd]])
+
+    f.write('VKAPI_ATTR ' + return_type + ' checked' + gencom.base_name(cmd) +
+            '(' + param_types + ') {\n')
+    f.write(gencom.indent(1) + 'if (GetData(' + handle + ').hook_extensions[' +
+            ext_hook + ']) {\n')
+
+    f.write(gencom.indent(2))
+    if gencom.return_type_dict[cmd] != 'void':
+      f.write('return ')
+    f.write(gencom.base_name(cmd) + '(' + param_names + ');\n')
+
+    f.write(gencom.indent(1) + '} else {\n')
+    f.write(gencom.indent(2) + 'Logger(' + handle + ').Err(' + handle + ', \"' +
+            ext_name + ' not enabled. ' + cmd + ' not executed.\");\n')
+    if gencom.return_type_dict[cmd] != 'void':
+      f.write(gencom.indent(2) + 'return VK_SUCCESS;\n')
+    f.write(gencom.indent(1) + '}\n}\n\n')
+
+
+def _define_global_proc_hook(cmd, f):
+  """Emits definition of a global ProcHook.
+
+  Args:
+    cmd: Vulkan function name.
+    f: Output file handle.
+  """
+  assert cmd not in gencom.extension_dict
+
+  f.write(gencom.indent(1) + '{\n')
+  f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
+  f.write(gencom.indent(2) + 'ProcHook::GLOBAL,\n')
+  f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
+  f.write(gencom.indent(2) + 'reinterpret_cast<PFN_vkVoidFunction>(' +
+          gencom.base_name(cmd) + '),\n')
+  f.write(gencom.indent(2) + 'nullptr,\n')
+  f.write(gencom.indent(1) + '},\n')
+
+
+def _define_instance_proc_hook(cmd, f):
+  """Emits definition of a instance ProcHook.
+
+  Args:
+    cmd: Vulkan function name.
+    f: Output file handle.
+  """
+  f.write(gencom.indent(1) + '{\n')
+  f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
+  f.write(gencom.indent(2) + 'ProcHook::INSTANCE,\n')
+
+  if cmd in gencom.extension_dict:
+    ext_name = gencom.extension_dict[cmd]
+    f.write(gencom.indent(2) + 'ProcHook::' +
+            gencom.base_ext_name(ext_name) + ',\n')
+
+    if gencom.is_extension_internal(ext_name):
+      f.write("""\
         nullptr,
-    },\n""")
-
-def defineInstanceProcHook(functionName, f):
-  base_name = functionName[2:]
-  f.write (gencom.clang_off_spaces + '{\n')
-  f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n')
-  f.write (gencom.clang_off_spaces*2 + 'ProcHook::INSTANCE,\n')
-
-  if functionName in gencom.extensionsDict:
-    ext_name = gencom.extensionsDict[functionName]
-    f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n')
-    if gencom.isExtensionInternal(ext_name):
-      f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
+        nullptr,\n""")
     else:
-      f.write (gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(' + base_name + '),\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
-
+      f.write("""\
+        reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
+        nullptr,\n""")
   else:
-    f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE,
-        reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
+    f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
+    f.write("""\
+        reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
         nullptr,\n""")
 
-  f.write (gencom.clang_off_spaces + '},\n')
+  f.write(gencom.indent(1) + '},\n')
 
-def defineDeviceProcHook(functionName, f):
-  base_name = functionName[2:]
-  f.write (gencom.clang_off_spaces + '{\n')
-  f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n')
-  f.write (gencom.clang_off_spaces*2 + 'ProcHook::DEVICE,\n')
 
-  if functionName in gencom.extensionsDict:
-    ext_name = gencom.extensionsDict[functionName]
-    f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n')
-    if gencom.isExtensionInternal(ext_name):
-      f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
+def _define_device_proc_hook(cmd, f):
+  """Emits definition of a device ProcHook.
+
+  Args:
+    cmd: Vulkan function name.
+    f: Output file handle.
+  """
+  f.write(gencom.indent(1) + '{\n')
+  f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
+  f.write(gencom.indent(2) + 'ProcHook::DEVICE,\n')
+
+  if (cmd in gencom.extension_dict or
+      gencom.version_dict[cmd] != 'VK_VERSION_1_0'):
+    ext_name = ''
+    ext_hook = ''
+    if cmd in gencom.extension_dict:
+      ext_name = gencom.extension_dict[cmd]
+      ext_hook = 'ProcHook::' + gencom.base_ext_name(ext_name)
     else:
-      f.write (gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(' + base_name + '),\n' + gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(checked' + base_name + '),\n')
+      ext_name = gencom.version_dict[cmd]
+      ext_hook = _get_proc_hook_enum(cmd)
+    f.write(gencom.indent(2) + ext_hook + ',\n')
+
+    if gencom.is_extension_internal(ext_name):
+      f.write("""\
+        nullptr,
+        nullptr,\n""")
+    else:
+      f.write("""\
+        reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
+        reinterpret_cast<PFN_vkVoidFunction>(checked""" +
+              gencom.base_name(cmd) + '),\n')
 
   else:
-    f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE,
-        reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
+    f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
+    f.write("""\
+        reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
         nullptr,\n""")
 
-  f.write (gencom.clang_off_spaces + '},\n')
+  f.write(gencom.indent(1) + '},\n')
 
-def driver_gencpp():
-  header = """#include <log/log.h>
+
+def gen_cpp():
+  """Generates the driver_gen.cpp file.
+  """
+  genfile = os.path.join(os.path.dirname(__file__),
+                         '..', 'libvulkan', 'driver_gen.cpp')
+
+  with open(genfile, 'w') as f:
+    f.write(gencom.copyright_and_warning(2016))
+    f.write("""\
+#include <log/log.h>
 #include <string.h>
 
 #include <algorithm>
@@ -321,35 +436,34 @@
 
 namespace {
 
-// clang-format off\n\n"""
+// clang-format off\n\n""")
 
-  genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen.cpp')
+    for cmd in gencom.command_list:
+      _define_proc_hook_stub(cmd, f)
 
-  with open(genfile, 'w') as f:
-    f.write (gencom.copyright)
-    f.write (gencom.warning)
-    f.write (header)
+    f.write("""\
+// clang-format on
 
-    for cmds in gencom.allCommandsList:
-      defineProcHookStub(cmds, f)
-    gencom.clang_on(f, 0)
-    f.write ('\n')
+const ProcHook g_proc_hooks[] = {
+    // clang-format off\n""")
 
-    f.write ('const ProcHook g_proc_hooks[] = {\n')
-    gencom.clang_off(f, 1)
-    sortedCommandsList = sorted(gencom.allCommandsList)
-    for cmds in sortedCommandsList:
-      if isIntercepted(cmds):
-        if gencom.isGloballyDispatched(cmds):
-          defineGlobalProcHook(cmds, f)
-        elif gencom.isInstanceDispatched(cmds):
-          defineInstanceProcHook(cmds, f)
-        elif gencom.isDeviceDispatched(cmds):
-          defineDeviceProcHook(cmds, f)
-    gencom.clang_on(f, 1)
-    f.write ('};\n\n}  // namespace\n\n')
+    sorted_command_list = sorted(gencom.command_list)
+    for cmd in sorted_command_list:
+      if _is_intercepted(cmd):
+        if gencom.is_globally_dispatched(cmd):
+          _define_global_proc_hook(cmd, f)
+        elif gencom.is_instance_dispatched(cmd):
+          _define_instance_proc_hook(cmd, f)
+        elif gencom.is_device_dispatched(cmd):
+          _define_device_proc_hook(cmd, f)
 
-    f.write ("""const ProcHook* GetProcHook(const char* name) {
+    f.write("""\
+    // clang-format on
+};
+
+}  // namespace
+
+const ProcHook* GetProcHook(const char* name) {
     const auto& begin = g_proc_hooks;
     const auto& end =
         g_proc_hooks + sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]);
@@ -357,44 +471,76 @@
         begin, end, name,
         [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; });
     return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr;
-}\n\n""")
+}
 
-    f.write ('ProcHook::Extension GetProcHookExtension(const char* name) {\n')
-    gencom.clang_off(f, 1)
-    for exts in knownExtensions:
-      f.write (gencom.clang_off_spaces + 'if (strcmp(name, \"' + exts + '\") == 0) return ProcHook::' + exts[3:] + ';\n')
-    gencom.clang_on(f, 1)
-    f.write (gencom.clang_off_spaces + 'return ProcHook::EXTENSION_UNKNOWN;\n')
-    f.write ('}\n\n')
+ProcHook::Extension GetProcHookExtension(const char* name) {
+    // clang-format off\n""")
 
-    defineInitProc('driver', f)
-    defineInitProcExt(f)
+    for ext in _KNOWN_EXTENSIONS:
+      f.write(gencom.indent(1) + 'if (strcmp(name, \"' + ext +
+              '\") == 0) return ProcHook::' + gencom.base_ext_name(ext) + ';\n')
 
-    f.write ("""bool InitDriverTable(VkInstance instance,
+    f.write("""\
+    // clang-format on
+    return ProcHook::EXTENSION_UNKNOWN;
+}
+
+#define UNLIKELY(expr) __builtin_expect((expr), 0)
+
+#define INIT_PROC(required, obj, proc)                                 \\
+    do {                                                               \\
+        data.driver.proc =                                             \\
+            reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
+        if (UNLIKELY(required && !data.driver.proc)) {                 \\
+            ALOGE("missing " #obj " proc: vk" #proc);                  \\
+            success = false;                                           \\
+        }                                                              \\
+    } while (0)
+
+#define INIT_PROC_EXT(ext, required, obj, proc) \\
+    do {                                        \\
+        if (extensions[ProcHook::ext])          \\
+            INIT_PROC(required, obj, proc);     \\
+    } while (0)
+
+bool InitDriverTable(VkInstance instance,
                      PFN_vkGetInstanceProcAddr get_proc,
                      const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
     auto& data = GetData(instance);
-    bool success = true;\n\n""")
-    gencom.clang_off(f, 1)
-    for cmds in gencom.allCommandsList:
-      if isInstanceDriverTableEntry(cmds):
-        gencom.initProc(cmds, f)
-    gencom.clang_on(f, 1)
-    f.write ('\n' + gencom.clang_off_spaces + 'return success;\n')
-    f.write ('}\n\n')
+    bool success = true;
 
-    f.write ("""bool InitDriverTable(VkDevice dev,
+    // clang-format off\n""")
+
+    for cmd in gencom.command_list:
+      if _is_instance_driver_table_entry(cmd):
+        gencom.init_proc(cmd, f)
+
+    f.write("""\
+    // clang-format on
+
+    return success;
+}
+
+bool InitDriverTable(VkDevice dev,
                      PFN_vkGetDeviceProcAddr get_proc,
                      const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
     auto& data = GetData(dev);
-    bool success = true;\n\n""")
-    gencom.clang_off(f, 1)
-    for cmds in gencom.allCommandsList:
-      if isDeviceDriverTableEntry(cmds):
-        gencom.initProc(cmds, f)
-    gencom.clang_on(f, 1)
-    f.write ('\n' + gencom.clang_off_spaces + 'return success;\n')
-    f.write ('}\n\n}  // namespace driver\n}  // namespace vulkan\n\n')
-    gencom.clang_on(f, 0)
+    bool success = true;
+
+    // clang-format off\n""")
+
+    for cmd in gencom.command_list:
+      if _is_device_driver_table_entry(cmd):
+        gencom.init_proc(cmd, f)
+
+    f.write("""\
+    // clang-format on
+
+    return success;
+}
+
+}  // namespace driver
+}  // namespace vulkan\n""")
+
     f.close()
-  gencom.runClangFormat(genfile)
+  gencom.run_clang_format(genfile)
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index fe9dab4..cf370fa 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -13,14 +13,109 @@
 # 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.
-#
-# This script provides the common functions for generating the
-# vulkan framework directly from the vulkan registry (vk.xml).
 
-from subprocess import check_call
+"""Provide the utilities for framework generation.
+"""
 
-copyright = """/*
- * Copyright 2016 The Android Open Source Project
+import os
+import subprocess
+import xml.etree.ElementTree as element_tree
+
+# Extensions unsupported on Android.
+_BLACKLISTED_EXTENSIONS = [
+    'VK_EXT_acquire_xlib_display',
+    'VK_EXT_direct_mode_display',
+    'VK_EXT_display_control',
+    'VK_EXT_display_surface_counter',
+    'VK_EXT_full_screen_exclusive',
+    'VK_EXT_headless_surface',
+    'VK_EXT_metal_surface',
+    'VK_FUCHSIA_imagepipe_surface',
+    'VK_GGP_stream_descriptor_surface',
+    'VK_KHR_display',
+    'VK_KHR_display_swapchain',
+    'VK_KHR_external_fence_win32',
+    'VK_KHR_external_memory_win32',
+    'VK_KHR_external_semaphore_win32',
+    'VK_KHR_mir_surface',
+    'VK_KHR_wayland_surface',
+    'VK_KHR_win32_keyed_mutex',
+    'VK_KHR_win32_surface',
+    'VK_KHR_xcb_surface',
+    'VK_KHR_xlib_surface',
+    'VK_MVK_ios_surface',
+    'VK_MVK_macos_surface',
+    'VK_NN_vi_surface',
+    'VK_NV_cooperative_matrix',
+    'VK_NV_coverage_reduction_mode',
+    'VK_NV_external_memory_win32',
+    'VK_NV_win32_keyed_mutex',
+    'VK_NVX_image_view_handle',
+]
+
+# Extensions having functions exported by the loader.
+_EXPORTED_EXTENSIONS = [
+    'VK_ANDROID_external_memory_android_hardware_buffer',
+    'VK_KHR_android_surface',
+    'VK_KHR_surface',
+    'VK_KHR_swapchain',
+]
+
+# Functions optional on Android even if extension is advertised.
+_OPTIONAL_COMMANDS = [
+    'vkGetSwapchainGrallocUsageANDROID',
+    'vkGetSwapchainGrallocUsage2ANDROID',
+]
+
+# Dict for mapping dispatch table to a type.
+_DISPATCH_TYPE_DICT = {
+    'VkInstance ': 'Instance',
+    'VkPhysicalDevice ': 'Instance',
+    'VkDevice ': 'Device',
+    'VkQueue ': 'Device',
+    'VkCommandBuffer ': 'Device'
+}
+
+# Dict for mapping a function to its alias.
+alias_dict = {}
+
+# List of all the Vulkan functions.
+command_list = []
+
+# Dict for mapping a function to an extension.
+extension_dict = {}
+
+# Dict for mapping a function to all its parameters.
+param_dict = {}
+
+# Dict for mapping a function to its return type.
+return_type_dict = {}
+
+# List of the sorted Vulkan version codes. e.g. '1_0', '1_1'.
+version_code_list = []
+
+# Dict for mapping a function to the core Vulkan API version.
+version_dict = {}
+
+
+def indent(num):
+  """Returns the requested indents.
+
+  Args:
+    num: Number of the 4-space indents.
+  """
+  return '    ' * num
+
+
+def copyright_and_warning(year):
+  """Returns the standard copyright and warning codes.
+
+  Args:
+    year: An integer year for the copyright.
+  """
+  return """\
+/*
+ * Copyright """ + str(year) + """ 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.
@@ -35,221 +130,277 @@
  * limitations under the License.
  */
 
+// WARNING: This file is generated. See ../README.md for instructions.
+
 """
 
-warning = '// WARNING: This file is generated. See ../README.md for instructions.\n\n'
 
-blacklistedExtensions = [
-    'VK_KHR_display',
-    'VK_KHR_display_swapchain',
-    'VK_KHR_mir_surface',
-    'VK_KHR_xcb_surface',
-    'VK_KHR_xlib_surface',
-    'VK_KHR_wayland_surface',
-    'VK_KHR_win32_surface',
-    'VK_KHR_external_memory_win32',
-    'VK_KHR_win32_keyed_mutex',
-    'VK_KHR_external_semaphore_win32',
-    'VK_KHR_external_fence_win32',
-    'VK_EXT_acquire_xlib_display',
-    'VK_EXT_direct_mode_display',
-    'VK_EXT_display_surface_counter',
-    'VK_EXT_display_control',
-    'VK_FUCHSIA_imagepipe_surface',
-    'VK_MVK_ios_surface',
-    'VK_MVK_macos_surface',
-    'VK_NN_vi_surface',
-    'VK_NV_external_memory_win32',
-    'VK_NV_win32_keyed_mutex',
-    'VK_EXT_metal_surface', #not present in vulkan.api
-    'VK_NVX_image_view_handle', #not present in vulkan.api
-    'VK_NV_cooperative_matrix', #not present in vulkan.api
-    'VK_EXT_headless_surface', #not present in vulkan.api
-    'VK_GGP_stream_descriptor_surface', #not present in vulkan.api
-    'VK_NV_coverage_reduction_mode', #not present in vulkan.api
-    'VK_EXT_full_screen_exclusive' #not present in vulkan.api
-]
+def run_clang_format(args):
+  """Run clang format on the file.
 
-exportedExtensions = [
-    'VK_KHR_surface',
-    'VK_KHR_swapchain',
-    'VK_KHR_android_surface',
-    'VK_ANDROID_external_memory_android_hardware_buffer'
-]
+  Args:
+    args: The file to be formatted.
+  """
+  clang_call = ['clang-format', '--style', 'file', '-i', args]
+  subprocess.check_call(clang_call)
 
-def runClangFormat(args):
-  clang_call = ["clang-format", "--style", "file", "-i", args]
-  check_call (clang_call)
 
-def isExtensionInternal(extensionName):
-  if extensionName == 'VK_ANDROID_native_buffer':
-    return True
-  return False
+def is_extension_internal(ext):
+  """Returns true if an extension is internal to the loader and drivers.
 
-def isFunctionSupported(functionName):
-  if functionName not in extensionsDict:
+  The loader should not enumerate this extension.
+
+  Args:
+    ext: Vulkan extension name.
+  """
+  return ext == 'VK_ANDROID_native_buffer'
+
+
+def base_name(cmd):
+  """Returns a function name without the 'vk' prefix.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  return cmd[2:]
+
+
+def base_ext_name(ext):
+  """Returns an extension name without the 'VK_' prefix.
+
+  Args:
+    ext: Vulkan extension name.
+  """
+  return ext[3:]
+
+
+def version_code(version):
+  """Returns the version code from a version string.
+
+  Args:
+    version: Vulkan version string.
+  """
+  return version[11:]
+
+
+def is_function_supported(cmd):
+  """Returns true if a function is core or from a supportable extension.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  if cmd not in extension_dict:
     return True
   else:
-    if extensionsDict[functionName] not in blacklistedExtensions:
+    if extension_dict[cmd] not in _BLACKLISTED_EXTENSIONS:
       return True
   return False
 
-def isInstanceDispatched(functionName):
-  return isFunctionSupported(functionName) and getDispatchTableType(functionName) == 'Instance'
 
-def isDeviceDispatched(functionName):
-  return isFunctionSupported(functionName) and getDispatchTableType(functionName) == 'Device'
+def get_dispatch_table_type(cmd):
+  """Returns the dispatch table type for a function.
 
-def isGloballyDispatched(functionName):
-  return isFunctionSupported(functionName) and getDispatchTableType(functionName) == 'Global'
-
-def isExtensionExported(extensionName):
-  if extensionName in exportedExtensions:
-    return True
-  return False
-
-def isFunctionExported(functionName):
-  if isFunctionSupported(functionName):
-    if functionName in extensionsDict:
-      return isExtensionExported(extensionsDict[functionName])
-    return True
-  return False
-
-def getDispatchTableType(functionName):
-  if functionName not in paramDict:
+  Args:
+    cmd: Vulkan function name.
+  """
+  if cmd not in param_dict:
     return None
 
-  switchCase = {
-      'VkInstance ' : 'Instance',
-      'VkPhysicalDevice ' : 'Instance',
-      'VkDevice ' : 'Device',
-      'VkQueue ' : 'Device',
-      'VkCommandBuffer ' : 'Device'
-  }
-
-  if len(paramDict[functionName]) > 0:
-    return switchCase.get(paramDict[functionName][0][0], 'Global')
+  if param_dict[cmd]:
+    return _DISPATCH_TYPE_DICT.get(param_dict[cmd][0][0], 'Global')
   return 'Global'
 
-def isInstanceDispatchTableEntry(functionName):
-  if functionName == 'vkEnumerateDeviceLayerProperties': # deprecated, unused internally - @dbd33bc
+
+def is_globally_dispatched(cmd):
+  """Returns true if the function is global, which is not dispatched.
+
+  Only global functions and functions handled in the loader top without calling
+  into lower layers are not dispatched.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  return is_function_supported(cmd) and get_dispatch_table_type(cmd) == 'Global'
+
+
+def is_instance_dispatched(cmd):
+  """Returns true for functions that can have instance-specific dispatch.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  return (is_function_supported(cmd) and
+          get_dispatch_table_type(cmd) == 'Instance')
+
+
+def is_device_dispatched(cmd):
+  """Returns true for functions that can have device-specific dispatch.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  return is_function_supported(cmd) and get_dispatch_table_type(cmd) == 'Device'
+
+
+def is_extension_exported(ext):
+  """Returns true if an extension has functions exported by the loader.
+
+  E.g. applications can directly link to an extension function.
+
+  Args:
+    ext: Vulkan extension name.
+  """
+  return ext in _EXPORTED_EXTENSIONS
+
+
+def is_function_exported(cmd):
+  """Returns true if a function is exported from the Android Vulkan library.
+
+  Functions in the core API and in loader extensions are exported.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  if is_function_supported(cmd):
+    if cmd in extension_dict:
+      return is_extension_exported(extension_dict[cmd])
+    return True
+  return False
+
+
+def is_instance_dispatch_table_entry(cmd):
+  """Returns true if a function is exported and instance-dispatched.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  if cmd == 'vkEnumerateDeviceLayerProperties':
+    # deprecated, unused internally - @dbd33bc
     return False
-  if isFunctionExported(functionName) and isInstanceDispatched(functionName):
-    return True
-  return False
-
-def isDeviceDispatchTableEntry(functionName):
-  if isFunctionExported(functionName) and isDeviceDispatched(functionName):
-    return True
-  return False
+  return is_function_exported(cmd) and is_instance_dispatched(cmd)
 
 
-def clang_on(f, indent):
-  f.write (clang_off_spaces * indent + '// clang-format on\n')
+def is_device_dispatch_table_entry(cmd):
+  """Returns true if a function is exported and device-dispatched.
 
-def clang_off(f, indent):
-  f.write (clang_off_spaces * indent + '// clang-format off\n')
+  Args:
+    cmd: Vulkan function name.
+  """
+  return is_function_exported(cmd) and is_device_dispatched(cmd)
 
-clang_off_spaces = ' ' * 4
 
-parametersList = []
-paramDict = {}
-allCommandsList = []
-extensionsDict = {}
-returnTypeDict = {}
-versionDict = {}
-aliasDict = {}
+def init_proc(name, f):
+  """Emits code to invoke INIT_PROC or INIT_PROC_EXT.
 
-def parseVulkanRegistry():
-  import xml.etree.ElementTree as ET
-  import os
-  vulkan_registry = os.path.join(os.path.dirname(__file__),'..','..','..','..','external','vulkan-headers','registry','vk.xml')
-  tree = ET.parse(vulkan_registry)
+  Args:
+    name: Vulkan function name.
+    f: Output file handle.
+  """
+  f.write(indent(1))
+  if name in extension_dict:
+    f.write('INIT_PROC_EXT(' + base_ext_name(extension_dict[name]) + ', ')
+  else:
+    f.write('INIT_PROC(')
+
+  if name in version_dict and version_dict[name] == 'VK_VERSION_1_1':
+    f.write('false, ')
+  elif name in _OPTIONAL_COMMANDS:
+    f.write('false, ')
+  else:
+    f.write('true, ')
+
+  if is_instance_dispatched(name):
+    f.write('instance, ')
+  else:
+    f.write('dev, ')
+
+  f.write(base_name(name) + ');\n')
+
+
+def parse_vulkan_registry():
+  """Parses Vulkan registry into the below global variables.
+
+  alias_dict
+  command_list
+  extension_dict
+  param_dict
+  return_type_dict
+  version_code_list
+  version_dict
+  """
+  registry = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..',
+                          'external', 'vulkan-headers', 'registry', 'vk.xml')
+  tree = element_tree.parse(registry)
   root = tree.getroot()
   for commands in root.iter('commands'):
     for command in commands:
       if command.tag == 'command':
-        parametersList.clear()
+        parameter_list = []
         protoset = False
-        fnName = ""
-        fnType = ""
-        if command.get('alias') != None:
+        cmd_name = ''
+        cmd_type = ''
+        if command.get('alias') is not None:
           alias = command.get('alias')
-          fnName = command.get('name')
-          aliasDict[fnName] = alias
-          allCommandsList.append(fnName)
-          paramDict[fnName] = paramDict[alias].copy()
-          returnTypeDict[fnName] = returnTypeDict[alias]
+          cmd_name = command.get('name')
+          alias_dict[cmd_name] = alias
+          command_list.append(cmd_name)
+          param_dict[cmd_name] = param_dict[alias].copy()
+          return_type_dict[cmd_name] = return_type_dict[alias]
         for params in command:
           if params.tag == 'param':
-            paramtype = ""
-            if params.text != None and params.text.strip() != '':
-              paramtype = params.text.strip() + ' '
-            typeval = params.find('type')
-            paramtype = paramtype + typeval.text
-            if typeval.tail != None:
-              paramtype += typeval.tail.strip() + ' '
+            param_type = ''
+            if params.text is not None and params.text.strip():
+              param_type = params.text.strip() + ' '
+            type_val = params.find('type')
+            param_type = param_type + type_val.text
+            if type_val.tail is not None:
+              param_type += type_val.tail.strip() + ' '
             pname = params.find('name')
-            paramname = pname.text
-            if pname.tail != None and pname.tail.strip() != '':
-              parametersList.append((paramtype, paramname, pname.tail.strip()))
+            param_name = pname.text
+            if pname.tail is not None and pname.tail.strip():
+              parameter_list.append(
+                  (param_type, param_name, pname.tail.strip()))
             else:
-              parametersList.append((paramtype, paramname))
+              parameter_list.append((param_type, param_name))
           if params.tag == 'proto':
             for c in params:
               if c.tag == 'type':
-                fnType = c.text
+                cmd_type = c.text
               if c.tag == 'name':
-                fnName = c.text
+                cmd_name = c.text
                 protoset = True
-                allCommandsList.append(fnName)
-                returnTypeDict[fnName] = fnType
-        if protoset == True:
-          paramDict[fnName] = parametersList.copy()
+                command_list.append(cmd_name)
+                return_type_dict[cmd_name] = cmd_type
+        if protoset:
+          param_dict[cmd_name] = parameter_list.copy()
 
   for exts in root.iter('extensions'):
     for extension in exts:
-      apiversion = ""
+      apiversion = ''
       if extension.tag == 'extension':
         extname = extension.get('name')
         for req in extension:
-          if req.get('feature') != None:
+          if req.get('feature') is not None:
             apiversion = req.get('feature')
           for commands in req:
             if commands.tag == 'command':
-              commandname = commands.get('name')
-              if commandname not in extensionsDict:
-                extensionsDict[commandname] = extname
-                if apiversion != "":
-                  versionDict[commandname] = apiversion
+              cmd_name = commands.get('name')
+              if cmd_name not in extension_dict:
+                extension_dict[cmd_name] = extname
+                if apiversion:
+                  version_dict[cmd_name] = apiversion
 
   for feature in root.iter('feature'):
     apiversion = feature.get('name')
     for req in feature:
       for command in req:
         if command.tag == 'command':
-          cmdName = command.get('name')
-          if cmdName in allCommandsList:
-            versionDict[cmdName] = apiversion
+          cmd_name = command.get('name')
+          if cmd_name in command_list:
+            version_dict[cmd_name] = apiversion
 
-
-def initProc(name, f):
-  if name in extensionsDict:
-    f.write ('    INIT_PROC_EXT(' + extensionsDict[name][3:] + ', ')
-  else:
-    f.write ('    INIT_PROC(')
-
-  if name in versionDict and versionDict[name] == 'VK_VERSION_1_1':
-    f.write('false, ')
-  elif name == 'vkGetSwapchainGrallocUsageANDROID' or name == 'vkGetSwapchainGrallocUsage2ANDROID': # optional in vulkan.api
-    f.write('false, ')
-  else:
-    f.write('true, ')
-
-  if isInstanceDispatched(name):
-    f.write('instance, ')
-  else:
-    f.write('dev, ')
-
-  f.write(name[2:] + ');\n')
-
+  version_code_set = set()
+  for version in version_dict.values():
+    version_code_set.add(version_code(version))
+  for code in sorted(version_code_set):
+    version_code_list.append(code)
diff --git a/vulkan/scripts/null_generator.py b/vulkan/scripts/null_generator.py
index ee8762e..e9faef6 100644
--- a/vulkan/scripts/null_generator.py
+++ b/vulkan/scripts/null_generator.py
@@ -13,49 +13,43 @@
 # 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.
-#
-# This script provides the functions for generating the null driver
-# framework directly from the vulkan registry (vk.xml).
 
-import generator_common as gencom
-import os
-
-copyright = """/*
- * Copyright 2015 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.
- */
-
+"""Generates the null_driver_gen.h and null_driver_gen.cpp.
 """
 
-def isDriverExtension(extensionName):
-  switchCase = {
-    'VK_ANDROID_native_buffer' : True,
-    'VK_EXT_debug_report' : True,
-    'VK_KHR_get_physical_device_properties2' : True
-  }
+import os
+import generator_common as gencom
 
-  if extensionName in switchCase:
-    return switchCase[extensionName]
-  return False
+# Extensions implemented by the driver.
+_DRIVER_EXTENSION_DICT = {
+    'VK_ANDROID_native_buffer',
+    'VK_EXT_debug_report',
+    'VK_KHR_get_physical_device_properties2'
+}
 
-def isDriverFunction(functionName):
-  if functionName in gencom.extensionsDict:
-    return isDriverExtension(gencom.extensionsDict[functionName])
+
+def _is_driver_function(cmd):
+  """Returns true if the function is implemented by the driver.
+
+  Args:
+    cmd: Vulkan function name.
+  """
+  if cmd in gencom.extension_dict:
+    return gencom.extension_dict[cmd] in _DRIVER_EXTENSION_DICT
   return True
 
-def null_driver_genh():
-  header = """#ifndef NULLDRV_NULL_DRIVER_H
+
+def gen_h():
+  """Generates the null_driver_gen.h file.
+  """
+  genfile = os.path.join(os.path.dirname(__file__),
+                         '..', 'nulldrv', 'null_driver_gen.h')
+
+  with open(genfile, 'w') as f:
+    f.write(gencom.copyright_and_warning(2015))
+
+    f.write("""\
+#ifndef NULLDRV_NULL_DRIVER_H
 #define NULLDRV_NULL_DRIVER_H 1
 
 #include <vulkan/vk_android_native_buffer.h>
@@ -66,30 +60,36 @@
 PFN_vkVoidFunction GetGlobalProcAddr(const char* name);
 PFN_vkVoidFunction GetInstanceProcAddr(const char* name);
 
-"""
-  genfile = os.path.join(os.path.dirname(__file__),'..','nulldrv','null_driver_gen.h')
-  with open(genfile, 'w') as f:
-    f.write (copyright)
-    f.write (gencom.warning)
-    f.write (header)
-    gencom.clang_off(f,0)
+// clang-format off\n""")
 
-    for cmds in gencom.allCommandsList:
-      if isDriverFunction(cmds):
-        paramList = [''.join(i) for i in gencom.paramDict[cmds]]
-        f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' +', '.join(paramList) + ');\n')
-    f.write ("""VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
-VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
-VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);\n""")
-    gencom.clang_on(f,0)
+    for cmd in gencom.command_list:
+      if _is_driver_function(cmd):
+        param_list = [''.join(i) for i in gencom.param_dict[cmd]]
+        f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
+                gencom.base_name(cmd) + '(' + ', '.join(param_list) + ');\n')
 
-    f.write ('\n}  // namespace null_driver\n')
-    f.write ('\n#endif  // NULLDRV_NULL_DRIVER_H\n')
+    f.write("""\
+// clang-format on
+
+}  // namespace null_driver
+
+#endif  // NULLDRV_NULL_DRIVER_H\n""")
+
     f.close()
-  gencom.runClangFormat(genfile)
+  gencom.run_clang_format(genfile)
 
-def null_driver_gencpp():
-  header = """#include <algorithm>
+
+def gen_cpp():
+  """Generates the null_driver_gen.cpp file.
+  """
+  genfile = os.path.join(os.path.dirname(__file__),
+                         '..', 'nulldrv', 'null_driver_gen.cpp')
+
+  with open(genfile, 'w') as f:
+    f.write(gencom.copyright_and_warning(2015))
+
+    f.write("""\
+#include <algorithm>
 
 #include "null_driver_gen.h"
 
@@ -119,30 +119,36 @@
 }
 
 const NameProc kGlobalProcs[] = {
-"""
-  genfile = os.path.join(os.path.dirname(__file__),'..','nulldrv','null_driver_gen.cpp')
-  with open(genfile, 'w') as f:
-    f.write (copyright)
-    f.write (gencom.warning)
-    f.write (header)
-    gencom.clang_off(f,1)
+    // clang-format off\n""")
 
-    sortedCommandsList = sorted(gencom.allCommandsList)
-    for cmds in sortedCommandsList:
-      if isDriverFunction(cmds) and gencom.getDispatchTableType(cmds) == 'Global':
-        f.write (gencom.clang_off_spaces + '{\"' + cmds + '\", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_' + cmds + '>(' + cmds[2:] + '))},\n')
-    gencom.clang_on(f,1)
-    f.write ('};\n\n')
+    sorted_command_list = sorted(gencom.command_list)
+    for cmd in sorted_command_list:
+      if (_is_driver_function(cmd) and
+          gencom.get_dispatch_table_type(cmd) == 'Global'):
+        f.write(gencom.indent(1) + '{\"' + cmd +
+                '\", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_' +
+                cmd + '>(' + gencom.base_name(cmd) + '))},\n')
 
-    f.write ('const NameProc kInstanceProcs[] = {\n')
-    gencom.clang_off(f,1)
-    for cmds in sortedCommandsList:
-      if isDriverFunction(cmds):
-        f.write (gencom.clang_off_spaces + '{\"' + cmds + '\", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_' + cmds + '>(' + cmds[2:] + '))},\n')
-    gencom.clang_on(f,1)
-    f.write ('};\n\n}  // namespace\n\n')
+    f.write("""\
+    // clang-format on
+};
 
-    f.write ("""namespace null_driver {
+const NameProc kInstanceProcs[] = {
+    // clang-format off\n""")
+
+    for cmd in sorted_command_list:
+      if _is_driver_function(cmd):
+        f.write(gencom.indent(1) + '{\"' + cmd +
+                '\", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_' +
+                cmd + '>(' + gencom.base_name(cmd) + '))},\n')
+
+    f.write("""\
+    // clang-format on
+};
+
+}  // namespace
+
+namespace null_driver {
 
 PFN_vkVoidFunction GetGlobalProcAddr(const char* name) {
     return Lookup(name, kGlobalProcs);
@@ -153,6 +159,6 @@
 }
 
 }  // namespace null_driver\n""")
-    f.close()
-  gencom.runClangFormat(genfile)
 
+    f.close()
+  gencom.run_clang_format(genfile)