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.push_back("encode");
70 argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
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 std::string error_msg;
110
111 File fd(file.GetFilename(), O_RDONLY, /* check_usage= */ false);
112 if (fd.Fd() == -1) {
113 PLOG(FATAL) << "Unable to open file '" << file.GetFilename() << "'";
114 UNREACHABLE();
115 }
116
117 ArtDexFileLoader dex_loader(&fd, file.GetFilename());
118 std::unique_ptr<const DexFile> dex_file(dex_loader.Open(
119 /*location_checksum=*/0,
120 /*verify=*/true,
121 /*verify_checksum=*/true,
122 &error_msg));
123 if (dex_file.get() == nullptr) {
124 LOG(FATAL) << "Open failed for '" << file.GetFilename() << "' " << error_msg;
125 UNREACHABLE();
126 } else if (!dex_file->IsStandardDexFile()) {
127 LOG(FATAL) << "Expected a standard dex file '" << file.GetFilename() << "'";
128 UNREACHABLE();
129 }
130
131 return dex_file;
132 }
133
OpenStream(const ScratchFile & file)134 std::ofstream OpenStream(const ScratchFile& file) {
135 std::ofstream ofs(file.GetFilename(), std::ofstream::out);
136 if (ofs.fail()) {
137 PLOG(FATAL) << "Open failed for '" << file.GetFilename() << "'";
138 UNREACHABLE();
139 }
140 return ofs;
141 }
142
ReadFlagsCsvFile(const ScratchFile & file)143 std::map<std::string, std::string> ReadFlagsCsvFile(const ScratchFile& file) {
144 std::ifstream ifs(file.GetFilename());
145 std::map<std::string, std::string> flags;
146
147 for (std::string line; std::getline(ifs, line);) {
148 std::size_t comma = line.find(',');
149 if (comma == std::string::npos) {
150 flags.emplace(line, "");
151 } else {
152 flags.emplace(line.substr(0, comma), line.substr(comma + 1));
153 }
154 }
155
156 return flags;
157 }
158
SafeMapGet(const std::string & key,const std::map<std::string,std::string> & map)159 std::string SafeMapGet(const std::string& key, const std::map<std::string, std::string>& map) {
160 auto it = map.find(key);
161 if (it == map.end()) {
162 LOG(FATAL) << "Key not found: " << key;
163 UNREACHABLE();
164 }
165 return it->second;
166 }
167
FindClass(const char * desc,const DexFile & dex_file)168 const dex::ClassDef& FindClass(const char* desc, const DexFile& dex_file) {
169 const dex::TypeId* type_id = dex_file.FindTypeId(desc);
170 CHECK(type_id != nullptr) << "Could not find class " << desc;
171 const dex::ClassDef* found = dex_file.FindClassDef(dex_file.GetIndexForTypeId(*type_id));
172 CHECK(found != nullptr) << "Could not find class " << desc;
173 return *found;
174 }
175
GetFieldHiddenFlags(const char * name,uint32_t expected_visibility,const dex::ClassDef & class_def,const DexFile & dex_file)176 hiddenapi::ApiList GetFieldHiddenFlags(const char* name,
177 uint32_t expected_visibility,
178 const dex::ClassDef& class_def,
179 const DexFile& dex_file) {
180 ClassAccessor accessor(dex_file, class_def, /* parse hiddenapi flags */ true);
181 CHECK(accessor.HasClassData()) << "Class " << accessor.GetDescriptor() << " has no data";
182
183 if (!accessor.HasHiddenapiClassData()) {
184 return hiddenapi::ApiList::Sdk();
185 }
186
187 for (const ClassAccessor::Field& field : accessor.GetFields()) {
188 const dex::FieldId& fid = dex_file.GetFieldId(field.GetIndex());
189 if (strcmp(name, dex_file.GetFieldName(fid)) == 0) {
190 const uint32_t actual_visibility = field.GetAccessFlags() & kAccVisibilityFlags;
191 CHECK_EQ(actual_visibility, expected_visibility)
192 << "Field " << name << " in class " << accessor.GetDescriptor();
193 return hiddenapi::ApiList(field.GetHiddenapiFlags());
194 }
195 }
196
197 LOG(FATAL) << "Could not find field " << name << " in class "
198 << dex_file.GetClassDescriptor(class_def);
199 UNREACHABLE();
200 }
201
GetMethodHiddenFlags(const char * name,uint32_t expected_visibility,bool expected_native,const dex::ClassDef & class_def,const DexFile & dex_file)202 hiddenapi::ApiList GetMethodHiddenFlags(const char* name,
203 uint32_t expected_visibility,
204 bool expected_native,
205 const dex::ClassDef& class_def,
206 const DexFile& dex_file) {
207 ClassAccessor accessor(dex_file, class_def, /* parse hiddenapi flags */ true);
208 CHECK(accessor.HasClassData()) << "Class " << accessor.GetDescriptor() << " has no data";
209
210 if (!accessor.HasHiddenapiClassData()) {
211 return hiddenapi::ApiList::Sdk();
212 }
213
214 for (const ClassAccessor::Method& method : accessor.GetMethods()) {
215 const dex::MethodId& mid = dex_file.GetMethodId(method.GetIndex());
216 if (strcmp(name, dex_file.GetMethodName(mid)) == 0) {
217 CHECK_EQ(expected_native, method.MemberIsNative())
218 << "Method " << name << " in class " << accessor.GetDescriptor();
219 const uint32_t actual_visibility = method.GetAccessFlags() & kAccVisibilityFlags;
220 CHECK_EQ(actual_visibility, expected_visibility)
221 << "Method " << name << " in class " << accessor.GetDescriptor();
222 return hiddenapi::ApiList(method.GetHiddenapiFlags());
223 }
224 }
225
226 LOG(FATAL) << "Could not find method " << name << " in class "
227 << dex_file.GetClassDescriptor(class_def);
228 UNREACHABLE();
229 }
230
GetIFieldHiddenFlags(const DexFile & dex_file)231 hiddenapi::ApiList GetIFieldHiddenFlags(const DexFile& dex_file) {
232 return GetFieldHiddenFlags("ifield", kAccPublic, FindClass("LMain;", dex_file), dex_file);
233 }
234
GetSFieldHiddenFlags(const DexFile & dex_file)235 hiddenapi::ApiList GetSFieldHiddenFlags(const DexFile& dex_file) {
236 return GetFieldHiddenFlags("sfield", kAccPrivate, FindClass("LMain;", dex_file), dex_file);
237 }
238
GetIMethodHiddenFlags(const DexFile & dex_file)239 hiddenapi::ApiList GetIMethodHiddenFlags(const DexFile& dex_file) {
240 return GetMethodHiddenFlags(
241 "imethod", 0, /* expected_native= */ false, FindClass("LMain;", dex_file), dex_file);
242 }
243
GetSMethodHiddenFlags(const DexFile & dex_file)244 hiddenapi::ApiList GetSMethodHiddenFlags(const DexFile& dex_file) {
245 return GetMethodHiddenFlags("smethod",
246 kAccPublic,
247 /* expected_native= */ false,
248 FindClass("LMain;", dex_file),
249 dex_file);
250 }
251
GetINMethodHiddenFlags(const DexFile & dex_file)252 hiddenapi::ApiList GetINMethodHiddenFlags(const DexFile& dex_file) {
253 return GetMethodHiddenFlags("inmethod",
254 kAccPublic,
255 /* expected_native= */ true,
256 FindClass("LMain;", dex_file),
257 dex_file);
258 }
259
GetSNMethodHiddenFlags(const DexFile & dex_file)260 hiddenapi::ApiList GetSNMethodHiddenFlags(const DexFile& dex_file) {
261 return GetMethodHiddenFlags("snmethod",
262 kAccProtected,
263 /* expected_native= */ true,
264 FindClass("LMain;", dex_file),
265 dex_file);
266 }
267 };
268
TEST_F(HiddenApiTest,InstanceFieldNoMatch)269 TEST_F(HiddenApiTest, InstanceFieldNoMatch) {
270 ScratchFile dex, flags_csv;
271 OpenStream(flags_csv)
272 << "LMain;->ifield:LBadType1;,unsupported" << std::endl
273 << "LMain;->ifield:LBadType2;,max-target-o" << std::endl
274 << "LMain;->ifield:LBadType3;,blocked" << std::endl;
275 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
276 ASSERT_NE(dex_file.get(), nullptr);
277 ASSERT_EQ(hiddenapi::ApiList::Sdk(), GetIFieldHiddenFlags(*dex_file));
278 }
279
TEST_F(HiddenApiTest,InstanceFieldLightunsupportedMatch)280 TEST_F(HiddenApiTest, InstanceFieldLightunsupportedMatch) {
281 ScratchFile dex, flags_csv;
282 OpenStream(flags_csv)
283 << "LMain;->ifield:I,unsupported" << std::endl
284 << "LMain;->ifield:LBadType2;,max-target-o" << std::endl
285 << "LMain;->ifield:LBadType3;,blocked" << std::endl;
286 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
287 ASSERT_NE(dex_file.get(), nullptr);
288 ASSERT_EQ(hiddenapi::ApiList::Unsupported(), GetIFieldHiddenFlags(*dex_file));
289 }
290
TEST_F(HiddenApiTest,InstanceFieldDarkunsupportedMatch)291 TEST_F(HiddenApiTest, InstanceFieldDarkunsupportedMatch) {
292 ScratchFile dex, flags_csv;
293 OpenStream(flags_csv)
294 << "LMain;->ifield:LBadType1;,unsupported" << std::endl
295 << "LMain;->ifield:I,max-target-o" << std::endl
296 << "LMain;->ifield:LBadType3;,blocked" << std::endl;
297 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
298 ASSERT_NE(dex_file.get(), nullptr);
299 ASSERT_EQ(hiddenapi::ApiList::MaxTargetO(), GetIFieldHiddenFlags(*dex_file));
300 }
301
TEST_F(HiddenApiTest,InstanceFieldblockedMatch)302 TEST_F(HiddenApiTest, InstanceFieldblockedMatch) {
303 ScratchFile dex, flags_csv;
304 OpenStream(flags_csv)
305 << "LMain;->ifield:LBadType1;,unsupported" << std::endl
306 << "LMain;->ifield:LBadType2;,max-target-o" << std::endl
307 << "LMain;->ifield:I,blocked" << std::endl;
308 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
309 ASSERT_NE(dex_file.get(), nullptr);
310 ASSERT_EQ(hiddenapi::ApiList::Blocked(), GetIFieldHiddenFlags(*dex_file));
311 }
312
TEST_F(HiddenApiTest,InstanceFieldTwoListsMatch1)313 TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch1) {
314 ScratchFile dex, flags_csv;
315 OpenStream(flags_csv)
316 << "LMain;->ifield:LBadType1;,unsupported" << std::endl
317 << "LMain;->ifield:I,blocked,max-target-o" << std::endl;
318 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
319 ASSERT_EQ(dex_file.get(), nullptr);
320 }
321
TEST_F(HiddenApiTest,InstanceFieldTwoListsMatch2)322 TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch2) {
323 ScratchFile dex, flags_csv;
324 OpenStream(flags_csv)
325 << "LMain;->ifield:LBadType2;,max-target-o" << std::endl
326 << "LMain;->ifield:I,blocked,unsupported" << std::endl;
327 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
328 ASSERT_EQ(dex_file.get(), nullptr);
329 }
330
TEST_F(HiddenApiTest,InstanceFieldTwoListsMatch3)331 TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch3) {
332 ScratchFile dex, flags_csv;
333 OpenStream(flags_csv)
334 << "LMain;->ifield:I,unsupported,max-target-o" << std::endl
335 << "LMain;->ifield:LBadType3;,blocked" << std::endl;
336 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
337 ASSERT_EQ(dex_file.get(), nullptr);
338 }
339
TEST_F(HiddenApiTest,StaticFieldNoMatch)340 TEST_F(HiddenApiTest, StaticFieldNoMatch) {
341 ScratchFile dex, flags_csv;
342 OpenStream(flags_csv)
343 << "LMain;->sfield:LBadType1;,unsupported" << std::endl
344 << "LMain;->sfield:LBadType2;,max-target-o" << std::endl
345 << "LMain;->sfield:LBadType3;,blocked" << std::endl;
346 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
347 ASSERT_NE(dex_file.get(), nullptr);
348 ASSERT_EQ(hiddenapi::ApiList::Sdk(), GetSFieldHiddenFlags(*dex_file));
349 }
350
TEST_F(HiddenApiTest,StaticFieldLightunsupportedMatch)351 TEST_F(HiddenApiTest, StaticFieldLightunsupportedMatch) {
352 ScratchFile dex, flags_csv;
353 OpenStream(flags_csv)
354 << "LMain;->sfield:Ljava/lang/Object;,unsupported" << std::endl
355 << "LMain;->sfield:LBadType2;,max-target-o" << std::endl
356 << "LMain;->sfield:LBadType3;,blocked" << std::endl;
357 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
358 ASSERT_NE(dex_file.get(), nullptr);
359 ASSERT_EQ(hiddenapi::ApiList::Unsupported(), GetSFieldHiddenFlags(*dex_file));
360 }
361
TEST_F(HiddenApiTest,StaticFieldDarkunsupportedMatch)362 TEST_F(HiddenApiTest, StaticFieldDarkunsupportedMatch) {
363 ScratchFile dex, flags_csv;
364 OpenStream(flags_csv)
365 << "LMain;->sfield:LBadType1;,unsupported" << std::endl
366 << "LMain;->sfield:Ljava/lang/Object;,max-target-o" << std::endl
367 << "LMain;->sfield:LBadType3;,blocked" << std::endl;
368 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
369 ASSERT_NE(dex_file.get(), nullptr);
370 ASSERT_EQ(hiddenapi::ApiList::MaxTargetO(), GetSFieldHiddenFlags(*dex_file));
371 }
372
TEST_F(HiddenApiTest,StaticFieldblockedMatch)373 TEST_F(HiddenApiTest, StaticFieldblockedMatch) {
374 ScratchFile dex, flags_csv;
375 OpenStream(flags_csv)
376 << "LMain;->sfield:LBadType1;,unsupported" << std::endl
377 << "LMain;->sfield:LBadType2;,max-target-o" << std::endl
378 << "LMain;->sfield:Ljava/lang/Object;,blocked" << std::endl;
379 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
380 ASSERT_NE(dex_file.get(), nullptr);
381 ASSERT_EQ(hiddenapi::ApiList::Blocked(), GetSFieldHiddenFlags(*dex_file));
382 }
383
TEST_F(HiddenApiTest,StaticFieldTwoListsMatch1)384 TEST_F(HiddenApiTest, StaticFieldTwoListsMatch1) {
385 ScratchFile dex, flags_csv;
386 OpenStream(flags_csv)
387 << "LMain;->sfield:LBadType1;,unsupported" << std::endl
388 << "LMain;->sfield:Ljava/lang/Object;,blocked,max-target-o" << std::endl;
389 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
390 ASSERT_EQ(dex_file.get(), nullptr);
391 }
392
TEST_F(HiddenApiTest,StaticFieldTwoListsMatch2)393 TEST_F(HiddenApiTest, StaticFieldTwoListsMatch2) {
394 ScratchFile dex, flags_csv;
395 OpenStream(flags_csv)
396 << "LMain;->sfield:LBadType2;,max-target-o" << std::endl
397 << "LMain;->sfield:Ljava/lang/Object;,blocked,unsupported" << std::endl;
398 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
399 ASSERT_EQ(dex_file.get(), nullptr);
400 }
401
TEST_F(HiddenApiTest,StaticFieldTwoListsMatch3)402 TEST_F(HiddenApiTest, StaticFieldTwoListsMatch3) {
403 ScratchFile dex, flags_csv;
404 OpenStream(flags_csv)
405 << "LMain;->sfield:Ljava/lang/Object;,unsupported,max-target-o" << std::endl
406 << "LMain;->sfield:LBadType3;,blocked" << std::endl;
407 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
408 ASSERT_EQ(dex_file.get(), nullptr);
409 }
410
TEST_F(HiddenApiTest,InstanceMethodNoMatch)411 TEST_F(HiddenApiTest, InstanceMethodNoMatch) {
412 ScratchFile dex, flags_csv;
413 OpenStream(flags_csv)
414 << "LMain;->imethod(LBadType1;)V,unsupported" << std::endl
415 << "LMain;->imethod(LBadType2;)V,max-target-o" << std::endl
416 << "LMain;->imethod(LBadType3;)V,blocked" << std::endl;
417 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
418 ASSERT_NE(dex_file.get(), nullptr);
419 ASSERT_EQ(hiddenapi::ApiList::Sdk(), GetIMethodHiddenFlags(*dex_file));
420 }
421
TEST_F(HiddenApiTest,InstanceMethodLightunsupportedMatch)422 TEST_F(HiddenApiTest, InstanceMethodLightunsupportedMatch) {
423 ScratchFile dex, flags_csv;
424 OpenStream(flags_csv)
425 << "LMain;->imethod(J)V,unsupported" << std::endl
426 << "LMain;->imethod(LBadType2;)V,max-target-o" << std::endl
427 << "LMain;->imethod(LBadType3;)V,blocked" << std::endl;
428 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
429 ASSERT_NE(dex_file.get(), nullptr);
430 ASSERT_EQ(hiddenapi::ApiList::Unsupported(), GetIMethodHiddenFlags(*dex_file));
431 }
432
TEST_F(HiddenApiTest,InstanceMethodDarkunsupportedMatch)433 TEST_F(HiddenApiTest, InstanceMethodDarkunsupportedMatch) {
434 ScratchFile dex, flags_csv;
435 OpenStream(flags_csv)
436 << "LMain;->imethod(LBadType1;)V,unsupported" << std::endl
437 << "LMain;->imethod(J)V,max-target-o" << std::endl
438 << "LMain;->imethod(LBadType3;)V,blocked" << std::endl;
439 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
440 ASSERT_NE(dex_file.get(), nullptr);
441 ASSERT_EQ(hiddenapi::ApiList::MaxTargetO(), GetIMethodHiddenFlags(*dex_file));
442 }
443
TEST_F(HiddenApiTest,InstanceMethodblockedMatch)444 TEST_F(HiddenApiTest, InstanceMethodblockedMatch) {
445 ScratchFile dex, flags_csv;
446 OpenStream(flags_csv)
447 << "LMain;->imethod(LBadType1;)V,unsupported" << std::endl
448 << "LMain;->imethod(LBadType2;)V,max-target-o" << std::endl
449 << "LMain;->imethod(J)V,blocked" << std::endl;
450 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
451 ASSERT_NE(dex_file.get(), nullptr);
452 ASSERT_EQ(hiddenapi::ApiList::Blocked(), GetIMethodHiddenFlags(*dex_file));
453 }
454
TEST_F(HiddenApiTest,InstanceMethodTwoListsMatch1)455 TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch1) {
456 ScratchFile dex, flags_csv;
457 OpenStream(flags_csv)
458 << "LMain;->imethod(LBadType1;)V,unsupported" << std::endl
459 << "LMain;->imethod(J)V,blocked,max-target-o" << std::endl;
460 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
461 ASSERT_EQ(dex_file.get(), nullptr);
462 }
463
TEST_F(HiddenApiTest,InstanceMethodTwoListsMatch2)464 TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch2) {
465 ScratchFile dex, flags_csv;
466 OpenStream(flags_csv)
467 << "LMain;->imethod(LBadType2;)V,max-target-o" << std::endl
468 << "LMain;->imethod(J)V,blocked,unsupported" << std::endl;
469 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
470 ASSERT_EQ(dex_file.get(), nullptr);
471 }
472
TEST_F(HiddenApiTest,InstanceMethodTwoListsMatch3)473 TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch3) {
474 ScratchFile dex, flags_csv;
475 OpenStream(flags_csv)
476 << "LMain;->imethod(J)V,unsupported,max-target-o" << std::endl
477 << "LMain;->imethod(LBadType3;)V,blocked" << std::endl;
478 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
479 ASSERT_EQ(dex_file.get(), nullptr);
480 }
481
TEST_F(HiddenApiTest,StaticMethodNoMatch)482 TEST_F(HiddenApiTest, StaticMethodNoMatch) {
483 ScratchFile dex, flags_csv;
484 OpenStream(flags_csv)
485 << "LMain;->smethod(LBadType1;)V,unsupported" << std::endl
486 << "LMain;->smethod(LBadType2;)V,max-target-o" << std::endl
487 << "LMain;->smethod(LBadType3;)V,blocked" << std::endl;
488 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
489 ASSERT_NE(dex_file.get(), nullptr);
490 ASSERT_EQ(hiddenapi::ApiList::Sdk(), GetSMethodHiddenFlags(*dex_file));
491 }
492
TEST_F(HiddenApiTest,StaticMethodLightunsupportedMatch)493 TEST_F(HiddenApiTest, StaticMethodLightunsupportedMatch) {
494 ScratchFile dex, flags_csv;
495 OpenStream(flags_csv)
496 << "LMain;->smethod(Ljava/lang/Object;)V,unsupported" << std::endl
497 << "LMain;->smethod(LBadType2;)V,max-target-o" << std::endl
498 << "LMain;->smethod(LBadType3;)V,blocked" << std::endl;
499 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
500 ASSERT_NE(dex_file.get(), nullptr);
501 ASSERT_EQ(hiddenapi::ApiList::Unsupported(), GetSMethodHiddenFlags(*dex_file));
502 }
503
TEST_F(HiddenApiTest,StaticMethodDarkunsupportedMatch)504 TEST_F(HiddenApiTest, StaticMethodDarkunsupportedMatch) {
505 ScratchFile dex, flags_csv;
506 OpenStream(flags_csv)
507 << "LMain;->smethod(LBadType1;)V,unsupported" << std::endl
508 << "LMain;->smethod(Ljava/lang/Object;)V,max-target-o" << std::endl
509 << "LMain;->smethod(LBadType3;)V,blocked" << std::endl;
510 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
511 ASSERT_NE(dex_file.get(), nullptr);
512 ASSERT_EQ(hiddenapi::ApiList::MaxTargetO(), GetSMethodHiddenFlags(*dex_file));
513 }
514
TEST_F(HiddenApiTest,StaticMethodblockedMatch)515 TEST_F(HiddenApiTest, StaticMethodblockedMatch) {
516 ScratchFile dex, flags_csv;
517 OpenStream(flags_csv)
518 << "LMain;->smethod(LBadType1;)V,unsupported" << std::endl
519 << "LMain;->smethod(LBadType2;)V,max-target-o" << std::endl
520 << "LMain;->smethod(Ljava/lang/Object;)V,blocked" << std::endl;
521 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
522 ASSERT_NE(dex_file.get(), nullptr);
523 ASSERT_EQ(hiddenapi::ApiList::Blocked(), GetSMethodHiddenFlags(*dex_file));
524 }
525
TEST_F(HiddenApiTest,StaticMethodTwoListsMatch1)526 TEST_F(HiddenApiTest, StaticMethodTwoListsMatch1) {
527 ScratchFile dex, flags_csv;
528 OpenStream(flags_csv)
529 << "LMain;->smethod(LBadType1;)V,unsupported" << std::endl
530 << "LMain;->smethod(Ljava/lang/Object;)V,blocked,max-target-o" << std::endl;
531 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
532 ASSERT_EQ(dex_file.get(), nullptr);
533 }
534
TEST_F(HiddenApiTest,StaticMethodTwoListsMatch2)535 TEST_F(HiddenApiTest, StaticMethodTwoListsMatch2) {
536 ScratchFile dex, flags_csv;
537 OpenStream(flags_csv)
538 << "LMain;->smethod(LBadType2;)V,max-target-o" << std::endl
539 << "LMain;->smethod(Ljava/lang/Object;)V,blocked,unsupported" << std::endl;
540 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
541 ASSERT_EQ(dex_file.get(), nullptr);
542 }
543
TEST_F(HiddenApiTest,StaticMethodTwoListsMatch3)544 TEST_F(HiddenApiTest, StaticMethodTwoListsMatch3) {
545 ScratchFile dex, flags_csv;
546 OpenStream(flags_csv)
547 << "LMain;->smethod(Ljava/lang/Object;)V,unsupported,max-target-o" << std::endl
548 << "LMain;->smethod(LBadType3;)V,blocked" << std::endl;
549 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
550 ASSERT_EQ(dex_file.get(), nullptr);
551 }
552
TEST_F(HiddenApiTest,InstanceNativeMethodNoMatch)553 TEST_F(HiddenApiTest, InstanceNativeMethodNoMatch) {
554 ScratchFile dex, flags_csv;
555 OpenStream(flags_csv)
556 << "LMain;->inmethod(LBadType1;)V,unsupported" << std::endl
557 << "LMain;->inmethod(LBadType2;)V,max-target-o" << std::endl
558 << "LMain;->inmethod(LBadType3;)V,blocked" << std::endl;
559 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
560 ASSERT_NE(dex_file.get(), nullptr);
561 ASSERT_EQ(hiddenapi::ApiList::Sdk(), GetINMethodHiddenFlags(*dex_file));
562 }
563
TEST_F(HiddenApiTest,InstanceNativeMethodLightunsupportedMatch)564 TEST_F(HiddenApiTest, InstanceNativeMethodLightunsupportedMatch) {
565 ScratchFile dex, flags_csv;
566 OpenStream(flags_csv)
567 << "LMain;->inmethod(C)V,unsupported" << std::endl
568 << "LMain;->inmethod(LBadType2;)V,max-target-o" << std::endl
569 << "LMain;->inmethod(LBadType3;)V,blocked" << std::endl;
570 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
571 ASSERT_NE(dex_file.get(), nullptr);
572 ASSERT_EQ(hiddenapi::ApiList::Unsupported(), GetINMethodHiddenFlags(*dex_file));
573 }
574
TEST_F(HiddenApiTest,InstanceNativeMethodDarkunsupportedMatch)575 TEST_F(HiddenApiTest, InstanceNativeMethodDarkunsupportedMatch) {
576 ScratchFile dex, flags_csv;
577 OpenStream(flags_csv)
578 << "LMain;->inmethod(LBadType1;)V,unsupported" << std::endl
579 << "LMain;->inmethod(C)V,max-target-o" << std::endl
580 << "LMain;->inmethod(LBadType3;)V,blocked" << std::endl;
581 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
582 ASSERT_NE(dex_file.get(), nullptr);
583 ASSERT_EQ(hiddenapi::ApiList::MaxTargetO(), GetINMethodHiddenFlags(*dex_file));
584 }
585
TEST_F(HiddenApiTest,InstanceNativeMethodblockedMatch)586 TEST_F(HiddenApiTest, InstanceNativeMethodblockedMatch) {
587 ScratchFile dex, flags_csv;
588 OpenStream(flags_csv)
589 << "LMain;->inmethod(LBadType1;)V,unsupported" << std::endl
590 << "LMain;->inmethod(LBadType2;)V,max-target-o" << std::endl
591 << "LMain;->inmethod(C)V,blocked" << std::endl;
592 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
593 ASSERT_NE(dex_file.get(), nullptr);
594 ASSERT_EQ(hiddenapi::ApiList::Blocked(), GetINMethodHiddenFlags(*dex_file));
595 }
596
TEST_F(HiddenApiTest,InstanceNativeMethodTwoListsMatch1)597 TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch1) {
598 ScratchFile dex, flags_csv;
599 OpenStream(flags_csv)
600 << "LMain;->inmethod(LBadType1;)V,unsupported" << std::endl
601 << "LMain;->inmethod(C)V,blocked,max-target-o" << std::endl;
602 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
603 ASSERT_EQ(dex_file.get(), nullptr);
604 }
605
TEST_F(HiddenApiTest,InstanceNativeMethodTwoListsMatch2)606 TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch2) {
607 ScratchFile dex, flags_csv;
608 OpenStream(flags_csv)
609 << "LMain;->inmethod(C)V,blocked,unsupported" << std::endl
610 << "LMain;->inmethod(LBadType2;)V,max-target-o" << std::endl;
611 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
612 ASSERT_EQ(dex_file.get(), nullptr);
613 }
614
TEST_F(HiddenApiTest,InstanceNativeMethodTwoListsMatch3)615 TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch3) {
616 ScratchFile dex, flags_csv;
617 OpenStream(flags_csv)
618 << "LMain;->inmethod(C)V,unsupported,max-target-o" << std::endl
619 << "LMain;->inmethod(LBadType3;)V,blocked" << std::endl;
620 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
621 ASSERT_EQ(dex_file.get(), nullptr);
622 }
623
TEST_F(HiddenApiTest,StaticNativeMethodNoMatch)624 TEST_F(HiddenApiTest, StaticNativeMethodNoMatch) {
625 ScratchFile dex, flags_csv;
626 OpenStream(flags_csv)
627 << "LMain;->snmethod(LBadType1;)V,unsupported" << std::endl
628 << "LMain;->snmethod(LBadType2;)V,max-target-o" << std::endl
629 << "LMain;->snmethod(LBadType3;)V,blocked" << std::endl;
630 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
631 ASSERT_NE(dex_file.get(), nullptr);
632 ASSERT_EQ(hiddenapi::ApiList::Sdk(), GetSNMethodHiddenFlags(*dex_file));
633 }
634
TEST_F(HiddenApiTest,StaticNativeMethodLightunsupportedMatch)635 TEST_F(HiddenApiTest, StaticNativeMethodLightunsupportedMatch) {
636 ScratchFile dex, flags_csv;
637 OpenStream(flags_csv)
638 << "LMain;->snmethod(Ljava/lang/Integer;)V,unsupported" << std::endl
639 << "LMain;->snmethod(LBadType2;)V,max-target-o" << std::endl
640 << "LMain;->snmethod(LBadType3;)V,blocked" << std::endl;
641 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
642 ASSERT_NE(dex_file.get(), nullptr);
643 ASSERT_EQ(hiddenapi::ApiList::Unsupported(), GetSNMethodHiddenFlags(*dex_file));
644 }
645
TEST_F(HiddenApiTest,StaticNativeMethodDarkunsupportedMatch)646 TEST_F(HiddenApiTest, StaticNativeMethodDarkunsupportedMatch) {
647 ScratchFile dex, flags_csv;
648 OpenStream(flags_csv)
649 << "LMain;->snmethod(LBadType1;)V,unsupported" << std::endl
650 << "LMain;->snmethod(Ljava/lang/Integer;)V,max-target-o" << std::endl
651 << "LMain;->snmethod(LBadType3;)V,blocked" << std::endl;
652 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
653 ASSERT_NE(dex_file.get(), nullptr);
654 ASSERT_EQ(hiddenapi::ApiList::MaxTargetO(), GetSNMethodHiddenFlags(*dex_file));
655 }
656
TEST_F(HiddenApiTest,StaticNativeMethodblockedMatch)657 TEST_F(HiddenApiTest, StaticNativeMethodblockedMatch) {
658 ScratchFile dex, flags_csv;
659 OpenStream(flags_csv)
660 << "LMain;->snmethod(LBadType1;)V,unsupported" << std::endl
661 << "LMain;->snmethod(LBadType2;)V,max-target-o" << std::endl
662 << "LMain;->snmethod(Ljava/lang/Integer;)V,blocked" << std::endl;
663 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
664 ASSERT_NE(dex_file.get(), nullptr);
665 ASSERT_EQ(hiddenapi::ApiList::Blocked(), GetSNMethodHiddenFlags(*dex_file));
666 }
667
TEST_F(HiddenApiTest,StaticNativeMethodTwoListsMatch1)668 TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch1) {
669 ScratchFile dex, flags_csv;
670 OpenStream(flags_csv)
671 << "LMain;->snmethod(LBadType1;)V,unsupported" << std::endl
672 << "LMain;->snmethod(Ljava/lang/Integer;)V,blocked,max-target-o" << std::endl;
673 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
674 ASSERT_EQ(dex_file.get(), nullptr);
675 }
676
TEST_F(HiddenApiTest,StaticNativeMethodTwoListsMatch2)677 TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch2) {
678 ScratchFile dex, flags_csv;
679 OpenStream(flags_csv)
680 << "LMain;->snmethod(Ljava/lang/Integer;)V,blocked,unsupported" << std::endl
681 << "LMain;->snmethod(LBadType2;)V,max-target-o" << std::endl;
682 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
683 ASSERT_EQ(dex_file.get(), nullptr);
684 }
685
TEST_F(HiddenApiTest,StaticNativeMethodTwoListsMatch3)686 TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch3) {
687 ScratchFile dex, flags_csv;
688 OpenStream(flags_csv)
689 << "LMain;->snmethod(Ljava/lang/Integer;)V,unsupported,max-target-o" << std::endl
690 << "LMain;->snmethod(LBadType3;)V,blocked" << std::endl;
691 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
692 ASSERT_EQ(dex_file.get(), nullptr);
693 }
694
TEST_F(HiddenApiTest,InstanceFieldCorePlatformApiMatch)695 TEST_F(HiddenApiTest, InstanceFieldCorePlatformApiMatch) {
696 ScratchFile dex, flags_csv;
697 OpenStream(flags_csv)
698 << "LMain;->ifield:LBadType1;,unsupported" << std::endl
699 << "LMain;->ifield:LBadType2;,max-target-o" << std::endl
700 << "LMain;->ifield:I,unsupported,core-platform-api" << std::endl;
701 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
702 ASSERT_NE(dex_file.get(), nullptr);
703 ASSERT_EQ(hiddenapi::ApiList::CorePlatformApi() |
704 hiddenapi::ApiList::Unsupported(), GetIFieldHiddenFlags(*dex_file));
705 }
706
TEST_F(HiddenApiTest,InstanceFieldTestApiMatch)707 TEST_F(HiddenApiTest, InstanceFieldTestApiMatch) {
708 ScratchFile dex, flags_csv;
709 OpenStream(flags_csv)
710 << "LMain;->ifield:LBadType1;,unsupported" << std::endl
711 << "LMain;->ifield:LBadType2;,max-target-o" << std::endl
712 << "LMain;->ifield:I,unsupported,test-api" << std::endl;
713 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
714 ASSERT_NE(dex_file.get(), nullptr);
715 ASSERT_EQ(hiddenapi::ApiList::TestApi()
716 | hiddenapi::ApiList::Unsupported(), GetIFieldHiddenFlags(*dex_file));
717 }
718
TEST_F(HiddenApiTest,InstanceFieldUnknownFlagMatch)719 TEST_F(HiddenApiTest, InstanceFieldUnknownFlagMatch) {
720 ScratchFile dex, flags_csv;
721 OpenStream(flags_csv)
722 << "LMain;->ifield:LBadType1;,unsupported" << std::endl
723 << "LMain;->ifield:LBadType2;,max-target-o" << std::endl
724 << "LMain;->ifield:I,unsupported,unknown-flag" << std::endl;
725 auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
726 ASSERT_EQ(dex_file.get(), nullptr);
727 }
728
TEST_F(HiddenApiTest,InstanceFieldMaxSdkHigherThanMaxHiddenApiLevel)729 TEST_F(HiddenApiTest, InstanceFieldMaxSdkHigherThanMaxHiddenApiLevel) {
730 ScratchFile dex, flags_csv;
731 OpenStream(flags_csv)
732 << "LMain;->ifield:I,max-target-r" << std::endl;
733 auto dex_file = RunHiddenapiEncode(flags_csv, {"--max-hiddenapi-level=max-target-q"}, dex);
734 ASSERT_EQ(dex_file.get(), nullptr);
735 }
736
TEST_F(HiddenApiTest,InstanceFieldMaxSdkEqualsMaxHiddenApiLevel)737 TEST_F(HiddenApiTest, InstanceFieldMaxSdkEqualsMaxHiddenApiLevel) {
738 ScratchFile dex, flags_csv;
739 OpenStream(flags_csv)
740 << "LMain;->ifield:I,max-target-r" << std::endl;
741 auto dex_file = RunHiddenapiEncode(flags_csv, {"--max-hiddenapi-level=max-target-r"}, dex);
742 ASSERT_NE(dex_file.get(), nullptr);
743 ASSERT_EQ(hiddenapi::ApiList::MaxTargetR(), GetIFieldHiddenFlags(*dex_file));
744 }
745
TEST_F(HiddenApiTest,InstanceFieldMaxSdkLowerThanMaxHiddenApiLevel)746 TEST_F(HiddenApiTest, InstanceFieldMaxSdkLowerThanMaxHiddenApiLevel) {
747 ScratchFile dex, flags_csv;
748 OpenStream(flags_csv)
749 << "LMain;->ifield:I,max-target-q" << std::endl;
750 auto dex_file = RunHiddenapiEncode(flags_csv, {"--max-hiddenapi-level=max-target-r"}, dex);
751 ASSERT_NE(dex_file.get(), nullptr);
752 ASSERT_EQ(hiddenapi::ApiList::MaxTargetQ(), GetIFieldHiddenFlags(*dex_file));
753 }
754
TEST_F(HiddenApiTest,InstanceFieldBlockedUnchangedByMaxHiddenApiLevel)755 TEST_F(HiddenApiTest, InstanceFieldBlockedUnchangedByMaxHiddenApiLevel) {
756 ScratchFile dex, flags_csv;
757 OpenStream(flags_csv)
758 << "LMain;->ifield:I,blocked" << std::endl;
759 auto dex_file = RunHiddenapiEncode(flags_csv, {"--max-hiddenapi-level=max-target-r"}, dex);
760 ASSERT_NE(dex_file.get(), nullptr);
761 ASSERT_EQ(hiddenapi::ApiList::Blocked(), GetIFieldHiddenFlags(*dex_file));
762 }
763
TEST_F(HiddenApiTest,InstanceFieldUnsupportedUnchangedByMaxHiddenApiLevel)764 TEST_F(HiddenApiTest, InstanceFieldUnsupportedUnchangedByMaxHiddenApiLevel) {
765 ScratchFile dex, flags_csv;
766 OpenStream(flags_csv)
767 << "LMain;->ifield:I,unsupported" << std::endl;
768 auto dex_file = RunHiddenapiEncode(flags_csv, {"--max-hiddenapi-level=max-target-r"}, dex);
769 ASSERT_NE(dex_file.get(), nullptr);
770 ASSERT_EQ(hiddenapi::ApiList::Unsupported(), GetIFieldHiddenFlags(*dex_file));
771 }
772
TEST_F(HiddenApiTest,InstanceFieldSdkUnchangedByMaxHiddenApiLevel)773 TEST_F(HiddenApiTest, InstanceFieldSdkUnchangedByMaxHiddenApiLevel) {
774 ScratchFile dex, flags_csv;
775 OpenStream(flags_csv)
776 << "LMain;->ifield:I,sdk" << std::endl;
777 auto dex_file = RunHiddenapiEncode(flags_csv, {"--max-hiddenapi-level=max-target-r"}, dex);
778 ASSERT_NE(dex_file.get(), nullptr);
779 ASSERT_EQ(hiddenapi::ApiList::Sdk(), GetIFieldHiddenFlags(*dex_file));
780 }
781
782 // The following tests use this class hierarchy:
783 //
784 // AbstractPackageClass PublicInterface
785 // | |
786 // | ┌----------------┘
787 // | |
788 // PackageClass
789 //
790 // Only PublicInterface is in stubs.
791
792 // Test a method declared in PublicInterface and defined in PackageClass.
TEST_F(HiddenApiTest,InterfaceMethodImplemented)793 TEST_F(HiddenApiTest, InterfaceMethodImplemented) {
794 ScratchFile flags_csv;
795 ASSERT_TRUE(RunHiddenapiList(flags_csv));
796 auto flags = ReadFlagsCsvFile(flags_csv);
797 ASSERT_EQ(SafeMapGet("LPackageClass;->publicMethod1()V", flags), "public-api");
798 }
799
800 // Test a method declared in PublicInterface, defined in AbstractPackageClass and
801 // inherited by PackageClass.
TEST_F(HiddenApiTest,InterfaceMethodImplementedInParent)802 TEST_F(HiddenApiTest, InterfaceMethodImplementedInParent) {
803 ScratchFile flags_csv;
804 ASSERT_TRUE(RunHiddenapiList(flags_csv));
805 auto flags = ReadFlagsCsvFile(flags_csv);
806 ASSERT_EQ(SafeMapGet("LAbstractPackageClass;->publicMethod2()V", flags), "public-api");
807 }
808
809 } // namespace art
810