Loading cmds/installd/dexopt.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -1838,6 +1838,11 @@ bool reconcile_secondary_dex_file(const std::string& dex_path, result = unlink_if_exists(current_profile) && result; result = unlink_if_exists(reference_profile) && result; // We upgraded once the location of current profile for secondary dex files. // Check for any previous left-overs and remove them as well. std::string old_current_profile = dex_path + ".prof"; result = unlink_if_exists(old_current_profile); // Try removing the directories as well, they might be empty. result = rmdir_if_empty(oat_isa_dir) && result; result = rmdir_if_empty(oat_dir) && result; Loading cmds/installd/tests/installd_utils_test.cpp +97 −15 Original line number Diff line number Diff line Loading @@ -38,16 +38,6 @@ #define TEST_PROFILE_DIR "/data/misc/profiles" #define REALLY_LONG_APP_NAME "com.example." \ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" #define REALLY_LONG_LEAF_NAME "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" namespace android { namespace installd { Loading Loading @@ -88,6 +78,14 @@ protected: virtual void TearDown() { free(android_system_dirs.dirs); } std::string create_too_long_path(const std::string& seed) { std::string result = seed; for (size_t i = seed.size(); i < PKG_PATH_MAX; i++) { result += "a"; } return result; } }; TEST_F(UtilsTest, IsValidApkPath_BadPrefix) { Loading Loading @@ -388,17 +386,18 @@ TEST_F(UtilsTest, CreateMovePath_Primary) { << "Primary user package directory should be created correctly"; } TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) { char path[PKG_PATH_MAX]; EXPECT_EQ(-1, create_move_path(path, REALLY_LONG_APP_NAME, "shared_prefs", 0)) std::string really_long_app_name = create_too_long_path("com.example"); EXPECT_EQ(-1, create_move_path(path, really_long_app_name.c_str(), "shared_prefs", 0)) << "Should fail to create move path for primary user"; } TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) { char path[PKG_PATH_MAX]; EXPECT_EQ(-1, create_move_path(path, "com.android.test", REALLY_LONG_LEAF_NAME, 0)) std::string really_long_leaf_name = create_too_long_path("leaf_"); EXPECT_EQ(-1, create_move_path(path, "com.android.test", really_long_leaf_name.c_str(), 0)) << "Should fail to create move path for primary user"; } Loading Loading @@ -560,7 +559,7 @@ TEST_F(UtilsTest, CreatePrimaryReferenceProfile) { } TEST_F(UtilsTest, CreateSecondaryCurrentProfile) { EXPECT_EQ("/data/user/0/com.example/secondary.dex.prof", EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.cur.prof", create_current_profile_path(/*user*/0, "/data/user/0/com.example/secondary.dex", /*is_secondary*/true)); } Loading @@ -571,5 +570,88 @@ TEST_F(UtilsTest, CreateSecondaryReferenceProfile) { "/data/user/0/com.example/secondary.dex", /*is_secondary*/true)); } static void pass_secondary_dex_validation(const std::string& package_name, const std::string& dex_path, int uid, int storage_flag) { EXPECT_TRUE(validate_secondary_dex_path(package_name, dex_path, /*volume_uuid*/ nullptr, uid, storage_flag)) << dex_path << " should be allowed as a valid secondary dex path"; } static void fail_secondary_dex_validation(const std::string& package_name, const std::string& dex_path, int uid, int storage_flag) { EXPECT_FALSE(validate_secondary_dex_path(package_name, dex_path, /*volume_uuid*/ nullptr, uid, storage_flag)) << dex_path << " should not be allowed as a valid secondary dex path"; } 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_10 = "/data/user/10/" + package_name; std::string app_dir_de_user_0 = "/data/user_de/0/" + package_name; std::string app_dir_de_user_10 = "/data/user_de/10/" + package_name; EXPECT_EQ(app_dir_ce_user_0, create_data_user_ce_package_path(nullptr, 0, package_name.c_str())); EXPECT_EQ(app_dir_ce_user_10, create_data_user_ce_package_path(nullptr, 10, package_name.c_str())); EXPECT_EQ(app_dir_de_user_0, create_data_user_de_package_path(nullptr, 0, package_name.c_str())); EXPECT_EQ(app_dir_de_user_10, create_data_user_de_package_path(nullptr, 10, package_name.c_str())); uid_t app_uid_for_user_0 = multiuser_get_uid(/*user_id*/0, /*app_id*/ 1234); uid_t app_uid_for_user_10 = multiuser_get_uid(/*user_id*/10, /*app_id*/ 1234); // 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); // 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); // Standard path for user 0 on DE storage. pass_secondary_dex_validation( package_name, app_dir_de_user_0 + "/de0.dex", app_uid_for_user_0, FLAG_STORAGE_DE); // Standard path for user 10 on DE storage. pass_secondary_dex_validation( package_name, app_dir_de_user_10 + "/de0.dex", app_uid_for_user_10, FLAG_STORAGE_DE); // Dex path for user 0 accessed from user 10. fail_secondary_dex_validation( package_name, app_dir_ce_user_0 + "/path0_from10.dex", app_uid_for_user_10, FLAG_STORAGE_CE); // Dex path for CE storage accessed with DE. fail_secondary_dex_validation( package_name, app_dir_ce_user_0 + "/ce_from_de.dex", app_uid_for_user_0, FLAG_STORAGE_DE); // Dex path for DE storage accessed with CE. fail_secondary_dex_validation( package_name, app_dir_de_user_0 + "/de_from_ce.dex", app_uid_for_user_0, FLAG_STORAGE_CE); // Location which does not start with '/'. fail_secondary_dex_validation( package_name, "without_slash.dex", app_uid_for_user_10, FLAG_STORAGE_DE); // The dex file is not in the specified package directory. fail_secondary_dex_validation( "another.package", app_dir_ce_user_0 + "/for_another_package.dex", app_uid_for_user_0, FLAG_STORAGE_DE); // The dex path contains indirect directories. fail_secondary_dex_validation( package_name, app_dir_ce_user_0 + "/1/../foo.dex", app_uid_for_user_0, FLAG_STORAGE_CE); fail_secondary_dex_validation( package_name, app_dir_ce_user_0 + "/1/./foo.dex", app_uid_for_user_0, FLAG_STORAGE_CE); // Super long path. std::string too_long = create_too_long_path("too_long_"); fail_secondary_dex_validation( package_name, app_dir_ce_user_10 + "/" + too_long, app_uid_for_user_10, FLAG_STORAGE_CE); } } // namespace installd } // namespace android cmds/installd/utils.cpp +47 −15 Original line number Diff line number Diff line Loading @@ -238,13 +238,38 @@ std::string create_data_dalvik_cache_path() { // Keep profile paths in sync with ActivityThread and LoadedApk. const std::string PROFILE_EXT = ".prof"; const std::string CURRENT_PROFILE_EXT = ".cur"; const std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT; // Gets the parent directory and the file name for the given secondary dex path. // Returns true on success, false on failure (if the dex_path does not have the expected // structure). static bool get_secondary_dex_location(const std::string& dex_path, std::string* out_dir_name, std::string* out_file_name) { size_t dirIndex = dex_path.rfind('/'); if (dirIndex == std::string::npos) { return false; } if (dirIndex == dex_path.size() - 1) { return false; } *out_dir_name = dex_path.substr(0, dirIndex); *out_file_name = dex_path.substr(dirIndex + 1); return true; } std::string create_current_profile_path(userid_t user, const std::string& location, bool is_secondary_dex) { if (is_secondary_dex) { // Secondary dex profiles are stored next to the dex files using .prof extension. return StringPrintf("%s%s", location.c_str(), PROFILE_EXT.c_str()); // Secondary dex current profiles are stored next to the dex files under the oat folder. std::string dex_dir; std::string dex_name; CHECK(get_secondary_dex_location(location, &dex_dir, &dex_name)) << "Unexpected dir structure for secondary dex " << location; return StringPrintf("%s/oat/%s%s%s", dex_dir.c_str(), dex_name.c_str(), CURRENT_PROFILE_EXT.c_str(), PROFILE_EXT.c_str()); } else { // Profiles for primary apks are under /data/misc/profiles/cur. std::string profile_dir = create_primary_current_profile_package_dir_path(user, location); Loading @@ -255,12 +280,10 @@ std::string create_current_profile_path(userid_t user, const std::string& locati std::string create_reference_profile_path(const std::string& location, bool is_secondary_dex) { if (is_secondary_dex) { // Secondary dex reference profiles are stored next to the dex files under the oat folder. size_t dirIndex = location.rfind('/'); CHECK(dirIndex != std::string::npos) std::string dex_dir; std::string dex_name; CHECK(get_secondary_dex_location(location, &dex_dir, &dex_name)) << "Unexpected dir structure for secondary dex " << location; std::string dex_dir = location.substr(0, dirIndex); std::string dex_name = location.substr(dirIndex +1); return StringPrintf("%s/oat/%s%s", dex_dir.c_str(), dex_name.c_str(), PROFILE_EXT.c_str()); } else { Loading Loading @@ -781,21 +804,30 @@ bool validate_secondary_dex_path(const std::string& pkgname, const std::string& 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. if (dex_path.empty()) { return false; } // First character should always be '/'. No relative paths. if (dex_path[0] != '/') { return false; } // The last character should not be '/'. if (dex_path[dex_path.size() - 1] == '/') { return false; } // There should be no '.' after the directory marker. if (dex_path.find("/.") != std::string::npos) { return false; } // The path should be at most PKG_PATH_MAX long. if (dex_path.size() > PKG_PATH_MAX) { return false; } // 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()); dir_rec_t dir; if (get_path_from_string(&dir, app_private_dir.c_str()) != 0) { LOG(WARNING) << "Could not get dir rec for " << app_private_dir; if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) { return false; } // Usually secondary dex files have a nested directory structure. // Pick at most 10 subdirectories when validating (arbitrary value). // If the secondary dex file is >10 directory nested then validation will // fail and the file will not be compiled. return validate_path(&dir, dex_path.c_str(), /*max_subdirs*/ 10) == 0; // If we got here we have a valid path. return true; } /** Loading Loading
cmds/installd/dexopt.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -1838,6 +1838,11 @@ bool reconcile_secondary_dex_file(const std::string& dex_path, result = unlink_if_exists(current_profile) && result; result = unlink_if_exists(reference_profile) && result; // We upgraded once the location of current profile for secondary dex files. // Check for any previous left-overs and remove them as well. std::string old_current_profile = dex_path + ".prof"; result = unlink_if_exists(old_current_profile); // Try removing the directories as well, they might be empty. result = rmdir_if_empty(oat_isa_dir) && result; result = rmdir_if_empty(oat_dir) && result; Loading
cmds/installd/tests/installd_utils_test.cpp +97 −15 Original line number Diff line number Diff line Loading @@ -38,16 +38,6 @@ #define TEST_PROFILE_DIR "/data/misc/profiles" #define REALLY_LONG_APP_NAME "com.example." \ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" #define REALLY_LONG_LEAF_NAME "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" namespace android { namespace installd { Loading Loading @@ -88,6 +78,14 @@ protected: virtual void TearDown() { free(android_system_dirs.dirs); } std::string create_too_long_path(const std::string& seed) { std::string result = seed; for (size_t i = seed.size(); i < PKG_PATH_MAX; i++) { result += "a"; } return result; } }; TEST_F(UtilsTest, IsValidApkPath_BadPrefix) { Loading Loading @@ -388,17 +386,18 @@ TEST_F(UtilsTest, CreateMovePath_Primary) { << "Primary user package directory should be created correctly"; } TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) { char path[PKG_PATH_MAX]; EXPECT_EQ(-1, create_move_path(path, REALLY_LONG_APP_NAME, "shared_prefs", 0)) std::string really_long_app_name = create_too_long_path("com.example"); EXPECT_EQ(-1, create_move_path(path, really_long_app_name.c_str(), "shared_prefs", 0)) << "Should fail to create move path for primary user"; } TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) { char path[PKG_PATH_MAX]; EXPECT_EQ(-1, create_move_path(path, "com.android.test", REALLY_LONG_LEAF_NAME, 0)) std::string really_long_leaf_name = create_too_long_path("leaf_"); EXPECT_EQ(-1, create_move_path(path, "com.android.test", really_long_leaf_name.c_str(), 0)) << "Should fail to create move path for primary user"; } Loading Loading @@ -560,7 +559,7 @@ TEST_F(UtilsTest, CreatePrimaryReferenceProfile) { } TEST_F(UtilsTest, CreateSecondaryCurrentProfile) { EXPECT_EQ("/data/user/0/com.example/secondary.dex.prof", EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.cur.prof", create_current_profile_path(/*user*/0, "/data/user/0/com.example/secondary.dex", /*is_secondary*/true)); } Loading @@ -571,5 +570,88 @@ TEST_F(UtilsTest, CreateSecondaryReferenceProfile) { "/data/user/0/com.example/secondary.dex", /*is_secondary*/true)); } static void pass_secondary_dex_validation(const std::string& package_name, const std::string& dex_path, int uid, int storage_flag) { EXPECT_TRUE(validate_secondary_dex_path(package_name, dex_path, /*volume_uuid*/ nullptr, uid, storage_flag)) << dex_path << " should be allowed as a valid secondary dex path"; } static void fail_secondary_dex_validation(const std::string& package_name, const std::string& dex_path, int uid, int storage_flag) { EXPECT_FALSE(validate_secondary_dex_path(package_name, dex_path, /*volume_uuid*/ nullptr, uid, storage_flag)) << dex_path << " should not be allowed as a valid secondary dex path"; } 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_10 = "/data/user/10/" + package_name; std::string app_dir_de_user_0 = "/data/user_de/0/" + package_name; std::string app_dir_de_user_10 = "/data/user_de/10/" + package_name; EXPECT_EQ(app_dir_ce_user_0, create_data_user_ce_package_path(nullptr, 0, package_name.c_str())); EXPECT_EQ(app_dir_ce_user_10, create_data_user_ce_package_path(nullptr, 10, package_name.c_str())); EXPECT_EQ(app_dir_de_user_0, create_data_user_de_package_path(nullptr, 0, package_name.c_str())); EXPECT_EQ(app_dir_de_user_10, create_data_user_de_package_path(nullptr, 10, package_name.c_str())); uid_t app_uid_for_user_0 = multiuser_get_uid(/*user_id*/0, /*app_id*/ 1234); uid_t app_uid_for_user_10 = multiuser_get_uid(/*user_id*/10, /*app_id*/ 1234); // 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); // 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); // Standard path for user 0 on DE storage. pass_secondary_dex_validation( package_name, app_dir_de_user_0 + "/de0.dex", app_uid_for_user_0, FLAG_STORAGE_DE); // Standard path for user 10 on DE storage. pass_secondary_dex_validation( package_name, app_dir_de_user_10 + "/de0.dex", app_uid_for_user_10, FLAG_STORAGE_DE); // Dex path for user 0 accessed from user 10. fail_secondary_dex_validation( package_name, app_dir_ce_user_0 + "/path0_from10.dex", app_uid_for_user_10, FLAG_STORAGE_CE); // Dex path for CE storage accessed with DE. fail_secondary_dex_validation( package_name, app_dir_ce_user_0 + "/ce_from_de.dex", app_uid_for_user_0, FLAG_STORAGE_DE); // Dex path for DE storage accessed with CE. fail_secondary_dex_validation( package_name, app_dir_de_user_0 + "/de_from_ce.dex", app_uid_for_user_0, FLAG_STORAGE_CE); // Location which does not start with '/'. fail_secondary_dex_validation( package_name, "without_slash.dex", app_uid_for_user_10, FLAG_STORAGE_DE); // The dex file is not in the specified package directory. fail_secondary_dex_validation( "another.package", app_dir_ce_user_0 + "/for_another_package.dex", app_uid_for_user_0, FLAG_STORAGE_DE); // The dex path contains indirect directories. fail_secondary_dex_validation( package_name, app_dir_ce_user_0 + "/1/../foo.dex", app_uid_for_user_0, FLAG_STORAGE_CE); fail_secondary_dex_validation( package_name, app_dir_ce_user_0 + "/1/./foo.dex", app_uid_for_user_0, FLAG_STORAGE_CE); // Super long path. std::string too_long = create_too_long_path("too_long_"); fail_secondary_dex_validation( package_name, app_dir_ce_user_10 + "/" + too_long, app_uid_for_user_10, FLAG_STORAGE_CE); } } // namespace installd } // namespace android
cmds/installd/utils.cpp +47 −15 Original line number Diff line number Diff line Loading @@ -238,13 +238,38 @@ std::string create_data_dalvik_cache_path() { // Keep profile paths in sync with ActivityThread and LoadedApk. const std::string PROFILE_EXT = ".prof"; const std::string CURRENT_PROFILE_EXT = ".cur"; const std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT; // Gets the parent directory and the file name for the given secondary dex path. // Returns true on success, false on failure (if the dex_path does not have the expected // structure). static bool get_secondary_dex_location(const std::string& dex_path, std::string* out_dir_name, std::string* out_file_name) { size_t dirIndex = dex_path.rfind('/'); if (dirIndex == std::string::npos) { return false; } if (dirIndex == dex_path.size() - 1) { return false; } *out_dir_name = dex_path.substr(0, dirIndex); *out_file_name = dex_path.substr(dirIndex + 1); return true; } std::string create_current_profile_path(userid_t user, const std::string& location, bool is_secondary_dex) { if (is_secondary_dex) { // Secondary dex profiles are stored next to the dex files using .prof extension. return StringPrintf("%s%s", location.c_str(), PROFILE_EXT.c_str()); // Secondary dex current profiles are stored next to the dex files under the oat folder. std::string dex_dir; std::string dex_name; CHECK(get_secondary_dex_location(location, &dex_dir, &dex_name)) << "Unexpected dir structure for secondary dex " << location; return StringPrintf("%s/oat/%s%s%s", dex_dir.c_str(), dex_name.c_str(), CURRENT_PROFILE_EXT.c_str(), PROFILE_EXT.c_str()); } else { // Profiles for primary apks are under /data/misc/profiles/cur. std::string profile_dir = create_primary_current_profile_package_dir_path(user, location); Loading @@ -255,12 +280,10 @@ std::string create_current_profile_path(userid_t user, const std::string& locati std::string create_reference_profile_path(const std::string& location, bool is_secondary_dex) { if (is_secondary_dex) { // Secondary dex reference profiles are stored next to the dex files under the oat folder. size_t dirIndex = location.rfind('/'); CHECK(dirIndex != std::string::npos) std::string dex_dir; std::string dex_name; CHECK(get_secondary_dex_location(location, &dex_dir, &dex_name)) << "Unexpected dir structure for secondary dex " << location; std::string dex_dir = location.substr(0, dirIndex); std::string dex_name = location.substr(dirIndex +1); return StringPrintf("%s/oat/%s%s", dex_dir.c_str(), dex_name.c_str(), PROFILE_EXT.c_str()); } else { Loading Loading @@ -781,21 +804,30 @@ bool validate_secondary_dex_path(const std::string& pkgname, const std::string& 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. if (dex_path.empty()) { return false; } // First character should always be '/'. No relative paths. if (dex_path[0] != '/') { return false; } // The last character should not be '/'. if (dex_path[dex_path.size() - 1] == '/') { return false; } // There should be no '.' after the directory marker. if (dex_path.find("/.") != std::string::npos) { return false; } // The path should be at most PKG_PATH_MAX long. if (dex_path.size() > PKG_PATH_MAX) { return false; } // 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()); dir_rec_t dir; if (get_path_from_string(&dir, app_private_dir.c_str()) != 0) { LOG(WARNING) << "Could not get dir rec for " << app_private_dir; if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) { return false; } // Usually secondary dex files have a nested directory structure. // Pick at most 10 subdirectories when validating (arbitrary value). // If the secondary dex file is >10 directory nested then validation will // fail and the file will not be compiled. return validate_path(&dir, dex_path.c_str(), /*max_subdirs*/ 10) == 0; // If we got here we have a valid path. return true; } /** Loading