| /* | 
 |  ** Copyright 2016, The Android Open Source Project | 
 |  ** | 
 |  ** Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  ** you may not use this file except in compliance with the License. | 
 |  ** You may obtain a copy of the License at | 
 |  ** | 
 |  **     http://www.apache.org/licenses/LICENSE-2.0 | 
 |  ** | 
 |  ** Unless required by applicable law or agreed to in writing, software | 
 |  ** distributed under the License is distributed on an "AS IS" BASIS, | 
 |  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  ** See the License for the specific language governing permissions and | 
 |  ** limitations under the License. | 
 |  */ | 
 |  | 
 | #include "otapreopt_parameters.h" | 
 |  | 
 | #include <cstring> | 
 |  | 
 | #include <android-base/logging.h> | 
 |  | 
 | #include "dexopt.h" | 
 | #include "installd_constants.h" | 
 | #include "otapreopt_utils.h" | 
 |  | 
 | #ifndef LOG_TAG | 
 | #define LOG_TAG "otapreopt" | 
 | #endif | 
 |  | 
 | namespace android { | 
 | namespace installd { | 
 |  | 
 | static bool ParseBool(const char* in) { | 
 |     if (strcmp(in, "true") == 0) { | 
 |         return true; | 
 |     } | 
 |     return false; | 
 | } | 
 |  | 
 | static const char* ParseNull(const char* arg) { | 
 |     return (strcmp(arg, "!") == 0) ? nullptr : arg; | 
 | } | 
 |  | 
 | static bool ParseUInt(const char* in, uint32_t* out) { | 
 |     char* end; | 
 |     long long int result = strtoll(in, &end, 0); | 
 |     if (in == end || *end != '\0') { | 
 |         return false; | 
 |     } | 
 |     if (result < std::numeric_limits<uint32_t>::min() || | 
 |             std::numeric_limits<uint32_t>::max() < result) { | 
 |         return false; | 
 |     } | 
 |     *out = static_cast<uint32_t>(result); | 
 |     return true; | 
 | } | 
 |  | 
 | bool OTAPreoptParameters::ReadArguments(int argc, const char** argv) { | 
 |     // Expected command line: | 
 |     //   target-slot [version] dexopt {DEXOPT_PARAMETERS} | 
 |  | 
 |     const char* target_slot_arg = argv[1]; | 
 |     if (target_slot_arg == nullptr) { | 
 |         LOG(ERROR) << "Missing parameters"; | 
 |         return false; | 
 |     } | 
 |     // Sanitize value. Only allow (a-zA-Z0-9_)+. | 
 |     target_slot = target_slot_arg; | 
 |     if (!ValidateTargetSlotSuffix(target_slot)) { | 
 |         LOG(ERROR) << "Target slot suffix not legal: " << target_slot; | 
 |         return false; | 
 |     } | 
 |  | 
 |     // Check for version or "dexopt" next. | 
 |     if (argv[2] == nullptr) { | 
 |         LOG(ERROR) << "Missing parameters"; | 
 |         return false; | 
 |     } | 
 |  | 
 |     if (std::string("dexopt").compare(argv[2]) == 0) { | 
 |         // This is version 1 (N) or pre-versioning version 2. | 
 |         constexpr int kV2ArgCount =   1   // "otapreopt" | 
 |                                     + 1   // slot | 
 |                                     + 1   // "dexopt" | 
 |                                     + 1   // apk_path | 
 |                                     + 1   // uid | 
 |                                     + 1   // pkg | 
 |                                     + 1   // isa | 
 |                                     + 1   // dexopt_needed | 
 |                                     + 1   // oat_dir | 
 |                                     + 1   // dexopt_flags | 
 |                                     + 1   // filter | 
 |                                     + 1   // volume | 
 |                                     + 1   // libs | 
 |                                     + 1;  // seinfo | 
 |         if (argc == kV2ArgCount) { | 
 |             return ReadArgumentsPostV1(2, argv, false); | 
 |         } else { | 
 |             return ReadArgumentsV1(argv); | 
 |         } | 
 |     } | 
 |  | 
 |     uint32_t version; | 
 |     if (!ParseUInt(argv[2], &version)) { | 
 |         LOG(ERROR) << "Could not parse version: " << argv[2]; | 
 |         return false; | 
 |     } | 
 |  | 
 |     return ReadArgumentsPostV1(version, argv, true); | 
 | } | 
 |  | 
 | static int ReplaceMask(int input, int old_mask, int new_mask) { | 
 |     return (input & old_mask) != 0 ? new_mask : 0; | 
 | } | 
 |  | 
 | void OTAPreoptParameters::SetDefaultsForPostV1Arguments() { | 
 |     // 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"; | 
 |  | 
 |     // By default we don't have a dex metadata file. | 
 |     dex_metadata_path = nullptr; | 
 |  | 
 |     // The compilation reason is ab-ota (match the system property pm.dexopt.ab-ota) | 
 |     compilation_reason = "ab-ota"; | 
 |  | 
 |     // Flag is enabled by default for A/B otas. | 
 |     dexopt_flags = DEXOPT_GENERATE_COMPACT_DEX; | 
 | } | 
 |  | 
 | 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\" but found: " << argv[2]; | 
 |         return false; | 
 |     } | 
 |  | 
 |     SetDefaultsForPostV1Arguments(); | 
 |  | 
 |     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; | 
 |                 static_assert(DEXOPT_GENERATE_COMPACT_DEX > OLD_DEXOPT_OTA, "must not overlap"); | 
 |                 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; | 
 |     } | 
 |  | 
 |     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; | 
 |         case 6: num_args_expected = 15; break; | 
 |         case 7: | 
 |         // Version 8 adds a new dexopt flag: DEXOPT_GENERATE_COMPACT_DEX | 
 |         case 8: num_args_expected = 16; break; | 
 |         // Version 9 adds a new dexopt flag: DEXOPT_GENERATE_APP_IMAGE | 
 |         case 9: num_args_expected = 16; break; | 
 |         // Version 10 is a compatibility bump. | 
 |         case 10: num_args_expected = 16; 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. | 
 |     SetDefaultsForPostV1Arguments(); | 
 |  | 
 |     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); | 
 |                 // Add CompactDex generation flag for versions less than 8 since it wasn't passed | 
 |                 // from the package manager. Only conditionally set the flag here so that it can | 
 |                 // be fully controlled by the package manager. | 
 |                 dexopt_flags |= (version < 8) ? DEXOPT_GENERATE_COMPACT_DEX : 0u; | 
 |                 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; | 
 |  | 
 |             case 14: | 
 |                 dex_metadata_path = ParseNull(param); | 
 |                 break; | 
 |  | 
 |             case 15: | 
 |                 compilation_reason = ParseNull(param); | 
 |                 break; | 
 |  | 
 |             default: | 
 |                 LOG(FATAL) << "Should not get here. Did you call ReadArguments " | 
 |                         << "with the right expectation? index=" << param_index | 
 |                         << " num_args=" << num_args_actual; | 
 |                 return false; | 
 |         } | 
 |     } | 
 |  | 
 |     if (version < 10) { | 
 |         // Do not accept '&' as shared libraries from versions prior to 10. These may lead | 
 |         // to runtime crashes. The server side of version 10+ should send the correct | 
 |         // context in almost all cases (e.g., only for actual shared packages). | 
 |         if (shared_libraries != nullptr && std::string("&") == shared_libraries) { | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     return true; | 
 | } | 
 |  | 
 | }  // namespace installd | 
 | }  // namespace android |