1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "art_dex_file_loader.h" 18 19 #include <sys/mman.h> 20 21 #include <memory> 22 #include <optional> 23 #include <vector> 24 25 #include "base/common_art_test.h" 26 #include "base/mem_map.h" 27 #include "base/os.h" 28 #include "base/stl_util.h" 29 #include "base/unix_file/fd_file.h" 30 #include "dex/base64_test_util.h" 31 #include "dex/class_accessor-inl.h" 32 #include "dex/code_item_accessors-inl.h" 33 #include "dex/descriptors_names.h" 34 #include "dex/dex_file-inl.h" 35 #include "dex/dex_file.h" 36 #include "dex/dex_file_loader.h" 37 38 namespace art { 39 40 class ArtDexFileLoaderTest : public CommonArtTest { SetUp()41 void SetUp() override { 42 CommonArtTest::SetUp(); 43 // Open a jar file from the boot classpath for use in basic tests of dex accessors. 44 std::vector<std::string> lib_core_dex_file_names = GetLibCoreDexFileNames(); 45 CHECK_NE(lib_core_dex_file_names.size(), 0U); 46 dex_files_ = OpenDexFiles(lib_core_dex_file_names[0].c_str()); 47 CHECK_NE(dex_files_.size(), 0U); 48 // Save a dex file for use by tests. 49 java_lang_dex_file_ = dex_files_[0].get(); 50 } 51 52 protected: 53 std::vector<std::unique_ptr<const DexFile>> dex_files_; 54 const DexFile* java_lang_dex_file_; 55 }; 56 TEST_F(ArtDexFileLoaderTest,Open)57 TEST_F(ArtDexFileLoaderTest, Open) { 58 std::unique_ptr<const DexFile> dex(OpenTestDexFile("Nested")); 59 ASSERT_TRUE(dex.get() != nullptr); 60 } 61 TEST_F(ArtDexFileLoaderTest,OpenZipMultiDex)62 TEST_F(ArtDexFileLoaderTest, OpenZipMultiDex) { 63 std::string zip_file = GetTestDexFileName("MultiDex"); 64 File file(zip_file, O_RDONLY, /*check_usage=*/false); 65 ASSERT_GE(file.Fd(), 0); 66 std::vector<std::unique_ptr<const DexFile>> dex_files; 67 std::string error_msg; 68 ArtDexFileLoader dex_file_loader(&file, zip_file); 69 ASSERT_TRUE(dex_file_loader.Open(/*verify=*/false, 70 /*verify_checksum=*/true, 71 /*allow_no_dex_files=*/true, 72 &error_msg, 73 &dex_files)) 74 << error_msg; 75 EXPECT_GT(dex_files.size(), 1); 76 } 77 TEST_F(ArtDexFileLoaderTest,OpenZipEmpty)78 TEST_F(ArtDexFileLoaderTest, OpenZipEmpty) { 79 std::string zip_file = GetTestDexFileName("MainEmptyUncompressed"); 80 File file(zip_file, O_RDONLY, /*check_usage=*/false); 81 ASSERT_GE(file.Fd(), 0); 82 std::vector<std::unique_ptr<const DexFile>> dex_files; 83 std::string error_msg; 84 ArtDexFileLoader dex_file_loader(&file, zip_file); 85 ASSERT_TRUE(dex_file_loader.Open(/*verify=*/false, 86 /*verify_checksum=*/true, 87 /*allow_no_dex_files=*/true, 88 &error_msg, 89 &dex_files)) 90 << error_msg; 91 EXPECT_EQ(dex_files.size(), 0); 92 } 93 TEST_F(ArtDexFileLoaderTest,GetLocationChecksum)94 TEST_F(ArtDexFileLoaderTest, GetLocationChecksum) { 95 std::unique_ptr<const DexFile> raw(OpenTestDexFile("Main")); 96 EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum()); 97 } 98 TEST_F(ArtDexFileLoaderTest,GetChecksum)99 TEST_F(ArtDexFileLoaderTest, GetChecksum) { 100 std::optional<uint32_t> checksum; 101 std::string error_msg; 102 ArtDexFileLoader dex_loader(GetLibCoreDexFileNames()[0]); 103 ASSERT_TRUE(dex_loader.GetMultiDexChecksum(&checksum, &error_msg)) << error_msg; 104 ASSERT_TRUE(checksum.has_value()); 105 106 std::vector<const DexFile*> dex_files{java_lang_dex_file_}; 107 uint32_t expected_checksum = DexFileLoader::GetMultiDexChecksum(dex_files); 108 EXPECT_EQ(expected_checksum, checksum.value()); 109 } 110 TEST_F(ArtDexFileLoaderTest,GetMultiDexChecksum)111 TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksum) { 112 std::string error_msg; 113 std::optional<uint32_t> checksum; 114 std::string multidex_file = GetTestDexFileName("MultiDex"); 115 ArtDexFileLoader dex_loader(multidex_file); 116 EXPECT_TRUE(dex_loader.GetMultiDexChecksum(&checksum, &error_msg)) << error_msg; 117 118 std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex"); 119 ASSERT_EQ(2U, dexes.size()); 120 ASSERT_TRUE(checksum.has_value()); 121 122 uint32_t expected_checksum = DexFileLoader::GetMultiDexChecksum(dexes); 123 EXPECT_EQ(dexes[0]->GetLocation(), DexFileLoader::GetMultiDexLocation(0, multidex_file.c_str())); 124 EXPECT_EQ(dexes[1]->GetLocation(), DexFileLoader::GetMultiDexLocation(1, multidex_file.c_str())); 125 EXPECT_EQ(expected_checksum, checksum.value()); 126 } 127 TEST_F(ArtDexFileLoaderTest,GetMultiDexChecksumsEmptyZip)128 TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksumsEmptyZip) { 129 std::string error_msg; 130 std::optional<uint32_t> checksum; 131 std::string multidex_file = GetTestDexFileName("MainEmptyUncompressed"); 132 ArtDexFileLoader dex_loader(multidex_file); 133 EXPECT_TRUE(dex_loader.GetMultiDexChecksum(&checksum, &error_msg)) << error_msg; 134 EXPECT_FALSE(checksum.has_value()); 135 } 136 TEST_F(ArtDexFileLoaderTest,GetMultiDexChecksumsDexFile)137 TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksumsDexFile) { 138 std::string error_msg; 139 std::optional<uint32_t> checksum; 140 std::string multidex_file = GetTestDexFileName("VerifierDeps"); // This is a .dex file. 141 DexFileLoader loader(multidex_file); 142 EXPECT_TRUE(loader.GetMultiDexChecksum(&checksum, &error_msg)) << error_msg; 143 EXPECT_TRUE(checksum.has_value()); 144 } 145 TEST_F(ArtDexFileLoaderTest,ClassDefs)146 TEST_F(ArtDexFileLoaderTest, ClassDefs) { 147 std::unique_ptr<const DexFile> raw(OpenTestDexFile("Nested")); 148 ASSERT_TRUE(raw.get() != nullptr); 149 EXPECT_EQ(3U, raw->NumClassDefs()); 150 151 const dex::ClassDef& c0 = raw->GetClassDef(0); 152 EXPECT_STREQ("LNested$1;", raw->GetClassDescriptor(c0)); 153 154 const dex::ClassDef& c1 = raw->GetClassDef(1); 155 EXPECT_STREQ("LNested$Inner;", raw->GetClassDescriptor(c1)); 156 157 const dex::ClassDef& c2 = raw->GetClassDef(2); 158 EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c2)); 159 } 160 TEST_F(ArtDexFileLoaderTest,GetMethodSignature)161 TEST_F(ArtDexFileLoaderTest, GetMethodSignature) { 162 std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature")); 163 ASSERT_TRUE(raw.get() != nullptr); 164 EXPECT_EQ(1U, raw->NumClassDefs()); 165 166 const dex::ClassDef& class_def = raw->GetClassDef(0); 167 ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def)); 168 169 ClassAccessor accessor(*raw, class_def); 170 ASSERT_TRUE(accessor.HasClassData()); 171 auto methods = accessor.GetMethods(); 172 auto cur_method = methods.begin(); 173 174 // Check the signature for the static initializer. 175 { 176 ASSERT_EQ(1U, accessor.NumDirectMethods()); 177 const dex::MethodId& method_id = raw->GetMethodId(cur_method->GetIndex()); 178 const char* name = raw->GetStringData(method_id.name_idx_); 179 ASSERT_STREQ("<init>", name); 180 std::string signature(raw->GetMethodSignature(method_id).ToString()); 181 ASSERT_EQ("()V", signature); 182 } 183 184 // Check all virtual methods. 185 struct Result { 186 const char* name; 187 const char* signature; 188 const char* pretty_method; 189 }; 190 static const Result results[] = { 191 { 192 "m1", 193 "(IDJLjava/lang/Object;)Ljava/lang/Float;", 194 "java.lang.Float GetMethodSignature.m1(int, double, long, java.lang.Object)" 195 }, 196 { 197 "m2", 198 "(ZSC)LGetMethodSignature;", 199 "GetMethodSignature GetMethodSignature.m2(boolean, short, char)" 200 }, 201 { 202 "m3", 203 "()V", 204 "void GetMethodSignature.m3()" 205 }, 206 { 207 "m4", 208 "(I)V", 209 "void GetMethodSignature.m4(int)" 210 }, 211 { 212 "m5", 213 "(II)V", 214 "void GetMethodSignature.m5(int, int)" 215 }, 216 { 217 "m6", 218 "(II[[I)V", 219 "void GetMethodSignature.m6(int, int, int[][])" 220 }, 221 { 222 "m7", 223 "(II[[ILjava/lang/Object;)V", 224 "void GetMethodSignature.m7(int, int, int[][], java.lang.Object)" 225 }, 226 { 227 "m8", 228 "(II[[ILjava/lang/Object;[[Ljava/lang/Object;)V", 229 "void GetMethodSignature.m8(int, int, int[][], java.lang.Object, java.lang.Object[][])" 230 }, 231 { 232 "m9", 233 "()I", 234 "int GetMethodSignature.m9()" 235 }, 236 { 237 "mA", 238 "()[[I", 239 "int[][] GetMethodSignature.mA()" 240 }, 241 { 242 "mB", 243 "()[[Ljava/lang/Object;", 244 "java.lang.Object[][] GetMethodSignature.mB()" 245 }, 246 }; 247 ASSERT_EQ(arraysize(results), accessor.NumVirtualMethods()); 248 for (const Result& r : results) { 249 ++cur_method; 250 ASSERT_TRUE(cur_method != methods.end()); 251 const dex::MethodId& method_id = raw->GetMethodId(cur_method->GetIndex()); 252 253 const char* name = raw->GetStringData(method_id.name_idx_); 254 ASSERT_STREQ(r.name, name); 255 256 std::string signature(raw->GetMethodSignature(method_id).ToString()); 257 ASSERT_EQ(r.signature, signature); 258 259 std::string plain_method = std::string("GetMethodSignature.") + r.name; 260 ASSERT_EQ(plain_method, 261 raw->PrettyMethod(cur_method->GetIndex(), /* with_signature= */ false)); 262 ASSERT_EQ(r.pretty_method, 263 raw->PrettyMethod(cur_method->GetIndex(), /* with_signature= */ true)); 264 } 265 } 266 TEST_F(ArtDexFileLoaderTest,FindStringId)267 TEST_F(ArtDexFileLoaderTest, FindStringId) { 268 std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature")); 269 ASSERT_TRUE(raw.get() != nullptr); 270 EXPECT_EQ(1U, raw->NumClassDefs()); 271 272 const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;", 273 "D", "I", "J", nullptr }; 274 for (size_t i = 0; strings[i] != nullptr; i++) { 275 const char* str = strings[i]; 276 const dex::StringId* str_id = raw->FindStringId(str); 277 const char* dex_str = raw->GetStringData(*str_id); 278 EXPECT_STREQ(dex_str, str); 279 } 280 } 281 TEST_F(ArtDexFileLoaderTest,FindTypeId)282 TEST_F(ArtDexFileLoaderTest, FindTypeId) { 283 for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) { 284 const char* type_str = java_lang_dex_file_->GetTypeDescriptor(dex::TypeIndex(i)); 285 const dex::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str); 286 ASSERT_TRUE(type_str_id != nullptr); 287 dex::StringIndex type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id); 288 const dex::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx); 289 ASSERT_EQ(type_id, java_lang_dex_file_->FindTypeId(type_str)); 290 ASSERT_TRUE(type_id != nullptr); 291 EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id).index_, i); 292 } 293 } 294 TEST_F(ArtDexFileLoaderTest,FindProtoId)295 TEST_F(ArtDexFileLoaderTest, FindProtoId) { 296 for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) { 297 const dex::ProtoId& to_find = java_lang_dex_file_->GetProtoId(dex::ProtoIndex(i)); 298 const dex::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find); 299 std::vector<dex::TypeIndex> to_find_types; 300 if (to_find_tl != nullptr) { 301 for (size_t j = 0; j < to_find_tl->Size(); j++) { 302 to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_); 303 } 304 } 305 const dex::ProtoId* found = 306 java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types); 307 ASSERT_TRUE(found != nullptr); 308 EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), dex::ProtoIndex(i)); 309 } 310 } 311 TEST_F(ArtDexFileLoaderTest,FindMethodId)312 TEST_F(ArtDexFileLoaderTest, FindMethodId) { 313 for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) { 314 const dex::MethodId& to_find = java_lang_dex_file_->GetMethodId(i); 315 const dex::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_); 316 const dex::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_); 317 const dex::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_); 318 const dex::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature); 319 ASSERT_TRUE(found != nullptr) << "Didn't find method " << i << ": " 320 << java_lang_dex_file_->GetTypeDescriptor(to_find.class_idx_) << "." 321 << java_lang_dex_file_->GetStringData(name) 322 << java_lang_dex_file_->GetMethodSignature(to_find); 323 EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i); 324 } 325 } 326 TEST_F(ArtDexFileLoaderTest,FindFieldId)327 TEST_F(ArtDexFileLoaderTest, FindFieldId) { 328 for (size_t i = 0; i < java_lang_dex_file_->NumFieldIds(); i++) { 329 const dex::FieldId& to_find = java_lang_dex_file_->GetFieldId(i); 330 const dex::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_); 331 const dex::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_); 332 const dex::TypeId& type = java_lang_dex_file_->GetTypeId(to_find.type_idx_); 333 const dex::FieldId* found = java_lang_dex_file_->FindFieldId(klass, name, type); 334 ASSERT_TRUE(found != nullptr) << "Didn't find field " << i << ": " 335 << java_lang_dex_file_->GetTypeDescriptor(to_find.type_idx_) << " " 336 << java_lang_dex_file_->GetTypeDescriptor(to_find.class_idx_) << "." 337 << java_lang_dex_file_->GetStringData(name); 338 EXPECT_EQ(java_lang_dex_file_->GetIndexForFieldId(*found), i); 339 } 340 } 341 TEST_F(ArtDexFileLoaderTest,GetDexCanonicalLocation)342 TEST_F(ArtDexFileLoaderTest, GetDexCanonicalLocation) { 343 ScratchFile file; 344 UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr)); 345 std::string dex_location(dex_location_real.get()); 346 347 ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location.c_str())); 348 std::string multidex_location = DexFileLoader::GetMultiDexLocation(1, dex_location.c_str()); 349 ASSERT_EQ(multidex_location, DexFileLoader::GetDexCanonicalLocation(multidex_location.c_str())); 350 351 std::string dex_location_sym = dex_location + "symlink"; 352 ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str())); 353 354 ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location_sym.c_str())); 355 356 std::string multidex_location_sym = DexFileLoader::GetMultiDexLocation( 357 1, dex_location_sym.c_str()); 358 ASSERT_EQ(multidex_location, 359 DexFileLoader::GetDexCanonicalLocation(multidex_location_sym.c_str())); 360 361 ASSERT_EQ(0, unlink(dex_location_sym.c_str())); 362 } 363 364 } // namespace art 365