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
view_compiler(const char * apk_path,const char * package_name,const char * out_dex_file,int uid)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