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

Commit cb2e477f authored by Calin Juravle's avatar Calin Juravle Committed by Gerrit Code Review
Browse files

Merge "Support profile guided compilation for secondary dex files"

parents fd695a61 114f0810
Loading
Loading
Loading
Loading
+25 −23
Original line number Diff line number Diff line
@@ -351,17 +351,20 @@ binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::s
        }

        if (property_get_bool("dalvik.vm.usejitprofiles", false)) {
            const std::string profile_path = create_data_user_profile_package_path(userId, pkgname);
            const std::string profile_dir =
                    create_primary_current_profile_package_dir_path(userId, pkgname);
            // read-write-execute only for the app user.
            if (fs_prepare_dir_strict(profile_path.c_str(), 0700, uid, uid) != 0) {
                return error("Failed to prepare " + profile_path);
            if (fs_prepare_dir_strict(profile_dir.c_str(), 0700, uid, uid) != 0) {
                return error("Failed to prepare " + profile_dir);
            }
            std::string profile_file = create_primary_profile(profile_path);
            const std::string profile_file = create_current_profile_path(userId, pkgname,
                    /*is_secondary_dex*/false);
            // read-write only for the app user.
            if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
                return error("Failed to prepare " + profile_path);
                return error("Failed to prepare " + profile_file);
            }
            const std::string ref_profile_path = create_data_ref_profile_package_path(pkgname);
            const std::string ref_profile_path =
                    create_primary_reference_profile_package_dir_path(pkgname);
            // dex2oat/profman runs under the shared app gid and it needs to read/write reference
            // profiles.
            int shared_app_gid = multiuser_get_shared_gid(0, appId);
@@ -425,10 +428,10 @@ binder::Status InstalldNativeService::clearAppProfiles(const std::string& packag
    std::lock_guard<std::recursive_mutex> lock(mLock);

    binder::Status res = ok();
    if (!clear_reference_profile(packageName)) {
    if (!clear_primary_reference_profile(packageName)) {
        res = error("Failed to clear reference profile for " + packageName);
    }
    if (!clear_current_profiles(packageName)) {
    if (!clear_primary_current_profiles(packageName)) {
        res = error("Failed to clear current profiles for " + packageName);
    }
    return res;
@@ -476,7 +479,7 @@ binder::Status InstalldNativeService::clearAppData(const std::unique_ptr<std::st
            }
        }
        if (!only_cache) {
            if (!clear_current_profile(packageName, userId)) {
            if (!clear_primary_current_profile(packageName, userId)) {
                res = error("Failed to clear current profile for " + packageName);
            }
        }
@@ -486,13 +489,13 @@ binder::Status InstalldNativeService::clearAppData(const std::unique_ptr<std::st

static int destroy_app_reference_profile(const std::string& pkgname) {
    return delete_dir_contents_and_dir(
        create_data_ref_profile_package_path(pkgname),
        create_primary_reference_profile_package_dir_path(pkgname),
        /*ignore_if_missing*/ true);
}

static int destroy_app_current_profiles(const std::string& pkgname, userid_t userid) {
    return delete_dir_contents_and_dir(
        create_data_user_profile_package_path(userid, pkgname),
        create_primary_current_profile_package_dir_path(userid, pkgname),
        /*ignore_if_missing*/ true);
}

@@ -719,7 +722,7 @@ binder::Status InstalldNativeService::destroyUserData(const std::unique_ptr<std:
            if (delete_dir_contents_and_dir(path, true) != 0) {
                res = error("Failed to delete " + path);
            }
            path = create_data_user_profile_path(userId);
            path = create_primary_cur_profile_dir_path(userId);
            if (delete_dir_contents_and_dir(path, true) != 0) {
                res = error("Failed to delete " + path);
            }
@@ -1216,9 +1219,9 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri
            ATRACE_END();

            ATRACE_BEGIN("profiles");
            auto userProfilePath = create_data_user_profile_package_path(userId, pkgname);
            auto userProfilePath = create_primary_current_profile_package_dir_path(userId, pkgname);
            calculate_tree_size(userProfilePath, &stats.dataSize);
            auto refProfilePath = create_data_ref_profile_package_path(pkgname);
            auto refProfilePath = create_primary_reference_profile_package_dir_path(pkgname);
            calculate_tree_size(refProfilePath, &stats.codeSize);
            ATRACE_END();

@@ -1236,7 +1239,7 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri
            calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
                    sharedGid, -1);
        }
        calculate_tree_size(create_data_user_profile_path(userId), &stats.dataSize,
        calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize,
                multiuser_get_uid(userId, appId), -1);
        ATRACE_END();
    }
@@ -1310,9 +1313,9 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str
        ATRACE_END();

        ATRACE_BEGIN("profile");
        auto userProfilePath = create_data_user_profile_path(userId);
        auto userProfilePath = create_primary_cur_profile_dir_path(userId);
        calculate_tree_size(userProfilePath, &stats.dataSize, -1, -1, true);
        auto refProfilePath = create_data_ref_profile_path();
        auto refProfilePath = create_primary_ref_profile_dir_path();
        calculate_tree_size(refProfilePath, &stats.codeSize, -1, -1, true);
        ATRACE_END();

@@ -1334,7 +1337,7 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str
        ATRACE_BEGIN("dalvik");
        calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
                -1, -1, true);
        calculate_tree_size(create_data_user_profile_path(userId), &stats.dataSize,
        calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize,
                -1, -1, true);
        ATRACE_END();

@@ -1367,9 +1370,9 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str
        ATRACE_END();

        ATRACE_BEGIN("profile");
        auto userProfilePath = create_data_user_profile_path(userId);
        auto userProfilePath = create_primary_cur_profile_dir_path(userId);
        calculate_tree_size(userProfilePath, &stats.dataSize);
        auto refProfilePath = create_data_ref_profile_path();
        auto refProfilePath = create_primary_ref_profile_dir_path();
        calculate_tree_size(refProfilePath, &stats.codeSize);
        ATRACE_END();

@@ -1384,7 +1387,7 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str

        ATRACE_BEGIN("dalvik");
        calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize);
        calculate_tree_size(create_data_user_profile_path(userId), &stats.dataSize);
        calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize);
        ATRACE_END();
    }

