1 /*
2  * Copyright (C) 2023 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 package com.android.hoststubgen.filters
17 
18 import com.android.hoststubgen.asm.ClassNodes
19 
20 /**
21  * Filter that deals with Android specific heuristics.
22  */
23 class AndroidHeuristicsFilter(
24         private val classes: ClassNodes,
25         val aidlPolicy: FilterPolicyWithReason?,
26         val featureFlagsPolicy: FilterPolicyWithReason?,
27         val syspropsPolicy: FilterPolicyWithReason?,
28         val rFilePolicy: FilterPolicyWithReason?,
29         fallback: OutputFilter
30 ) : DelegatingFilter(fallback) {
getPolicyForClassnull31     override fun getPolicyForClass(className: String): FilterPolicyWithReason {
32         if (aidlPolicy != null && classes.isAidlClass(className)) {
33             return aidlPolicy
34         }
35         if (featureFlagsPolicy != null && classes.isFeatureFlagsClass(className)) {
36             return featureFlagsPolicy
37         }
38         if (syspropsPolicy != null && classes.isSyspropsClass(className)) {
39             return syspropsPolicy
40         }
41         if (rFilePolicy != null && classes.isRClass(className)) {
42             return rFilePolicy
43         }
44         return super.getPolicyForClass(className)
45     }
46 }
47 
48 /**
49  * @return if a given class "seems like" an AIDL (top-level) class.
50  */
ClassNodesnull51 private fun ClassNodes.isAidlClass(className: String): Boolean {
52     return hasClass(className) &&
53             hasClass("$className\$Stub") &&
54             hasClass("$className\$Stub\$Proxy")
55 }
56 
57 /**
58  * Effectively apply @RavenwoodKeepWholeClass to all classes with these names
59  *
60  * @return if a given class "seems like" an feature flags class.
61  */
isFeatureFlagsClassnull62 private fun ClassNodes.isFeatureFlagsClass(className: String): Boolean {
63     // Matches template classes defined here:
64     // https://cs.android.com/android/platform/superproject/+/master:build/make/tools/aconfig/templates/
65     return className.endsWith("/Flags")
66             || className.endsWith("/FeatureFlags")
67             || className.endsWith("/FeatureFlagsImpl")
68             || className.endsWith("/CustomFeatureFlags")
69             || className.endsWith("/FakeFeatureFlagsImpl");
70 }
71 
72 /**
73  * @return if a given class "seems like" a sysprops class.
74  */
ClassNodesnull75 private fun ClassNodes.isSyspropsClass(className: String): Boolean {
76     // Matches template classes defined here:
77     // https://cs.android.com/android/platform/superproject/main/+/main:system/tools/sysprop/
78     return className.startsWith("android/sysprop/")
79             && className.endsWith("Properties")
80 }
81 
82 /**
83  * @return if a given class "seems like" an R class or its nested classes.
84  */
isRClassnull85 private fun ClassNodes.isRClass(className: String): Boolean {
86     return className.endsWith("/R") || className.contains("/R$")
87 }
88