Merge "libs/ui/DebugUtils.cpp typo fix"
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 352cf0a..94c3102 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -5,6 +5,10 @@
         "-Wall",
         "-Werror",
         "-Wextra",
+
+        "-Wunreachable-code",
+        "-Wunreachable-code-break",
+        "-Wunreachable-code-return",
     ],
     srcs: [
         "CacheItem.cpp",
@@ -15,6 +19,9 @@
         "utils.cpp",
         ":installd_aidl",
     ],
+    header_libs: [
+        "dex2oat_headers",
+    ],
     shared_libs: [
         "libbase",
         "libbinder",
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 0a45ab0..e53a223 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1971,10 +1971,11 @@
     const char* profile_name = getCStr(profileName);
     const char* dm_path = getCStr(dexMetadataPath);
     const char* compilation_reason = getCStr(compilationReason);
+    std::string error_msg;
     int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
             oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info,
-            downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason);
-    return res ? error(res, "Failed to dexopt") : ok();
+            downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg);
+    return res ? error(res, error_msg) : ok();
 }
 
 binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 9f1cd45..230853d 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -28,6 +28,8 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <iomanip>
+
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
@@ -37,6 +39,7 @@
 #include <cutils/fs.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
+#include <dex2oat_return_codes.h>
 #include <log/log.h>               // TODO: Move everything to base/logging.
 #include <openssl/sha.h>
 #include <private/android_filesystem_config.h>
@@ -44,6 +47,7 @@
 #include <system/thread_defs.h>
 
 #include "dexopt.h"
+#include "dexopt_return_codes.h"
 #include "globals.h"
 #include "installd_deps.h"
 #include "otapreopt_utils.h"
@@ -68,6 +72,7 @@
 static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info";
 static constexpr const char* kDisableCompactDexFlag = "--compact-dex-level=none";
 
+
 // Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
 struct FreeDelete {
   // NOTE: Deleting a const object is valid but free() takes a non-const pointer.
@@ -219,6 +224,7 @@
     }
 }
 
+[[ noreturn ]]
 static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
         const char* input_file_name, const char* output_file_name, int swap_fd,
         const char* instruction_set, const char* compiler_filter,
@@ -228,9 +234,9 @@
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
     if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
-        ALOGE("Instruction set %s longer than max length of %d",
-              instruction_set, MAX_INSTRUCTION_SET_LEN);
-        return;
+        LOG(ERROR) << "Instruction set '" << instruction_set << "' longer than max length of "
+                   << MAX_INSTRUCTION_SET_LEN;
+        exit(DexoptReturnCodes::kInstructionSetLength);
     }
 
     // Get the relative path to the input file.
@@ -302,10 +308,11 @@
 
     // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
     const char* dex2oat_bin = "/system/bin/dex2oat";
-    static const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
+    constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
     if (is_debug_runtime() || (background_job_compile && is_debuggable_build())) {
-        DCHECK(access(kDex2oatDebugPath, X_OK) == 0);
-        dex2oat_bin = kDex2oatDebugPath;
+        if (access(kDex2oatDebugPath, X_OK) == 0) {
+            dex2oat_bin = kDex2oatDebugPath;
+        }
     }
 
     bool generate_minidebug_info = kEnableMinidebugInfo &&
@@ -548,7 +555,8 @@
     argv[i] = NULL;
 
     execv(dex2oat_bin, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", dex2oat_bin, strerror(errno));
+    PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
+    exit(DexoptReturnCodes::kDex2oatExec);
 }
 
 /*
@@ -600,12 +608,12 @@
 static void SetDex2OatScheduling(bool set_to_bg) {
     if (set_to_bg) {
         if (set_sched_policy(0, SP_BACKGROUND) < 0) {
-            ALOGE("set_sched_policy failed: %s\n", strerror(errno));
-            exit(70);
+            PLOG(ERROR) << "set_sched_policy failed";
+            exit(DexoptReturnCodes::kSetSchedPolicy);
         }
         if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
-            ALOGE("setpriority failed: %s\n", strerror(errno));
-            exit(71);
+            PLOG(ERROR) << "setpriority failed";
+            exit(DexoptReturnCodes::kSetPriority);
         }
     }
 }
@@ -705,12 +713,12 @@
 
 static void drop_capabilities(uid_t uid) {
     if (setgid(uid) != 0) {
-        ALOGE("setgid(%d) failed in installd during dexopt\n", uid);
-        exit(64);
+        PLOG(ERROR) << "setgid(" << uid << ") failed in installd during dexopt";
+        exit(DexoptReturnCodes::kSetGid);
     }
     if (setuid(uid) != 0) {
-        ALOGE("setuid(%d) failed in installd during dexopt\n", uid);
-        exit(65);
+        PLOG(ERROR) << "setuid(" << uid << ") failed in installd during dexopt";
+        exit(DexoptReturnCodes::kSetUid);
     }
     // drop capabilities
     struct __user_cap_header_struct capheader;
@@ -719,8 +727,8 @@
     memset(&capdata, 0, sizeof(capdata));
     capheader.version = _LINUX_CAPABILITY_VERSION_3;
     if (capset(&capheader, &capdata[0]) < 0) {
-        ALOGE("capset failed: %s\n", strerror(errno));
-        exit(66);
+        PLOG(ERROR) << "capset failed";
+        exit(DexoptReturnCodes::kCapSet);
     }
 }
 
@@ -730,6 +738,7 @@
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
 
+[[ noreturn ]]
 static void run_profman(const std::vector<unique_fd>& profile_fds,
                         const unique_fd& reference_profile_fd,
                         const std::vector<unique_fd>* apk_fds,
@@ -773,18 +782,18 @@
     argv[i] = NULL;
 
     execv(profman_bin, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", profman_bin, strerror(errno));
-    exit(68);   /* only get here on exec failure */
+    PLOG(ERROR) << "execv(" << profman_bin << ") failed";
+    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
 }
 
-
+[[ noreturn ]]
 static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
                               const unique_fd& reference_profile_fd,
                               const std::vector<unique_fd>* apk_fds = nullptr) {
     run_profman(profiles_fd, reference_profile_fd, apk_fds, /*copy_and_update*/false);
 }
 
-
+[[ noreturn ]]
 static void run_profman_copy_and_update(unique_fd&& profile_fd,
                                         unique_fd&& reference_profile_fd,
                                         unique_fd&& apk_fd) {
@@ -819,7 +828,6 @@
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
         run_profman_merge(profiles_fd, reference_profile_fd);
-        exit(68);   /* only get here on exec failure */
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -892,6 +900,7 @@
     return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false);
 }
 
