diff options
author | Richard Uhler <ruhler@google.com> | 2015-03-25 17:10:11 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2015-03-25 17:10:12 +0000 |
commit | 3679a47027b40290018d0ccc50b996a15645dfef (patch) | |
tree | 92c6fcbb8fe5c647eb06bb63277c90f36c319101 /runtime | |
parent | 139cec015abd195727d5410dc313b483babeda10 (diff) | |
parent | e5fed03772144595c0904faf3d6974cc55214c8c (diff) | |
download | art-3679a47027b40290018d0ccc50b996a15645dfef.zip art-3679a47027b40290018d0ccc50b996a15645dfef.tar.gz art-3679a47027b40290018d0ccc50b996a15645dfef.tar.bz2 |
Merge "Support relative encoded dex locations in oat files."
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/dex_file.h | 19 | ||||
-rw-r--r-- | runtime/dex_file_test.cc | 9 | ||||
-rw-r--r-- | runtime/gc/space/image_space.cc | 3 | ||||
-rw-r--r-- | runtime/oat_file.cc | 53 | ||||
-rw-r--r-- | runtime/oat_file.h | 29 | ||||
-rw-r--r-- | runtime/oat_file_assistant.cc | 5 | ||||
-rw-r--r-- | runtime/oat_file_assistant_test.cc | 37 | ||||
-rw-r--r-- | runtime/oat_file_test.cc | 59 | ||||
-rw-r--r-- | runtime/runtime.cc | 2 |
9 files changed, 191 insertions, 25 deletions
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 be8652c..41dc2d7 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -326,12 +326,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 2dacfe2..9ca00b1 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -688,7 +688,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; |