• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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