Add zip-fd support in dexoptanalyzer
Test: installd flow(manual), oat_file_assistant_test
(cherry-picked from commit 89455b30a30de68d389cef68748a01e13ea1356)
Bug: 67111829
Change-Id: Icf24c671ee060c75ba53932a7ccbe422e0ceb2e0
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index 7e9ecab..39c9b99 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -103,6 +103,8 @@
UsageError("");
UsageError(" --vdex-fd=number: file descriptor of the vdex file corresponding to the oat file");
UsageError("");
+ UsageError(" --zip-fd=number: specifies a file descriptor corresponding to the dex file.");
+ UsageError("");
UsageError(" --downgrade: optional, if the purpose of dexopt is to downgrade the dex file");
UsageError(" By default, dexopt considers upgrade case.");
UsageError("");
@@ -175,8 +177,19 @@
downgrade_ = true;
} else if (option.starts_with("--oat-fd")) {
oat_fd_ = std::stoi(option.substr(strlen("--oat-fd=")).ToString(), nullptr, 0);
+ if (oat_fd_ < 0) {
+ Usage("Invalid --oat-fd %d", oat_fd_);
+ }
} else if (option.starts_with("--vdex-fd")) {
vdex_fd_ = std::stoi(option.substr(strlen("--vdex-fd=")).ToString(), nullptr, 0);
+ if (vdex_fd_ < 0) {
+ Usage("Invalid --vdex-fd %d", vdex_fd_);
+ }
+ } else if (option.starts_with("--zip-fd")) {
+ zip_fd_ = std::stoi(option.substr(strlen("--zip-fd=")).ToString(), nullptr, 0);
+ if (zip_fd_ < 0) {
+ Usage("Invalid --zip-fd %d", zip_fd_);
+ }
} else if (option.starts_with("--class-loader-context=")) {
std::string context_str = option.substr(strlen("--class-loader-context=")).ToString();
class_loader_context_ = ClassLoaderContext::Create(context_str);
@@ -199,12 +212,6 @@
Usage("--image unspecified and ANDROID_ROOT not set or image file does not exist.");
}
}
- if (oat_fd_ > 0 && vdex_fd_ < 0) {
- Usage("A valid --vdex-fd must also be provided with --oat-fd.");
- }
- if (oat_fd_ < 0 && vdex_fd_ > 0) {
- Usage("A valid --oat-fd must also be provided with --vdex-fd.");
- }
}
bool CreateRuntime() {
@@ -248,17 +255,12 @@
std::unique_ptr<Runtime> runtime(Runtime::Current());
std::unique_ptr<OatFileAssistant> oat_file_assistant;
- if (oat_fd_ != -1 && vdex_fd_ != -1) {
- oat_file_assistant = std::make_unique<OatFileAssistant>(dex_file_.c_str(),
- isa_,
- false /*load_executable*/,
- vdex_fd_,
- oat_fd_);
- } else {
- oat_file_assistant = std::make_unique<OatFileAssistant>(dex_file_.c_str(),
- isa_,
- false /*load_executable*/);
- }
+ oat_file_assistant = std::make_unique<OatFileAssistant>(dex_file_.c_str(),
+ isa_,
+ false /*load_executable*/,
+ vdex_fd_,
+ oat_fd_,
+ zip_fd_);
// Always treat elements of the bootclasspath as up-to-date.
// TODO(calin): this check should be in OatFileAssistant.
if (oat_file_assistant->IsInBootClassPath()) {
@@ -295,6 +297,8 @@
std::string image_;
int oat_fd_ = -1;
int vdex_fd_ = -1;
+ // File descriptor corresponding to apk, dex_file, or zip.
+ int zip_fd_ = -1;
};
static int dexoptAnalyze(int argc, char** argv) {
diff --git a/runtime/base/file_magic.cc b/runtime/base/file_magic.cc
index 30b4f05..dffb9b4 100644
--- a/runtime/base/file_magic.cc
+++ b/runtime/base/file_magic.cc
@@ -37,19 +37,26 @@
*error_msg = StringPrintf("Unable to open '%s' : %s", filename, strerror(errno));
return File();
}
- int n = TEMP_FAILURE_RETRY(read(fd.Fd(), magic, sizeof(*magic)));
- if (n != sizeof(*magic)) {
- *error_msg = StringPrintf("Failed to find magic in '%s'", filename);
- return File();
- }
- if (lseek(fd.Fd(), 0, SEEK_SET) != 0) {
- *error_msg = StringPrintf("Failed to seek to beginning of file '%s' : %s", filename,
- strerror(errno));
+ if (!ReadMagicAndReset(fd.Fd(), magic, error_msg)) {
+ StringPrintf("Error in reading magic from file %s: %s", filename, error_msg->c_str());
return File();
}
return fd;
}
+bool ReadMagicAndReset(int fd, uint32_t* magic, std::string* error_msg) {
+ int n = TEMP_FAILURE_RETRY(read(fd, magic, sizeof(*magic)));
+ if (n != sizeof(*magic)) {
+ *error_msg = StringPrintf("Failed to find magic");
+ return false;
+ }
+ if (lseek(fd, 0, SEEK_SET) != 0) {
+ *error_msg = StringPrintf("Failed to seek to beginning of file : %s", strerror(errno));
+ return false;
+ }
+ return true;
+}
+
bool IsZipMagic(uint32_t magic) {
return (('P' == ((magic >> 0) & 0xff)) &&
('K' == ((magic >> 8) & 0xff)));
diff --git a/runtime/base/file_magic.h b/runtime/base/file_magic.h
index 1c9effd..e7bd706 100644
--- a/runtime/base/file_magic.h
+++ b/runtime/base/file_magic.h
@@ -27,6 +27,9 @@
// Open file and read magic number
File OpenAndReadMagic(const char* filename, uint32_t* magic, std::string* error_msg);
+// Read magic number and reset pointer to SEEK_SET.
+bool ReadMagicAndReset(int fd, uint32_t* magic, std::string* error_msg);
+
// Check whether the given magic matches a known file type.
bool IsZipMagic(uint32_t magic);
diff --git a/runtime/dex_file_loader.cc b/runtime/dex_file_loader.cc
index 06e3397..bc92769 100644
--- a/runtime/dex_file_loader.cc
+++ b/runtime/dex_file_loader.cc
@@ -103,11 +103,19 @@
bool DexFileLoader::GetMultiDexChecksums(const char* filename,
std::vector<uint32_t>* checksums,
- std::string* error_msg) {
+ std::string* error_msg,
+ int zip_fd) {
CHECK(checksums != nullptr);
uint32_t magic;
- File fd = OpenAndReadMagic(filename, &magic, error_msg);
+ File fd;
+ if (zip_fd != -1) {
+ if (ReadMagicAndReset(zip_fd, &magic, error_msg)) {
+ fd = File(zip_fd, false /* check_usage */);
+ }
+ } else {
+ fd = OpenAndReadMagic(filename, &magic, error_msg);
+ }
if (fd.Fd() == -1) {
DCHECK(!error_msg->empty());
return false;
diff --git a/runtime/dex_file_loader.h b/runtime/dex_file_loader.h
index 97c886a..1763123 100644
--- a/runtime/dex_file_loader.h
+++ b/runtime/dex_file_loader.h
@@ -50,10 +50,15 @@
// For .dex files, this is the single header checksum.
// For zip files, this is the zip entry CRC32 checksum for classes.dex and
// each additional multidex entry classes2.dex, classes3.dex, etc.
+ // If a valid zip_fd is provided the file content will be read directly from
+ // the descriptor and `filename` will be used as alias for error logging. If
+ // zip_fd is -1, the method will try to open the `filename` and read the
+ // content from it.
// Return true if the checksums could be found, false otherwise.
static bool GetMultiDexChecksums(const char* filename,
std::vector<uint32_t>* checksums,
- std::string* error_msg);
+ std::string* error_msg,
+ int zip_fd = -1);
// Check whether a location denotes a multidex dex file. This is a very simple check: returns
// whether the string contains the separator character.
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 9f6bf69..97b2aec 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -71,15 +71,34 @@
OatFileAssistant::OatFileAssistant(const char* dex_location,
const InstructionSet isa,
+ bool load_executable)
+ : OatFileAssistant(dex_location,
+ isa, load_executable,
+ -1 /* vdex_fd */,
+ -1 /* oat_fd */,
+ -1 /* zip_fd */) {}
+
+
+OatFileAssistant::OatFileAssistant(const char* dex_location,
+ const InstructionSet isa,
bool load_executable,
int vdex_fd,
- int oat_fd)
+ int oat_fd,
+ int zip_fd)
: isa_(isa),
load_executable_(load_executable),
odex_(this, /*is_oat_location*/ false),
- oat_(this, /*is_oat_location*/ true) {
+ oat_(this, /*is_oat_location*/ true),
+ zip_fd_(zip_fd) {
CHECK(dex_location != nullptr) << "OatFileAssistant: null dex location";
+ if (zip_fd < 0) {
+ CHECK_LE(oat_fd, 0) << "zip_fd must be provided with valid oat_fd. zip_fd=" << zip_fd
+ << " oat_fd=" << oat_fd;
+ CHECK_LE(vdex_fd, 0) << "zip_fd must be provided with valid vdex_fd. zip_fd=" << zip_fd
+ << " vdex_fd=" << vdex_fd;;
+ }
+
// Try to get the realpath for the dex location.
//
// This is OK with respect to dalvik cache naming scheme because we never
@@ -113,18 +132,20 @@
std::string error_msg;
std::string odex_file_name;
if (DexLocationToOdexFilename(dex_location_, isa_, &odex_file_name, &error_msg)) {
- odex_.Reset(odex_file_name, vdex_fd, oat_fd);
+ odex_.Reset(odex_file_name, UseFdToReadFiles(), vdex_fd, oat_fd);
} else {
LOG(WARNING) << "Failed to determine odex file name: " << error_msg;
}
- // Get the oat filename.
- std::string oat_file_name;
- if (DexLocationToOatFilename(dex_location_, isa_, &oat_file_name, &error_msg)) {
- oat_.Reset(oat_file_name);
- } else {
- LOG(WARNING) << "Failed to determine oat file name for dex location "
- << dex_location_ << ": " << error_msg;
+ if (!UseFdToReadFiles()) {
+ // Get the oat filename.
+ std::string oat_file_name;
+ if (DexLocationToOatFilename(dex_location_, isa_, &oat_file_name, &error_msg)) {
+ oat_.Reset(oat_file_name, false /* use_fd */);
+ } else {
+ LOG(WARNING) << "Failed to determine oat file name for dex location "
+ << dex_location_ << ": " << error_msg;
+ }
}
// Check if the dex directory is writable.
@@ -134,9 +155,11 @@
size_t pos = dex_location_.rfind('/');
if (pos == std::string::npos) {
LOG(WARNING) << "Failed to determine dex file parent directory: " << dex_location_;
- } else {
+ } else if (!UseFdToReadFiles()) {
+ // We cannot test for parent access when using file descriptors. That's ok
+ // because in this case we will always pick the odex file anyway.
std::string parent = dex_location_.substr(0, pos);
- if (access(parent.c_str(), W_OK) == 0 || oat_fd > 0) {
+ if (access(parent.c_str(), W_OK) == 0) {
dex_parent_writable_ = true;
} else {
VLOG(oat) << "Dex parent of " << dex_location_ << " is not writable: " << strerror(errno);
@@ -151,6 +174,10 @@
}
}
+bool OatFileAssistant::UseFdToReadFiles() {
+ return zip_fd_ >= 0;
+}
+
bool OatFileAssistant::IsInBootClassPath() {
// Note: We check the current boot class path, regardless of the ISA
// specified by the user. This is okay, because the boot class path should
@@ -237,6 +264,9 @@
OatFileAssistant::MakeUpToDate(bool profile_changed,
ClassLoaderContext* class_loader_context,
std::string* error_msg) {
+ // The method doesn't use zip_fd_ and directly opens dex files at dex_locations_.
+ CHECK_EQ(-1, zip_fd_) << "MakeUpToDate should not be called with zip_fd";
+
CompilerFilter::Filter target;
if (!GetRuntimeCompilerFilterOption(&target, error_msg)) {
return kUpdateNotAttempted;
@@ -869,7 +899,8 @@
std::string error_msg;
if (DexFileLoader::GetMultiDexChecksums(dex_location_.c_str(),
&cached_required_dex_checksums_,
- &error_msg)) {
+ &error_msg,
+ zip_fd_)) {
required_dex_checksums_found_ = true;
has_original_dex_files_ = true;
} else {
@@ -932,7 +963,7 @@
OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
// TODO(calin): Document the side effects of class loading when
// running dalvikvm command line.
- if (dex_parent_writable_) {
+ if (dex_parent_writable_ || UseFdToReadFiles()) {
// 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
@@ -1021,26 +1052,28 @@
std::string error_msg;
std::string vdex_filename = GetVdexFilename(filename_);
std::unique_ptr<VdexFile> vdex;
- if (vdex_fd_ == -1) {
+ if (use_fd_) {
+ if (vdex_fd_ >= 0) {
+ struct stat s;
+ int rc = TEMP_FAILURE_RETRY(fstat(vdex_fd_, &s));
+ if (rc == -1) {
+ error_msg = StringPrintf("Failed getting length of the vdex file %s.", strerror(errno));
+ } else {
+ vdex = VdexFile::Open(vdex_fd_,
+ s.st_size,
+ vdex_filename,
+ false /*writable*/,
+ false /*low_4gb*/,
+ false /* unquicken */,
+ &error_msg);
+ }
+ }
+ } else {
vdex = VdexFile::Open(vdex_filename,
false /*writeable*/,
false /*low_4gb*/,
false /*unquicken*/,
&error_msg);
- } else {
- struct stat s;
- int rc = TEMP_FAILURE_RETRY(fstat(vdex_fd_, &s));
- if (rc == -1) {
- PLOG(WARNING) << "Failed getting length of vdex file";
- } else {
- vdex = VdexFile::Open(vdex_fd_,
- s.st_size,
- vdex_filename,
- false /*writable*/,
- false /*low_4gb*/,
- false /* unquicken */,
- &error_msg);
- }
}
if (vdex == nullptr) {
status_ = kOatCannotOpen;
@@ -1116,16 +1149,18 @@
load_attempted_ = true;
if (filename_provided_) {
std::string error_msg;
- if (oat_fd_ != -1 && vdex_fd_ != -1) {
- file_.reset(OatFile::Open(vdex_fd_,
- oat_fd_,
- filename_.c_str(),
- nullptr,
- nullptr,
- oat_file_assistant_->load_executable_,
- false /* low_4gb */,
- oat_file_assistant_->dex_location_.c_str(),
- &error_msg));
+ if (use_fd_) {
+ if (oat_fd_ >= 0 && vdex_fd_ >= 0) {
+ file_.reset(OatFile::Open(vdex_fd_,
+ oat_fd_,
+ filename_.c_str(),
+ nullptr,
+ nullptr,
+ oat_file_assistant_->load_executable_,
+ false /* low_4gb */,
+ oat_file_assistant_->dex_location_.c_str(),
+ &error_msg));
+ }
} else {
file_.reset(OatFile::Open(filename_.c_str(),
filename_.c_str(),
@@ -1203,10 +1238,11 @@
status_attempted_ = false;
}
-void OatFileAssistant::OatFileInfo::Reset(const std::string& filename, int vdex_fd,
+void OatFileAssistant::OatFileInfo::Reset(const std::string& filename, bool use_fd, int vdex_fd,
int oat_fd) {
filename_provided_ = true;
filename_ = filename;
+ use_fd_ = use_fd;
vdex_fd_ = vdex_fd;
oat_fd_ = oat_fd;
Reset();
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 44d8bd8..6c01c1e 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -121,9 +121,17 @@
// executable code for this dex location.
OatFileAssistant(const char* dex_location,
const InstructionSet isa,
+ bool load_executable);
+
+ // Similar to this(const char*, const InstructionSet, bool), however, if a valid zip_fd is
+ // provided, vdex, oat, and zip files will be read from vdex_fd, oat_fd and zip_fd respectively.
+ // Otherwise, dex_location will be used to construct necessary filenames.
+ OatFileAssistant(const char* dex_location,
+ const InstructionSet isa,
bool load_executable,
- int vdex_fd = -1,
- int oat_fd = -1);
+ int vdex_fd,
+ int oat_fd,
+ int zip_fd);
~OatFileAssistant();
@@ -351,7 +359,7 @@
// Clear any cached information and switch to getting info about the oat
// file with the given filename.
- void Reset(const std::string& filename, int vdex_fd = -1, int oat_fd = -1);
+ void Reset(const std::string& filename, bool use_fd, int vdex_fd = -1, int oat_fd = -1);
// Release the loaded oat file for runtime use.
// Returns null if the oat file hasn't been loaded or is out of date.
@@ -390,6 +398,7 @@
int oat_fd_ = -1;
int vdex_fd_ = -1;
+ bool use_fd_ = false;
bool load_attempted_ = false;
std::unique_ptr<OatFile> file_;
@@ -420,6 +429,12 @@
// Return info for the best oat file.
OatFileInfo& GetBestInfo();
+ // Returns true when vdex/oat/odex files should be read from file descriptors.
+ // The method checks the value of zip_fd_, and if the value is valid, returns
+ // true. This is required to have a deterministic behavior around how different
+ // files are being read.
+ bool UseFdToReadFiles();
+
// Returns true if the dex checksums in the given vdex file are up to date
// with respect to the dex location. If the dex checksums are not up to
// date, error_msg is updated with a message describing the problem.
@@ -482,6 +497,9 @@
OatFileInfo odex_;
OatFileInfo oat_;
+ // File descriptor corresponding to apk, dex file, or zip.
+ int zip_fd_;
+
// Cached value of the image info.
// Use the GetImageInfo method rather than accessing these directly.
// TODO: The image info should probably be moved out of the oat file
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index d12c331..bd500eb 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -241,12 +241,14 @@
android::base::unique_fd odex_fd(open(odex_location.c_str(), O_RDONLY));
android::base::unique_fd vdex_fd(open(vdex_location.c_str(), O_RDONLY));
+ android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY));
OatFileAssistant oat_file_assistant(dex_location.c_str(),
kRuntimeISA,
false,
vdex_fd.get(),
- odex_fd.get());
+ odex_fd.get(),
+ zip_fd.get());
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
@@ -262,37 +264,8 @@
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
-// Case: Passing valid odex fd, however, invalid fd for vdex with
-// the dex file.
-// Expect: The status is kDex2oatFromScratch.
-TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidVdexFd) {
- std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
- std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
-
- Copy(GetDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str(),
- odex_location.c_str(),
- CompilerFilter::kSpeed,
- true,
- false,
- false);
-
- android::base::unique_fd odex_fd(open(odex_location.c_str(), O_RDONLY));
-
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- false,
- -1,
- odex_fd.get());
- EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
- EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-}
-
-// Case: Passing valid vdex fd, however, invalid fd for odex with
-// the dex file.
-// Expect: The status is kDex2oatFromScratch.
+// Case: Passing invalid odex fd and valid vdex and zip fds.
+// Expect: The status should be kDex2OatForBootImage.
TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidOdexFd) {
std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
@@ -307,35 +280,71 @@
false);
android::base::unique_fd vdex_fd(open(vdex_location.c_str(), O_RDONLY));
+ android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY));
OatFileAssistant oat_file_assistant(dex_location.c_str(),
kRuntimeISA,
false,
vdex_fd.get(),
- -1);
- // Even though the vdex file is up to date, because we don't have the oat
- // file, we can't know that the vdex depends on the boot image and is up to
- // date with respect to the boot image. Instead we must assume the vdex file
- // depends on the boot image and is out of date with respect to the boot
- // image.
+ -1 /* oat_fd */,
+ zip_fd.get());
EXPECT_EQ(-OatFileAssistant::kDex2OatForBootImage,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_EQ(-OatFileAssistant::kDex2OatForBootImage,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
+
+ EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
-// Case: Passing invalid vdex and odex fd with the dex file.
+// Case: Passing invalid vdex fd and valid odex and zip fds.
+// Expect: The status should be kDex2OatFromScratch.
+TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidVdexFd) {
+ std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
+ std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
+
+ Copy(GetDexSrc1(), dex_location);
+ GenerateOatForTest(dex_location.c_str(),
+ odex_location.c_str(),
+ CompilerFilter::kSpeed,
+ true,
+ false,
+ false);
+
+ android::base::unique_fd odex_fd(open(odex_location.c_str(), O_RDONLY));
+ android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY));
+
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ false,
+ -1 /* vdex_fd */,
+ odex_fd.get(),
+ zip_fd.get());
+
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+}
+
+// Case: Passing invalid vdex and odex fd with valid zip fd.
// Expect: The status is kDex2oatFromScratch.
TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidOdexVdexFd) {
std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
Copy(GetDexSrc1(), dex_location);
+ android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY));
OatFileAssistant oat_file_assistant(dex_location.c_str(),
kRuntimeISA,
false,
- -1,
- -1);
+ -1 /* vdex_fd */,
+ -1 /* oat_fd */,
+ zip_fd);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());