Home | History | Annotate | Download | only in installd
      1 /*
      2  ** Copyright 2016, The Android Open Source Project
      3  **
      4  ** Licensed under the Apache License, Version 2.0 (the "License");
      5  ** you may not use this file except in compliance with the License.
      6  ** You may obtain a copy of the License at
      7  **
      8  **     http://www.apache.org/licenses/LICENSE-2.0
      9  **
     10  ** Unless required by applicable law or agreed to in writing, software
     11  ** distributed under the License is distributed on an "AS IS" BASIS,
     12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  ** See the License for the specific language governing permissions and
     14  ** limitations under the License.
     15  */
     16 
     17 #include <algorithm>
     18 #include <inttypes.h>
     19 #include <limits>
     20 #include <random>
     21 #include <regex>
     22 #include <selinux/android.h>
     23 #include <selinux/avc.h>
     24 #include <stdlib.h>
     25 #include <string.h>
     26 #include <sys/capability.h>
     27 #include <sys/prctl.h>
     28 #include <sys/stat.h>
     29 
     30 #include <android-base/logging.h>
     31 #include <android-base/macros.h>
     32 #include <android-base/stringprintf.h>
     33 #include <android-base/strings.h>
     34 #include <art_image_values.h>
     35 #include <cutils/fs.h>
     36 #include <cutils/properties.h>
     37 #include <dex2oat_return_codes.h>
     38 #include <log/log.h>
     39 #include <private/android_filesystem_config.h>
     40 
     41 #include "dexopt.h"
     42 #include "file_parsing.h"
     43 #include "globals.h"
     44 #include "installd_constants.h"
     45 #include "installd_deps.h"  // Need to fill in requirements of commands.
     46 #include "otapreopt_parameters.h"
     47 #include "otapreopt_utils.h"
     48 #include "system_properties.h"
     49 #include "utils.h"
     50 
     51 #ifndef LOG_TAG
     52 #define LOG_TAG "otapreopt"
     53 #endif
     54 
     55 #define BUFFER_MAX    1024  /* input buffer for commands */
     56 #define TOKEN_MAX     16    /* max number of arguments in buffer */
     57 #define REPLY_MAX     256   /* largest reply allowed */
     58 
     59 using android::base::EndsWith;
     60 using android::base::Split;
     61 using android::base::StartsWith;
     62 using android::base::StringPrintf;
     63 
     64 namespace android {
     65 namespace installd {
     66 
     67 // Check expected values for dexopt flags. If you need to change this:
     68 //
     69 //   RUN AN A/B OTA TO MAKE SURE THINGS STILL WORK!
     70 //
     71 // You most likely need to increase the protocol version and all that entails!
     72 
     73 static_assert(DEXOPT_PUBLIC         == 1 << 1, "DEXOPT_PUBLIC unexpected.");
     74 static_assert(DEXOPT_DEBUGGABLE     == 1 << 2, "DEXOPT_DEBUGGABLE unexpected.");
     75 static_assert(DEXOPT_BOOTCOMPLETE   == 1 << 3, "DEXOPT_BOOTCOMPLETE unexpected.");
     76 static_assert(DEXOPT_PROFILE_GUIDED == 1 << 4, "DEXOPT_PROFILE_GUIDED unexpected.");
     77 static_assert(DEXOPT_SECONDARY_DEX  == 1 << 5, "DEXOPT_SECONDARY_DEX unexpected.");
     78 static_assert(DEXOPT_FORCE          == 1 << 6, "DEXOPT_FORCE unexpected.");
     79 static_assert(DEXOPT_STORAGE_CE     == 1 << 7, "DEXOPT_STORAGE_CE unexpected.");
     80 static_assert(DEXOPT_STORAGE_DE     == 1 << 8, "DEXOPT_STORAGE_DE unexpected.");
     81 static_assert(DEXOPT_ENABLE_HIDDEN_API_CHECKS == 1 << 10,
     82         "DEXOPT_ENABLE_HIDDEN_API_CHECKS unexpected");
     83 static_assert(DEXOPT_GENERATE_COMPACT_DEX == 1 << 11, "DEXOPT_GENERATE_COMPACT_DEX unexpected");
     84 static_assert(DEXOPT_GENERATE_APP_IMAGE == 1 << 12, "DEXOPT_GENERATE_APP_IMAGE unexpected");
     85 
     86 static_assert(DEXOPT_MASK           == (0x1dfe | DEXOPT_IDLE_BACKGROUND_JOB),
     87               "DEXOPT_MASK unexpected.");
     88 
     89 
     90 template<typename T>
     91 static constexpr bool IsPowerOfTwo(T x) {
     92   static_assert(std::is_integral<T>::value, "T must be integral");
     93   // TODO: assert unsigned. There is currently many uses with signed values.
     94   return (x & (x - 1)) == 0;
     95 }
     96 
     97 template<typename T>
     98 static constexpr T RoundDown(T x, typename std::decay<T>::type n) {
     99     return DCHECK_CONSTEXPR(IsPowerOfTwo(n), , T(0))(x & -n);
    100 }
    101 
    102 template<typename T>
    103 static constexpr T RoundUp(T x, typename std::remove_reference<T>::type n) {
    104     return RoundDown(x + n - 1, n);
    105 }
    106 
    107 class OTAPreoptService {
    108  public:
    109     // Main driver. Performs the following steps.
    110     //
    111     // 1) Parse options (read system properties etc from B partition).
    112     //
    113     // 2) Read in package data.
    114     //
    115     // 3) Prepare environment variables.
    116     //
    117     // 4) Prepare(compile) boot image, if necessary.
    118     //
    119     // 5) Run update.
    120     int Main(int argc, char** argv) {
    121         if (!ReadArguments(argc, argv)) {
    122             LOG(ERROR) << "Failed reading command line.";
    123             return 1;
    124         }
    125 
    126         if (!ReadSystemProperties()) {
    127             LOG(ERROR)<< "Failed reading system properties.";
    128             return 2;
    129         }
    130 
    131         if (!ReadEnvironment()) {
    132             LOG(ERROR) << "Failed reading environment properties.";
    133             return 3;
    134         }
    135 
    136         if (!CheckAndInitializeInstalldGlobals()) {
    137             LOG(ERROR) << "Failed initializing globals.";
    138             return 4;
    139         }
    140 
    141         PrepareEnvironment();
    142 
    143         if (!PrepareBootImage(/* force */ false)) {
    144             LOG(ERROR) << "Failed preparing boot image.";
    145             return 5;
    146         }
    147 
    148         int dexopt_retcode = RunPreopt();
    149 
    150         return dexopt_retcode;
    151     }
    152 
    153     int GetProperty(const char* key, char* value, const char* default_value) const {
    154         const std::string* prop_value = system_properties_.GetProperty(key);
    155         if (prop_value == nullptr) {
    156             if (default_value == nullptr) {
    157                 return 0;
    158             }
    159             // Copy in the default value.
    160             strlcpy(value, default_value, kPropertyValueMax - 1);
    161             value[kPropertyValueMax - 1] = 0;
    162             return strlen(default_value);// TODO: Need to truncate?
    163         }
    164         size_t size = std::min(kPropertyValueMax - 1, prop_value->length()) + 1;
    165         strlcpy(value, prop_value->data(), size);
    166         return static_cast<int>(size - 1);
    167     }
    168 
    169     std::string GetOTADataDirectory() const {
    170         return StringPrintf("%s/%s", GetOtaDirectoryPrefix().c_str(), GetTargetSlot().c_str());
    171     }
    172 
    173     const std::string& GetTargetSlot() const {
    174         return parameters_.target_slot;
    175     }
    176 
    177 private:
    178 
    179     bool ReadSystemProperties() {
    180         static constexpr const char* kPropertyFiles[] = {
    181                 "/default.prop", "/system/build.prop"
    182         };
    183 
    184         for (size_t i = 0; i < arraysize(kPropertyFiles); ++i) {
    185             if (!system_properties_.Load(kPropertyFiles[i])) {
    186                 return false;
    187             }
    188         }
    189 
    190         return true;
    191     }
    192 
    193     bool ReadEnvironment() {
    194         // Parse the environment variables from init.environ.rc, which have the form
    195         //   export NAME VALUE
    196         // For simplicity, don't respect string quotation. The values we are interested in can be
    197         // encoded without them.
    198         std::regex export_regex("\\s*export\\s+(\\S+)\\s+(\\S+)");
    199         bool parse_result = ParseFile("/init.environ.rc", [&](const std::string& line) {
    200             std::smatch export_match;
    201             if (!std::regex_match(line, export_match, export_regex)) {
    202                 return true;
    203             }
    204 
    205             if (export_match.size() != 3) {
    206                 return true;
    207             }
    208 
    209             std::string name = export_match[1].str();
    210             std::string value = export_match[2].str();
    211 
    212             system_properties_.SetProperty(name, value);
    213 
    214             return true;
    215         });
    216         if (!parse_result) {
    217             return false;
    218         }
    219 
    220         if (system_properties_.GetProperty(kAndroidDataPathPropertyName) == nullptr) {
    221             return false;
    222         }
    223         android_data_ = *system_properties_.GetProperty(kAndroidDataPathPropertyName);
    224 
    225         if (system_properties_.GetProperty(kAndroidRootPathPropertyName) == nullptr) {
    226             return false;
    227         }
    228         android_root_ = *system_properties_.GetProperty(kAndroidRootPathPropertyName);
    229 
    230         if (system_properties_.GetProperty(kBootClassPathPropertyName) == nullptr) {
    231             return false;
    232         }
    233         boot_classpath_ = *system_properties_.GetProperty(kBootClassPathPropertyName);
    234 
    235         if (system_properties_.GetProperty(ASEC_MOUNTPOINT_ENV_NAME) == nullptr) {
    236             return false;
    237         }
    238         asec_mountpoint_ = *system_properties_.GetProperty(ASEC_MOUNTPOINT_ENV_NAME);
    239 
    240         return true;
    241     }
    242 
    243     const std::string& GetAndroidData() const {
    244         return android_data_;
    245     }
    246 
    247     const std::string& GetAndroidRoot() const {
    248         return android_root_;
    249     }
    250 
    251     const std::string GetOtaDirectoryPrefix() const {
    252         return GetAndroidData() + "/ota";
    253     }
    254 
    255     bool CheckAndInitializeInstalldGlobals() {
    256         // init_globals_from_data_and_root requires "ASEC_MOUNTPOINT" in the environment. We
    257         // do not use any datapath that includes this, but we'll still have to set it.
    258         CHECK(system_properties_.GetProperty(ASEC_MOUNTPOINT_ENV_NAME) != nullptr);
    259         int result = setenv(ASEC_MOUNTPOINT_ENV_NAME, asec_mountpoint_.c_str(), 0);
    260         if (result != 0) {
    261             LOG(ERROR) << "Could not set ASEC_MOUNTPOINT environment variable";
    262             return false;
    263         }
    264 
    265         if (!init_globals_from_data_and_root(GetAndroidData().c_str(), GetAndroidRoot().c_str())) {
    266             LOG(ERROR) << "Could not initialize globals; exiting.";
    267             return false;
    268         }
    269 
    270         // This is different from the normal installd. We only do the base
    271         // directory, the rest will be created on demand when each app is compiled.
    272         if (access(GetOtaDirectoryPrefix().c_str(), R_OK) < 0) {
    273             LOG(ERROR) << "Could not access " << GetOtaDirectoryPrefix();
    274             return false;
    275         }
    276 
    277         return true;
    278     }
    279 
    280     bool ParseBool(const char* in) {
    281         if (strcmp(in, "true") == 0) {
    282             return true;
    283         }
    284         return false;
    285     }
    286 
    287     bool ParseUInt(const char* in, uint32_t* out) {
    288         char* end;
    289         long long int result = strtoll(in, &end, 0);
    290         if (in == end || *end != '\0') {
    291             return false;
    292         }
    293         if (result < std::numeric_limits<uint32_t>::min() ||
    294                 std::numeric_limits<uint32_t>::max() < result) {
    295             return false;
    296         }
    297         *out = static_cast<uint32_t>(result);
    298         return true;
    299     }
    300 
    301     bool ReadArguments(int argc, char** argv) {
    302         return parameters_.ReadArguments(argc, const_cast<const char**>(argv));
    303     }
    304 
    305     void PrepareEnvironment() {
    306         environ_.push_back(StringPrintf("BOOTCLASSPATH=%s", boot_classpath_.c_str()));
    307         environ_.push_back(StringPrintf("ANDROID_DATA=%s", GetOTADataDirectory().c_str()));
    308         environ_.push_back(StringPrintf("ANDROID_ROOT=%s", android_root_.c_str()));
    309 
    310         for (const std::string& e : environ_) {
    311             putenv(const_cast<char*>(e.c_str()));
    312         }
    313     }
    314 
    315     // Ensure that we have the right boot image. The first time any app is
    316     // compiled, we'll try to generate it.
    317     bool PrepareBootImage(bool force) const {
    318         if (parameters_.instruction_set == nullptr) {
    319             LOG(ERROR) << "Instruction set missing.";
    320             return false;
    321         }
    322         const char* isa = parameters_.instruction_set;
    323         std::string dalvik_cache = GetOTADataDirectory() + "/" + DALVIK_CACHE;
    324         std::string isa_path = dalvik_cache + "/" + isa;
    325 
    326         // Reset umask in otapreopt, so that we control the the access for the files we create.
    327         umask(0);
    328 
    329         // Create the directories, if necessary.
    330         if (access(dalvik_cache.c_str(), F_OK) != 0) {
    331             if (!CreatePath(dalvik_cache)) {
    332                 PLOG(ERROR) << "Could not create dalvik-cache dir " << dalvik_cache;
    333                 return false;
    334             }
    335         }
    336         if (access(isa_path.c_str(), F_OK) != 0) {
    337             if (!CreatePath(isa_path)) {
    338                 PLOG(ERROR) << "Could not create dalvik-cache isa dir";
    339                 return false;
    340             }
    341         }
    342 
    343         // Check whether we have files in /data.
    344         // TODO: check that the files are correct wrt/ jars.
    345         std::string art_path = isa_path + "/system@framework (at) boot.art";
    346         std::string oat_path = isa_path + "/system@framework (at) boot.oat";
    347         bool cleared = false;
    348         if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) {
    349             // Files exist, assume everything is alright if not forced. Otherwise clean up.
    350             if (!force) {
    351                 return true;
    352             }
    353             ClearDirectory(isa_path);
    354             cleared = true;
    355         }
    356 
    357         // Check whether we have an image in /system.
    358         // TODO: check that the files are correct wrt/ jars.
    359         std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
    360         if (access(preopted_boot_art_path.c_str(), F_OK) == 0) {
    361             // Note: we ignore |force| here.
    362             return true;
    363         }
    364 
    365 
    366         if (!cleared) {
    367             ClearDirectory(isa_path);
    368         }
    369 
    370         return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
    371     }
    372 
    373     static bool CreatePath(const std::string& path) {
    374         // Create the given path. Use string processing instead of dirname, as dirname's need for
    375         // a writable char buffer is painful.
    376 
    377         // First, try to use the full path.
    378         if (mkdir(path.c_str(), 0711) == 0) {
    379             return true;
    380         }
    381         if (errno != ENOENT) {
    382             PLOG(ERROR) << "Could not create path " << path;
    383             return false;
    384         }
    385 
    386         // Now find the parent and try that first.
    387         size_t last_slash = path.find_last_of('/');
    388         if (last_slash == std::string::npos || last_slash == 0) {
    389             PLOG(ERROR) << "Could not create " << path;
    390             return false;
    391         }
    392 
    393         if (!CreatePath(path.substr(0, last_slash))) {
    394             return false;
    395         }
    396 
    397         if (mkdir(path.c_str(), 0711) == 0) {
    398             return true;
    399         }
    400         PLOG(ERROR) << "Could not create " << path;
    401         return false;
    402     }
    403 
    404     static void ClearDirectory(const std::string& dir) {
    405         DIR* c_dir = opendir(dir.c_str());
    406         if (c_dir == nullptr) {
    407             PLOG(WARNING) << "Unable to open " << dir << " to delete it's contents";
    408             return;
    409         }
    410 
    411         for (struct dirent* de = readdir(c_dir); de != nullptr; de = readdir(c_dir)) {
    412             const char* name = de->d_name;
    413             if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
    414                 continue;
    415             }
    416             // We only want to delete regular files and symbolic links.
    417             std::string file = StringPrintf("%s/%s", dir.c_str(), name);
    418             if (de->d_type != DT_REG && de->d_type != DT_LNK) {
    419                 LOG(WARNING) << "Unexpected file "
    420                              << file
    421                              << " of type "
    422                              << std::hex
    423                              << de->d_type
    424                              << " encountered.";
    425             } else {
    426                 // Try to unlink the file.
    427                 if (unlink(file.c_str()) != 0) {
    428                     PLOG(ERROR) << "Unable to unlink " << file;
    429                 }
    430             }
    431         }
    432         CHECK_EQ(0, closedir(c_dir)) << "Unable to close directory.";
    433     }
    434 
    435     bool Dex2oatBootImage(const std::string& boot_cp,
    436                           const std::string& art_path,
    437                           const std::string& oat_path,
    438                           const char* isa) const {
    439         // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
    440         std::vector<std::string> cmd;
    441         cmd.push_back(kDex2oatPath);
    442         cmd.push_back(StringPrintf("--image=%s", art_path.c_str()));
    443         for (const std::string& boot_part : Split(boot_cp, ":")) {
    444             cmd.push_back(StringPrintf("--dex-file=%s", boot_part.c_str()));
    445         }
    446         cmd.push_back(StringPrintf("--oat-file=%s", oat_path.c_str()));
    447 
    448         int32_t base_offset = ChooseRelocationOffsetDelta(art::GetImageMinBaseAddressDelta(),
    449                                                           art::GetImageMaxBaseAddressDelta());
    450         cmd.push_back(StringPrintf("--base=0x%x", art::GetImageBaseAddress() + base_offset));
    451 
    452         cmd.push_back(StringPrintf("--instruction-set=%s", isa));
    453 
    454         // These things are pushed by AndroidRuntime, see frameworks/base/core/jni/AndroidRuntime.cpp.
    455         AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-Xms",
    456                 "-Xms",
    457                 true,
    458                 cmd);
    459         AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-Xmx",
    460                 "-Xmx",
    461                 true,
    462                 cmd);
    463         AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-filter",
    464                 "--compiler-filter=",
    465                 false,
    466                 cmd);
    467         cmd.push_back("--image-classes=/system/etc/preloaded-classes");
    468         // TODO: Compiled-classes.
    469         const std::string* extra_opts =
    470                 system_properties_.GetProperty("dalvik.vm.image-dex2oat-flags");
    471         if (extra_opts != nullptr) {
    472             std::vector<std::string> extra_vals = Split(*extra_opts, " ");
    473             cmd.insert(cmd.end(), extra_vals.begin(), extra_vals.end());
    474         }
    475         // TODO: Should we lower this? It's usually set close to max, because
    476         //       normally there's not much else going on at boot.
    477         AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-threads",
    478                 "-j",
    479                 false,
    480                 cmd);
    481         AddCompilerOptionFromSystemProperty(
    482                 StringPrintf("dalvik.vm.isa.%s.variant", isa).c_str(),
    483                 "--instruction-set-variant=",
    484                 false,
    485                 cmd);
    486         AddCompilerOptionFromSystemProperty(
    487                 StringPrintf("dalvik.vm.isa.%s.features", isa).c_str(),
    488                 "--instruction-set-features=",
    489                 false,
    490                 cmd);
    491 
    492         std::string error_msg;
    493         bool result = Exec(cmd, &error_msg);
    494         if (!result) {
    495             LOG(ERROR) << "Could not generate boot image: " << error_msg;
    496         }
    497         return result;
    498     }
    499 
    500     static const char* ParseNull(const char* arg) {
    501         return (strcmp(arg, "!") == 0) ? nullptr : arg;
    502     }
    503 
    504     bool ShouldSkipPreopt() const {
    505         // There's one thing we have to be careful about: we may/will be asked to compile an app
    506         // living in the system image. This may be a valid request - if the app wasn't compiled,
    507         // e.g., if the system image wasn't large enough to include preopted files. However, the
    508         // data we have is from the old system, so the driver (the OTA service) can't actually
    509         // know. Thus, we will get requests for apps that have preopted components. To avoid
    510         // duplication (we'd generate files that are not used and are *not* cleaned up), do two
    511         // simple checks:
    512         //
    513         // 1) Does the apk_path start with the value of ANDROID_ROOT? (~in the system image)
    514         //    (For simplicity, assume the value of ANDROID_ROOT does not contain a symlink.)
    515         //
    516         // 2) If you replace the name in the apk_path with "oat," does the path exist?
    517         //    (=have a subdirectory for preopted files)
    518         //
    519         // If the answer to both is yes, skip the dexopt.
    520         //
    521         // Note: while one may think it's OK to call dexopt and it will fail (because APKs should
    522         //       be stripped), that's not true for APKs signed outside the build system (so the
    523         //       jar content must be exactly the same).
    524 
    525         //       (This is ugly as it's the only thing where we need to understand the contents
    526         //        of parameters_, but it beats postponing the decision or using the call-
    527         //        backs to do weird things.)
    528         const char* apk_path = parameters_.apk_path;
    529         CHECK(apk_path != nullptr);
    530         if (StartsWith(apk_path, android_root_)) {
    531             const char* last_slash = strrchr(apk_path, '/');
    532             if (last_slash != nullptr) {
    533                 std::string path(apk_path, last_slash - apk_path + 1);
    534                 CHECK(EndsWith(path, "/"));
    535                 path = path + "oat";
    536                 if (access(path.c_str(), F_OK) == 0) {
    537                     LOG(INFO) << "Skipping A/B OTA preopt of already preopted package " << apk_path;
    538                     return true;
    539                 }
    540             }
    541         }
    542 
    543         // Another issue is unavailability of files in the new system. If the partition
    544         // layout changes, otapreopt_chroot may not know about this. Then files from that
    545         // partition will not be available and fail to build. This is problematic, as
    546         // this tool will wipe the OTA artifact cache and try again (for robustness after
    547         // a failed OTA with remaining cache artifacts).
    548         if (access(apk_path, F_OK) != 0) {
    549             LOG(WARNING) << "Skipping A/B OTA preopt of non-existing package " << apk_path;
    550             return true;
    551         }
    552 
    553         return false;
    554     }
    555 
    556     // Run dexopt with the parameters of parameters_.
    557     // TODO(calin): embed the profile name in the parameters.
    558     int Dexopt() {
    559         std::string dummy;
    560         return dexopt(parameters_.apk_path,
    561                       parameters_.uid,
    562                       parameters_.pkgName,
    563                       parameters_.instruction_set,
    564                       parameters_.dexopt_needed,
    565                       parameters_.oat_dir,
    566                       parameters_.dexopt_flags,
    567                       parameters_.compiler_filter,
    568                       parameters_.volume_uuid,
    569                       parameters_.shared_libraries,
    570                       parameters_.se_info,
    571                       parameters_.downgrade,
    572                       parameters_.target_sdk_version,
    573                       parameters_.profile_name,
    574                       parameters_.dex_metadata_path,
    575                       parameters_.compilation_reason,
    576                       &dummy);
    577     }
    578 
    579     int RunPreopt() {
    580         if (ShouldSkipPreopt()) {
    581             return 0;
    582         }
    583 
    584         int dexopt_result = Dexopt();
    585         if (dexopt_result == 0) {
    586             return 0;
    587         }
    588 
    589         // If the dexopt failed, we may have a stale boot image from a previous OTA run.
    590         // Then regenerate and retry.
    591         if (WEXITSTATUS(dexopt_result) ==
    592                 static_cast<int>(::art::dex2oat::ReturnCode::kCreateRuntime)) {
    593             if (!PrepareBootImage(/* force */ true)) {
    594                 LOG(ERROR) << "Forced boot image creating failed. Original error return was "
    595                         << dexopt_result;
    596                 return dexopt_result;
    597             }
    598 
    599             int dexopt_result_boot_image_retry = Dexopt();
    600             if (dexopt_result_boot_image_retry == 0) {
    601                 return 0;
    602             }
    603         }
    604 
    605         // If this was a profile-guided run, we may have profile version issues. Try to downgrade,
    606         // if possible.
    607         if ((parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) {
    608             return dexopt_result;
    609         }
    610 
    611         LOG(WARNING) << "Downgrading compiler filter in an attempt to progress compilation";
    612         parameters_.dexopt_flags &= ~DEXOPT_PROFILE_GUIDED;
    613         return Dexopt();
    614     }
    615 
    616     ////////////////////////////////////
    617     // Helpers, mostly taken from ART //
    618     ////////////////////////////////////
    619 
    620     // Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc.
    621     static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
    622         constexpr size_t kPageSize = PAGE_SIZE;
    623         CHECK_EQ(min_delta % kPageSize, 0u);
    624         CHECK_EQ(max_delta % kPageSize, 0u);
    625         CHECK_LT(min_delta, max_delta);
    626 
    627         std::default_random_engine generator;
    628         generator.seed(GetSeed());
    629         std::uniform_int_distribution<int32_t> distribution(min_delta, max_delta);
    630         int32_t r = distribution(generator);
    631         if (r % 2 == 0) {
    632             r = RoundUp(r, kPageSize);
    633         } else {
    634             r = RoundDown(r, kPageSize);
    635         }
    636         CHECK_LE(min_delta, r);
    637         CHECK_GE(max_delta, r);
    638         CHECK_EQ(r % kPageSize, 0u);
    639         return r;
    640     }
    641 
    642     static uint64_t GetSeed() {
    643 #ifdef __BIONIC__
    644         // Bionic exposes arc4random, use it.
    645         uint64_t random_data;
    646         arc4random_buf(&random_data, sizeof(random_data));
    647         return random_data;
    648 #else
    649 #error "This is only supposed to run with bionic. Otherwise, implement..."
    650 #endif
    651     }
    652 
    653     void AddCompilerOptionFromSystemProperty(const char* system_property,
    654             const char* prefix,
    655             bool runtime,
    656             std::vector<std::string>& out) const {
    657         const std::string* value = system_properties_.GetProperty(system_property);
    658         if (value != nullptr) {
    659             if (runtime) {
    660                 out.push_back("--runtime-arg");
    661             }
    662             if (prefix != nullptr) {
    663                 out.push_back(StringPrintf("%s%s", prefix, value->c_str()));
    664             } else {
    665                 out.push_back(*value);
    666             }
    667         }
    668     }
    669 
    670     static constexpr const char* kBootClassPathPropertyName = "BOOTCLASSPATH";
    671     static constexpr const char* kAndroidRootPathPropertyName = "ANDROID_ROOT";
    672     static constexpr const char* kAndroidDataPathPropertyName = "ANDROID_DATA";
    673     // The index of the instruction-set string inside the package parameters. Needed for
    674     // some special-casing that requires knowledge of the instruction-set.
    675     static constexpr size_t kISAIndex = 3;
    676 
    677     // Stores the system properties read out of the B partition. We need to use these properties
    678     // to compile, instead of the A properties we could get from init/get_property.
    679     SystemProperties system_properties_;
    680 
    681     // Some select properties that are always needed.
    682     std::string android_root_;
    683     std::string android_data_;
    684     std::string boot_classpath_;
    685     std::string asec_mountpoint_;
    686 
    687     OTAPreoptParameters parameters_;
    688 
    689     // Store environment values we need to set.
    690     std::vector<std::string> environ_;
    691 };
    692 
    693 OTAPreoptService gOps;
    694 
    695 ////////////////////////
    696 // Plug-in functions. //
    697 ////////////////////////
    698 
    699 int get_property(const char *key, char *value, const char *default_value) {
    700     return gOps.GetProperty(key, value, default_value);
    701 }
    702 
    703 // Compute the output path of
    704 bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir,
    705                              const char *apk_path,
    706                              const char *instruction_set) {
    707     const char *file_name_start;
    708     const char *file_name_end;
    709 
    710     file_name_start = strrchr(apk_path, '/');
    711     if (file_name_start == nullptr) {
    712         ALOGE("apk_path '%s' has no '/'s in it\n", apk_path);
    713         return false;
    714     }
    715     file_name_end = strrchr(file_name_start, '.');
    716     if (file_name_end == nullptr) {
    717         ALOGE("apk_path '%s' has no extension\n", apk_path);
    718         return false;
    719     }
    720 
    721     // Calculate file_name
    722     file_name_start++;  // Move past '/', is valid as file_name_end is valid.
    723     size_t file_name_len = file_name_end - file_name_start;
    724     std::string file_name(file_name_start, file_name_len);
    725 
    726     // <apk_parent_dir>/oat/<isa>/<file_name>.odex.b
    727     snprintf(path,
    728              PKG_PATH_MAX,
    729              "%s/%s/%s.odex.%s",
    730              oat_dir,
    731              instruction_set,
    732              file_name.c_str(),
    733              gOps.GetTargetSlot().c_str());
    734     return true;
    735 }
    736 
    737 /*
    738  * Computes the odex file for the given apk_path and instruction_set.
    739  * /system/framework/whatever.jar -> /system/framework/oat/<isa>/whatever.odex
    740  *
    741  * Returns false if it failed to determine the odex file path.
    742  */
    743 bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
    744                               const char *instruction_set) {
    745     const char *path_end = strrchr(apk_path, '/');
    746     if (path_end == nullptr) {
    747         ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
    748         return false;
    749     }
    750     std::string path_component(apk_path, path_end - apk_path);
    751 
    752     const char *name_begin = path_end + 1;
    753     const char *extension_start = strrchr(name_begin, '.');
    754     if (extension_start == nullptr) {
    755         ALOGE("apk_path '%s' has no extension.\n", apk_path);
    756         return false;
    757     }
    758     std::string name_component(name_begin, extension_start - name_begin);
    759 
    760     std::string new_path = StringPrintf("%s/oat/%s/%s.odex.%s",
    761                                         path_component.c_str(),
    762                                         instruction_set,
    763                                         name_component.c_str(),
    764                                         gOps.GetTargetSlot().c_str());
    765     if (new_path.length() >= PKG_PATH_MAX) {
    766         LOG(ERROR) << "apk_path of " << apk_path << " is too long: " << new_path;
    767         return false;
    768     }
    769     strcpy(path, new_path.c_str());
    770     return true;
    771 }
    772 
    773 bool create_cache_path(char path[PKG_PATH_MAX],
    774                        const char *src,
    775                        const char *instruction_set) {
    776     size_t srclen = strlen(src);
    777 
    778         /* demand that we are an absolute path */
    779     if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
    780         return false;
    781     }
    782 
    783     if (srclen > PKG_PATH_MAX) {        // XXX: PKG_NAME_MAX?
    784         return false;
    785     }
    786 
    787     std::string from_src = std::string(src + 1);
    788     std::replace(from_src.begin(), from_src.end(), '/', '@');
    789 
    790     std::string assembled_path = StringPrintf("%s/%s/%s/%s%s",
    791                                               gOps.GetOTADataDirectory().c_str(),
    792                                               DALVIK_CACHE,
    793                                               instruction_set,
    794                                               from_src.c_str(),
    795                                               DALVIK_CACHE_POSTFIX);
    796 
    797     if (assembled_path.length() + 1 > PKG_PATH_MAX) {
    798         return false;
    799     }
    800     strcpy(path, assembled_path.c_str());
    801 
    802     return true;
    803 }
    804 
    805 static int log_callback(int type, const char *fmt, ...) {
    806     va_list ap;
    807     int priority;
    808 
    809     switch (type) {
    810         case SELINUX_WARNING:
    811             priority = ANDROID_LOG_WARN;
    812             break;
    813         case SELINUX_INFO:
    814             priority = ANDROID_LOG_INFO;
    815             break;
    816         default:
    817             priority = ANDROID_LOG_ERROR;
    818             break;
    819     }
    820     va_start(ap, fmt);
    821     LOG_PRI_VA(priority, "SELinux", fmt, ap);
    822     va_end(ap);
    823     return 0;
    824 }
    825 
    826 static int otapreopt_main(const int argc, char *argv[]) {
    827     int selinux_enabled = (is_selinux_enabled() > 0);
    828 
    829     setenv("ANDROID_LOG_TAGS", "*:v", 1);
    830     android::base::InitLogging(argv);
    831 
    832     if (argc < 2) {
    833         ALOGE("Expecting parameters");
    834         exit(1);
    835     }
    836 
    837     union selinux_callback cb;
    838     cb.func_log = log_callback;
    839     selinux_set_callback(SELINUX_CB_LOG, cb);
    840 
    841     if (selinux_enabled && selinux_status_open(true) < 0) {
    842         ALOGE("Could not open selinux status; exiting.\n");
    843         exit(1);
    844     }
    845 
    846     int ret = android::installd::gOps.Main(argc, argv);
    847 
    848     return ret;
    849 }
    850 
    851 }  // namespace installd
    852 }  // namespace android
    853 
    854 int main(const int argc, char *argv[]) {
    855     return android::installd::otapreopt_main(argc, argv);
    856 }
    857