@@ -1549,8 +1552,7 @@ binder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::stri
    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
    std::lock_guard<std::recursive_mutex> lock(mLock);

    const char* pkgname = packageName.c_str();
    *_aidl_return = analyse_profiles(uid, pkgname);
    *_aidl_return = analyze_primary_profiles(uid, packageName);
    return ok();
}

+189 −107

File changed.

Preview size limit exceeded, changes collapsed.

+14 −4
Original line number Diff line number Diff line
@@ -32,13 +32,23 @@ static constexpr int DEX2OAT_FOR_FILTER = 3;
static constexpr int DEX2OAT_FOR_RELOCATION      = 4;
static constexpr int PATCHOAT_FOR_RELOCATION     = 5;

bool clear_reference_profile(const std::string& pkgname);
bool clear_current_profile(const std::string& pkgname, userid_t user);
bool clear_current_profiles(const std::string& pkgname);
// Clear the reference profile for the primary apk of the given package.
bool clear_primary_reference_profile(const std::string& pkgname);
// Clear the current profile for the primary apk of the given package and user.
bool clear_primary_current_profile(const std::string& pkgname, userid_t user);
// Clear all current profile for the primary apk of the given package.
bool clear_primary_current_profiles(const std::string& pkgname);

bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path);

bool analyse_profiles(uid_t uid, const std::string& pkgname);
// Decide if profile guided compilation is needed or not based on existing profiles.
// The analysis is done for the primary apks (base + splits) of the given package.
// Returns true if there is enough information in the current profiles that makes it
// worth to recompile the package.
// If the return value is true all the current profiles would have been merged into
// the reference profiles accessible with open_reference_profile().
bool analyze_primary_profiles(uid_t uid, const std::string& pkgname);

bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);

bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path);
+30 −9
Original line number Diff line number Diff line
@@ -521,29 +521,50 @@ TEST_F(UtilsTest, IsValidPackageName) {
}

TEST_F(UtilsTest, CreateDataUserProfilePath) {
    EXPECT_EQ("/data/misc/profiles/cur/0", create_data_user_profile_path(0));
    EXPECT_EQ("/data/misc/profiles/cur/1", create_data_user_profile_path(1));
    EXPECT_EQ("/data/misc/profiles/cur/0", create_primary_cur_profile_dir_path(0));
    EXPECT_EQ("/data/misc/profiles/cur/1", create_primary_cur_profile_dir_path(1));
}

TEST_F(UtilsTest, CreateDataUserProfilePackagePath) {
    EXPECT_EQ("/data/misc/profiles/cur/0/com.example",
            create_data_user_profile_package_path(0, "com.example"));
            create_primary_current_profile_package_dir_path(0, "com.example"));
    EXPECT_EQ("/data/misc/profiles/cur/1/com.example",
            create_data_user_profile_package_path(1, "com.example"));
            create_primary_current_profile_package_dir_path(1, "com.example"));
}

TEST_F(UtilsTest, CreateDataRefProfilePath) {
    EXPECT_EQ("/data/misc/profiles/ref", create_data_ref_profile_path());
    EXPECT_EQ("/data/misc/profiles/ref", create_primary_ref_profile_dir_path());
}

