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

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

Merge "Refactor argument parsing in ota preopt"

parents b6db090f 7707aeaa
Loading
Loading
Loading
Loading
+77 −335
Original line number Diff line number Diff line
@@ -93,9 +93,9 @@ bool OTAPreoptParameters::ReadArguments(int argc, const char** argv) {
                                    + 1   // libs
                                    + 1;  // seinfo
        if (argc == kV2ArgCount) {
            return ReadArgumentsV2(argc, argv, false);
            return ReadArgumentsPostV1(2, argv, false);
        } else {
            return ReadArgumentsV1(argc, argv);
            return ReadArgumentsV1(argv);
        }
    }

@@ -105,38 +105,27 @@ bool OTAPreoptParameters::ReadArguments(int argc, const char** argv) {
        return false;
    }

    switch (version) {
        case 2:
            return ReadArgumentsV2(argc, argv, true);
        case 3:
            return ReadArgumentsV3(argc, argv);
        case 4:
            return ReadArgumentsV4(argc, argv);
        case 5:
            return ReadArgumentsV5(argc, argv);

        default:
            LOG(ERROR) << "Unsupported version " << version;
            return false;
    }
    return ReadArgumentsPostV1(version, argv, true);
}

bool OTAPreoptParameters::ReadArgumentsV2(int argc ATTRIBUTE_UNUSED, const char** argv, bool versioned) {
    size_t dexopt_index = versioned ? 3 : 2;
static int ReplaceMask(int input, int old_mask, int new_mask) {
    return (input & old_mask) != 0 ? new_mask : 0;
}

bool OTAPreoptParameters::ReadArgumentsV1(const char** argv) {
    // Check for "dexopt".
    if (argv[dexopt_index] == nullptr) {
    if (argv[2] == nullptr) {
        LOG(ERROR) << "Missing parameters";
        return false;
    }
    if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
        LOG(ERROR) << "Expected \"dexopt\"";
    if (std::string("dexopt").compare(argv[2]) != 0) {
        LOG(ERROR) << "Expected \"dexopt\" but found: " << argv[2];
        return false;
    }

    size_t param_index = 0;
    for (;; ++param_index) {
        const char* param = argv[dexopt_index + 1 + param_index];
        const char* param = argv[3 + param_index];
        if (param == nullptr) {
            break;
        }
@@ -158,17 +147,38 @@ bool OTAPreoptParameters::ReadArgumentsV2(int argc ATTRIBUTE_UNUSED, const char*
                instruction_set = param;
                break;

            case 4:
                dexopt_needed = atoi(param);
            case 4: {
                // Version 1 had:
                //   DEXOPT_DEX2OAT_NEEDED       = 1
                //   DEXOPT_PATCHOAT_NEEDED      = 2
                //   DEXOPT_SELF_PATCHOAT_NEEDED = 3
                // We will simply use DEX2OAT_FROM_SCRATCH.
                dexopt_needed = DEX2OAT_FROM_SCRATCH;
                break;
            }

            case 5:
                oat_dir = param;
                break;

            case 6:
                dexopt_flags = atoi(param);
            case 6: {
                // Version 1 had:
                constexpr int OLD_DEXOPT_PUBLIC         = 1 << 1;
                // Note: DEXOPT_SAFEMODE has been removed.
                // constexpr int OLD_DEXOPT_SAFEMODE       = 1 << 2;
                constexpr int OLD_DEXOPT_DEBUGGABLE     = 1 << 3;
                constexpr int OLD_DEXOPT_BOOTCOMPLETE   = 1 << 4;
                constexpr int OLD_DEXOPT_PROFILE_GUIDED = 1 << 5;
                constexpr int OLD_DEXOPT_OTA            = 1 << 6;
                int input = atoi(param);
                dexopt_flags =
                        ReplaceMask(input, OLD_DEXOPT_PUBLIC, DEXOPT_PUBLIC) |
                        ReplaceMask(input, OLD_DEXOPT_DEBUGGABLE, DEXOPT_DEBUGGABLE) |
                        ReplaceMask(input, OLD_DEXOPT_BOOTCOMPLETE, DEXOPT_BOOTCOMPLETE) |
                        ReplaceMask(input, OLD_DEXOPT_PROFILE_GUIDED, DEXOPT_PROFILE_GUIDED) |
                        ReplaceMask(input, OLD_DEXOPT_OTA, 0);
                break;
            }

            case 7:
                compiler_filter = param;
@@ -182,16 +192,21 @@ bool OTAPreoptParameters::ReadArgumentsV2(int argc ATTRIBUTE_UNUSED, const char*
                shared_libraries = ParseNull(param);
                break;

            case 10:
                se_info = ParseNull(param);
                break;

            default:
                LOG(ERROR) << "Too many arguments, got " << param;
                return false;
        }
    }

    if (param_index != 10) {
        LOG(ERROR) << "Not enough parameters";
        return false;
    }

    // Set se_info to null. It is only relevant for secondary dex files, which we won't
    // receive from a v1 A side.
    se_info = nullptr;

    // Set downgrade to false. It is only relevant when downgrading compiler
    // filter, which is not the case during ota.
    downgrade = false;
@@ -203,106 +218,21 @@ bool OTAPreoptParameters::ReadArgumentsV2(int argc ATTRIBUTE_UNUSED, const char*
    // Set the profile name to the primary apk profile.
    profile_name = "primary.prof";

    if (param_index != 11) {
        LOG(ERROR) << "Not enough parameters";
        return false;
    }

    return true;
}

bool OTAPreoptParameters::ReadArgumentsV3(int argc ATTRIBUTE_UNUSED, const char** argv) {
    size_t dexopt_index = 3;

    // Check for "dexopt".
    if (argv[dexopt_index] == nullptr) {
        LOG(ERROR) << "Missing parameters";
        return false;
    }
    if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
        LOG(ERROR) << "Expected \"dexopt\"";
        return false;
    }

    size_t param_index = 0;
    for (;; ++param_index) {
        const char* param = argv[dexopt_index + 1 + param_index];
        if (param == nullptr) {
            break;
        }

        switch (param_index) {
            case 0:
                apk_path = param;
                break;

            case 1:
                uid = atoi(param);
                break;

            case 2:
                pkgName = param;
                break;

            case 3:
                instruction_set = param;
                break;

            case 4:
                dexopt_needed = atoi(param);
                break;

            case 5:
                oat_dir = param;
                break;

            case 6:
                dexopt_flags = atoi(param);
                break;

            case 7:
                compiler_filter = param;
                break;

            case 8:
                volume_uuid = ParseNull(param);
                break;

            case 9:
                shared_libraries = ParseNull(param);
                break;

            case 10:
                se_info = ParseNull(param);
                break;

            case 11:
                downgrade = ParseBool(param);
                break;

bool OTAPreoptParameters::ReadArgumentsPostV1(uint32_t version, const char** argv, bool versioned) {
    size_t num_args_expected = 0;
    switch (version) {
        case 2: num_args_expected = 11; break;
        case 3: num_args_expected = 12; break;
        case 4: num_args_expected = 13; break;
        case 5: num_args_expected = 14; break;
        default:
                LOG(ERROR) << "Too many arguments, got " << param;
            LOG(ERROR) << "Don't know how to read arguments for version " << version;
            return false;
    }
    }

    // Set target_sdk_version to 0, ie the platform SDK version. This is
    // conservative and may force some classes to verify at runtime.
    target_sdk_version = 0;

    // Set the profile name to the primary apk profile.
    profile_name = "primary.prof";

    if (param_index != 12) {
        LOG(ERROR) << "Not enough parameters";
        return false;
    }

    return true;
}

bool OTAPreoptParameters::ReadArgumentsV4(int argc ATTRIBUTE_UNUSED, const char** argv) {
    size_t dexopt_index = 3;
    size_t dexopt_index = versioned ? 3 : 2;

    // Check for "dexopt".
    if (argv[dexopt_index] == nullptr) {
@@ -310,109 +240,39 @@ bool OTAPreoptParameters::ReadArgumentsV4(int argc ATTRIBUTE_UNUSED, const char*
        return false;
    }
    if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
        LOG(ERROR) << "Expected \"dexopt\"";
        LOG(ERROR) << "Expected \"dexopt\" but found: " << argv[dexopt_index];
        return false;
    }

    size_t param_index = 0;
    for (;; ++param_index) {
        const char* param = argv[dexopt_index + 1 + param_index];
        if (param == nullptr) {
            break;
    // Validate the number of arguments.
    size_t num_args_actual = 0;
    while (argv[dexopt_index + 1 + num_args_actual] != nullptr) {
        num_args_actual++;
    }

        switch (param_index) {
            case 0:
                apk_path = param;
                break;

            case 1:
                uid = atoi(param);
                break;

            case 2:
                pkgName = param;
                break;

            case 3:
                instruction_set = param;
                break;

            case 4:
                dexopt_needed = atoi(param);
                break;

            case 5:
                oat_dir = param;
                break;

            case 6:
                dexopt_flags = atoi(param);
                break;

            case 7:
                compiler_filter = param;
                break;

            case 8:
                volume_uuid = ParseNull(param);
                break;

            case 9:
                shared_libraries = ParseNull(param);
                break;

            case 10:
                se_info = ParseNull(param);
                break;

            case 11:
                downgrade = ParseBool(param);
                break;

            case 12:
                target_sdk_version = atoi(param);
                break;

            default:
                LOG(ERROR) << "Too many arguments, got " << param;
    if (num_args_actual != num_args_expected) {
        LOG(ERROR) << "Invalid number of arguments. expected="
                << num_args_expected << " actual=" << num_args_actual;
        return false;
    }
    }

    // Set the profile name to the primary apk profile.
    profile_name = "primary.prof";

    if (param_index != 13) {
        LOG(ERROR) << "Not enough parameters";
        return false;
    }
    // The number of arguments is OK.
    // Configure the default values for the parameters that were added after V1.
    // The default values will be overwritten in case they are passed as arguments.

    return true;
}
    // Set downgrade to false. It is only relevant when downgrading compiler
    // filter, which is not the case during ota.
    downgrade = false;

// TODO: this pattern does not scale and result in a lot of code duplication.
// Either find a better pattern or refactor the code to eliminate the duplication.
bool OTAPreoptParameters::ReadArgumentsV5(int argc ATTRIBUTE_UNUSED, const char** argv) {
    size_t dexopt_index = 3;
    // Set target_sdk_version to 0, ie the platform SDK version. This is
    // conservative and may force some classes to verify at runtime.
    target_sdk_version = 0;

    // Check for "dexopt".
    if (argv[dexopt_index] == nullptr) {
        LOG(ERROR) << "Missing parameters";
        return false;
    }
    if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
        LOG(ERROR) << "Expected \"dexopt\"";
        return false;
    }
    // Set the profile name to the primary apk profile.
    profile_name = "primary.prof";

    size_t param_index = 0;
    for (;; ++param_index) {
    for (size_t param_index = 0; param_index < num_args_actual; ++param_index) {
        const char* param = argv[dexopt_index + 1 + param_index];
        if (param == nullptr) {
            break;
        }

        switch (param_index) {
            case 0:
                apk_path = param;
@@ -471,131 +331,13 @@ bool OTAPreoptParameters::ReadArgumentsV5(int argc ATTRIBUTE_UNUSED, const char*
                break;

            default:
                LOG(ERROR) << "Too many arguments, got " << param;
                return false;
        }
                CHECK(false) << "Should not get here. Did you call ReadArguments "
                        << "with the right expectation?";
        }

    if (param_index != 14) {
        LOG(ERROR) << "Not enough parameters";
        return false;
    }

    return true;
}

static int ReplaceMask(int input, int old_mask, int new_mask) {
    return (input & old_mask) != 0 ? new_mask : 0;
}

bool OTAPreoptParameters::ReadArgumentsV1(int argc ATTRIBUTE_UNUSED, const char** argv) {
    // Check for "dexopt".
    if (argv[2] == nullptr) {
        LOG(ERROR) << "Missing parameters";
        return false;
    }
    if (std::string("dexopt").compare(argv[2]) != 0) {
        LOG(ERROR) << "Expected \"dexopt\"";
        return false;
    }

    size_t param_index = 0;
    for (;; ++param_index) {
        const char* param = argv[3 + param_index];
        if (param == nullptr) {
            break;
        }

        switch (param_index) {
            case 0:
                apk_path = param;
                break;

            case 1:
                uid = atoi(param);
                break;

            case 2:
                pkgName = param;
                break;

            case 3:
                instruction_set = param;
                break;

            case 4: {
                // Version 1 had:
                //   DEXOPT_DEX2OAT_NEEDED       = 1
                //   DEXOPT_PATCHOAT_NEEDED      = 2
                //   DEXOPT_SELF_PATCHOAT_NEEDED = 3
                // We will simply use DEX2OAT_FROM_SCRATCH.
                dexopt_needed = DEX2OAT_FROM_SCRATCH;
                break;
            }

            case 5:
                oat_dir = param;
                break;

            case 6: {
                // Version 1 had:
                constexpr int OLD_DEXOPT_PUBLIC         = 1 << 1;
                // Note: DEXOPT_SAFEMODE has been removed.
                // constexpr int OLD_DEXOPT_SAFEMODE       = 1 << 2;
                constexpr int OLD_DEXOPT_DEBUGGABLE     = 1 << 3;
                constexpr int OLD_DEXOPT_BOOTCOMPLETE   = 1 << 4;
                constexpr int OLD_DEXOPT_PROFILE_GUIDED = 1 << 5;
                constexpr int OLD_DEXOPT_OTA            = 1 << 6;
                int input = atoi(param);
                dexopt_flags =
                        ReplaceMask(input, OLD_DEXOPT_PUBLIC, DEXOPT_PUBLIC) |
                        ReplaceMask(input, OLD_DEXOPT_DEBUGGABLE, DEXOPT_DEBUGGABLE) |
                        ReplaceMask(input, OLD_DEXOPT_BOOTCOMPLETE, DEXOPT_BOOTCOMPLETE) |
                        ReplaceMask(input, OLD_DEXOPT_PROFILE_GUIDED, DEXOPT_PROFILE_GUIDED) |
                        ReplaceMask(input, OLD_DEXOPT_OTA, 0);
                break;
            }

            case 7:
                compiler_filter = param;
                break;

            case 8:
                volume_uuid = ParseNull(param);
                break;

            case 9:
                shared_libraries = ParseNull(param);
                break;

            default:
                LOG(ERROR) << "Too many arguments, got " << param;
                return false;
        }
    }

    if (param_index != 10) {
        LOG(ERROR) << "Not enough parameters";
        return false;
    }

    // Set se_info to null. It is only relevant for secondary dex files, which we won't
    // receive from a v1 A side.
    se_info = nullptr;

    // Set downgrade to false. It is only relevant when downgrading compiler
    // filter, which is not the case during ota.
    downgrade = false;

    // Set target_sdk_version to 0, ie the platform SDK version. This is
    // conservative and may force some classes to verify at runtime.
    target_sdk_version = 0;

    // Set the profile name to the primary apk profile.
    profile_name = "primary.prof";

    return true;
}

}  // namespace installd
}  // namespace android
+2 −5
Original line number Diff line number Diff line
@@ -28,11 +28,8 @@ class OTAPreoptParameters {
    bool ReadArguments(int argc, const char** argv);

  private:
    bool ReadArgumentsV1(int argc, const char** argv);
    bool ReadArgumentsV2(int argc, const char** argv, bool versioned);
    bool ReadArgumentsV3(int argc, const char** argv);
    bool ReadArgumentsV4(int argc, const char** argv);
    bool ReadArgumentsV5(int argc, const char** argv);
    bool ReadArgumentsV1(const char** argv);
    bool ReadArgumentsPostV1(uint32_t version, const char** argv, bool versioned);

    const char* apk_path;
    uid_t uid;