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

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

Merge "Move secondary dex files processing in the app process"

parents 6d1fba82 46e27bcc
Loading
Loading
Loading
Loading
+247 −168
Original line number Diff line number Diff line
@@ -1385,6 +1385,8 @@ bool maybe_open_oat_and_vdex_file(const std::string& apk_path,
                             oat_dir.c_str(),
                             is_secondary_dex,
                             oat_path)) {
        LOG(ERROR) << "Could not create oat out path for "
                << apk_path << " with oat dir " << oat_dir;
        return false;
    }
    oat_file_fd->reset(open(oat_path, O_RDONLY));
@@ -1489,7 +1491,7 @@ static void exec_dexoptanalyzer(const std::string& dex_file, int vdex_fd, int oa

// Prepares the oat dir for the secondary dex files.
static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
        const char* instruction_set, std::string* oat_dir_out) {
        const char* instruction_set) {
    unsigned long dirIndex = dex_path.rfind('/');
    if (dirIndex == std::string::npos) {
        LOG(ERROR ) << "Unexpected dir structure for secondary dex " << dex_path;
@@ -1506,10 +1508,8 @@ static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,

    char oat_dir[PKG_PATH_MAX];
    snprintf(oat_dir, PKG_PATH_MAX, "%s/oat", dex_dir.c_str());
    oat_dir_out->assign(oat_dir);

    // Create oat/isa output directory.
    if (prepare_app_cache_dir(*oat_dir_out, instruction_set, oat_dir_mode, uid, uid) != 0) {
    if (prepare_app_cache_dir(oat_dir, instruction_set, oat_dir_mode, uid, uid) != 0) {
        LOG(ERROR) << "Could not prepare oat/isa dir for secondary dex: " << dex_path;
        return false;
    }
@@ -1517,166 +1517,236 @@ static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
    return true;
}

static int constexpr DEXOPTANALYZER_BIN_EXEC_ERROR = 200;
// Return codes for identifying the reason why dexoptanalyzer was not invoked when processing
// secondary dex files. This return codes are returned by the child process created for
// analyzing secondary dex files in process_secondary_dex_dexopt.

// The dexoptanalyzer was not invoked because of validation or IO errors.
static int constexpr SECONDARY_DEX_DEXOPTANALYZER_SKIPPED = 200;
// The dexoptanalyzer was not invoked because the dex file does not exist anymore.
static int constexpr SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE = 201;

// Verifies the result of dexoptanalyzer executed for the apk_path.
// Verifies the result of analyzing secondary dex files from process_secondary_dex_dexopt.
// If the result is valid returns true and sets dexopt_needed_out to a valid value.
// Returns false for errors or unexpected result values.
static bool process_dexoptanalyzer_result(const std::string& dex_path, int result,
// The result is expected to be either one of SECONDARY_DEX_* codes or a valid exit code
// of dexoptanalyzer.
static bool process_secondary_dexoptanalyzer_result(const std::string& dex_path, int result,
            int* dexopt_needed_out) {
    // The result values are defined in dexoptanalyzer.
    switch (result) {
        case 0:  // no_dexopt_needed
        case 0:  // dexoptanalyzer: no_dexopt_needed
            *dexopt_needed_out = NO_DEXOPT_NEEDED; return true;
        case 1:  // dex2oat_from_scratch
        case 1:  // dexoptanalyzer: dex2oat_from_scratch
            *dexopt_needed_out = DEX2OAT_FROM_SCRATCH; return true;
        case 5:  // dex2oat_for_bootimage_odex
        case 5:  // dexoptanalyzer: dex2oat_for_bootimage_odex
            *dexopt_needed_out = -DEX2OAT_FOR_BOOT_IMAGE; return true;
        case 6:  // dex2oat_for_filter_odex
        case 6:  // dexoptanalyzer: dex2oat_for_filter_odex
            *dexopt_needed_out = -DEX2OAT_FOR_FILTER; return true;
        case 7:  // dex2oat_for_relocation_odex
        case 7:  // dexoptanalyzer: dex2oat_for_relocation_odex
            *dexopt_needed_out = -DEX2OAT_FOR_RELOCATION; return true;
        case 2:  // dex2oat_for_bootimage_oat
        case 3:  // dex2oat_for_filter_oat
        case 4:  // dex2oat_for_relocation_oat
        case 2:  // dexoptanalyzer: dex2oat_for_bootimage_oat
        case 3:  // dexoptanalyzer: dex2oat_for_filter_oat
        case 4:  // dexoptanalyzer: dex2oat_for_relocation_oat
            LOG(ERROR) << "Dexoptnalyzer return the status of an oat file."
                    << " Expected odex file status for secondary dex " << dex_path
                    << " : dexoptanalyzer result=" << result;
            return false;
        case SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE:
            // If the file does not exist there's no need for dexopt.
            *dexopt_needed_out = NO_DEXOPT_NEEDED;
            return true;
        case SECONDARY_DEX_DEXOPTANALYZER_SKIPPED:
            return false;
        default:
            LOG(ERROR) << "Unexpected result for dexoptanalyzer " << dex_path
                    << " exec_dexoptanalyzer result=" << result;
            LOG(ERROR) << "Unexpected result from analyzing secondary dex " << dex_path
                    << " result=" << result;
            return false;
    }
}

// Processes the dex_path as a secondary dex files and return true if the path dex file should
// be compiled. Returns false for errors (logged) or true if the secondary dex path was process
// successfully.
// When returning true, the output parameters will be:
//   - is_public_out: whether or not the oat file should not be made public
//   - dexopt_needed_out: valid OatFileAsssitant::DexOptNeeded
//   - oat_dir_out: the oat dir path where the oat file should be stored
//   - dex_path_out: the real path of the dex file
static bool process_secondary_dex_dexopt(const char* original_dex_path, const char* pkgname,
        int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
        const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
        std::string* oat_dir_out, std::string* dex_path_out, bool downgrade,
        const char* class_loader_context) {
    int storage_flag;
enum SecondaryDexAccess {
    kSecondaryDexAccessReadOk = 0,
    kSecondaryDexAccessDoesNotExist = 1,
    kSecondaryDexAccessPermissionError = 2,
    kSecondaryDexAccessIOError = 3
};

static SecondaryDexAccess check_secondary_dex_access(const std::string& dex_path) {
    // Check if the path exists and can be read. If not, there's nothing to do.
    if (access(dex_path.c_str(), R_OK) == 0) {
        return kSecondaryDexAccessReadOk;
    } else {
        if (errno == ENOENT) {
            LOG(INFO) << "Secondary dex does not exist: " <<  dex_path;
            return kSecondaryDexAccessDoesNotExist;
        } else {
            PLOG(ERROR) << "Could not access secondary dex " << dex_path;
            return errno == EACCES
                ? kSecondaryDexAccessPermissionError
                : kSecondaryDexAccessIOError;
        }
    }
}

static bool is_file_public(const std::string& filename) {
    struct stat file_stat;
    if (stat(filename.c_str(), &file_stat) == 0) {
        return (file_stat.st_mode & S_IROTH) != 0;
    }
    return false;
}

// Create the oat file structure for the secondary dex 'dex_path' and assign
// the individual path component to the 'out_' parameters.
static bool create_secondary_dex_oat_layout(const std::string& dex_path, const std::string& isa,
        char* out_oat_dir, char* out_oat_isa_dir, char* out_oat_path) {
    size_t dirIndex = dex_path.rfind('/');
    if (dirIndex == std::string::npos) {
        LOG(ERROR) << "Unexpected dir structure for dex file " << dex_path;
        return false;
    }
    // TODO(calin): we have similar computations in at lest 3 other places
    // (InstalldNativeService, otapropt and dexopt). Unify them and get rid of snprintf by
    // using string append.
    std::string apk_dir = dex_path.substr(0, dirIndex);
    snprintf(out_oat_dir, PKG_PATH_MAX, "%s/oat", apk_dir.c_str());
    snprintf(out_oat_isa_dir, PKG_PATH_MAX, "%s/%s", out_oat_dir, isa.c_str());

    if (!create_oat_out_path(dex_path.c_str(), isa.c_str(), out_oat_dir,
            /*is_secondary_dex*/true, out_oat_path)) {
        LOG(ERROR) << "Could not create oat path for secondary dex " << dex_path;
        return false;
    }
    return true;
}

// Validate that the dexopt_flags contain a valid storage flag and convert that to an installd
// recognized storage flags (FLAG_STORAGE_CE or FLAG_STORAGE_DE).
static bool validate_dexopt_storage_flags(int dexopt_flags, int* out_storage_flag) {
    if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
        storage_flag = FLAG_STORAGE_CE;
        *out_storage_flag = FLAG_STORAGE_CE;
        if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
            LOG(ERROR) << "Ambiguous secondary dex storage flag. Both, CE and DE, flags are set";
            return false;
        }
    } else if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
        storage_flag = FLAG_STORAGE_DE;
        *out_storage_flag = FLAG_STORAGE_DE;
    } else {
        LOG(ERROR) << "Secondary dex storage flag must be set";
        return false;
    }
    return true;
}

    {
        // As opposed to the primary apk, secondary dex files might contain symlinks.
        // Resolve the path before passing it to the validate method to
        // make sure the verification is done on the real location.
        UniqueCPtr<char> dex_real_path_cstr(realpath(original_dex_path, nullptr));
        if (dex_real_path_cstr == nullptr) {
            PLOG(ERROR) << "Could not get the real path of the secondary dex file "
                    << original_dex_path;
// Processes the dex_path as a secondary dex files and return true if the path dex file should
// be compiled. Returns false for errors (logged) or true if the secondary dex path was process
// successfully.
// When returning true, the output parameters will be:
//   - is_public_out: whether or not the oat file should not be made public
//   - dexopt_needed_out: valid OatFileAsssitant::DexOptNeeded
//   - oat_dir_out: the oat dir path where the oat file should be stored
static bool process_secondary_dex_dexopt(const std::string& dex_path, const char* pkgname,
        int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
        const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
        std::string* oat_dir_out, bool downgrade, const char* class_loader_context) {
    LOG(DEBUG) << "Processing secondary dex path " << dex_path;
    int storage_flag;
    if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag)) {
        return false;
        } else {
            dex_path_out->assign(dex_real_path_cstr.get());
    }
    }
    const std::string& dex_path = *dex_path_out;
    if (!validate_dex_path_size(dex_path)) {
    // Compute the oat dir as it's not easy to extract it from the child computation.
    char oat_path[PKG_PATH_MAX];
    char oat_dir[PKG_PATH_MAX];
    char oat_isa_dir[PKG_PATH_MAX];
    if (!create_secondary_dex_oat_layout(
            dex_path, instruction_set, oat_dir, oat_isa_dir, oat_path)) {
        LOG(ERROR) << "Could not create secondary odex layout: " << dex_path;
        return false;
    }
    oat_dir_out->assign(oat_dir);

    pid_t pid = fork();
    if (pid == 0) {
        // child -- drop privileges before continuing.
        drop_capabilities(uid);

        // Validate the path structure.
        if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
            LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
        return false;
            _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
        }

    // Check if the path exist. If not, there's nothing to do.
    struct stat dex_path_stat;
    if (stat(dex_path.c_str(), &dex_path_stat) != 0) {
        // Open the dex file.
        unique_fd zip_fd;
        zip_fd.reset(open(dex_path.c_str(), O_RDONLY));
        if (zip_fd.get() < 0) {
            if (errno == ENOENT) {
            // Secondary dex files might be deleted any time by the app.
            // Nothing to do if that's the case
            ALOGV("Secondary dex does not exist %s", dex_path.c_str());
            return NO_DEXOPT_NEEDED;
                _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE);
            } else {
            PLOG(ERROR) << "Could not access secondary dex " << dex_path;
                _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
            }
        }

    // Check if we should make the oat file public.
    // Note that if the dex file is not public the compiled code cannot be made public.
    *is_public_out = ((dexopt_flags & DEXOPT_PUBLIC) != 0) &&
            ((dex_path_stat.st_mode & S_IROTH) != 0);

        // Prepare the oat directories.
    if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set, oat_dir_out)) {
        return false;
        if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set)) {
            _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
        }

    // Analyze profiles.
    bool profile_was_updated = analyze_profiles(uid, dex_path, /*is_secondary_dex*/true);

        // Open the vdex/oat files if any.
        unique_fd oat_file_fd;
        unique_fd vdex_file_fd;
    unique_fd zip_fd;
    zip_fd.reset(open(dex_path.c_str(), O_RDONLY));
    if (zip_fd.get() < 0) {
        PLOG(ERROR) << "installd cannot open " << dex_path << " for input during dexopt";
        return false;
    }
        if (!maybe_open_oat_and_vdex_file(dex_path,
                                          *oat_dir_out,
                                          instruction_set,
                                          true /* is_secondary_dex */,
                                          &oat_file_fd,
                                          &vdex_file_fd)) {
      return false;
            _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
        }

    pid_t pid = fork();
    if (pid == 0) {
        // child -- drop privileges before continuing.
        drop_capabilities(uid);
        // Run dexoptanalyzer to get dexopt_needed code.
        // Analyze profiles.
        bool profile_was_updated = analyze_profiles(uid, dex_path, /*is_secondary_dex*/true);

        // Run dexoptanalyzer to get dexopt_needed code. This is not expected to return.
        exec_dexoptanalyzer(dex_path,
                            vdex_file_fd.get(),
                            oat_file_fd.get(),
                            zip_fd.get(),
                            instruction_set,
                            compiler_filter,
                            profile_was_updated,
                            downgrade, class_loader_context);
        exit(DEXOPTANALYZER_BIN_EXEC_ERROR);
                            compiler_filter, profile_was_updated,
                            downgrade,
                            class_loader_context);
        PLOG(ERROR) << "Failed to exec dexoptanalyzer";
        _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
    }

    /* parent */

    int result = wait_child(pid);
    if (!WIFEXITED(result)) {
        LOG(ERROR) << "dexoptanalyzer failed for path " << dex_path << ": " << result;
        return false;
    }
    result = WEXITSTATUS(result);
    bool success = process_dexoptanalyzer_result(dex_path, result, dexopt_needed_out);
    // Check that we successfully executed dexoptanalyzer.
    bool success = process_secondary_dexoptanalyzer_result(dex_path, result, dexopt_needed_out);

    LOG(DEBUG) << "Processed secondary dex file " << dex_path << " result=" << result;

    // Run dexopt only if needed or forced.
    // Note that dexoptanalyzer is executed even if force compilation is enabled.
    // We ignore its valid dexopNeeded result, but still check (in process_dexoptanalyzer_result)
    // that we only get results for odex files (apk_dir/oat/isa/code.odex) and not
    // for oat files from dalvik-cache.
    if (success && ((dexopt_flags & DEXOPT_FORCE) != 0)) {
    // Note that dexoptanalyzer is executed even if force compilation is enabled (because it
    // makes the code simpler; force compilation is only needed during tests).
    if (success &&
        (result != SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE) &&
        ((dexopt_flags & DEXOPT_FORCE) != 0)) {
        *dexopt_needed_out = DEX2OAT_FROM_SCRATCH;
    }

    // Check if we should make the oat file public.
    // Note that if the dex file is not public the compiled code cannot be made public.
    // It is ok to check this flag outside in the parent process.
    *is_public_out = ((dexopt_flags & DEXOPT_PUBLIC) != 0) && is_file_public(dex_path);

    return success;
}