+[[ noreturn ]]
 static void run_profman_dump(const std::vector<unique_fd>& profile_fds,
                              const unique_fd& reference_profile_fd,
                              const std::vector<std::string>& dex_locations,
@@ -923,8 +932,8 @@
     argv[i] = NULL;
 
     execv(PROFMAN_BIN, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
-    exit(68);   /* only get here on exec failure */
+    PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
+    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
 }
 
 bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
@@ -969,7 +978,6 @@
         drop_capabilities(uid);
         run_profman_dump(profile_fds, reference_profile_fd, dex_locations,
                          apk_fds, output_fd);
-        exit(68);   /* only get here on exec failure */
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -1640,10 +1648,17 @@
 // secondary dex files. This return codes are returned by the child process created for
 // analyzing secondary dex files in process_secondary_dex_dexopt.
 
-// The dexoptanalyzer was not invoked because of validation or IO errors.
-static int constexpr SECONDARY_DEX_DEXOPTANALYZER_SKIPPED = 200;
-// The dexoptanalyzer was not invoked because the dex file does not exist anymore.
-static int constexpr SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE = 201;
+enum DexoptAnalyzerSkipCodes {
+  // The dexoptanalyzer was not invoked because of validation or IO errors.
+  // Specific errors are encoded in the name.
+  kSecondaryDexDexoptAnalyzerSkippedValidatePath = 200,
+  kSecondaryDexDexoptAnalyzerSkippedOpenZip = 201,
+  kSecondaryDexDexoptAnalyzerSkippedPrepareDir = 202,
+  kSecondaryDexDexoptAnalyzerSkippedOpenOutput = 203,
+  kSecondaryDexDexoptAnalyzerSkippedFailExec = 204,
+  // The dexoptanalyzer was not invoked because the dex file does not exist anymore.
+  kSecondaryDexDexoptAnalyzerSkippedNoFile = 205,
+};
 
 // Verifies the result of analyzing secondary dex files from process_secondary_dex_dexopt.
 // If the result is valid returns true and sets dexopt_needed_out to a valid value.
@@ -1651,7 +1666,7 @@
 // The result is expected to be either one of SECONDARY_DEX_* codes or a valid exit code
 // of dexoptanalyzer.
 static bool process_secondary_dexoptanalyzer_result(const std::string& dex_path, int result,
-            int* dexopt_needed_out) {
+            int* dexopt_needed_out, std::string* error_msg) {
     // The result values are defined in dexoptanalyzer.
     switch (result) {
         case 0:  // dexoptanalyzer: no_dexopt_needed
@@ -1667,21 +1682,42 @@
         case 2:  // dexoptanalyzer: dex2oat_for_bootimage_oat
         case 3:  // dexoptanalyzer: dex2oat_for_filter_oat
         case 4:  // dexoptanalyzer: dex2oat_for_relocation_oat
-            LOG(ERROR) << "Dexoptnalyzer return the status of an oat file."
-                    << " Expected odex file status for secondary dex " << dex_path
-                    << " : dexoptanalyzer result=" << result;
+            *error_msg = StringPrintf("Dexoptanalyzer return the status of an oat file."
+                                      " Expected odex file status for secondary dex %s"
+                                      " : dexoptanalyzer result=%d",
+                                      dex_path.c_str(),
+                                      result);
             return false;
-        case SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE:
+    }
+
+    // Use a second switch for enum switch-case analysis.
+    switch (static_cast<DexoptAnalyzerSkipCodes>(result)) {
+        case kSecondaryDexDexoptAnalyzerSkippedNoFile:
             // If the file does not exist there's no need for dexopt.
             *dexopt_needed_out = NO_DEXOPT_NEEDED;
             return true;
-        case SECONDARY_DEX_DEXOPTANALYZER_SKIPPED:
+
+        case kSecondaryDexDexoptAnalyzerSkippedValidatePath:
+            *error_msg = "Dexoptanalyzer path validation failed";
             return false;
-        default:
-            LOG(ERROR) << "Unexpected result from analyzing secondary dex " << dex_path
-                    << " result=" << result;
+        case kSecondaryDexDexoptAnalyzerSkippedOpenZip:
+            *error_msg = "Dexoptanalyzer open zip failed";
+            return false;
+        case kSecondaryDexDexoptAnalyzerSkippedPrepareDir:
+            *error_msg = "Dexoptanalyzer dir preparation failed";
+            return false;
+        case kSecondaryDexDexoptAnalyzerSkippedOpenOutput:
+            *error_msg = "Dexoptanalyzer open output failed";
+            return false;
+        case kSecondaryDexDexoptAnalyzerSkippedFailExec:
+            *error_msg = "Dexoptanalyzer failed to execute";
             return false;
     }
+
+    *error_msg = StringPrintf("Unexpected result from analyzing secondary dex %s result=%d",
+                              dex_path.c_str(),
+                              result);
+    return false;
 }
 
 enum SecondaryDexAccess {
@@ -1719,10 +1755,10 @@
 // Create the oat file structure for the secondary dex 'dex_path' and assign
 // the individual path component to the 'out_' parameters.
 static bool create_secondary_dex_oat_layout(const std::string& dex_path, const std::string& isa,
-        char* out_oat_dir, char* out_oat_isa_dir, char* out_oat_path) {
+        char* out_oat_dir, char* out_oat_isa_dir, char* out_oat_path, std::string* error_msg) {
     size_t dirIndex = dex_path.rfind('/');
     if (dirIndex == std::string::npos) {
-        LOG(ERROR) << "Unexpected dir structure for dex file " << dex_path;
+        *error_msg = std::string("Unexpected dir structure for dex file ").append(dex_path);
         return false;
     }
     // TODO(calin): we have similar computations in at lest 3 other places
@@ -1734,7 +1770,7 @@
 
     if (!create_oat_out_path(dex_path.c_str(), isa.c_str(), out_oat_dir,
             /*is_secondary_dex*/true, out_oat_path)) {
-        LOG(ERROR) << "Could not create oat path for secondary dex " << dex_path;
+        *error_msg = std::string("Could not create oat path for secondary dex ").append(dex_path);
         return false;
     }
     return true;
@@ -1742,17 +1778,19 @@
 
 // Validate that the dexopt_flags contain a valid storage flag and convert that to an installd
 // recognized storage flags (FLAG_STORAGE_CE or FLAG_STORAGE_DE).
-static bool validate_dexopt_storage_flags(int dexopt_flags, int* out_storage_flag) {
+static bool validate_dexopt_storage_flags(int dexopt_flags,
+                                          int* out_storage_flag,
+                                          std::string* error_msg) {
     if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
         *out_storage_flag = FLAG_STORAGE_CE;
         if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
-            LOG(ERROR) << "Ambiguous secondary dex storage flag. Both, CE and DE, flags are set";
+            *error_msg = "Ambiguous secondary dex storage flag. Both, CE and DE, flags are set";
             return false;
         }
     } else if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
         *out_storage_flag = FLAG_STORAGE_DE;
     } else {
-        LOG(ERROR) << "Secondary dex storage flag must be set";
+        *error_msg = "Secondary dex storage flag must be set";
         return false;
     }
     return true;
@@ -1768,10 +1806,12 @@
 static bool process_secondary_dex_dexopt(const std::string& dex_path, const char* pkgname,
         int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
         const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
-        std::string* oat_dir_out, bool downgrade, const char* class_loader_context) {
+        std::string* oat_dir_out, bool downgrade, const char* class_loader_context,
+        /* out */ std::string* error_msg) {
     LOG(DEBUG) << "Processing secondary dex path " << dex_path;
     int storage_flag;
-    if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag)) {
+    if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag, error_msg)) {
+        LOG(ERROR) << *error_msg;
         return false;
     }
     // Compute the oat dir as it's not easy to extract it from the child computation.
@@ -1779,8 +1819,8 @@
     char oat_dir[PKG_PATH_MAX];
     char oat_isa_dir[PKG_PATH_MAX];
     if (!create_secondary_dex_oat_layout(
-            dex_path, instruction_set, oat_dir, oat_isa_dir, oat_path)) {
-        LOG(ERROR) << "Could not create secondary odex layout: " << dex_path;
+            dex_path, instruction_set, oat_dir, oat_isa_dir, oat_path, error_msg)) {
+        LOG(ERROR) << "Could not create secondary odex layout: " << *error_msg;
         return false;
     }
     oat_dir_out->assign(oat_dir);
@@ -1793,7 +1833,7 @@
         // Validate the path structure.
         if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
             LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
-            _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+            _exit(kSecondaryDexDexoptAnalyzerSkippedValidatePath);
         }
 
         // Open the dex file.
