Merge "Fix foldable emulator touch does not work"
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/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 657dfb6..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"));
@@ -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");
 }
 
@@ -960,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) {
@@ -1905,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"
@@ -1915,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");
 }
@@ -1976,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",
@@ -2103,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()) {
@@ -2141,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) {
@@ -2174,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) {
@@ -2238,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:
@@ -2249,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);
@@ -2338,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);
@@ -2346,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,
@@ -2364,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);
 }
 
@@ -2383,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
@@ -2409,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;
 }
 
@@ -2418,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;
     }
 
@@ -2426,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;
@@ -2526,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);
@@ -2571,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());
 
@@ -2599,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());
             }
@@ -2698,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
@@ -2746,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();
@@ -2776,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));
@@ -2810,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();
@@ -3676,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 fbb01f5..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,8 +205,6 @@
         // 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();
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/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 9344368..934646d 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -165,7 +165,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);
     }
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/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 e5646ef..2a140f4 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -73,7 +73,6 @@
     // or dessert updates. Instead, apex users should use libbinder_ndk.
     apex_available: [
         "//apex_available:platform",
-        "com.android.vndk.current",
         // TODO(b/139016109) remove these three
         "com.android.media.swcodec",
         "test_com.android.media.swcodec",
@@ -165,3 +164,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/Parcel.cpp b/libs/binder/Parcel.cpp
index 7d9846a..323e079 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -505,7 +505,7 @@
     }
 }
 
-#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
+#if 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');
@@ -2562,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 6971c72..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.");
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..471b63f 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
diff --git a/libs/binder/fuzzer/binder.cpp b/libs/binder/fuzzer/binder.cpp
index 04fe0e7..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),
@@ -148,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),
@@ -239,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/main.cpp b/libs/binder/fuzzer/main.cpp
index 3b7caea..6657edb 100644
--- a/libs/binder/fuzzer/main.cpp
+++ b/libs/binder/fuzzer/main.cpp
@@ -77,6 +77,10 @@
 
 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/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/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 b2f51d3..2894482 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -81,7 +81,7 @@
         VINTF = 0b111111,
     };
 
-#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
+#if 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/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..dc3c8d2 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -201,7 +201,22 @@
     /**
      * See AStatus_isOk.
      */
-    bool isOk() { return get() != nullptr && AStatus_isOk(get()); }
+    bool isOk() const { return get() != nullptr && AStatus_isOk(get()); }
+
+    /**
+     * 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()); }
 
     /**
      * Convenience method for okay status.
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index 924812e..e1a8cfd 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -20,8 +20,21 @@
 
 __BEGIN_DECLS
 
-#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || \
-        (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_VNDK__) && !defined(__ANDROID_APEX__))
+
+enum {
+    FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_VENDOR,
+};
 
 /**
  * This interface has the stability of the vendor image.
@@ -32,8 +45,11 @@
     AIBinder_markVendorStability(binder);
 }
 
-#else  // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) &&
-       // !defined(__ANDROID_APEX__))
+#else  // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+
+enum {
+    FLAG_PRIVATE_LOCAL = 0,
+};
 
 /**
  * This interface has the stability of the system image.
@@ -44,8 +60,7 @@
     AIBinder_markSystemStability(binder);
 }
 
-#endif  // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) &&
-        // !defined(__ANDROID_APEX__))
+#endif  // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
 
 /**
  * This interface has system<->vendor stability
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/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl b/libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl
similarity index 66%
rename from cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
rename to libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl
index 7f74ceb..3a5bd9c 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
+++ b/libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
+/*
+ * 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
+ *      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,
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-package android.os;
-
-/**
-  * Token used by the IDumpstateListener to watch for dumpstate death.
-  * {@hide}
-  */
-interface IDumpstateToken {
+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/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 3a369cd..9a50175 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -64,7 +64,7 @@
                                                    : Fence::NO_FENCE);
         mNextCallbackBufferItem = BufferItem();
     }
-    mDequeueWaitCV.notify_one();
+    mDequeueWaitCV.notify_all();
     decStrong((void*)transactionCallbackThunk);
 }
 
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/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/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index a5f115e..db1ac24 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -18,8 +18,14 @@
 
 #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>
 
@@ -27,10 +33,8 @@
 
 namespace android {
 
-const int DEFAULT_WIDTH = 100;
-const int DEFAULT_HEIGHT = 100;
-
 using Transaction = SurfaceComposerClient::Transaction;
+using android::hardware::graphics::common::V1_2::BufferUsage;
 
 class BLASTBufferQueueHelper {
 public:
@@ -47,12 +51,24 @@
     }
 
     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;
 };
@@ -73,39 +89,149 @@
     }
 
     void SetUp() {
+        mComposer = ComposerService::getComposerService();
         mClient = new SurfaceComposerClient();
-        mSurfaceControl = mClient->createSurface(String8("TestSurface"), DEFAULT_WIDTH,
-                                                 DEFAULT_HEIGHT, PIXEL_FORMAT_RGBA_8888);
+        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, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
     ASSERT_EQ(mSurfaceControl, adapter.getSurfaceControl());
-    ASSERT_EQ(DEFAULT_WIDTH, adapter.getWidth());
-    ASSERT_EQ(DEFAULT_HEIGHT, adapter.getHeight());
+    ASSERT_EQ(mDisplayWidth, adapter.getWidth());
+    ASSERT_EQ(mDisplayHeight, adapter.getHeight());
     ASSERT_EQ(nullptr, adapter.getNextTransaction());
 }
 
 TEST_F(BLASTBufferQueueTest, Update) {
-    BLASTBufferQueueHelper adapter(mSurfaceControl, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
     sp<SurfaceControl> updateSurface =
-            mClient->createSurface(String8("UpdateTest"), DEFAULT_WIDTH / 2, DEFAULT_HEIGHT / 2,
-                                   PIXEL_FORMAT_RGB_888);
-    adapter.update(updateSurface, DEFAULT_WIDTH / 2, DEFAULT_HEIGHT / 2);
+            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(DEFAULT_WIDTH / 2, adapter.getWidth());
-    ASSERT_EQ(DEFAULT_HEIGHT / 2, adapter.getHeight());
+    ASSERT_EQ(mDisplayWidth / 2, adapter.getWidth());
+    ASSERT_EQ(mDisplayHeight / 2, adapter.getHeight());
 }
 
 TEST_F(BLASTBufferQueueTest, SetNextTransaction) {
-    BLASTBufferQueueHelper adapter(mSurfaceControl, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+    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/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 b8cf0ea..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);
 
@@ -457,10 +455,9 @@
 }
 
 void GLESRenderEngine::primeCache() const {
-    ProgramCache::getInstance().primeCache(
-            mInProtectedContext ? mProtectedEGLContext : mEGLContext,
-                    mFeatureFlags & USE_COLOR_MANAGEMENT,
-                    mFeatureFlags & PRECACHE_TONE_MAPPER_SHADER_ONLY);
+    ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext,
+                                           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/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 9dcd510..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,19 +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,
-
-        // Only precache HDR to SDR tone-mapping shaders
-        PRECACHE_TONE_MAPPER_SHADER_ONLY = 1 << 3,
+    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;
 
@@ -173,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,
@@ -206,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/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..9c600a8 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,16 @@
 
     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 (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 +160,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..4bbc549
--- /dev/null
+++ b/libs/ui/tests/GraphicBufferAllocator_test.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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, AllocateBadStride) {
+    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/ui/tests/mock/MockGrallocAllocator.cpp b/libs/ui/tests/mock/MockGrallocAllocator.cpp
new file mode 100644
index 0000000..d71e25f
--- /dev/null
+++ b/libs/ui/tests/mock/MockGrallocAllocator.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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 "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/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 ee8c344..d8cf8dd 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -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),
@@ -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,14 +390,14 @@
             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;
         }
 
@@ -407,15 +407,15 @@
                 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,7 +442,7 @@
     }
 
     if (done) {
-        if (dropReason != DROP_REASON_NOT_DROPPED) {
+        if (dropReason != DropReason::NOT_DROPPED) {
             dropInboundEventLocked(mPendingEvent, dropReason);
         }
         mLastDropReason = dropReason;
@@ -594,35 +594,36 @@
 void InputDispatcher::dropInboundEventLocked(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) {
@@ -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;
@@ -926,9 +927,9 @@
     }
 
     // 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;
     }
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 1f906e4..9d22e2c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -113,14 +113,13 @@
     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;
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/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index b500ad3..603a9f7 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);
 
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index d80a70e..8cc1831 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,11 +372,17 @@
 // Interface implementation for BufferLayerConsumer::ContentsChangedListener
 // -----------------------------------------------------------------------
 
+void BufferQueueLayer::onFrameDequeued(const uint64_t bufferId) {
+    const int32_t layerID = getSequence();
+    mFlinger->mFrameTracer->traceTimestamp(layerID, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER,
+                                           systemTime(), FrameTracer::FrameEvent::DEQUEUE, 3000);
+}
+
 void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
     const int32_t layerID = getSequence();
     mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str());
     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
@@ -398,7 +404,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 +432,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 +465,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,9 +535,7 @@
 }
 
 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 = mFlinger->getFactory().createBufferQueueLayer(args);
     layer->setInitialValuesForClone(this);
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index f3e8a19..95e0b10 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -93,6 +93,7 @@
     void onFrameAvailable(const BufferItem& item) override;
     void onFrameReplaced(const BufferItem& item) override;
     void onSidebandStreamChanged() override;
+    void onFrameDequeued(const uint64_t bufferId) override;
     // -----------------------------------------------------------------------
 
 public:
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 75fc0e9..85d2253 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) {
@@ -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,9 +672,7 @@
 }
 
 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 = mFlinger->getFactory().createBufferStateLayer(args);
     layer->mHwcSlotGenerator = mHwcSlotGenerator;
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 172d445..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 = mFlinger->getFactory().createColorLayer(
-            LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata()));
+            LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0,
+                              LayerMetadata()));
     layer->setInitialValuesForClone(this);
     return layer;
 }
 
-// ---------------------------------------------------------------------------
-
-}; // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index e58e6f4..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 = mFlinger->getFactory().createContainerLayer(
-            LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata()));
+            LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0,
+                              LayerMetadata()));
     layer->setInitialValuesForClone(this);
     return layer;
 }
+
 } // namespace android
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 7065460..37caab2 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;
@@ -137,11 +135,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 +233,6 @@
 // set-up
 // ---------------------------------------------------------------------------
 
-const String8& Layer::getName() const {
-    return mName;
-}
-
 bool Layer::getPremultipledAlpha() const {
     return mPremultipliedAlpha;
 }
@@ -523,7 +517,7 @@
 }
 
 const char* Layer::getDebugName() const {
-    return mName.string();
+    return mName.c_str();
 }
 
 // ---------------------------------------------------------------------------
@@ -614,7 +608,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 +632,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 +640,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 +651,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 +659,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 +711,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,
@@ -999,9 +993,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 +1191,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 +1264,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 +1316,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..ad81920 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;
@@ -804,7 +803,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 +819,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;
 
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..30027de 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -436,7 +436,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..5473db6 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -40,7 +40,7 @@
 LayerHistory::LayerHistory() {
     char value[PROPERTY_VALUE_MAX];
     property_get("debug.sf.layer_history_trace", value, "0");
-    mTraceEnabled = bool(atoi(value));
+    mTraceEnabled = static_cast<bool>(atoi(value));
 }
 
 LayerHistory::~LayerHistory() = default;
@@ -128,19 +128,23 @@
 
     // 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;
+        const bool recent = layerInfo->isRecentlyActive();
+        if (recent || CC_UNLIKELY(mTraceEnabled)) {
+            const float refreshRate = layerInfo->getDesiredRefreshRate();
+            if (recent && refreshRate > newRefreshRate) {
+                newRefreshRate = refreshRate;
+            }
+
+            if (CC_UNLIKELY(mTraceEnabled)) {
+                std::string name = "LFPS " + layerInfo->getName();
+                const float rate = std::round(refreshRate);
+                ATRACE_INT(name.c_str(), rate);
+                ALOGD("%s: %f", name.c_str(), rate);
+            }
         }
         isHDR |= layerInfo->getHDRContent();
     }
-    if (mTraceEnabled) {
+    if (CC_UNLIKELY(mTraceEnabled)) {
         ALOGD("LayerHistory DesiredRefreshRate: %.2f", newRefreshRate);
     }
 
@@ -158,7 +162,7 @@
             (!it->second->getHDRContent() && it->second->getLastUpdatedTime() < obsoleteEpsilon)) {
             // erase() function returns the iterator of the next
             // to last deleted element.
-            if (mTraceEnabled) {
+            if (CC_UNLIKELY(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();
@@ -189,4 +193,4 @@
 }
 
 } // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
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 54e2065..057669b 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;
@@ -599,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.");
@@ -1911,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));
         }
     });
 
