blob: 865c8a6a85bd3ffd3670d30fd63c7084b4bb805f [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>
David Sehr10db8fe2018-07-18 11:01:20 -070022#ifndef _WIN32
David Sehr891a50e2017-10-27 17:01:07 -070023#include <sys/wait.h>
David Sehr10db8fe2018-07-18 11:01:20 -070024#endif
David Sehr891a50e2017-10-27 17:01:07 -070025#include <unistd.h>
26
27// We need dladdr.
David Sehr10db8fe2018-07-18 11:01:20 -070028#if !defined(__APPLE__) && !defined(_WIN32)
David Sehr891a50e2017-10-27 17:01:07 -070029#ifndef _GNU_SOURCE
30#define _GNU_SOURCE
31#define DEFINED_GNU_SOURCE
32#endif
33#include <dlfcn.h>
34#include <libgen.h>
35#ifdef DEFINED_GNU_SOURCE
36#undef _GNU_SOURCE
37#undef DEFINED_GNU_SOURCE
38#endif
39#endif
40
41
42#include <memory>
43
44#include "android-base/stringprintf.h"
45#include "android-base/strings.h"
46
David Sehrb2ec9f52018-02-21 13:20:31 -080047#include "base/bit_utils.h"
David Sehr1979c642018-04-26 14:41:18 -070048#include "base/globals.h"
David Sehrc431b9d2018-03-02 12:01:51 -080049#include "base/os.h"
David Sehr1979c642018-04-26 14:41:18 -070050#include "base/stl_util.h"
David Sehr891a50e2017-10-27 17:01:07 -070051#include "base/unix_file/fd_file.h"
David Sehr891a50e2017-10-27 17:01:07 -070052
53#if defined(__APPLE__)
54#include <crt_externs.h>
55#include <sys/syscall.h>
56#include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED
57#endif
58
59#if defined(__linux__)
60#include <linux/unistd.h>
61#endif
62
63namespace art {
64
David Sehr891a50e2017-10-27 17:01:07 -070065using android::base::StringPrintf;
66
David Sehrc3e18952018-05-11 16:59:31 -070067static constexpr const char* kClassesDex = "classes.dex";
David Brazdile7e26d12019-02-28 15:04:14 +000068static constexpr const char* kApexDefaultPath = "/apex/";
69static constexpr const char* kRuntimeApexEnvVar = "ANDROID_RUNTIME_ROOT";
70static constexpr const char* kRuntimeApexDefaultPath = "/apex/com.android.runtime";
David Brazdil3c839212019-03-04 14:29:50 +000071static constexpr const char* kConscryptApexEnvVar = "ANDROID_CONSCRYPT_ROOT";
72static constexpr const char* kConscryptApexDefaultPath = "/apex/com.android.conscrypt";
David Sehrc3e18952018-05-11 16:59:31 -070073
David Sehr891a50e2017-10-27 17:01:07 -070074bool ReadFileToString(const std::string& file_name, std::string* result) {
75 File file(file_name, O_RDONLY, false);
76 if (!file.IsOpened()) {
77 return false;
78 }
79
80 std::vector<char> buf(8 * KB);
81 while (true) {
82 int64_t n = TEMP_FAILURE_RETRY(read(file.Fd(), &buf[0], buf.size()));
83 if (n == -1) {
84 return false;
85 }
86 if (n == 0) {
87 return true;
88 }
89 result->append(&buf[0], n);
90 }
91}
92
David Sehr891a50e2017-10-27 17:01:07 -070093std::string GetAndroidRootSafe(std::string* error_msg) {
David Sehr10db8fe2018-07-18 11:01:20 -070094#ifdef _WIN32
95 *error_msg = "GetAndroidRootSafe unsupported for Windows.";
96 return "";
97#else
David Sehr891a50e2017-10-27 17:01:07 -070098 // Prefer ANDROID_ROOT if it's set.
99 const char* android_dir = getenv("ANDROID_ROOT");
100 if (android_dir != nullptr) {
101 if (!OS::DirectoryExists(android_dir)) {
102 *error_msg = StringPrintf("Failed to find ANDROID_ROOT directory %s", android_dir);
103 return "";
104 }
105 return android_dir;
106 }
107
108 // Check where libart is from, and derive from there. Only do this for non-Mac.
109#ifndef __APPLE__
110 {
111 Dl_info info;
112 if (dladdr(reinterpret_cast<const void*>(&GetAndroidRootSafe), /* out */ &info) != 0) {
113 // Make a duplicate of the fname so dirname can modify it.
114 UniqueCPtr<char> fname(strdup(info.dli_fname));
115
116 char* dir1 = dirname(fname.get()); // This is the lib directory.
117 char* dir2 = dirname(dir1); // This is the "system" directory.
118 if (OS::DirectoryExists(dir2)) {
119 std::string tmp = dir2; // Make a copy here so that fname can be released.
120 return tmp;
121 }
122 }
123 }
124#endif
125
126 // Try "/system".
127 if (!OS::DirectoryExists("/system")) {
128 *error_msg = "Failed to find ANDROID_ROOT directory /system";
129 return "";
130 }
131 return "/system";
David Sehr10db8fe2018-07-18 11:01:20 -0700132#endif
David Sehr891a50e2017-10-27 17:01:07 -0700133}
134
135std::string GetAndroidRoot() {
136 std::string error_msg;
137 std::string ret = GetAndroidRootSafe(&error_msg);
138 if (ret.empty()) {
139 LOG(FATAL) << error_msg;
140 UNREACHABLE();
141 }
142 return ret;
143}
144
145
146static const char* GetAndroidDirSafe(const char* env_var,
147 const char* default_dir,
148 std::string* error_msg) {
149 const char* android_dir = getenv(env_var);
150 if (android_dir == nullptr) {
151 if (OS::DirectoryExists(default_dir)) {
152 android_dir = default_dir;
153 } else {
154 *error_msg = StringPrintf("%s not set and %s does not exist", env_var, default_dir);
155 return nullptr;
156 }
157 }
158 if (!OS::DirectoryExists(android_dir)) {
159 *error_msg = StringPrintf("Failed to find %s directory %s", env_var, android_dir);
160 return nullptr;
161 }
162 return android_dir;
163}
164
165static const char* GetAndroidDir(const char* env_var, const char* default_dir) {
166 std::string error_msg;
167 const char* dir = GetAndroidDirSafe(env_var, default_dir, &error_msg);
168 if (dir != nullptr) {
169 return dir;
170 } else {
171 LOG(FATAL) << error_msg;
Elliott Hughesc1896c92018-11-29 11:33:18 -0800172 UNREACHABLE();
David Sehr891a50e2017-10-27 17:01:07 -0700173 }
174}
175
176const char* GetAndroidData() {
177 return GetAndroidDir("ANDROID_DATA", "/data");
178}
179
180const char* GetAndroidDataSafe(std::string* error_msg) {
181 return GetAndroidDirSafe("ANDROID_DATA", "/data", error_msg);
182}
183
Nicolas Geoffrayde1b2a22019-02-27 09:10:57 +0000184std::string GetDefaultBootImageLocation(const std::string& android_root) {
185 return StringPrintf("%s/framework/boot.art", android_root.c_str());
186}
187
David Sehr891a50e2017-10-27 17:01:07 -0700188std::string GetDefaultBootImageLocation(std::string* error_msg) {
189 std::string android_root = GetAndroidRootSafe(error_msg);
190 if (android_root.empty()) {
191 return "";
192 }
Nicolas Geoffrayde1b2a22019-02-27 09:10:57 +0000193 return GetDefaultBootImageLocation(android_root);
David Sehr891a50e2017-10-27 17:01:07 -0700194}
195
196void GetDalvikCache(const char* subdir, const bool create_if_absent, std::string* dalvik_cache,
197 bool* have_android_data, bool* dalvik_cache_exists, bool* is_global_cache) {
David Sehr10db8fe2018-07-18 11:01:20 -0700198#ifdef _WIN32
199 UNUSED(subdir);
200 UNUSED(create_if_absent);
201 UNUSED(dalvik_cache);
202 UNUSED(have_android_data);
203 UNUSED(dalvik_cache_exists);
204 UNUSED(is_global_cache);
205 LOG(FATAL) << "GetDalvikCache unsupported on Windows.";
206#else
David Sehr891a50e2017-10-27 17:01:07 -0700207 CHECK(subdir != nullptr);
208 std::string error_msg;
209 const char* android_data = GetAndroidDataSafe(&error_msg);
210 if (android_data == nullptr) {
211 *have_android_data = false;
212 *dalvik_cache_exists = false;
213 *is_global_cache = false;
214 return;
215 } else {
216 *have_android_data = true;
217 }
218 const std::string dalvik_cache_root(StringPrintf("%s/dalvik-cache/", android_data));
219 *dalvik_cache = dalvik_cache_root + subdir;
220 *dalvik_cache_exists = OS::DirectoryExists(dalvik_cache->c_str());
221 *is_global_cache = strcmp(android_data, "/data") == 0;
222 if (create_if_absent && !*dalvik_cache_exists && !*is_global_cache) {
223 // Don't create the system's /data/dalvik-cache/... because it needs special permissions.
224 *dalvik_cache_exists = ((mkdir(dalvik_cache_root.c_str(), 0700) == 0 || errno == EEXIST) &&
225 (mkdir(dalvik_cache->c_str(), 0700) == 0 || errno == EEXIST));
226 }
David Sehr10db8fe2018-07-18 11:01:20 -0700227#endif
David Sehr891a50e2017-10-27 17:01:07 -0700228}
229
230std::string GetDalvikCache(const char* subdir) {
231 CHECK(subdir != nullptr);
232 const char* android_data = GetAndroidData();
233 const std::string dalvik_cache_root(StringPrintf("%s/dalvik-cache/", android_data));
234 const std::string dalvik_cache = dalvik_cache_root + subdir;
235 if (!OS::DirectoryExists(dalvik_cache.c_str())) {
236 // TODO: Check callers. Traditional behavior is to not abort.
237 return "";
238 }
239 return dalvik_cache;
240}
241
242bool GetDalvikCacheFilename(const char* location, const char* cache_location,
243 std::string* filename, std::string* error_msg) {
244 if (location[0] != '/') {
245 *error_msg = StringPrintf("Expected path in location to be absolute: %s", location);
246 return false;
247 }
248 std::string cache_file(&location[1]); // skip leading slash
249 if (!android::base::EndsWith(location, ".dex") &&
250 !android::base::EndsWith(location, ".art") &&
251 !android::base::EndsWith(location, ".oat")) {
252 cache_file += "/";
David Sehrc3e18952018-05-11 16:59:31 -0700253 cache_file += kClassesDex;
David Sehr891a50e2017-10-27 17:01:07 -0700254 }
255 std::replace(cache_file.begin(), cache_file.end(), '/', '@');
256 *filename = StringPrintf("%s/%s", cache_location, cache_file.c_str());
257 return true;
258}
259
260std::string GetVdexFilename(const std::string& oat_location) {
261 return ReplaceFileExtension(oat_location, "vdex");
262}
263
264static void InsertIsaDirectory(const InstructionSet isa, std::string* filename) {
265 // in = /foo/bar/baz
266 // out = /foo/bar/<isa>/baz
267 size_t pos = filename->rfind('/');
268 CHECK_NE(pos, std::string::npos) << *filename << " " << isa;
269 filename->insert(pos, "/", 1);
270 filename->insert(pos + 1, GetInstructionSetString(isa));
271}
272
273std::string GetSystemImageFilename(const char* location, const InstructionSet isa) {
274 // location = /system/framework/boot.art
275 // filename = /system/framework/<isa>/boot.art
276 std::string filename(location);
277 InsertIsaDirectory(isa, &filename);
278 return filename;
279}
280
David Sehr891a50e2017-10-27 17:01:07 -0700281std::string ReplaceFileExtension(const std::string& filename, const std::string& new_extension) {
Vladimir Marko62c2d712018-03-09 12:54:05 +0000282 const size_t last_ext = filename.find_last_of("./");
283 if (last_ext == std::string::npos || filename[last_ext] != '.') {
David Sehr891a50e2017-10-27 17:01:07 -0700284 return filename + "." + new_extension;
285 } else {
286 return filename.substr(0, last_ext + 1) + new_extension;
287 }
288}
289
David Brazdil3c839212019-03-04 14:29:50 +0000290static bool IsLocationOnModule(const char* full_path,
291 const char* env_var,
292 const char* default_path) {
Orion Hodson12162de2019-01-21 16:01:30 +0000293 std::string error_msg;
David Brazdil3c839212019-03-04 14:29:50 +0000294 const char* module_path = GetAndroidDirSafe(env_var, default_path, &error_msg);
295 if (module_path == nullptr) {
Orion Hodson12162de2019-01-21 16:01:30 +0000296 return false;
297 }
David Brazdil3c839212019-03-04 14:29:50 +0000298 return android::base::StartsWith(full_path, module_path);
299}
300
301bool LocationIsOnRuntimeModule(const char* full_path) {
302 return IsLocationOnModule(full_path, kRuntimeApexEnvVar, kRuntimeApexDefaultPath);
303}
304
305bool LocationIsOnConscryptModule(const char* full_path) {
306 return IsLocationOnModule(full_path, kConscryptApexEnvVar, kConscryptApexDefaultPath);
Orion Hodson12162de2019-01-21 16:01:30 +0000307}
308
David Brazdile7e26d12019-02-28 15:04:14 +0000309bool LocationIsOnApex(const char* full_path) {
310 return android::base::StartsWith(full_path, kApexDefaultPath);
311}
312
Nicolas Geoffray0d0f3162018-05-10 12:55:40 +0100313bool LocationIsOnSystem(const char* path) {
David Sehr10db8fe2018-07-18 11:01:20 -0700314#ifdef _WIN32
315 UNUSED(path);
316 LOG(FATAL) << "LocationIsOnSystem is unsupported on Windows.";
317 return false;
318#else
Nicolas Geoffray0d0f3162018-05-10 12:55:40 +0100319 UniqueCPtr<const char[]> full_path(realpath(path, nullptr));
Nicolas Geoffraye64d58c2018-05-21 14:17:59 +0100320 return full_path != nullptr &&
321 android::base::StartsWith(full_path.get(), GetAndroidRoot().c_str());
David Sehr10db8fe2018-07-18 11:01:20 -0700322#endif
Nicolas Geoffray29742602017-12-14 10:09:03 +0000323}
324
Nicolas Geoffray0d0f3162018-05-10 12:55:40 +0100325bool LocationIsOnSystemFramework(const char* full_path) {
David Brazdil8e1a7cb2018-03-27 08:14:25 +0000326 std::string error_msg;
327 std::string root_path = GetAndroidRootSafe(&error_msg);
328 if (root_path.empty()) {
329 // Could not find Android root.
330 // TODO(dbrazdil): change to stricter GetAndroidRoot() once b/76452688 is resolved.
331 return false;
332 }
333 std::string framework_path = root_path + "/framework/";
Nicolas Geoffray0d0f3162018-05-10 12:55:40 +0100334 return android::base::StartsWith(full_path, framework_path);
David Brazdil8e1a7cb2018-03-27 08:14:25 +0000335}
336
David Brazdilbfaba282019-03-15 11:35:51 +0000337bool RuntimeModuleRootDistinctFromAndroidRoot() {
338 std::string error_msg;
339 std::string android_root = GetAndroidRootSafe(&error_msg);
340 const char* runtime_root =
341 GetAndroidDirSafe(kRuntimeApexEnvVar, kRuntimeApexDefaultPath, &error_msg);
342 return !android_root.empty()
343 && (runtime_root != nullptr)
344 && (android_root != std::string_view(runtime_root));
345}
346
Josh Gao35696a02018-08-30 17:24:16 -0700347int DupCloexec(int fd) {
348#if defined(__linux__)
349 return fcntl(fd, F_DUPFD_CLOEXEC, 0);
350#else
351 return dup(fd);
352#endif
353}
354
David Sehr891a50e2017-10-27 17:01:07 -0700355} // namespace art