1 /*
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>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #ifndef _WIN32
23 #include <sys/wait.h>
24 #endif
25 #include <unistd.h>
26
27 // We need dladdr.
28 #if !defined(__APPLE__) && !defined(_WIN32)
29 #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
47 #include "base/bit_utils.h"
48 #include "base/globals.h"
49 #include "base/os.h"
50 #include "base/stl_util.h"
51 #include "base/unix_file/fd_file.h"
52
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
63 namespace art {
64
65 using android::base::StringPrintf;
66
67 static constexpr const char* kClassesDex = "classes.dex";
68 static constexpr const char* kApexDefaultPath = "/apex/";
69 static constexpr const char* kAndroidRootEnvVar = "ANDROID_ROOT";
70 static constexpr const char* kAndroidRootDefaultPath = "/system";
71 static constexpr const char* kAndroidDataEnvVar = "ANDROID_DATA";
72 static constexpr const char* kAndroidDataDefaultPath = "/data";
73 static constexpr const char* kAndroidRuntimeRootEnvVar = "ANDROID_RUNTIME_ROOT";
74 static constexpr const char* kAndroidRuntimeApexDefaultPath = "/apex/com.android.runtime";
75 static constexpr const char* kAndroidConscryptRootEnvVar = "ANDROID_CONSCRYPT_ROOT";
76 static constexpr const char* kAndroidConscryptApexDefaultPath = "/apex/com.android.conscrypt";
77
ReadFileToString(const std::string & file_name,std::string * result)78 bool ReadFileToString(const std::string& file_name, std::string* result) {
79 File file(file_name, O_RDONLY, false);
80 if (!file.IsOpened()) {
81 return false;
82 }
83
84 std::vector<char> buf(8 * KB);
85 while (true) {
86 int64_t n = TEMP_FAILURE_RETRY(read(file.Fd(), &buf[0], buf.size()));
87 if (n == -1) {
88 return false;
89 }
90 if (n == 0) {
91 return true;
92 }
93 result->append(&buf[0], n);
94 }
95 }
96
GetAndroidRootSafe(std::string * error_msg)97 std::string GetAndroidRootSafe(std::string* error_msg) {
98 #ifdef _WIN32
99 UNUSED(kAndroidRootEnvVar, kAndroidRootDefaultPath);
100 *error_msg = "GetAndroidRootSafe unsupported for Windows.";
101 return "";
102 #else
103 // Prefer ANDROID_ROOT if it's set.
104 const char* android_root_from_env = getenv(kAndroidRootEnvVar);
105 if (android_root_from_env != nullptr) {
106 if (!OS::DirectoryExists(android_root_from_env)) {
107 *error_msg = StringPrintf("Failed to find ANDROID_ROOT directory %s", android_root_from_env);
108 return "";
109 }
110 return android_root_from_env;
111 }
112
113 // Check where libart is from, and derive from there. Only do this for non-Mac.
114 #ifndef __APPLE__
115 {
116 Dl_info info;
117 if (dladdr(reinterpret_cast<const void*>(&GetAndroidRootSafe), /* out */ &info) != 0) {
118 // Make a duplicate of the fname so dirname can modify it.
119 UniqueCPtr<char> fname(strdup(info.dli_fname));
120
121 char* dir1 = dirname(fname.get()); // This is the lib directory.
122 char* dir2 = dirname(dir1); // This is the "system" directory.
123 if (OS::DirectoryExists(dir2)) {
124 std::string tmp = dir2; // Make a copy here so that fname can be released.
125 return tmp;
126 }
127 }
128 }
129 #endif
130
131 // Try the default path.
132 if (!OS::DirectoryExists(kAndroidRootDefaultPath)) {
133 *error_msg = StringPrintf("Failed to find directory %s", kAndroidRootDefaultPath);
134 return "";
135 }
136 return kAndroidRootDefaultPath;
137 #endif
138 }
139
GetAndroidRoot()140 std::string GetAndroidRoot() {
141 std::string error_msg;
142 std::string ret = GetAndroidRootSafe(&error_msg);
143 if (ret.empty()) {
144 LOG(FATAL) << error_msg;
145 UNREACHABLE();
146 }
147 return ret;
148 }
149
150
GetAndroidDirSafe(const char * env_var,const char * default_dir,bool must_exist,std::string * error_msg)151 static const char* GetAndroidDirSafe(const char* env_var,
152 const char* default_dir,
153 bool must_exist,
154 std::string* error_msg) {
155 const char* android_dir = getenv(env_var);
156 if (android_dir == nullptr) {
157 if (!must_exist || OS::DirectoryExists(default_dir)) {
158 android_dir = default_dir;
159 } else {
160 *error_msg = StringPrintf("%s not set and %s does not exist", env_var, default_dir);
161 return nullptr;
162 }
163 }
164 if (must_exist && !OS::DirectoryExists(android_dir)) {
165 *error_msg = StringPrintf("Failed to find %s directory %s", env_var, android_dir);
166 return nullptr;
167 }
168 return android_dir;
169 }
170
GetAndroidDir(const char * env_var,const char * default_dir)171 static const char* GetAndroidDir(const char* env_var, const char* default_dir) {
172 std::string error_msg;
173 const char* dir = GetAndroidDirSafe(env_var, default_dir, /* must_exist= */ true, &error_msg);
174 if (dir != nullptr) {
175 return dir;
176 } else {
177 LOG(FATAL) << error_msg;
178 UNREACHABLE();
179 }
180 }
181
GetAndroidRuntimeRootSafe(std::string * error_msg)182 std::string GetAndroidRuntimeRootSafe(std::string* error_msg) {
183 const char* android_dir = GetAndroidDirSafe(kAndroidRuntimeRootEnvVar,
184 kAndroidRuntimeApexDefaultPath,
185 /* must_exist= */ true,
186 error_msg);
187 return (android_dir != nullptr) ? android_dir : "";
188 }
189
GetAndroidRuntimeRoot()190 std::string GetAndroidRuntimeRoot() {
191 return GetAndroidDir(kAndroidRuntimeRootEnvVar, kAndroidRuntimeApexDefaultPath);
192 }
193
GetAndroidDataSafe(std::string * error_msg)194 std::string GetAndroidDataSafe(std::string* error_msg) {
195 const char* android_dir = GetAndroidDirSafe(kAndroidDataEnvVar,
196 kAndroidDataDefaultPath,
197 /* must_exist= */ true,
198 error_msg);
199 return (android_dir != nullptr) ? android_dir : "";
200 }
201
GetAndroidData()202 std::string GetAndroidData() {
203 return GetAndroidDir(kAndroidDataEnvVar, kAndroidDataDefaultPath);
204 }
205
GetDefaultBootImageLocation(const std::string & android_root)206 std::string GetDefaultBootImageLocation(const std::string& android_root) {
207 return StringPrintf("%s/framework/boot.art", android_root.c_str());
208 }
209
GetDefaultBootImageLocation(std::string * error_msg)210 std::string GetDefaultBootImageLocation(std::string* error_msg) {
211 std::string android_root = GetAndroidRootSafe(error_msg);
212 if (android_root.empty()) {
213 return "";
214 }
215 return GetDefaultBootImageLocation(android_root);
216 }
217
GetDalvikCache(const char * subdir,const bool create_if_absent,std::string * dalvik_cache,bool * have_android_data,bool * dalvik_cache_exists,bool * is_global_cache)218 void GetDalvikCache(const char* subdir, const bool create_if_absent, std::string* dalvik_cache,
219 bool* have_android_data, bool* dalvik_cache_exists, bool* is_global_cache) {
220 #ifdef _WIN32
221 UNUSED(subdir);
222 UNUSED(create_if_absent);
223 UNUSED(dalvik_cache);
224 UNUSED(have_android_data);
225 UNUSED(dalvik_cache_exists);
226 UNUSED(is_global_cache);
227 LOG(FATAL) << "GetDalvikCache unsupported on Windows.";
228 #else
229 CHECK(subdir != nullptr);
230 std::string unused_error_msg;
231 std::string android_data = GetAndroidDataSafe(&unused_error_msg);
232 if (android_data.empty()) {
233 *have_android_data = false;
234 *dalvik_cache_exists = false;
235 *is_global_cache = false;
236 return;
237 } else {
238 *have_android_data = true;
239 }
240 const std::string dalvik_cache_root = android_data + "/dalvik-cache";
241 *dalvik_cache = dalvik_cache_root + '/' + subdir;
242 *dalvik_cache_exists = OS::DirectoryExists(dalvik_cache->c_str());
243 *is_global_cache = (android_data == kAndroidDataDefaultPath);
244 if (create_if_absent && !*dalvik_cache_exists && !*is_global_cache) {
245 // Don't create the system's /data/dalvik-cache/... because it needs special permissions.
246 *dalvik_cache_exists = ((mkdir(dalvik_cache_root.c_str(), 0700) == 0 || errno == EEXIST) &&
247 (mkdir(dalvik_cache->c_str(), 0700) == 0 || errno == EEXIST));
248 }
249 #endif
250 }
251
GetDalvikCache(const char * subdir)252 std::string GetDalvikCache(const char* subdir) {
253 CHECK(subdir != nullptr);
254 std::string android_data = GetAndroidData();
255 const std::string dalvik_cache_root = android_data + "/dalvik-cache";
256 const std::string dalvik_cache = dalvik_cache_root + '/' + subdir;
257 if (!OS::DirectoryExists(dalvik_cache.c_str())) {
258 // TODO: Check callers. Traditional behavior is to not abort.
259 return "";
260 }
261 return dalvik_cache;
262 }
263
GetDalvikCacheFilename(const char * location,const char * cache_location,std::string * filename,std::string * error_msg)264 bool GetDalvikCacheFilename(const char* location, const char* cache_location,
265 std::string* filename, std::string* error_msg) {
266 if (location[0] != '/') {
267 *error_msg = StringPrintf("Expected path in location to be absolute: %s", location);
268 return false;
269 }
270 std::string cache_file(&location[1]); // skip leading slash
271 if (!android::base::EndsWith(location, ".dex") &&
272 !android::base::EndsWith(location, ".art") &&
273 !android::base::EndsWith(location, ".oat")) {
274 cache_file += "/";
275 cache_file += kClassesDex;
276 }
277 std::replace(cache_file.begin(), cache_file.end(), '/', '@');
278 *filename = StringPrintf("%s/%s", cache_location, cache_file.c_str());
279 return true;
280 }
281
GetVdexFilename(const std::string & oat_location)282 std::string GetVdexFilename(const std::string& oat_location) {
283 return ReplaceFileExtension(oat_location, "vdex");
284 }
285
InsertIsaDirectory(const InstructionSet isa,std::string * filename)286 static void InsertIsaDirectory(const InstructionSet isa, std::string* filename) {
287 // in = /foo/bar/baz
288 // out = /foo/bar/<isa>/baz
289 size_t pos = filename->rfind('/');
290 CHECK_NE(pos, std::string::npos) << *filename << " " << isa;
291 filename->insert(pos, "/", 1);
292 filename->insert(pos + 1, GetInstructionSetString(isa));
293 }
294
GetSystemImageFilename(const char * location,const InstructionSet isa)295 std::string GetSystemImageFilename(const char* location, const InstructionSet isa) {
296 // location = /system/framework/boot.art
297 // filename = /system/framework/<isa>/boot.art
298 std::string filename(location);
299 InsertIsaDirectory(isa, &filename);
300 return filename;
301 }
302
ReplaceFileExtension(const std::string & filename,const std::string & new_extension)303 std::string ReplaceFileExtension(const std::string& filename, const std::string& new_extension) {
304 const size_t last_ext = filename.find_last_of("./");
305 if (last_ext == std::string::npos || filename[last_ext] != '.') {
306 return filename + "." + new_extension;
307 } else {
308 return filename.substr(0, last_ext + 1) + new_extension;
309 }
310 }
311
StartsWithSlash(const char * str)312 static bool StartsWithSlash(const char* str) {
313 DCHECK(str != nullptr);
314 return str[0] == '/';
315 }
316
EndsWithSlash(const char * str)317 static bool EndsWithSlash(const char* str) {
318 DCHECK(str != nullptr);
319 size_t len = strlen(str);
320 return len > 0 && str[len - 1] == '/';
321 }
322
323 // Returns true if `full_path` is located in folder either provided with `env_var`
324 // or in `default_path` otherwise. The caller may optionally provide a `subdir`
325 // which will be appended to the tested prefix.
326 // All of `default_path`, `subdir` and the value of environment variable `env_var`
327 // are expected to begin with a slash and not end with one. If this ever changes,
328 // the path-building logic should be updated.
IsLocationOnModule(const char * full_path,const char * env_var,const char * default_path,const char * subdir=nullptr)329 static bool IsLocationOnModule(const char* full_path,
330 const char* env_var,
331 const char* default_path,
332 const char* subdir = nullptr) {
333 std::string unused_error_msg;
334 const char* module_path = GetAndroidDirSafe(env_var,
335 default_path,
336 /* must_exist= */ kIsTargetBuild,
337 &unused_error_msg);
338 if (module_path == nullptr) {
339 return false;
340 }
341
342 // Build the path which we will check is a prefix of `full_path`. The prefix must
343 // end with a slash, so that "/foo/bar" does not match "/foo/barz".
344 DCHECK(StartsWithSlash(module_path)) << module_path;
345 std::string path_prefix(module_path);
346 if (!EndsWithSlash(path_prefix.c_str())) {
347 path_prefix.append("/");
348 }
349 if (subdir != nullptr) {
350 // If `subdir` is provided, we assume it is provided without a starting slash
351 // but ending with one, e.g. "sub/dir/". `path_prefix` ends with a slash at
352 // this point, so we simply append `subdir`.
353 DCHECK(!StartsWithSlash(subdir) && EndsWithSlash(subdir)) << subdir;
354 path_prefix.append(subdir);
355 }
356
357 return android::base::StartsWith(full_path, path_prefix);
358 }
359
LocationIsOnSystemFramework(const char * full_path)360 bool LocationIsOnSystemFramework(const char* full_path) {
361 return IsLocationOnModule(full_path,
362 kAndroidRootEnvVar,
363 kAndroidRootDefaultPath,
364 /* subdir= */ "framework/");
365 }
366
LocationIsOnRuntimeModule(const char * full_path)367 bool LocationIsOnRuntimeModule(const char* full_path) {
368 return IsLocationOnModule(full_path, kAndroidRuntimeRootEnvVar, kAndroidRuntimeApexDefaultPath);
369 }
370
LocationIsOnConscryptModule(const char * full_path)371 bool LocationIsOnConscryptModule(const char* full_path) {
372 return IsLocationOnModule(
373 full_path, kAndroidConscryptRootEnvVar, kAndroidConscryptApexDefaultPath);
374 }
375
LocationIsOnApex(const char * full_path)376 bool LocationIsOnApex(const char* full_path) {
377 return android::base::StartsWith(full_path, kApexDefaultPath);
378 }
379
LocationIsOnSystem(const char * path)380 bool LocationIsOnSystem(const char* path) {
381 #ifdef _WIN32
382 UNUSED(path);
383 LOG(FATAL) << "LocationIsOnSystem is unsupported on Windows.";
384 return false;
385 #else
386 UniqueCPtr<const char[]> full_path(realpath(path, nullptr));
387 return full_path != nullptr &&
388 android::base::StartsWith(full_path.get(), GetAndroidRoot().c_str());
389 #endif
390 }
391
RuntimeModuleRootDistinctFromAndroidRoot()392 bool RuntimeModuleRootDistinctFromAndroidRoot() {
393 std::string error_msg;
394 const char* android_root = GetAndroidDirSafe(kAndroidRootEnvVar,
395 kAndroidRootDefaultPath,
396 /* must_exist= */ kIsTargetBuild,
397 &error_msg);
398 const char* runtime_root = GetAndroidDirSafe(kAndroidRuntimeRootEnvVar,
399 kAndroidRuntimeApexDefaultPath,
400 /* must_exist= */ kIsTargetBuild,
401 &error_msg);
402 return (android_root != nullptr)
403 && (runtime_root != nullptr)
404 && (std::string_view(android_root) != std::string_view(runtime_root));
405 }
406
DupCloexec(int fd)407 int DupCloexec(int fd) {
408 #if defined(__linux__)
409 return fcntl(fd, F_DUPFD_CLOEXEC, 0);
410 #else
411 return dup(fd);
412 #endif
413 }
414
415 } // namespace art
416