@@ -1801,15 +1841,15 @@
         zip_fd.reset(open(dex_path.c_str(), O_RDONLY));
         if (zip_fd.get() < 0) {
             if (errno == ENOENT) {
-                _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE);
+                _exit(kSecondaryDexDexoptAnalyzerSkippedNoFile);
             } else {
-                _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+                _exit(kSecondaryDexDexoptAnalyzerSkippedOpenZip);
             }
         }
 
         // Prepare the oat directories.
         if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set)) {
-            _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+            _exit(kSecondaryDexDexoptAnalyzerSkippedPrepareDir);
         }
 
         // Open the vdex/oat files if any.
@@ -1821,7 +1861,7 @@
                                           true /* is_secondary_dex */,
                                           &oat_file_fd,
                                           &vdex_file_fd)) {
-            _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+            _exit(kSecondaryDexDexoptAnalyzerSkippedOpenOutput);
         }
 
         // Analyze profiles.
@@ -1838,18 +1878,27 @@
                             downgrade,
                             class_loader_context);
         PLOG(ERROR) << "Failed to exec dexoptanalyzer";
-        _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+        _exit(kSecondaryDexDexoptAnalyzerSkippedFailExec);
     }
 
     /* parent */
     int result = wait_child(pid);
     if (!WIFEXITED(result)) {
-        LOG(ERROR) << "dexoptanalyzer failed for path " << dex_path << ": " << result;
+        *error_msg = StringPrintf("dexoptanalyzer failed for path %s: 0x%04x",
+                                  dex_path.c_str(),
+                                  result);
+        LOG(ERROR) << *error_msg;
         return false;
     }
     result = WEXITSTATUS(result);
     // Check that we successfully executed dexoptanalyzer.
-    bool success = process_secondary_dexoptanalyzer_result(dex_path, result, dexopt_needed_out);
+    bool success = process_secondary_dexoptanalyzer_result(dex_path,
+                                                           result,
+                                                           dexopt_needed_out,
+                                                           error_msg);
+    if (!success) {
+        LOG(ERROR) << *error_msg;
+    }
 
     LOG(DEBUG) << "Processed secondary dex file " << dex_path << " result=" << result;
 
@@ -1857,7 +1906,7 @@
     // Note that dexoptanalyzer is executed even if force compilation is enabled (because it
     // makes the code simpler; force compilation is only needed during tests).
     if (success &&
-        (result != SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE) &&
+        (result != kSecondaryDexDexoptAnalyzerSkippedNoFile) &&
         ((dexopt_flags & DEXOPT_FORCE) != 0)) {
         *dexopt_needed_out = DEX2OAT_FROM_SCRATCH;
     }
@@ -1870,23 +1919,37 @@
     return success;
 }
 
+static std::string format_dexopt_error(int status, const char* dex_path) {
+  if (WIFEXITED(status)) {
+    int int_code = WEXITSTATUS(status);
+    const char* code_name = get_return_code_name(static_cast<DexoptReturnCodes>(int_code));
+    if (code_name != nullptr) {
+      return StringPrintf("Dex2oat invocation for %s failed: %s", dex_path, code_name);
+    }
+  }
+  return StringPrintf("Dex2oat invocation for %s failed with 0x%04x", dex_path, status);
+}
+
 int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
         bool downgrade, int target_sdk_version, const char* profile_name,
-        const char* dex_metadata_path, const char* compilation_reason) {
+        const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg) {
     CHECK(pkgname != nullptr);
     CHECK(pkgname[0] != 0);
-    if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
-        LOG_FATAL("dexopt flags contains unknown fields\n");
-    }
+    CHECK(error_msg != nullptr);
+    CHECK_EQ(dexopt_flags & ~DEXOPT_MASK, 0)
+        << "dexopt flags contains unknown fields: " << dexopt_flags;
 
     if (!validate_dex_path_size(dex_path)) {
+        *error_msg = StringPrintf("Failed to validate %s", dex_path);
         return -1;
     }
 
     if (class_loader_context != nullptr && strlen(class_loader_context) > PKG_PATH_MAX) {
-        LOG(ERROR) << "Class loader context exceeds the allowed size: " << class_loader_context;
+        *error_msg = StringPrintf("Class loader context exceeds the allowed size: %s",
+                                  class_loader_context);
+        LOG(ERROR) << *error_msg;
         return -1;
     }
 
@@ -1903,12 +1966,15 @@
     if (is_secondary_dex) {
         if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
                 instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
-                downgrade, class_loader_context)) {
+                downgrade, class_loader_context, error_msg)) {
             oat_dir = oat_dir_str.c_str();
             if (dexopt_needed == NO_DEXOPT_NEEDED) {
                 return 0;  // Nothing to do, report success.
             }
         } else {
+            if (error_msg->empty()) {  // TODO: Make this a CHECK.
+                *error_msg = "Failed processing secondary.";
+            }
             return -1;  // We had an error, logged in the process method.
         }
     } else {
@@ -1921,7 +1987,8 @@
     // Open the input file.
     unique_fd input_fd(open(dex_path, O_RDONLY, 0));
     if (input_fd.get() < 0) {
-        ALOGE("installd cannot open '%s' for input during dexopt\n", dex_path);
+        *error_msg = StringPrintf("installd cannot open '%s' for input during dexopt", dex_path);
+        LOG(ERROR) << *error_msg;
         return -1;
     }
 
@@ -1930,6 +1997,7 @@
     Dex2oatFileWrapper out_oat_fd = open_oat_out_file(dex_path, oat_dir, is_public, uid,
             instruction_set, is_secondary_dex, out_oat_path);
     if (out_oat_fd.get() < 0) {
+        *error_msg = "Could not open out oat file.";
         return -1;
     }
 
@@ -1938,6 +2006,7 @@
     Dex2oatFileWrapper out_vdex_fd;
     if (!open_vdex_files_for_dex2oat(dex_path, out_oat_path, dexopt_needed, instruction_set,
             is_public, uid, is_secondary_dex, profile_guided, &in_vdex_fd, &out_vdex_fd)) {
+        *error_msg = "Could not open vdex files.";
         return -1;
     }
 
@@ -1949,7 +2018,8 @@
     if (is_secondary_dex) {
         if (selinux_android_restorecon_pkgdir(oat_dir, se_info, uid,
                 SELINUX_ANDROID_RESTORECON_RECURSE)) {
-            LOG(ERROR) << "Failed to restorecon " << oat_dir;
+            *error_msg = std::string("Failed to restorecon ").append(oat_dir);
+            LOG(ERROR) << *error_msg;
             return -1;
         }
     }
@@ -1973,7 +2043,7 @@
         }
     }
 
-    ALOGV("DexInv: --- BEGIN '%s' ---\n", dex_path);
+    LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";
 
     pid_t pid = fork();
     if (pid == 0) {
@@ -1982,8 +2052,8 @@
 
         SetDex2OatScheduling(boot_complete);
         if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
-            ALOGE("flock(%s) failed: %s\n", out_oat_path, strerror(errno));
-            _exit(67);
+            PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
+            _exit(DexoptReturnCodes::kFlock);
         }
 
         run_dex2oat(input_fd.get(),
@@ -2005,13 +2075,14 @@
                     enable_hidden_api_checks,
                     dex_metadata_fd.get(),
                     compilation_reason);
-        _exit(68);   /* only get here on exec failure */
     } else {
         int res = wait_child(pid);
         if (res == 0) {
-            ALOGV("DexInv: --- END '%s' (success) ---\n", dex_path);
+            LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' (success) ---";
         } else {
-            ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", dex_path, res);
+            LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- status=0x"
+                         << std::hex << std::setw(4) << res << ", process failed";
+            *error_msg = format_dexopt_error(res, dex_path);
             return res;
         }
     }
