You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
12 KiB
381 lines
12 KiB
/*
|
|
** 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
|