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 file.reset();
150
151 // read dex file
152 ScopedObjectAccess soa(Thread::Current());
153 std::string error_msg;
154 std::vector<const DexFile*> tmp;
155 bool success = DexFile::Open(location, location, &error_msg, &tmp);
156 CHECK(success) << error_msg;
157 EXPECT_EQ(1U, tmp.size());
158 const DexFile* dex_file = tmp[0];
159 EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
160 EXPECT_TRUE(dex_file->IsReadOnly());
161 return dex_file;
162 }
163
TEST_F(DexFileTest,Header)164 TEST_F(DexFileTest, Header) {
165 ScratchFile tmp;
166 std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename().c_str()));
167 ASSERT_TRUE(raw.get() != NULL);
168
169 const DexFile::Header& header = raw->GetHeader();
170 // TODO: header.magic_
171 EXPECT_EQ(0x00d87910U, header.checksum_);
172 // TODO: header.signature_
173 EXPECT_EQ(904U, header.file_size_);
174 EXPECT_EQ(112U, header.header_size_);
175 EXPECT_EQ(0U, header.link_size_);
176 EXPECT_EQ(0U, header.link_off_);
177 EXPECT_EQ(15U, header.string_ids_size_);
178 EXPECT_EQ(112U, header.string_ids_off_);
179 EXPECT_EQ(7U, header.type_ids_size_);
180 EXPECT_EQ(172U, header.type_ids_off_);
181 EXPECT_EQ(2U, header.proto_ids_size_);
182 EXPECT_EQ(200U, header.proto_ids_off_);
183 EXPECT_EQ(1U, header.field_ids_size_);
184 EXPECT_EQ(224U, header.field_ids_off_);
185 EXPECT_EQ(3U, header.method_ids_size_);
186 EXPECT_EQ(232U, header.method_ids_off_);
187 EXPECT_EQ(2U, header.class_defs_size_);
188 EXPECT_EQ(256U, header.class_defs_off_);
189 EXPECT_EQ(584U, header.data_size_);
190 EXPECT_EQ(320U, header.data_off_);
191
192 EXPECT_EQ(header.checksum_, raw->GetLocationChecksum());
193 }
194
TEST_F(DexFileTest,GetLocationChecksum)195 TEST_F(DexFileTest, GetLocationChecksum) {
196 ScopedObjectAccess soa(Thread::Current());
197 const DexFile* raw(OpenTestDexFile("Main"));
198 EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum());
199 }
200
TEST_F(DexFileTest,GetChecksum)201 TEST_F(DexFileTest, GetChecksum) {
202 uint32_t checksum;
203 ScopedObjectAccess soa(Thread::Current());
204 std::string error_msg;
205 EXPECT_TRUE(DexFile::GetChecksum(GetLibCoreDexFileName().c_str(), &checksum, &error_msg))
206 << error_msg;
207 EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksum);
208 }
209
TEST_F(DexFileTest,ClassDefs)210 TEST_F(DexFileTest, ClassDefs) {
211 ScopedObjectAccess soa(Thread::Current());
212 const DexFile* raw(OpenTestDexFile("Nested"));
213 ASSERT_TRUE(raw != NULL);
214 EXPECT_EQ(2U, raw->NumClassDefs());
215
216 const DexFile::ClassDef& c0 = raw->GetClassDef(0);
217 EXPECT_STREQ("LNested$Inner;", raw->GetClassDescriptor(c0));
218
219 const DexFile::ClassDef& c1 = raw->GetClassDef(1);
220 EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c1));
221 }
222
TEST_F(DexFileTest,GetMethodSignature)223 TEST_F(DexFileTest, GetMethodSignature) {
224 ScopedObjectAccess soa(Thread::Current());
225 const DexFile* raw(OpenTestDexFile("GetMethodSignature"));
226 ASSERT_TRUE(raw != NULL);
227 EXPECT_EQ(1U, raw->NumClassDefs());
228
229 const DexFile::ClassDef& class_def = raw->GetClassDef(0);
230 ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def));
231
232 const byte* class_data = raw->GetClassData(class_def);
233 ASSERT_TRUE(class_data != NULL);
234 ClassDataItemIterator it(*raw, class_data);
235
236 EXPECT_EQ(1u, it.NumDirectMethods());
237
238 // Check the signature for the static initializer.
239 {
240 ASSERT_EQ(1U, it.NumDirectMethods());
241 const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
242 const char* name = raw->StringDataByIdx(method_id.name_idx_);
243 ASSERT_STREQ("<init>", name);
244 std::string signature(raw->GetMethodSignature(method_id).ToString());
245 ASSERT_EQ("()V", signature);
246 }
247
248 // Check both virtual methods.
249 ASSERT_EQ(2U, it.NumVirtualMethods());
250 {
251 it.Next();
252 const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
253
254 const char* name = raw->StringDataByIdx(method_id.name_idx_);
255 ASSERT_STREQ("m1", name);
256
257 std::string signature(raw->GetMethodSignature(method_id).ToString());
258 ASSERT_EQ("(IDJLjava/lang/Object;)Ljava/lang/Float;", signature);
259 }
260
261 {
262 it.Next();
263 const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
264
265 const char* name = raw->StringDataByIdx(method_id.name_idx_);
266 ASSERT_STREQ("m2", name);
267
268 std::string signature(raw->GetMethodSignature(method_id).ToString());
269 ASSERT_EQ("(ZSC)LGetMethodSignature;", signature);
270 }
271 }
272
TEST_F(DexFileTest,FindStringId)273 TEST_F(DexFileTest, FindStringId) {
274 ScopedObjectAccess soa(Thread::Current());
275 const DexFile* raw(OpenTestDexFile("GetMethodSignature"));
276 ASSERT_TRUE(raw != NULL);
277 EXPECT_EQ(1U, raw->NumClassDefs());
278
279 const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;",
280 "D", "I", "J", NULL };
281 for (size_t i = 0; strings[i] != NULL; i++) {
282 const char* str = strings[i];
283 const DexFile::StringId* str_id = raw->FindStringId(str);
284 const char* dex_str = raw->GetStringData(*str_id);
285 EXPECT_STREQ(dex_str, str);
286 }
287 }
288
TEST_F(DexFileTest,FindTypeId)289 TEST_F(DexFileTest, FindTypeId) {
290 for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) {
291 const char* type_str = java_lang_dex_file_->StringByTypeIdx(i);
292 const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str);
293 ASSERT_TRUE(type_str_id != NULL);
294 uint32_t type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id);
295 const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx);
296 ASSERT_TRUE(type_id != NULL);
297 EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id), i);
298 }
299 }
300
TEST_F(DexFileTest,FindProtoId)301 TEST_F(DexFileTest, FindProtoId) {
302 for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) {
303 const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i);
304 const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find);
305 std::vector<uint16_t> to_find_types;
306 if (to_find_tl != NULL) {
307 for (size_t j = 0; j < to_find_tl->Size(); j++) {
308 to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_);
309 }
310 }
311 const DexFile::ProtoId* found =
312 java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types);
313 ASSERT_TRUE(found != NULL);
314 EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i);
315 }
316 }
317
TEST_F(DexFileTest,FindMethodId)318 TEST_F(DexFileTest, FindMethodId) {
319 for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) {
320 const DexFile::MethodId& to_find = java_lang_dex_file_->GetMethodId(i);
321 const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
322 const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
323 const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_);
324 const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature);
325 ASSERT_TRUE(found != NULL) << "Didn't find method " << i << ": "
326 << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
327 << java_lang_dex_file_->GetStringData(name)
328 << java_lang_dex_file_->GetMethodSignature(to_find);
329 EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i);
330 }
331 }
332
TEST_F(DexFileTest,FindFieldId)333 TEST_F(DexFileTest, FindFieldId) {
334 for (size_t i = 0; i < java_lang_dex_file_->NumFieldIds(); i++) {
335 const DexFile::FieldId& to_find = java_lang_dex_file_->GetFieldId(i);
336 const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
337 const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
338 const DexFile::TypeId& type = java_lang_dex_file_->GetTypeId(to_find.type_idx_);
339 const DexFile::FieldId* found = java_lang_dex_file_->FindFieldId(klass, name, type);
340 ASSERT_TRUE(found != NULL) << "Didn't find field " << i << ": "
341 << java_lang_dex_file_->StringByTypeIdx(to_find.type_idx_) << " "
342 << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
343 << java_lang_dex_file_->GetStringData(name);
344 EXPECT_EQ(java_lang_dex_file_->GetIndexForFieldId(*found), i);
345 }
346 }
347
TEST_F(DexFileTest,GetMultiDexClassesDexName)348 TEST_F(DexFileTest, GetMultiDexClassesDexName) {
349 std::string dex_location_str = "/system/app/framework.jar";
350 const char* dex_location = dex_location_str.c_str();
351 ASSERT_EQ("/system/app/framework.jar", DexFile::GetMultiDexClassesDexName(0, dex_location));
352 ASSERT_EQ("/system/app/framework.jar:classes2.dex", DexFile::GetMultiDexClassesDexName(1, dex_location));
353 ASSERT_EQ("/system/app/framework.jar:classes101.dex", DexFile::GetMultiDexClassesDexName(100, dex_location));
354 }
355
TEST_F(DexFileTest,GetDexCanonicalLocation)356 TEST_F(DexFileTest, GetDexCanonicalLocation) {
357 ScratchFile file;
358 UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr));
359 std::string dex_location(dex_location_real.get());
360
361 ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location.c_str()));
362 std::string multidex_location = DexFile::GetMultiDexClassesDexName(1, dex_location.c_str());
363 ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location.c_str()));
364
365 std::string dex_location_sym = dex_location + "symlink";
366 ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str()));
367
368 ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location_sym.c_str()));
369
370 std::string multidex_location_sym = DexFile::GetMultiDexClassesDexName(1, dex_location_sym.c_str());
371 ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location_sym.c_str()));
372
373 ASSERT_EQ(0, unlink(dex_location_sym.c_str()));
374 }
375
376 } // namespace art
377