otapreopt.cpp revision febf0bf33ca81edcdaab3625e2711fa58b398cc5
173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe/* 273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ** Copyright 2016, The Android Open Source Project 373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ** 473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ** Licensed under the Apache License, Version 2.0 (the "License"); 573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ** you may not use this file except in compliance with the License. 673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ** You may obtain a copy of the License at 773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ** 873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ** http://www.apache.org/licenses/LICENSE-2.0 973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ** 1073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ** Unless required by applicable law or agreed to in writing, software 1173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ** distributed under the License is distributed on an "AS IS" BASIS, 1273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ** See the License for the specific language governing permissions and 1473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ** limitations under the License. 1573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe */ 1673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 1773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <algorithm> 1873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <inttypes.h> 1973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <random> 2073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <selinux/android.h> 2173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <selinux/avc.h> 2273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <stdlib.h> 2373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <string.h> 2473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <sys/capability.h> 2573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <sys/prctl.h> 2673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <sys/stat.h> 2773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <sys/wait.h> 2873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 2973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <android-base/logging.h> 3073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <android-base/macros.h> 3173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <android-base/stringprintf.h> 3273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <cutils/fs.h> 3373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <cutils/log.h> 3473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <cutils/properties.h> 3573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <private/android_filesystem_config.h> 3673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 3773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <commands.h> 3873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <globals.h> 3973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <installd_deps.h> // Need to fill in requirements of commands. 4073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <string_helpers.h> 4173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <system_properties.h> 4273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#include <utils.h> 4373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 4473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#ifndef LOG_TAG 4573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#define LOG_TAG "otapreopt" 4673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#endif 4773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 4873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#define BUFFER_MAX 1024 /* input buffer for commands */ 4973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#define TOKEN_MAX 16 /* max number of arguments in buffer */ 5073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#define REPLY_MAX 256 /* largest reply allowed */ 5173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 5273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampeusing android::base::StringPrintf; 5373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 5473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampenamespace android { 5573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampenamespace installd { 5673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 5773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampestatic constexpr const char* kBootClassPathPropertyName = "env.BOOTCLASSPATH"; 5873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampestatic constexpr const char* kAndroidRootPathPropertyName = "env.ANDROID_ROOT"; 5973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampestatic constexpr const char* kOTARootDirectory = "/system-b"; 6073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampestatic constexpr size_t kISAIndex = 3; 6173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 6273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampetemplate<typename T> 6373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampestatic constexpr T RoundDown(T x, typename std::decay<T>::type n) { 6473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return DCHECK_CONSTEXPR(IsPowerOfTwo(n), , T(0))(x & -n); 6573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe} 6673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 6773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampetemplate<typename T> 6873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampestatic constexpr T RoundUp(T x, typename std::remove_reference<T>::type n) { 6973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return RoundDown(x + n - 1, n); 7073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe} 7173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 7273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampeclass OTAPreoptService { 7373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe public: 7473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe static constexpr const char* kOTADataDirectory = "/data/ota"; 7573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 7673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Main driver. Performs the following steps. 7773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // 7873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // 1) Parse options (read system properties etc from B partition). 7973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // 8073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // 2) Read in package data. 8173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // 8273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // 3) Prepare environment variables. 8373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // 8473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // 4) Prepare(compile) boot image, if necessary. 8573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // 8673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // 5) Run update. 8773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe int Main(int argc, char** argv) { 8873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (!ReadSystemProperties()) { 8973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe LOG(ERROR)<< "Failed reading system properties."; 9073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return 1; 9173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 9273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 9373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (!ReadEnvironment()) { 9473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe LOG(ERROR) << "Failed reading environment properties."; 9573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return 2; 9673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 9773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 9873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (!ReadPackage(argc, argv)) { 9973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe LOG(ERROR) << "Failed reading command line file."; 10073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return 3; 10173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 10273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 10373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe PrepareEnvironment(); 10473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 10573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (!PrepareBootImage()) { 10673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe LOG(ERROR) << "Failed preparing boot image."; 10773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return 4; 10873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 10973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 11073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe int dexopt_retcode = RunPreopt(); 11173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 11273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return dexopt_retcode; 11373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 11473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 11573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe int GetProperty(const char* key, char* value, const char* default_value) { 11673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const std::string* prop_value = system_properties_.GetProperty(key); 11773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (prop_value == nullptr) { 11873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (default_value == nullptr) { 11973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return 0; 12073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 12173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Copy in the default value. 12273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe strncpy(value, default_value, kPropertyValueMax - 1); 12373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe value[kPropertyValueMax - 1] = 0; 12473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return strlen(default_value);// TODO: Need to truncate? 12573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 12673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe size_t size = std::min(kPropertyValueMax - 1, prop_value->length()); 12773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe strncpy(value, prop_value->data(), size); 12873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe value[size] = 0; 12973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return static_cast<int>(size); 13073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 13173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 13273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampeprivate: 13373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe bool ReadSystemProperties() { 13473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // TODO(agampe): What to do about the things in default.prop? It's only heap sizes, so it's easy 13573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // to emulate for now, but has issues (e.g., vendors modifying the boot classpath 13673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // may require larger values here - revisit). That's why this goes first, so that 13773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // if those dummy values are overridden in build.prop, that's what we'll get. 13873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // 13973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Note: It seems we'll get access to the B root partition, so we should read the default.prop 14073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // file. 14173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // if (!system_properties_.Load(b_mount_path_ + "/default.prop") { 14273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // return false; 14373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // } 14473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe system_properties_.SetProperty("dalvik.vm.image-dex2oat-Xms", "64m"); 14573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe system_properties_.SetProperty("dalvik.vm.image-dex2oat-Xmx", "64m"); 14673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe system_properties_.SetProperty("dalvik.vm.dex2oat-Xms", "64m"); 14773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe system_properties_.SetProperty("dalvik.vm.dex2oat-Xmx", "512m"); 14873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 14973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // TODO(agampe): Do this properly/test. 15073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return system_properties_.Load(b_mount_path_ + "/system/build.prop"); 15173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 15273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 15373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe bool ReadEnvironment() { 15473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Read important environment variables. For simplicity, store them as 15573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // system properties. 15673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // TODO(agampe): We'll have to parse init.environ.rc for BOOTCLASSPATH. 15773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // For now, just the A version. 15873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char* boot_classpath = getenv("BOOTCLASSPATH"); 15973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (boot_classpath == nullptr) { 16073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 16173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 16273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe system_properties_.SetProperty(kBootClassPathPropertyName, boot_classpath); 16373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 16473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char* root_path = getenv("ANDROID_ROOT"); 16573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (root_path == nullptr) { 16673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 16773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 16873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe system_properties_.SetProperty(kAndroidRootPathPropertyName, b_mount_path_ + root_path); 16973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 17073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return true; 17173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 17273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 17373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe bool ReadPackage(int argc ATTRIBUTE_UNUSED, char** argv) { 17473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe size_t index = 0; 17573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe while (index < ARRAY_SIZE(package_parameters_) && 17673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe argv[index + 1] != nullptr) { 17773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe package_parameters_[index] = argv[index + 1]; 17873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe index++; 17973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 18073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (index != ARRAY_SIZE(package_parameters_)) { 18173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe LOG(ERROR) << "Wrong number of parameters"; 18273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 18373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 18473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 18573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return true; 18673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 18773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 18873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe void PrepareEnvironment() { 18973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe CHECK(system_properties_.GetProperty(kBootClassPathPropertyName) != nullptr); 19073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const std::string& boot_cp = 19173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe *system_properties_.GetProperty(kBootClassPathPropertyName); 19273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe environ_.push_back(StringPrintf("BOOTCLASSPATH=%s", boot_cp.c_str())); 19373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe environ_.push_back(StringPrintf("ANDROID_DATA=%s", kOTADataDirectory)); 19473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe CHECK(system_properties_.GetProperty(kAndroidRootPathPropertyName) != nullptr); 19573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const std::string& android_root = 19673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe *system_properties_.GetProperty(kAndroidRootPathPropertyName); 19773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe environ_.push_back(StringPrintf("ANDROID_ROOT=%s", android_root.c_str())); 19873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 19973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe for (const std::string& e : environ_) { 20073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe putenv(const_cast<char*>(e.c_str())); 20173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 20273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 20373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 20473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Ensure that we have the right boot image. The first time any app is 20573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // compiled, we'll try to generate it. 20673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe bool PrepareBootImage() { 20773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (package_parameters_[kISAIndex] == nullptr) { 20873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe LOG(ERROR) << "Instruction set missing."; 20973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 21073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 21173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char* isa = package_parameters_[kISAIndex]; 21273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 21373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Check whether the file exists where expected. 21473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::string dalvik_cache = std::string(kOTADataDirectory) + "/" + DALVIK_CACHE; 21573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::string isa_path = dalvik_cache + "/" + isa; 21673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::string art_path = isa_path + "/system@framework@boot.art"; 21773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::string oat_path = isa_path + "/system@framework@boot.oat"; 21873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (access(art_path.c_str(), F_OK) == 0 && 21973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe access(oat_path.c_str(), F_OK) == 0) { 22073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Files exist, assume everything is alright. 22173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return true; 22273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 22373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 22473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Create the directories, if necessary. 22573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (access(dalvik_cache.c_str(), F_OK) != 0) { 22673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (mkdir(dalvik_cache.c_str(), 0711) != 0) { 22773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe PLOG(ERROR) << "Could not create dalvik-cache dir"; 22873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 22973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 23073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 23173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (access(isa_path.c_str(), F_OK) != 0) { 23273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (mkdir(isa_path.c_str(), 0711) != 0) { 23373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe PLOG(ERROR) << "Could not create dalvik-cache isa dir"; 23473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 23573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 23673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 23773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 2385709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe // Prepare to create. 23973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // TODO: Delete files, just for a blank slate. 24073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const std::string& boot_cp = *system_properties_.GetProperty(kBootClassPathPropertyName); 24173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 2425709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe std::string preopted_boot_art_path = StringPrintf("%s/system/framework/%s/boot.art", 2435709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe b_mount_path_.c_str(), 2445709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe isa); 2455709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe if (access(preopted_boot_art_path.c_str(), F_OK) == 0) { 2465709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe return PatchoatBootImage(art_path, isa); 2475709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe } else { 2485709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe // No preopted boot image. Try to compile. 2495709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe return Dex2oatBootImage(boot_cp, art_path, oat_path, isa); 2505709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe } 2515709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe } 2525709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe 2535709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe bool PatchoatBootImage(const std::string& art_path, const char* isa) { 2545709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc. 2555709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe 2565709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe std::vector<std::string> cmd; 2575709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe cmd.push_back(b_mount_path_ + "/system/bin/patchoat"); 2585709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe 2595709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe cmd.push_back("--input-image-location=/system/framework/boot.art"); 2605709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe cmd.push_back(StringPrintf("--output-image-file=%s", art_path.c_str())); 2615709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe 2625709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe cmd.push_back(StringPrintf("--instruction-set=%s", isa)); 2635709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe 2645709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA, 2655709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe ART_BASE_ADDRESS_MAX_DELTA); 266febf0bf33ca81edcdaab3625e2711fa58b398cc5Andreas Gampe cmd.push_back(StringPrintf("--base-offset-delta=%d", base_offset)); 2675709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe 2685709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe std::string error_msg; 2695709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe bool result = Exec(cmd, &error_msg); 2705709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe if (!result) { 2715709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe LOG(ERROR) << "Could not generate boot image: " << error_msg; 2725709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe } 2735709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe return result; 2745709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe } 2755709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe 2765709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe bool Dex2oatBootImage(const std::string& boot_cp, 2775709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe const std::string& art_path, 2785709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe const std::string& oat_path, 2795709b5758d75085aeab121db94e8d6dbafe0b7aeAndreas Gampe const char* isa) { 28073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc. 28173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::vector<std::string> cmd; 28273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd.push_back(b_mount_path_ + "/system/bin/dex2oat"); 28373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd.push_back(StringPrintf("--image=%s", art_path.c_str())); 28473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe for (const std::string& boot_part : Split(boot_cp, ':')) { 28573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd.push_back(StringPrintf("--dex-file=%s", boot_part.c_str())); 28673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 28773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd.push_back(StringPrintf("--oat-file=%s", oat_path.c_str())); 28873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 28973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA, 29073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ART_BASE_ADDRESS_MAX_DELTA); 29173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd.push_back(StringPrintf("--base=0x%x", ART_BASE_ADDRESS + base_offset)); 29273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 29373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd.push_back(StringPrintf("--instruction-set=%s", isa)); 29473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 29573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // These things are pushed by AndroidRuntime, see frameworks/base/core/jni/AndroidRuntime.cpp. 29673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-Xms", 29773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe "-Xms", 29873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe true, 29973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd); 30073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-Xmx", 30173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe "-Xmx", 30273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe true, 30373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd); 30473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-filter", 30573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe "--compiler-filter=", 30673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe false, 30773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd); 30873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd.push_back(StringPrintf("--image-classes=%s/system/etc/preloaded-classes", 30973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe b_mount_path_.c_str())); 31073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // TODO: Compiled-classes. 31173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const std::string* extra_opts = 31273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe system_properties_.GetProperty("dalvik.vm.image-dex2oat-flags"); 31373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (extra_opts != nullptr) { 31473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::vector<std::string> extra_vals = Split(*extra_opts, ' '); 31573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd.insert(cmd.end(), extra_vals.begin(), extra_vals.end()); 31673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 31773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // TODO: Should we lower this? It's usually set close to max, because 31873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // normally there's not much else going on at boot. 31973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-threads", 32073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe "-j", 32173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe false, 32273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd); 32373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe AddCompilerOptionFromSystemProperty( 32473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe StringPrintf("dalvik.vm.isa.%s.variant", isa).c_str(), 32573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe "--instruction-set-variant=", 32673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe false, 32773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd); 32873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe AddCompilerOptionFromSystemProperty( 32973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe StringPrintf("dalvik.vm.isa.%s.features", isa).c_str(), 33073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe "--instruction-set-features=", 33173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe false, 33273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cmd); 33373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 33473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::string error_msg; 33573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe bool result = Exec(cmd, &error_msg); 33673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (!result) { 33773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe LOG(ERROR) << "Could not generate boot image: " << error_msg; 33873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 33973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return result; 34073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 34173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 34273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe static const char* ParseNull(const char* arg) { 34373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return (strcmp(arg, "!") == 0) ? nullptr : arg; 34473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 34573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 34673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe int RunPreopt() { 34773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe /* apk_path, uid, pkgname, instruction_set, dexopt_needed, oat_dir, dexopt_flags, 34873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe volume_uuid, use_profiles */ 34973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe int ret = dexopt(package_parameters_[0], 35073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe atoi(package_parameters_[1]), 35173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe package_parameters_[2], 35273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe package_parameters_[3], 35373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe atoi(package_parameters_[4]), 35473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe package_parameters_[5], 35573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe atoi(package_parameters_[6]), 35673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ParseNull(package_parameters_[7]), 35773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe (atoi(package_parameters_[8]) == 0 ? false : true)); 35873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return ret; 35973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 36073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 36173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe //////////////////////////////////// 36273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Helpers, mostly taken from ART // 36373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe //////////////////////////////////// 36473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 36573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Wrapper on fork/execv to run a command in a subprocess. 36673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) { 36773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const std::string command_line(Join(arg_vector, ' ')); 36873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 36973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe CHECK_GE(arg_vector.size(), 1U) << command_line; 37073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 37173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Convert the args to char pointers. 37273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char* program = arg_vector[0].c_str(); 37373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::vector<char*> args; 37473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe for (size_t i = 0; i < arg_vector.size(); ++i) { 37573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const std::string& arg = arg_vector[i]; 37673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe char* arg_str = const_cast<char*>(arg.c_str()); 37773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe CHECK(arg_str != nullptr) << i; 37873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe args.push_back(arg_str); 37973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 38073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe args.push_back(nullptr); 38173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 38273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Fork and exec. 38373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe pid_t pid = fork(); 38473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (pid == 0) { 38573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // No allocation allowed between fork and exec. 38673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 38773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Change process groups, so we don't get reaped by ProcessManager. 38873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe setpgid(0, 0); 38973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 39073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe execv(program, &args[0]); 39173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 39273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe PLOG(ERROR) << "Failed to execv(" << command_line << ")"; 39373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // _exit to avoid atexit handlers in child. 39473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe _exit(1); 39573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } else { 39673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (pid == -1) { 39773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s", 39873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe command_line.c_str(), strerror(errno)); 39973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 40073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 40173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 40273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // wait for subprocess to finish 40373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe int status; 40473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); 40573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (got_pid != pid) { 40673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: " 40773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe "wanted %d, got %d: %s", 40873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe command_line.c_str(), pid, got_pid, strerror(errno)); 40973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 41073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 41173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 41273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status", 41373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe command_line.c_str()); 41473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 41573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 41673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 41773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return true; 41873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 41973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 42073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc. 42173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) { 42273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe constexpr size_t kPageSize = PAGE_SIZE; 42373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe CHECK_EQ(min_delta % kPageSize, 0u); 42473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe CHECK_EQ(max_delta % kPageSize, 0u); 42573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe CHECK_LT(min_delta, max_delta); 42673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 42773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::default_random_engine generator; 42873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe generator.seed(GetSeed()); 42973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::uniform_int_distribution<int32_t> distribution(min_delta, max_delta); 43073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe int32_t r = distribution(generator); 43173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (r % 2 == 0) { 43273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe r = RoundUp(r, kPageSize); 43373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } else { 43473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe r = RoundDown(r, kPageSize); 43573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 43673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe CHECK_LE(min_delta, r); 43773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe CHECK_GE(max_delta, r); 43873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe CHECK_EQ(r % kPageSize, 0u); 43973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return r; 44073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 44173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 44273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe static uint64_t GetSeed() { 44373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#ifdef __BIONIC__ 44473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Bionic exposes arc4random, use it. 44573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe uint64_t random_data; 44673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe arc4random_buf(&random_data, sizeof(random_data)); 44773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return random_data; 44873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#else 44973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#error "This is only supposed to run with bionic. Otherwise, implement..." 45073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe#endif 45173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 45273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 45373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe void AddCompilerOptionFromSystemProperty(const char* system_property, 45473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char* prefix, 45573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe bool runtime, 45673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::vector<std::string>& out) { 45773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const std::string* value = 45873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe system_properties_.GetProperty(system_property); 45973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (value != nullptr) { 46073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (runtime) { 46173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe out.push_back("--runtime-arg"); 46273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 46373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (prefix != nullptr) { 46473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe out.push_back(StringPrintf("%s%s", prefix, value->c_str())); 46573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } else { 46673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe out.push_back(*value); 46773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 46873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 46973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 47073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 47173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // The path where the B partitions are mounted. 47273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // TODO(agampe): If we're running this *inside* the change-root, we wouldn't need this. 47373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::string b_mount_path_; 47473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 47573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Stores the system properties read out of the B partition. We need to use these properties 47673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // to compile, instead of the A properties we could get from init/get_property. 47773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe SystemProperties system_properties_; 47873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 47973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char* package_parameters_[9]; 48073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 48173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Store environment values we need to set. 48273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::vector<std::string> environ_; 48373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe}; 48473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 48573dae11162aa61396c06cbdb05b954764e944e02Andreas GampeOTAPreoptService gOps; 48673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 48773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe//////////////////////// 48873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe// Plug-in functions. // 48973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe//////////////////////// 49073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 49173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampeint get_property(const char *key, char *value, const char *default_value) { 49273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // TODO: Replace with system-properties map. 49373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return gOps.GetProperty(key, value, default_value); 49473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe} 49573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 49673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe// Compute the output path of 49773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampebool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, 49873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char *apk_path, 49973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char *instruction_set) { 50073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // TODO: Insert B directory. 50173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe char *file_name_start; 50273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe char *file_name_end; 50373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 50473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe file_name_start = strrchr(apk_path, '/'); 50573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (file_name_start == nullptr) { 50673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ALOGE("apk_path '%s' has no '/'s in it\n", apk_path); 50773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 50873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 50973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe file_name_end = strrchr(file_name_start, '.'); 51073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (file_name_end == nullptr) { 51173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ALOGE("apk_path '%s' has no extension\n", apk_path); 51273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 51373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 51473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 51573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // Calculate file_name 51673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe file_name_start++; // Move past '/', is valid as file_name_end is valid. 51773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe size_t file_name_len = file_name_end - file_name_start; 51873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::string file_name(file_name_start, file_name_len); 51973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 52073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // <apk_parent_dir>/oat/<isa>/<file_name>.odex.b 52173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe snprintf(path, PKG_PATH_MAX, "%s/%s/%s.odex.b", oat_dir, instruction_set, 52273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe file_name.c_str()); 52373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return true; 52473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe} 52573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 52673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe/* 52773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe * Computes the odex file for the given apk_path and instruction_set. 52873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe * /system/framework/whatever.jar -> /system/framework/oat/<isa>/whatever.odex 52973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe * 53073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe * Returns false if it failed to determine the odex file path. 53173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe */ 53273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampebool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path, 53373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char *instruction_set) { 53473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (StringPrintf("%soat/%s/odex.b", apk_path, instruction_set).length() + 1 > PKG_PATH_MAX) { 53573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ALOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path); 53673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 53773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 53873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 53973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char *path_end = strrchr(apk_path, '/'); 54073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (path_end == nullptr) { 54173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path); 54273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 54373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 54473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::string path_component(apk_path, path_end - apk_path); 54573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 54673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char *name_begin = path_end + 1; 54773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char *extension_start = strrchr(name_begin, '.'); 54873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (extension_start == nullptr) { 54973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ALOGE("apk_path '%s' has no extension.\n", apk_path); 55073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 55173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 55273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::string name_component(name_begin, extension_start - name_begin); 55373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 55473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::string new_path = StringPrintf("%s/oat/%s/%s.odex.b", 55573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe path_component.c_str(), 55673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe instruction_set, 55773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe name_component.c_str()); 55873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe CHECK_LT(new_path.length(), PKG_PATH_MAX); 55973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe strcpy(path, new_path.c_str()); 56073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return true; 56173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe} 56273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 56373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampebool create_cache_path(char path[PKG_PATH_MAX], 56473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char *src, 56573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char *instruction_set) { 56673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe size_t srclen = strlen(src); 56773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 56873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe /* demand that we are an absolute path */ 56973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if ((src == 0) || (src[0] != '/') || strstr(src,"..")) { 57073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 57173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 57273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 57373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX? 57473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 57573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 57673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 57773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::string from_src = std::string(src + 1); 57873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::replace(from_src.begin(), from_src.end(), '/', '@'); 57973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 58073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe std::string assembled_path = StringPrintf("%s/%s/%s/%s%s", 58173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe OTAPreoptService::kOTADataDirectory, 58273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe DALVIK_CACHE, 58373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe instruction_set, 58473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe from_src.c_str(), 58573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe DALVIK_CACHE_POSTFIX2); 58673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 58773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (assembled_path.length() + 1 > PKG_PATH_MAX) { 58873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 58973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 59073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe strcpy(path, assembled_path.c_str()); 59173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 59273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return true; 59373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe} 59473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 59573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampebool initialize_globals() { 59673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe const char* data_path = getenv("ANDROID_DATA"); 59773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (data_path == nullptr) { 59873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ALOGE("Could not find ANDROID_DATA"); 59973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 60073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 60173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return init_globals_from_data_and_root(data_path, kOTARootDirectory); 60273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe} 60373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 60473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampestatic bool initialize_directories() { 60573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // This is different from the normal installd. We only do the base 60673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe // directory, the rest will be created on demand when each app is compiled. 60773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe mode_t old_umask = umask(0); 60873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe LOG(INFO) << "Old umask: " << old_umask; 60973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (access(OTAPreoptService::kOTADataDirectory, R_OK) < 0) { 61073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ALOGE("Could not access %s\n", OTAPreoptService::kOTADataDirectory); 61173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return false; 61273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 61373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return true; 61473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe} 61573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 61673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampestatic int log_callback(int type, const char *fmt, ...) { 61773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe va_list ap; 61873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe int priority; 61973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 62073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe switch (type) { 62173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe case SELINUX_WARNING: 62273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe priority = ANDROID_LOG_WARN; 62373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe break; 62473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe case SELINUX_INFO: 62573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe priority = ANDROID_LOG_INFO; 62673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe break; 62773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe default: 62873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe priority = ANDROID_LOG_ERROR; 62973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe break; 63073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 63173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe va_start(ap, fmt); 63273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe LOG_PRI_VA(priority, "SELinux", fmt, ap); 63373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe va_end(ap); 63473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return 0; 63573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe} 63673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 63773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampestatic int otapreopt_main(const int argc, char *argv[]) { 63873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe int selinux_enabled = (is_selinux_enabled() > 0); 63973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 64073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe setenv("ANDROID_LOG_TAGS", "*:v", 1); 64173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe android::base::InitLogging(argv); 64273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 64373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ALOGI("otapreopt firing up\n"); 64473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 64573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (argc < 2) { 64673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ALOGE("Expecting parameters"); 64773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe exit(1); 64873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 64973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 65073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe union selinux_callback cb; 65173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe cb.func_log = log_callback; 65273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe selinux_set_callback(SELINUX_CB_LOG, cb); 65373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 65473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (!initialize_globals()) { 65573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ALOGE("Could not initialize globals; exiting.\n"); 65673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe exit(1); 65773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 65873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 65973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (!initialize_directories()) { 66073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ALOGE("Could not create directories; exiting.\n"); 66173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe exit(1); 66273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 66373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 66473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe if (selinux_enabled && selinux_status_open(true) < 0) { 66573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe ALOGE("Could not open selinux status; exiting.\n"); 66673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe exit(1); 66773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe } 66873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 66973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe int ret = android::installd::gOps.Main(argc, argv); 67073dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 67173dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return ret; 67273dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe} 67373dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 67473dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe} // namespace installd 67573dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe} // namespace android 67673dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe 67773dae11162aa61396c06cbdb05b954764e944e02Andreas Gampeint main(const int argc, char *argv[]) { 67873dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe return android::installd::otapreopt_main(argc, argv); 67973dae11162aa61396c06cbdb05b954764e944e02Andreas Gampe} 680