blob: f8d6016315f76976eedb4f1f8c8a24211902461a [file] [log] [blame]
David Sehr891a50e2017-10-27 17:01:07 -07001/*
2 * Copyright (C) 2011 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 "file_utils.h"
18
19#include <inttypes.h>
David Sehr891a50e2017-10-27 17:01:07 -070020#include <sys/stat.h>
David Sehr891a50e2017-10-27 17:01:07 -070021#include <sys/types.h>
22#include <sys/wait.h>
23#include <unistd.h>
24
25// We need dladdr.
26#ifndef __APPLE__
27#ifndef _GNU_SOURCE
28#define _GNU_SOURCE
29#define DEFINED_GNU_SOURCE
30#endif
31#include <dlfcn.h>
32#include <libgen.h>
33#ifdef DEFINED_GNU_SOURCE
34#undef _GNU_SOURCE
35#undef DEFINED_GNU_SOURCE
36#endif
37#endif
38
39
40#include <memory>
41
42#include "android-base/stringprintf.h"
43#include "android-base/strings.h"
44
David Sehrb2ec9f52018-02-21 13:20:31 -080045#include "base/bit_utils.h"
David Sehr1979c642018-04-26 14:41:18 -070046#include "base/globals.h"
David Sehrc431b9d2018-03-02 12:01:51 -080047#include "base/os.h"
David Sehr1979c642018-04-26 14:41:18 -070048#include "base/stl_util.h"
David Sehr891a50e2017-10-27 17:01:07 -070049#include "base/unix_file/fd_file.h"
David Sehr891a50e2017-10-27 17:01:07 -070050
51#if defined(__APPLE__)
52#include <crt_externs.h>
53#include <sys/syscall.h>
54#include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED
55#endif
56
57#if defined(__linux__)
58#include <linux/unistd.h>
59#endif
60
61namespace art {
62
David Sehr891a50e2017-10-27 17:01:07 -070063using android::base::StringPrintf;
64
David Sehrc3e18952018-05-11 16:59:31 -070065static constexpr const char* kClassesDex = "classes.dex";
66
David Sehr891a50e2017-10-27 17:01:07 -070067bool ReadFileToString(const std::string& file_name, std::string* result) {
68 File file(file_name, O_RDONLY, false);
69 if (!file.IsOpened()) {
70 return false;
71 }
72
73 std::vector<char> buf(8 * KB);
74 while (true) {
75 int64_t n = TEMP_FAILURE_RETRY(read(file.Fd(), &buf[0], buf.size()));
76 if (n == -1) {
77 return false;
78 }
79 if (n == 0) {
80 return true;
81 }
82 result->append(&buf[0], n);
83 }
84}
85
David Sehr891a50e2017-10-27 17:01:07 -070086std::string GetAndroidRootSafe(std::string* error_msg) {
87 // Prefer ANDROID_ROOT if it's set.
88 const char* android_dir = getenv("ANDROID_ROOT");
89 if (android_dir != nullptr) {
90 if (!OS::DirectoryExists(android_dir)) {
91 *error_msg = StringPrintf("Failed to find ANDROID_ROOT directory %s", android_dir);
92 return "";
93 }
94 return android_dir;
95 }
96
97 // Check where libart is from, and derive from there. Only do this for non-Mac.
98#ifndef __APPLE__
99 {
100 Dl_info info;
101 if (dladdr(reinterpret_cast<const void*>(&GetAndroidRootSafe), /* out */ &info) != 0) {
102 // Make a duplicate of the fname so dirname can modify it.
103 UniqueCPtr<char> fname(strdup(info.dli_fname));
104
105 char* dir1 = dirname(fname.get()); // This is the lib directory.
106 char* dir2 = dirname(dir1); // This is the "system" directory.
107 if (OS::DirectoryExists(dir2)) {
108 std::string tmp = dir2; // Make a copy here so that fname can be released.
109 return tmp;
110 }
111 }
112 }
113#endif
114
115 // Try "/system".
116 if (!OS::DirectoryExists("/system")) {
117 *error_msg = "Failed to find ANDROID_ROOT directory /system";
118 return "";
119 }
120 return "/system";
121}
122
123std::string GetAndroidRoot() {
124 std::string error_msg;
125 std::string ret = GetAndroidRootSafe(&error_msg);
126 if (ret.empty()) {
127 LOG(FATAL) << error_msg;
128 UNREACHABLE();
129 }
130 return ret;
131}
132
133
134static const char* GetAndroidDirSafe(const char* env_var,
135 const char* default_dir,
136 std::string* error_msg) {
137 const char* android_dir = getenv(env_var);
138 if (android_dir == nullptr) {
139 if (OS::DirectoryExists(default_dir)) {
140 android_dir = default_dir;
141 } else {
142 *error_msg = StringPrintf("%s not set and %s does not exist", env_var, default_dir);
143 return nullptr;
144 }
145 }
146 if (!OS::DirectoryExists(android_dir)) {
147 *error_msg = StringPrintf("Failed to find %s directory %s", env_var, android_dir);
148 return nullptr;
149 }
150 return android_dir;
151}
152
153static const char* GetAndroidDir(const char* env_var, const char* default_dir) {
154 std::string error_msg;
155 const char* dir = GetAndroidDirSafe(env_var, default_dir, &error_msg);
156 if (dir != nullptr) {
157 return dir;
158 } else {
159 LOG(FATAL) << error_msg;
Elliott Hughesc1896c92018-11-29 11:33:18 -0800160 UNREACHABLE();
David Sehr891a50e2017-10-27 17:01:07 -0700161 }
162}
163
164const char* GetAndroidData() {
165 return GetAndroidDir("ANDROID_DATA", "/data");
166}
167
168const char* GetAndroidDataSafe(std::string* error_msg) {
169 return GetAndroidDirSafe("ANDROID_DATA", "/data", error_msg);
170}
171
172std::string GetDefaultBootImageLocation(std::string* error_msg) {
173 std::string android_root = GetAndroidRootSafe(error_msg);
174 if (android_root.empty()) {
175 return "";
176 }
177 return StringPrintf("%s/framework/boot.art", android_root.c_str());
178}
179
180void GetDalvikCache(const char* subdir, const bool create_if_absent, std::string* dalvik_cache,
181 bool* have_android_data, bool* dalvik_cache_exists, bool* is_global_cache) {
182 CHECK(subdir != nullptr);
183 std::string error_msg;
184 const char* android_data = GetAndroidDataSafe(&error_msg);
185 if (android_data == nullptr) {
186 *have_android_data = false;
187 *dalvik_cache_exists = false;
188 *is_global_cache = false;
189 return;
190 } else {
191 *have_android_data = true;
192 }
193 const std::string dalvik_cache_root(StringPrintf("%s/dalvik-cache/", android_data));
194 *dalvik_cache = dalvik_cache_root + subdir;
195 *dalvik_cache_exists = OS::DirectoryExists(dalvik_cache->c_str());
196 *is_global_cache = strcmp(android_data, "/data") == 0;
197 if (create_if_absent && !*dalvik_cache_exists && !*is_global_cache) {
198 // Don't create the system's /data/dalvik-cache/... because it needs special permissions.
199 *dalvik_cache_exists = ((mkdir(dalvik_cache_root.c_str(), 0700) == 0 || errno == EEXIST) &&
200 (mkdir(dalvik_cache->c_str(), 0700) == 0 || errno == EEXIST));
201 }
202}
203
204std::string GetDalvikCache(const char* subdir) {
205 CHECK(subdir != nullptr);
206 const char* android_data = GetAndroidData();
207 const std::string dalvik_cache_root(StringPrintf("%s/dalvik-cache/", android_data));
208 const std::string dalvik_cache = dalvik_cache_root + subdir;
209 if (!OS::DirectoryExists(dalvik_cache.c_str())) {
210 // TODO: Check callers. Traditional behavior is to not abort.
211 return "";
212 }
213 return dalvik_cache;
214}
215
216bool GetDalvikCacheFilename(const char* location, const char* cache_location,
217 std::string* filename, std::string* error_msg) {
218 if (location[0] != '/') {
219 *error_msg = StringPrintf("Expected path in location to be absolute: %s", location);
220 return false;
221 }
222 std::string cache_file(&location[1]); // skip leading slash
223 if (!android::base::EndsWith(location, ".dex") &&
224 !android::base::EndsWith(location, ".art") &&
225 !android::base::EndsWith(location, ".oat")) {
226 cache_file += "/";
David Sehrc3e18952018-05-11 16:59:31 -0700227 cache_file += kClassesDex;
David Sehr891a50e2017-10-27 17:01:07 -0700228 }
229 std::replace(cache_file.begin(), cache_file.end(), '/', '@');
230 *filename = StringPrintf("%s/%s", cache_location, cache_file.c_str());
231 return true;
232}
233
234std::string GetVdexFilename(const std::string& oat_location) {
235 return ReplaceFileExtension(oat_location, "vdex");
236}
237
238static void InsertIsaDirectory(const InstructionSet isa, std::string* filename) {
239 // in = /foo/bar/baz
240 // out = /foo/bar/<isa>/baz
241 size_t pos = filename->rfind('/');
242 CHECK_NE(pos, std::string::npos) << *filename << " " << isa;
243 filename->insert(pos, "/", 1);
244 filename->insert(pos + 1, GetInstructionSetString(isa));
245}
246
247std::string GetSystemImageFilename(const char* location, const InstructionSet isa) {
248 // location = /system/framework/boot.art
249 // filename = /system/framework/<isa>/boot.art
250 std::string filename(location);
251 InsertIsaDirectory(isa, &filename);
252 return filename;
253}
254
David Sehr891a50e2017-10-27 17:01:07 -0700255std::string ReplaceFileExtension(const std::string& filename, const std::string& new_extension) {
Vladimir Marko62c2d712018-03-09 12:54:05 +0000256 const size_t last_ext = filename.find_last_of("./");
257 if (last_ext == std::string::npos || filename[last_ext] != '.') {
David Sehr891a50e2017-10-27 17:01:07 -0700258 return filename + "." + new_extension;
259 } else {
260 return filename.substr(0, last_ext + 1) + new_extension;
261 }
262}
263
Nicolas Geoffray0d0f3162018-05-10 12:55:40 +0100264bool LocationIsOnSystem(const char* path) {
265 UniqueCPtr<const char[]> full_path(realpath(path, nullptr));
Nicolas Geoffraye64d58c2018-05-21 14:17:59 +0100266 return full_path != nullptr &&
267 android::base::StartsWith(full_path.get(), GetAndroidRoot().c_str());
Nicolas Geoffray29742602017-12-14 10:09:03 +0000268}
269
Nicolas Geoffray0d0f3162018-05-10 12:55:40 +0100270bool LocationIsOnSystemFramework(const char* full_path) {
David Brazdil8e1a7cb2018-03-27 08:14:25 +0000271 std::string error_msg;
272 std::string root_path = GetAndroidRootSafe(&error_msg);
273 if (root_path.empty()) {
274 // Could not find Android root.
275 // TODO(dbrazdil): change to stricter GetAndroidRoot() once b/76452688 is resolved.
276 return false;
277 }
278 std::string framework_path = root_path + "/framework/";
Nicolas Geoffray0d0f3162018-05-10 12:55:40 +0100279 return android::base::StartsWith(full_path, framework_path);
David Brazdil8e1a7cb2018-03-27 08:14:25 +0000280}
281
Josh Gao35696a02018-08-30 17:24:16 -0700282int DupCloexec(int fd) {
283#if defined(__linux__)
284 return fcntl(fd, F_DUPFD_CLOEXEC, 0);
285#else
286 return dup(fd);
287#endif
288}
289
David Sehr891a50e2017-10-27 17:01:07 -0700290} // namespace art