Home | History | Annotate | Download | only in base
      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 #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 
     45 #include "base/bit_utils.h"
     46 #include "base/stl_util.h"
     47 #include "base/os.h"
     48 #include "base/unix_file/fd_file.h"
     49 #include "dex/dex_file_loader.h"
     50 #include "globals.h"
     51 
     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 
     62 namespace art {
     63 
     64 using android::base::StringAppendF;
     65 using android::base::StringPrintf;
     66 
     67 bool 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 
     86 bool PrintFileToLog(const std::string& file_name, android::base::LogSeverity level) {
     87   File file(file_name, O_RDONLY, false);
     88   if (!file.IsOpened()) {
     89     return false;
     90   }
     91 
     92   constexpr size_t kBufSize = 256;  // Small buffer. Avoid stack overflow and stack size warnings.
     93   char buf[kBufSize + 1];           // +1 for terminator.
     94   size_t filled_to = 0;
     95   while (true) {
     96     DCHECK_LT(filled_to, kBufSize);
     97     int64_t n = TEMP_FAILURE_RETRY(read(file.Fd(), &buf[filled_to], kBufSize - filled_to));
     98     if (n <= 0) {
     99       // Print the rest of the buffer, if it exists.
    100       if (filled_to > 0) {
    101         buf[filled_to] = 0;
    102         LOG(level) << buf;
    103       }
    104       return n == 0;
    105     }
    106     // Scan for '\n'.
    107     size_t i = filled_to;
    108     bool found_newline = false;
    109     for (; i < filled_to + n; ++i) {
    110       if (buf[i] == '\n') {
    111         // Found a line break, that's something to print now.
    112         buf[i] = 0;
    113         LOG(level) << buf;
    114         // Copy the rest to the front.
    115         if (i + 1 < filled_to + n) {
    116           memmove(&buf[0], &buf[i + 1], filled_to + n - i - 1);
    117           filled_to = filled_to + n - i - 1;
    118         } else {
    119           filled_to = 0;
    120         }
    121         found_newline = true;
    122         break;
    123       }
    124     }
    125     if (found_newline) {
    126       continue;
    127     } else {
    128       filled_to += n;
    129       // Check if we must flush now.
    130       if (filled_to == kBufSize) {
    131         buf[kBufSize] = 0;
    132         LOG(level) << buf;
    133         filled_to = 0;
    134       }
    135     }
    136   }
    137 }
    138 
    139 std::string GetAndroidRootSafe(std::string* error_msg) {
    140   // Prefer ANDROID_ROOT if it's set.
    141   const char* android_dir = getenv("ANDROID_ROOT");
    142   if (android_dir != nullptr) {
    143     if (!OS::DirectoryExists(android_dir)) {
    144       *error_msg = StringPrintf("Failed to find ANDROID_ROOT directory %s", android_dir);
    145       return "";
    146     }
    147     return android_dir;
    148   }
    149 
    150   // Check where libart is from, and derive from there. Only do this for non-Mac.
    151 #ifndef __APPLE__
    152   {
    153     Dl_info info;
    154     if (dladdr(reinterpret_cast<const void*>(&GetAndroidRootSafe), /* out */ &info) != 0) {
    155       // Make a duplicate of the fname so dirname can modify it.
    156       UniqueCPtr<char> fname(strdup(info.dli_fname));
    157 
    158       char* dir1 = dirname(fname.get());  // This is the lib directory.
    159       char* dir2 = dirname(dir1);         // This is the "system" directory.
    160       if (OS::DirectoryExists(dir2)) {
    161         std::string tmp = dir2;  // Make a copy here so that fname can be released.
    162         return tmp;
    163       }
    164     }
    165   }
    166 #endif
    167 
    168   // Try "/system".
    169   if (!OS::DirectoryExists("/system")) {
    170     *error_msg = "Failed to find ANDROID_ROOT directory /system";
    171     return "";
    172   }
    173   return "/system";
    174 }
    175 
    176 std::string GetAndroidRoot() {
    177   std::string error_msg;
    178   std::string ret = GetAndroidRootSafe(&error_msg);
    179   if (ret.empty()) {
    180     LOG(FATAL) << error_msg;
    181     UNREACHABLE();
    182   }
    183   return ret;
    184 }
    185 
    186 
    187 static const char* GetAndroidDirSafe(const char* env_var,
    188                                      const char* default_dir,
    189                                      std::string* error_msg) {
    190   const char* android_dir = getenv(env_var);
    191   if (android_dir == nullptr) {
    192     if (OS::DirectoryExists(default_dir)) {
    193       android_dir = default_dir;
    194     } else {
    195       *error_msg = StringPrintf("%s not set and %s does not exist", env_var, default_dir);
    196       return nullptr;
    197     }
    198   }
    199   if (!OS::DirectoryExists(android_dir)) {
    200     *error_msg = StringPrintf("Failed to find %s directory %s", env_var, android_dir);
    201     return nullptr;
    202   }
    203   return android_dir;
    204 }
    205 
    206 static const char* GetAndroidDir(const char* env_var, const char* default_dir) {
    207   std::string error_msg;
    208   const char* dir = GetAndroidDirSafe(env_var, default_dir, &error_msg);
    209   if (dir != nullptr) {
    210     return dir;
    211   } else {
    212     LOG(FATAL) << error_msg;
    213     return nullptr;
    214   }
    215 }
    216 
    217 const char* GetAndroidData() {
    218   return GetAndroidDir("ANDROID_DATA", "/data");
    219 }
    220 
    221 const char* GetAndroidDataSafe(std::string* error_msg) {
    222   return GetAndroidDirSafe("ANDROID_DATA", "/data", error_msg);
    223 }
    224 
    225 std::string GetDefaultBootImageLocation(std::string* error_msg) {
    226   std::string android_root = GetAndroidRootSafe(error_msg);
    227   if (android_root.empty()) {
    228     return "";
    229   }
    230   return StringPrintf("%s/framework/boot.art", android_root.c_str());
    231 }
    232 
    233 void GetDalvikCache(const char* subdir, const bool create_if_absent, std::string* dalvik_cache,
    234                     bool* have_android_data, bool* dalvik_cache_exists, bool* is_global_cache) {
    235   CHECK(subdir != nullptr);
    236   std::string error_msg;
    237   const char* android_data = GetAndroidDataSafe(&error_msg);
    238   if (android_data == nullptr) {
    239     *have_android_data = false;
    240     *dalvik_cache_exists = false;
    241     *is_global_cache = false;
    242     return;
    243   } else {
    244     *have_android_data = true;
    245   }
    246   const std::string dalvik_cache_root(StringPrintf("%s/dalvik-cache/", android_data));
    247   *dalvik_cache = dalvik_cache_root + subdir;
    248   *dalvik_cache_exists = OS::DirectoryExists(dalvik_cache->c_str());
    249   *is_global_cache = strcmp(android_data, "/data") == 0;
    250   if (create_if_absent && !*dalvik_cache_exists && !*is_global_cache) {
    251     // Don't create the system's /data/dalvik-cache/... because it needs special permissions.
    252     *dalvik_cache_exists = ((mkdir(dalvik_cache_root.c_str(), 0700) == 0 || errno == EEXIST) &&
    253                             (mkdir(dalvik_cache->c_str(), 0700) == 0 || errno == EEXIST));
    254   }
    255 }
    256 
    257 std::string GetDalvikCache(const char* subdir) {
    258   CHECK(subdir != nullptr);
    259   const char* android_data = GetAndroidData();
    260   const std::string dalvik_cache_root(StringPrintf("%s/dalvik-cache/", android_data));
    261   const std::string dalvik_cache = dalvik_cache_root + subdir;
    262   if (!OS::DirectoryExists(dalvik_cache.c_str())) {
    263     // TODO: Check callers. Traditional behavior is to not abort.
    264     return "";
    265   }
    266   return dalvik_cache;
    267 }
    268 
    269 bool GetDalvikCacheFilename(const char* location, const char* cache_location,
    270                             std::string* filename, std::string* error_msg) {
    271   if (location[0] != '/') {
    272     *error_msg = StringPrintf("Expected path in location to be absolute: %s", location);
    273     return false;
    274   }
    275   std::string cache_file(&location[1]);  // skip leading slash
    276   if (!android::base::EndsWith(location, ".dex") &&
    277       !android::base::EndsWith(location, ".art") &&
    278       !android::base::EndsWith(location, ".oat")) {
    279     cache_file += "/";
    280     cache_file += DexFileLoader::kClassesDex;
    281   }
    282   std::replace(cache_file.begin(), cache_file.end(), '/', '@');
    283   *filename = StringPrintf("%s/%s", cache_location, cache_file.c_str());
    284   return true;
    285 }
    286 
    287 std::string GetVdexFilename(const std::string& oat_location) {
    288   return ReplaceFileExtension(oat_location, "vdex");
    289 }
    290 
    291 static void InsertIsaDirectory(const InstructionSet isa, std::string* filename) {
    292   // in = /foo/bar/baz
    293   // out = /foo/bar/<isa>/baz
    294   size_t pos = filename->rfind('/');
    295   CHECK_NE(pos, std::string::npos) << *filename << " " << isa;
    296   filename->insert(pos, "/", 1);
    297   filename->insert(pos + 1, GetInstructionSetString(isa));
    298 }
    299 
    300 std::string GetSystemImageFilename(const char* location, const InstructionSet isa) {
    301   // location = /system/framework/boot.art
    302   // filename = /system/framework/<isa>/boot.art
    303   std::string filename(location);
    304   InsertIsaDirectory(isa, &filename);
    305   return filename;
    306 }
    307 
    308 std::string ReplaceFileExtension(const std::string& filename, const std::string& new_extension) {
    309   const size_t last_ext = filename.find_last_of('.');
    310   if (last_ext == std::string::npos) {
    311     return filename + "." + new_extension;
    312   } else {
    313     return filename.substr(0, last_ext + 1) + new_extension;
    314   }
    315 }
    316 
    317 bool LocationIsOnSystem(const char* path) {
    318   UniqueCPtr<const char[]> full_path(realpath(path, nullptr));
    319   return full_path != nullptr &&
    320       android::base::StartsWith(full_path.get(), GetAndroidRoot().c_str());
    321 }
    322 
    323 bool LocationIsOnSystemFramework(const char* full_path) {
    324   std::string error_msg;
    325   std::string root_path = GetAndroidRootSafe(&error_msg);
    326   if (root_path.empty()) {
    327     // Could not find Android root.
    328     // TODO(dbrazdil): change to stricter GetAndroidRoot() once b/76452688 is resolved.
    329     return false;
    330   }
    331   std::string framework_path = root_path + "/framework/";
    332   return android::base::StartsWith(full_path, framework_path);
    333 }
    334 
    335 }  // namespace art
    336