• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 package android.signature.cts.api;
18 
19 import java.util.function.Predicate;
20 
21 import android.os.Bundle;
22 import android.provider.Settings;
23 import android.signature.cts.DexField;
24 import android.signature.cts.DexMember;
25 import android.signature.cts.DexMemberChecker;
26 import android.signature.cts.DexMethod;
27 import android.signature.cts.FailureType;
28 import repackaged.android.test.InstrumentationTestRunner;
29 
30 public abstract class BaseKillswitchTest extends AbstractApiTest {
31 
32     protected String mErrorMessageAppendix;
33 
34     @Override
setUp()35     protected void setUp() throws Exception {
36         super.setUp();
37         DexMemberChecker.init();
38     }
39 
getGlobalExemptions()40     protected String getGlobalExemptions() {
41       return Settings.Global.getString(
42           getInstrumentation().getContext().getContentResolver(),
43           Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS);
44     }
45 
46     // We have four methods to split up the load, keeping individual test runs small.
47     // Tests shared by all the subclasses.
48 
49     private final static Predicate<DexMember> METHOD_FILTER =
50             dexMember -> (dexMember instanceof DexMethod);
51 
52     private final static Predicate<DexMember> FIELD_FILTER =
53             dexMember -> (dexMember instanceof DexField);
54 
testKillswitchMechanismMethodsThroughReflection()55     public void testKillswitchMechanismMethodsThroughReflection() {
56         doTestKillswitchMechanism(METHOD_FILTER, /* reflection= */ true, /* jni= */ false);
57     }
58 
testKillswitchMechanismMethodsThroughJni()59     public void testKillswitchMechanismMethodsThroughJni() {
60         doTestKillswitchMechanism(METHOD_FILTER, /* reflection= */ false, /* jni= */ true);
61     }
62 
testKillswitchMechanismFieldsThroughReflection()63     public void testKillswitchMechanismFieldsThroughReflection() {
64         doTestKillswitchMechanism(FIELD_FILTER, /* reflection= */ true, /* jni= */ false);
65     }
66 
testKillswitchMechanismFieldsThroughJni()67     public void testKillswitchMechanismFieldsThroughJni() {
68         doTestKillswitchMechanism(FIELD_FILTER, /* reflection= */ false, /* jni= */ true);
69     }
70 
doTestKillswitchMechanism(Predicate<DexMember> memberFilter, boolean reflection, boolean jni)71     private void doTestKillswitchMechanism(Predicate<DexMember> memberFilter, boolean reflection,
72             boolean jni) {
73         runWithTestResultObserver(resultObserver -> {
74             DexMemberChecker.Observer observer = new DexMemberChecker.Observer() {
75                 @Override
76                 public void classAccessible(boolean accessible, DexMember member) {
77                     if (!accessible) {
78                         resultObserver.notifyFailure(
79                                 FailureType.MISSING_CLASS,
80                                 member.toString(),
81                                 "Class from boot classpath is not accessible"
82                                         + mErrorMessageAppendix);
83                     }
84                 }
85 
86                 @Override
87                 public void fieldAccessibleViaReflection(boolean accessible, DexField field) {
88                     if (!accessible) {
89                         resultObserver.notifyFailure(
90                                 FailureType.MISSING_FIELD,
91                                 field.toString(),
92                                 "Field from boot classpath is not accessible via reflection"
93                                         + mErrorMessageAppendix);
94                     }
95                 }
96 
97                 @Override
98                 public void fieldAccessibleViaJni(boolean accessible, DexField field) {
99                     if (!accessible) {
100                         resultObserver.notifyFailure(
101                                 FailureType.MISSING_FIELD,
102                                 field.toString(),
103                                 "Field from boot classpath is not accessible via JNI"
104                                         + mErrorMessageAppendix);
105                     }
106                 }
107 
108                 @Override
109                 public void methodAccessibleViaReflection(boolean accessible, DexMethod method) {
110                     if (method.isStaticConstructor()) {
111                         // Skip static constructors. They cannot be discovered with reflection.
112                         return;
113                     }
114 
115                     if (!accessible) {
116                         resultObserver.notifyFailure(
117                                 FailureType.MISSING_METHOD,
118                                 method.toString(),
119                                 "Method from boot classpath is not accessible via reflection"
120                                         + mErrorMessageAppendix);
121                     }
122                 }
123 
124                 @Override
125                 public void methodAccessibleViaJni(boolean accessible, DexMethod method) {
126                     if (!accessible) {
127                         resultObserver.notifyFailure(
128                                 FailureType.MISSING_METHOD,
129                                 method.toString(),
130                                 "Method from boot classpath is not accessible via JNI"
131                                         + mErrorMessageAppendix);
132                     }
133                 }
134 
135             };
136             classProvider.getAllClasses().forEach(klass -> {
137                 classProvider.getAllMembers(klass)
138                         .filter(memberFilter)
139                         .forEach(member -> {
140                             DexMemberChecker.checkSingleMember(member, reflection, jni, observer);
141                         });
142             });
143         });
144     }
145 }
146