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 "dex_file.h" 18 19 #include <memory> 20 21 #include "base/stl_util.h" 22 #include "base/unix_file/fd_file.h" 23 #include "common_runtime_test.h" 24 #include "os.h" 25 #include "scoped_thread_state_change.h" 26 #include "thread-inl.h" 27 28 namespace art { 29 30 class DexFileTest : public CommonRuntimeTest {}; 31 32 TEST_F(DexFileTest, Open) { 33 ScopedObjectAccess soa(Thread::Current()); 34 const DexFile* dex(OpenTestDexFile("Nested")); 35 ASSERT_TRUE(dex != NULL); 36 } 37 38 static const byte kBase64Map[256] = { 39 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 40 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 41 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 42 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 43 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 44 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 45 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, // NOLINT 46 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // NOLINT 47 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 48 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // NOLINT 49 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, // NOLINT 50 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 51 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 52 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 53 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 54 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 55 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 56 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 57 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 58 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 59 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 60 255, 255, 255, 255 61 }; 62 63 static inline byte* DecodeBase64(const char* src, size_t* dst_size) { 64 std::vector<byte> tmp; 65 uint32_t t = 0, y = 0; 66 int g = 3; 67 for (size_t i = 0; src[i] != '\0'; ++i) { 68 byte c = kBase64Map[src[i] & 0xFF]; 69 if (c == 255) continue; 70 // the final = symbols are read and used to trim the remaining bytes 71 if (c == 254) { 72 c = 0; 73 // prevent g < 0 which would potentially allow an overflow later 74 if (--g < 0) { 75 *dst_size = 0; 76 return nullptr; 77 } 78 } else if (g != 3) { 79 // we only allow = to be at the end 80 *dst_size = 0; 81 return nullptr; 82 } 83 t = (t << 6) | c; 84 if (++y == 4) { 85 tmp.push_back((t >> 16) & 255); 86 if (g > 1) { 87 tmp.push_back((t >> 8) & 255); 88 } 89 if (g > 2) { 90 tmp.push_back(t & 255); 91 } 92 y = t = 0; 93 } 94 } 95 if (y != 0) { 96 *dst_size = 0; 97 return nullptr; 98 } 99 std::unique_ptr<byte[]> dst(new byte[tmp.size()]); 100 if (dst_size != nullptr) { 101 *dst_size = tmp.size(); 102 } else { 103 *dst_size = 0; 104 } 105 std::copy(tmp.begin(), tmp.end(), dst.get()); 106 return dst.release(); 107 } 108 109 // Although this is the same content logically as the Nested test dex, 110 // the DexFileHeader test is sensitive to subtle changes in the 111 // contents due to the checksum etc, so we embed the exact input here. 112 // 113 // class Nested { 114 // class Inner { 115 // } 116 // } 117 static const char kRawDex[] = 118 "ZGV4CjAzNQAQedgAe7gM1B/WHsWJ6L7lGAISGC7yjD2IAwAAcAAAAHhWNBIAAAAAAAAAAMQCAAAP" 119 "AAAAcAAAAAcAAACsAAAAAgAAAMgAAAABAAAA4AAAAAMAAADoAAAAAgAAAAABAABIAgAAQAEAAK4B" 120 "AAC2AQAAvQEAAM0BAADXAQAA+wEAABsCAAA+AgAAUgIAAF8CAABiAgAAZgIAAHMCAAB5AgAAgQIA" 121 "AAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAkAAAAJAAAABgAAAAAAAAAKAAAABgAAAKgBAAAAAAEA" 122 "DQAAAAAAAQAAAAAAAQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAIAAAAiAEAAKsCAAAA" 123 "AAAAAQAAAAAAAAAFAAAAAAAAAAgAAACYAQAAuAIAAAAAAAACAAAAlAIAAJoCAAABAAAAowIAAAIA" 124 "AgABAAAAiAIAAAYAAABbAQAAcBACAAAADgABAAEAAQAAAI4CAAAEAAAAcBACAAAADgBAAQAAAAAA" 125 "AAAAAAAAAAAATAEAAAAAAAAAAAAAAAAAAAEAAAABAAY8aW5pdD4ABUlubmVyAA5MTmVzdGVkJElu" 126 "bmVyOwAITE5lc3RlZDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2" 127 "aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAhTGRhbHZpay9hbm5vdGF0aW9uL01lbWJlckNsYXNz" 128 "ZXM7ABJMamF2YS9sYW5nL09iamVjdDsAC05lc3RlZC5qYXZhAAFWAAJWTAALYWNjZXNzRmxhZ3MA" 129 "BG5hbWUABnRoaXMkMAAFdmFsdWUAAgEABw4AAQAHDjwAAgIBDhgBAgMCCwQADBcBAgQBDhwBGAAA" 130 "AQEAAJAgAICABNQCAAABAAGAgATwAgAAEAAAAAAAAAABAAAAAAAAAAEAAAAPAAAAcAAAAAIAAAAH" 131 "AAAArAAAAAMAAAACAAAAyAAAAAQAAAABAAAA4AAAAAUAAAADAAAA6AAAAAYAAAACAAAAAAEAAAMQ" 132 "AAACAAAAQAEAAAEgAAACAAAAVAEAAAYgAAACAAAAiAEAAAEQAAABAAAAqAEAAAIgAAAPAAAArgEA" 133 "AAMgAAACAAAAiAIAAAQgAAADAAAAlAIAAAAgAAACAAAAqwIAAAAQAAABAAAAxAIAAA=="; 134 135 static const DexFile* OpenDexFileBase64(const char* base64, 136 const char* location) { 137 // decode base64 138 CHECK(base64 != NULL); 139 size_t length; 140 std::unique_ptr<byte[]> dex_bytes(DecodeBase64(base64, &length)); 141 CHECK(dex_bytes.get() != NULL); 142 143 // write to provided file 144 std::unique_ptr<File> file(OS::CreateEmptyFile(location)); 145 CHECK(file.get() != NULL); 146 if (!file->WriteFully(dex_bytes.get(), length)) { 147 PLOG(FATAL) << "Failed to write base64 as dex file"; 148 } 149 if (file->FlushCloseOrErase() != 0) { 150 PLOG(FATAL) << "Could not flush and close test file."; 151 } 152 file.reset(); 153 154 // read dex file 155 ScopedObjectAccess soa(Thread::Current()); 156 std::string error_msg; 157 std::vector<const DexFile*> tmp; 158 bool success = DexFile::Open(location, location, &error_msg, &tmp); 159 CHECK(success) << error_msg; 160 EXPECT_EQ(1U, tmp.size()); 161 const DexFile* dex_file = tmp[0]; 162 EXPECT_EQ(PROT_READ, dex_file->GetPermissions()); 163 EXPECT_TRUE(dex_file->IsReadOnly()); 164 return dex_file; 165 } 166 167 TEST_F(DexFileTest, Header) { 168 ScratchFile tmp; 169 std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename().c_str())); 170 ASSERT_TRUE(raw.get() != NULL); 171 172 const DexFile::Header& header = raw->GetHeader(); 173 // TODO: header.magic_ 174 EXPECT_EQ(0x00d87910U, header.checksum_); 175 // TODO: header.signature_ 176 EXPECT_EQ(904U, header.file_size_); 177 EXPECT_EQ(112U, header.header_size_); 178 EXPECT_EQ(0U, header.link_size_); 179 EXPECT_EQ(0U, header.link_off_); 180 EXPECT_EQ(15U, header.string_ids_size_); 181 EXPECT_EQ(112U, header.string_ids_off_); 182 EXPECT_EQ(7U, header.type_ids_size_); 183 EXPECT_EQ(172U, header.type_ids_off_); 184 EXPECT_EQ(2U, header.proto_ids_size_); 185 EXPECT_EQ(200U, header.proto_ids_off_); 186 EXPECT_EQ(1U, header.field_ids_size_); 187 EXPECT_EQ(224U, header.field_ids_off_); 188 EXPECT_EQ(3U, header.method_ids_size_); 189 EXPECT_EQ(232U, header.method_ids_off_); 190 EXPECT_EQ(2U, header.class_defs_size_); 191 EXPECT_EQ(256U, header.class_defs_off_); 192 EXPECT_EQ(584U, header.data_size_); 193 EXPECT_EQ(320U, header.data_off_); 194 195 EXPECT_EQ(header.checksum_, raw->GetLocationChecksum()); 196 } 197 198 TEST_F(DexFileTest, GetLocationChecksum) { 199 ScopedObjectAccess soa(Thread::Current()); 200 const DexFile* raw(OpenTestDexFile("Main")); 201 EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum()); 202 } 203 204 TEST_F(DexFileTest, GetChecksum) { 205 uint32_t checksum; 206 ScopedObjectAccess soa(Thread::Current()); 207 std::string error_msg; 208 EXPECT_TRUE(DexFile::GetChecksum(GetLibCoreDexFileName().c_str(), &checksum, &error_msg)) 209 << error_msg; 210 EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksum); 211 } 212 213 TEST_F(DexFileTest, ClassDefs) { 214 ScopedObjectAccess soa(Thread::Current()); 215 const DexFile* raw(OpenTestDexFile("Nested")); 216 ASSERT_TRUE(raw != NULL); 217 EXPECT_EQ(2U, raw->NumClassDefs()); 218 219 const DexFile::ClassDef& c0 = raw->GetClassDef(0); 220 EXPECT_STREQ("LNested$Inner;", raw->GetClassDescriptor(c0)); 221 222 const DexFile::ClassDef& c1 = raw->GetClassDef(1); 223 EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c1)); 224 } 225 226 TEST_F(DexFileTest, GetMethodSignature) { 227 ScopedObjectAccess soa(Thread::Current()); 228 const DexFile* raw(OpenTestDexFile("GetMethodSignature")); 229 ASSERT_TRUE(raw != NULL); 230 EXPECT_EQ(1U, raw->NumClassDefs()); 231 232 const DexFile::ClassDef& class_def = raw->GetClassDef(0); 233 ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def)); 234 235 const byte* class_data = raw->GetClassData(class_def); 236 ASSERT_TRUE(class_data != NULL); 237 ClassDataItemIterator it(*raw, class_data); 238 239 EXPECT_EQ(1u, it.NumDirectMethods()); 240 241 // Check the signature for the static initializer. 242 { 243 ASSERT_EQ(1U, it.NumDirectMethods()); 244 const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex()); 245 const char* name = raw->StringDataByIdx(method_id.name_idx_); 246 ASSERT_STREQ("<init>", name); 247 std::string signature(raw->GetMethodSignature(method_id).ToString()); 248 ASSERT_EQ("()V", signature); 249 } 250 251 // Check both virtual methods. 252 ASSERT_EQ(2U, it.NumVirtualMethods()); 253 { 254 it.Next(); 255 const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex()); 256 257 const char* name = raw->StringDataByIdx(method_id.name_idx_); 258 ASSERT_STREQ("m1", name); 259 260 std::string signature(raw->GetMethodSignature(method_id).ToString()); 261 ASSERT_EQ("(IDJLjava/lang/Object;)Ljava/lang/Float;", signature); 262 } 263 264 { 265 it.Next(); 266 const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex()); 267 268 const char* name = raw->StringDataByIdx(method_id.name_idx_); 269 ASSERT_STREQ("m2", name); 270 271 std::string signature(raw->GetMethodSignature(method_id).ToString()); 272 ASSERT_EQ("(ZSC)LGetMethodSignature;", signature); 273 } 274 } 275 276 TEST_F(DexFileTest, FindStringId) { 277 ScopedObjectAccess soa(Thread::Current()); 278 const DexFile* raw(OpenTestDexFile("GetMethodSignature")); 279 ASSERT_TRUE(raw != NULL); 280 EXPECT_EQ(1U, raw->NumClassDefs()); 281 282 const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;", 283 "D", "I", "J", NULL }; 284 for (size_t i = 0; strings[i] != NULL; i++) { 285 const char* str = strings[i]; 286 const DexFile::StringId* str_id = raw->FindStringId(str); 287 const char* dex_str = raw->GetStringData(*str_id); 288 EXPECT_STREQ(dex_str, str); 289 } 290 } 291 292 TEST_F(DexFileTest, FindTypeId) { 293 for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) { 294 const char* type_str = java_lang_dex_file_->StringByTypeIdx(i); 295 const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str); 296 ASSERT_TRUE(type_str_id != NULL); 297 uint32_t type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id); 298 const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx); 299 ASSERT_TRUE(type_id != NULL); 300 EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id), i); 301 } 302 } 303 304 TEST_F(DexFileTest, FindProtoId) { 305 for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) { 306 const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i); 307 const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find); 308 std::vector<uint16_t> to_find_types; 309 if (to_find_tl != NULL) { 310 for (size_t j = 0; j < to_find_tl->Size(); j++) { 311 to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_); 312 } 313 } 314 const DexFile::ProtoId* found = 315 java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types); 316 ASSERT_TRUE(found != NULL); 317 EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i); 318 } 319 } 320 321 TEST_F(DexFileTest, FindMethodId) { 322 for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) { 323 const DexFile::MethodId& to_find = java_lang_dex_file_->GetMethodId(i); 324 const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_); 325 const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_); 326 const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_); 327 const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature); 328 ASSERT_TRUE(found != NULL) << "Didn't find method " << i << ": " 329 << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "." 330 << java_lang_dex_file_->GetStringData(name) 331 << java_lang_dex_file_->GetMethodSignature(to_find); 332 EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i); 333 } 334 } 335 336 TEST_F(DexFileTest, FindFieldId) { 337 for (size_t i = 0; i < java_lang_dex_file_->NumFieldIds(); i++) { 338 const DexFile::FieldId& to_find = java_lang_dex_file_->GetFieldId(i); 339 const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_); 340 const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_); 341 const DexFile::TypeId& type = java_lang_dex_file_->GetTypeId(to_find.type_idx_); 342 const DexFile::FieldId* found = java_lang_dex_file_->FindFieldId(klass, name, type); 343 ASSERT_TRUE(found != NULL) << "Didn't find field " << i << ": " 344 << java_lang_dex_file_->StringByTypeIdx(to_find.type_idx_) << " " 345 << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "." 346 << java_lang_dex_file_->GetStringData(name); 347 EXPECT_EQ(java_lang_dex_file_->GetIndexForFieldId(*found), i); 348 } 349 } 350 351 TEST_F(DexFileTest, GetMultiDexClassesDexName) { 352 std::string dex_location_str = "/system/app/framework.jar"; 353 const char* dex_location = dex_location_str.c_str(); 354 ASSERT_EQ("/system/app/framework.jar", DexFile::GetMultiDexClassesDexName(0, dex_location)); 355 ASSERT_EQ("/system/app/framework.jar:classes2.dex", DexFile::GetMultiDexClassesDexName(1, dex_location)); 356 ASSERT_EQ("/system/app/framework.jar:classes101.dex", DexFile::GetMultiDexClassesDexName(100, dex_location)); 357 } 358 359 TEST_F(DexFileTest, GetDexCanonicalLocation) { 360 ScratchFile file; 361 UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr)); 362 std::string dex_location(dex_location_real.get()); 363 364 ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location.c_str())); 365 std::string multidex_location = DexFile::GetMultiDexClassesDexName(1, dex_location.c_str()); 366 ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location.c_str())); 367 368 std::string dex_location_sym = dex_location + "symlink"; 369 ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str())); 370 371 ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location_sym.c_str())); 372 373 std::string multidex_location_sym = DexFile::GetMultiDexClassesDexName(1, dex_location_sym.c_str()); 374 ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location_sym.c_str())); 375 376 ASSERT_EQ(0, unlink(dex_location_sym.c_str())); 377 } 378 379 } // namespace art 380