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

Commit 2c44e11d authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 4450504 from 5fe21afe to pi-release

Change-Id: I9aef707fed4a42e8d22dea1339691157a6928fd9
parents 08407e38 5fe21afe
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