@@ -2574,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()) {
@@ -3244,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);
@@ -3406,7 +3407,7 @@
 
     sp<Layer> mirrorLayer;
     sp<Layer> mirrorFrom;
-    String8 uniqueName = getUniqueLayerName(String8("MirrorRoot"));
+    std::string uniqueName = getUniqueLayerName("MirrorRoot");
 
     {
         Mutex::Autolock _l(mStateLock);
@@ -3415,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;
         }
@@ -3447,7 +3448,7 @@
 
     sp<Layer> layer;
 
-    String8 uniqueName = getUniqueLayerName(name);
+    std::string uniqueName = getUniqueLayerName(name.string());
 
     bool primaryDisplayOnly = false;
 
@@ -3463,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.
@@ -3479,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.
@@ -3489,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;
@@ -3517,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,
@@ -3563,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
@@ -3585,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);
@@ -3600,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;
@@ -3828,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,
@@ -3885,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 {
@@ -3894,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);
             }
         });
@@ -3904,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();
         }
     });
@@ -3924,7 +3920,7 @@
         layer->logFrameStats();
     });
 
-    mAnimFrameTracker.logAndResetStats(String8("<win-anim>"));
+    mAnimFrameTracker.logAndResetStats("<win-anim>");
 }
 
 void SurfaceFlinger::appendSfConfigString(std::string& result) const {
@@ -3982,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) {
@@ -5031,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();
@@ -5454,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",
@@ -5462,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);
         }
     }));
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9f3a914..b719245 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -607,27 +607,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
@@ -866,8 +866,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
index f0457e3..4f439da 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -17,12 +17,14 @@
 #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"
@@ -92,6 +94,18 @@
     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);
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 89e0679..42bb177 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -42,6 +42,12 @@
     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;
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/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/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 2183d34..f85da20 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -53,6 +53,7 @@
         "TimeStatsTest.cpp",
         "FrameTracerTest.cpp",
         "TransactionApplicationTest.cpp",
+        "StrongTypingTest.cpp",
         "mock/DisplayHardware/MockComposer.cpp",
         "mock/DisplayHardware/MockDisplay.cpp",
         "mock/DisplayHardware/MockPowerAdvisor.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 8aff096..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);
                 });
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/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index b85c1b6..c7664fb 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -62,23 +62,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 +84,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 +138,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;
     }
 
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 f676573..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,
     },
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index cd7d8f8..43c4d14 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -49,7 +49,8 @@
         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..758ab25 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <sys/prctl.h>
 
+#include <memory>
 #include <mutex>
 #include <string>
 #include <vector>
@@ -38,13 +39,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 +96,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,17 +219,10 @@
     }
 
     // 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);
-    if (result != VK_SUCCESS) {
-        ALOGE("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
-              path_.c_str(), result);
-        return false;
-    }
+    auto properties = std::make_unique<VkLayerProperties[]>(num_instance_layers + num_device_layers);
     if (num_device_layers > 0) {
         result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
-                                         properties + num_instance_layers);
+                                         properties.get() + num_instance_layers);
         if (result != VK_SUCCESS) {
             ALOGE(
                 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
@@ -321,21 +307,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 +446,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 +531,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..d234e17 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.
@@ -953,7 +953,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 +1291,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 +1300,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 +1812,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/scripts/api_generator.py b/vulkan/scripts/api_generator.py
index d1fff42..7c39075 100644
--- a/vulkan/scripts/api_generator.py
+++ b/vulkan/scripts/api_generator.py
@@ -13,13 +13,14 @@
 # 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
 
+# Functions intercepted at vulkan::api level.
 _INTERCEPTED_COMMANDS = [
     'vkCreateDevice',
     'vkDestroyDevice',
@@ -30,6 +31,8 @@
 
 
 def gen_h():
+  """Generates the api_gen.h file.
+  """
   genfile = os.path.join(os.path.dirname(__file__),
                          '..', 'libvulkan', 'api_gen.h')
 
@@ -100,6 +103,12 @@
 
 
 def _define_extension_stub(cmd, f):
+  """Emits a stub for an exported extension function.
+
+  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]
@@ -121,6 +130,11 @@
 
 
 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
@@ -128,6 +142,11 @@
 
 
 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""")
@@ -180,6 +199,11 @@
 
 
 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");
@@ -220,6 +244,12 @@
 
 
 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))
