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 <sys/mman.h> 18 19 #include <fstream> 20 #include <memory> 21 22 #include "art_dex_file_loader.h" 23 #include "base/file_utils.h" 24 #include "base/os.h" 25 #include "base/stl_util.h" 26 #include "base/unix_file/fd_file.h" 27 #include "common_runtime_test.h" 28 #include "dex/base64_test_util.h" 29 #include "dex/code_item_accessors-inl.h" 30 #include "dex/descriptors_names.h" 31 #include "dex/dex_file.h" 32 #include "dex/dex_file-inl.h" 33 #include "dex/dex_file_loader.h" 34 #include "mem_map.h" 35 #include "scoped_thread_state_change-inl.h" 36 #include "thread-current-inl.h" 37 38 namespace art { 39 40 static void Copy(const std::string& src, const std::string& dst) { 41 std::ifstream src_stream(src, std::ios::binary); 42 std::ofstream dst_stream(dst, std::ios::binary); 43 dst_stream << src_stream.rdbuf(); 44 } 45 46 class ArtDexFileLoaderTest : public CommonRuntimeTest {}; 47 48 // TODO: Port OpenTestDexFile(s) need to be ported to use non-ART utilities, and 49 // the tests that depend upon them should be moved to dex_file_loader_test.cc 50 51 TEST_F(ArtDexFileLoaderTest, Open) { 52 ScopedObjectAccess soa(Thread::Current()); 53 std::unique_ptr<const DexFile> dex(OpenTestDexFile("Nested")); 54 ASSERT_TRUE(dex.get() != nullptr); 55 } 56 57 TEST_F(ArtDexFileLoaderTest, GetLocationChecksum) { 58 ScopedObjectAccess soa(Thread::Current()); 59 std::unique_ptr<const DexFile> raw(OpenTestDexFile("Main")); 60 EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum()); 61 } 62 63 TEST_F(ArtDexFileLoaderTest, GetChecksum) { 64 std::vector<uint32_t> checksums; 65 ScopedObjectAccess soa(Thread::Current()); 66 std::string error_msg; 67 const ArtDexFileLoader dex_file_loader; 68 EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(), 69 &checksums, 70 &error_msg)) 71 << error_msg; 72 ASSERT_EQ(1U, checksums.size()); 73 EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksums[0]); 74 } 75 76 TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksums) { 77 std::string error_msg; 78 std::vector<uint32_t> checksums; 79 std::string multidex_file = GetTestDexFileName("MultiDex"); 80 const ArtDexFileLoader dex_file_loader; 81 EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(multidex_file.c_str(), 82 &checksums, 83 &error_msg)) << error_msg; 84 85 std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex"); 86 ASSERT_EQ(2U, dexes.size()); 87 ASSERT_EQ(2U, checksums.size()); 88 89 EXPECT_EQ(dexes[0]->GetLocation(), DexFileLoader::GetMultiDexLocation(0, multidex_file.c_str())); 90 EXPECT_EQ(dexes[0]->GetLocationChecksum(), checksums[0]); 91 92 EXPECT_EQ(dexes[1]->GetLocation(), DexFileLoader::GetMultiDexLocation(1, multidex_file.c_str())); 93 EXPECT_EQ(dexes[1]->GetLocationChecksum(), checksums[1]); 94 } 95 96 TEST_F(ArtDexFileLoaderTest, ClassDefs) { 97 ScopedObjectAccess soa(Thread::Current()); 98 std::unique_ptr<const DexFile> raw(OpenTestDexFile("Nested")); 99 ASSERT_TRUE(raw.get() != nullptr); 100 EXPECT_EQ(3U, raw->NumClassDefs()); 101 102 const DexFile::ClassDef& c0 = raw->GetClassDef(0); 103 EXPECT_STREQ("LNested$1;", raw->GetClassDescriptor(c0)); 104 105 const DexFile::ClassDef& c1 = raw->GetClassDef(1); 106 EXPECT_STREQ("LNested$Inner;", raw->GetClassDescriptor(c1)); 107 108 const DexFile::ClassDef& c2 = raw->GetClassDef(2); 109 EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c2)); 110 } 111 112 TEST_F(ArtDexFileLoaderTest, GetMethodSignature) { 113 ScopedObjectAccess soa(Thread::Current()); 114 std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature")); 115 ASSERT_TRUE(raw.get() != nullptr); 116 EXPECT_EQ(1U, raw->NumClassDefs()); 117 118 const DexFile::ClassDef& class_def = raw->GetClassDef(0); 119 ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def)); 120 121 const uint8_t* class_data = raw->GetClassData(class_def); 122 ASSERT_TRUE(class_data != nullptr); 123 ClassDataItemIterator it(*raw, class_data); 124 125 EXPECT_EQ(1u, it.NumDirectMethods()); 126 127 // Check the signature for the static initializer. 128 { 129 ASSERT_EQ(1U, it.NumDirectMethods()); 130 const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex()); 131 const char* name = raw->StringDataByIdx(method_id.name_idx_); 132 ASSERT_STREQ("<init>", name); 133 std::string signature(raw->GetMethodSignature(method_id).ToString()); 134 ASSERT_EQ("()V", signature); 135 } 136 137 // Check all virtual methods. 138 struct Result { 139 const char* name; 140 const char* signature; 141 const char* pretty_method; 142 }; 143 static const Result results[] = { 144 { 145 "m1", 146 "(IDJLjava/lang/Object;)Ljava/lang/Float;", 147 "java.lang.Float GetMethodSignature.m1(int, double, long, java.lang.Object)" 148 }, 149 { 150 "m2", 151 "(ZSC)LGetMethodSignature;", 152 "GetMethodSignature GetMethodSignature.m2(boolean, short, char)" 153 }, 154 { 155 "m3", 156 "()V", 157 "void GetMethodSignature.m3()" 158 }, 159 { 160 "m4", 161 "(I)V", 162 "void GetMethodSignature.m4(int)" 163 }, 164 { 165 "m5", 166 "(II)V", 167 "void GetMethodSignature.m5(int, int)" 168 }, 169 { 170 "m6", 171 "(II[[I)V", 172 "void GetMethodSignature.m6(int, int, int[][])" 173 }, 174 { 175 "m7", 176 "(II[[ILjava/lang/Object;)V", 177 "void GetMethodSignature.m7(int, int, int[][], java.lang.Object)" 178 }, 179 { 180 "m8", 181 "(II[[ILjava/lang/Object;[[Ljava/lang/Object;)V", 182 "void GetMethodSignature.m8(int, int, int[][], java.lang.Object, java.lang.Object[][])" 183 }, 184 { 185 "m9", 186 "()I", 187 "int GetMethodSignature.m9()" 188 }, 189 { 190 "mA", 191 "()[[I", 192 "int[][] GetMethodSignature.mA()" 193 }, 194 { 195 "mB", 196 "()[[Ljava/lang/Object;", 197 "java.lang.Object[][] GetMethodSignature.mB()" 198 }, 199 }; 200 ASSERT_EQ(arraysize(results), it.NumVirtualMethods()); 201 for (const Result& r : results) { 202 it.Next(); 203 const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex()); 204 205 const char* name = raw->StringDataByIdx(method_id.name_idx_); 206 ASSERT_STREQ(r.name, name); 207 208 std::string signature(raw->GetMethodSignature(method_id).ToString()); 209 ASSERT_EQ(r.signature, signature); 210 211 std::string plain_method = std::string("GetMethodSignature.") + r.name; 212 ASSERT_EQ(plain_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ false)); 213 ASSERT_EQ(r.pretty_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ true)); 214 } 215 } 216 217 TEST_F(ArtDexFileLoaderTest, FindStringId) { 218 ScopedObjectAccess soa(Thread::Current()); 219 std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature")); 220 ASSERT_TRUE(raw.get() != nullptr); 221 EXPECT_EQ(1U, raw->NumClassDefs()); 222 223 const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;", 224 "D", "I", "J", nullptr }; 225 for (size_t i = 0; strings[i] != nullptr; i++) { 226 const char* str = strings[i]; 227 const DexFile::StringId* str_id = raw->FindStringId(str); 228 const char* dex_str = raw->GetStringData(*str_id); 229 EXPECT_STREQ(dex_str, str); 230 } 231 } 232 233 TEST_F(ArtDexFileLoaderTest, FindTypeId) { 234 for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) { 235 const char* type_str = java_lang_dex_file_->StringByTypeIdx(dex::TypeIndex(i)); 236 const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str); 237 ASSERT_TRUE(type_str_id != nullptr); 238 dex::StringIndex type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id); 239 const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx); 240 ASSERT_EQ(type_id, java_lang_dex_file_->FindTypeId(type_str)); 241 ASSERT_TRUE(type_id != nullptr); 242 EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id).index_, i); 243 } 244 } 245 246 TEST_F(ArtDexFileLoaderTest, FindProtoId) { 247 for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) { 248 const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i); 249 const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find); 250 std::vector<dex::TypeIndex> to_find_types; 251 if (to_find_tl != nullptr) { 252 for (size_t j = 0; j < to_find_tl->Size(); j++) { 253 to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_); 254 } 255 } 256 const DexFile::ProtoId* found = 257 java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types); 258 ASSERT_TRUE(found != nullptr); 259 EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i); 260 } 261 } 262 263 TEST_F(ArtDexFileLoaderTest, FindMethodId) { 264 for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) { 265 const DexFile::MethodId& to_find = java_lang_dex_file_->GetMethodId(i); 266 const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_); 267 const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_); 268 const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_); 269 const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature); 270 ASSERT_TRUE(found != nullptr) << "Didn't find method " << i << ": " 271 << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "." 272 << java_lang_dex_file_->GetStringData(name) 273 << java_lang_dex_file_->GetMethodSignature(to_find); 274 EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i); 275 } 276 } 277 278 TEST_F(ArtDexFileLoaderTest, FindFieldId) { 279 for (size_t i = 0; i < java_lang_dex_file_->NumFieldIds(); i++) { 280 const DexFile::FieldId& to_find = java_lang_dex_file_->GetFieldId(i); 281 const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_); 282 const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_); 283 const DexFile::TypeId& type = java_lang_dex_file_->GetTypeId(to_find.type_idx_); 284 const DexFile::FieldId* found = java_lang_dex_file_->FindFieldId(klass, name, type); 285 ASSERT_TRUE(found != nullptr) << "Didn't find field " << i << ": " 286 << java_lang_dex_file_->StringByTypeIdx(to_find.type_idx_) << " " 287 << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "." 288 << java_lang_dex_file_->GetStringData(name); 289 EXPECT_EQ(java_lang_dex_file_->GetIndexForFieldId(*found), i); 290 } 291 } 292 293 TEST_F(ArtDexFileLoaderTest, GetDexCanonicalLocation) { 294 ScratchFile file; 295 UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr)); 296 std::string dex_location(dex_location_real.get()); 297 298 ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location.c_str())); 299 std::string multidex_location = DexFileLoader::GetMultiDexLocation(1, dex_location.c_str()); 300 ASSERT_EQ(multidex_location, DexFileLoader::GetDexCanonicalLocation(multidex_location.c_str())); 301 302 std::string dex_location_sym = dex_location + "symlink"; 303 ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str())); 304 305 ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location_sym.c_str())); 306 307 std::string multidex_location_sym = DexFileLoader::GetMultiDexLocation( 308 1, dex_location_sym.c_str()); 309 ASSERT_EQ(multidex_location, 310 DexFileLoader::GetDexCanonicalLocation(multidex_location_sym.c_str())); 311 312 ASSERT_EQ(0, unlink(dex_location_sym.c_str())); 313 } 314 315 TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile_DataDir) { 316 // Load file from a non-system directory and check that it is not flagged as framework. 317 std::string data_location_path = android_data_ + "/foo.jar"; 318 ASSERT_FALSE(LocationIsOnSystemFramework(data_location_path.c_str())); 319 320 Copy(GetTestDexFileName("Main"), data_location_path); 321 322 ArtDexFileLoader loader; 323 std::vector<std::unique_ptr<const DexFile>> dex_files; 324 std::string error_msg; 325 bool success = loader.Open(data_location_path.c_str(), 326 data_location_path, 327 /* verify */ false, 328 /* verify_checksum */ false, 329 &error_msg, 330 &dex_files); 331 ASSERT_TRUE(success) << error_msg; 332 333 ASSERT_GE(dex_files.size(), 1u); 334 for (std::unique_ptr<const DexFile>& dex_file : dex_files) { 335 ASSERT_FALSE(dex_file->IsPlatformDexFile()); 336 } 337 338 dex_files.clear(); 339 340 ASSERT_EQ(0, remove(data_location_path.c_str())); 341 } 342 343 TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile_SystemDir) { 344 // Load file from a system, non-framework directory and check that it is not flagged as framework. 345 std::string system_location_path = GetAndroidRoot() + "/foo.jar"; 346 ASSERT_FALSE(LocationIsOnSystemFramework(system_location_path.c_str())); 347 348 Copy(GetTestDexFileName("Main"), system_location_path); 349 350 ArtDexFileLoader loader; 351 std::vector<std::unique_ptr<const DexFile>> dex_files; 352 std::string error_msg; 353 bool success = loader.Open(system_location_path.c_str(), 354 system_location_path, 355 /* verify */ false, 356 /* verify_checksum */ false, 357 &error_msg, 358 &dex_files); 359 ASSERT_TRUE(success) << error_msg; 360 361 ASSERT_GE(dex_files.size(), 1u); 362 for (std::unique_ptr<const DexFile>& dex_file : dex_files) { 363 ASSERT_FALSE(dex_file->IsPlatformDexFile()); 364 } 365 366 dex_files.clear(); 367 368 ASSERT_EQ(0, remove(system_location_path.c_str())); 369 } 370 371 TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile_SystemFrameworkDir) { 372 // Load file from a system/framework directory and check that it is flagged as a framework dex. 373 std::string system_framework_location_path = GetAndroidRoot() + "/framework/foo.jar"; 374 ASSERT_TRUE(LocationIsOnSystemFramework(system_framework_location_path.c_str())); 375 376 Copy(GetTestDexFileName("Main"), system_framework_location_path); 377 378 ArtDexFileLoader loader; 379 std::vector<std::unique_ptr<const DexFile>> dex_files; 380 std::string error_msg; 381 bool success = loader.Open(system_framework_location_path.c_str(), 382 system_framework_location_path, 383 /* verify */ false, 384 /* verify_checksum */ false, 385 &error_msg, 386 &dex_files); 387 ASSERT_TRUE(success) << error_msg; 388 389 ASSERT_GE(dex_files.size(), 1u); 390 for (std::unique_ptr<const DexFile>& dex_file : dex_files) { 391 ASSERT_TRUE(dex_file->IsPlatformDexFile()); 392 } 393 394 dex_files.clear(); 395 396 ASSERT_EQ(0, remove(system_framework_location_path.c_str())); 397 } 398 399 TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile_DataDir_MultiDex) { 400 // Load multidex file from a non-system directory and check that it is not flagged as framework. 401 std::string data_multi_location_path = android_data_ + "/multifoo.jar"; 402 ASSERT_FALSE(LocationIsOnSystemFramework(data_multi_location_path.c_str())); 403 404 Copy(GetTestDexFileName("MultiDex"), data_multi_location_path); 405 406 ArtDexFileLoader loader; 407 std::vector<std::unique_ptr<const DexFile>> dex_files; 408 std::string error_msg; 409 bool success = loader.Open(data_multi_location_path.c_str(), 410 data_multi_location_path, 411 /* verify */ false, 412 /* verify_checksum */ false, 413 &error_msg, 414 &dex_files); 415 ASSERT_TRUE(success) << error_msg; 416 417 ASSERT_GT(dex_files.size(), 1u); 418 for (std::unique_ptr<const DexFile>& dex_file : dex_files) { 419 ASSERT_FALSE(dex_file->IsPlatformDexFile()); 420 } 421 422 dex_files.clear(); 423 424 ASSERT_EQ(0, remove(data_multi_location_path.c_str())); 425 } 426 427 TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile_SystemDir_MultiDex) { 428 // Load multidex file from a system, non-framework directory and check that it is not flagged 429 // as framework. 430 std::string system_multi_location_path = GetAndroidRoot() + "/multifoo.jar"; 431 ASSERT_FALSE(LocationIsOnSystemFramework(system_multi_location_path.c_str())); 432 433 Copy(GetTestDexFileName("MultiDex"), system_multi_location_path); 434 435 ArtDexFileLoader loader; 436 std::vector<std::unique_ptr<const DexFile>> dex_files; 437 std::string error_msg; 438 bool success = loader.Open(system_multi_location_path.c_str(), 439 system_multi_location_path, 440 /* verify */ false, 441 /* verify_checksum */ false, 442 &error_msg, 443 &dex_files); 444 ASSERT_TRUE(success) << error_msg; 445 446 ASSERT_GT(dex_files.size(), 1u); 447 for (std::unique_ptr<const DexFile>& dex_file : dex_files) { 448 ASSERT_FALSE(dex_file->IsPlatformDexFile()); 449 } 450 451 dex_files.clear(); 452 453 ASSERT_EQ(0, remove(system_multi_location_path.c_str())); 454 } 455 456 TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile_SystemFrameworkDir_MultiDex) { 457 // Load multidex file from a system/framework directory and check that it is flagged as a 458 // framework dex. 459 std::string system_framework_multi_location_path = GetAndroidRoot() + "/framework/multifoo.jar"; 460 ASSERT_TRUE(LocationIsOnSystemFramework(system_framework_multi_location_path.c_str())); 461 462 Copy(GetTestDexFileName("MultiDex"), system_framework_multi_location_path); 463 464 ArtDexFileLoader loader; 465 std::vector<std::unique_ptr<const DexFile>> dex_files; 466 std::string error_msg; 467 bool success = loader.Open(system_framework_multi_location_path.c_str(), 468 system_framework_multi_location_path, 469 /* verify */ false, 470 /* verify_checksum */ false, 471 &error_msg, 472 &dex_files); 473 ASSERT_TRUE(success) << error_msg; 474 475 ASSERT_GT(dex_files.size(), 1u); 476 for (std::unique_ptr<const DexFile>& dex_file : dex_files) { 477 ASSERT_TRUE(dex_file->IsPlatformDexFile()); 478 } 479 480 dex_files.clear(); 481 482 ASSERT_EQ(0, remove(system_framework_multi_location_path.c_str())); 483 } 484 485 } // namespace art 486