blob: 949079855265a57d904a20e63d01025cb5816ad8 [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";
68
David Sehr891a50e2017-10-27 17:01:07 -070069bool ReadFileToString(const std::string& file_name, std::string* result) {
70 File file(file_name, O_RDONLY, false);
71 if (!file.IsOpened()) {
72 return false;
73 }
74
75 std::vector<char> buf(8 * KB);
76 while (true) {
77 int64_t n = TEMP_FAILURE_RETRY(read(file.Fd(), &buf[0], buf.size()));
78 if (n == -1) {
79 return false;
80 }
81 if (n == 0) {
82 return true;
83 }
84 result->append(&buf[0], n);
85 }
86}
87
David Sehr891a50e2017-10-27 17:01:07 -070088std::string GetAndroidRootSafe(std::string* error_msg) {
David Sehr10db8fe2018-07-18 11:01:20 -070089#ifdef _WIN32
90 *error_msg = "GetAndroidRootSafe unsupported for Windows.";
91 return "";
92#else
David Sehr891a50e2017-10-27 17:01:07 -070093 // Prefer ANDROID_ROOT if it's set.
94 const char* android_dir = getenv("ANDROID_ROOT");
95 if (android_dir != nullptr) {
96 if (!OS::DirectoryExists(android_dir)) {
97 *error_msg = StringPrintf("Failed to find ANDROID_ROOT directory %s", android_dir);
98 return "";
99 }
100 return android_dir;
101 }
102
103 // Check where libart is from, and derive from there. Only do this for non-Mac.
104#ifndef __APPLE__
105 {
106 Dl_info info;
107 if (dladdr(reinterpret_cast<const void*>(&GetAndroidRootSafe), /* out */ &info) != 0) {
108 // Make a duplicate of the fname so dirname can modify it.
109 UniqueCPtr<char> fname(strdup(info.dli_fname));
110
111 char* dir1 = dirname(fname.get()); // This is the lib directory.
112 char* dir2 = dirname(dir1); // This is the "system" directory.
113 if (OS::DirectoryExists(dir2)) {
114 std::string tmp = dir2; // Make a copy here so that fname can be released.
115 return tmp;
116 }
117 }
118 }
119#endif
120
121 // Try "/system".
122 if (!OS::DirectoryExists("/system")) {
123 *error_msg = "Failed to find ANDROID_ROOT directory /system";
124 return "";
125 }
126 return "/system";
David Sehr10db8fe2018-07-18 11:01:20 -0700127#endif
David Sehr891a50e2017-10-27 17:01:07 -0700128}
129
130std::string GetAndroidRoot() {
131 std::string error_msg;
132 std::string ret = GetAndroidRootSafe(&error_msg);
133 if (ret.empty()) {
134 LOG(FATAL) << error_msg;
135 UNREACHABLE();
136 }
137 return ret;
138}
139
140
141static const char* GetAndroidDirSafe(const char* env_var,
142 const char* default_dir,
143 std::string* error_msg) {
144 const char* android_dir = getenv(env_var);
145 if (android_dir == nullptr) {
146 if (OS::DirectoryExists(default_dir)) {
147 android_dir = default_dir;
148 } else {
149 *error_msg = StringPrintf("%s not set and %s does not exist", env_var, default_dir);
150 return nullptr;
151 }
152 }
153 if (!OS::DirectoryExists(android_dir)) {
154 *error_msg = StringPrintf("Failed to find %s directory %s", env_var, android_dir);
155 return nullptr;
156 }
157 return android_dir;
158}
159
160static const char* GetAndroidDir(const char* env_var, const char* default_dir) {
161 std::string error_msg;
162 const char* dir = GetAndroidDirSafe(env_var, default_dir, &error_msg);
163 if (dir != nullptr) {
164 return dir;
165 } else {
166 LOG(FATAL) << error_msg;
Elliott Hughesc1896c92018-11-29 11:33:18 -0800167 UNREACHABLE();
David Sehr891a50e2017-10-27 17:01:07 -0700168 }
169}
170
171const char* GetAndroidData() {
172 return GetAndroidDir("ANDROID_DATA", "/data");
173}
174
175const char* GetAndroidDataSafe(std::string* error_msg) {
176 return GetAndroidDirSafe("ANDROID_DATA", "/data", error_msg);
177}
178
179std::string GetDefaultBootImageLocation(std::string* error_msg) {
180 std::string android_root = GetAndroidRootSafe(error_msg);
181 if (android_root.empty()) {
182 return "";
183 }
184 return StringPrintf("%s/framework/boot.art", android_root.c_str());
185}
186
187void GetDalvikCache(const char* subdir, const bool create_if_absent, std::string* dalvik_cache,
188 bool* have_android_data, bool* dalvik_cache_exists, bool* is_global_cache) {
David Sehr10db8fe2018-07-18 11:01:20 -0700189#ifdef _WIN32
190 UNUSED(subdir);
191 UNUSED(create_if_absent);
192 UNUSED(dalvik_cache);
193 UNUSED(have_android_data);
194 UNUSED(dalvik_cache_exists);
195 UNUSED(is_global_cache);
196 LOG(FATAL) << "GetDalvikCache unsupported on Windows.";
197#else
David Sehr891a50e2017-10-27 17:01:07 -0700198 CHECK(subdir != nullptr);
199 std::string error_msg;
200 const char* android_data = GetAndroidDataSafe(&error_msg);
201 if (android_data == nullptr) {
202 *have_android_data = false;
203 *dalvik_cache_exists = false;
204 *is_global_cache = false;
205 return;
206 } else {
207 *have_android_data = true;
208 }
209 const std::string dalvik_cache_root(StringPrintf("%s/dalvik-cache/", android_data));
210 *dalvik_cache = dalvik_cache_root + subdir;
211 *dalvik_cache_exists = OS::DirectoryExists(dalvik_cache->c_str());
212 *is_global_cache = strcmp(android_data, "/data") == 0;
213 if (create_if_absent && !*dalvik_cache_exists && !*is_global_cache) {
214 // Don't create the system's /data/dalvik-cache/... because it needs special permissions.
215 *dalvik_cache_exists = ((mkdir(dalvik_cache_root.c_str(), 0700) == 0 || errno == EEXIST) &&
216 (mkdir(dalvik_cache->c_str(), 0700) == 0 || errno == EEXIST));
217 }
David Sehr10db8fe2018-07-18 11:01:20 -0700218#endif
David Sehr891a50e2017-10-27 17:01:07 -0700219}
220
221std::string GetDalvikCache(const char* subdir) {
222 CHECK(subdir != nullptr);
223 const char* android_data = GetAndroidData();
224 const std::string dalvik_cache_root(StringPrintf("%s/dalvik-cache/", android_data));
225 const std::string dalvik_cache = dalvik_cache_root + subdir;
226 if (!OS::DirectoryExists(dalvik_cache.c_str())) {
227 // TODO: Check callers. Traditional behavior is to not abort.
228 return "";
229 }
230 return dalvik_cache;
231}
232
233bool GetDalvikCacheFilename(const char* location, const char* cache_location,
234 std::string* filename, std::string* error_msg) {
235 if (location[0] != '/') {
236 *error_msg = StringPrintf("Expected path in location to be absolute: %s", location);
237 return false;
238 }
239 std::string cache_file(&location[1]); // skip leading slash
240 if (!android::base::EndsWith(location, ".dex") &&
241 !android::base::EndsWith(location, ".art") &&
242 !android::base::EndsWith(location, ".oat")) {
243 cache_file += "/";
David Sehrc3e18952018-05-11 16:59:31 -0700244 cache_file += kClassesDex;
David Sehr891a50e2017-10-27 17:01:07 -0700245 }
246 std::replace(cache_file.begin(), cache_file.end(), '/', '@');
247 *filename = StringPrintf("%s/%s", cache_location, cache_file.c_str());
248 return true;
249}
250
251std::string GetVdexFilename(const std::string& oat_location) {
252 return ReplaceFileExtension(oat_location, "vdex");
253}
254
255static void InsertIsaDirectory(const InstructionSet isa, std::string* filename) {
256 // in = /foo/bar/baz
257 // out = /foo/bar/<isa>/baz
258 size_t pos = filename->rfind('/');
259 CHECK_NE(pos, std::string::npos) << *filename << " " << isa;
260 filename->insert(pos, "/", 1);
261 filename->insert(pos + 1, GetInstructionSetString(isa));
262}
263
264std::string GetSystemImageFilename(const char* location, const InstructionSet isa) {
265 // location = /system/framework/boot.art
266 // filename = /system/framework/<isa>/boot.art
267 std::string filename(location);
268 InsertIsaDirectory(isa, &filename);
269 return filename;
270}
271
David Sehr891a50e2017-10-27 17:01:07 -0700272std::string ReplaceFileExtension(const std::string& filename, const std::string& new_extension) {
Vladimir Marko62c2d712018-03-09 12:54:05 +0000273 const size_t last_ext = filename.find_last_of("./");
274 if (last_ext == std::string::npos || filename[last_ext] != '.') {
David Sehr891a50e2017-10-27 17:01:07 -0700275 return filename + "." + new_extension;
276 } else {
277 return filename.substr(0, last_ext + 1) + new_extension;
278 }
279}
280
Nicolas Geoffray0d0f3162018-05-10 12:55:40 +0100281bool LocationIsOnSystem(const char* path) {
David Sehr10db8fe2018-07-18 11:01:20 -0700282#ifdef _WIN32
283 UNUSED(path);
284 LOG(FATAL) << "LocationIsOnSystem is unsupported on Windows.";
285 return false;
286#else
Nicolas Geoffray0d0f3162018-05-10 12:55:40 +0100287 UniqueCPtr<const char[]> full_path(realpath(path, nullptr));
Nicolas Geoffraye64d58c2018-05-21 14:17:59 +0100288 return full_path != nullptr &&
289 android::base::StartsWith(full_path.get(), GetAndroidRoot().c_str());
David Sehr10db8fe2018-07-18 11:01:20 -0700290#endif
Nicolas Geoffray29742602017-12-14 10:09:03 +0000291}
292
Nicolas Geoffray0d0f3162018-05-10 12:55:40 +0100293bool LocationIsOnSystemFramework(const char* full_path) {
David Brazdil8e1a7cb2018-03-27 08:14:25 +0000294 std::string error_msg;
295 std::string root_path = GetAndroidRootSafe(&error_msg);
296 if (root_path.empty()) {
297 // Could not find Android root.
298 // TODO(dbrazdil): change to stricter GetAndroidRoot() once b/76452688 is resolved.
299 return false;
300 }
301 std::string framework_path = root_path + "/framework/";
Nicolas Geoffray0d0f3162018-05-10 12:55:40 +0100302 return android::base::StartsWith(full_path, framework_path);
David Brazdil8e1a7cb2018-03-27 08:14:25 +0000303}
304
Josh Gao35696a02018-08-30 17:24:16 -0700305int DupCloexec(int fd) {
306#if defined(__linux__)
307 return fcntl(fd, F_DUPFD_CLOEXEC, 0);
308#else
309 return dup(fd);
310#endif
311}
312
David Sehr891a50e2017-10-27 17:01:07 -0700313} // namespace art