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 
ParseBool(const char * in)34 static bool ParseBool(const char* in) {
35     if (strcmp(in, "true") == 0) {
36         return true;
37     }
38     return false;
39 }
40 
ParseNull(const char * arg)41 static const char* ParseNull(const char* arg) {
42     return (strcmp(arg, "!") == 0) ? nullptr : arg;
43 }
44 
ParseUInt(const char * in,uint32_t * out)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 
ReadArguments(int argc,const char ** argv)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 
ReplaceMask(int input,int old_mask,int new_mask)113 static int ReplaceMask(int input, int old_mask, int new_mask) {
114     return (input & old_mask) != 0 ? new_mask : 0;
115 }
116 
SetDefaultsForPostV1Arguments()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 
ReadArgumentsV1(const char ** argv)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 
ReadArgumentsPostV1(uint32_t version,const char ** argv,bool versioned)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