Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 008b0378 authored by Calin Juravle's avatar Calin Juravle Committed by android-build-merger
Browse files

Merge "Change the location of current profiles for secondary dex files" into oc-mr1-dev

am: 3a02aee2

Change-Id: Idcf8259cc590723798a02bbf0648d4afd46909bc
parents ef974d6c 3a02aee2
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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;
+97 −15
Original line number Diff line number Diff line
@@ -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 {

@@ -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) {
@@ -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";
}

@@ -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));
}
@@ -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
+47 −15
Original line number Diff line number Diff line
@@ -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);
@@ -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 {
@@ -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;
}

/**