@@ -2119,9 +2190,10 @@
         char oat_isa_dir[PKG_PATH_MAX];
         bool result = true;
         for (size_t i = 0; i < isas.size(); i++) {
+            std::string error_msg;
             if (!create_secondary_dex_oat_layout(
-                    dex_path,isas[i], oat_dir, oat_isa_dir, oat_path)) {
-                LOG(ERROR) << "Could not create secondary odex layout: " << dex_path;
+                    dex_path,isas[i], oat_dir, oat_isa_dir, oat_path, &error_msg)) {
+                LOG(ERROR) << error_msg;
                 _exit(kReconcileSecondaryDexValidationError);
             }
 
@@ -2222,7 +2294,7 @@
 
         if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr, uid, storage_flag)) {
             LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
-            _exit(1);
+            _exit(DexoptReturnCodes::kHashValidatePath);
         }
 
         unique_fd fd(TEMP_FAILURE_RETRY(open(dex_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)));
@@ -2232,7 +2304,7 @@
                 _exit(0);
             }
             PLOG(ERROR) << "Failed to open secondary dex " << dex_path;
-            _exit(1);
+            _exit(DexoptReturnCodes::kHashOpenPath);
         }
 
         SHA256_CTX ctx;
@@ -2245,7 +2317,7 @@
                 break;
             } else if (bytes_read == -1) {
                 PLOG(ERROR) << "Failed to read secondary dex " << dex_path;
-                _exit(1);
+                _exit(DexoptReturnCodes::kHashReadDex);
             }
 
             SHA256_Update(&ctx, buffer.data(), bytes_read);
@@ -2254,7 +2326,7 @@
         std::array<uint8_t, SHA256_DIGEST_LENGTH> hash;
         SHA256_Final(hash.data(), &ctx);
         if (!WriteFully(pipe_write, hash.data(), hash.size())) {
-            _exit(1);
+            _exit(DexoptReturnCodes::kHashWrite);
         }
 
         _exit(0);
@@ -2572,7 +2644,6 @@
         /* child -- drop privileges before continuing */
         drop_capabilities(app_shared_gid);
         run_profman_merge(profiles_fd, snapshot_fd, &apk_fds);
-        exit(42);   /* only get here on exec failure */
     }
 
     /* parent */
@@ -2650,7 +2721,6 @@
             drop_capabilities(AID_SYSTEM);
 
             run_profman_merge(profiles_fd, snapshot_fd, &apk_fds);
-            exit(42);   /* only get here on exec failure */
         }
 
         /* parent */
@@ -2714,7 +2784,6 @@
         run_profman_copy_and_update(std::move(dex_metadata_fd),
                                     std::move(ref_profile_fd),
                                     std::move(apk_fd));
-        exit(42);   /* only get here on exec failure */
     }
 
     /* parent */
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 62f9467..bb6fab3 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -106,7 +106,7 @@
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
         bool downgrade, int target_sdk_version, const char* profile_name,
-        const char* dexMetadataPath, const char* compilation_reason);
+        const char* dexMetadataPath, const char* compilation_reason, std::string* error_msg);
 
 bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
         const char *apk_path, const char *instruction_set);
