Home | History | Annotate | Download | only in installd
      1 /*
      2  * Copyright (C) 2019 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 "view_compiler.h"
     18 
     19 #include <string>
     20 
     21 #include <fcntl.h>
     22 #include <sys/stat.h>
     23 #include <sys/types.h>
     24 #include <sys/wait.h>
     25 #include <unistd.h>
     26 
     27 #include "utils.h"
     28 
     29 #include "android-base/logging.h"
     30 #include "android-base/stringprintf.h"
     31 #include "android-base/unique_fd.h"
     32 
     33 namespace android {
     34 namespace installd {
     35 
     36 using base::unique_fd;
     37 
     38 bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
     39                    int uid) {
     40     CHECK(apk_path != nullptr);
     41     CHECK(package_name != nullptr);
     42     CHECK(out_dex_file != nullptr);
     43 
     44     // viewcompiler won't have permission to open anything, so we have to open the files first
     45     // and pass file descriptors.
     46 
     47     // Open input file
     48     unique_fd infd{open(apk_path, O_RDONLY)}; // NOLINT(android-cloexec-open)
     49     if (infd.get() < 0) {
     50         PLOG(ERROR) << "Could not open input file: " << apk_path;
     51         return false;
     52     }
     53 
     54     // Set up output file. viewcompiler can't open outputs by fd, but it can write to stdout, so
     55     // we close stdout and open it towards the right output.
     56     unique_fd outfd{open(out_dex_file, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644)};
     57     if (outfd.get() < 0) {
     58         PLOG(ERROR) << "Could not open output file: " << out_dex_file;
     59         return false;
     60     }
     61     if (fchmod(outfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0) {
     62         PLOG(ERROR) << "Could not change output file permissions";
     63         return false;
     64     }
     65     if (dup2(outfd, STDOUT_FILENO) < 0) {
     66         PLOG(ERROR) << "Could not duplicate output file descriptor";
     67         return false;
     68     }
     69 
     70     // Prepare command line arguments for viewcompiler
     71     std::string args[] = {"/system/bin/viewcompiler",
     72                           "--apk",
     73                           "--infd",
     74                           android::base::StringPrintf("%d", infd.get()),
     75                           "--dex",
     76                           "--package",
     77                           package_name};
     78     char* const argv[] = {const_cast<char*>(args[0].c_str()), const_cast<char*>(args[1].c_str()),
     79                           const_cast<char*>(args[2].c_str()), const_cast<char*>(args[3].c_str()),
     80                           const_cast<char*>(args[4].c_str()), const_cast<char*>(args[5].c_str()),
     81                           const_cast<char*>(args[6].c_str()), nullptr};
     82 
     83     pid_t pid = fork();
     84     if (pid == 0) {
     85         // Now that we've opened the files we need, drop privileges.
     86         drop_capabilities(uid);
     87         execv("/system/bin/viewcompiler", argv);
     88         _exit(1);
     89     }
     90 
     91     return wait_child(pid) == 0;
     92 }
     93 
     94 } // namespace installd
     95 } // namespace android
     96