Merge "Vulkan: remove some redundant codes"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 09aee89..be7e3e1 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -66,7 +66,6 @@
     name: "dumpstate_aidl",
     srcs: [
         "binder/android/os/IDumpstateListener.aidl",
-        "binder/android/os/IDumpstateToken.aidl",
         "binder/android/os/IDumpstate.aidl",
     ],
     path: "binder",
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index f98df99..ccd74db 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -58,8 +58,6 @@
     exit(0);
 }
 
-class DumpstateToken : public BnDumpstateToken {};
-
 }  // namespace
 
 DumpstateService::DumpstateService() : ds_(nullptr) {
@@ -81,38 +79,6 @@
     return android::OK;
 }
 
-// Note: this method is part of the old flow and is not expected to be used in combination
-// with startBugreport.
-binder::Status DumpstateService::setListener(const std::string& name,
-                                             const sp<IDumpstateListener>& listener,
-                                             bool getSectionDetails,
-                                             sp<IDumpstateToken>* returned_token) {
-    *returned_token = nullptr;
-    if (name.empty()) {
-        MYLOGE("setListener(): name not set\n");
-        return binder::Status::ok();
-    }
-    if (listener == nullptr) {
-        MYLOGE("setListener(): listener not set\n");
-        return binder::Status::ok();
-    }
-    std::lock_guard<std::mutex> lock(lock_);
-    if (ds_ == nullptr) {
-        ds_ = &(Dumpstate::GetInstance());
-    }
-    if (ds_->listener_ != nullptr) {
-        MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_->listener_name_.c_str());
-        return binder::Status::ok();
-    }
-
-    ds_->listener_name_ = name;
-    ds_->listener_ = listener;
-    ds_->report_section_ = getSectionDetails;
-    *returned_token = new DumpstateToken();
-
-    return binder::Status::ok();
-}
-
 binder::Status DumpstateService::startBugreport(int32_t calling_uid,
                                                 const std::string& calling_package,
                                                 const android::base::unique_fd& bugreport_fd,
@@ -121,8 +87,7 @@
                                                 const sp<IDumpstateListener>& listener) {
     MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
 
-    // This is the bugreporting API flow, so ensure there is only one bugreport in progress at a
-    // time.
+    // Ensure there is only one bugreport in progress at a time.
     std::lock_guard<std::mutex> lock(lock_);
     if (ds_ != nullptr) {
         MYLOGE("Error! There is already a bugreport in progress. Returning.");
@@ -204,19 +169,17 @@
     dprintf(fd, "progress:\n");
     ds_->progress_->Dump(fd, "  ");
     dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
-    dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
+    dprintf(fd, "bugreport_mode: %s\n", ds_->options_->bugreport_mode.c_str());
     dprintf(fd, "version: %s\n", ds_->version_.c_str());
     dprintf(fd, "bugreport_dir: %s\n", destination.c_str());
     dprintf(fd, "screenshot_path: %s\n", ds_->screenshot_path_.c_str());
     dprintf(fd, "log_path: %s\n", ds_->log_path_.c_str());
     dprintf(fd, "tmp_path: %s\n", ds_->tmp_path_.c_str());
     dprintf(fd, "path: %s\n", ds_->path_.c_str());
-    dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
     dprintf(fd, "base_name: %s\n", ds_->base_name_.c_str());
     dprintf(fd, "name: %s\n", ds_->name_.c_str());
     dprintf(fd, "now: %ld\n", ds_->now_);
     dprintf(fd, "is_zipping: %s\n", ds_->IsZipping() ? "true" : "false");
-    dprintf(fd, "listener: %s\n", ds_->listener_name_.c_str());
     dprintf(fd, "notification title: %s\n", ds_->options_->notification_title.c_str());
     dprintf(fd, "notification description: %s\n", ds_->options_->notification_description.c_str());
 
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 68eda47..27954ad 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -24,7 +24,6 @@
 #include <binder/BinderService.h>
 
 #include "android/os/BnDumpstate.h"
-#include "android/os/BnDumpstateToken.h"
 #include "dumpstate.h"
 
 namespace android {
@@ -38,9 +37,6 @@
     static char const* getServiceName();
 
     status_t dump(int fd, const Vector<String16>& args) override;
-    binder::Status setListener(const std::string& name, const sp<IDumpstateListener>& listener,
-                               bool getSectionDetails,
-                               sp<IDumpstateToken>* returned_token) override;
 
     binder::Status startBugreport(int32_t calling_uid, const std::string& calling_package,
                                   const android::base::unique_fd& bugreport_fd,
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index cb2d8b8..3f359c8 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -17,24 +17,12 @@
 package android.os;
 
 import android.os.IDumpstateListener;
-import android.os.IDumpstateToken;
 
 /**
   * Binder interface for the currently running dumpstate process.
   * {@hide}
   */
 interface IDumpstate {
-    // TODO: remove method once startBugReport is used by Shell.
-    /*
-     * Sets the listener for this dumpstate progress.
-     *
-     * Returns a token used to monitor dumpstate death, or `nullptr` if the listener was already
-     * set (the listener behaves like a Highlander: There Can be Only One).
-     * Set {@code getSectionDetails} to true in order to receive callbacks with per section
-     * progress details
-     */
-    IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener,
-                                boolean getSectionDetails);
 
     // NOTE: If you add to or change these modes, please also change the corresponding enums
     // in system server, in BugreportParams.java.
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl b/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
deleted file mode 100644
index 7f74ceb..0000000
--- a/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-/**
-  * Token used by the IDumpstateListener to watch for dumpstate death.
-  * {@hide}
-  */
-interface IDumpstateToken {
-}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index b87582e..748f927 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");
 }
 
@@ -1905,7 +1894,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 +1904,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 +1962,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 +2054,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 +2065,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 +2079,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 +2100,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 +2110,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 +2143,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 +2150,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 +2166,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 +2184,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 +2209,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 +2217,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 +2225,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;
@@ -2528,7 +2323,7 @@
 
     MYLOGD("dumpstate calling_uid = %d ; calling package = %s \n",
             calling_uid, calling_package.c_str());
-    if (options_->bugreport_fd.get() != -1) {
+    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);
@@ -2573,8 +2368,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());
 
@@ -2601,18 +2396,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());
             }
