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