diff --git a/cmds/installd/dexopt_return_codes.h b/cmds/installd/dexopt_return_codes.h
new file mode 100644
index 0000000..bbecfa4
--- /dev/null
+++ b/cmds/installd/dexopt_return_codes.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dex2oat_return_codes.h>
+
+namespace android {
+namespace installd {
+
+// Constants for exit codes that installd code emits. These are failure situations before calling
+// any tools, e.g., in validation, and must not overlap with the exit codes of tools, so they
+// can be distinguished.
+enum DexoptReturnCodes : int {
+    kSetGid = 64,
+    kSetUid = 65,
+    kCapSet = 66,
+    kFlock = 67,
+    kProfmanExec = 68,
+    kSetSchedPolicy = 70,
+    kSetPriority = 71,
+    kDex2oatExec = 72,
+    kInstructionSetLength = 73,
+    kHashValidatePath = 74,
+    kHashOpenPath = 75,
+    kHashReadDex = 76,
+    kHashWrite = 77,
+};
+
+inline const char* get_installd_return_code_name(DexoptReturnCodes code) {
+    switch (code) {
+        case kSetGid:
+            return "setgid";
+        case kSetUid:
+            return "setuid";
+        case kCapSet:
+            return "capset";
+        case kFlock:
+            return "flock";
+        case kProfmanExec:
+            return "exec(profman)";
+        case kSetSchedPolicy:
+            return "setschedpolicy";
+        case kSetPriority:
+            return "setpriority";
+        case kDex2oatExec:
+            return "exec(dex2oat)";
+        case kInstructionSetLength:
+            return "instruction-set-length";
+        case kHashValidatePath:
+            return "hash(validate-path)";
+        case kHashOpenPath:
+            return "hash(open-path)";
+        case kHashReadDex:
+            return "hash(read-dex)";
+        case kHashWrite:
+            return "hash(write)";
+    }
+    return nullptr;
+}
+
+inline const char* get_dex2oat_return_code_name(art::dex2oat::ReturnCode code) {
+    switch (code) {
+        case art::dex2oat::ReturnCode::kNoFailure:
+            return "dex2oat success";
+        case art::dex2oat::ReturnCode::kOther:
+            return "unspecified dex2oat error";
+        case art::dex2oat::ReturnCode::kCreateRuntime:
+            return "dex2oat failed to create a runtime";
+    }
+    return nullptr;
+}
+
+// Get some slightly descriptive string for the return code. Handles both DexoptReturnCodes (local
+// exit codes) as well as art::dex2oat::ReturnCode.
+inline const char* get_return_code_name(int code) {
+    // Try to enforce non-overlap (see comment on DexoptReturnCodes)
+    // TODO: How could switch-case checks be used to enforce completeness?
+    switch (code) {
+        case kSetGid:
+        case kSetUid:
+        case kCapSet:
+        case kFlock:
+        case kProfmanExec:
+        case kSetSchedPolicy:
+        case kSetPriority:
+        case kDex2oatExec:
+        case kInstructionSetLength:
+        case kHashValidatePath:
+        case kHashOpenPath:
+        case kHashReadDex:
+        case kHashWrite:
+            break;
+        case static_cast<int>(art::dex2oat::ReturnCode::kNoFailure):
+        case static_cast<int>(art::dex2oat::ReturnCode::kOther):
+        case static_cast<int>(art::dex2oat::ReturnCode::kCreateRuntime):
+            break;
+    }
+    const char* value = get_installd_return_code_name(static_cast<DexoptReturnCodes>(code));
+    if (value != nullptr) {
+        return value;
+    }
+    value = get_dex2oat_return_code_name(static_cast<art::dex2oat::ReturnCode>(code));
+    return value;
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 06c83e4..6282ba2 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -64,6 +64,7 @@
     | DEXOPT_FORCE
     | DEXOPT_STORAGE_CE
     | DEXOPT_STORAGE_DE
+    | DEXOPT_IDLE_BACKGROUND_JOB
     | DEXOPT_ENABLE_HIDDEN_API_CHECKS;
 
 // NOTE: keep in sync with StorageManager
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 899285a..c1a1202 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -82,7 +82,8 @@
 static_assert(DEXOPT_ENABLE_HIDDEN_API_CHECKS == 1 << 10,
         "DEXOPT_ENABLE_HIDDEN_API_CHECKS unexpected");
 
-static_assert(DEXOPT_MASK           == 0x5fe, "DEXOPT_MASK unexpected.");
+static_assert(DEXOPT_MASK           == (0x5fe | DEXOPT_IDLE_BACKGROUND_JOB),
+              "DEXOPT_MASK unexpected.");
 
 
 
@@ -568,6 +569,7 @@
     // Run dexopt with the parameters of parameters_.
     // TODO(calin): embed the profile name in the parameters.
     int Dexopt() {
+        std::string dummy;
         return dexopt(parameters_.apk_path,
                       parameters_.uid,
                       parameters_.pkgName,
@@ -583,7 +585,8 @@
                       parameters_.target_sdk_version,
                       parameters_.profile_name,
                       parameters_.dex_metadata_path,
-                      parameters_.compilation_reason);
+                      parameters_.compilation_reason,
+                      &dummy);
     }
 
     int RunPreopt() {
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index d640558..668e604 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -249,7 +249,7 @@
 
     void CompileSecondaryDex(const std::string& path, int32_t dex_storage_flag,
             bool should_binder_call_succeed, bool should_dex_be_compiled = true,
-            int32_t uid = -1) {
+            /*out */ binder::Status* binder_result = nullptr, int32_t uid = -1) {
         if (uid == -1) {
             uid = kTestAppUid;
         }
@@ -290,6 +290,9 @@
         ASSERT_EQ(expected_access, access(odex.c_str(), R_OK));
         ASSERT_EQ(expected_access, access(vdex.c_str(), R_OK));
         ASSERT_EQ(-1, access(art.c_str(), R_OK));  // empty profiles do not generate an image.
+        if (binder_result != nullptr) {
+            *binder_result = result;
+        }
     }
 
     void reconcile_secondary_dex(const std::string& path, int32_t storage_flag,
@@ -335,10 +338,18 @@
                              const char* oat_dir,
                              int32_t uid,
                              int32_t dexopt_needed,
+                             binder::Status* binder_result = nullptr,
                              const char* dm_path = nullptr,
                              bool downgrade = false) {
-        return CompilePrimaryDex(
-                compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, dm_path, downgrade, true);
+        CompilePrimaryDex(compiler_filter,
+                          dex_flags,
+                          oat_dir,
+                          uid,
+                          dexopt_needed,
+                          dm_path,
+                          downgrade,
+                          true,
+                          binder_result);
     }
 
     void CompilePrimaryDexFail(std::string compiler_filter,
@@ -346,10 +357,18 @@
                                const char* oat_dir,
                                int32_t uid,
                                int32_t dexopt_needed,
+                               binder::Status* binder_result = nullptr,
                                const char* dm_path = nullptr,
                                bool downgrade = false) {
-        return CompilePrimaryDex(
-                compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, dm_path, downgrade, false);
+        CompilePrimaryDex(compiler_filter,
+                          dex_flags,
+                          oat_dir,
+                          uid,
+                          dexopt_needed,
+                          dm_path,
+                          downgrade,
+                          false,
+                          binder_result);
     }
 
     void CompilePrimaryDex(std::string compiler_filter,
@@ -359,7 +378,8 @@
                            int32_t dexopt_needed,
                            const char* dm_path,
                            bool downgrade,
-                           bool should_binder_call_succeed) {
+                           bool should_binder_call_succeed,
+                           /*out */ binder::Status* binder_result) {
         std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
         std::unique_ptr<std::string> out_path(
                 oat_dir == nullptr ? nullptr : new std::string(oat_dir));
@@ -400,6 +420,9 @@
         ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str();
 
         if (!should_binder_call_succeed) {
+            if (binder_result != nullptr) {
+                *binder_result = result;
+            }
             return;
         }
         // Check the access to the compiler output.
@@ -417,6 +440,9 @@
         if (compiler_filter == "speed-profile") {
             CheckFileAccess(art, kSystemUid, uid, mode);
         }
+        if (binder_result != nullptr) {
+            *binder_result = result;
+        }
     }
 
     std::string GetPrimaryDexArtifact(const char* oat_dir,
@@ -462,26 +488,36 @@
 TEST_F(DexoptTest, DexoptSecondaryDoesNotExist) {
     LOG(INFO) << "DexoptSecondaryDoesNotExist";
     // If the file validates but does not exist we do not treat it as an error.
+    binder::Status status;
     CompileSecondaryDex(secondary_dex_ce_ + "not.there", DEXOPT_STORAGE_CE,
-        /*binder_ok*/ true,  /*compile_ok*/ false);
+        /*binder_ok*/ true,  /*compile_ok*/ false, &status);
+    EXPECT_STREQ(status.toString8().c_str(), "No error");
 }
 
 TEST_F(DexoptTest, DexoptSecondaryStorageValidationError) {
     LOG(INFO) << "DexoptSecondaryStorageValidationError";
+    binder::Status status;
     CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_DE,
-        /*binder_ok*/ false,  /*compile_ok*/ false);
+        /*binder_ok*/ false,  /*compile_ok*/ false, &status);
+    EXPECT_STREQ(status.toString8().c_str(),
+                 "Status(-8): '-1: Dexoptanalyzer path validation failed'");
 }
 
 TEST_F(DexoptTest, DexoptSecondaryAppOwnershipValidationError) {
     LOG(INFO) << "DexoptSecondaryAppOwnershipValidationError";
+    binder::Status status;
     CompileSecondaryDex("/data/data/random.app/secondary.jar", DEXOPT_STORAGE_CE,
-        /*binder_ok*/ false,  /*compile_ok*/ false);
+        /*binder_ok*/ false,  /*compile_ok*/ false, &status);
+    EXPECT_STREQ(status.toString8().c_str(),
+                 "Status(-8): '-1: Dexoptanalyzer path validation failed'");
 }
 
 TEST_F(DexoptTest, DexoptSecondaryAcessViaDifferentUidError) {
     LOG(INFO) << "DexoptSecondaryAcessViaDifferentUidError";
+    binder::Status status;
     CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
-        /*binder_ok*/ false,  /*compile_ok*/ false, kSystemUid);
+        /*binder_ok*/ false,  /*compile_ok*/ false, &status, kSystemUid);
+    EXPECT_STREQ(status.toString8().c_str(), "Status(-8): '-1: Dexoptanalyzer open zip failed'");
 }
 
 TEST_F(DexoptTest, DexoptPrimaryPublic) {
@@ -495,11 +531,16 @@
 
 TEST_F(DexoptTest, DexoptPrimaryFailedInvalidFilter) {
     LOG(INFO) << "DexoptPrimaryFailedInvalidFilter";
+    binder::Status status;
     CompilePrimaryDexFail("awesome-filter",
                           DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PUBLIC,
                           app_oat_dir_.c_str(),
                           kTestAppGid,
-                          DEX2OAT_FROM_SCRATCH);
+                          DEX2OAT_FROM_SCRATCH,
+                          &status);
+    EXPECT_STREQ(status.toString8().c_str(),
+                 "Status(-8): \'256: Dex2oat invocation for "
+                 "/data/app/com.installd.test.dexopt/base.jar failed: unspecified dex2oat error'");
 }
 
 TEST_F(DexoptTest, DexoptPrimaryProfileNonPublic) {
diff --git a/headers/media_plugin/media/cas/DescramblerAPI.h b/headers/media_plugin/media/cas/DescramblerAPI.h
index 0a51952..033c8ce 100644
--- a/headers/media_plugin/media/cas/DescramblerAPI.h
+++ b/headers/media_plugin/media/cas/DescramblerAPI.h
@@ -48,6 +48,10 @@
         kScrambling_Reserved    = 1,
         kScrambling_EvenKey     = 2,
         kScrambling_OddKey      = 3,
+        kScrambling_Mask_Key    = 0x3,
+
+        // Hint that the descrambling request is for a PES header only
+        kScrambling_Flag_PesHeader = (1 << 31),
     };
 
     struct SubSample {
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index f3b86ae..62c8987 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -100,11 +100,12 @@
             : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 }
 
