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

Commit 114f0810 authored by Calin Juravle's avatar Calin Juravle
Browse files

Support profile guided compilation for secondary dex files

Test: adb shell cmd package bg-dexopt-job works for sercondary dex files
Bug: 26719109
Change-Id: I4011a780f65378c23a4631c07c37cdb4f5fee41e
parent fd695a61
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