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 "art_dex_file_loader.h"
18 
19 #include <sys/mman.h>
20 
21 #include <memory>
22 
23 #include "base/common_art_test.h"
24 #include "base/mem_map.h"
25 #include "base/os.h"
26 #include "base/stl_util.h"
27 #include "base/unix_file/fd_file.h"
28 #include "dex/base64_test_util.h"
29 #include "dex/class_accessor-inl.h"
30 #include "dex/code_item_accessors-inl.h"
31 #include "dex/descriptors_names.h"
32 #include "dex/dex_file.h"
33 #include "dex/dex_file-inl.h"
34 #include "dex/dex_file_loader.h"
35 
36 namespace art {
37 
38 class ArtDexFileLoaderTest : public CommonArtTest {
SetUp()39   void SetUp() override {
40     CommonArtTest::SetUp();
41     // Open a jar file from the boot classpath for use in basic tests of dex accessors.
42     std::vector<std::string> lib_core_dex_file_names = GetLibCoreDexFileNames();
43     CHECK_NE(lib_core_dex_file_names.size(), 0U);
44     dex_files_ = OpenDexFiles(lib_core_dex_file_names[0].c_str());
45     CHECK_NE(dex_files_.size(), 0U);
46     // Save a dex file for use by tests.
47     java_lang_dex_file_ = dex_files_[0].get();
48   }
49 
50  protected:
51   std::vector<std::unique_ptr<const DexFile>> dex_files_;
52   const DexFile* java_lang_dex_file_;
53 };
54 
TEST_F(ArtDexFileLoaderTest,Open)55 TEST_F(ArtDexFileLoaderTest, Open) {
56   std::unique_ptr<const DexFile> dex(OpenTestDexFile("Nested"));
57   ASSERT_TRUE(dex.get() != nullptr);
58 }
59 
TEST_F(ArtDexFileLoaderTest,GetLocationChecksum)60 TEST_F(ArtDexFileLoaderTest, GetLocationChecksum) {
61   std::unique_ptr<const DexFile> raw(OpenTestDexFile("Main"));
62   EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum());
63 }
64 
TEST_F(ArtDexFileLoaderTest,GetChecksum)65 TEST_F(ArtDexFileLoaderTest, GetChecksum) {
66   std::vector<uint32_t> checksums;
67   std::string error_msg;
68   const ArtDexFileLoader dex_file_loader;
69   EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(),
70                                                     &checksums,
71                                                     &error_msg))
72       << error_msg;
73   ASSERT_EQ(1U, checksums.size());
74   EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksums[0]);
75 }
76 
TEST_F(ArtDexFileLoaderTest,GetMultiDexChecksums)77 TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksums) {
78   std::string error_msg;
79   std::vector<uint32_t> checksums;
80   std::string multidex_file = GetTestDexFileName("MultiDex");
81   const ArtDexFileLoader dex_file_loader;
82   EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(multidex_file.c_str(),
83                                                     &checksums,
84                                                     &error_msg)) << error_msg;
85 
86   std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex");
87   ASSERT_EQ(2U, dexes.size());
88   ASSERT_EQ(2U, checksums.size());
89 
90   EXPECT_EQ(dexes[0]->GetLocation(), DexFileLoader::GetMultiDexLocation(0, multidex_file.c_str()));
91   EXPECT_EQ(dexes[0]->GetLocationChecksum(), checksums[0]);
92 
93   EXPECT_EQ(dexes[1]->GetLocation(), DexFileLoader::GetMultiDexLocation(1, multidex_file.c_str()));
94   EXPECT_EQ(dexes[1]->GetLocationChecksum(), checksums[1]);
95 }
96 
TEST_F(ArtDexFileLoaderTest,ClassDefs)97 TEST_F(ArtDexFileLoaderTest, ClassDefs) {
98   std::unique_ptr<const DexFile> raw(OpenTestDexFile("Nested"));
99   ASSERT_TRUE(raw.get() != nullptr);
100   EXPECT_EQ(3U, raw->NumClassDefs());
101 
102   const dex::ClassDef& c0 = raw->GetClassDef(0);
103   EXPECT_STREQ("LNested$1;", raw->GetClassDescriptor(c0));
104 
105   const dex::ClassDef& c1 = raw->GetClassDef(1);
106   EXPECT_STREQ("LNested$Inner;", raw->GetClassDescriptor(c1));
107 
108   const dex::ClassDef& c2 = raw->GetClassDef(2);
109   EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c2));
110 }
111 
TEST_F(ArtDexFileLoaderTest,GetMethodSignature)112 TEST_F(ArtDexFileLoaderTest, GetMethodSignature) {
113   std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature"));
114   ASSERT_TRUE(raw.get() != nullptr);
115   EXPECT_EQ(1U, raw->NumClassDefs());
116 
117   const dex::ClassDef& class_def = raw->GetClassDef(0);
118   ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def));
119 
120   ClassAccessor accessor(*raw, class_def);
121   ASSERT_TRUE(accessor.HasClassData());
122   auto methods = accessor.GetMethods();
123   auto cur_method = methods.begin();
124 
125   // Check the signature for the static initializer.
126   {
127     ASSERT_EQ(1U, accessor.NumDirectMethods());
128     const dex::MethodId& method_id = raw->GetMethodId(cur_method->GetIndex());
129     const char* name = raw->StringDataByIdx(method_id.name_idx_);
130     ASSERT_STREQ("<init>", name);
131     std::string signature(raw->GetMethodSignature(method_id).ToString());
132     ASSERT_EQ("()V", signature);
133   }
134 
135   // Check all virtual methods.
136   struct Result {
137     const char* name;
138     const char* signature;
139     const char* pretty_method;
140   };
141   static const Result results[] = {
142       {
143           "m1",
144           "(IDJLjava/lang/Object;)Ljava/lang/Float;",
145           "java.lang.Float GetMethodSignature.m1(int, double, long, java.lang.Object)"
146       },
147       {
148           "m2",
149           "(ZSC)LGetMethodSignature;",
150           "GetMethodSignature GetMethodSignature.m2(boolean, short, char)"
151       },
152       {
153           "m3",
154           "()V",
155           "void GetMethodSignature.m3()"
156       },
157       {
158           "m4",
159           "(I)V",
160           "void GetMethodSignature.m4(int)"
161       },
162       {
163           "m5",
164           "(II)V",
165           "void GetMethodSignature.m5(int, int)"
166       },
167       {
168           "m6",
169           "(II[[I)V",
170           "void GetMethodSignature.m6(int, int, int[][])"
171       },
172       {
173           "m7",
174           "(II[[ILjava/lang/Object;)V",
175           "void GetMethodSignature.m7(int, int, int[][], java.lang.Object)"
176       },
177       {
178           "m8",
179           "(II[[ILjava/lang/Object;[[Ljava/lang/Object;)V",
180           "void GetMethodSignature.m8(int, int, int[][], java.lang.Object, java.lang.Object[][])"
181       },
182       {
183           "m9",
184           "()I",
185           "int GetMethodSignature.m9()"
186       },
187       {
188           "mA",
189           "()[[I",
190           "int[][] GetMethodSignature.mA()"
191       },
192       {
193           "mB",
194           "()[[Ljava/lang/Object;",
195           "java.lang.Object[][] GetMethodSignature.mB()"
196       },
197   };
198   ASSERT_EQ(arraysize(results), accessor.NumVirtualMethods());
199   for (const Result& r : results) {
200     ++cur_method;
201     ASSERT_TRUE(cur_method != methods.end());
202     const dex::MethodId& method_id = raw->GetMethodId(cur_method->GetIndex());
203 
204     const char* name = raw->StringDataByIdx(method_id.name_idx_);
205     ASSERT_STREQ(r.name, name);
206 
207     std::string signature(raw->GetMethodSignature(method_id).ToString());
208     ASSERT_EQ(r.signature, signature);
209 
210     std::string plain_method = std::string("GetMethodSignature.") + r.name;
211     ASSERT_EQ(plain_method,
212               raw->PrettyMethod(cur_method->GetIndex(), /* with_signature= */ false));
213     ASSERT_EQ(r.pretty_method,
214               raw->PrettyMethod(cur_method->GetIndex(), /* with_signature= */ true));
215   }
216 }
217 
TEST_F(ArtDexFileLoaderTest,FindStringId)218 TEST_F(ArtDexFileLoaderTest, FindStringId) {
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 dex::StringId* str_id = raw->FindStringId(str);
228     const char* dex_str = raw->GetStringData(*str_id);
229     EXPECT_STREQ(dex_str, str);
230   }
231 }
232 
TEST_F(ArtDexFileLoaderTest,FindTypeId)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 dex::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 dex::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 
TEST_F(ArtDexFileLoaderTest,FindProtoId)246 TEST_F(ArtDexFileLoaderTest, FindProtoId) {
247   for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) {
248     const dex::ProtoId& to_find = java_lang_dex_file_->GetProtoId(dex::ProtoIndex(i));
249     const dex::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 dex::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), dex::ProtoIndex(i));
260   }
261 }
262 
TEST_F(ArtDexFileLoaderTest,FindMethodId)263 TEST_F(ArtDexFileLoaderTest, FindMethodId) {
264   for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) {
265     const dex::MethodId& to_find = java_lang_dex_file_->GetMethodId(i);
266     const dex::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
267     const dex::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
268     const dex::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_);
269     const dex::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 
TEST_F(ArtDexFileLoaderTest,FindFieldId)278 TEST_F(ArtDexFileLoaderTest, FindFieldId) {
279   for (size_t i = 0; i < java_lang_dex_file_->NumFieldIds(); i++) {
280     const dex::FieldId& to_find = java_lang_dex_file_->GetFieldId(i);
281     const dex::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
282     const dex::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
283     const dex::TypeId& type = java_lang_dex_file_->GetTypeId(to_find.type_idx_);
284     const dex::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 
TEST_F(ArtDexFileLoaderTest,GetDexCanonicalLocation)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 }  // namespace art
316