-int32_t AppOpsManager::startOp(int32_t op, int32_t uid, const String16& callingPackage) {
+int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+        bool startIfModeDefault) {
     sp<IAppOpsService> service = getService();
     return service != NULL
-            ? service->startOperation(getToken(service), op, uid, callingPackage)
-            : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+            ? service->startOperation(getToken(service), op, uid, callingPackage,
+                    startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 }
 
 void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 638ae5c..9c76350 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -61,13 +61,14 @@
     }
 
     virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-                const String16& packageName) {
+                const String16& packageName, bool startIfModeDefault) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
         data.writeStrongBinder(token);
         data.writeInt32(code);
         data.writeInt32(uid);
         data.writeString16(packageName);
+        data.writeInt32(startIfModeDefault ? 1 : 0);
         remote()->transact(START_OPERATION_TRANSACTION, data, &reply);
         // fail on exception
         if (reply.readExceptionCode() != 0) return MODE_ERRORED;
@@ -159,7 +160,8 @@
             int32_t code = data.readInt32();
             int32_t uid = data.readInt32();
             String16 packageName = data.readString16();
-            int32_t res = startOperation(token, code, uid, packageName);
+            bool startIfModeDefault = data.readInt32() == 1;
+            int32_t res = startOperation(token, code, uid, packageName, startIfModeDefault);
             reply->writeNoException();
             reply->writeInt32(res);
             return NO_ERROR;
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 4212776..a44d270 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -99,7 +99,8 @@
 
     int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
     int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
-    int32_t startOp(int32_t op, int32_t uid, const String16& callingPackage);
+    int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+            bool startIfModeDefault);
     void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
     void startWatchingMode(int32_t op, const String16& packageName,
             const sp<IAppOpsCallback>& callback);
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index dc18045..ecba5d6 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -33,7 +33,7 @@
     virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
     virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
     virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName) = 0;
