Revert "Ensure dex file are extracted and verified at load time"
The art build bot fails for the oat location tests. I suspect that ScopedNonWritable is not working properly on the bot.
This reverts commit d2510c92e7c1f571ab012fcb82e77d7e1806ae3b.
Change-Id: Ica70862fd608ebdeb3c710f786ae21b99b69bc20
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 603bbbf..eafa77f 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -68,34 +68,19 @@
OatFileAssistant::OatFileAssistant(const char* dex_location,
const InstructionSet isa,
bool load_executable)
+ : OatFileAssistant(dex_location, nullptr, isa, load_executable)
+{ }
+
+OatFileAssistant::OatFileAssistant(const char* dex_location,
+ const char* oat_location,
+ const InstructionSet isa,
+ bool load_executable)
: isa_(isa),
load_executable_(load_executable),
odex_(this, /*is_oat_location*/ false),
oat_(this, /*is_oat_location*/ true) {
CHECK(dex_location != nullptr) << "OatFileAssistant: null dex location";
-
- // Try to get the realpath for the dex location.
- //
- // This is OK with respect to dalvik cache naming scheme because we never
- // generate oat files starting from symlinks which go into dalvik cache.
- // (recall that the oat files in dalvik cache are encoded by replacing '/'
- // with '@' in the path).
- // The boot image oat files (which are symlinked in dalvik-cache) are not
- // loaded via the oat file assistant.
- //
- // The only case when the dex location may resolve to a different path
- // is for secondary dex files (e.g. /data/user/0 symlinks to /data/data and
- // the app is free to create its own internal layout). Related to this it is
- // worthwhile to mention that installd resolves the secondary dex location
- // before calling dex2oat.
- UniqueCPtr<const char[]> dex_location_real(realpath(dex_location, nullptr));
- if (dex_location_real != nullptr) {
- dex_location_.assign(dex_location_real.get());
- } else {
- // If we can't get the realpath of the location there's not much point in trying to move on.
- PLOG(ERROR) << "Could not get the realpath of dex_location " << dex_location;
- return;
- }
+ dex_location_.assign(dex_location);
if (load_executable_ && isa != kRuntimeISA) {
LOG(WARNING) << "OatFileAssistant: Load executable specified, "
@@ -113,27 +98,15 @@
}
// Get the oat filename.
- std::string oat_file_name;
- if (DexLocationToOatFilename(dex_location_, isa_, &oat_file_name, &error_msg)) {
- oat_.Reset(oat_file_name);
+ if (oat_location != nullptr) {
+ oat_.Reset(oat_location);
} else {
- LOG(WARNING) << "Failed to determine oat file name for dex location "
- << dex_location_ << ": " << error_msg;
- }
-
- // Check if the dex directory is writable.
- // This will be needed in most uses of OatFileAssistant and so it's OK to
- // compute it eagerly. (the only use which will not make use of it is
- // OatFileAssistant::GetStatusDump())
- size_t pos = dex_location_.rfind('/');
- if (pos == std::string::npos) {
- LOG(WARNING) << "Failed to determine dex file parent directory: " << dex_location_;
- } else {
- std::string parent = dex_location_.substr(0, pos);
- if (access(parent.c_str(), W_OK) == 0) {
- dex_parent_writable_ = true;
+ std::string oat_file_name;
+ if (DexLocationToOatFilename(dex_location_, isa_, &oat_file_name, &error_msg)) {
+ oat_.Reset(oat_file_name);
} else {
- VLOG(oat) << "Dex parent of " << dex_location_ << " is not writable: " << strerror(errno);
+ LOG(WARNING) << "Failed to determine oat file name for dex location "
+ << dex_location_ << ": " << error_msg;
}
}
}
@@ -166,17 +139,12 @@
CHECK(error_msg != nullptr);
CHECK(!flock_.HasFile()) << "OatFileAssistant::Lock already acquired";
- // Note the lock will only succeed for secondary dex files and in test
- // environment.
- //
- // The lock *will fail* for all primary apks in a production environment.
- // The app does not have permissions to create locks next to its dex location
- // (be it system, data or vendor parition). We also cannot use the odex or
- // oat location for the same reasoning.
- //
- // This is best effort and if it fails it's unlikely that we will be able
- // to generate oat files anyway.
- std::string lock_file_name = dex_location_ + "." + GetInstructionSetString(isa_) + ".flock";
+ const std::string* oat_file_name = oat_.Filename();
+ if (oat_file_name == nullptr) {
+ *error_msg = "Failed to determine lock file";
+ return false;
+ }
+ std::string lock_file_name = *oat_file_name + ".flock";
if (!flock_.Init(lock_file_name.c_str(), error_msg)) {
unlink(lock_file_name.c_str());
@@ -202,7 +170,7 @@
CHECK(filter != nullptr);
CHECK(error_msg != nullptr);
- *filter = OatFileAssistant::kDefaultCompilerFilterForDexLoading;
+ *filter = CompilerFilter::kDefaultCompilerFilter;
for (StringPiece option : Runtime::Current()->GetCompilerOptions()) {
if (option.starts_with("--compiler-filter=")) {
const char* compiler_filter_string = option.substr(strlen("--compiler-filter=")).data();
@@ -239,7 +207,7 @@
case kDex2OatForBootImage:
case kDex2OatForRelocation:
case kDex2OatForFilter:
- return GenerateOatFileNoChecks(info, error_msg);
+ return GenerateOatFile(error_msg);
}
UNREACHABLE();
}
@@ -511,110 +479,8 @@
return kOatUpToDate;
}
-static bool DexLocationToOdexNames(const std::string& location,
- InstructionSet isa,
- std::string* odex_filename,
- std::string* oat_dir,
- std::string* isa_dir,
- std::string* error_msg) {
- CHECK(odex_filename != nullptr);
- CHECK(error_msg != nullptr);
-
- // The odex file name is formed by replacing the dex_location extension with
- // .odex and inserting an oat/<isa> directory. For example:
- // location = /foo/bar/baz.jar
- // odex_location = /foo/bar/oat/<isa>/baz.odex
-
- // Find the directory portion of the dex location and add the oat/<isa>
- // directory.
- size_t pos = location.rfind('/');
- if (pos == std::string::npos) {
- *error_msg = "Dex location " + location + " has no directory.";
- return false;
- }
- std::string dir = location.substr(0, pos+1);
- // Add the oat directory.
- dir += "oat";
- if (oat_dir != nullptr) {
- *oat_dir = dir;
- }
- // Add the isa directory
- dir += "/" + std::string(GetInstructionSetString(isa));
- if (isa_dir != nullptr) {
- *isa_dir = dir;
- }
-
- // Get the base part of the file without the extension.
- std::string file = location.substr(pos+1);
- pos = file.rfind('.');
- if (pos == std::string::npos) {
- *error_msg = "Dex location " + location + " has no extension.";
- return false;
- }
- std::string base = file.substr(0, pos);
-
- *odex_filename = dir + "/" + base + ".odex";
- return true;
-}
-
-// Prepare a subcomponent of the odex directory.
-// (i.e. create and set the expected permissions on the path `dir`).
-static bool PrepareDirectory(const std::string& dir, std::string* error_msg) {
- struct stat dir_stat;
- if (TEMP_FAILURE_RETRY(stat(dir.c_str(), &dir_stat)) == 0) {
- // The directory exists. Check if it is indeed a directory.
- if (!S_ISDIR(dir_stat.st_mode)) {
- *error_msg = dir + " is not a dir";
- return false;
- } else {
- // The dir is already on disk.
- return true;
- }
- }
-
- // Failed to stat. We need to create the directory.
- if (errno != ENOENT) {
- *error_msg = "Could not stat isa dir " + dir + ":" + strerror(errno);
- return false;
- }
-
- mode_t mode = S_IRWXU | S_IXGRP | S_IXOTH;
- if (mkdir(dir.c_str(), mode) != 0) {
- *error_msg = "Could not create dir " + dir + ":" + strerror(errno);
- return false;
- }
- if (chmod(dir.c_str(), mode) != 0) {
- *error_msg = "Could not create the oat dir " + dir + ":" + strerror(errno);
- return false;
- }
- return true;
-}
-
-// Prepares the odex directory for the given dex location.
-static bool PrepareOdexDirectories(const std::string& dex_location,
- const std::string& expected_odex_location,
- InstructionSet isa,
- std::string* error_msg) {
- std::string actual_odex_location;
- std::string oat_dir;
- std::string isa_dir;
- if (!DexLocationToOdexNames(
- dex_location, isa, &actual_odex_location, &oat_dir, &isa_dir, error_msg)) {
- return false;
- }
- DCHECK_EQ(expected_odex_location, actual_odex_location);
-
- if (!PrepareDirectory(oat_dir, error_msg)) {
- return false;
- }
- if (!PrepareDirectory(isa_dir, error_msg)) {
- return false;
- }
- return true;
-}
-
-OatFileAssistant::ResultOfAttemptToUpdate OatFileAssistant::GenerateOatFileNoChecks(
- OatFileAssistant::OatFileInfo& info, std::string* error_msg) {
+OatFileAssistant::ResultOfAttemptToUpdate
+OatFileAssistant::GenerateOatFile(std::string* error_msg) {
CHECK(error_msg != nullptr);
Runtime* runtime = Runtime::Current();
@@ -624,37 +490,22 @@
return kUpdateNotAttempted;
}
- if (info.Filename() == nullptr) {
+ if (oat_.Filename() == nullptr) {
*error_msg = "Generation of oat file for dex location " + dex_location_
+ " not attempted because the oat file name could not be determined.";
return kUpdateNotAttempted;
}
- const std::string& oat_file_name = *info.Filename();
+ const std::string& oat_file_name = *oat_.Filename();
const std::string& vdex_file_name = ReplaceFileExtension(oat_file_name, "vdex");
// dex2oat ignores missing dex files and doesn't report an error.
// Check explicitly here so we can detect the error properly.
// TODO: Why does dex2oat behave that way?
- struct stat dex_path_stat;
- if (TEMP_FAILURE_RETRY(stat(dex_location_.c_str(), &dex_path_stat)) != 0) {
- *error_msg = "Could not access dex location " + dex_location_ + ":" + strerror(errno);
+ if (!OS::FileExists(dex_location_.c_str())) {
+ *error_msg = "Dex location " + dex_location_ + " does not exists.";
return kUpdateNotAttempted;
}
- // If this is the odex location, we need to create the odex file layout (../oat/isa/..)
- if (!info.IsOatLocation()) {
- if (!PrepareOdexDirectories(dex_location_, oat_file_name, isa_, error_msg)) {
- return kUpdateNotAttempted;
- }
- }
-
- // Set the permissions for the oat and the vdex files.
- // The user always gets read and write while the group and others propagate
- // the reading access of the original dex file.
- mode_t file_mode = S_IRUSR | S_IWUSR |
- (dex_path_stat.st_mode & S_IRGRP) |
- (dex_path_stat.st_mode & S_IROTH);
-
std::unique_ptr<File> vdex_file(OS::CreateEmptyFile(vdex_file_name.c_str()));
if (vdex_file.get() == nullptr) {
*error_msg = "Generation of oat file " + oat_file_name
@@ -663,7 +514,7 @@
return kUpdateNotAttempted;
}
- if (fchmod(vdex_file->Fd(), file_mode) != 0) {
+ if (fchmod(vdex_file->Fd(), 0644) != 0) {
*error_msg = "Generation of oat file " + oat_file_name
+ " not attempted because the vdex file " + vdex_file_name
+ " could not be made world readable.";
@@ -677,7 +528,7 @@
return kUpdateNotAttempted;
}
- if (fchmod(oat_file->Fd(), file_mode) != 0) {
+ if (fchmod(oat_file->Fd(), 0644) != 0) {
*error_msg = "Generation of oat file " + oat_file_name
+ " not attempted because the oat file could not be made world readable.";
oat_file->Erase();
@@ -712,8 +563,8 @@
return kUpdateFailed;
}
- // Mark that the odex file has changed and we should try to reload.
- info.Reset();
+ // Mark that the oat file has changed and we should try to reload.
+ oat_.Reset();
return kUpdateSucceeded;
}
@@ -772,7 +623,35 @@
InstructionSet isa,
std::string* odex_filename,
std::string* error_msg) {
- return DexLocationToOdexNames(location, isa, odex_filename, nullptr, nullptr, error_msg);
+ CHECK(odex_filename != nullptr);
+ CHECK(error_msg != nullptr);
+
+ // The odex file name is formed by replacing the dex_location extension with
+ // .odex and inserting an oat/<isa> directory. For example:
+ // location = /foo/bar/baz.jar
+ // odex_location = /foo/bar/oat/<isa>/baz.odex
+
+ // Find the directory portion of the dex location and add the oat/<isa>
+ // directory.
+ size_t pos = location.rfind('/');
+ if (pos == std::string::npos) {
+ *error_msg = "Dex location " + location + " has no directory.";
+ return false;
+ }
+ std::string dir = location.substr(0, pos+1);
+ dir += "oat/" + std::string(GetInstructionSetString(isa));
+
+ // Get the base part of the file without the extension.
+ std::string file = location.substr(pos+1);
+ pos = file.rfind('.');
+ if (pos == std::string::npos) {
+ *error_msg = "Dex location " + location + " has no extension.";
+ return false;
+ }
+ std::string base = file.substr(0, pos);
+
+ *odex_filename = dir + "/" + base + ".odex";
+ return true;
}
bool OatFileAssistant::DexLocationToOatFilename(const std::string& location,
@@ -873,45 +752,8 @@
}
OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
- // TODO(calin): Document the side effects of class loading when
- // running dalvikvm command line.
- if (dex_parent_writable_) {
- // If the parent of the dex file is writable it means that we can
- // create the odex file. In this case we unconditionally pick the odex
- // as the best oat file. This corresponds to the regular use case when
- // apps gets installed or when they load private, secondary dex file.
- // For apps on the system partition the odex location will not be
- // writable and thus the oat location might be more up to date.
- return odex_;
- }
-
- // We cannot write to the odex location. This must be a system app.
-
- // If the oat location is usable take it.
- if (oat_.IsUseable()) {
- return oat_;
- }
-
- // The oat file is not usable but the odex file might be up to date.
- // This is an indication that we are dealing with an up to date prebuilt
- // (that doesn't need relocation).
- if (odex_.Status() == kOatUpToDate) {
- return odex_;
- }
-
- // The oat file is not usable and the odex file is not up to date.
- // However we have access to the original dex file which means we can make
- // the oat location up to date.
- if (HasOriginalDexFiles()) {
- return oat_;
- }
-
- // We got into the worst situation here:
- // - the oat location is not usable
- // - the prebuild odex location is not up to date
- // - and we don't have the original dex file anymore (stripped).
- // Pick the odex if it exists, or the oat if not.
- return (odex_.Status() == kOatCannotOpen) ? oat_ : odex_;
+ bool use_oat = oat_.IsUseable() || odex_.Status() == kOatCannotOpen;
+ return use_oat ? oat_ : odex_;
}
std::unique_ptr<gc::space::ImageSpace> OatFileAssistant::OpenImageSpace(const OatFile* oat_file) {