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 "otapreopt_parameters.h"
     18 
     19 #include <cstring>
     20 
     21 #include <android-base/logging.h>
     22 
     23 #include "dexopt.h"
     24 #include "installd_constants.h"
     25 #include "otapreopt_utils.h"
     26 
     27 #ifndef LOG_TAG
     28 #define LOG_TAG "otapreopt"
     29 #endif
     30 
     31 namespace android {
     32 namespace installd {
     33 
     34 static bool ParseBool(const char* in) {
     35     if (strcmp(in, "true") == 0) {
     36         return true;
     37     }
     38     return false;
     39 }
     40 
     41 static const char* ParseNull(const char* arg) {
     42     return (strcmp(arg, "!") == 0) ? nullptr : arg;
     43 }
     44 
     45 static bool ParseUInt(const char* in, uint32_t* out) {
     46     char* end;
     47     long long int result = strtoll(in, &end, 0);
     48     if (in == end || *end != '\0') {
     49         return false;
     50     }
     51     if (result < std::numeric_limits<uint32_t>::min() ||
     52             std::numeric_limits<uint32_t>::max() < result) {
     53         return false;
     54     }
     55     *out = static_cast<uint32_t>(result);
     56     return true;
     57 }
     58 
     59 bool OTAPreoptParameters::ReadArguments(int argc, const char** argv) {
     60     // Expected command line:
     61     //   target-slot [version] dexopt {DEXOPT_PARAMETERS}
     62 
     63     const char* target_slot_arg = argv[1];
     64     if (target_slot_arg == nullptr) {
     65         LOG(ERROR) << "Missing parameters";
     66         return false;
     67     }
     68     // Sanitize value. Only allow (a-zA-Z0-9_)+.
     69     target_slot = target_slot_arg;
     70     if (!ValidateTargetSlotSuffix(target_slot)) {
     71         LOG(ERROR) << "Target slot suffix not legal: " << target_slot;
     72         return false;
     73     }
     74 
     75     // Check for version or "dexopt" next.
     76     if (argv[2] == nullptr) {
     77         LOG(ERROR) << "Missing parameters";
     78         return false;
     79     }
     80 
     81     if (std::string("dexopt").compare(argv[2]) == 0) {
     82         // This is version 1 (N) or pre-versioning version 2.
     83         constexpr int kV2ArgCount =   1   // "otapreopt"
     84                                     + 1   // slot
     85                                     + 1   // "dexopt"
     86                                     + 1   // apk_path
     87                                     + 1   // uid
     88                                     + 1   // pkg
     89                                     + 1   // isa
     90                                     + 1   // dexopt_needed
     91                                     + 1   // oat_dir
     92                                     + 1   // dexopt_flags
     93                                     + 1   // filter
     94                                     + 1   // volume
     95                                     + 1   // libs
     96                                     + 1;  // seinfo
     97         if (argc == kV2ArgCount) {
     98             return ReadArgumentsPostV1(2, argv, false);
     99         } else {
    100             return ReadArgumentsV1(argv);
    101         }
    102     }
    103 
    104     uint32_t version;
    105     if (!ParseUInt(argv[2], &version)) {
    106         LOG(ERROR) << "Could not parse version: " << argv[2];
    107         return false;
    108     }
    109 
    110     return ReadArgumentsPostV1(version, argv, true);
    111 }
    112 
    113 static int ReplaceMask(int input, int old_mask, int new_mask) {
    114     return (input & old_mask) != 0 ? new_mask : 0;
    115 }
    116 
    117 void OTAPreoptParameters::SetDefaultsForPostV1Arguments() {
    118     // Set se_info to null. It is only relevant for secondary dex files, which we won't
    119     // receive from a v1 A side.
    120     se_info = nullptr;
    121 
    122     // Set downgrade to false. It is only relevant when downgrading compiler
    123     // filter, which is not the case during ota.
    124     downgrade = false;
    125 
    126     // Set target_sdk_version to 0, ie the platform SDK version. This is
    127     // conservative and may force some classes to verify at runtime.
    128     target_sdk_version = 0;
    129 
    130     // Set the profile name to the primary apk profile.
    131     profile_name = "primary.prof";
    132 
    133     // By default we don't have a dex metadata file.
    134     dex_metadata_path = nullptr;
    135 
    136     // The compilation reason is ab-ota (match the system property pm.dexopt.ab-ota)
    137     compilation_reason = "ab-ota";
    138 
    139     // Flag is enabled by default for A/B otas.
    140     dexopt_flags = DEXOPT_GENERATE_COMPACT_DEX;
    141 }
    142 
    143 bool OTAPreoptParameters::ReadArgumentsV1(const char** argv) {
    144     // Check for "dexopt".
    145     if (argv[2] == nullptr) {
    146         LOG(ERROR) << "Missing parameters";
    147         return false;
    148     }
    149     if (std::string("dexopt").compare(argv[2]) != 0) {
    150         LOG(ERROR) << "Expected \"dexopt\" but found: " << argv[2];
    151         return false;
    152     }
    153 
    154     SetDefaultsForPostV1Arguments();
    155 
    156     size_t param_index = 0;
    157     for (;; ++param_index) {
    158         const char* param = argv[3 + param_index];
    159         if (param == nullptr) {
    160             break;
    161         }
    162 
    163         switch (param_index) {
    164             case 0:
    165                 apk_path = param;
    166                 break;
    167 
    168             case 1:
    169                 uid = atoi(param);
    170                 break;
    171 
    172             case 2:
    173                 pkgName = param;
    174                 break;
    175 
    176             case 3:
    177                 instruction_set = param;
    178                 break;
    179 
    180             case 4: {
    181                 // Version 1 had:
    182                 //   DEXOPT_DEX2OAT_NEEDED       = 1
    183                 //   DEXOPT_PATCHOAT_NEEDED      = 2
    184                 //   DEXOPT_SELF_PATCHOAT_NEEDED = 3
    185                 // We will simply use DEX2OAT_FROM_SCRATCH.
    186                 dexopt_needed = DEX2OAT_FROM_SCRATCH;
    187                 break;
    188             }
    189 
    190             case 5:
    191                 oat_dir = param;
    192                 break;
    193 
    194             case 6: {
    195                 // Version 1 had:
    196                 constexpr int OLD_DEXOPT_PUBLIC         = 1 << 1;
    197                 // Note: DEXOPT_SAFEMODE has been removed.
    198                 // constexpr int OLD_DEXOPT_SAFEMODE       = 1 << 2;
    199                 constexpr int OLD_DEXOPT_DEBUGGABLE     = 1 << 3;
    200                 constexpr int OLD_DEXOPT_BOOTCOMPLETE   = 1 << 4;
    201                 constexpr int OLD_DEXOPT_PROFILE_GUIDED = 1 << 5;
    202                 constexpr int OLD_DEXOPT_OTA            = 1 << 6;
    203                 static_assert(DEXOPT_GENERATE_COMPACT_DEX > OLD_DEXOPT_OTA, "must not overlap");
    204                 int input = atoi(param);
    205                 dexopt_flags |=
    206                         ReplaceMask(input, OLD_DEXOPT_PUBLIC, DEXOPT_PUBLIC) |
    207                         ReplaceMask(input, OLD_DEXOPT_DEBUGGABLE, DEXOPT_DEBUGGABLE) |
    208                         ReplaceMask(input, OLD_DEXOPT_BOOTCOMPLETE, DEXOPT_BOOTCOMPLETE) |
    209                         ReplaceMask(input, OLD_DEXOPT_PROFILE_GUIDED, DEXOPT_PROFILE_GUIDED) |
    210                         ReplaceMask(input, OLD_DEXOPT_OTA, 0);
    211                 break;
    212             }
    213 
    214             case 7:
    215                 compiler_filter = param;
    216                 break;
    217 
    218             case 8:
    219                 volume_uuid = ParseNull(param);
    220                 break;
    221 
    222             case 9:
    223                 shared_libraries = ParseNull(param);
    224                 break;
    225 
    226             default:
    227                 LOG(ERROR) << "Too many arguments, got " << param;
    228                 return false;
    229         }
    230     }
    231 
    232     if (param_index != 10) {
    233         LOG(ERROR) << "Not enough parameters";
    234         return false;
    235     }
    236 
    237     return true;
    238 }
    239 
    240 bool OTAPreoptParameters::ReadArgumentsPostV1(uint32_t version, const char** argv, bool versioned) {
    241     size_t num_args_expected = 0;
    242     switch (version) {
    243         case 2: num_args_expected = 11; break;
    244         case 3: num_args_expected = 12; break;
    245         case 4: num_args_expected = 13; break;
    246         case 5: num_args_expected = 14; break;
    247         case 6: num_args_expected = 15; break;
    248         case 7:
    249         // Version 8 adds a new dexopt flag: DEXOPT_GENERATE_COMPACT_DEX
    250         case 8: num_args_expected = 16; break;
    251         // Version 9 adds a new dexopt flag: DEXOPT_GENERATE_APP_IMAGE
    252         case 9: num_args_expected = 16; break;
    253         // Version 10 is a compatibility bump.
    254         case 10: num_args_expected = 16; break;
    255         default:
    256             LOG(ERROR) << "Don't know how to read arguments for version " << version;
    257             return false;
    258     }
    259     size_t dexopt_index = versioned ? 3 : 2;
    260 
    261     // Check for "dexopt".
    262     if (argv[dexopt_index] == nullptr) {
    263         LOG(ERROR) << "Missing parameters";
    264         return false;
    265     }
    266     if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
    267         LOG(ERROR) << "Expected \"dexopt\" but found: " << argv[dexopt_index];
    268         return false;
    269     }
    270 
    271     // Validate the number of arguments.
    272     size_t num_args_actual = 0;
    273     while (argv[dexopt_index + 1 + num_args_actual] != nullptr) {
    274         num_args_actual++;
    275     }
    276 
    277     if (num_args_actual != num_args_expected) {
    278         LOG(ERROR) << "Invalid number of arguments. expected="
    279                 << num_args_expected << " actual=" << num_args_actual;
    280         return false;
    281     }
    282 
    283     // The number of arguments is OK.
    284     // Configure the default values for the parameters that were added after V1.
    285     // The default values will be overwritten in case they are passed as arguments.
    286     SetDefaultsForPostV1Arguments();
    287 
    288     for (size_t param_index = 0; param_index < num_args_actual; ++param_index) {
    289         const char* param = argv[dexopt_index + 1 + param_index];
    290         switch (param_index) {
    291             case 0:
    292                 apk_path = param;
    293                 break;
    294 
    295             case 1:
    296                 uid = atoi(param);
    297                 break;
    298 
    299             case 2:
    300                 pkgName = param;
    301                 break;
    302 
    303             case 3:
    304                 instruction_set = param;
    305                 break;
    306 
    307             case 4:
    308                 dexopt_needed = atoi(param);
    309                 break;
    310 
    311             case 5:
    312                 oat_dir = param;
    313                 break;
    314 
    315             case 6:
    316                 dexopt_flags = atoi(param);
    317                 // Add CompactDex generation flag for versions less than 8 since it wasn't passed
    318                 // from the package manager. Only conditionally set the flag here so that it can
    319                 // be fully controlled by the package manager.
    320                 dexopt_flags |= (version < 8) ? DEXOPT_GENERATE_COMPACT_DEX : 0u;
    321                 break;
    322 
    323             case 7:
    324                 compiler_filter = param;
    325                 break;
    326 
    327             case 8:
    328                 volume_uuid = ParseNull(param);
    329                 break;
    330 
    331             case 9:
    332                 shared_libraries = ParseNull(param);
    333                 break;
    334 
    335             case 10:
    336                 se_info = ParseNull(param);
    337                 break;
    338 
    339             case 11:
    340                 downgrade = ParseBool(param);
    341                 break;
    342 
    343             case 12:
    344                 target_sdk_version = atoi(param);
    345                 break;
    346 
    347             case 13:
    348                 profile_name = ParseNull(param);
    349                 break;
    350 
    351             case 14:
    352                 dex_metadata_path = ParseNull(param);
    353                 break;
    354 
    355             case 15:
    356                 compilation_reason = ParseNull(param);
    357                 break;
    358 
    359             default:
    360                 LOG(FATAL) << "Should not get here. Did you call ReadArguments "
    361                         << "with the right expectation? index=" << param_index
    362                         << " num_args=" << num_args_actual;
    363                 return false;
    364         }
    365     }
    366 
    367     if (version < 10) {
    368         // Do not accept '&' as shared libraries from versions prior to 10. These may lead
    369         // to runtime crashes. The server side of version 10+ should send the correct
    370         // context in almost all cases (e.g., only for actual shared packages).
    371         if (shared_libraries != nullptr && std::string("&") == shared_libraries) {
    372             return false;
    373         }
    374     }
    375 
    376     return true;
    377 }
    378 
    379 }  // namespace installd
    380 }  // namespace android
    381