TEST_F(UtilsTest, CreateDataRefProfilePackagePath) {
    EXPECT_EQ("/data/misc/profiles/ref/com.example",
        create_data_ref_profile_package_path("com.example"));
        create_primary_reference_profile_package_dir_path("com.example"));
}

TEST_F(UtilsTest, CreatePrimaryProfile) {
    EXPECT_EQ("/data/misc/profiles/ref/com.example/primary.prof",
        create_primary_profile("/data/misc/profiles/ref/com.example"));
TEST_F(UtilsTest, CreatePrimaryCurrentProfile) {
    std::string expected =
        create_primary_current_profile_package_dir_path(1, "com.example") + "/primary.prof";
    EXPECT_EQ(expected,
            create_current_profile_path(/*user*/0, "com.example", /*is_secondary*/false));
}

TEST_F(UtilsTest, CreatePrimaryReferenceProfile) {
    std::string expected =
        create_primary_reference_profile_package_dir_path("com.example") + "/primary.prof";
    EXPECT_EQ(expected,
            create_reference_profile_path("com.example", /*is_secondary*/false));
}

TEST_F(UtilsTest, CreateSecondaryCurrentProfile) {
    EXPECT_EQ("/data/user/0/com.example/secondary.dex.prof",
            create_current_profile_path(/*user*/0,
                    "/data/user/0/com.example/secondary.dex", /*is_secondary*/true));
}

TEST_F(UtilsTest, CreateSecondaryReferenceProfile) {
    EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.prof",
            create_reference_profile_path(
                    "/data/user/0/com.example/secondary.dex", /*is_secondary*/true));
}

}  // namespace installd
+44 −13
Original line number Diff line number Diff line
@@ -213,20 +213,22 @@ std::string create_data_misc_legacy_path(userid_t userid) {
    return StringPrintf("%s/misc/user/%u", create_data_path(nullptr).c_str(), userid);
}

std::string create_data_user_profile_path(userid_t userid) {
std::string create_primary_cur_profile_dir_path(userid_t userid) {
    return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid);
}

std::string create_data_user_profile_package_path(userid_t user, const std::string& package_name) {
std::string create_primary_current_profile_package_dir_path(userid_t user,
        const std::string& package_name) {
    check_package_name(package_name.c_str());
    return StringPrintf("%s/%s",create_data_user_profile_path(user).c_str(), package_name.c_str());
    return StringPrintf("%s/%s",
            create_primary_cur_profile_dir_path(user).c_str(), package_name.c_str());
}

std::string create_data_ref_profile_path() {
std::string create_primary_ref_profile_dir_path() {
    return StringPrintf("%s/ref", android_profiles_dir.path);
}

std::string create_data_ref_profile_package_path(const std::string& package_name) {
std::string create_primary_reference_profile_package_dir_path(const std::string& package_name) {
    check_package_name(package_name.c_str());
    return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name.c_str());
}
@@ -235,11 +237,38 @@ std::string create_data_dalvik_cache_path() {
    return "/data/dalvik-cache";
}

// Keep profile paths in sync with ActivityThread.
constexpr const char* PRIMARY_PROFILE_NAME = "primary.prof";
// Keep profile paths in sync with ActivityThread and LoadedApk.
const std::string PROFILE_EXT = ".prof";
const std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT;

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());
    } else {
        // Profiles for primary apks are under /data/misc/profiles/cur.
        std::string profile_dir = create_primary_current_profile_package_dir_path(user, location);
        return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME.c_str());
    }
}

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)
                << "Unexpected dir structure for secondary dex " << location;

std::string create_primary_profile(const std::string& profile_dir) {
    return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME);
        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 {
        // Reference profiles for primary apks are stored in /data/misc/profile/ref.
        std::string profile_dir = create_primary_reference_profile_package_dir_path(location);
        return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME.c_str());
    }
}

std::vector<userid_t> get_known_users(const char* volume_uuid) {
@@ -1163,13 +1192,15 @@ int validate_system_app_path(const char* path) {
    return -1;
}

bool validate_secondary_dex_path(const char* pkgname, 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) {
    CHECK(storage_flag == FLAG_STORAGE_CE || storage_flag == FLAG_STORAGE_DE);

    std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
        ? create_data_user_ce_package_path(volume_uuid, multiuser_get_user_id(uid), pkgname)
        : create_data_user_de_package_path(volume_uuid, multiuser_get_user_id(uid), pkgname);
        ? 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;
@@ -1179,7 +1210,7 @@ bool validate_secondary_dex_path(const char* pkgname, const char* path,
    // 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, path, /*max_subdirs*/ 10) == 0;
    return validate_path(&dir, dex_path.c_str(), /*max_subdirs*/ 10) == 0;
}

/**
Loading