@@ -233,6 +263,8 @@
 
 
 def gen_cpp():
+  """Generates the api_gen.cpp file.
+  """
   genfile = os.path.join(os.path.dirname(__file__),
                          '..', 'libvulkan', 'api_gen.cpp')
 
diff --git a/vulkan/scripts/code_generator.py b/vulkan/scripts/code_generator.py
index 378a9c0..2a017d2 100755
--- a/vulkan/scripts/code_generator.py
+++ b/vulkan/scripts/code_generator.py
@@ -13,9 +13,9 @@
 # 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).
+
+"""Generates vulkan framework directly from the vulkan registry (vk.xml).
+"""
 
 import api_generator
 import driver_generator
diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py
index 5fff83e..a64a702 100644
--- a/vulkan/scripts/driver_generator.py
+++ b/vulkan/scripts/driver_generator.py
@@ -13,13 +13,14 @@
 # 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).
+
+"""Generates the driver_gen.h and driver_gen.cpp.
+"""
 
 import os
 import generator_common as gencom
 
+# Extensions intercepted at vulkan::driver level.
 _INTERCEPTED_EXTENSIONS = [
     'VK_ANDROID_native_buffer',
     'VK_EXT_debug_report',
@@ -34,12 +35,14 @@
     'VK_KHR_swapchain',
 ]
 
+# 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',
 ]
 
+# Functions needed at vulkan::driver level.
 _NEEDED_COMMANDS = [
     # Create functions of dispatchable objects
     'vkCreateDevice',
@@ -76,6 +79,7 @@
     'vkBindImageMemory2KHR',
 ]
 
+# Functions intercepted at vulkan::driver level.
 _INTERCEPTED_COMMANDS = [
     # Create functions of dispatchable objects
     'vkCreateInstance',
@@ -106,6 +110,11 @@
 
 
 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
@@ -117,16 +126,28 @@
 
 
 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')
 
@@ -153,11 +174,15 @@
     };
     enum Extension {\n""")
 
-    for exts in _KNOWN_EXTENSIONS:
-      f.write(gencom.indent(2) + exts[3:] + ',\n')
+    for ext in _KNOWN_EXTENSIONS:
+      f.write(gencom.indent(2) + gencom.base_ext_name(ext) + ',\n')
 
-    f.write("""
-        EXTENSION_CORE,  // valid bit
+    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,
     };
@@ -214,6 +239,11 @@
 
 
 def _is_intercepted(cmd):
+  """Returns true if a function is intercepted by vulkan::driver.
+
+  Args:
+    cmd: Vulkan function name.
+  """
   if gencom.is_function_supported(cmd):
     if cmd in _INTERCEPTED_COMMANDS:
       return True
@@ -223,19 +253,52 @@
   return False
 
 
+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 _define_proc_hook_stub(cmd, f):
+  """Emits a stub for ProcHook::checked_proc.
+
+  Args:
+    cmd: Vulkan function name.
+    f: Output file handle.
+  """
   if _need_proc_hook_stub(cmd):
     return_type = gencom.return_type_dict[cmd]
-    ext_name = gencom.extension_dict[cmd]
-    ext_hook = 'ProcHook::' + ext_name[3:]
+
+    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)
+
     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]])
@@ -259,26 +322,39 @@
 
 
 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("""\
-        ProcHook::GLOBAL,
-        ProcHook::EXTENSION_CORE,
-        reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
-        nullptr,
-    },\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::' + ext_name[3:] + ',\n')
+    f.write(gencom.indent(2) + 'ProcHook::' +
+            gencom.base_ext_name(ext_name) + ',\n')
 
     if gencom.is_extension_internal(ext_name):
       f.write("""\
@@ -289,8 +365,8 @@
         reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
         nullptr,\n""")
   else:
+    f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
     f.write("""\
-        ProcHook::EXTENSION_CORE,
         reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
         nullptr,\n""")
 
@@ -298,13 +374,27 @@
 
 
 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:
-    ext_name = gencom.extension_dict[cmd]
-    f.write(gencom.indent(2) + 'ProcHook::' + ext_name[3:] + ',\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:
+      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("""\
@@ -317,8 +407,8 @@
               gencom.base_name(cmd) + '),\n')
 
   else:
