Merge "Fix trivial compiler warnings"
diff --git a/cmds/flatland/Android.mk b/cmds/flatland/Android.mk
index c295167..7aa111c 100644
--- a/cmds/flatland/Android.mk
+++ b/cmds/flatland/Android.mk
@@ -8,6 +8,8 @@
Renderers.cpp \
Main.cpp \
+LOCAL_CFLAGS := -Wall -Werror
+
LOCAL_MODULE:= flatland
LOCAL_MODULE_TAGS := tests
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index ec1e543..3d7cac0 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -284,7 +284,6 @@
public:
Layer() :
- mFirstFrame(true),
mGLHelper(NULL),
mSurface(EGL_NO_SURFACE) {
}
@@ -358,8 +357,6 @@
}
private:
- bool mFirstFrame;
-
LayerDesc mDesc;
GLHelper* mGLHelper;
@@ -389,7 +386,6 @@
ATRACE_CALL();
bool result;
- EGLint resulte;
float scaleFactor = float(mDesc.runHeights[mInstance]) /
float(mDesc.height);
@@ -465,7 +461,6 @@
ATRACE_CALL();
bool result;
- status_t err;
resetColorGenerator();
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 20b7728..af2c527 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1385,6 +1385,8 @@
oat_dir.c_str(),
is_secondary_dex,
oat_path)) {
+ LOG(ERROR) << "Could not create oat out path for "
+ << apk_path << " with oat dir " << oat_dir;
return false;
}
oat_file_fd->reset(open(oat_path, O_RDONLY));
@@ -1489,7 +1491,7 @@
// Prepares the oat dir for the secondary dex files.
static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
- const char* instruction_set, std::string* oat_dir_out) {
+ const char* instruction_set) {
unsigned long dirIndex = dex_path.rfind('/');
if (dirIndex == std::string::npos) {
LOG(ERROR ) << "Unexpected dir structure for secondary dex " << dex_path;
@@ -1506,10 +1508,8 @@
char oat_dir[PKG_PATH_MAX];
snprintf(oat_dir, PKG_PATH_MAX, "%s/oat", dex_dir.c_str());
- oat_dir_out->assign(oat_dir);
- // Create oat/isa output directory.
- if (prepare_app_cache_dir(*oat_dir_out, instruction_set, oat_dir_mode, uid, uid) != 0) {
+ if (prepare_app_cache_dir(oat_dir, instruction_set, oat_dir_mode, uid, uid) != 0) {
LOG(ERROR) << "Could not prepare oat/isa dir for secondary dex: " << dex_path;
return false;
}
@@ -1517,39 +1517,128 @@
return true;
}
-static int constexpr DEXOPTANALYZER_BIN_EXEC_ERROR = 200;
+// Return codes for identifying the reason why dexoptanalyzer was not invoked when processing
+// secondary dex files. This return codes are returned by the child process created for
+// analyzing secondary dex files in process_secondary_dex_dexopt.
-// Verifies the result of dexoptanalyzer executed for the apk_path.
+// 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;
+
+// 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.
// Returns false for errors or unexpected result values.
-static bool process_dexoptanalyzer_result(const std::string& dex_path, int result,
+// 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) {
// The result values are defined in dexoptanalyzer.
switch (result) {
- case 0: // no_dexopt_needed
+ case 0: // dexoptanalyzer: no_dexopt_needed
*dexopt_needed_out = NO_DEXOPT_NEEDED; return true;
- case 1: // dex2oat_from_scratch
+ case 1: // dexoptanalyzer: dex2oat_from_scratch
*dexopt_needed_out = DEX2OAT_FROM_SCRATCH; return true;
- case 5: // dex2oat_for_bootimage_odex
+ case 5: // dexoptanalyzer: dex2oat_for_bootimage_odex
*dexopt_needed_out = -DEX2OAT_FOR_BOOT_IMAGE; return true;
- case 6: // dex2oat_for_filter_odex
+ case 6: // dexoptanalyzer: dex2oat_for_filter_odex
*dexopt_needed_out = -DEX2OAT_FOR_FILTER; return true;
- case 7: // dex2oat_for_relocation_odex
+ case 7: // dexoptanalyzer: dex2oat_for_relocation_odex
*dexopt_needed_out = -DEX2OAT_FOR_RELOCATION; return true;
- case 2: // dex2oat_for_bootimage_oat
- case 3: // dex2oat_for_filter_oat
- case 4: // dex2oat_for_relocation_oat
+ 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;
return false;
+ case SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE:
+ // 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:
+ return false;
default:
- LOG(ERROR) << "Unexpected result for dexoptanalyzer " << dex_path
- << " exec_dexoptanalyzer result=" << result;
+ LOG(ERROR) << "Unexpected result from analyzing secondary dex " << dex_path
+ << " result=" << result;
return false;
}
}
+enum SecondaryDexAccess {
+ kSecondaryDexAccessReadOk = 0,
+ kSecondaryDexAccessDoesNotExist = 1,
+ kSecondaryDexAccessPermissionError = 2,
+ kSecondaryDexAccessIOError = 3
+};
+
+static SecondaryDexAccess check_secondary_dex_access(const std::string& dex_path) {
+ // Check if the path exists and can be read. If not, there's nothing to do.
+ if (access(dex_path.c_str(), R_OK) == 0) {
+ return kSecondaryDexAccessReadOk;
+ } else {
+ if (errno == ENOENT) {
+ LOG(INFO) << "Secondary dex does not exist: " << dex_path;
+ return kSecondaryDexAccessDoesNotExist;
+ } else {
+ PLOG(ERROR) << "Could not access secondary dex " << dex_path;
+ return errno == EACCES
+ ? kSecondaryDexAccessPermissionError
+ : kSecondaryDexAccessIOError;
+ }
+ }
+}
+
+static bool is_file_public(const std::string& filename) {
+ struct stat file_stat;
+ if (stat(filename.c_str(), &file_stat) == 0) {
+ return (file_stat.st_mode & S_IROTH) != 0;
+ }
+ return false;
+}
+
+// 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) {
+ size_t dirIndex = dex_path.rfind('/');
+ if (dirIndex == std::string::npos) {
+ LOG(ERROR) << "Unexpected dir structure for dex file " << dex_path;
+ return false;
+ }
+ // TODO(calin): we have similar computations in at lest 3 other places
+ // (InstalldNativeService, otapropt and dexopt). Unify them and get rid of snprintf by
+ // using string append.
+ std::string apk_dir = dex_path.substr(0, dirIndex);
+ snprintf(out_oat_dir, PKG_PATH_MAX, "%s/oat", apk_dir.c_str());
+ snprintf(out_oat_isa_dir, PKG_PATH_MAX, "%s/%s", out_oat_dir, isa.c_str());
+
+ 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;
+ return false;
+ }
+ return true;
+}
+
+// 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) {
+ 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";
+ 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";
+ return false;
+ }
+ return true;
+}
+
// Processes the dex_path as a secondary dex files and return true if the path dex file should
// be compiled. Returns false for errors (logged) or true if the secondary dex path was process
// successfully.
@@ -1557,126 +1646,107 @@
// - is_public_out: whether or not the oat file should not be made public
// - dexopt_needed_out: valid OatFileAsssitant::DexOptNeeded
// - oat_dir_out: the oat dir path where the oat file should be stored
-// - dex_path_out: the real path of the dex file
-static bool process_secondary_dex_dexopt(const char* original_dex_path, const char* pkgname,
+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, std::string* dex_path_out, bool downgrade,
- const char* class_loader_context) {
+ std::string* oat_dir_out, bool downgrade, const char* class_loader_context) {
+ LOG(DEBUG) << "Processing secondary dex path " << dex_path;
int storage_flag;
-
- if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
- 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";
- return false;
- }
- } else if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
- storage_flag = FLAG_STORAGE_DE;
- } else {
- LOG(ERROR) << "Secondary dex storage flag must be set";
+ if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag)) {
return false;
}
-
- {
- // As opposed to the primary apk, secondary dex files might contain symlinks.
- // Resolve the path before passing it to the validate method to
- // make sure the verification is done on the real location.
- UniqueCPtr<char> dex_real_path_cstr(realpath(original_dex_path, nullptr));
- if (dex_real_path_cstr == nullptr) {
- PLOG(ERROR) << "Could not get the real path of the secondary dex file "
- << original_dex_path;
- return false;
- } else {
- dex_path_out->assign(dex_real_path_cstr.get());
- }
- }
- const std::string& dex_path = *dex_path_out;
- if (!validate_dex_path_size(dex_path)) {
+ // Compute the oat dir as it's not easy to extract it from the child computation.
+ char oat_path[PKG_PATH_MAX];
+ 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;
return false;
}
- if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
- LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
- return false;
- }
-
- // Check if the path exist. If not, there's nothing to do.
- struct stat dex_path_stat;
- if (stat(dex_path.c_str(), &dex_path_stat) != 0) {
- if (errno == ENOENT) {
- // Secondary dex files might be deleted any time by the app.
- // Nothing to do if that's the case
- ALOGV("Secondary dex does not exist %s", dex_path.c_str());
- return NO_DEXOPT_NEEDED;
- } else {
- PLOG(ERROR) << "Could not access secondary dex " << dex_path;
- }
- }
-
- // Check if we should make the oat file public.
- // Note that if the dex file is not public the compiled code cannot be made public.
- *is_public_out = ((dexopt_flags & DEXOPT_PUBLIC) != 0) &&
- ((dex_path_stat.st_mode & S_IROTH) != 0);
-
- // Prepare the oat directories.
- if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set, oat_dir_out)) {
- return false;
- }
-
- // Analyze profiles.
- bool profile_was_updated = analyze_profiles(uid, dex_path, /*is_secondary_dex*/true);
-
- unique_fd oat_file_fd;
- unique_fd vdex_file_fd;
- unique_fd zip_fd;
- zip_fd.reset(open(dex_path.c_str(), O_RDONLY));
- if (zip_fd.get() < 0) {
- PLOG(ERROR) << "installd cannot open " << dex_path << " for input during dexopt";
- return false;
- }
- if (!maybe_open_oat_and_vdex_file(dex_path,
- *oat_dir_out,
- instruction_set,
- true /* is_secondary_dex */,
- &oat_file_fd,
- &vdex_file_fd)) {
- return false;
- }
+ oat_dir_out->assign(oat_dir);
pid_t pid = fork();
if (pid == 0) {
// child -- drop privileges before continuing.
drop_capabilities(uid);
- // Run dexoptanalyzer to get dexopt_needed code.
+
+ // 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);
+ }
+
+ // Open the dex file.
+ unique_fd zip_fd;
+ 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);
+ } else {
+ _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+ }
+ }
+
+ // Prepare the oat directories.
+ if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set)) {
+ _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+ }
+
+ // Open the vdex/oat files if any.
+ unique_fd oat_file_fd;
+ unique_fd vdex_file_fd;
+ if (!maybe_open_oat_and_vdex_file(dex_path,
+ *oat_dir_out,
+ instruction_set,
+ true /* is_secondary_dex */,
+ &oat_file_fd,
+ &vdex_file_fd)) {
+ _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+ }
+
+ // Analyze profiles.
+ bool profile_was_updated = analyze_profiles(uid, dex_path, /*is_secondary_dex*/true);
+
+ // Run dexoptanalyzer to get dexopt_needed code. This is not expected to return.
exec_dexoptanalyzer(dex_path,
vdex_file_fd.get(),
oat_file_fd.get(),
zip_fd.get(),
instruction_set,
- compiler_filter,
- profile_was_updated,
- downgrade, class_loader_context);
- exit(DEXOPTANALYZER_BIN_EXEC_ERROR);
+ compiler_filter, profile_was_updated,
+ downgrade,
+ class_loader_context);
+ PLOG(ERROR) << "Failed to exec dexoptanalyzer";
+ _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
}
/* parent */
-
int result = wait_child(pid);
if (!WIFEXITED(result)) {
LOG(ERROR) << "dexoptanalyzer failed for path " << dex_path << ": " << result;
return false;
}
result = WEXITSTATUS(result);
- bool success = process_dexoptanalyzer_result(dex_path, result, dexopt_needed_out);
+ // Check that we successfully executed dexoptanalyzer.
+ bool success = process_secondary_dexoptanalyzer_result(dex_path, result, dexopt_needed_out);
+
+ LOG(DEBUG) << "Processed secondary dex file " << dex_path << " result=" << result;
+
// Run dexopt only if needed or forced.
- // Note that dexoptanalyzer is executed even if force compilation is enabled.
- // We ignore its valid dexopNeeded result, but still check (in process_dexoptanalyzer_result)
- // that we only get results for odex files (apk_dir/oat/isa/code.odex) and not
- // for oat files from dalvik-cache.
- if (success && ((dexopt_flags & DEXOPT_FORCE) != 0)) {
+ // 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) &&
+ ((dexopt_flags & DEXOPT_FORCE) != 0)) {
*dexopt_needed_out = DEX2OAT_FROM_SCRATCH;
}
+ // Check if we should make the oat file public.
+ // Note that if the dex file is not public the compiled code cannot be made public.
+ // It is ok to check this flag outside in the parent process.
+ *is_public_out = ((dexopt_flags & DEXOPT_PUBLIC) != 0) && is_file_public(dex_path);
+
return success;
}
@@ -1708,13 +1778,11 @@
// Check if we're dealing with a secondary dex file and if we need to compile it.
std::string oat_dir_str;
- std::string dex_real_path;
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,
- &dex_real_path, downgrade, class_loader_context)) {
+ downgrade, class_loader_context)) {
oat_dir = oat_dir_str.c_str();
- dex_path = dex_real_path.c_str();
if (dexopt_needed == NO_DEXOPT_NEEDED) {
return 0; // Nothing to do, report success.
}
@@ -1852,29 +1920,13 @@
return false;
}
-// 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,
- /*out*/char* out_oat_dir, /*out*/char* out_oat_isa_dir, /*out*/char* out_oat_path) {
- size_t dirIndex = dex_path.rfind('/');
- if (dirIndex == std::string::npos) {
- LOG(ERROR) << "Unexpected dir structure for dex file " << dex_path;
- return false;
- }
- // TODO(calin): we have similar computations in at lest 3 other places
- // (InstalldNativeService, otapropt and dexopt). Unify them and get rid of snprintf by
- // use string append.
- std::string apk_dir = dex_path.substr(0, dirIndex);
- snprintf(out_oat_dir, PKG_PATH_MAX, "%s/oat", apk_dir.c_str());
- snprintf(out_oat_isa_dir, PKG_PATH_MAX, "%s/%s", out_oat_dir, isa.c_str());
-
- 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;
- return false;
- }
- return true;
-}
+enum ReconcileSecondaryDexResult {
+ kReconcileSecondaryDexExists = 0,
+ kReconcileSecondaryDexCleanedUp = 1,
+ kReconcileSecondaryDexValidationError = 2,
+ kReconcileSecondaryDexCleanUpError = 3,
+ kReconcileSecondaryDexAccessIOError = 4,
+};
// Reconcile the secondary dex 'dex_path' and its generated oat files.
// Return true if all the parameters are valid and the secondary dex file was
@@ -1888,36 +1940,15 @@
const std::string& pkgname, int uid, const std::vector<std::string>& isas,
const std::unique_ptr<std::string>& volume_uuid, int storage_flag,
/*out*/bool* out_secondary_dex_exists) {
- // Set out to false to start with, just in case we have validation errors.
- *out_secondary_dex_exists = false;
- if (!validate_dex_path_size(dex_path)) {
- return false;
- }
-
+ *out_secondary_dex_exists = false; // start by assuming the file does not exist.
if (isas.size() == 0) {
LOG(ERROR) << "reconcile_secondary_dex_file called with empty isas vector";
return false;
}
- const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
-
- // Note that we cannot validate the package path here because the file might not exist
- // and we cannot call realpath to resolve system symlinks. Since /data/user/0 symlinks to
- // /data/data/ a lot of validations will fail if we attempt to check the package path.
- // It is still ok to be more relaxed because any file removal is done after forking and
- // dropping capabilities.
- if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
- uid, storage_flag, /*validate_package_path*/ false)) {
- LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
- return false;
- }
-
- if (access(dex_path.c_str(), F_OK) == 0) {
- // The path exists, nothing to do. The odex files (if any) will be left untouched.
- *out_secondary_dex_exists = true;
- return true;
- } else if (errno != ENOENT) {
- PLOG(ERROR) << "Failed to check access to secondary dex " << dex_path;
+ if (storage_flag != FLAG_STORAGE_CE && storage_flag != FLAG_STORAGE_DE) {
+ LOG(ERROR) << "reconcile_secondary_dex_file called with invalid storage_flag: "
+ << storage_flag;
return false;
}
@@ -1925,23 +1956,39 @@
// of the package user id. So we fork and drop capabilities in the child.
pid_t pid = fork();
if (pid == 0) {
- // The secondary dex does not exist anymore. Clear any generated files.
+ /* child -- drop privileges before continuing */
+ drop_capabilities(uid);
+
+ const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
+ if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
+ uid, storage_flag)) {
+ LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+ _exit(kReconcileSecondaryDexValidationError);
+ }
+
+ SecondaryDexAccess access_check = check_secondary_dex_access(dex_path);
+ switch (access_check) {
+ case kSecondaryDexAccessDoesNotExist:
+ // File does not exist. Proceed with cleaning.
+ break;
+ case kSecondaryDexAccessReadOk: _exit(kReconcileSecondaryDexExists);
+ case kSecondaryDexAccessIOError: _exit(kReconcileSecondaryDexAccessIOError);
+ case kSecondaryDexAccessPermissionError: _exit(kReconcileSecondaryDexValidationError);
+ default:
+ LOG(ERROR) << "Unexpected result from check_secondary_dex_access: " << access_check;
+ _exit(kReconcileSecondaryDexValidationError);
+ }
+
+ // The secondary dex does not exist anymore or it's. Clear any generated files.
char oat_path[PKG_PATH_MAX];
char oat_dir[PKG_PATH_MAX];
char oat_isa_dir[PKG_PATH_MAX];
bool result = true;
- /* child -- drop privileges before continuing */
- drop_capabilities(uid);
for (size_t i = 0; i < isas.size(); i++) {
- 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;
- result = false;
- continue;
+ 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;
+ _exit(kReconcileSecondaryDexValidationError);
}
// Delete oat/vdex/art files.
@@ -1966,11 +2013,43 @@
result = rmdir_if_empty(oat_isa_dir) && result;
result = rmdir_if_empty(oat_dir) && result;
}
- result ? _exit(0) : _exit(1);
+ if (!result) {
+ PLOG(ERROR) << "Failed to clean secondary dex artifacts for location " << dex_path;
+ }
+ _exit(result ? kReconcileSecondaryDexCleanedUp : kReconcileSecondaryDexAccessIOError);
}
int return_code = wait_child(pid);
- return return_code == 0;
+ if (!WIFEXITED(return_code)) {
+ LOG(WARNING) << "reconcile dex failed for location " << dex_path << ": " << return_code;
+ } else {
+ return_code = WEXITSTATUS(return_code);
+ }
+
+ LOG(DEBUG) << "Reconcile secondary dex path " << dex_path << " result=" << return_code;
+
+ switch (return_code) {
+ case kReconcileSecondaryDexCleanedUp:
+ case kReconcileSecondaryDexValidationError:
+ // If we couldn't validate assume the dex file does not exist.
+ // This will purge the entry from the PM records.
+ *out_secondary_dex_exists = false;
+ return true;
+ case kReconcileSecondaryDexExists:
+ *out_secondary_dex_exists = true;
+ return true;
+ case kReconcileSecondaryDexAccessIOError:
+ // We had an access IO error.
+ // Return false so that we can try again.
+ // The value of out_secondary_dex_exists does not matter in this case and by convention
+ // is set to false.
+ *out_secondary_dex_exists = false;
+ return false;
+ default:
+ LOG(ERROR) << "Unexpected code from reconcile_secondary_dex_file: " << return_code;
+ *out_secondary_dex_exists = false;
+ return false;
+ }
}
// Helper for move_ab, so that we can have common failure-case cleanup.
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 89c11aa..1a22992 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -55,3 +55,23 @@
"liblogwrap",
],
}
+
+cc_test {
+ name: "installd_dexopt_test",
+ clang: true,
+ srcs: ["installd_dexopt_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libselinux",
+ "libutils",
+ ],
+ static_libs: [
+ "libdiskusage",
+ "libinstalld",
+ "liblog",
+ "liblogwrap",
+ ],
+}
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
new file mode 100644
index 0000000..821b96f
--- /dev/null
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2017 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 <stdlib.h>
+#include <string.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
+
+#include "dexopt.h"
+#include "InstalldNativeService.h"
+#include "globals.h"
+#include "tests/test_utils.h"
+#include "utils.h"
+
+namespace android {
+namespace installd {
+
+// TODO(calin): try to dedup this code.
+#if defined(__arm__)
+static const std::string kRuntimeIsa = "arm";
+#elif defined(__aarch64__)
+static const std::string kRuntimeIsa = "arm64";
+#elif defined(__mips__) && !defined(__LP64__)
+static const std::string kRuntimeIsa = "mips";
+#elif defined(__mips__) && defined(__LP64__)
+static const std::string kRuntimeIsa = "mips64";
+#elif defined(__i386__)
+static const std::string kRuntimeIsa = "x86";
+#elif defined(__x86_64__)
+static const std::string kRuntimeIsa = "x86_64";
+#else
+static const std::string kRuntimeIsa = "none";
+#endif
+
+int get_property(const char *key, char *value, const char *default_value) {
+ return property_get(key, value, default_value);
+}
+
+bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
+ const char *instruction_set) {
+ return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
+}
+
+bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
+ const char *instruction_set) {
+ return calculate_odex_file_path_default(path, apk_path, instruction_set);
+}
+
+bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
+ return create_cache_path_default(path, src, instruction_set);
+}
+
+static void run_cmd(const std::string& cmd) {
+ system(cmd.c_str());
+}
+
+static void mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
+ ::mkdir(path.c_str(), mode);
+ ::chown(path.c_str(), owner, group);
+ ::chmod(path.c_str(), mode);
+}
+
+// Base64 encoding of a simple dex files with 2 methods.
+static const char kDexFile[] =
+ "UEsDBBQAAAAIAOiOYUs9y6BLCgEAABQCAAALABwAY2xhc3Nlcy5kZXhVVAkAA/Ns+lkOHv1ZdXgL"
+ "AAEEI+UCAASIEwAAS0mt4DIwNmX4qpn7j/2wA7v7N+ZvoQpCJRlVx5SWa4YaiDAxMBQwMDBUhJkI"
+ "MUBBDyMDAzsDRJwFxAdioBDDHAYEYAbiFUAM1M5wAIhFGCGKDIDYAogdgNgDiH2BOAiI0xghekDm"
+ "sQIxGxQzM6ACRijNhCbOhCZfyohdPYyuh8szgtVkMkLsLhAAqeCDi+ejibPZZOZlltgxsDnqZSWW"
+ "JTKwOUFoZh9HayDhZM0g5AMS0M9JzEvX90/KSk0usWZgDAMaws5nAyXBzmpoYGlgAjsAyJoBMp0b"
+ "zQ8gGhbOTEhhzYwU3qxIYc2GFN6MClC/AhUyKUDMAYU9M1Qc5F8GKBscVgIQM0FxCwBQSwECHgMU"
+ "AAAACADojmFLPcugSwoBAAAUAgAACwAYAAAAAAAAAAAAoIEAAAAAY2xhc3Nlcy5kZXhVVAUAA/Ns"
+ "+ll1eAsAAQQj5QIABIgTAABQSwUGAAAAAAEAAQBRAAAATwEAAAAA";
+
+
+class DexoptTest : public testing::Test {
+protected:
+ static constexpr bool kDebug = false;
+ static constexpr uid_t kSystemUid = 1000;
+ static constexpr uid_t kSystemGid = 1000;
+ static constexpr int32_t kOSdkVersion = 25;
+ static constexpr int32_t kAppDataFlags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+ static constexpr uid_t kTestAppUid = 19999;
+ static constexpr gid_t kTestAppGid = 19999;
+ static constexpr int32_t kTestUserId = 0;
+
+ InstalldNativeService* service_;
+ std::unique_ptr<std::string> volume_uuid_;
+ std::string package_name_;
+ std::string app_apk_dir_;
+ std::string app_private_dir_ce_;
+ std::string app_private_dir_de_;
+ std::string se_info_;
+
+ int64_t ce_data_inode_;
+
+ std::string secondary_dex_ce_;
+ std::string secondary_dex_ce_link_;
+ std::string secondary_dex_de_;
+
+ virtual void SetUp() {
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
+ android::base::InitLogging(nullptr);
+
+ service_ = new InstalldNativeService();
+
+ volume_uuid_ = nullptr;
+ package_name_ = "com.installd.test.dexopt";
+ se_info_ = "default";
+
+ init_globals_from_data_and_root();
+
+ app_apk_dir_ = android_app_dir + package_name_;
+
+ create_mock_app();
+ }
+
+ virtual void TearDown() {
+ if (!kDebug) {
+ service_->destroyAppData(
+ volume_uuid_, package_name_, kTestUserId, kAppDataFlags, ce_data_inode_);
+ run_cmd("rm -rf " + app_apk_dir_);
+ run_cmd("rm -rf " + app_private_dir_ce_);
+ run_cmd("rm -rf " + app_private_dir_de_);
+ }
+ delete service_;
+ }
+
+ void create_mock_app() {
+ // Create the oat dir.
+ std::string app_oat_dir = app_apk_dir_ + "/oat";
+ mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755);
+ service_->createOatDir(app_oat_dir, kRuntimeIsa);
+
+ // Copy the primary apk.
+ std::string apk_path = app_apk_dir_ + "/base.jar";
+ ASSERT_TRUE(WriteBase64ToFile(kDexFile, apk_path, kSystemUid, kSystemGid, 0644));
+
+ // Create the app user data.
+ ASSERT_TRUE(service_->createAppData(
+ volume_uuid_,
+ package_name_,
+ kTestUserId,
+ kAppDataFlags,
+ kTestAppUid,
+ se_info_,
+ kOSdkVersion,
+ &ce_data_inode_).isOk());
+
+ // Create a secondary dex file on CE storage
+ const char* volume_uuid_cstr = volume_uuid_ == nullptr ? nullptr : volume_uuid_->c_str();
+ app_private_dir_ce_ = create_data_user_ce_package_path(
+ volume_uuid_cstr, kTestUserId, package_name_.c_str());
+ secondary_dex_ce_ = app_private_dir_ce_ + "/secondary_ce.jar";
+ ASSERT_TRUE(WriteBase64ToFile(kDexFile, secondary_dex_ce_, kTestAppUid, kTestAppGid, 0600));
+ std::string app_private_dir_ce_link = create_data_user_ce_package_path_as_user_link(
+ volume_uuid_cstr, kTestUserId, package_name_.c_str());
+ secondary_dex_ce_link_ = app_private_dir_ce_link + "/secondary_ce.jar";
+
+ // Create a secondary dex file on DE storage.
+ app_private_dir_de_ = create_data_user_de_package_path(
+ volume_uuid_cstr, kTestUserId, package_name_.c_str());
+ secondary_dex_de_ = app_private_dir_de_ + "/secondary_de.jar";
+ ASSERT_TRUE(WriteBase64ToFile(kDexFile, secondary_dex_de_, kTestAppUid, kTestAppGid, 0600));
+
+ // Fix app data uid.
+ ASSERT_TRUE(service_->fixupAppData(volume_uuid_, kTestUserId).isOk());
+ }
+
+
+ std::string get_secondary_dex_artifact(const std::string& path, const std::string& type) {
+ std::string::size_type end = path.rfind('.');
+ std::string::size_type start = path.rfind('/', end);
+ return path.substr(0, start) + "/oat/" + kRuntimeIsa + "/" +
+ path.substr(start + 1, end - start) + type;
+ }
+
+ void compile_secondary_dex(const std::string& path, int32_t dex_storage_flag,
+ bool should_binder_call_succeed, bool should_dex_be_compiled = true,
+ int uid = kTestAppUid) {
+ std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
+ int32_t dexopt_needed = 0; // does not matter;
+ std::unique_ptr<std::string> out_path = nullptr; // does not matter
+ int32_t dex_flags = DEXOPT_SECONDARY_DEX | dex_storage_flag;
+ std::string compiler_filter = "speed-profile";
+ std::unique_ptr<std::string> class_loader_context_ptr(new std::string("&"));
+ std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
+ bool downgrade = false;
+
+ binder::Status result = service_->dexopt(path,
+ uid,
+ package_name_ptr,
+ kRuntimeIsa,
+ dexopt_needed,
+ out_path,
+ dex_flags,
+ compiler_filter,
+ volume_uuid_,
+ class_loader_context_ptr,
+ se_info_ptr,
+ downgrade);
+ ASSERT_EQ(should_binder_call_succeed, result.isOk());
+ int expected_access = should_dex_be_compiled ? 0 : -1;
+ std::string odex = get_secondary_dex_artifact(path, "odex");
+ std::string vdex = get_secondary_dex_artifact(path, "vdex");
+ std::string art = get_secondary_dex_artifact(path, "art");
+ 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.
+ }
+
+ void reconcile_secondary_dex(const std::string& path, int32_t storage_flag,
+ bool should_binder_call_succeed, bool should_dex_exist, bool should_dex_be_deleted,
+ int uid = kTestAppUid, std::string* package_override = nullptr) {
+ std::vector<std::string> isas;
+ isas.push_back(kRuntimeIsa);
+ bool out_secondary_dex_exists = false;
+ binder::Status result = service_->reconcileSecondaryDexFile(
+ path,
+ package_override == nullptr ? package_name_ : *package_override,
+ uid,
+ isas,
+ volume_uuid_,
+ storage_flag,
+ &out_secondary_dex_exists);
+
+ ASSERT_EQ(should_binder_call_succeed, result.isOk());
+ ASSERT_EQ(should_dex_exist, out_secondary_dex_exists);
+
+ int expected_access = should_dex_be_deleted ? -1 : 0;
+ std::string odex = get_secondary_dex_artifact(path, "odex");
+ std::string vdex = get_secondary_dex_artifact(path, "vdex");
+ std::string art = get_secondary_dex_artifact(path, "art");
+ ASSERT_EQ(expected_access, access(odex.c_str(), F_OK));
+ ASSERT_EQ(expected_access, access(vdex.c_str(), F_OK));
+ ASSERT_EQ(-1, access(art.c_str(), R_OK)); // empty profiles do not generate an image.
+ }
+};
+
+
+TEST_F(DexoptTest, DexoptSecondaryCe) {
+ LOG(INFO) << "DexoptSecondaryCe";
+ compile_secondary_dex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+ /*binder_ok*/ true, /*compile_ok*/ true);
+}
+
+TEST_F(DexoptTest, DexoptSecondaryCeLink) {
+ LOG(INFO) << "DexoptSecondaryCeLink";
+ compile_secondary_dex(secondary_dex_ce_link_, DEXOPT_STORAGE_CE,
+ /*binder_ok*/ true, /*compile_ok*/ true);
+}
+
+TEST_F(DexoptTest, DexoptSecondaryDe) {
+ LOG(INFO) << "DexoptSecondaryDe";
+ compile_secondary_dex(secondary_dex_de_, DEXOPT_STORAGE_DE,
+ /*binder_ok*/ true, /*compile_ok*/ true);
+}
+
+TEST_F(DexoptTest, DexoptSecondaryDoesNotExist) {
+ LOG(INFO) << "DexoptSecondaryDoesNotExist";
+ // If the file validates but does not exist we do not treat it as an error.
+ compile_secondary_dex(secondary_dex_ce_ + "not.there", DEXOPT_STORAGE_CE,
+ /*binder_ok*/ true, /*compile_ok*/ false);
+}
+
+TEST_F(DexoptTest, DexoptSecondaryStorageValidationError) {
+ LOG(INFO) << "DexoptSecondaryStorageValidationError";
+ compile_secondary_dex(secondary_dex_ce_, DEXOPT_STORAGE_DE,
+ /*binder_ok*/ false, /*compile_ok*/ false);
+}
+
+TEST_F(DexoptTest, DexoptSecondaryAppOwnershipValidationError) {
+ LOG(INFO) << "DexoptSecondaryAppOwnershipValidationError";
+ compile_secondary_dex("/data/data/random.app/secondary.jar", DEXOPT_STORAGE_CE,
+ /*binder_ok*/ false, /*compile_ok*/ false);
+}
+
+TEST_F(DexoptTest, DexoptSecondaryAcessViaDifferentUidError) {
+ LOG(INFO) << "DexoptSecondaryAcessViaDifferentUidError";
+ compile_secondary_dex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+ /*binder_ok*/ false, /*compile_ok*/ false, kSystemUid);
+}
+
+
+class ReconcileTest : public DexoptTest {
+ virtual void SetUp() {
+ DexoptTest::SetUp();
+ compile_secondary_dex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+ /*binder_ok*/ true, /*compile_ok*/ true);
+ compile_secondary_dex(secondary_dex_de_, DEXOPT_STORAGE_DE,
+ /*binder_ok*/ true, /*compile_ok*/ true);
+ }
+};
+
+TEST_F(ReconcileTest, ReconcileSecondaryCeExists) {
+ LOG(INFO) << "ReconcileSecondaryCeExists";
+ reconcile_secondary_dex(secondary_dex_ce_, FLAG_STORAGE_CE,
+ /*binder_ok*/ true, /*dex_ok */ true, /*odex_deleted*/ false);
+}
+
+TEST_F(ReconcileTest, ReconcileSecondaryCeLinkExists) {
+ LOG(INFO) << "ReconcileSecondaryCeLinkExists";
+ reconcile_secondary_dex(secondary_dex_ce_link_, FLAG_STORAGE_CE,
+ /*binder_ok*/ true, /*dex_ok */ true, /*odex_deleted*/ false);
+}
+
+TEST_F(ReconcileTest, ReconcileSecondaryDeExists) {
+ LOG(INFO) << "ReconcileSecondaryDeExists";
+ reconcile_secondary_dex(secondary_dex_de_, FLAG_STORAGE_DE,
+ /*binder_ok*/ true, /*dex_ok */ true, /*odex_deleted*/ false);
+}
+
+TEST_F(ReconcileTest, ReconcileSecondaryDeDoesNotExist) {
+ LOG(INFO) << "ReconcileSecondaryDeDoesNotExist";
+ run_cmd("rm -rf " + secondary_dex_de_);
+ reconcile_secondary_dex(secondary_dex_de_, FLAG_STORAGE_DE,
+ /*binder_ok*/ true, /*dex_ok */ false, /*odex_deleted*/ true);
+}
+
+TEST_F(ReconcileTest, ReconcileSecondaryStorageValidationError) {
+ // Validation errors will not clean the odex/vdex/art files but will mark
+ // the file as non existent so that the PM knows it should purge it from its
+ // records.
+ LOG(INFO) << "ReconcileSecondaryStorageValidationError";
+ reconcile_secondary_dex(secondary_dex_ce_, FLAG_STORAGE_DE,
+ /*binder_ok*/ true, /*dex_ok */ false, /*odex_deleted*/ false);
+}
+
+TEST_F(ReconcileTest, ReconcileSecondaryAppOwnershipValidationError) {
+ LOG(INFO) << "ReconcileSecondaryAppOwnershipValidationError";
+ // Attempt to reconcile the dex files of the test app from a different app.
+ std::string another_app = "another.app";
+ reconcile_secondary_dex(secondary_dex_ce_, FLAG_STORAGE_CE,
+ /*binder_ok*/ true, /*dex_ok */ false, /*odex_deleted*/ false, kSystemUid, &another_app);
+}
+
+TEST_F(ReconcileTest, ReconcileSecondaryAcessViaDifferentUidError) {
+ LOG(INFO) << "ReconcileSecondaryAcessViaDifferentUidError";
+ reconcile_secondary_dex(secondary_dex_ce_, FLAG_STORAGE_CE,
+ /*binder_ok*/ true, /*dex_ok */ false, /*odex_deleted*/ false, kSystemUid);
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 2ca7ac2..a6a4451 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -379,6 +379,7 @@
TEST_F(UtilsTest, ValidateSecondaryDexFilesPath) {
std::string package_name = "com.test.app";
std::string app_dir_ce_user_0 = "/data/data/" + package_name;
+ std::string app_dir_ce_user_0_link = "/data/user/0/" + package_name;
std::string app_dir_ce_user_10 = "/data/user/10/" + package_name;
std::string app_dir_de_user_0 = "/data/user_de/0/" + package_name;
@@ -400,6 +401,8 @@
// Standard path for user 0 on CE storage.
pass_secondary_dex_validation(
package_name, app_dir_ce_user_0 + "/ce0.dex", app_uid_for_user_0, FLAG_STORAGE_CE);
+ pass_secondary_dex_validation(
+ package_name, app_dir_ce_user_0_link + "/ce0.dex", app_uid_for_user_0, FLAG_STORAGE_CE);
// Standard path for user 10 on CE storage.
pass_secondary_dex_validation(
package_name, app_dir_ce_user_10 + "/ce10.dex", app_uid_for_user_10, FLAG_STORAGE_CE);
diff --git a/cmds/installd/tests/test_utils.h b/cmds/installd/tests/test_utils.h
new file mode 100644
index 0000000..7d1162e
--- /dev/null
+++ b/cmds/installd/tests/test_utils.h
@@ -0,0 +1,107 @@
+#include <android-base/logging.h>
+#include <stdlib.h>
+#include <string.h>
+
+uint8_t kBase64Map[256] = {
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
+ 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
+ 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255
+};
+
+uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
+ CHECK(dst_size != nullptr);
+ std::vector<uint8_t> tmp;
+ uint32_t t = 0, y = 0;
+ int g = 3;
+ for (size_t i = 0; src[i] != '\0'; ++i) {
+ uint8_t c = kBase64Map[src[i] & 0xFF];
+ if (c == 255) continue;
+ // the final = symbols are read and used to trim the remaining bytes
+ if (c == 254) {
+ c = 0;
+ // prevent g < 0 which would potentially allow an overflow later
+ if (--g < 0) {
+ *dst_size = 0;
+ return nullptr;
+ }
+ } else if (g != 3) {
+ // we only allow = to be at the end
+ *dst_size = 0;
+ return nullptr;
+ }
+ t = (t << 6) | c;
+ if (++y == 4) {
+ tmp.push_back((t >> 16) & 255);
+ if (g > 1) {
+ tmp.push_back((t >> 8) & 255);
+ }
+ if (g > 2) {
+ tmp.push_back(t & 255);
+ }
+ y = t = 0;
+ }
+ }
+ if (y != 0) {
+ *dst_size = 0;
+ return nullptr;
+ }
+ std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]);
+ *dst_size = tmp.size();
+ std::copy(tmp.begin(), tmp.end(), dst.get());
+ return dst.release();
+}
+
+bool WriteBase64ToFile(const char* base64, const std::string& file,
+ uid_t uid, gid_t gid, int mode) {
+ CHECK(base64 != nullptr);
+ size_t length;
+ std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length));
+ CHECK(bytes != nullptr);
+
+
+ int fd = open(file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+
+ if (fd < 0) {
+ PLOG(ERROR) << "Could not open file " << file;
+ return false;
+ }
+
+ size_t wrote = 0;
+ while (wrote < length) {
+ ssize_t cur = write(fd, bytes.get() + wrote, length - wrote);
+ if (cur == -1) {
+ PLOG(ERROR) << "Could not write file " << file;
+ return false;
+ }
+ wrote += cur;
+ }
+
+ if (::chown(file.c_str(), uid, gid) != 0) {
+ PLOG(ERROR) << "Could not chown file " << file;
+ return false;
+ }
+ if (::chmod(file.c_str(), mode) != 0) {
+ PLOG(ERROR) << "Could not chmod file " << file;
+ return false;
+ }
+ return true;
+}
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index ca0a82e..7dca7c6 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -87,6 +87,20 @@
create_data_user_ce_path(volume_uuid, user).c_str(), package_name);
}
+/**
+ * Create the path name where package data should be stored for the given
+ * volume UUID, package name, and user ID. An empty UUID is assumed to be
+ * internal storage.
+ * Compared to create_data_user_ce_package_path this method always return the
+ * ".../user/..." directory.
+ */
+std::string create_data_user_ce_package_path_as_user_link(
+ const char* volume_uuid, userid_t userid, const char* package_name) {
+ check_package_name(package_name);
+ std::string data(create_data_path(volume_uuid));
+ return StringPrintf("%s/user/%u/%s", data.c_str(), userid, package_name);
+}
+
std::string create_data_user_ce_package_path(const char* volume_uuid, userid_t user,
const char* package_name, ino_t ce_data_inode) {
// For testing purposes, rely on the inode when defined; this could be
@@ -786,7 +800,7 @@
}
bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
- const char* volume_uuid, int uid, int storage_flag, bool validate_package_path) {
+ const char* volume_uuid, int uid, int storage_flag) {
CHECK(storage_flag == FLAG_STORAGE_CE || storage_flag == FLAG_STORAGE_DE);
// Empty paths are not allowed.
@@ -800,16 +814,20 @@
// The path should be at most PKG_PATH_MAX long.
if (dex_path.size() > PKG_PATH_MAX) { return false; }
- if (validate_package_path) {
- // If we are asked to validate the package path check that
- // the dex_path is under the app data directory.
- std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
+ // The dex_path should be under the app data directory.
+ std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
? create_data_user_ce_package_path(
volume_uuid, multiuser_get_user_id(uid), pkgname.c_str())
: create_data_user_de_package_path(
volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
- if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) {
+ if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) {
+ // The check above might fail if the dex file is accessed via the /data/user/0 symlink.
+ // If that's the case, attempt to validate against the user data link.
+ std::string app_private_dir_symlink = create_data_user_ce_package_path_as_user_link(
+ volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
+ if (strncmp(dex_path.c_str(), app_private_dir_symlink.c_str(),
+ app_private_dir_symlink.size()) != 0) {
return false;
}
}
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 3e04af9..b90caf9 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -60,6 +60,8 @@
userid_t user, const char* package_name, ino_t ce_data_inode);
std::string create_data_user_de_package_path(const char* volume_uuid,
userid_t user, const char* package_name);
+std::string create_data_user_ce_package_path_as_user_link(
+ const char* volume_uuid, userid_t userid, const char* package_name);
std::string create_data_media_path(const char* volume_uuid, userid_t userid);
std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name);
@@ -114,7 +116,7 @@
int validate_system_app_path(const char* path);
bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
- const char* volume_uuid, int uid, int storage_flag, bool validate_package_path = true);
+ const char* volume_uuid, int uid, int storage_flag);
int validate_apk_path(const char *path);
int validate_apk_path_subdirs(const char *path);
diff --git a/cmds/ip-up-vpn/Android.mk b/cmds/ip-up-vpn/Android.mk
index 36bbdf5..e1e2204 100644
--- a/cmds/ip-up-vpn/Android.mk
+++ b/cmds/ip-up-vpn/Android.mk
@@ -18,6 +18,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := ip-up-vpn.c
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_MODULE := ip-up-vpn
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/ppp
diff --git a/cmds/rawbu/Android.mk b/cmds/rawbu/Android.mk
index b580390..9322151 100644
--- a/cmds/rawbu/Android.mk
+++ b/cmds/rawbu/Android.mk
@@ -5,6 +5,8 @@
LOCAL_SRC_FILES:= backup.cpp
+LOCAL_CFLAGS := -Wall -Werror
+
LOCAL_SHARED_LIBRARIES := libcutils libc
LOCAL_MODULE:= rawbu
diff --git a/cmds/rawbu/backup.cpp b/cmds/rawbu/backup.cpp
index ff6719f..0072281 100644
--- a/cmds/rawbu/backup.cpp
+++ b/cmds/rawbu/backup.cpp
@@ -129,7 +129,6 @@
}
if(S_ISDIR(statBuffer.st_mode)) {
- int i;
char *newpath;
newpath = strdup(nameBuffer);
diff --git a/cmds/surfacereplayer/proto/Android.bp b/cmds/surfacereplayer/proto/Android.bp
index dda80bb..71a5e23 100644
--- a/cmds/surfacereplayer/proto/Android.bp
+++ b/cmds/surfacereplayer/proto/Android.bp
@@ -3,6 +3,10 @@
srcs: [
"src/trace.proto",
],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
proto: {
type: "lite",
export_proto_headers: true,
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 719ed9b..016de64 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -47,6 +47,8 @@
"-DLOG_TAG=\"libbufferhub\"",
"-DTRACE=0",
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
+ "-Wall",
+ "-Werror",
],
export_include_dirs: localIncludeFiles,
static_libs: staticLibraries,
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 93ccd0f..b279875 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -49,6 +49,11 @@
"-DLOG_TAG=\"libbufferhubqueue\"",
"-DTRACE=0",
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
+ "-Wall",
+ "-Werror",
+ "-Wno-format",
+ "-Wno-unused-parameter",
+ "-Wno-unused-variable",
],
srcs: sourceFiles,
export_include_dirs: includeFiles,
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index 865573c..5a3c3a6 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -28,6 +28,9 @@
"-DTRACE=0",
"-O0",
"-g",
+ "-Wall",
+ "-Werror",
+ "-Wno-error=sign-compare", // to fix later
],
name: "buffer_hub_queue-test",
tags: ["optional"],
@@ -42,6 +45,8 @@
"-DTRACE=0",
"-O0",
"-g",
+ "-Wall",
+ "-Werror",
],
name: "buffer_hub_queue_producer-test",
tags: ["optional"],
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index e3ab7fa..8213ca2 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -57,6 +57,8 @@
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
+ "-Wall",
+ "-Werror",
], // + [ "-UNDEBUG", "-DDEBUG", "-O0", "-g" ],
export_include_dirs: localIncludeFiles,
shared_libs: sharedLibraries,
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 7fe9825..0d23b62 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -22,6 +22,8 @@
cflags = [
"-DLOG_TAG=\"libdvr\"",
"-DTRACE=0",
+ "-Wall",
+ "-Werror",
]
srcs = [
diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp
index 62aeb79..c7d808b 100644
--- a/libs/vr/libdvrcommon/Android.bp
+++ b/libs/vr/libdvrcommon/Android.bp
@@ -40,6 +40,8 @@
cflags: [
"-DLOG_TAG=\"libdvrcommon\"",
"-DTRACE=0",
+ "-Wall",
+ "-Werror",
],
export_include_dirs: localIncludeFiles,
@@ -59,6 +61,11 @@
tags: ["optional"],
srcs: testFiles,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ ],
shared_libs: sharedLibraries,
diff --git a/libs/vr/libperformance/Android.bp b/libs/vr/libperformance/Android.bp
index 364873d..6a46876 100644
--- a/libs/vr/libperformance/Android.bp
+++ b/libs/vr/libperformance/Android.bp
@@ -32,7 +32,9 @@
srcs: sourceFiles,
cflags: [
"-DLOG_TAG=\"libperformance\"",
- "-DTRACE=0"
+ "-DTRACE=0",
+ "-Wall",
+ "-Werror",
],
export_include_dirs: includeFiles,
static_libs: staticLibraries,
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 0fb2d84..4d80e91 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -77,6 +77,10 @@
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
+ "-Wall",
+ "-Werror",
+ "-Wno-error=sign-compare", // to fix later
+ "-Wno-unused-variable",
],
shared_libs: sharedLibraries,
whole_static_libs: staticLibraries,
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index d022adf..e92178a 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -42,6 +42,11 @@
cc_library {
srcs: sourceFiles,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-macro-redefined",
+ ],
export_include_dirs: includeFiles,
static_libs: staticLibraries,
shared_libs: sharedLibraries,
diff --git a/libs/vr/libvrsensor/include/dvr/pose_client.h b/libs/vr/libvrsensor/include/dvr/pose_client.h
index d684ddc..6a9437c 100644
--- a/libs/vr/libvrsensor/include/dvr/pose_client.h
+++ b/libs/vr/libvrsensor/include/dvr/pose_client.h
@@ -7,7 +7,7 @@
#ifndef __FLOAT32X4T_86
#define __FLOAT32X4T_86
typedef float float32x4_t __attribute__ ((__vector_size__ (16)));
-typedef struct float32x4x4_t { float32x4_t val[4]; };
+typedef struct float32x4x4_t { float32x4_t val[4]; } float32x4x4_t;
#endif
#endif
diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
index f6813fd..f90e3ec 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
@@ -17,11 +17,10 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
index 4df61d3..12b96f4 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
@@ -17,11 +17,10 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
index 1fa9275..dd17ca4 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
@@ -18,7 +18,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
index 1fa9275..dd17ca4 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
@@ -18,7 +18,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
index 1fa9275..dd17ca4 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
@@ -18,7 +18,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
index 1fa9275..dd17ca4 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
@@ -18,7 +18,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
index 4004a7d..b2bbdf6 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
@@ -18,7 +18,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES2/gl2.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp
index c5bdf32..b039bc9 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp
@@ -18,7 +18,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES3/gl3.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp
index 2260a80..dd00e92 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp
@@ -17,7 +17,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES3/gl31.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp
index 130612d..88e00be 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp
@@ -17,7 +17,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <stdint.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp
index e9c5fc7..3e7ec8b 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp
@@ -17,8 +17,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <stdint.h>
-#include <GLES3/gl32.h>
\ No newline at end of file
+#include <GLES3/gl32.h>
diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp
index 7062c57..2163d76 100644
--- a/opengl/tools/glgen/stubs/gles11/common.cpp
+++ b/opengl/tools/glgen/stubs/gles11/common.cpp
@@ -1,5 +1,5 @@
#include <jni.h>
-#include <JNIHelp.h>
+#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
#include <assert.h>
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 026cb37..29296ff 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -17,11 +17,10 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
diff --git a/services/sensorservice/tests/Android.mk b/services/sensorservice/tests/Android.mk
index e894655..8a9c36b 100644
--- a/services/sensorservice/tests/Android.mk
+++ b/services/sensorservice/tests/Android.mk
@@ -4,6 +4,8 @@
LOCAL_SRC_FILES:= \
sensorservicetest.cpp
+LOCAL_CFLAGS := -Wall -Werror
+
LOCAL_SHARED_LIBRARIES := \
libutils libsensor libandroid