1 /*
2  * Copyright (C) 2017 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 <fstream>
18 
19 #include "android-base/strings.h"
20 
21 #include "base/unix_file/fd_file.h"
22 #include "base/zip_archive.h"
23 #include "common_runtime_test.h"
24 #include "dex/art_dex_file_loader.h"
25 #include "dex/class_accessor-inl.h"
26 #include "dex/dex_file-inl.h"
27 #include "exec_utils.h"
28 
29 namespace art {
30 
31 class HiddenApiTest : public CommonRuntimeTest {
32  protected:
GetHiddenApiCmd()33   std::string GetHiddenApiCmd() {
34     std::string file_path = GetTestAndroidRoot();
35     file_path += "/bin/hiddenapi";
36     if (kIsDebugBuild) {
37       file_path += "d";
38     }
39     if (!OS::FileExists(file_path.c_str())) {
40       LOG(FATAL) << "Could not find binary " << file_path;
41       UNREACHABLE();
42     }
43     return file_path;
44   }
45 
RunHiddenapiEncode(const ScratchFile & flags_csv,const std::vector<std::string> & extra_args,const ScratchFile & out_dex)46   std::unique_ptr<const DexFile> RunHiddenapiEncode(const ScratchFile& flags_csv,
47                                                     const std::vector<std::string>& extra_args,
48                                                     const ScratchFile& out_dex) {
49     std::string error;
50     ScratchFile in_dex;
51     std::unique_ptr<ZipArchive> jar(
52         ZipArchive::Open(GetTestDexFileName("HiddenApi").c_str(), &error));
53     if (jar == nullptr) {
54       LOG(FATAL) << "Could not open test file " << GetTestDexFileName("HiddenApi") << ": " << error;
55       UNREACHABLE();
56     }
57     std::unique_ptr<ZipEntry> jar_classes_dex(jar->Find("classes.dex", &error));
58     if (jar_classes_dex == nullptr) {
59       LOG(FATAL) << "Could not find classes.dex in test file " << GetTestDexFileName("HiddenApi")
60                  << ": " << error;
61       UNREACHABLE();
62     } else if (!jar_classes_dex->ExtractToFile(*in_dex.GetFile(), &error)) {
63       LOG(FATAL) << "Could not extract classes.dex from test file "
64                  << GetTestDexFileName("HiddenApi") << ": " << error;
65       UNREACHABLE();
66     }
67 
68     std::vector<std::string> argv_str;
69     argv_str.push_back(GetHiddenApiCmd());
70     argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
71     argv_str.push_back("encode");
72     argv_str.push_back("--input-dex=" + in_dex.GetFilename());
73     argv_str.push_back("--output-dex=" + out_dex.GetFilename());
74     argv_str.push_back("--api-flags=" + flags_csv.GetFilename());
75     argv_str.push_back("--no-force-assign-all");
76     int return_code = ExecAndReturnCode(argv_str, &error);
77     if (return_code == 0) {
78       return OpenDex(out_dex);
79     } else {
80       LOG(ERROR) << "HiddenApi binary exited with unexpected return code " << return_code;
81       return nullptr;
82     }
83   }
84 
RunHiddenapiList(const ScratchFile & out_flags_csv)85   bool RunHiddenapiList(const ScratchFile& out_flags_csv) {
86     std::string error;
87     std::string boot_jar = GetTestDexFileName("HiddenApi");
88     std::string stub_jar = GetTestDexFileName("HiddenApiStubs");
89     std::string boot_cp = android::base::Join(GetLibCoreDexFileNames(), ":");
90 
91     std::vector<std::string> argv_str;
92     argv_str.push_back(GetHiddenApiCmd());
93     argv_str.push_back("list");
94     for (const std::string& core_jar : GetLibCoreDexFileNames()) {
95       argv_str.push_back("--boot-dex=" + core_jar);
96     }
97     argv_str.push_back("--boot-dex=" + boot_jar);
98     argv_str.push_back("--public-stub-classpath=" + boot_cp + ":" + stub_jar);
99     argv_str.push_back("--out-api-flags=" + out_flags_csv.GetFilename());
100     int return_code = ExecAndReturnCode(argv_str, &error);
101     if (return_code == 0) {
102       return true;
103     } else {
104       LOG(ERROR) << "HiddenApi binary exited with unexpected return code " << return_code;
105       return false;
106     }
107   }
108 
OpenDex(const ScratchFile & file)109   std::unique_ptr<const DexFile> OpenDex(const ScratchFile& file) {
110     ArtDexFileLoader dex_loader;
111     std::string error_msg;
112 
113     File fd(file.GetFilename(), O_RDONLY, /* check_usage= */ false);
114     if (fd.Fd() == -1) {
115       PLOG(FATAL) << "Unable to open file '" << file.GetFilename() << "'";
116       UNREACHABLE();
117     }
118 
119     std::unique_ptr<const DexFile> dex_file(dex_loader.OpenDex(
120         fd.Release(), /* location= */ file.GetFilename(), /* verify= */ true,
121         /* verify_checksum= */ true, /* mmap_shared= */ false, &error_msg));
122     if (dex_file.get() == nullptr) {
123       LOG(FATAL) << "Open failed for '" << file.GetFilename() << "' " << error_msg;
124       UNREACHABLE();
125     } else if (!dex_file->IsStandardDexFile()) {
126       LOG(FATAL) << "Expected a standard dex file '" << file.GetFilename() << "'";
127       UNREACHABLE();
128     }
129 
130     return dex_file;
131   }
132 
OpenStream(const ScratchFile & file)133   std::ofstream OpenStream(const ScratchFile& file) {
134     std::ofstream ofs(file.GetFilename(), std::ofstream::out);
135     if (ofs.fail()) {
136       PLOG(FATAL) << "Open failed for '" << file.GetFilename() << "'";
137       UNREACHABLE();
138     }
139     return ofs;
140   }
141 
ReadFlagsCsvFile(const ScratchFile & file)142   std::map<std::string, std::string> ReadFlagsCsvFile(const ScratchFile& file) {
143     std::ifstream ifs(file.GetFilename());
144     std::map<std::string, std::string> flags;
145 
146     for (std::string line; std::getline(ifs, line);) {
147       std::size_t comma = line.find(",");
148       if (comma == std::string::npos) {
149         flags.emplace(line, "");
150       } else {
151         flags.emplace(line.substr(0, comma), line.substr(comma + 1));
152       }
153     }
154 
155     return flags;
156   }
157 
SafeMapGet(const std::string & key,const std::map<std::string,std::string> & map)158   std::string SafeMapGet(const std::string& key, const std::map<std::string, std::string>& map) {
159     auto it = map.find(key);
160     if (it == map.end()) {
161       LOG(FATAL) << "Key not found: " << key;
162       UNREACHABLE();
163     }
164     return it->second;
165   }
166 
FindClass(const char * desc,const DexFile & dex_file)167   const dex::ClassDef& FindClass(const char* desc, const DexFile& dex_file) {
168     const dex::TypeId* type_id = dex_file.FindTypeId(desc);
169     CHECK(type_id != nullptr) << "Could not find class " << desc;
170     const dex::ClassDef* found = dex_file.FindClassDef(dex_file.GetIndexForTypeId(*type_id));
171     CHECK(found != nullptr) << "Could not find class " << desc;
172     return *found;
173   }
174 
GetFieldHiddenFlags(const char * name,uint32_t expected_visibility,const dex::ClassDef & class_def,const DexFile & dex_file)175   hiddenapi::ApiList GetFieldHiddenFlags(const char* name,
176                                          uint32_t expected_visibility,
177                                          const dex::ClassDef& class_def,
178                                          const DexFile& dex_file) {
179     ClassAccessor accessor(dex_file, class_def, /* parse hiddenapi flags */ true);
180     CHECK(accessor.HasClassData()) << "Class " << accessor.GetDescriptor() << " has no data";
181 
182     if (!accessor.HasHiddenapiClassData()) {
183       return hiddenapi::ApiList::Whitelist();
184     }
185 
186     for (const ClassAccessor::Field& field : accessor.GetFields()) {
187       const dex::FieldId& fid = dex_file.GetFieldId(field.GetIndex());
188       if (strcmp(name, dex_file.GetFieldName(fid)) == 0) {
189         const uint32_t actual_visibility = field.GetAccessFlags() & kAccVisibilityFlags;
190         CHECK_EQ(actual_visibility, expected_visibility)
191             << "Field " << name << " in class " << accessor.GetDescriptor();
192         return hiddenapi::ApiList(field.GetHiddenapiFlags());
193       }
194     }
195 
196     LOG(FATAL) << "Could not find field " << name << " in class "
197                << dex_file.GetClassDescriptor(class_def);
198     UNREACHABLE();
199   }
200 
GetMethodHiddenFlags(const char * name,uint32_t expected_visibility,bool expected_native,const dex::ClassDef & class_def,const DexFile & dex_file)201   hiddenapi::ApiList GetMethodHiddenFlags(const char* name,
202                                           uint32_t expected_visibility,
203                                           bool expected_native,
204                                           const dex::ClassDef& class_def,
205                                           const DexFile& dex_file) {
206     ClassAccessor accessor(dex_file, class_def, /* parse hiddenapi flags */ true);
207     CHECK(accessor.HasClassData()) << "Class " << accessor.GetDescriptor() << " has no data";
208 
209     if (!accessor.HasHiddenapiClassData()) {
210       return hiddenapi::ApiList::Whitelist();
211     }
212 
213     for (const ClassAccessor::Method& method : accessor.GetMethods()) {
214       const dex::MethodId& mid = dex_file.GetMethodId(method.GetIndex());
215       if (strcmp(name, dex_file.GetMethodName(mid)) == 0) {
216         CHECK_EQ(expected_native, method.MemberIsNative())
217             << "Method " << name << " in class " << accessor.GetDescriptor();
218         const uint32_t actual_visibility = method.GetAccessFlags() & kAccVisibilityFlags;
219         CHECK_EQ(actual_visibility, expected_visibility)
220             << "Method " << name << " in class " << accessor.GetDescriptor();
221         return hiddenapi::ApiList(method.GetHiddenapiFlags());
222       }
223     }
224 
225     LOG(FATAL) << "Could not find method " << name << " in class "
226                << dex_file.GetClassDescriptor(class_def);
227     UNREACHABLE();
228   }
229 
GetIFieldHiddenFlags(const DexFile & dex_file)230   hiddenapi::ApiList GetIFieldHiddenFlags(const DexFile& dex_file) {
231     return GetFieldHiddenFlags("ifield", kAccPublic, FindClass("LMain;", dex_file), dex_file);
232   }
233 
GetSFieldHiddenFlags(const DexFile & dex_file)234   hiddenapi::ApiList GetSFieldHiddenFlags(const DexFile& dex_file) {
235     return GetFieldHiddenFlags("sfield", kAccPrivate, FindClass("LMain;", dex_file), dex_file);
236   }
237 
GetIMethodHiddenFlags(const DexFile & dex_file)238   hiddenapi::ApiList GetIMethodHiddenFlags(const DexFile& dex_file) {
239     return GetMethodHiddenFlags(
240         "imethod", 0, /* expected_native= */ false, FindClass("LMain;", dex_file), dex_file);
241   }
242 
GetSMethodHiddenFlags(const DexFile & dex_file)243   hiddenapi::ApiList GetSMethodHiddenFlags(const DexFile& dex_file) {
244     return GetMethodHiddenFlags("smethod",
245                                 kAccPublic,
246                                 /* expected_native= */ false,
247                                 FindClass("LMain;", dex_file),
248                                 dex_file);
249   }
250 
GetINMethodHiddenFlags(const DexFile & dex_file)251   hiddenapi::ApiList GetINMethodHiddenFlags(const DexFile& dex_file) {
252     return GetMethodHiddenFlags("inmethod",
253                                 kAccPublic,
254                                 /* expected_native= */ true,
255                                 FindClass("LMain;", dex_file),
256                                 dex_file);
257   }
258 
GetSNMethodHiddenFlags(const DexFile & dex_file)259   hiddenapi::ApiList GetSNMethodHiddenFlags(const DexFile& dex_file) {
260     return GetMethodHiddenFlags("snmethod",
261                                 kAccProtected,
262                                 /* expected_native= */ true,
263                                 FindClass("LMain;", dex_file),
264                                 dex_file);
265   }
266 };
267 
TEST_F(HiddenApiTest,InstanceFieldNoMatch)268 TEST_F(HiddenApiTest, InstanceFieldNoMatch) {
269   ScratchFile dex, flags_csv;
270   OpenStream(flags_csv)
271       << "LMain;->ifield:LBadType1;,greylist" << std::endl
272       << "LMain;->ifield:LBadType2;,greylist-max-o" << std::endl
273       << "LMain;->ifield:LBadType3;,blacklist" << std::endl;
274   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
275   ASSERT_NE(dex_file.get(), nullptr);
276   ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetIFieldHiddenFlags(*dex_file));
277 }
278 
TEST_F(HiddenApiTest,InstanceFieldLightGreylistMatch)279 TEST_F(HiddenApiTest, InstanceFieldLightGreylistMatch) {
280   ScratchFile dex, flags_csv;
281   OpenStream(flags_csv)
282       << "LMain;->ifield:I,greylist" << std::endl
283       << "LMain;->ifield:LBadType2;,greylist-max-o" << std::endl
284       << "LMain;->ifield:LBadType3;,blacklist" << std::endl;
285   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
286   ASSERT_NE(dex_file.get(), nullptr);
287   ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetIFieldHiddenFlags(*dex_file));
288 }
289 
TEST_F(HiddenApiTest,InstanceFieldDarkGreylistMatch)290 TEST_F(HiddenApiTest, InstanceFieldDarkGreylistMatch) {
291   ScratchFile dex, flags_csv;
292   OpenStream(flags_csv)
293       << "LMain;->ifield:LBadType1;,greylist" << std::endl
294       << "LMain;->ifield:I,greylist-max-o" << std::endl
295       << "LMain;->ifield:LBadType3;,blacklist" << std::endl;
296   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
297   ASSERT_NE(dex_file.get(), nullptr);
298   ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetIFieldHiddenFlags(*dex_file));
299 }
300 
TEST_F(HiddenApiTest,InstanceFieldBlacklistMatch)301 TEST_F(HiddenApiTest, InstanceFieldBlacklistMatch) {
302   ScratchFile dex, flags_csv;
303   OpenStream(flags_csv)
304       << "LMain;->ifield:LBadType1;,greylist" << std::endl
305       << "LMain;->ifield:LBadType2;,greylist-max-o" << std::endl
306       << "LMain;->ifield:I,blacklist" << std::endl;
307   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
308   ASSERT_NE(dex_file.get(), nullptr);
309   ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetIFieldHiddenFlags(*dex_file));
310 }
311 
TEST_F(HiddenApiTest,InstanceFieldTwoListsMatch1)312 TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch1) {
313   ScratchFile dex, flags_csv;
314   OpenStream(flags_csv)
315       << "LMain;->ifield:LBadType1;,greylist" << std::endl
316       << "LMain;->ifield:I,blacklist,greylist-max-o" << std::endl;
317   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
318   ASSERT_EQ(dex_file.get(), nullptr);
319 }
320 
TEST_F(HiddenApiTest,InstanceFieldTwoListsMatch2)321 TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch2) {
322   ScratchFile dex, flags_csv;
323   OpenStream(flags_csv)
324       << "LMain;->ifield:LBadType2;,greylist-max-o" << std::endl
325       << "LMain;->ifield:I,blacklist,greylist" << std::endl;
326   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
327   ASSERT_EQ(dex_file.get(), nullptr);
328 }
329 
TEST_F(HiddenApiTest,InstanceFieldTwoListsMatch3)330 TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch3) {
331   ScratchFile dex, flags_csv;
332   OpenStream(flags_csv)
333       << "LMain;->ifield:I,greylist,greylist-max-o" << std::endl
334       << "LMain;->ifield:LBadType3;,blacklist" << std::endl;
335   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
336   ASSERT_EQ(dex_file.get(), nullptr);
337 }
338 
TEST_F(HiddenApiTest,StaticFieldNoMatch)339 TEST_F(HiddenApiTest, StaticFieldNoMatch) {
340   ScratchFile dex, flags_csv;
341   OpenStream(flags_csv)
342       << "LMain;->sfield:LBadType1;,greylist" << std::endl
343       << "LMain;->sfield:LBadType2;,greylist-max-o" << std::endl
344       << "LMain;->sfield:LBadType3;,blacklist" << std::endl;
345   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
346   ASSERT_NE(dex_file.get(), nullptr);
347   ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetSFieldHiddenFlags(*dex_file));
348 }
349 
TEST_F(HiddenApiTest,StaticFieldLightGreylistMatch)350 TEST_F(HiddenApiTest, StaticFieldLightGreylistMatch) {
351   ScratchFile dex, flags_csv;
352   OpenStream(flags_csv)
353       << "LMain;->sfield:Ljava/lang/Object;,greylist" << std::endl
354       << "LMain;->sfield:LBadType2;,greylist-max-o" << std::endl
355       << "LMain;->sfield:LBadType3;,blacklist" << std::endl;
356   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
357   ASSERT_NE(dex_file.get(), nullptr);
358   ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetSFieldHiddenFlags(*dex_file));
359 }
360 
TEST_F(HiddenApiTest,StaticFieldDarkGreylistMatch)361 TEST_F(HiddenApiTest, StaticFieldDarkGreylistMatch) {
362   ScratchFile dex, flags_csv;
363   OpenStream(flags_csv)
364       << "LMain;->sfield:LBadType1;,greylist" << std::endl
365       << "LMain;->sfield:Ljava/lang/Object;,greylist-max-o" << std::endl
366       << "LMain;->sfield:LBadType3;,blacklist" << std::endl;
367   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
368   ASSERT_NE(dex_file.get(), nullptr);
369   ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetSFieldHiddenFlags(*dex_file));
370 }
371 
TEST_F(HiddenApiTest,StaticFieldBlacklistMatch)372 TEST_F(HiddenApiTest, StaticFieldBlacklistMatch) {
373   ScratchFile dex, flags_csv;
374   OpenStream(flags_csv)
375       << "LMain;->sfield:LBadType1;,greylist" << std::endl
376       << "LMain;->sfield:LBadType2;,greylist-max-o" << std::endl
377       << "LMain;->sfield:Ljava/lang/Object;,blacklist" << std::endl;
378   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
379   ASSERT_NE(dex_file.get(), nullptr);
380   ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetSFieldHiddenFlags(*dex_file));
381 }
382 
TEST_F(HiddenApiTest,StaticFieldTwoListsMatch1)383 TEST_F(HiddenApiTest, StaticFieldTwoListsMatch1) {
384   ScratchFile dex, flags_csv;
385   OpenStream(flags_csv)
386       << "LMain;->sfield:LBadType1;,greylist" << std::endl
387       << "LMain;->sfield:Ljava/lang/Object;,blacklist,greylist-max-o" << std::endl;
388   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
389   ASSERT_EQ(dex_file.get(), nullptr);
390 }
391 
TEST_F(HiddenApiTest,StaticFieldTwoListsMatch2)392 TEST_F(HiddenApiTest, StaticFieldTwoListsMatch2) {
393   ScratchFile dex, flags_csv;
394   OpenStream(flags_csv)
395       << "LMain;->sfield:LBadType2;,greylist-max-o" << std::endl
396       << "LMain;->sfield:Ljava/lang/Object;,blacklist,greylist" << std::endl;
397   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
398   ASSERT_EQ(dex_file.get(), nullptr);
399 }
400 
TEST_F(HiddenApiTest,StaticFieldTwoListsMatch3)401 TEST_F(HiddenApiTest, StaticFieldTwoListsMatch3) {
402   ScratchFile dex, flags_csv;
403   OpenStream(flags_csv)
404       << "LMain;->sfield:Ljava/lang/Object;,greylist,greylist-max-o" << std::endl
405       << "LMain;->sfield:LBadType3;,blacklist" << std::endl;
406   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
407   ASSERT_EQ(dex_file.get(), nullptr);
408 }
409 
TEST_F(HiddenApiTest,InstanceMethodNoMatch)410 TEST_F(HiddenApiTest, InstanceMethodNoMatch) {
411   ScratchFile dex, flags_csv;
412   OpenStream(flags_csv)
413       << "LMain;->imethod(LBadType1;)V,greylist" << std::endl
414       << "LMain;->imethod(LBadType2;)V,greylist-max-o" << std::endl
415       << "LMain;->imethod(LBadType3;)V,blacklist" << std::endl;
416   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
417   ASSERT_NE(dex_file.get(), nullptr);
418   ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetIMethodHiddenFlags(*dex_file));
419 }
420 
TEST_F(HiddenApiTest,InstanceMethodLightGreylistMatch)421 TEST_F(HiddenApiTest, InstanceMethodLightGreylistMatch) {
422   ScratchFile dex, flags_csv;
423   OpenStream(flags_csv)
424       << "LMain;->imethod(J)V,greylist" << std::endl
425       << "LMain;->imethod(LBadType2;)V,greylist-max-o" << std::endl
426       << "LMain;->imethod(LBadType3;)V,blacklist" << std::endl;
427   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
428   ASSERT_NE(dex_file.get(), nullptr);
429   ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetIMethodHiddenFlags(*dex_file));
430 }
431 
TEST_F(HiddenApiTest,InstanceMethodDarkGreylistMatch)432 TEST_F(HiddenApiTest, InstanceMethodDarkGreylistMatch) {
433   ScratchFile dex, flags_csv;
434   OpenStream(flags_csv)
435       << "LMain;->imethod(LBadType1;)V,greylist" << std::endl
436       << "LMain;->imethod(J)V,greylist-max-o" << std::endl
437       << "LMain;->imethod(LBadType3;)V,blacklist" << std::endl;
438   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
439   ASSERT_NE(dex_file.get(), nullptr);
440   ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetIMethodHiddenFlags(*dex_file));
441 }
442 
TEST_F(HiddenApiTest,InstanceMethodBlacklistMatch)443 TEST_F(HiddenApiTest, InstanceMethodBlacklistMatch) {
444   ScratchFile dex, flags_csv;
445   OpenStream(flags_csv)
446       << "LMain;->imethod(LBadType1;)V,greylist" << std::endl
447       << "LMain;->imethod(LBadType2;)V,greylist-max-o" << std::endl
448       << "LMain;->imethod(J)V,blacklist" << std::endl;
449   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
450   ASSERT_NE(dex_file.get(), nullptr);
451   ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetIMethodHiddenFlags(*dex_file));
452 }
453 
TEST_F(HiddenApiTest,InstanceMethodTwoListsMatch1)454 TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch1) {
455   ScratchFile dex, flags_csv;
456   OpenStream(flags_csv)
457       << "LMain;->imethod(LBadType1;)V,greylist" << std::endl
458       << "LMain;->imethod(J)V,blacklist,greylist-max-o" << std::endl;
459   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
460   ASSERT_EQ(dex_file.get(), nullptr);
461 }
462 
TEST_F(HiddenApiTest,InstanceMethodTwoListsMatch2)463 TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch2) {
464   ScratchFile dex, flags_csv;
465   OpenStream(flags_csv)
466       << "LMain;->imethod(LBadType2;)V,greylist-max-o" << std::endl
467       << "LMain;->imethod(J)V,blacklist,greylist" << std::endl;
468   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
469   ASSERT_EQ(dex_file.get(), nullptr);
470 }
471 
TEST_F(HiddenApiTest,InstanceMethodTwoListsMatch3)472 TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch3) {
473   ScratchFile dex, flags_csv;
474   OpenStream(flags_csv)
475       << "LMain;->imethod(J)V,greylist,greylist-max-o" << std::endl
476       << "LMain;->imethod(LBadType3;)V,blacklist" << std::endl;
477   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
478   ASSERT_EQ(dex_file.get(), nullptr);
479 }
480 
TEST_F(HiddenApiTest,StaticMethodNoMatch)481 TEST_F(HiddenApiTest, StaticMethodNoMatch) {
482   ScratchFile dex, flags_csv;
483   OpenStream(flags_csv)
484       << "LMain;->smethod(LBadType1;)V,greylist" << std::endl
485       << "LMain;->smethod(LBadType2;)V,greylist-max-o" << std::endl
486       << "LMain;->smethod(LBadType3;)V,blacklist" << std::endl;
487   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
488   ASSERT_NE(dex_file.get(), nullptr);
489   ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetSMethodHiddenFlags(*dex_file));
490 }
491 
TEST_F(HiddenApiTest,StaticMethodLightGreylistMatch)492 TEST_F(HiddenApiTest, StaticMethodLightGreylistMatch) {
493   ScratchFile dex, flags_csv;
494   OpenStream(flags_csv)
495       << "LMain;->smethod(Ljava/lang/Object;)V,greylist" << std::endl
496       << "LMain;->smethod(LBadType2;)V,greylist-max-o" << std::endl
497       << "LMain;->smethod(LBadType3;)V,blacklist" << std::endl;
498   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
499   ASSERT_NE(dex_file.get(), nullptr);
500   ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetSMethodHiddenFlags(*dex_file));
501 }
502 
TEST_F(HiddenApiTest,StaticMethodDarkGreylistMatch)503 TEST_F(HiddenApiTest, StaticMethodDarkGreylistMatch) {
504   ScratchFile dex, flags_csv;
505   OpenStream(flags_csv)
506       << "LMain;->smethod(LBadType1;)V,greylist" << std::endl
507       << "LMain;->smethod(Ljava/lang/Object;)V,greylist-max-o" << std::endl
508       << "LMain;->smethod(LBadType3;)V,blacklist" << std::endl;
509   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
510   ASSERT_NE(dex_file.get(), nullptr);
511   ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetSMethodHiddenFlags(*dex_file));
512 }
513 
TEST_F(HiddenApiTest,StaticMethodBlacklistMatch)514 TEST_F(HiddenApiTest, StaticMethodBlacklistMatch) {
515   ScratchFile dex, flags_csv;
516   OpenStream(flags_csv)
517       << "LMain;->smethod(LBadType1;)V,greylist" << std::endl
518       << "LMain;->smethod(LBadType2;)V,greylist-max-o" << std::endl
519       << "LMain;->smethod(Ljava/lang/Object;)V,blacklist" << std::endl;
520   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
521   ASSERT_NE(dex_file.get(), nullptr);
522   ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetSMethodHiddenFlags(*dex_file));
523 }
524 
TEST_F(HiddenApiTest,StaticMethodTwoListsMatch1)525 TEST_F(HiddenApiTest, StaticMethodTwoListsMatch1) {
526   ScratchFile dex, flags_csv;
527   OpenStream(flags_csv)
528       << "LMain;->smethod(LBadType1;)V,greylist" << std::endl
529       << "LMain;->smethod(Ljava/lang/Object;)V,blacklist,greylist-max-o" << std::endl;
530   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
531   ASSERT_EQ(dex_file.get(), nullptr);
532 }
533 
TEST_F(HiddenApiTest,StaticMethodTwoListsMatch2)534 TEST_F(HiddenApiTest, StaticMethodTwoListsMatch2) {
535   ScratchFile dex, flags_csv;
536   OpenStream(flags_csv)
537       << "LMain;->smethod(LBadType2;)V,greylist-max-o" << std::endl
538       << "LMain;->smethod(Ljava/lang/Object;)V,blacklist,greylist" << std::endl;
539   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
540   ASSERT_EQ(dex_file.get(), nullptr);
541 }
542 
TEST_F(HiddenApiTest,StaticMethodTwoListsMatch3)543 TEST_F(HiddenApiTest, StaticMethodTwoListsMatch3) {
544   ScratchFile dex, flags_csv;
545   OpenStream(flags_csv)
546       << "LMain;->smethod(Ljava/lang/Object;)V,greylist,greylist-max-o" << std::endl
547       << "LMain;->smethod(LBadType3;)V,blacklist" << std::endl;
548   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
549   ASSERT_EQ(dex_file.get(), nullptr);
550 }
551 
TEST_F(HiddenApiTest,InstanceNativeMethodNoMatch)552 TEST_F(HiddenApiTest, InstanceNativeMethodNoMatch) {
553   ScratchFile dex, flags_csv;
554   OpenStream(flags_csv)
555       << "LMain;->inmethod(LBadType1;)V,greylist" << std::endl
556       << "LMain;->inmethod(LBadType2;)V,greylist-max-o" << std::endl
557       << "LMain;->inmethod(LBadType3;)V,blacklist" << std::endl;
558   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
559   ASSERT_NE(dex_file.get(), nullptr);
560   ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetINMethodHiddenFlags(*dex_file));
561 }
562 
TEST_F(HiddenApiTest,InstanceNativeMethodLightGreylistMatch)563 TEST_F(HiddenApiTest, InstanceNativeMethodLightGreylistMatch) {
564   ScratchFile dex, flags_csv;
565   OpenStream(flags_csv)
566       << "LMain;->inmethod(C)V,greylist" << std::endl
567       << "LMain;->inmethod(LBadType2;)V,greylist-max-o" << std::endl
568       << "LMain;->inmethod(LBadType3;)V,blacklist" << std::endl;
569   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
570   ASSERT_NE(dex_file.get(), nullptr);
571   ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetINMethodHiddenFlags(*dex_file));
572 }
573 
TEST_F(HiddenApiTest,InstanceNativeMethodDarkGreylistMatch)574 TEST_F(HiddenApiTest, InstanceNativeMethodDarkGreylistMatch) {
575   ScratchFile dex, flags_csv;
576   OpenStream(flags_csv)
577       << "LMain;->inmethod(LBadType1;)V,greylist" << std::endl
578       << "LMain;->inmethod(C)V,greylist-max-o" << std::endl
579       << "LMain;->inmethod(LBadType3;)V,blacklist" << std::endl;
580   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
581   ASSERT_NE(dex_file.get(), nullptr);
582   ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetINMethodHiddenFlags(*dex_file));
583 }
584 
TEST_F(HiddenApiTest,InstanceNativeMethodBlacklistMatch)585 TEST_F(HiddenApiTest, InstanceNativeMethodBlacklistMatch) {
586   ScratchFile dex, flags_csv;
587   OpenStream(flags_csv)
588       << "LMain;->inmethod(LBadType1;)V,greylist" << std::endl
589       << "LMain;->inmethod(LBadType2;)V,greylist-max-o" << std::endl
590       << "LMain;->inmethod(C)V,blacklist" << std::endl;
591   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
592   ASSERT_NE(dex_file.get(), nullptr);
593   ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetINMethodHiddenFlags(*dex_file));
594 }
595 
TEST_F(HiddenApiTest,InstanceNativeMethodTwoListsMatch1)596 TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch1) {
597   ScratchFile dex, flags_csv;
598   OpenStream(flags_csv)
599       << "LMain;->inmethod(LBadType1;)V,greylist" << std::endl
600       << "LMain;->inmethod(C)V,blacklist,greylist-max-o" << std::endl;
601   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
602   ASSERT_EQ(dex_file.get(), nullptr);
603 }
604 
TEST_F(HiddenApiTest,InstanceNativeMethodTwoListsMatch2)605 TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch2) {
606   ScratchFile dex, flags_csv;
607   OpenStream(flags_csv)
608       << "LMain;->inmethod(C)V,blacklist,greylist" << std::endl
609       << "LMain;->inmethod(LBadType2;)V,greylist-max-o" << std::endl;
610   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
611   ASSERT_EQ(dex_file.get(), nullptr);
612 }
613 
TEST_F(HiddenApiTest,InstanceNativeMethodTwoListsMatch3)614 TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch3) {
615   ScratchFile dex, flags_csv;
616   OpenStream(flags_csv)
617       << "LMain;->inmethod(C)V,greylist,greylist-max-o" << std::endl
618       << "LMain;->inmethod(LBadType3;)V,blacklist" << std::endl;
619   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
620   ASSERT_EQ(dex_file.get(), nullptr);
621 }
622 
TEST_F(HiddenApiTest,StaticNativeMethodNoMatch)623 TEST_F(HiddenApiTest, StaticNativeMethodNoMatch) {
624   ScratchFile dex, flags_csv;
625   OpenStream(flags_csv)
626       << "LMain;->snmethod(LBadType1;)V,greylist" << std::endl
627       << "LMain;->snmethod(LBadType2;)V,greylist-max-o" << std::endl
628       << "LMain;->snmethod(LBadType3;)V,blacklist" << std::endl;
629   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
630   ASSERT_NE(dex_file.get(), nullptr);
631   ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetSNMethodHiddenFlags(*dex_file));
632 }
633 
TEST_F(HiddenApiTest,StaticNativeMethodLightGreylistMatch)634 TEST_F(HiddenApiTest, StaticNativeMethodLightGreylistMatch) {
635   ScratchFile dex, flags_csv;
636   OpenStream(flags_csv)
637       << "LMain;->snmethod(Ljava/lang/Integer;)V,greylist" << std::endl
638       << "LMain;->snmethod(LBadType2;)V,greylist-max-o" << std::endl
639       << "LMain;->snmethod(LBadType3;)V,blacklist" << std::endl;
640   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
641   ASSERT_NE(dex_file.get(), nullptr);
642   ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetSNMethodHiddenFlags(*dex_file));
643 }
644 
TEST_F(HiddenApiTest,StaticNativeMethodDarkGreylistMatch)645 TEST_F(HiddenApiTest, StaticNativeMethodDarkGreylistMatch) {
646   ScratchFile dex, flags_csv;
647   OpenStream(flags_csv)
648       << "LMain;->snmethod(LBadType1;)V,greylist" << std::endl
649       << "LMain;->snmethod(Ljava/lang/Integer;)V,greylist-max-o" << std::endl
650       << "LMain;->snmethod(LBadType3;)V,blacklist" << std::endl;
651   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
652   ASSERT_NE(dex_file.get(), nullptr);
653   ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetSNMethodHiddenFlags(*dex_file));
654 }
655 
TEST_F(HiddenApiTest,StaticNativeMethodBlacklistMatch)656 TEST_F(HiddenApiTest, StaticNativeMethodBlacklistMatch) {
657   ScratchFile dex, flags_csv;
658   OpenStream(flags_csv)
659       << "LMain;->snmethod(LBadType1;)V,greylist" << std::endl
660       << "LMain;->snmethod(LBadType2;)V,greylist-max-o" << std::endl
661       << "LMain;->snmethod(Ljava/lang/Integer;)V,blacklist" << std::endl;
662   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
663   ASSERT_NE(dex_file.get(), nullptr);
664   ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetSNMethodHiddenFlags(*dex_file));
665 }
666 
TEST_F(HiddenApiTest,StaticNativeMethodTwoListsMatch1)667 TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch1) {
668   ScratchFile dex, flags_csv;
669   OpenStream(flags_csv)
670       << "LMain;->snmethod(LBadType1;)V,greylist" << std::endl
671       << "LMain;->snmethod(Ljava/lang/Integer;)V,blacklist,greylist-max-o" << std::endl;
672   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
673   ASSERT_EQ(dex_file.get(), nullptr);
674 }
675 
TEST_F(HiddenApiTest,StaticNativeMethodTwoListsMatch2)676 TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch2) {
677   ScratchFile dex, flags_csv;
678   OpenStream(flags_csv)
679       << "LMain;->snmethod(Ljava/lang/Integer;)V,blacklist,greylist" << std::endl
680       << "LMain;->snmethod(LBadType2;)V,greylist-max-o" << std::endl;
681   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
682   ASSERT_EQ(dex_file.get(), nullptr);
683 }
684 
TEST_F(HiddenApiTest,StaticNativeMethodTwoListsMatch3)685 TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch3) {
686   ScratchFile dex, flags_csv;
687   OpenStream(flags_csv)
688       << "LMain;->snmethod(Ljava/lang/Integer;)V,greylist,greylist-max-o" << std::endl
689       << "LMain;->snmethod(LBadType3;)V,blacklist" << std::endl;
690   auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
691   ASSERT_EQ(dex_file.get(), nullptr);
692 }
693 
694 // The following tests use this class hierarchy:
695 //
696 //    AbstractPackageClass  PublicInterface
697 //           |                     |
698 //           |    ┌----------------┘
699 //           |    |
700 //        PackageClass
701 //
702 // Only PublicInterface is in stubs.
703 
704 // Test a method declared in PublicInterface and defined in PackageClass.
TEST_F(HiddenApiTest,InterfaceMethodImplemented)705 TEST_F(HiddenApiTest, InterfaceMethodImplemented) {
706   ScratchFile flags_csv;
707   ASSERT_TRUE(RunHiddenapiList(flags_csv));
708   auto flags = ReadFlagsCsvFile(flags_csv);
709   ASSERT_EQ(SafeMapGet("LPackageClass;->publicMethod1()V", flags), "public-api");
710 }
711 
712 // Test a method declared in PublicInterface, defined in AbstractPackageClass and
713 // inherited by PackageClass.
TEST_F(HiddenApiTest,InterfaceMethodImplementedInParent)714 TEST_F(HiddenApiTest, InterfaceMethodImplementedInParent) {
715   ScratchFile flags_csv;
716   ASSERT_TRUE(RunHiddenapiList(flags_csv));
717   auto flags = ReadFlagsCsvFile(flags_csv);
718   ASSERT_EQ(SafeMapGet("LAbstractPackageClass;->publicMethod2()V", flags), "public-api");
719 }
720 
721 }  // namespace art
722