+    f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
     f.write("""\
-        ProcHook::EXTENSION_CORE,
         reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
         nullptr,\n""")
 
@@ -326,6 +416,8 @@
 
 
 def gen_cpp():
+  """Generates the driver_gen.cpp file.
+  """
   genfile = os.path.join(os.path.dirname(__file__),
                          '..', 'libvulkan', 'driver_gen.cpp')
 
@@ -384,9 +476,9 @@
 ProcHook::Extension GetProcHookExtension(const char* name) {
     // clang-format off\n""")
 
-    for exts in _KNOWN_EXTENSIONS:
-      f.write(gencom.indent(1) + 'if (strcmp(name, \"' + exts +
-              '\") == 0) return ProcHook::' + exts[3:] + ';\n')
+    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("""\
     // clang-format on
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index 03993e2..cf370fa 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -13,14 +13,15 @@
 # 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).
+
+"""Provide the utilities for framework generation.
+"""
 
 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',
@@ -52,6 +53,7 @@
     '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',
@@ -59,11 +61,13 @@
     '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',
@@ -72,19 +76,43 @@
     '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
@@ -108,19 +136,59 @@
 
 
 def run_clang_format(args):
+  """Run clang format on the file.
+
+  Args:
+    args: The file to be formatted.
+  """
   clang_call = ['clang-format', '--style', 'file', '-i', args]
   subprocess.check_call(clang_call)
 
 
-def is_extension_internal(extension_name):
-  return extension_name == 'VK_ANDROID_native_buffer'
+def is_extension_internal(ext):
+  """Returns true if an extension is internal to the loader and drivers.
+
+  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:
@@ -130,6 +198,11 @@
 
 
 def get_dispatch_table_type(cmd):
+  """Returns the dispatch table type for a function.
+
+  Args:
+    cmd: Vulkan function name.
+  """
   if cmd not in param_dict:
     return None
 
@@ -139,23 +212,55 @@
 
 
 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(extension_name):
-  return extension_name in _EXPORTED_EXTENSIONS
+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])
@@ -164,6 +269,11 @@
 
 
 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
@@ -171,13 +281,24 @@
 
 
 def is_device_dispatch_table_entry(cmd):
+  """Returns true if a function is exported and device-dispatched.
+
+  Args:
+    cmd: Vulkan function name.
+  """
   return is_function_exported(cmd) and is_device_dispatched(cmd)
 
 
 def init_proc(name, f):
+  """Emits code to invoke INIT_PROC or INIT_PROC_EXT.
+
+  Args:
+    name: Vulkan function name.
+    f: Output file handle.
+  """
   f.write(indent(1))
   if name in extension_dict:
-    f.write('INIT_PROC_EXT(' + extension_dict[name][3:] + ', ')
+    f.write('INIT_PROC_EXT(' + base_ext_name(extension_dict[name]) + ', ')
   else:
     f.write('INIT_PROC(')
 
@@ -197,6 +318,16 @@
 
 
 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)
@@ -267,3 +398,9 @@
           cmd_name = command.get('name')
           if cmd_name in command_list:
             version_dict[cmd_name] = apiversion
+
+  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 2a99a1d..e9faef6 100644
--- a/vulkan/scripts/null_generator.py
+++ b/vulkan/scripts/null_generator.py
@@ -13,13 +13,14 @@
 # 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).
+
+"""Generates the null_driver_gen.h and null_driver_gen.cpp.
+"""
 
 import os
 import generator_common as gencom
 
+# Extensions implemented by the driver.
 _DRIVER_EXTENSION_DICT = {
     'VK_ANDROID_native_buffer',
     'VK_EXT_debug_report',
@@ -28,12 +29,19 @@
 
 
 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 gen_h():
+  """Generates the null_driver_gen.h file.
+  """
   genfile = os.path.join(os.path.dirname(__file__),
                          '..', 'nulldrv', 'null_driver_gen.h')
 
@@ -72,6 +80,8 @@
 
 
 def gen_cpp():
+  """Generates the null_driver_gen.cpp file.
+  """
   genfile = os.path.join(os.path.dirname(__file__),
                          '..', 'nulldrv', 'null_driver_gen.cpp')