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
TEST_F(DexFileTest,Open)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
DecodeBase64(const char * src,size_t * dst_size)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
OpenDexFileBase64(const char * base64,const char * location)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
TEST_F(DexFileTest,Header)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
TEST_F(DexFileTest,GetLocationChecksum)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
TEST_F(DexFileTest,GetChecksum)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
TEST_F(DexFileTest,ClassDefs)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
TEST_F(DexFileTest,GetMethodSignature)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
TEST_F(DexFileTest,FindStringId)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
TEST_F(DexFileTest,FindTypeId)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
TEST_F(DexFileTest,FindProtoId)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
TEST_F(DexFileTest,FindMethodId)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
TEST_F(DexFileTest,FindFieldId)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
TEST_F(DexFileTest,GetMultiDexClassesDexName)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
TEST_F(DexFileTest,GetDexCanonicalLocation)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