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