otapreopt.cpp revision 6db8db9f3369c48de87f97f4d4636d446837fe32
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 <algorithm>
18#include <inttypes.h>
19#include <random>
20#include <regex>
21#include <selinux/android.h>
22#include <selinux/avc.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/capability.h>
26#include <sys/prctl.h>
27#include <sys/stat.h>
28#include <sys/wait.h>
29
30#include <android-base/logging.h>
31#include <android-base/macros.h>
32#include <android-base/stringprintf.h>
33#include <android-base/strings.h>
34#include <cutils/fs.h>
35#include <cutils/log.h>
36#include <cutils/properties.h>
37#include <private/android_filesystem_config.h>
38
39#include <commands.h>
40#include <file_parsing.h>
41#include <globals.h>
42#include <installd_deps.h>  // Need to fill in requirements of commands.
43#include <system_properties.h>
44#include <utils.h>
45
46#ifndef LOG_TAG
47#define LOG_TAG "otapreopt"
48#endif
49
50#define BUFFER_MAX    1024  /* input buffer for commands */
51#define TOKEN_MAX     16    /* max number of arguments in buffer */
52#define REPLY_MAX     256   /* largest reply allowed */
53
54using android::base::Join;
55using android::base::Split;
56using android::base::StringPrintf;
57
58namespace android {
59namespace installd {
60
61static constexpr const char* kBootClassPathPropertyName = "BOOTCLASSPATH";
62static constexpr const char* kAndroidRootPathPropertyName = "ANDROID_ROOT";
63static constexpr const char* kOTARootDirectory = "/system-b";
64static constexpr size_t kISAIndex = 3;
65
66template<typename T>
67static constexpr T RoundDown(T x, typename std::decay<T>::type n) {
68    return DCHECK_CONSTEXPR(IsPowerOfTwo(n), , T(0))(x & -n);
69}
70
71template<typename T>
72static constexpr T RoundUp(T x, typename std::remove_reference<T>::type n) {
73    return RoundDown(x + n - 1, n);
74}
75
76class OTAPreoptService {
77 public:
78    static constexpr const char* kOTADataDirectory = "/data/ota";
79
80    // Main driver. Performs the following steps.
81    //
82    // 1) Parse options (read system properties etc from B partition).
83    //
84    // 2) Read in package data.
85    //
86    // 3) Prepare environment variables.
87    //
88    // 4) Prepare(compile) boot image, if necessary.
89    //
90    // 5) Run update.
91    int Main(int argc, char** argv) {
92        if (!ReadSystemProperties()) {
93            LOG(ERROR)<< "Failed reading system properties.";
94            return 1;
95        }
96
97        if (!ReadEnvironment()) {
98            LOG(ERROR) << "Failed reading environment properties.";
99            return 2;
100        }
101
102        if (!ReadPackage(argc, argv)) {
103            LOG(ERROR) << "Failed reading command line file.";
104            return 3;
105        }
106
107        PrepareEnvironment();
108
109        if (!PrepareBootImage()) {
110            LOG(ERROR) << "Failed preparing boot image.";
111            return 4;
112        }
113
114        int dexopt_retcode = RunPreopt();
115
116        return dexopt_retcode;
117    }
118
119    int GetProperty(const char* key, char* value, const char* default_value) {
120        const std::string* prop_value = system_properties_.GetProperty(key);
121        if (prop_value == nullptr) {
122            if (default_value == nullptr) {
123                return 0;
124            }
125            // Copy in the default value.
126            strncpy(value, default_value, kPropertyValueMax - 1);
127            value[kPropertyValueMax - 1] = 0;
128            return strlen(default_value);// TODO: Need to truncate?
129        }
130        size_t size = std::min(kPropertyValueMax - 1, prop_value->length());
131        strncpy(value, prop_value->data(), size);
132        value[size] = 0;
133        return static_cast<int>(size);
134    }
135
136private:
137    bool ReadSystemProperties() {
138        static constexpr const char* kPropertyFiles[] = {
139                "/default.prop", "/system/build.prop"
140        };
141
142        for (size_t i = 0; i < arraysize(kPropertyFiles); ++i) {
143            if (!system_properties_.Load(kPropertyFiles[i])) {
144                return false;
145            }
146        }
147
148        return true;
149    }
150
151    bool ReadEnvironment() {
152        // Parse the environment variables from init.environ.rc, which have the form
153        //   export NAME VALUE
154        // For simplicity, don't respect string quotation. The values we are interested in can be
155        // encoded without them.
156        std::regex export_regex("\\s*export\\s+(\\S+)\\s+(\\S+)");
157        bool parse_result = ParseFile("/init.environ.rc", [&](const std::string& line) {
158            std::smatch export_match;
159            if (!std::regex_match(line, export_match, export_regex)) {
160                return true;
161            }
162
163            if (export_match.size() != 3) {
164                return true;
165            }
166
167            std::string name = export_match[1].str();
168            std::string value = export_match[2].str();
169
170            system_properties_.SetProperty(name, value);
171
172            return true;
173        });
174        if (!parse_result) {
175            return false;
176        }
177
178        // Check that we found important properties.
179        constexpr const char* kRequiredProperties[] = {
180                kBootClassPathPropertyName, kAndroidRootPathPropertyName
181        };
182        for (size_t i = 0; i < arraysize(kRequiredProperties); ++i) {
183            if (system_properties_.GetProperty(kRequiredProperties[i]) == nullptr) {
184                return false;
185            }
186        }
187
188        return true;
189    }
190
191    bool ReadPackage(int argc ATTRIBUTE_UNUSED, char** argv) {
192        size_t index = 0;
193        static_assert(DEXOPT_PARAM_COUNT == ARRAY_SIZE(package_parameters_),
194                      "Unexpected dexopt param count");
195        while (index < DEXOPT_PARAM_COUNT &&
196                argv[index + 1] != nullptr) {
197            package_parameters_[index] = argv[index + 1];
198            index++;
199        }
200        if (index != ARRAY_SIZE(package_parameters_) || argv[index + 1] != nullptr) {
201            LOG(ERROR) << "Wrong number of parameters";
202            return false;
203        }
204
205        return true;
206    }
207
208    void PrepareEnvironment() {
209        CHECK(system_properties_.GetProperty(kBootClassPathPropertyName) != nullptr);
210        const std::string& boot_cp =
211                *system_properties_.GetProperty(kBootClassPathPropertyName);
212        environ_.push_back(StringPrintf("BOOTCLASSPATH=%s", boot_cp.c_str()));
213        environ_.push_back(StringPrintf("ANDROID_DATA=%s", kOTADataDirectory));
214        CHECK(system_properties_.GetProperty(kAndroidRootPathPropertyName) != nullptr);
215        const std::string& android_root =
216                *system_properties_.GetProperty(kAndroidRootPathPropertyName);
217        environ_.push_back(StringPrintf("ANDROID_ROOT=%s", android_root.c_str()));
218
219        for (const std::string& e : environ_) {
220            putenv(const_cast<char*>(e.c_str()));
221        }
222    }
223
224    // Ensure that we have the right boot image. The first time any app is
225    // compiled, we'll try to generate it.
226    bool PrepareBootImage() {
227        if (package_parameters_[kISAIndex] == nullptr) {
228            LOG(ERROR) << "Instruction set missing.";
229            return false;
230        }
231        const char* isa = package_parameters_[kISAIndex];
232
233        // Check whether the file exists where expected.
234        std::string dalvik_cache = std::string(kOTADataDirectory) + "/" + DALVIK_CACHE;
235        std::string isa_path = dalvik_cache + "/" + isa;
236        std::string art_path = isa_path + "/system@framework@boot.art";
237        std::string oat_path = isa_path + "/system@framework@boot.oat";
238        if (access(art_path.c_str(), F_OK) == 0 &&
239                access(oat_path.c_str(), F_OK) == 0) {
240            // Files exist, assume everything is alright.
241            return true;
242        }
243
244        // Create the directories, if necessary.
245        if (access(dalvik_cache.c_str(), F_OK) != 0) {
246            if (mkdir(dalvik_cache.c_str(), 0711) != 0) {
247                PLOG(ERROR) << "Could not create dalvik-cache dir";
248                return false;
249            }
250        }
251        if (access(isa_path.c_str(), F_OK) != 0) {
252            if (mkdir(isa_path.c_str(), 0711) != 0) {
253                PLOG(ERROR) << "Could not create dalvik-cache isa dir";
254                return false;
255            }
256        }
257
258        // Prepare to create.
259        // TODO: Delete files, just for a blank slate.
260        const std::string& boot_cp = *system_properties_.GetProperty(kBootClassPathPropertyName);
261
262        std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
263        if (access(preopted_boot_art_path.c_str(), F_OK) == 0) {
264          return PatchoatBootImage(art_path, isa);
265        } else {
266          // No preopted boot image. Try to compile.
267          return Dex2oatBootImage(boot_cp, art_path, oat_path, isa);
268        }
269    }
270
271    bool PatchoatBootImage(const std::string& art_path, const char* isa) {
272        // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
273
274        std::vector<std::string> cmd;
275        cmd.push_back("/system/bin/patchoat");
276
277        cmd.push_back("--input-image-location=/system/framework/boot.art");
278        cmd.push_back(StringPrintf("--output-image-file=%s", art_path.c_str()));
279
280        cmd.push_back(StringPrintf("--instruction-set=%s", isa));
281
282        int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA,
283                                                          ART_BASE_ADDRESS_MAX_DELTA);
284        cmd.push_back(StringPrintf("--base-offset-delta=%d", base_offset));
285
286        std::string error_msg;
287        bool result = Exec(cmd, &error_msg);
288        if (!result) {
289            LOG(ERROR) << "Could not generate boot image: " << error_msg;
290        }
291        return result;
292    }
293
294    bool Dex2oatBootImage(const std::string& boot_cp,
295                          const std::string& art_path,
296                          const std::string& oat_path,
297                          const char* isa) {
298        // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
299        std::vector<std::string> cmd;
300        cmd.push_back("/system/bin/dex2oat");
301        cmd.push_back(StringPrintf("--image=%s", art_path.c_str()));
302        for (const std::string& boot_part : Split(boot_cp, ":")) {
303            cmd.push_back(StringPrintf("--dex-file=%s", boot_part.c_str()));
304        }
305        cmd.push_back(StringPrintf("--oat-file=%s", oat_path.c_str()));
306
307        int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA,
308                ART_BASE_ADDRESS_MAX_DELTA);
309        cmd.push_back(StringPrintf("--base=0x%x", ART_BASE_ADDRESS + base_offset));
310
311        cmd.push_back(StringPrintf("--instruction-set=%s", isa));
312
313        // These things are pushed by AndroidRuntime, see frameworks/base/core/jni/AndroidRuntime.cpp.
314        AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-Xms",
315                "-Xms",
316                true,
317                cmd);
318        AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-Xmx",
319                "-Xmx",
320                true,
321                cmd);
322        AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-filter",
323                "--compiler-filter=",
324                false,
325                cmd);
326        cmd.push_back("--image-classes=/system/etc/preloaded-classes");
327        // TODO: Compiled-classes.
328        const std::string* extra_opts =
329                system_properties_.GetProperty("dalvik.vm.image-dex2oat-flags");
330        if (extra_opts != nullptr) {
331            std::vector<std::string> extra_vals = Split(*extra_opts, " ");
332            cmd.insert(cmd.end(), extra_vals.begin(), extra_vals.end());
333        }
334        // TODO: Should we lower this? It's usually set close to max, because
335        //       normally there's not much else going on at boot.
336        AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-threads",
337                "-j",
338                false,
339                cmd);
340        AddCompilerOptionFromSystemProperty(
341                StringPrintf("dalvik.vm.isa.%s.variant", isa).c_str(),
342                "--instruction-set-variant=",
343                false,
344                cmd);
345        AddCompilerOptionFromSystemProperty(
346                StringPrintf("dalvik.vm.isa.%s.features", isa).c_str(),
347                "--instruction-set-features=",
348                false,
349                cmd);
350
351        std::string error_msg;
352        bool result = Exec(cmd, &error_msg);
353        if (!result) {
354            LOG(ERROR) << "Could not generate boot image: " << error_msg;
355        }
356        return result;
357    }
358
359    static const char* ParseNull(const char* arg) {
360        return (strcmp(arg, "!") == 0) ? nullptr : arg;
361    }
362
363    int RunPreopt() {
364        return dexopt(package_parameters_);
365    }
366
367    ////////////////////////////////////
368    // Helpers, mostly taken from ART //
369    ////////////////////////////////////
370
371    // Wrapper on fork/execv to run a command in a subprocess.
372    bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) {
373        const std::string command_line = Join(arg_vector, ' ');
374
375        CHECK_GE(arg_vector.size(), 1U) << command_line;
376
377        // Convert the args to char pointers.
378        const char* program = arg_vector[0].c_str();
379        std::vector<char*> args;
380        for (size_t i = 0; i < arg_vector.size(); ++i) {
381            const std::string& arg = arg_vector[i];
382            char* arg_str = const_cast<char*>(arg.c_str());
383            CHECK(arg_str != nullptr) << i;
384            args.push_back(arg_str);
385        }
386        args.push_back(nullptr);
387
388        // Fork and exec.
389        pid_t pid = fork();
390        if (pid == 0) {
391            // No allocation allowed between fork and exec.
392
393            // Change process groups, so we don't get reaped by ProcessManager.
394            setpgid(0, 0);
395
396            execv(program, &args[0]);
397
398            PLOG(ERROR) << "Failed to execv(" << command_line << ")";
399            // _exit to avoid atexit handlers in child.
400            _exit(1);
401        } else {
402            if (pid == -1) {
403                *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
404                        command_line.c_str(), strerror(errno));
405                return false;
406            }
407
408            // wait for subprocess to finish
409            int status;
410            pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
411            if (got_pid != pid) {
412                *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: "
413                        "wanted %d, got %d: %s",
414                        command_line.c_str(), pid, got_pid, strerror(errno));
415                return false;
416            }
417            if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
418                *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status",
419                        command_line.c_str());
420                return false;
421            }
422        }
423        return true;
424    }
425
426    // Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc.
427    static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
428        constexpr size_t kPageSize = PAGE_SIZE;
429        CHECK_EQ(min_delta % kPageSize, 0u);
430        CHECK_EQ(max_delta % kPageSize, 0u);
431        CHECK_LT(min_delta, max_delta);
432
433        std::default_random_engine generator;
434        generator.seed(GetSeed());
435        std::uniform_int_distribution<int32_t> distribution(min_delta, max_delta);
436        int32_t r = distribution(generator);
437        if (r % 2 == 0) {
438            r = RoundUp(r, kPageSize);
439        } else {
440            r = RoundDown(r, kPageSize);
441        }
442        CHECK_LE(min_delta, r);
443        CHECK_GE(max_delta, r);
444        CHECK_EQ(r % kPageSize, 0u);
445        return r;
446    }
447
448    static uint64_t GetSeed() {
449#ifdef __BIONIC__
450        // Bionic exposes arc4random, use it.
451        uint64_t random_data;
452        arc4random_buf(&random_data, sizeof(random_data));
453        return random_data;
454#else
455#error "This is only supposed to run with bionic. Otherwise, implement..."
456#endif
457    }
458
459    void AddCompilerOptionFromSystemProperty(const char* system_property,
460            const char* prefix,
461            bool runtime,
462            std::vector<std::string>& out) {
463        const std::string* value =
464        system_properties_.GetProperty(system_property);
465        if (value != nullptr) {
466            if (runtime) {
467                out.push_back("--runtime-arg");
468            }
469            if (prefix != nullptr) {
470                out.push_back(StringPrintf("%s%s", prefix, value->c_str()));
471            } else {
472                out.push_back(*value);
473            }
474        }
475    }
476
477    // Stores the system properties read out of the B partition. We need to use these properties
478    // to compile, instead of the A properties we could get from init/get_property.
479    SystemProperties system_properties_;
480
481    const char* package_parameters_[DEXOPT_PARAM_COUNT];
482
483    // Store environment values we need to set.
484    std::vector<std::string> environ_;
485};
486
487OTAPreoptService gOps;
488
489////////////////////////
490// Plug-in functions. //
491////////////////////////
492
493int get_property(const char *key, char *value, const char *default_value) {
494    // TODO: Replace with system-properties map.
495    return gOps.GetProperty(key, value, default_value);
496}
497
498// Compute the output path of
499bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir,
500                             const char *apk_path,
501                             const char *instruction_set) {
502    // TODO: Insert B directory.
503    const char *file_name_start;
504    const char *file_name_end;
505
506    file_name_start = strrchr(apk_path, '/');
507    if (file_name_start == nullptr) {
508        ALOGE("apk_path '%s' has no '/'s in it\n", apk_path);
509        return false;
510    }
511    file_name_end = strrchr(file_name_start, '.');
512    if (file_name_end == nullptr) {
513        ALOGE("apk_path '%s' has no extension\n", apk_path);
514        return false;
515    }
516
517    // Calculate file_name
518    file_name_start++;  // Move past '/', is valid as file_name_end is valid.
519    size_t file_name_len = file_name_end - file_name_start;
520    std::string file_name(file_name_start, file_name_len);
521
522    // <apk_parent_dir>/oat/<isa>/<file_name>.odex.b
523    snprintf(path, PKG_PATH_MAX, "%s/%s/%s.odex.b", oat_dir, instruction_set,
524             file_name.c_str());
525    return true;
526}
527
528/*
529 * Computes the odex file for the given apk_path and instruction_set.
530 * /system/framework/whatever.jar -> /system/framework/oat/<isa>/whatever.odex
531 *
532 * Returns false if it failed to determine the odex file path.
533 */
534bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
535                              const char *instruction_set) {
536    if (StringPrintf("%soat/%s/odex.b", apk_path, instruction_set).length() + 1 > PKG_PATH_MAX) {
537        ALOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path);
538        return false;
539    }
540
541    const char *path_end = strrchr(apk_path, '/');
542    if (path_end == nullptr) {
543        ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
544        return false;
545    }
546    std::string path_component(apk_path, path_end - apk_path);
547
548    const char *name_begin = path_end + 1;
549    const char *extension_start = strrchr(name_begin, '.');
550    if (extension_start == nullptr) {
551        ALOGE("apk_path '%s' has no extension.\n", apk_path);
552        return false;
553    }
554    std::string name_component(name_begin, extension_start - name_begin);
555
556    std::string new_path = StringPrintf("%s/oat/%s/%s.odex.b",
557                                        path_component.c_str(),
558                                        instruction_set,
559                                        name_component.c_str());
560    CHECK_LT(new_path.length(), PKG_PATH_MAX);
561    strcpy(path, new_path.c_str());
562    return true;
563}
564
565bool create_cache_path(char path[PKG_PATH_MAX],
566                       const char *src,
567                       const char *instruction_set) {
568    size_t srclen = strlen(src);
569
570        /* demand that we are an absolute path */
571    if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
572        return false;
573    }
574
575    if (srclen > PKG_PATH_MAX) {        // XXX: PKG_NAME_MAX?
576        return false;
577    }
578
579    std::string from_src = std::string(src + 1);
580    std::replace(from_src.begin(), from_src.end(), '/', '@');
581
582    std::string assembled_path = StringPrintf("%s/%s/%s/%s%s",
583                                              OTAPreoptService::kOTADataDirectory,
584                                              DALVIK_CACHE,
585                                              instruction_set,
586                                              from_src.c_str(),
587                                              DALVIK_CACHE_POSTFIX2);
588
589    if (assembled_path.length() + 1 > PKG_PATH_MAX) {
590        return false;
591    }
592    strcpy(path, assembled_path.c_str());
593
594    return true;
595}
596
597bool initialize_globals() {
598    const char* data_path = getenv("ANDROID_DATA");
599    if (data_path == nullptr) {
600        ALOGE("Could not find ANDROID_DATA");
601        return false;
602    }
603    return init_globals_from_data_and_root(data_path, kOTARootDirectory);
604}
605
606static bool initialize_directories() {
607    // This is different from the normal installd. We only do the base
608    // directory, the rest will be created on demand when each app is compiled.
609    mode_t old_umask = umask(0);
610    LOG(INFO) << "Old umask: " << old_umask;
611    if (access(OTAPreoptService::kOTADataDirectory, R_OK) < 0) {
612        ALOGE("Could not access %s\n", OTAPreoptService::kOTADataDirectory);
613        return false;
614    }
615    return true;
616}
617
618static int log_callback(int type, const char *fmt, ...) {
619    va_list ap;
620    int priority;
621
622    switch (type) {
623        case SELINUX_WARNING:
624            priority = ANDROID_LOG_WARN;
625            break;
626        case SELINUX_INFO:
627            priority = ANDROID_LOG_INFO;
628            break;
629        default:
630            priority = ANDROID_LOG_ERROR;
631            break;
632    }
633    va_start(ap, fmt);
634    LOG_PRI_VA(priority, "SELinux", fmt, ap);
635    va_end(ap);
636    return 0;
637}
638
639static int otapreopt_main(const int argc, char *argv[]) {
640    int selinux_enabled = (is_selinux_enabled() > 0);
641
642    setenv("ANDROID_LOG_TAGS", "*:v", 1);
643    android::base::InitLogging(argv);
644
645    ALOGI("otapreopt firing up\n");
646
647    if (argc < 2) {
648        ALOGE("Expecting parameters");
649        exit(1);
650    }
651
652    union selinux_callback cb;
653    cb.func_log = log_callback;
654    selinux_set_callback(SELINUX_CB_LOG, cb);
655
656    if (!initialize_globals()) {
657        ALOGE("Could not initialize globals; exiting.\n");
658        exit(1);
659    }
660
661    if (!initialize_directories()) {
662        ALOGE("Could not create directories; exiting.\n");
663        exit(1);
664    }
665
666    if (selinux_enabled && selinux_status_open(true) < 0) {
667        ALOGE("Could not open selinux status; exiting.\n");
668        exit(1);
669    }
670
671    int ret = android::installd::gOps.Main(argc, argv);
672
673    return ret;
674}
675
676}  // namespace installd
677}  // namespace android
678
679int main(const int argc, char *argv[]) {
680    return android::installd::otapreopt_main(argc, argv);
681}
682