@@ -2700,14 +2490,14 @@
         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 or Shell is the caller.
     Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
-    if (options_->bugreport_fd.get() != -1) {
+    if (CalledByApi()) {
         status = CopyBugreportIfUserConsented(calling_uid);
         if (status != Dumpstate::RunStatus::OK &&
             status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
@@ -2748,12 +2538,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();
@@ -3686,13 +3470,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 430936e..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_;
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/binder/Android.bp b/libs/binder/Android.bp
index 643a956..2a140f4 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -164,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/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/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/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/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 1c5dba3..ebd08b2 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -77,6 +77,7 @@
     static_libs: [
         "IBinderVendorDoubleLoadTest-cpp",
         "IBinderVendorDoubleLoadTest-ndk_platform",
+        "libbinder_aidl_test_stub-ndk_platform",
     ],
     shared_libs: [
         "libbase",
diff --git a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
index f72dc36..d3ccdc2 100644
--- a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
+++ b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
@@ -16,6 +16,7 @@
 
 #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>
@@ -109,6 +110,24 @@
     }
 }
 
+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.
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/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/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/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index cc9ccbc..9c600a8 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -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/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/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/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index a4f7797..8cc1831 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -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
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 6fe89c4..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);
 
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/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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0e33f10..057669b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -601,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.");
@@ -5452,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",
@@ -5460,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/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/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/driver.cpp b/vulkan/libvulkan/driver.cpp
index 4aa7d55..646f615 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"
@@ -148,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 = {{
@@ -176,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;
         }
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 5679412..dd91739 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>
@@ -101,9 +102,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 +225,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 +313,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 +452,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 +537,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;
 }