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

Commit 5b5589df authored by Calin Juravle's avatar Calin Juravle Committed by Android (Google) Code Review
Browse files

Merge "[installd] Create profile snaphots for boot image"

parents e292a930 e61189e0
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -1872,12 +1872,13 @@ binder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::stri
}

binder::Status InstalldNativeService::createProfileSnapshot(int32_t appId,
        const std::string& packageName, const std::string& profileName, bool* _aidl_return) {
        const std::string& packageName, const std::string& profileName,
        const std::string& classpath, bool* _aidl_return) {
    ENFORCE_UID(AID_SYSTEM);
    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
    std::lock_guard<std::recursive_mutex> lock(mLock);

    *_aidl_return = create_profile_snapshot(appId, packageName, profileName);
    *_aidl_return = create_profile_snapshot(appId, packageName, profileName, classpath);
    return ok();
}

+1 −1
Original line number Diff line number Diff line
@@ -100,7 +100,7 @@ public:
    binder::Status destroyAppProfiles(const std::string& packageName);

    binder::Status createProfileSnapshot(int32_t appId, const std::string& packageName,
            const std::string& profileName, bool* _aidl_return);
            const std::string& profileName, const std::string& classpath, bool* _aidl_return);
    binder::Status destroyProfileSnapshot(const std::string& packageName,
            const std::string& profileName);

+1 −1
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ interface IInstalld {
    void destroyAppProfiles(@utf8InCpp String packageName);

    boolean createProfileSnapshot(int appId, @utf8InCpp String packageName,
            @utf8InCpp String profileName);
            @utf8InCpp String profileName, @utf8InCpp String classpath);
    void destroyProfileSnapshot(@utf8InCpp String packageName, @utf8InCpp String profileName);

    void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid);
+130 −12
Original line number Diff line number Diff line
@@ -716,27 +716,34 @@ static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;

static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
        const unique_fd& reference_profile_fd) {
    static const size_t MAX_INT_LEN = 32;
        const unique_fd& reference_profile_fd, const std::vector<unique_fd>* apk_fds = nullptr) {
    const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";

    std::vector<std::string> profile_args(profiles_fd.size());
    char profile_buf[strlen("--profile-file-fd=") + MAX_INT_LEN];
    for (size_t k = 0; k < profiles_fd.size(); k++) {
        sprintf(profile_buf, "--profile-file-fd=%d", profiles_fd[k].get());
        profile_args[k].assign(profile_buf);
        profile_args[k] = "--profile-file-fd=" + std::to_string(profiles_fd[k].get());
    }
    std::string reference_profile_arg = "--reference-profile-file-fd="
            + std::to_string(reference_profile_fd.get());

    std::vector<std::string> apk_args;
    if (apk_fds != nullptr) {
        for (size_t k = 0; k < apk_fds->size(); k++) {
            apk_args.push_back("--apk-fd=" + std::to_string((*apk_fds)[k].get()));
        }
    }
    char reference_profile_arg[strlen("--reference-profile-file-fd=") + MAX_INT_LEN];
    sprintf(reference_profile_arg, "--reference-profile-file-fd=%d", reference_profile_fd.get());

    // program name, reference profile fd, the final NULL and the profile fds
    const char* argv[3 + profiles_fd.size()];
    const char* argv[3 + profile_args.size() + apk_args.size()];
    int i = 0;
    argv[i++] = profman_bin;
    argv[i++] = reference_profile_arg;
    argv[i++] = reference_profile_arg.c_str();
    for (size_t k = 0; k < profile_args.size(); k++) {
        argv[i++] = profile_args[k].c_str();
    }
    for (size_t k = 0; k < apk_args.size(); k++) {
        argv[i++] = apk_args[k].c_str();
    }
    // Do not add after dex2oat_flags, they should override others for debugging.
    argv[i] = NULL;

@@ -2441,8 +2448,24 @@ bool create_cache_path_default(char path[PKG_PATH_MAX], const char *src,
    }
}

