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