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 <inttypes.h>
18 #include <selinux/android.h>
19 #include <selinux/avc.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/capability.h>
23 #include <sys/mman.h>
24 #include <sys/prctl.h>
25 #include <sys/stat.h>
26 #include <sys/wait.h>
27 #include <algorithm>
28 #include <iterator>
29 #include <limits>
30 #include <random>
31 #include <regex>
32 
33 #include <android-base/logging.h>
34 #include <android-base/macros.h>
35 #include <android-base/stringprintf.h>
36 #include <android-base/strings.h>
37 #include <cutils/fs.h>
38 #include <cutils/properties.h>
39 #include <log/log.h>
40 #include <private/android_filesystem_config.h>
41 
42 #include "android-base/file.h"
43 #include "dexopt.h"
44 #include "file_parsing.h"
45 #include "globals.h"
46 #include "installd_constants.h"
47 #include "installd_deps.h"  // Need to fill in requirements of commands.
48 #include "otapreopt_parameters.h"
49 #include "otapreopt_utils.h"
50 #include "system_properties.h"
51 #include "unique_file.h"
52 #include "utils.h"
53 
54 #ifndef LOG_TAG
55 #define LOG_TAG "otapreopt"
56 #endif
57 
58 #define BUFFER_MAX    1024  /* input buffer for commands */
59 #define TOKEN_MAX     16    /* max number of arguments in buffer */
60 #define REPLY_MAX     256   /* largest reply allowed */
61 
62 using android::base::EndsWith;
63 using android::base::Split;
64 using android::base::StartsWith;
65 using android::base::StringPrintf;
66 
67 namespace android {
68 namespace installd {
69 
70 // Check expected values for dexopt flags. If you need to change this:
71 //
72 //   RUN AN A/B OTA TO MAKE SURE THINGS STILL WORK!
73 //
74 // You most likely need to increase the protocol version and all that entails!
75 
76 static_assert(DEXOPT_PUBLIC         == 1 << 1, "DEXOPT_PUBLIC unexpected.");
77 static_assert(DEXOPT_DEBUGGABLE     == 1 << 2, "DEXOPT_DEBUGGABLE unexpected.");
78 static_assert(DEXOPT_BOOTCOMPLETE   == 1 << 3, "DEXOPT_BOOTCOMPLETE unexpected.");
79 static_assert(DEXOPT_PROFILE_GUIDED == 1 << 4, "DEXOPT_PROFILE_GUIDED unexpected.");
80 static_assert(DEXOPT_SECONDARY_DEX  == 1 << 5, "DEXOPT_SECONDARY_DEX unexpected.");
81 static_assert(DEXOPT_FORCE          == 1 << 6, "DEXOPT_FORCE unexpected.");
82 static_assert(DEXOPT_STORAGE_CE     == 1 << 7, "DEXOPT_STORAGE_CE unexpected.");
83 static_assert(DEXOPT_STORAGE_DE     == 1 << 8, "DEXOPT_STORAGE_DE unexpected.");
84 static_assert(DEXOPT_ENABLE_HIDDEN_API_CHECKS == 1 << 10,
85         "DEXOPT_ENABLE_HIDDEN_API_CHECKS unexpected");
86 static_assert(DEXOPT_GENERATE_COMPACT_DEX == 1 << 11, "DEXOPT_GENERATE_COMPACT_DEX unexpected");
87 static_assert(DEXOPT_GENERATE_APP_IMAGE == 1 << 12, "DEXOPT_GENERATE_APP_IMAGE unexpected");
88 
89 static_assert(DEXOPT_MASK           == (0x3dfe | DEXOPT_IDLE_BACKGROUND_JOB),
90               "DEXOPT_MASK unexpected.");
91 
92 constexpr const char* kAotCompilerFilters[]{
93         "space-profile", "space", "speed-profile", "speed", "everything-profile", "everything",
94 };
95 
96 template<typename T>
IsPowerOfTwo(T x)97 static constexpr bool IsPowerOfTwo(T x) {
98   static_assert(std::is_integral<T>::value, "T must be integral");
99   // TODO: assert unsigned. There is currently many uses with signed values.
100   return (x & (x - 1)) == 0;
101 }
102 
103 template<typename T>
RoundDown(T x,typename std::decay<T>::type n)104 static constexpr T RoundDown(T x, typename std::decay<T>::type n) {
105     return (x & -n);
106 }
107 
108 template<typename T>
RoundUp(T x,typename std::remove_reference<T>::type n)109 static constexpr T RoundUp(T x, typename std::remove_reference<T>::type n) {
110     return RoundDown(x + n - 1, n);
111 }
112 
113 class OTAPreoptService {
114  public:
115     // Main driver. Performs the following steps.
116     //
117     // 1) Parse options (read system properties etc from B partition).
118     //
119     // 2) Read in package data.
120     //
121     // 3) Prepare environment variables.
122     //
123     // 4) Prepare(compile) boot image, if necessary.
124     //
125     // 5) Run update.
Main(int argc,char ** argv)126     int Main(int argc, char** argv) {
127         if (!ReadArguments(argc, argv)) {
128             LOG(ERROR) << "Failed reading command line.";
129             return 1;
130         }
131 
132         if (!ReadSystemProperties()) {
133             LOG(ERROR)<< "Failed reading system properties.";
134             return 2;
135         }
136 
137         if (!ReadEnvironment()) {
138             LOG(ERROR) << "Failed reading environment properties.";
139             return 3;
140         }
141 
142         if (!CheckAndInitializeInstalldGlobals()) {
143             LOG(ERROR) << "Failed initializing globals.";
144             return 4;
145         }
146 
147         PrepareEnvironmentVariables();
148 
149         if (!EnsureDalvikCache()) {
150             LOG(ERROR) << "Bad dalvik cache.";
151             return 5;
152         }
153 
154         int dexopt_retcode = RunPreopt();
155 
156         return dexopt_retcode;
157     }
158 
GetProperty(const char * key,char * value,const char * default_value) const159     int GetProperty(const char* key, char* value, const char* default_value) const {
160         const std::string* prop_value = system_properties_.GetProperty(key);
161         if (prop_value == nullptr) {
162             if (default_value == nullptr) {
163                 return 0;
164             }
165             // Copy in the default value.
166             strlcpy(value, default_value, kPropertyValueMax - 1);
167             value[kPropertyValueMax - 1] = 0;
168             return strlen(default_value);// TODO: Need to truncate?
169         }
170         size_t size = std::min(kPropertyValueMax - 1, prop_value->length()) + 1;
171         strlcpy(value, prop_value->data(), size);
172         return static_cast<int>(size - 1);
173     }
174 
GetOTADataDirectory() const175     std::string GetOTADataDirectory() const {
176         return StringPrintf("%s/%s", GetOtaDirectoryPrefix().c_str(), GetTargetSlot().c_str());
177     }
178 
GetTargetSlot() const179     const std::string& GetTargetSlot() const {
180         return parameters_.target_slot;
181     }
182 
183 private:
184 
ReadSystemProperties()185     bool ReadSystemProperties() {
186         // TODO This file does not have a stable format. It should be read by
187         // code shared by init and otapreopt. See b/181182967#comment80
188         static constexpr const char* kPropertyFiles[] = {
189                 "/system/build.prop"
190         };
191 
192         for (size_t i = 0; i < arraysize(kPropertyFiles); ++i) {
193             if (!system_properties_.Load(kPropertyFiles[i])) {
194                 return false;
195             }
196         }
197 
198         return true;
199     }
200 
ReadEnvironment()201     bool ReadEnvironment() {
202         // Parse the environment variables from init.environ.rc, which have the form
203         //   export NAME VALUE
204         // For simplicity, don't respect string quotation. The values we are interested in can be
205         // encoded without them.
206         //
207         // init.environ.rc and derive_classpath all have the same format for
208         // environment variable exports (since they are all meant to be read by
209         // init) and can be matched by the same regex.
210 
211         std::regex export_regex("\\s*export\\s+(\\S+)\\s+(\\S+)");
212         auto parse_results = [&](auto& input) {
213           ParseFile(input, [&](const std::string& line) {
214               std::smatch export_match;
215               if (!std::regex_match(line, export_match, export_regex)) {
216                   return true;
217               }
218 
219               if (export_match.size() != 3) {
220                   return true;
221               }
222 
223               std::string name = export_match[1].str();
224               std::string value = export_match[2].str();
225 
226               system_properties_.SetProperty(name, value);
227 
228               return true;
229           });
230         };
231 
232         // TODO Just like with the system-properties above we really should have
233         // common code between init and otapreopt to deal with reading these
234         // things. See b/181182967
235         // There have been a variety of places the various env-vars have been
236         // over the years.  Expand or reduce this list as needed.
237         static constexpr const char* kEnvironmentVariableSources[] = {
238                 "/init.environ.rc",
239         };
240         // First get everything from the static files.
241         for (const char* env_vars_file : kEnvironmentVariableSources) {
242           parse_results(env_vars_file);
243         }
244 
245         // Next get everything from derive_classpath, since we're already in the
246         // chroot it will get the new versions of any dependencies.
247         {
248           android::base::unique_fd fd(memfd_create("derive_classpath_temp", MFD_CLOEXEC));
249           if (!fd.ok()) {
250             LOG(ERROR) << "Unable to create fd for derive_classpath";
251             return false;
252           }
253           std::string memfd_file = StringPrintf("/proc/%d/fd/%d", getpid(), fd.get());
254           std::string error_msg;
255           if (!Exec({"/apex/com.android.sdkext/bin/derive_classpath", memfd_file}, &error_msg)) {
256             PLOG(ERROR) << "Running derive_classpath failed: " << error_msg;
257             return false;
258           }
259           std::ifstream ifs(memfd_file);
260           parse_results(ifs);
261         }
262 
263         if (system_properties_.GetProperty(kAndroidDataPathPropertyName) == nullptr) {
264             return false;
265         }
266         android_data_ = *system_properties_.GetProperty(kAndroidDataPathPropertyName);
267 
268         if (system_properties_.GetProperty(kAndroidRootPathPropertyName) == nullptr) {
269             return false;
270         }
271         android_root_ = *system_properties_.GetProperty(kAndroidRootPathPropertyName);
272 
273         if (system_properties_.GetProperty(kBootClassPathPropertyName) == nullptr) {
274             return false;
275         }
276         boot_classpath_ = *system_properties_.GetProperty(kBootClassPathPropertyName);
277 
278         if (system_properties_.GetProperty(ASEC_MOUNTPOINT_ENV_NAME) == nullptr) {
279             return false;
280         }
281         asec_mountpoint_ = *system_properties_.GetProperty(ASEC_MOUNTPOINT_ENV_NAME);
282 
283         return true;
284     }
285 
GetAndroidData() const286     const std::string& GetAndroidData() const {
287         return android_data_;
288     }
289 
GetAndroidRoot() const290     const std::string& GetAndroidRoot() const {
291         return android_root_;
292     }
293 
GetOtaDirectoryPrefix() const294     const std::string GetOtaDirectoryPrefix() const {
295         return GetAndroidData() + "/ota";
296     }
297 
CheckAndInitializeInstalldGlobals()298     bool CheckAndInitializeInstalldGlobals() {
299         // init_globals_from_data_and_root requires "ASEC_MOUNTPOINT" in the environment. We
300         // do not use any datapath that includes this, but we'll still have to set it.
301         CHECK(system_properties_.GetProperty(ASEC_MOUNTPOINT_ENV_NAME) != nullptr);
302         int result = setenv(ASEC_MOUNTPOINT_ENV_NAME, asec_mountpoint_.c_str(), 0);
303         if (result != 0) {
304             LOG(ERROR) << "Could not set ASEC_MOUNTPOINT environment variable";
305             return false;
306         }
307 
308         if (!init_globals_from_data_and_root(GetAndroidData().c_str(), GetAndroidRoot().c_str())) {
309             LOG(ERROR) << "Could not initialize globals; exiting.";
310             return false;
311         }
312 
313         // This is different from the normal installd. We only do the base
314         // directory, the rest will be created on demand when each app is compiled.
315         if (access(GetOtaDirectoryPrefix().c_str(), R_OK) < 0) {
316             PLOG(ERROR) << "Could not access " << GetOtaDirectoryPrefix();
317             return false;
318         }
319 
320         return true;
321     }
322 
ParseBool(const char * in)323     bool ParseBool(const char* in) {
324         if (strcmp(in, "true") == 0) {
325             return true;
326         }
327         return false;
328     }
329 
ParseUInt(const char * in,uint32_t * out)330     bool ParseUInt(const char* in, uint32_t* out) {
331         char* end;
332         long long int result = strtoll(in, &end, 0);
333         if (in == end || *end != '\0') {
334             return false;
335         }
336         if (result < std::numeric_limits<uint32_t>::min() ||
337                 std::numeric_limits<uint32_t>::max() < result) {
338             return false;
339         }
340         *out = static_cast<uint32_t>(result);
341         return true;
342     }
343 
ReadArguments(int argc,char ** argv)344     bool ReadArguments(int argc, char** argv) {
345         return parameters_.ReadArguments(argc, const_cast<const char**>(argv));
346     }
347 
PrepareEnvironmentVariables()348     void PrepareEnvironmentVariables() {
349         environ_.push_back(StringPrintf("BOOTCLASSPATH=%s", boot_classpath_.c_str()));
350         environ_.push_back(StringPrintf("ANDROID_DATA=%s", GetOTADataDirectory().c_str()));
351         environ_.push_back(StringPrintf("ANDROID_ROOT=%s", android_root_.c_str()));
352 
353         for (const std::string& e : environ_) {
354             putenv(const_cast<char*>(e.c_str()));
355         }
356     }
357 
358     // Ensure that we have the right cache file structures.
EnsureDalvikCache() const359     bool EnsureDalvikCache() const {
360         if (parameters_.instruction_set == nullptr) {
361             LOG(ERROR) << "Instruction set missing.";
362             return false;
363         }
364         const char* isa = parameters_.instruction_set;
365         std::string dalvik_cache = GetOTADataDirectory() + "/" + DALVIK_CACHE;
366         std::string isa_path = dalvik_cache + "/" + isa;
367 
368         // Reset umask in otapreopt, so that we control the the access for the files we create.
369         umask(0);
370 
371         // Create the directories, if necessary.
372         if (access(dalvik_cache.c_str(), F_OK) != 0) {
373             if (!CreatePath(dalvik_cache)) {
374                 PLOG(ERROR) << "Could not create dalvik-cache dir " << dalvik_cache;
375                 return false;
376             }
377         }
378         if (access(isa_path.c_str(), F_OK) != 0) {
379             if (!CreatePath(isa_path)) {
380                 PLOG(ERROR) << "Could not create dalvik-cache isa dir";
381                 return false;
382             }
383         }
384 
385         return true;
386     }
387 
CreatePath(const std::string & path)388     static bool CreatePath(const std::string& path) {
389         // Create the given path. Use string processing instead of dirname, as dirname's need for
390         // a writable char buffer is painful.
391 
392         // First, try to use the full path.
393         if (mkdir(path.c_str(), 0711) == 0) {
394             return true;
395         }
396         if (errno != ENOENT) {
397             PLOG(ERROR) << "Could not create path " << path;
398             return false;
399         }
400 
401         // Now find the parent and try that first.
402         size_t last_slash = path.find_last_of('/');
403         if (last_slash == std::string::npos || last_slash == 0) {
404             PLOG(ERROR) << "Could not create " << path;
405             return false;
406         }
407 
408         if (!CreatePath(path.substr(0, last_slash))) {
409             return false;
410         }
411 
412         if (mkdir(path.c_str(), 0711) == 0) {
413             return true;
414         }
415         PLOG(ERROR) << "Could not create " << path;
416         return false;
417     }
418 
ParseNull(const char * arg)419     static const char* ParseNull(const char* arg) {
420         return (strcmp(arg, "!") == 0) ? nullptr : arg;
421     }
422 
IsAotCompilation() const423     bool IsAotCompilation() const {
424         if (std::find(std::begin(kAotCompilerFilters), std::end(kAotCompilerFilters),
425                       std::string_view(parameters_.compiler_filter)) ==
426             std::end(kAotCompilerFilters)) {
427             return false;
428         }
429 
430         int dexopt_flags = parameters_.dexopt_flags;
431         bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
432         bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0;
433         bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0;
434 
435         if (profile_guided) {
436             UniqueFile reference_profile =
437                     maybe_open_reference_profile(parameters_.pkgName, parameters_.apk_path,
438                                                  parameters_.profile_name, profile_guided,
439                                                  is_public, parameters_.uid, is_secondary_dex);
440             // `maybe_open_reference_profile` installs a hook that clears the profile on
441             // destruction. Disable it.
442             reference_profile.DisableCleanup();
443             struct stat sbuf;
444             if (reference_profile.fd() == -1 ||
445                 (fstat(reference_profile.fd(), &sbuf) != -1 && sbuf.st_size == 0)) {
446                 return false;
447             }
448         }
449 
450         return true;
451     }
452 
ShouldSkipPreopt() const453     bool ShouldSkipPreopt() const {
454         // There's one thing we have to be careful about: we may/will be asked to compile an app
455         // living in the system image. This may be a valid request - if the app wasn't compiled,
456         // e.g., if the system image wasn't large enough to include preopted files. However, the
457         // data we have is from the old system, so the driver (the OTA service) can't actually
458         // know. Thus, we will get requests for apps that have preopted components. To avoid
459         // duplication (we'd generate files that are not used and are *not* cleaned up), do two
460         // simple checks:
461         //
462         // 1) Does the apk_path start with the value of ANDROID_ROOT? (~in the system image)
463         //    (For simplicity, assume the value of ANDROID_ROOT does not contain a symlink.)
464         //
465         // 2) If you replace the name in the apk_path with "oat," does the path exist?
466         //    (=have a subdirectory for preopted files)
467         //
468         // If the answer to both is yes, skip the dexopt.
469         //
470         // Note: while one may think it's OK to call dexopt and it will fail (because APKs should
471         //       be stripped), that's not true for APKs signed outside the build system (so the
472         //       jar content must be exactly the same).
473 
474         //       (This is ugly as it's the only thing where we need to understand the contents
475         //        of parameters_, but it beats postponing the decision or using the call-
476         //        backs to do weird things.)
477 
478         // In addition, no need to preopt for "verify". The existing vdex files in the OTA package
479         // and the /data partition will still be usable after the OTA update is applied.
480         const char* apk_path = parameters_.apk_path;
481         CHECK(apk_path != nullptr);
482         if (StartsWith(apk_path, android_root_) || !IsAotCompilation()) {
483             const char* last_slash = strrchr(apk_path, '/');
484             if (last_slash != nullptr) {
485                 std::string path(apk_path, last_slash - apk_path + 1);
486                 CHECK(EndsWith(path, "/"));
487                 path = path + "oat";
488                 if (access(path.c_str(), F_OK) == 0) {
489                     LOG(INFO) << "Skipping A/B OTA preopt of already preopted package " << apk_path;
490                     return true;
491                 }
492             }
493         }
494 
495         // Another issue is unavailability of files in the new system. If the partition
496         // layout changes, otapreopt_chroot may not know about this. Then files from that
497         // partition will not be available and fail to build. This is problematic, as
498         // this tool will wipe the OTA artifact cache and try again (for robustness after
499         // a failed OTA with remaining cache artifacts).
500         if (access(apk_path, F_OK) != 0) {
501             PLOG(WARNING) << "Skipping A/B OTA preopt of non-existing package " << apk_path;
502             return true;
503         }
504 
505         return false;
506     }
507 
508     // Run dexopt with the parameters of parameters_.
509     // TODO(calin): embed the profile name in the parameters.
Dexopt()510     int Dexopt() {
511         std::string error;
512 
513         int dexopt_flags = parameters_.dexopt_flags;
514         // Make sure dex2oat is run with background priority.
515         dexopt_flags |= DEXOPT_BOOTCOMPLETE | DEXOPT_IDLE_BACKGROUND_JOB;
516 
517         parameters_.compilation_reason = "ab-ota";
518 
519         int res = dexopt(parameters_.apk_path,
520                          parameters_.uid,
521                          parameters_.pkgName,
522                          parameters_.instruction_set,
523                          parameters_.dexopt_needed,
524                          parameters_.oat_dir,
525                          dexopt_flags,
526                          parameters_.compiler_filter,
527                          parameters_.volume_uuid,
528                          parameters_.shared_libraries,
529                          parameters_.se_info,
530                          parameters_.downgrade,
531                          parameters_.target_sdk_version,
532                          parameters_.profile_name,
533                          parameters_.dex_metadata_path,
534                          parameters_.compilation_reason,
535                          &error);
536         if (res != 0) {
537             LOG(ERROR) << "During preopt of " << parameters_.apk_path << " got result " << res
538                        << " error: " << error;
539         }
540         return res;
541     }
542 
RunPreopt()543     int RunPreopt() {
544         if (ShouldSkipPreopt()) {
545             return 0;
546         }
547 
548         int dexopt_result = Dexopt();
549         if (dexopt_result == 0) {
550             return 0;
551         }
552 
553         if (WIFSIGNALED(dexopt_result)) {
554             LOG(WARNING) << "Interrupted by signal " << WTERMSIG(dexopt_result) ;
555             return dexopt_result;
556         }
557 
558         // If this was a profile-guided run, we may have profile version issues. Try to downgrade,
559         // if possible.
560         if ((parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) {
561             return dexopt_result;
562         }
563 
564         LOG(WARNING) << "Downgrading compiler filter in an attempt to progress compilation";
565         parameters_.dexopt_flags &= ~DEXOPT_PROFILE_GUIDED;
566         return Dexopt();
567     }
568 
569     static constexpr const char* kBootClassPathPropertyName = "BOOTCLASSPATH";
570     static constexpr const char* kAndroidRootPathPropertyName = "ANDROID_ROOT";
571     static constexpr const char* kAndroidDataPathPropertyName = "ANDROID_DATA";
572     // The index of the instruction-set string inside the package parameters. Needed for
573     // some special-casing that requires knowledge of the instruction-set.
574     static constexpr size_t kISAIndex = 3;
575 
576     // Stores the system properties read out of the B partition. We need to use these properties
577     // to compile, instead of the A properties we could get from init/get_property.
578     SystemProperties system_properties_;
579 
580     // Some select properties that are always needed.
581     std::string android_root_;
582     std::string android_data_;
583     std::string boot_classpath_;
584     std::string asec_mountpoint_;
585 
586     OTAPreoptParameters parameters_;
587 
588     // Store environment values we need to set.
589     std::vector<std::string> environ_;
590 };
591 
592 OTAPreoptService gOps;
593 
594 ////////////////////////
595 // Plug-in functions. //
596 ////////////////////////
597 
get_property(const char * key,char * value,const char * default_value)598 int get_property(const char *key, char *value, const char *default_value) {
599     return gOps.GetProperty(key, value, default_value);
600 }
601 
602 // Compute the output path of
calculate_oat_file_path(char path[PKG_PATH_MAX],const char * oat_dir,const char * apk_path,const char * instruction_set)603 bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir,
604                              const char *apk_path,
605                              const char *instruction_set) {
606     const char *file_name_start;
607     const char *file_name_end;
608 
609     file_name_start = strrchr(apk_path, '/');
610     if (file_name_start == nullptr) {
611         ALOGE("apk_path '%s' has no '/'s in it\n", apk_path);
612         return false;
613     }
614     file_name_end = strrchr(file_name_start, '.');
615     if (file_name_end == nullptr) {
616         ALOGE("apk_path '%s' has no extension\n", apk_path);
617         return false;
618     }
619 
620     // Calculate file_name
621     file_name_start++;  // Move past '/', is valid as file_name_end is valid.
622     size_t file_name_len = file_name_end - file_name_start;
623     std::string file_name(file_name_start, file_name_len);
624 
625     // <apk_parent_dir>/oat/<isa>/<file_name>.odex.b
626     snprintf(path,
627              PKG_PATH_MAX,
628              "%s/%s/%s.odex.%s",
629              oat_dir,
630              instruction_set,
631              file_name.c_str(),
632              gOps.GetTargetSlot().c_str());
633     return true;
634 }
635 
636 /*
637  * Computes the odex file for the given apk_path and instruction_set.
638  * /system/framework/whatever.jar -> /system/framework/oat/<isa>/whatever.odex
639  *
640  * Returns false if it failed to determine the odex file path.
641  */
calculate_odex_file_path(char path[PKG_PATH_MAX],const char * apk_path,const char * instruction_set)642 bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
643                               const char *instruction_set) {
644     const char *path_end = strrchr(apk_path, '/');
645     if (path_end == nullptr) {
646         ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
647         return false;
648     }
649     std::string path_component(apk_path, path_end - apk_path);
650 
651     const char *name_begin = path_end + 1;
652     const char *extension_start = strrchr(name_begin, '.');
653     if (extension_start == nullptr) {
654         ALOGE("apk_path '%s' has no extension.\n", apk_path);
655         return false;
656     }
657     std::string name_component(name_begin, extension_start - name_begin);
658 
659     std::string new_path = StringPrintf("%s/oat/%s/%s.odex.%s",
660                                         path_component.c_str(),
661                                         instruction_set,
662                                         name_component.c_str(),
663                                         gOps.GetTargetSlot().c_str());
664     if (new_path.length() >= PKG_PATH_MAX) {
665         LOG(ERROR) << "apk_path of " << apk_path << " is too long: " << new_path;
666         return false;
667     }
668     strcpy(path, new_path.c_str());
669     return true;
670 }
671 
create_cache_path(char path[PKG_PATH_MAX],const char * src,const char * instruction_set)672 bool create_cache_path(char path[PKG_PATH_MAX],
673                        const char *src,
674                        const char *instruction_set) {
675     size_t srclen = strlen(src);
676 
677         /* demand that we are an absolute path */
678     if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
679         return false;
680     }
681 
682     if (srclen > PKG_PATH_MAX) {        // XXX: PKG_NAME_MAX?
683         return false;
684     }
685 
686     std::string from_src = std::string(src + 1);
687     std::replace(from_src.begin(), from_src.end(), '/', '@');
688 
689     std::string assembled_path = StringPrintf("%s/%s/%s/%s%s",
690                                               gOps.GetOTADataDirectory().c_str(),
691                                               DALVIK_CACHE,
692                                               instruction_set,
693                                               from_src.c_str(),
694                                               DALVIK_CACHE_POSTFIX);
695 
696     if (assembled_path.length() + 1 > PKG_PATH_MAX) {
697         return false;
698     }
699     strcpy(path, assembled_path.c_str());
700 
701     return true;
702 }
703 
force_compile_without_image()704 bool force_compile_without_image() {
705     // We don't have a boot image anyway. Compile without a boot image.
706     return true;
707 }
708 
log_callback(int type,const char * fmt,...)709 static int log_callback(int type, const char *fmt, ...) {
710     va_list ap;
711     int priority;
712 
713     switch (type) {
714         case SELINUX_WARNING:
715             priority = ANDROID_LOG_WARN;
716             break;
717         case SELINUX_INFO:
718             priority = ANDROID_LOG_INFO;
719             break;
720         default:
721             priority = ANDROID_LOG_ERROR;
722             break;
723     }
724     va_start(ap, fmt);
725     LOG_PRI_VA(priority, "SELinux", fmt, ap);
726     va_end(ap);
727     return 0;
728 }
729 
otapreopt_main(const int argc,char * argv[])730 static int otapreopt_main(const int argc, char *argv[]) {
731     int selinux_enabled = (is_selinux_enabled() > 0);
732 
733     setenv("ANDROID_LOG_TAGS", "*:v", 1);
734     android::base::InitLogging(argv);
735 
736     if (argc < 2) {
737         ALOGE("Expecting parameters");
738         exit(1);
739     }
740 
741     union selinux_callback cb;
742     cb.func_log = log_callback;
743     selinux_set_callback(SELINUX_CB_LOG, cb);
744 
745     if (selinux_enabled && selinux_status_open(true) < 0) {
746         ALOGE("Could not open selinux status; exiting.\n");
747         exit(1);
748     }
749 
750     int ret = android::installd::gOps.Main(argc, argv);
751 
752     return ret;
753 }
754 
755 }  // namespace installd
756 }  // namespace android
757 
main(const int argc,char * argv[])758 int main(const int argc, char *argv[]) {
759     return android::installd::otapreopt_main(argc, argv);
760 }
761