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