blob: 7b0796cf37e594027f851a8e97a93fd68b3569be [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 Sehr891a50e2017-10-27 17:01:07 -070046#include "base/stl_util.h"
David Sehrc431b9d2018-03-02 12:01:51 -080047#include "base/os.h"
David Sehr891a50e2017-10-27 17:01:07 -070048#include "base/unix_file/fd_file.h"
David Sehr9e734c72018-01-04 17:56:19 -080049#include "dex/dex_file_loader.h"
David Sehrb2ec9f52018-02-21 13:20:31 -080050#include "globals.h"
David Sehr891a50e2017-10-27 17:01:07 -070051
52#if defined(__APPLE__)
53#include <crt_externs.h>
54#include <sys/syscall.h>
55#include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED
56#endif
57
58#if defined(__linux__)
59#include <linux/unistd.h>
60#endif
61
62namespace art {
63
64using android::base::StringAppendF;
65using android::base::StringPrintf;
66
67bool 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;
160 return nullptr;
161 }
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 += "/";
227 cache_file += DexFileLoader::kClassesDex;
228 }
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 Geoffray29742602017-12-14 10:09:03 +0000264bool LocationIsOnSystem(const char* location) {
265 UniqueCPtr<const char[]> path(realpath(location, nullptr));
266 return path != nullptr && android::base::StartsWith(path.get(), GetAndroidRoot().c_str());
267}
268
David Brazdil8e1a7cb2018-03-27 08:14:25 +0000269bool LocationIsOnSystemFramework(const char* location) {
270 std::string error_msg;
271 std::string root_path = GetAndroidRootSafe(&error_msg);
272 if (root_path.empty()) {
273 // Could not find Android root.
274 // TODO(dbrazdil): change to stricter GetAndroidRoot() once b/76452688 is resolved.
275 return false;
276 }
277 std::string framework_path = root_path + "/framework/";
278
279 // Warning: Bionic implementation of realpath() allocates > 12KB on the stack.
280 // Do not run this code on a small stack, e.g. in signal handler.
281 UniqueCPtr<const char[]> path(realpath(location, nullptr));
282 return path != nullptr &&
283 android::base::StartsWith(path.get(), framework_path.c_str());
284}
285
David Sehr891a50e2017-10-27 17:01:07 -0700286} // namespace art