Refactor argument parsing in ota preopt
Unify the parsing of all the versions. This will make it much
easier to extend the interface to accept new arguments.
Test: installd_otapreopt_test
Bug: 30934496
Change-Id: Idf945d3f4078b4ef86e2c2532b321768d2868fa7
diff --git a/cmds/installd/otapreopt_parameters.cpp b/cmds/installd/otapreopt_parameters.cpp
index 0cfaab8..b8e6310 100644
--- a/cmds/installd/otapreopt_parameters.cpp
+++ b/cmds/installd/otapreopt_parameters.cpp
@@ -93,9 +93,9 @@
+ 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,397 +105,21 @@
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;
- }
-}
-
-bool OTAPreoptParameters::ReadArgumentsV2(int argc ATTRIBUTE_UNUSED, const char** argv, bool versioned) {
- size_t dexopt_index = versioned ? 3 : 2;
-
- // 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;
-
- default:
- LOG(ERROR) << "Too many arguments, got " << param;
- return false;
- }
- }
-
- // 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";
-
- 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;
-
- default:
- LOG(ERROR) << "Too many arguments, got " << param;
- 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;
-
- // 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;
-
- case 12:
- target_sdk_version = atoi(param);
- break;
-
- default:
- LOG(ERROR) << "Too many arguments, got " << param;
- 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;
- }
-
- return true;
-}
-
-// 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;
-
- // 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;
-
- case 12:
- target_sdk_version = atoi(param);
- break;
-
- case 13:
- profile_name = ParseNull(param);
- break;
-
- default:
- LOG(ERROR) << "Too many arguments, got " << param;
- return false;
- }
- }
-
- if (param_index != 14) {
- LOG(ERROR) << "Not enough parameters";
- return false;
- }
-
- return true;
+ return ReadArgumentsPostV1(version, argv, 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) {
+bool OTAPreoptParameters::ReadArgumentsV1(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\"";
+ LOG(ERROR) << "Expected \"dexopt\" but found: " << argv[2];
return false;
}
@@ -597,5 +221,123 @@
return true;
}
+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) << "Don't know how to read arguments for version " << version;
+ return false;
+ }
+ size_t dexopt_index = versioned ? 3 : 2;
+
+ // 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\" but found: " << argv[dexopt_index];
+ return false;
+ }
+
+ // Validate the number of arguments.
+ size_t num_args_actual = 0;
+ while (argv[dexopt_index + 1 + num_args_actual] != nullptr) {
+ num_args_actual++;
+ }
+
+ if (num_args_actual != num_args_expected) {
+ LOG(ERROR) << "Invalid number of arguments. expected="
+ << num_args_expected << " actual=" << num_args_actual;
+ 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.
+
+ // 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";
+
+ for (size_t param_index = 0; param_index < num_args_actual; ++param_index) {
+ const char* param = argv[dexopt_index + 1 + param_index];
+ 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;
+
+ case 13:
+ profile_name = ParseNull(param);
+ break;
+
+ default:
+ CHECK(false) << "Should not get here. Did you call ReadArguments "
+ << "with the right expectation?";
+ }
+ }
+
+ return true;
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/otapreopt_parameters.h b/cmds/installd/otapreopt_parameters.h
index 20faeb5..eb5dd85 100644
--- a/cmds/installd/otapreopt_parameters.h
+++ b/cmds/installd/otapreopt_parameters.h
@@ -28,11 +28,8 @@
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;