diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/oat.h | 1 | ||||
-rw-r--r-- | runtime/oat_file.cc | 87 | ||||
-rw-r--r-- | runtime/oat_file.h | 12 | ||||
-rw-r--r-- | runtime/oat_file_test.cc | 58 |
4 files changed, 157 insertions, 1 deletions
diff --git a/runtime/oat.h b/runtime/oat.h index de95fef..a31e09a 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -38,6 +38,7 @@ class PACKED(4) OatHeader { static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; static constexpr const char* kDex2OatHostKey = "dex2oat-host"; static constexpr const char* kPicKey = "pic"; + static constexpr const char* kClassPathKey = "classpath"; static OatHeader* Create(InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features, diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 81703b1..d3c4b49 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -20,6 +20,7 @@ #include <string.h> #include <unistd.h> +#include <cstdlib> #include <sstream> #include "base/bit_vector.h" @@ -592,4 +593,90 @@ bool OatFile::IsPic() const { // TODO: Check against oat_patches. b/18144996 } +static constexpr char kDexClassPathEncodingSeparator = '*'; + +std::string OatFile::EncodeDexFileDependencies(const std::vector<const DexFile*>& dex_files) { + std::ostringstream out; + + for (const DexFile* dex_file : dex_files) { + out << dex_file->GetLocation().c_str(); + out << kDexClassPathEncodingSeparator; + out << dex_file->GetLocationChecksum(); + out << kDexClassPathEncodingSeparator; + } + + return out.str(); +} + +bool OatFile::CheckStaticDexFileDependencies(const char* dex_dependencies, std::string* msg) { + if (dex_dependencies == nullptr || dex_dependencies[0] == 0) { + // No dependencies. + return true; + } + + // Assumption: this is not performance-critical. So it's OK to do this with a std::string and + // Split() instead of manual parsing of the combined char*. + std::vector<std::string> split; + Split(dex_dependencies, kDexClassPathEncodingSeparator, &split); + if (split.size() % 2 != 0) { + // Expected pairs of location and checksum. + *msg = StringPrintf("Odd number of elements in dependency list %s", dex_dependencies); + return false; + } + + for (auto it = split.begin(), end = split.end(); it != end; it += 2) { + std::string& location = *it; + std::string& checksum = *(it + 1); + int64_t converted = strtoll(checksum.c_str(), nullptr, 10); + if (converted == 0) { + // Conversion error. + *msg = StringPrintf("Conversion error for %s", checksum.c_str()); + return false; + } + + uint32_t dex_checksum; + std::string error_msg; + if (DexFile::GetChecksum(DexFile::GetDexCanonicalLocation(location.c_str()).c_str(), + &dex_checksum, + &error_msg)) { + if (converted != dex_checksum) { + *msg = StringPrintf("Checksums don't match for %s: %" PRId64 " vs %u", + location.c_str(), converted, dex_checksum); + return false; + } + } else { + // Problem retrieving checksum. + // TODO: odex files? + *msg = StringPrintf("Could not retrieve checksum for %s: %s", location.c_str(), + error_msg.c_str()); + return false; + } + } + + return true; +} + +bool OatFile::GetDexLocationsFromDependencies(const char* dex_dependencies, + std::vector<std::string>* locations) { + DCHECK(locations != nullptr); + if (dex_dependencies == nullptr || dex_dependencies[0] == 0) { + return true; + } + + // Assumption: this is not performance-critical. So it's OK to do this with a std::string and + // Split() instead of manual parsing of the combined char*. + std::vector<std::string> split; + Split(dex_dependencies, kDexClassPathEncodingSeparator, &split); + if (split.size() % 2 != 0) { + // Expected pairs of location and checksum. + return false; + } + + for (auto it = split.begin(), end = split.end(); it != end; it += 2) { + locations->push_back(*it); + } + + return true; +} + } // namespace art diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 73a8c8e..a5d5ae8 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -248,6 +248,18 @@ class OatFile FINAL { static std::string ResolveRelativeEncodedDexLocation( const char* abs_dex_location, const std::string& rel_dex_location); + // Create a dependency list (dex locations and checksums) for the given dex files. + static std::string EncodeDexFileDependencies(const std::vector<const DexFile*>& dex_files); + + // Check the given dependency list against their dex files - thus the name "Static," this does + // not check the class-loader environment, only whether there have been file updates. + static bool CheckStaticDexFileDependencies(const char* dex_dependencies, std::string* msg); + + // Get the dex locations of a dependency list. Note: this is *not* cleaned for synthetic + // locations of multidex files. + static bool GetDexLocationsFromDependencies(const char* dex_dependencies, + std::vector<std::string>* locations); + private: static void CheckLocation(const std::string& location); diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc index f2213e9..a88553c 100644 --- a/runtime/oat_file_test.cc +++ b/runtime/oat_file_test.cc @@ -20,9 +20,15 @@ #include <gtest/gtest.h> +#include "common_runtime_test.h" +#include "scoped_thread_state_change.h" + namespace art { -TEST(OatFileTest, ResolveRelativeEncodedDexLocation) { +class OatFileTest : public CommonRuntimeTest { +}; + +TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation) { EXPECT_EQ(std::string("/data/app/foo/base.apk"), OatFile::ResolveRelativeEncodedDexLocation( nullptr, "/data/app/foo/base.apk")); @@ -56,4 +62,54 @@ TEST(OatFileTest, ResolveRelativeEncodedDexLocation) { "/data/app/foo/base.apk", "o/base.apk")); } +static std::vector<const DexFile*> ToConstDexFiles( + const std::vector<std::unique_ptr<const DexFile>>& in) { + std::vector<const DexFile*> ret; + for (auto& d : in) { + ret.push_back(d.get()); + } + return ret; +} + +TEST_F(OatFileTest, DexFileDependencies) { + std::string error_msg; + + // No dependencies. + EXPECT_TRUE(OatFile::CheckStaticDexFileDependencies(nullptr, &error_msg)) << error_msg; + EXPECT_TRUE(OatFile::CheckStaticDexFileDependencies("", &error_msg)) << error_msg; + + // Ill-formed dependencies. + EXPECT_FALSE(OatFile::CheckStaticDexFileDependencies("abc", &error_msg)); + EXPECT_FALSE(OatFile::CheckStaticDexFileDependencies("abc*123*def", &error_msg)); + EXPECT_FALSE(OatFile::CheckStaticDexFileDependencies("abc*def*", &error_msg)); + + // Unsatisfiable dependency. + EXPECT_FALSE(OatFile::CheckStaticDexFileDependencies("abc*123*", &error_msg)); + + // Load some dex files to be able to do a real test. + ScopedObjectAccess soa(Thread::Current()); + + std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Main"); + std::vector<const DexFile*> dex_files_const1 = ToConstDexFiles(dex_files1); + std::string encoding1 = OatFile::EncodeDexFileDependencies(dex_files_const1); + EXPECT_TRUE(OatFile::CheckStaticDexFileDependencies(encoding1.c_str(), &error_msg)) + << error_msg << " " << encoding1; + std::vector<std::string> split1; + EXPECT_TRUE(OatFile::GetDexLocationsFromDependencies(encoding1.c_str(), &split1)); + ASSERT_EQ(split1.size(), 1U); + EXPECT_EQ(split1[0], dex_files_const1[0]->GetLocation()); + + std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex"); + EXPECT_GT(dex_files2.size(), 1U); + std::vector<const DexFile*> dex_files_const2 = ToConstDexFiles(dex_files2); + std::string encoding2 = OatFile::EncodeDexFileDependencies(dex_files_const2); + EXPECT_TRUE(OatFile::CheckStaticDexFileDependencies(encoding2.c_str(), &error_msg)) + << error_msg << " " << encoding2; + std::vector<std::string> split2; + EXPECT_TRUE(OatFile::GetDexLocationsFromDependencies(encoding2.c_str(), &split2)); + ASSERT_EQ(split2.size(), 2U); + EXPECT_EQ(split2[0], dex_files_const2[0]->GetLocation()); + EXPECT_EQ(split2[1], dex_files_const2[1]->GetLocation()); +} + } // namespace art |