bool create_profile_snapshot(int32_t app_id, const std::string& package_name,
        const std::string& profile_name) {
bool open_classpath_files(const std::string& classpath, std::vector<unique_fd>* apk_fds) {
    std::vector<std::string> classpaths_elems = base::Split(classpath, ":");
    for (const std::string& elem : classpaths_elems) {
        unique_fd fd(TEMP_FAILURE_RETRY(open(elem.c_str(), O_RDONLY)));
        if (fd < 0) {
            PLOG(ERROR) << "Could not open classpath elem " << elem;
            return false;
        } else {
            apk_fds->push_back(std::move(fd));
        }
    }
    return true;
}

static bool create_app_profile_snapshot(int32_t app_id,
                                        const std::string& package_name,
                                        const std::string& profile_name,
                                        const std::string& classpath) {
    int app_shared_gid = multiuser_get_shared_gid(/*user_id*/ 0, app_id);

    unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name);
@@ -2460,11 +2483,18 @@ bool create_profile_snapshot(int32_t app_id, const std::string& package_name,

    profiles_fd.push_back(std::move(reference_profile_fd));

    // Open the class paths elements. These will be used to filter out profile data that does
    // not belong to the classpath during merge.
    std::vector<unique_fd> apk_fds;
    if (!open_classpath_files(classpath, &apk_fds)) {
        return false;
    }

    pid_t pid = fork();
    if (pid == 0) {
        /* child -- drop privileges before continuing */
        drop_capabilities(app_shared_gid);
        run_profman_merge(profiles_fd, snapshot_fd);
        run_profman_merge(profiles_fd, snapshot_fd, &apk_fds);
        exit(42);   /* only get here on exec failure */
    }

@@ -2478,6 +2508,94 @@ bool create_profile_snapshot(int32_t app_id, const std::string& package_name,
    return true;
}

static bool create_boot_image_profile_snapshot(const std::string& package_name,
                                               const std::string& profile_name,
                                               const std::string& classpath) {
    // The reference profile directory for the android package might not be prepared. Do it now.
    const std::string ref_profile_dir =
            create_primary_reference_profile_package_dir_path(package_name);
    if (fs_prepare_dir(ref_profile_dir.c_str(), 0770, AID_SYSTEM, AID_SYSTEM) != 0) {
        PLOG(ERROR) << "Failed to prepare " << ref_profile_dir;
        return false;
    }

    // Open and create the snapshot profile.
    unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name);

    // Collect all non empty profiles.
    // The collection will traverse all applications profiles and find the non empty files.
    // This has the potential of inspecting a large number of files and directories (depending
    // on the number of applications and users). So there is a slight increase in the chance
    // to get get occasionally I/O errors (e.g. for opening the file). When that happens do not
    // fail the snapshot and aggregate whatever profile we could open.
    //
    // The profile snapshot is a best effort based on available data it's ok if some data
    // from some apps is missing. It will be counter productive for the snapshot to fail
    // because we could not open or read some of the files.
    std::vector<std::string> profiles;
    if (!collect_profiles(&profiles)) {
        LOG(WARNING) << "There were errors while collecting the profiles for the boot image.";
    }

    // If we have no profiles return early.
    if (profiles.empty()) {
        return true;
    }

    // Open the classpath elements. These will be used to filter out profile data that does
    // not belong to the classpath during merge.
    std::vector<unique_fd> apk_fds;
    if (!open_classpath_files(classpath, &apk_fds)) {
        return false;
    }

    // If we could not open any files from the classpath return an error.
    if (apk_fds.empty()) {
        LOG(ERROR) << "Could not open any of the classpath elements.";
        return false;
    }

    // Aggregate the profiles in batches of kAggregationBatchSize.
    // We do this to avoid opening a huge a amount of files.
    static constexpr size_t kAggregationBatchSize = 10;

    std::vector<unique_fd> profiles_fd;
    for (size_t i = 0; i < profiles.size(); )  {
        for (size_t k = 0; k < kAggregationBatchSize && i < profiles.size(); k++, i++) {
            unique_fd fd = open_profile(AID_SYSTEM, profiles[i], O_RDONLY);
            if (fd.get() >= 0) {
                profiles_fd.push_back(std::move(fd));
            }
        }
        pid_t pid = fork();
        if (pid == 0) {
            /* child -- drop privileges before continuing */
            drop_capabilities(AID_SYSTEM);

            run_profman_merge(profiles_fd, snapshot_fd, &apk_fds);
            exit(42);   /* only get here on exec failure */
        }

        /* parent */
        int return_code = wait_child(pid);
        if (!WIFEXITED(return_code)) {
            PLOG(WARNING) << "profman failed for " << package_name << ":" << profile_name;
            return false;
        }
        return true;
    }
    return true;
}

bool create_profile_snapshot(int32_t app_id, const std::string& package_name,
        const std::string& profile_name, const std::string& classpath) {
    if (app_id == -1) {
        return create_boot_image_profile_snapshot(package_name, profile_name, classpath);
    } else {
        return create_app_profile_snapshot(app_id, package_name, profile_name, classpath);
    }
}

bool prepare_app_profile(const std::string& package_name,
                         userid_t user_id,
                         appid_t app_id,
+9 −2
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@ bool analyze_primary_profiles(uid_t uid,
                              const std::string& profile_name);

// Create a snapshot of the profile information for the given package profile.
// If appId is -1, the method creates the profile snapshot for the boot image.
//
// The profile snapshot is the aggregation of all existing profiles (all current user
// profiles & the reference profile) and is meant to capture the all the profile information
// without performing a merge into the reference profile which might impact future dex2oat
@@ -60,8 +62,13 @@ bool analyze_primary_profiles(uid_t uid,
// ownership is assigned to AID_SYSTEM.
// The snapshot location is reference_profile_location.snapshot. If a snapshot is already
// there, it will be truncated and overwritten.
bool create_profile_snapshot(int32_t app_id, const std::string& package,
        const std::string& profile_name);
//
// The classpath acts as filter: only profiling data belonging to elements of the classpath
// will end up in the snapshot.
bool create_profile_snapshot(int32_t app_id,
                             const std::string& package,
                             const std::string& profile_name,
                             const std::string& classpath);

bool dump_profiles(int32_t uid,
                   const std::string& pkgname,
Loading