summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Uhler <ruhler@google.com>2015-03-18 08:21:11 -0700
committerRichard Uhler <ruhler@google.com>2015-03-24 12:48:09 -0700
commite5fed03772144595c0904faf3d6974cc55214c8c (patch)
tree27c242e48cabd2543f472930d1ad7e2ab86557fe
parentb93581f857e36a62f690e26e78167f2abea0f033 (diff)
downloadart-e5fed03772144595c0904faf3d6974cc55214c8c.zip
art-e5fed03772144595c0904faf3d6974cc55214c8c.tar.gz
art-e5fed03772144595c0904faf3d6974cc55214c8c.tar.bz2
Support relative encoded dex locations in oat files.
Now when opening an oat file, the caller can pass an absolute dex location used to resolve the absolute path for any relative encoded dex locations in the oat file. Bug: 19550105 Change-Id: I6e9559afe4d86ac12cf0b90176b5ea696a83d0e7
-rw-r--r--build/Android.gtest.mk1
-rw-r--r--compiler/image_writer.cc2
-rw-r--r--compiler/oat_test.cc2
-rw-r--r--oatdump/oatdump.cc8
-rw-r--r--runtime/dex_file.h19
-rw-r--r--runtime/dex_file_test.cc9
-rw-r--r--runtime/gc/space/image_space.cc3
-rw-r--r--runtime/oat_file.cc53
-rw-r--r--runtime/oat_file.h29
-rw-r--r--runtime/oat_file_assistant.cc5
-rw-r--r--runtime/oat_file_assistant_test.cc37
-rw-r--r--runtime/oat_file_test.cc59
-rw-r--r--runtime/runtime.cc2
13 files changed, 199 insertions, 30 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 6b6a9e0..2f8c323 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -166,6 +166,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \
runtime/mirror/object_test.cc \
runtime/monitor_pool_test.cc \
runtime/monitor_test.cc \
+ runtime/oat_file_test.cc \
runtime/oat_file_assistant_test.cc \
runtime/parsed_options_test.cc \
runtime/reference_table_test.cc \
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index c7f81ea..6b4eff1 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -133,7 +133,7 @@ bool ImageWriter::Write(const std::string& image_filename,
return false;
}
std::string error_msg;
- oat_file_ = OatFile::OpenReadable(oat_file.get(), oat_location, &error_msg);
+ oat_file_ = OatFile::OpenReadable(oat_file.get(), oat_location, nullptr, &error_msg);
if (oat_file_ == nullptr) {
PLOG(ERROR) << "Failed to open writable oat file " << oat_filename << " for " << oat_location
<< ": " << error_msg;
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 46aed60..c426625 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -122,7 +122,7 @@ TEST_F(OatTest, WriteRead) {
compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
}
std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), nullptr,
- nullptr, false, &error_msg));
+ nullptr, false, nullptr, &error_msg));
ASSERT_TRUE(oat_file.get() != nullptr) << error_msg;
const OatHeader& oat_header = oat_file->GetOatHeader();
ASSERT_TRUE(oat_header.IsValid());
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 9512376..2268532 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1500,7 +1500,9 @@ class ImageDumper {
std::string error_msg;
const OatFile* oat_file = class_linker->FindOpenedOatFileFromOatLocation(oat_location);
if (oat_file == nullptr) {
- oat_file = OatFile::Open(oat_location, oat_location, nullptr, nullptr, false, &error_msg);
+ oat_file = OatFile::Open(oat_location, oat_location,
+ nullptr, nullptr, false, nullptr,
+ &error_msg);
if (oat_file == nullptr) {
os << "NOT FOUND: " << error_msg << "\n";
return false;
@@ -2240,7 +2242,7 @@ static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions*
std::ostream* os) {
std::string error_msg;
OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false,
- &error_msg);
+ nullptr, &error_msg);
if (oat_file == nullptr) {
fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
return EXIT_FAILURE;
@@ -2256,7 +2258,7 @@ static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions*
static int SymbolizeOat(const char* oat_filename, std::string& output_name) {
std::string error_msg;
OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false,
- &error_msg);
+ nullptr, &error_msg);
if (oat_file == nullptr) {
fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
return EXIT_FAILURE;
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index c8ede48..da39573 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -421,15 +421,26 @@ class DexFile {
}
}
- std::string GetBaseLocation() const {
- size_t pos = location_.rfind(kMultiDexSeparator);
+ static std::string GetBaseLocation(const std::string& location) {
+ return GetBaseLocation(location.c_str());
+ }
+
+ // Returns the ':classes*.dex' part of the dex location. Returns an empty
+ // string if there is no multidex suffix for the given location.
+ // The kMultiDexSeparator is included in the returned suffix.
+ static std::string GetMultiDexSuffix(const std::string& location) {
+ size_t pos = location.rfind(kMultiDexSeparator);
if (pos == std::string::npos) {
- return location_;
+ return "";
} else {
- return location_.substr(0, pos);
+ return location.substr(pos);
}
}
+ std::string GetBaseLocation() const {
+ return GetBaseLocation(location_);
+ }
+
// For DexFiles directly from .dex files, this is the checksum from the DexFile::Header.
// For DexFiles opened from a zip files, this will be the ZipEntry CRC32 of classes.dex.
uint32_t GetLocationChecksum() const {
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 7f5a181..09ef3ee 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -377,4 +377,13 @@ TEST_F(DexFileTest, GetDexCanonicalLocation) {
ASSERT_EQ(0, unlink(dex_location_sym.c_str()));
}
+TEST(DexFileUtilsTest, GetBaseLocationAndMultiDexSuffix) {
+ EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar"));
+ EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar:classes2.dex"));
+ EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar:classes8.dex"));
+ EXPECT_EQ("", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar"));
+ EXPECT_EQ(":classes2.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar:classes2.dex"));
+ EXPECT_EQ(":classes8.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar:classes8.dex"));
+}
+
} // namespace art
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 14f770d..1fb3252 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -788,7 +788,8 @@ OatFile* ImageSpace::OpenOatFile(const char* image_path, std::string* error_msg)
OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, image_header.GetOatDataBegin(),
image_header.GetOatFileBegin(),
- !Runtime::Current()->IsAotCompiler(), error_msg);
+ !Runtime::Current()->IsAotCompiler(),
+ nullptr, error_msg);
if (oat_file == NULL) {
*error_msg = StringPrintf("Failed to open oat file '%s' referenced from image %s: %s",
oat_filename.c_str(), GetName(), error_msg->c_str());
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 356e3d2..69cb22d 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -17,10 +17,11 @@
#include "oat_file.h"
#include <dlfcn.h>
-#include <sstream>
#include <string.h>
#include <unistd.h>
+#include <sstream>
+
#include "base/bit_vector.h"
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
@@ -38,12 +39,33 @@
namespace art {
+std::string OatFile::ResolveRelativeEncodedDexLocation(
+ const char* abs_dex_location, const std::string& rel_dex_location) {
+ if (abs_dex_location != nullptr && rel_dex_location[0] != '/') {
+ // Strip :classes<N>.dex used for secondary multidex files.
+ std::string base = DexFile::GetBaseLocation(rel_dex_location);
+ std::string multidex_suffix = DexFile::GetMultiDexSuffix(rel_dex_location);
+
+ // Check if the base is a suffix of the provided abs_dex_location.
+ std::string target_suffix = "/" + base;
+ std::string abs_location(abs_dex_location);
+ if (abs_location.size() > target_suffix.size()) {
+ size_t pos = abs_location.size() - target_suffix.size();
+ if (abs_location.compare(pos, std::string::npos, target_suffix) == 0) {
+ return abs_location + multidex_suffix;
+ }
+ }
+ }
+ return rel_dex_location;
+}
+
void OatFile::CheckLocation(const std::string& location) {
CHECK(!location.empty());
}
OatFile* OatFile::OpenWithElfFile(ElfFile* elf_file,
const std::string& location,
+ const char* abs_dex_location,
std::string* error_msg) {
std::unique_ptr<OatFile> oat_file(new OatFile(location, false));
oat_file->elf_file_.reset(elf_file);
@@ -53,7 +75,7 @@ OatFile* OatFile::OpenWithElfFile(ElfFile* elf_file,
oat_file->begin_ = elf_file->Begin() + offset;
oat_file->end_ = elf_file->Begin() + size + offset;
// Ignore the optional .bss section when opening non-executable.
- return oat_file->Setup(error_msg) ? oat_file.release() : nullptr;
+ return oat_file->Setup(abs_dex_location, error_msg) ? oat_file.release() : nullptr;
}
OatFile* OatFile::Open(const std::string& filename,
@@ -61,6 +83,7 @@ OatFile* OatFile::Open(const std::string& filename,
uint8_t* requested_base,
uint8_t* oat_file_begin,
bool executable,
+ const char* abs_dex_location,
std::string* error_msg) {
CHECK(!filename.empty()) << location;
CheckLocation(location);
@@ -80,7 +103,7 @@ OatFile* OatFile::Open(const std::string& filename,
return nullptr;
}
ret.reset(OpenElfFile(file.get(), location, requested_base, oat_file_begin, false, executable,
- error_msg));
+ abs_dex_location, error_msg));
// It would be nice to unlink here. But we might have opened the file created by the
// ScopedLock, which we better not delete to avoid races. TODO: Investigate how to fix the API
@@ -88,14 +111,18 @@ OatFile* OatFile::Open(const std::string& filename,
return ret.release();
}
-OatFile* OatFile::OpenWritable(File* file, const std::string& location, std::string* error_msg) {
+OatFile* OatFile::OpenWritable(File* file, const std::string& location,
+ const char* abs_dex_location,
+ std::string* error_msg) {
CheckLocation(location);
- return OpenElfFile(file, location, nullptr, nullptr, true, false, error_msg);
+ return OpenElfFile(file, location, nullptr, nullptr, true, false, abs_dex_location, error_msg);
}
-OatFile* OatFile::OpenReadable(File* file, const std::string& location, std::string* error_msg) {
+OatFile* OatFile::OpenReadable(File* file, const std::string& location,
+ const char* abs_dex_location,
+ std::string* error_msg) {
CheckLocation(location);
- return OpenElfFile(file, location, nullptr, nullptr, false, false, error_msg);
+ return OpenElfFile(file, location, nullptr, nullptr, false, false, abs_dex_location, error_msg);
}
OatFile* OatFile::OpenElfFile(File* file,
@@ -104,10 +131,11 @@ OatFile* OatFile::OpenElfFile(File* file,
uint8_t* oat_file_begin,
bool writable,
bool executable,
+ const char* abs_dex_location,
std::string* error_msg) {
std::unique_ptr<OatFile> oat_file(new OatFile(location, executable));
bool success = oat_file->ElfFileOpen(file, requested_base, oat_file_begin, writable, executable,
- error_msg);
+ abs_dex_location, error_msg);
if (!success) {
CHECK(!error_msg->empty());
return nullptr;
@@ -131,6 +159,7 @@ OatFile::~OatFile() {
bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file_begin,
bool writable, bool executable,
+ const char* abs_dex_location,
std::string* error_msg) {
// TODO: rename requested_base to oat_data_begin
elf_file_.reset(ElfFile::Open(file, writable, /*program_header_only*/true, error_msg,
@@ -180,10 +209,10 @@ bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file
bss_end_ += sizeof(uint32_t);
}
- return Setup(error_msg);
+ return Setup(abs_dex_location, error_msg);
}
-bool OatFile::Setup(std::string* error_msg) {
+bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) {
if (!GetOatHeader().IsValid()) {
std::string cause = GetOatHeader().GetValidationErrorMessage();
*error_msg = StringPrintf("Invalid oat header for '%s': %s", GetLocation().c_str(),
@@ -230,7 +259,9 @@ bool OatFile::Setup(std::string* error_msg) {
return false;
}
- std::string dex_file_location(dex_file_location_data, dex_file_location_size);
+ std::string dex_file_location = ResolveRelativeEncodedDexLocation(
+ abs_dex_location,
+ std::string(dex_file_location_data, dex_file_location_size));
uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat);
oat += sizeof(dex_file_checksum);
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 564185c..51952f3 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -43,14 +43,18 @@ class OatFile {
// Opens an oat file contained within the given elf file. This is always opened as
// non-executable at the moment.
static OatFile* OpenWithElfFile(ElfFile* elf_file, const std::string& location,
+ const char* abs_dex_location,
std::string* error_msg);
// Open an oat file. Returns NULL on failure. Requested base can
// optionally be used to request where the file should be loaded.
+ // See the ResolveRelativeEncodedDexLocation for a description of how the
+ // abs_dex_location argument is used.
static OatFile* Open(const std::string& filename,
const std::string& location,
uint8_t* requested_base,
uint8_t* oat_file_begin,
bool executable,
+ const char* abs_dex_location,
std::string* error_msg);
// Open an oat file from an already opened File.
@@ -58,9 +62,13 @@ class OatFile {
// where relocations may be required. Currently used from
// ImageWriter which wants to open a writable version from an existing
// file descriptor for patching.
- static OatFile* OpenWritable(File* file, const std::string& location, std::string* error_msg);
+ static OatFile* OpenWritable(File* file, const std::string& location,
+ const char* abs_dex_location,
+ std::string* error_msg);
// Opens an oat file from an already opened File. Maps it PROT_READ, MAP_PRIVATE.
- static OatFile* OpenReadable(File* file, const std::string& location, std::string* error_msg);
+ static OatFile* OpenReadable(File* file, const std::string& location,
+ const char* abs_dex_location,
+ std::string* error_msg);
~OatFile();
@@ -279,6 +287,18 @@ class OatFile {
const uint8_t* BssBegin() const;
const uint8_t* BssEnd() const;
+ // Returns the absolute dex location for the encoded relative dex location.
+ //
+ // If not nullptr, abs_dex_location is used to resolve the absolute dex
+ // location of relative dex locations encoded in the oat file.
+ // For example, given absolute location "/data/app/foo/base.apk", encoded
+ // dex locations "base.apk", "base.apk:classes2.dex", etc. would be resolved
+ // to "/data/app/foo/base.apk", "/data/app/foo/base.apk:classes2.dex", etc.
+ // Relative encoded dex locations that don't match the given abs_dex_location
+ // are left unchanged.
+ static std::string ResolveRelativeEncodedDexLocation(
+ const char* abs_dex_location, const std::string& rel_dex_location);
+
private:
static void CheckLocation(const std::string& location);
@@ -288,14 +308,17 @@ class OatFile {
uint8_t* oat_file_begin, // Override base if not null
bool writable,
bool executable,
+ const char* abs_dex_location,
std::string* error_msg);
explicit OatFile(const std::string& filename, bool executable);
bool ElfFileOpen(File* file, uint8_t* requested_base,
uint8_t* oat_file_begin, // Override where the file is loaded to if not null
bool writable, bool executable,
+ const char* abs_dex_location,
std::string* error_msg);
- bool Setup(std::string* error_msg);
+
+ bool Setup(const char* abs_dex_location, std::string* error_msg);
// The oat file name.
//
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index f87fa4f..9a17b01 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -850,7 +850,7 @@ const OatFile* OatFileAssistant::GetOdexFile() {
std::string error_msg;
cached_odex_file_.reset(OatFile::Open(odex_file_name.c_str(),
odex_file_name.c_str(), nullptr, nullptr, load_executable_,
- &error_msg));
+ dex_location_, &error_msg));
if (cached_odex_file_.get() == nullptr) {
VLOG(oat) << "OatFileAssistant test for existing pre-compiled oat file "
<< odex_file_name << ": " << error_msg;
@@ -875,7 +875,8 @@ const OatFile* OatFileAssistant::GetOatFile() {
const std::string& oat_file_name = *OatFileName();
std::string error_msg;
cached_oat_file_.reset(OatFile::Open(oat_file_name.c_str(),
- oat_file_name.c_str(), nullptr, nullptr, load_executable_, &error_msg));
+ oat_file_name.c_str(), nullptr, nullptr, load_executable_,
+ dex_location_, &error_msg));
if (cached_oat_file_.get() == nullptr) {
VLOG(oat) << "OatFileAssistant test for existing oat file "
<< oat_file_name << ": " << error_msg;
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 71679ae..637789b 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -324,12 +324,43 @@ TEST_F(OatFileAssistantTest, MultiDexOatUpToDate) {
GenerateOatForTest(dex_location.c_str());
// Verify we can load both dex files.
- OatFileAssistant executable_oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
- std::unique_ptr<OatFile> oat_file = executable_oat_file_assistant.GetBestOatFile();
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+ std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
+ ASSERT_TRUE(oat_file.get() != nullptr);
+ EXPECT_TRUE(oat_file->IsExecutable());
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
+ EXPECT_EQ(2u, dex_files.size());
+}
+
+// Case: We have a MultiDEX file and up-to-date OAT file for it with relative
+// encoded dex locations.
+// Expect: The oat file status is kUpToDate.
+TEST_F(OatFileAssistantTest, RelativeEncodedDexLocation) {
+ std::string dex_location = GetScratchDir() + "/RelativeEncodedDexLocation.jar";
+ std::string oat_location = GetISADir() + "/RelativeEncodedDexLocation.oat";
+
+ // Create the dex file
+ Copy(GetMultiDexSrc1(), dex_location);
+
+ // Create the oat file with relative encoded dex location.
+ std::vector<std::string> args;
+ args.push_back("--dex-file=" + dex_location);
+ args.push_back("--dex-location=" + std::string("RelativeEncodedDexLocation.jar"));
+ args.push_back("--oat-file=" + oat_location);
+
+ std::string error_msg;
+ ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
+
+ // Verify we can load both dex files.
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ oat_location.c_str(),
+ kRuntimeISA, true);
+ std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
EXPECT_TRUE(oat_file->IsExecutable());
std::vector<std::unique_ptr<const DexFile>> dex_files;
- dex_files = executable_oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
+ dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
EXPECT_EQ(2u, dex_files.size());
}
diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc
new file mode 100644
index 0000000..f2213e9
--- /dev/null
+++ b/runtime/oat_file_test.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "oat_file.h"
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(OatFileTest, ResolveRelativeEncodedDexLocation) {
+ EXPECT_EQ(std::string("/data/app/foo/base.apk"),
+ OatFile::ResolveRelativeEncodedDexLocation(
+ nullptr, "/data/app/foo/base.apk"));
+
+ EXPECT_EQ(std::string("/system/framework/base.apk"),
+ OatFile::ResolveRelativeEncodedDexLocation(
+ "/data/app/foo/base.apk", "/system/framework/base.apk"));
+
+ EXPECT_EQ(std::string("/data/app/foo/base.apk"),
+ OatFile::ResolveRelativeEncodedDexLocation(
+ "/data/app/foo/base.apk", "base.apk"));
+
+ EXPECT_EQ(std::string("/data/app/foo/base.apk"),
+ OatFile::ResolveRelativeEncodedDexLocation(
+ "/data/app/foo/base.apk", "foo/base.apk"));
+
+ EXPECT_EQ(std::string("/data/app/foo/base.apk:classes2.dex"),
+ OatFile::ResolveRelativeEncodedDexLocation(
+ "/data/app/foo/base.apk", "base.apk:classes2.dex"));
+
+ EXPECT_EQ(std::string("/data/app/foo/base.apk:classes11.dex"),
+ OatFile::ResolveRelativeEncodedDexLocation(
+ "/data/app/foo/base.apk", "base.apk:classes11.dex"));
+
+ EXPECT_EQ(std::string("base.apk"),
+ OatFile::ResolveRelativeEncodedDexLocation(
+ "/data/app/foo/sludge.apk", "base.apk"));
+
+ EXPECT_EQ(std::string("o/base.apk"),
+ OatFile::ResolveRelativeEncodedDexLocation(
+ "/data/app/foo/base.apk", "o/base.apk"));
+}
+
+} // namespace art
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 0728646..8945fd6 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -692,7 +692,7 @@ static bool OpenDexFilesFromImage(const std::string& image_location,
return false;
}
std::unique_ptr<OatFile> oat_file(OatFile::OpenWithElfFile(elf_file.release(), oat_location,
- &error_msg));
+ nullptr, &error_msg));
if (oat_file.get() == nullptr) {
LOG(INFO) << "Unable to use '" << oat_filename << "' because " << error_msg;
return false;