+            const String16& packageName, bool startIfModeDefault) = 0;
     virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
             const String16& packageName) = 0;
     virtual void startWatchingMode(int32_t op, const String16& packageName,
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index b7773c4..92a24ad 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -105,12 +105,11 @@
 }
 
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
-    for (auto const& state : other.mComposerStates) {
-        ssize_t index = mComposerStates.indexOf(state);
-        if (index < 0) {
-            mComposerStates.add(state);
+    for (auto const& kv : other.mComposerStates) {
+        if (mComposerStates.count(kv.first) == 0) {
+            mComposerStates[kv.first] = kv.second;
         } else {
-            mComposerStates.editItemAt(static_cast<size_t>(index)).state.merge(state.state);
+            mComposerStates[kv.first].state.merge(kv.second.state);
         }
     }
     other.mComposerStates.clear();
@@ -141,7 +140,10 @@
 
     mForceSynchronous |= synchronous;
 
-    composerStates = mComposerStates;
+    for (auto const& kv : mComposerStates){
+        composerStates.add(kv.second);
+    }
+
     mComposerStates.clear();
 
     displayStates = mDisplayStates;
@@ -182,18 +184,15 @@
 }
 
 layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
-    ComposerState s;
-    s.client = sc->getClient()->mClient;
-    s.state.surface = sc->getHandle();
-
-    ssize_t index = mComposerStates.indexOf(s);
-    if (index < 0) {
+    if (mComposerStates.count(sc) == 0) {
         // we don't have it, add an initialized layer_state to our list
-        index = mComposerStates.add(s);
+        ComposerState s;
+        s.client = sc->getClient()->mClient;
+        s.state.surface = sc->getHandle();
+        mComposerStates[sc] = s;
     }
 
-    ComposerState* const out = mComposerStates.editArray();
-    return &(out[index].state);
+    return &(mComposerStates[sc].state);
 }
 
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition(
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e5156c6..3fe6635 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <unordered_map>
 
 #include <binder/IBinder.h>
 
@@ -127,8 +128,14 @@
 
     static status_t injectVSync(nsecs_t when);
 
+    struct SCHash {
+        std::size_t operator()(const sp<SurfaceControl>& sc) const {
+            return std::hash<SurfaceControl *>{}(sc.get());
+        }
+    };
+
     class Transaction {
-        SortedVector<ComposerState> mComposerStates;
+        std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
         SortedVector<DisplayState > mDisplayStates;
         uint32_t                    mForceSynchronous = 0;
         uint32_t                    mTransactionNestCount = 0;
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 8a35509..b1d5e61 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -12,7 +12,7 @@
         "-Werror",
         "-Wno-unused-parameter",
     ],
-    shared_libs = [
+    shared_libs: [
         "libcutils",
         "liblog",
         "libutils",
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index ae34d34..3531c4e 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -73,8 +73,8 @@
 cc_library_headers {
     name: "libsurfaceflinger_headers",
     export_include_dirs: ["."],
-    static_libs = ["libserviceutils"],
-    export_static_lib_headers = ["libserviceutils"],
+    static_libs: ["libserviceutils"],
+    export_static_lib_headers: ["libserviceutils"],
 }
 
 filegroup {
@@ -139,7 +139,7 @@
         "frameworks/native/vulkan/include",
     ],
     cppflags: [
-        "-fwhole-program-vtables",  // requires ThinLTO
+        "-fwhole-program-vtables", // requires ThinLTO
     ],
     lto: {
         thin: true,
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 1a5a85e..389fbd2 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -33,26 +33,13 @@
     // because we don't know where this destructor is called from. It could be
     // called with the mStateLock held, leading to a dead-lock (it actually
     // happens).
-    class MessageCleanUpList : public MessageBase {
-    public:
-        MessageCleanUpList(const sp<SurfaceFlinger>& flinger,
-                const wp<IBinder>& producer)
-            : mFlinger(flinger), mProducer(producer) {}
+    sp<LambdaMessage> cleanUpListMessage =
+            new LambdaMessage([flinger = mFlinger, asBinder = wp<IBinder>(onAsBinder())]() {
+                Mutex::Autolock lock(flinger->mStateLock);
+                flinger->mGraphicBufferProducerList.erase(asBinder);
+            });
 
-        virtual ~MessageCleanUpList() {}
-
-        virtual bool handler() {
-            Mutex::Autolock _l(mFlinger->mStateLock);
-            mFlinger->mGraphicBufferProducerList.remove(mProducer);
-            return true;
-        }
-
-    private:
-        sp<SurfaceFlinger> mFlinger;
-        wp<IBinder> mProducer;
-    };
-
-    mFlinger->postMessageAsync(new MessageCleanUpList(mFlinger, asBinder(mProducer)));
+    mFlinger->postMessageAsync(cleanUpListMessage);
 }
 
 status_t MonitoredProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 9ecf8ce..ea7dc2f 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -210,42 +210,16 @@
     }
 }
 
-void GLES20RenderEngine::setColorMode(android_color_mode mode) {
-    ALOGV("setColorMode: %s (0x%x)", decodeColorMode(mode).c_str(), mode);
-
-    if (mColorMode == mode) return;
-
-    if (!mPlatformHasWideColor || !mDisplayHasWideColor || mode == HAL_COLOR_MODE_SRGB ||
-        mode == HAL_COLOR_MODE_NATIVE) {
-        // We are returning back to our default color_mode
-        mUseWideColor = false;
-        mWideColorFrameCount = 0;
-    } else {
-        mUseWideColor = true;
-    }
-
-    mColorMode = mode;
-}
-
-void GLES20RenderEngine::setSourceDataSpace(android_dataspace source) {
-    if (source == HAL_DATASPACE_UNKNOWN) {
-        // Treat UNKNOWN as SRGB
-        source = HAL_DATASPACE_V0_SRGB;
-    }
-    mDataSpace = source;
-}
-
 void GLES20RenderEngine::setSourceY410BT2020(bool enable) {
     mState.setY410BT2020(enable);
 }
 
-void GLES20RenderEngine::setWideColor(bool hasWideColor) {
-    ALOGV("setWideColor: %s", hasWideColor ? "true" : "false");
-    mDisplayHasWideColor = hasWideColor;
+void GLES20RenderEngine::setSourceDataSpace(android_dataspace source) {
+    mDataSpace = source;
 }
 
-bool GLES20RenderEngine::usesWideColor() {
-    return mUseWideColor;
+void GLES20RenderEngine::setOutputDataSpace(android_dataspace dataspace) {
+    mOutputDataSpace = dataspace;
 }
 
 void GLES20RenderEngine::setupLayerTexturing(const Texture& texture) {
@@ -326,17 +300,13 @@
     glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
                           mesh.getByteStride(), mesh.getPositions());
 
-    if (usesWideColor()) {
+    // DISPLAY_P3 is the only supported wide color output
+    if (mPlatformHasWideColor && mOutputDataSpace == HAL_DATASPACE_DISPLAY_P3) {
         Description wideColorState = mState;
         switch (int(mDataSpace)) {
             case HAL_DATASPACE_DISPLAY_P3:
                 // input matches output
                 break;
-            case HAL_DATASPACE_V0_SCRGB_LINEAR:
-                wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
-                wideColorState.setInputTransferFunction(Description::TransferFunction::LINEAR);
-                wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
-                break;
             case HAL_DATASPACE_BT2020_PQ:
             case HAL_DATASPACE_BT2020_ITU_PQ:
                 wideColorState.setColorMatrix(mState.getColorMatrix() * mBt2020ToDisplayP3);
@@ -345,8 +315,13 @@
                 wideColorState.enableToneMapping(true);
                 break;
             default:
+                // treat all other dataspaces as sRGB
                 wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
-                wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB);
+                if ((mDataSpace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_LINEAR) {
+                    wideColorState.setInputTransferFunction(Description::TransferFunction::LINEAR);
+                } else {
+                    wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB);
+                }
                 wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
                 ALOGV("drawMesh: gamut transform applied");
                 break;
@@ -356,8 +331,9 @@
         glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
 
         if (outputDebugPPMs) {
+            static uint64_t wideColorFrameCount = 0;
             std::ostringstream out;
-            out << "/data/texture_out" << mWideColorFrameCount++;
+            out << "/data/texture_out" << wideColorFrameCount++;
             writePPM(out.str().c_str(), mVpWidth, mVpHeight);
         }
     } else {
@@ -373,11 +349,9 @@
 
 void GLES20RenderEngine::dump(String8& result) {
     RenderEngine::dump(result);
-    if (usesWideColor()) {
-        result.append("Wide-color: On\n");
-    } else {
-        result.append("Wide-color: Off\n");
-    }
+    result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n",
+                        dataspaceDetails(mDataSpace).c_str(),
+                        dataspaceDetails(mOutputDataSpace).c_str());
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 6e86ea2..db3f792 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -72,27 +72,20 @@
                                     const half4& color) override;
 
     // Color management related functions and state
-    void setColorMode(android_color_mode mode);
-    void setSourceDataSpace(android_dataspace source);
-    void setSourceY410BT2020(bool enable);
-    void setWideColor(bool hasWideColor);
-    bool usesWideColor();
-
-    // Current color mode of display using the render engine
-    android_color_mode mColorMode = HAL_COLOR_MODE_NATIVE;
+    void setSourceY410BT2020(bool enable) override;
+    void setSourceDataSpace(android_dataspace source) override;
+    void setOutputDataSpace(android_dataspace dataspace) override;
 
     // Current dataspace of layer being rendered
-    android_dataspace mDataSpace = HAL_DATASPACE_V0_SRGB;
+    android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
 
-    // Indicate if wide-color mode is needed or not
-    bool mDisplayHasWideColor = false;
-    bool mUseWideColor = false;
-    uint64_t mWideColorFrameCount = 0;
+    // Current output dataspace of the render engine
+    android_dataspace mOutputDataSpace = HAL_DATASPACE_UNKNOWN;
 
     // Currently only supporting sRGB, BT2020 and DisplayP3 color spaces
+    const bool mPlatformHasWideColor = false;
     mat4 mSrgbToDisplayP3;
     mat4 mBt2020ToDisplayP3;
-    bool mPlatformHasWideColor = false;
 
     virtual void setupLayerTexturing(const Texture& texture);
     virtual void setupLayerBlackedOut();
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index eacef38..d140574 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -108,11 +108,6 @@
                                           bool yswap, Transform::orientation_flags rotation) = 0;
     virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
                                     const half4& color) = 0;
-    virtual void setColorMode(android_color_mode mode) = 0;
-    virtual void setSourceDataSpace(android_dataspace source) = 0;
-    virtual void setSourceY410BT2020(bool enable) = 0;
-    virtual void setWideColor(bool hasWideColor) = 0;
-    virtual bool usesWideColor() = 0;
     virtual void setupLayerTexturing(const Texture& texture) = 0;
     virtual void setupLayerBlackedOut() = 0;
     virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
@@ -122,6 +117,11 @@
     virtual void disableTexturing() = 0;
     virtual void disableBlending() = 0;
 
+    // wide color support
+    virtual void setSourceY410BT2020(bool enable) = 0;
+    virtual void setSourceDataSpace(android_dataspace source) = 0;
+    virtual void setOutputDataSpace(android_dataspace dataspace) = 0;
+
     // drawing
     virtual void drawMesh(const Mesh& mesh) = 0;
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e7c8bb2..cb410a1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -701,7 +701,7 @@
 bool SurfaceFlinger::authenticateSurfaceTextureLocked(
         const sp<IGraphicBufferProducer>& bufferProducer) const {
     sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer));
-    return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
+    return mGraphicBufferProducerList.count(surfaceTextureBinder.get()) > 0;
 }
 
 status_t SurfaceFlinger::getSupportedFrameTimestamps(
@@ -2266,9 +2266,8 @@
                 const wp<IBinder>& display(curr.keyAt(i));
 
                 if (dispSurface != nullptr) {
-                    bool useWideColorMode = hasWideColorDisplay;
-                    if (!mForceNativeColorMode) {
-                        bool hasWideColorModes = false;
+                    bool hasWideColorSupport = false;
+                    if (hasWideColorDisplay) {
                         std::vector<android_color_mode_t> modes =
                                 getHwComposer().getColorModes(state.type);
                         for (android_color_mode_t colorMode : modes) {
@@ -2276,13 +2275,12 @@
                                 case HAL_COLOR_MODE_DISPLAY_P3:
                                 case HAL_COLOR_MODE_ADOBE_RGB:
                                 case HAL_COLOR_MODE_DCI_P3:
-                                    hasWideColorModes = true;
+                                    hasWideColorSupport = true;
                                     break;
                                 default:
                                     break;
                             }
                         }
-                        useWideColorMode = hasWideColorModes && hasWideColorDisplay;
                     }
 
                     bool hasHdrSupport = false;
@@ -2296,11 +2294,11 @@
 
                     sp<DisplayDevice> hw =
                             new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
-                                              dispSurface, producer, useWideColorMode,
+                                              dispSurface, producer, hasWideColorSupport,
                                               hasHdrSupport);
 
                     android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
-                    if (useWideColorMode) {
+                    if (hasWideColorSupport) {
                         defaultColorMode = HAL_COLOR_MODE_SRGB;
                     }
                     setActiveColorModeInternal(hw, defaultColorMode);
@@ -2740,10 +2738,13 @@
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
 
-        getBE().mRenderEngine->setWideColor(
-                displayDevice->getWideColorSupport() && !mForceNativeColorMode);
-        getBE().mRenderEngine->setColorMode(mForceNativeColorMode ?
-                HAL_COLOR_MODE_NATIVE : displayDevice->getActiveColorMode());
+        android_dataspace outputDataspace = HAL_DATASPACE_UNKNOWN;
+        if (displayDevice->getWideColorSupport() &&
+                displayDevice->getActiveColorMode() == HAL_COLOR_MODE_DISPLAY_P3) {
+            outputDataspace = HAL_DATASPACE_DISPLAY_P3;
+        }
+        getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
+
         if (!displayDevice->makeCurrent()) {
             ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
                   displayDevice->getDisplayName().string());
@@ -2893,7 +2894,9 @@
             parent->addChild(lbc);
         }
 
-        mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
+        mGraphicBufferProducerList.insert(IInterface::asBinder(gbc).get());
+        LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() > MAX_LAYERS,
+                            "Suspected IGBP leak");
         mLayersAdded = true;
         mNumLayers++;
     }