@@ -1708,13 +1778,11 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins

    // Check if we're dealing with a secondary dex file and if we need to compile it.
    std::string oat_dir_str;
    std::string dex_real_path;
    if (is_secondary_dex) {
        if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
                instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
                &dex_real_path, downgrade, class_loader_context)) {
                downgrade, class_loader_context)) {
            oat_dir = oat_dir_str.c_str();
            dex_path = dex_real_path.c_str();
            if (dexopt_needed == NO_DEXOPT_NEEDED) {
                return 0;  // Nothing to do, report success.
            }
@@ -1852,29 +1920,13 @@ static bool unlink_if_exists(const std::string& file) {
    return false;
}

// Create the oat file structure for the secondary dex 'dex_path' and assign
// the individual path component to the 'out_' parameters.
static bool create_secondary_dex_oat_layout(const std::string& dex_path, const std::string& isa,
        /*out*/char* out_oat_dir, /*out*/char* out_oat_isa_dir, /*out*/char* out_oat_path) {
    size_t dirIndex = dex_path.rfind('/');
    if (dirIndex == std::string::npos) {
        LOG(ERROR) << "Unexpected dir structure for dex file " << dex_path;
        return false;
    }
    // TODO(calin): we have similar computations in at lest 3 other places
    // (InstalldNativeService, otapropt and dexopt). Unify them and get rid of snprintf by
    // use string append.
    std::string apk_dir = dex_path.substr(0, dirIndex);
    snprintf(out_oat_dir, PKG_PATH_MAX, "%s/oat", apk_dir.c_str());
    snprintf(out_oat_isa_dir, PKG_PATH_MAX, "%s/%s", out_oat_dir, isa.c_str());

    if (!create_oat_out_path(dex_path.c_str(), isa.c_str(), out_oat_dir,
            /*is_secondary_dex*/true, out_oat_path)) {
        LOG(ERROR) << "Could not create oat path for secondary dex " << dex_path;
        return false;
    }
    return true;
}
enum ReconcileSecondaryDexResult {
    kReconcileSecondaryDexExists = 0,
    kReconcileSecondaryDexCleanedUp = 1,
    kReconcileSecondaryDexValidationError = 2,
    kReconcileSecondaryDexCleanUpError = 3,
    kReconcileSecondaryDexAccessIOError = 4,
};

// Reconcile the secondary dex 'dex_path' and its generated oat files.
// Return true if all the parameters are valid and the secondary dex file was
@@ -1888,60 +1940,55 @@ bool reconcile_secondary_dex_file(const std::string& dex_path,
        const std::string& pkgname, int uid, const std::vector<std::string>& isas,
        const std::unique_ptr<std::string>& volume_uuid, int storage_flag,
        /*out*/bool* out_secondary_dex_exists) {
    // Set out to false to start with, just in case we have validation errors.
    *out_secondary_dex_exists = false;
    if (!validate_dex_path_size(dex_path)) {
    *out_secondary_dex_exists = false;  // start by assuming the file does not exist.
    if (isas.size() == 0) {
        LOG(ERROR) << "reconcile_secondary_dex_file called with empty isas vector";
        return false;
    }

    if (isas.size() == 0) {
        LOG(ERROR) << "reconcile_secondary_dex_file called with empty isas vector";
    if (storage_flag != FLAG_STORAGE_CE && storage_flag != FLAG_STORAGE_DE) {
        LOG(ERROR) << "reconcile_secondary_dex_file called with invalid storage_flag: "
                << storage_flag;
        return false;
    }

    const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
    // As a security measure we want to unlink art artifacts with the reduced capabilities
    // of the package user id. So we fork and drop capabilities in the child.
    pid_t pid = fork();
    if (pid == 0) {
        /* child -- drop privileges before continuing */
        drop_capabilities(uid);

    // Note that we cannot validate the package path here because the file might not exist
    // and we cannot call realpath to resolve system symlinks. Since /data/user/0 symlinks to
    // /data/data/ a lot of validations will fail if we attempt to check the package path.
    // It is still ok to be more relaxed because any file removal is done after forking and
    // dropping capabilities.
        const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
        if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
            uid, storage_flag, /*validate_package_path*/ false)) {
                uid, storage_flag)) {
            LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
        return false;
            _exit(kReconcileSecondaryDexValidationError);
        }

    if (access(dex_path.c_str(), F_OK) == 0) {
        // The path exists, nothing to do. The odex files (if any) will be left untouched.
        *out_secondary_dex_exists = true;
        return true;
    } else if (errno != ENOENT) {
        PLOG(ERROR) << "Failed to check access to secondary dex " << dex_path;
        return false;
        SecondaryDexAccess access_check = check_secondary_dex_access(dex_path);
        switch (access_check) {
            case kSecondaryDexAccessDoesNotExist:
                 // File does not exist. Proceed with cleaning.
                break;
            case kSecondaryDexAccessReadOk: _exit(kReconcileSecondaryDexExists);
            case kSecondaryDexAccessIOError: _exit(kReconcileSecondaryDexAccessIOError);
            case kSecondaryDexAccessPermissionError: _exit(kReconcileSecondaryDexValidationError);
            default:
                LOG(ERROR) << "Unexpected result from check_secondary_dex_access: " << access_check;
                _exit(kReconcileSecondaryDexValidationError);
        }

    // As a security measure we want to unlink art artifacts with the reduced capabilities
    // of the package user id. So we fork and drop capabilities in the child.
    pid_t pid = fork();
    if (pid == 0) {
        // The secondary dex does not exist anymore. Clear any generated files.
        // The secondary dex does not exist anymore or it's. Clear any generated files.
        char oat_path[PKG_PATH_MAX];
        char oat_dir[PKG_PATH_MAX];
        char oat_isa_dir[PKG_PATH_MAX];
        bool result = true;
        /* child -- drop privileges before continuing */
        drop_capabilities(uid);
        for (size_t i = 0; i < isas.size(); i++) {
            if (!create_secondary_dex_oat_layout(dex_path,
                                                 isas[i],
                                                 oat_dir,
                                                 oat_isa_dir,
                                                 oat_path)) {
                LOG(ERROR) << "Could not create secondary odex layout: "
                           << dex_path;
                result = false;
                continue;
            if (!create_secondary_dex_oat_layout(
                    dex_path,isas[i], oat_dir, oat_isa_dir, oat_path)) {
                LOG(ERROR) << "Could not create secondary odex layout: " << dex_path;
                _exit(kReconcileSecondaryDexValidationError);
            }

            // Delete oat/vdex/art files.
@@ -1966,11 +2013,43 @@ bool reconcile_secondary_dex_file(const std::string& dex_path,
            result = rmdir_if_empty(oat_isa_dir) && result;
            result = rmdir_if_empty(oat_dir) && result;
        }
        result ? _exit(0) : _exit(1);
        if (!result) {
            PLOG(ERROR) << "Failed to clean secondary dex artifacts for location " << dex_path;
        }
        _exit(result ? kReconcileSecondaryDexCleanedUp : kReconcileSecondaryDexAccessIOError);
    }

    int return_code = wait_child(pid);
    return return_code == 0;
    if (!WIFEXITED(return_code)) {
        LOG(WARNING) << "reconcile dex failed for location " << dex_path << ": " << return_code;
    } else {
        return_code = WEXITSTATUS(return_code);
    }

    LOG(DEBUG) << "Reconcile secondary dex path " << dex_path << " result=" << return_code;

    switch (return_code) {
        case kReconcileSecondaryDexCleanedUp:
        case kReconcileSecondaryDexValidationError:
            // If we couldn't validate assume the dex file does not exist.
            // This will purge the entry from the PM records.
            *out_secondary_dex_exists = false;
            return true;
        case kReconcileSecondaryDexExists:
            *out_secondary_dex_exists = true;
            return true;
        case kReconcileSecondaryDexAccessIOError:
            // We had an access IO error.
            // Return false so that we can try again.
            // The value of out_secondary_dex_exists does not matter in this case and by convention
            // is set to false.
            *out_secondary_dex_exists = false;
            return false;
        default:
            LOG(ERROR) << "Unexpected code from reconcile_secondary_dex_file: " << return_code;
            *out_secondary_dex_exists = false;
            return false;
    }
}

// Helper for move_ab, so that we can have common failure-case cleanup.
+20 −0

File changed.

Preview size limit exceeded, changes collapsed.

+359 −0

File added.

Preview size limit exceeded, changes collapsed.

+3 −0

File changed.

Preview size limit exceeded, changes collapsed.

+107 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading