| Calin Juravle | dff4729 | 2018-02-01 14:44:56 +0000 | [diff] [blame] | 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 |  | 
| Andreas Gampe | 2478cf2 | 2018-09-18 09:37:21 -0700 | [diff] [blame] | 19 | #include <cstring> | 
 | 20 |  | 
| Calin Juravle | dff4729 | 2018-02-01 14:44:56 +0000 | [diff] [blame] | 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) { | 
| Calin Juravle | 315d1f5 | 2018-02-01 14:56:14 +0000 | [diff] [blame] | 98 |             return ReadArgumentsPostV1(2, argv, false); | 
| Calin Juravle | dff4729 | 2018-02-01 14:44:56 +0000 | [diff] [blame] | 99 |         } else { | 
| Calin Juravle | 315d1f5 | 2018-02-01 14:56:14 +0000 | [diff] [blame] | 100 |             return ReadArgumentsV1(argv); | 
| Calin Juravle | dff4729 | 2018-02-01 14:44:56 +0000 | [diff] [blame] | 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 |  | 
| Calin Juravle | 315d1f5 | 2018-02-01 14:56:14 +0000 | [diff] [blame] | 110 |     return ReadArgumentsPostV1(version, argv, true); | 
| Calin Juravle | dff4729 | 2018-02-01 14:44:56 +0000 | [diff] [blame] | 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 |  | 
| Calin Juravle | 2efc402 | 2018-02-13 18:31:32 -0800 | [diff] [blame] | 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"; | 
| Mathieu Chartier | dbc4ce6 | 2018-03-07 09:38:16 -0800 | [diff] [blame] | 138 |  | 
 | 139 |     // Flag is enabled by default for A/B otas. | 
 | 140 |     dexopt_flags = DEXOPT_GENERATE_COMPACT_DEX; | 
| Calin Juravle | 2efc402 | 2018-02-13 18:31:32 -0800 | [diff] [blame] | 141 | } | 
 | 142 |  | 
| Calin Juravle | 315d1f5 | 2018-02-01 14:56:14 +0000 | [diff] [blame] | 143 | bool OTAPreoptParameters::ReadArgumentsV1(const char** argv) { | 
| Calin Juravle | dff4729 | 2018-02-01 14:44:56 +0000 | [diff] [blame] | 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) { | 
| Calin Juravle | 315d1f5 | 2018-02-01 14:56:14 +0000 | [diff] [blame] | 150 |         LOG(ERROR) << "Expected \"dexopt\" but found: " << argv[2]; | 
| Calin Juravle | dff4729 | 2018-02-01 14:44:56 +0000 | [diff] [blame] | 151 |         return false; | 
 | 152 |     } | 
 | 153 |  | 
| Mathieu Chartier | dbc4ce6 | 2018-03-07 09:38:16 -0800 | [diff] [blame] | 154 |     SetDefaultsForPostV1Arguments(); | 
 | 155 |  | 
| Calin Juravle | dff4729 | 2018-02-01 14:44:56 +0000 | [diff] [blame] | 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; | 
| Mathieu Chartier | dbc4ce6 | 2018-03-07 09:38:16 -0800 | [diff] [blame] | 203 |                 static_assert(DEXOPT_GENERATE_COMPACT_DEX > OLD_DEXOPT_OTA, "must not overlap"); | 
| Calin Juravle | dff4729 | 2018-02-01 14:44:56 +0000 | [diff] [blame] | 204 |                 int input = atoi(param); | 
| Mathieu Chartier | dbc4ce6 | 2018-03-07 09:38:16 -0800 | [diff] [blame] | 205 |                 dexopt_flags |= | 
| Calin Juravle | dff4729 | 2018-02-01 14:44:56 +0000 | [diff] [blame] | 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 |  | 
| Calin Juravle | dff4729 | 2018-02-01 14:44:56 +0000 | [diff] [blame] | 237 |     return true; | 
 | 238 | } | 
 | 239 |  | 
| Calin Juravle | 315d1f5 | 2018-02-01 14:56:14 +0000 | [diff] [blame] | 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; | 
| Calin Juravle | 62c5a37 | 2018-02-01 17:03:23 +0000 | [diff] [blame] | 247 |         case 6: num_args_expected = 15; break; | 
| Mathieu Chartier | dbc4ce6 | 2018-03-07 09:38:16 -0800 | [diff] [blame] | 248 |         case 7: | 
 | 249 |         // Version 8 adds a new dexopt flag: DEXOPT_GENERATE_COMPACT_DEX | 
 | 250 |         case 8: num_args_expected = 16; break; | 
| Mathieu Chartier | 1dc3dfa | 2018-03-12 17:55:06 -0700 | [diff] [blame] | 251 |         // Version 9 adds a new dexopt flag: DEXOPT_GENERATE_APP_IMAGE | 
 | 252 |         case 9: num_args_expected = 16; break; | 
| Andreas Gampe | 2478cf2 | 2018-09-18 09:37:21 -0700 | [diff] [blame] | 253 |         // Version 10 is a compatibility bump. | 
 | 254 |         case 10: num_args_expected = 16; break; | 
| Calin Juravle | 315d1f5 | 2018-02-01 14:56:14 +0000 | [diff] [blame] | 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. | 
| Calin Juravle | 2efc402 | 2018-02-13 18:31:32 -0800 | [diff] [blame] | 286 |     SetDefaultsForPostV1Arguments(); | 
| Calin Juravle | 0c609c2 | 2018-02-12 17:39:37 -0800 | [diff] [blame] | 287 |  | 
| Calin Juravle | 315d1f5 | 2018-02-01 14:56:14 +0000 | [diff] [blame] | 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); | 
| Mathieu Chartier | dbc4ce6 | 2018-03-07 09:38:16 -0800 | [diff] [blame] | 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; | 
| Calin Juravle | 315d1f5 | 2018-02-01 14:56:14 +0000 | [diff] [blame] | 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 |  | 
| Calin Juravle | 62c5a37 | 2018-02-01 17:03:23 +0000 | [diff] [blame] | 351 |             case 14: | 
| Calin Juravle | 0c609c2 | 2018-02-12 17:39:37 -0800 | [diff] [blame] | 352 |                 dex_metadata_path = ParseNull(param); | 
 | 353 |                 break; | 
| Calin Juravle | 62c5a37 | 2018-02-01 17:03:23 +0000 | [diff] [blame] | 354 |  | 
| Calin Juravle | 2efc402 | 2018-02-13 18:31:32 -0800 | [diff] [blame] | 355 |             case 15: | 
 | 356 |                 compilation_reason = ParseNull(param); | 
 | 357 |                 break; | 
 | 358 |  | 
| Calin Juravle | 315d1f5 | 2018-02-01 14:56:14 +0000 | [diff] [blame] | 359 |             default: | 
| Calin Juravle | 0c609c2 | 2018-02-12 17:39:37 -0800 | [diff] [blame] | 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; | 
| Calin Juravle | 315d1f5 | 2018-02-01 14:56:14 +0000 | [diff] [blame] | 364 |         } | 
 | 365 |     } | 
 | 366 |  | 
| Andreas Gampe | 2478cf2 | 2018-09-18 09:37:21 -0700 | [diff] [blame] | 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 |  | 
| Calin Juravle | 315d1f5 | 2018-02-01 14:56:14 +0000 | [diff] [blame] | 376 |     return true; | 
 | 377 | } | 
 | 378 |  | 
| Calin Juravle | dff4729 | 2018-02-01 14:44:56 +0000 | [diff] [blame] | 379 | }  // namespace installd | 
 | 380 | }  // namespace android |