@@ -4598,9 +4601,12 @@
         ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight);
     }
 
-    engine.setWideColor(renderArea.getWideColorSupport() && !mForceNativeColorMode);
-    engine.setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE
-                                              : renderArea.getActiveColorMode());
+    android_dataspace outputDataspace = HAL_DATASPACE_UNKNOWN;
+    if (renderArea.getWideColorSupport() &&
+            renderArea.getActiveColorMode() == HAL_COLOR_MODE_DISPLAY_P3) {
+        outputDataspace = HAL_DATASPACE_DISPLAY_P3;
+    }
+    getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
 
     // make sure to clear all GL error flags
     engine.checkErrors();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index aae8d2c..392acaa 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -717,7 +717,9 @@
     bool mTransactionPending;
     bool mAnimTransactionPending;
     SortedVector< sp<Layer> > mLayersPendingRemoval;
-    SortedVector< wp<IBinder> > mGraphicBufferProducerList;
+
+    // Can't be unordered_set because wp<> isn't hashable
+    std::set<wp<IBinder>> mGraphicBufferProducerList;
 
     // protected by mStateLock (but we could use another lock)
     bool mLayersRemoved;
diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp
index 8eb218c..485090c 100644
--- a/services/surfaceflinger/layerproto/Android.bp
+++ b/services/surfaceflinger/layerproto/Android.bp
@@ -33,4 +33,22 @@
         "-Wno-undef",
     ],
 
-}
\ No newline at end of file
+}
+
+java_library_static {
+    name: "layersprotosnano",
+    host_supported: true,
+    proto: {
+        type: "nano",
+    },
+    srcs: ["*.proto"],
+    no_framework_libs: true,
+    target: {
+        android: {
+            jarjar_rules: "jarjar-rules.txt",
+        },
+        host: {
+            static_libs: ["libprotobuf-java-nano"],
+        },
+    },
+}
diff --git a/services/surfaceflinger/layerproto/jarjar-rules.txt b/services/surfaceflinger/layerproto/jarjar-rules.txt
new file mode 100644
index 0000000..40043a8
--- /dev/null
+++ b/services/surfaceflinger/layerproto/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index be4127c..36424b9 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
 {
         "presubmit": {
-            "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*"
+            "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*"
         }
 }
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index ac8a2ad..92c26af 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -2460,4 +2460,49 @@
     ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, &outBuffer, Rect::EMPTY_RECT, 1.0));
 }
 
+
+class DereferenceSurfaceControlTest : public LayerTransactionTest {
+protected:
+    void SetUp() override {
+        LayerTransactionTest::SetUp();
+        bgLayer = createLayer("BG layer", 20, 20);
+        fillLayerColor(bgLayer, Color::RED);
+        fgLayer = createLayer("FG layer", 20, 20);
+        fillLayerColor(fgLayer, Color::BLUE);
+        Transaction().setLayer(fgLayer, mLayerZBase + 1).apply();
+        {
+            SCOPED_TRACE("before anything");
+            auto shot = screenshot();
+            shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
+        }
+    }
+    void TearDown() override {
+        LayerTransactionTest::TearDown();
+        bgLayer = 0;
+        fgLayer = 0;
+    }
+
+    sp<SurfaceControl> bgLayer;
+    sp<SurfaceControl> fgLayer;
+};
+
+TEST_F(DereferenceSurfaceControlTest, LayerNotInTransaction) {
+    fgLayer = nullptr;
+    {
+        SCOPED_TRACE("after setting null");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 20, 20), Color::RED);
+    }
+}
+
+TEST_F(DereferenceSurfaceControlTest, LayerInTransaction) {
+    auto transaction = Transaction().show(fgLayer);
+    fgLayer = nullptr;
+    {
+        SCOPED_TRACE("after setting null");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
+    }
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/MockRenderEngine.h
index aefbfcf..6d3e17f 100644
--- a/services/surfaceflinger/tests/unittests/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/MockRenderEngine.h
@@ -57,17 +57,15 @@
     MOCK_METHOD6(setViewportAndProjection,
                  void(size_t, size_t, Rect, size_t, bool, Transform::orientation_flags));
     MOCK_METHOD4(setupLayerBlending, void(bool, bool, bool, const half4&));
-    MOCK_METHOD1(setColorMode, void(android_color_mode));
-    MOCK_METHOD1(setSourceDataSpace, void(android_dataspace));
-    MOCK_METHOD1(setSourceY410BT2020, void(bool));
-    MOCK_METHOD1(setWideColor, void(bool));
-    MOCK_METHOD0(usesWideColor, bool());
     MOCK_METHOD1(setupLayerTexturing, void(const Texture&));
     MOCK_METHOD0(setupLayerBlackedOut, void());
     MOCK_METHOD4(setupFillWithColor, void(float, float, float, float));
     MOCK_METHOD1(setupColorTransform, mat4(const mat4&));
     MOCK_METHOD0(disableTexturing, void());
     MOCK_METHOD0(disableBlending, void());
+    MOCK_METHOD1(setSourceY410BT2020, void(bool));
+    MOCK_METHOD1(setSourceDataSpace, void(android_dataspace));
+    MOCK_METHOD1(setOutputDataSpace, void(android_dataspace));
     MOCK_METHOD2(bindNativeBufferAsFrameBuffer,
                  void(ANativeWindowBuffer*, RE::BindNativeBufferAsFramebuffer*));
     MOCK_METHOD1(unbindNativeBufferAsFrameBuffer, void(RE::BindNativeBufferAsFramebuffer*));
diff --git a/services/utils/tests/Android.bp b/services/utils/tests/Android.bp
index 15829fa..f21254c 100644
--- a/services/utils/tests/Android.bp
+++ b/services/utils/tests/Android.bp
@@ -17,13 +17,13 @@
 cc_test {
     name: "prioritydumper_test",
     test_suites: ["device-tests"],
-    srcs: [ "PriorityDumper_test.cpp"],
+    srcs: ["PriorityDumper_test.cpp"],
     shared_libs: [
         "libutils",
     ],
-    static_libs = [
+    static_libs: [
         "libgmock",
-        "libserviceutils"
+        "libserviceutils",
     ],
     clang: true,
-}
\ No newline at end of file
+}
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index 7196b2b..513fcc1 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -14,7 +14,7 @@
 ]
 
 header_libraries = [
-    "libdvr_headers"
+    "libdvr_headers",
 ]
 
 cc_library {
@@ -48,19 +48,19 @@
     srcs: test_src_files,
     static_libs: test_static_libs,
     header_libs: header_libraries,
-    cflags = [
+    cflags: [
         "-Wall",
         "-Werror",
     ],
-    cppflags = [
+    cppflags: [
         "-std=c++11",
     ],
-    host_ldlibs = [
+    host_ldlibs: [
         "-llog",
     ],
     name: "VirtualTouchpad_test",
     stl: "libc++_static",
-    tags: [ "optional" ],
+    tags: ["optional"],
 }
 
 // Service.