• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 namespace {
37 
38 using ::android::base::unique_fd;
39 
40 constexpr int kTimeoutMs = 300000;
41 
42 } // namespace
43 
view_compiler(const char * apk_path,const char * package_name,const char * out_dex_file,int uid)44 bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
45                    int uid) {
46     CHECK(apk_path != nullptr);
47     CHECK(package_name != nullptr);
48     CHECK(out_dex_file != nullptr);
49 
50     // viewcompiler won't have permission to open anything, so we have to open the files first
51     // and pass file descriptors.
52 
53     // Open input file
54     unique_fd infd{open(apk_path, O_RDONLY)}; // NOLINT(android-cloexec-open)
55     if (infd.get() < 0) {
56         PLOG(ERROR) << "Could not open input file: " << apk_path;
57         return false;
58     }
59 
60     // Set up output file. viewcompiler can't open outputs by fd, but it can write to stdout, so
61     // we close stdout and open it towards the right output.
62     unique_fd outfd{open(out_dex_file, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644)};
63     if (outfd.get() < 0) {
64         PLOG(ERROR) << "Could not open output file: " << out_dex_file;
65         return false;
66     }
67     if (fchmod(outfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0) {
68         PLOG(ERROR) << "Could not change output file permissions";
69         return false;
70     }
71     if (dup2(outfd, STDOUT_FILENO) < 0) {
72         PLOG(ERROR) << "Could not duplicate output file descriptor";
73         return false;
74     }
75 
76     // Prepare command line arguments for viewcompiler
77     std::string args[] = {"/system/bin/viewcompiler",
78                           "--apk",
79                           "--infd",
80                           android::base::StringPrintf("%d", infd.get()),
81                           "--dex",
82                           "--package",
83                           package_name};
84     char* const argv[] = {const_cast<char*>(args[0].c_str()), const_cast<char*>(args[1].c_str()),
85                           const_cast<char*>(args[2].c_str()), const_cast<char*>(args[3].c_str()),
86                           const_cast<char*>(args[4].c_str()), const_cast<char*>(args[5].c_str()),
87                           const_cast<char*>(args[6].c_str()), nullptr};
88 
89     pid_t pid = fork();
90     if (pid == 0) {
91         // Now that we've opened the files we need, drop privileges.
92         drop_capabilities(uid);
93         execv("/system/bin/viewcompiler", argv);
94         _exit(1);
95     }
96 
97     int return_code = wait_child_with_timeout(pid, kTimeoutMs);
98     if (!WIFEXITED(return_code)) {
99         LOG(WARNING) << "viewcompiler failed for " << package_name << ":" << apk_path;
100         if (WTERMSIG(return_code) == SIGKILL) {
101             // If the subprocess is killed while it's writing to the file, the file is likely
102             // corrupted, so we should remove it.
103             remove_file_at_fd(outfd.get());
104         }
105         return false;
106     }
107     return WEXITSTATUS(return_code) == 0;
108 }
109 
110 } // namespace installd
111 } // namespace android
112