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.