1 /*
2 * Copyright (C) 2025 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
17
18 import com.android.hoststubgen.filters.FilterPolicy
19 import com.android.hoststubgen.utils.ArgIterator
20 import com.android.hoststubgen.utils.BaseOptions
21 import com.android.hoststubgen.utils.FileOrResource
22 import com.android.hoststubgen.utils.SetOnce
23
parsePackageRedirectnull24 private fun parsePackageRedirect(fromColonTo: String): Pair<String, String> {
25 val colon = fromColonTo.indexOf(':')
26 if ((colon < 1) || (colon + 1 >= fromColonTo.length)) {
27 throw ArgumentsException("--package-redirect must be a colon-separated string")
28 }
29 // TODO check for duplicates
30 return Pair(fromColonTo.substring(0, colon), fromColonTo.substring(colon + 1))
31 }
32
33 /**
34 * Options to configure [HostStubGenClassProcessor].
35 */
36 open class HostStubGenClassProcessorOptions(
37 var keepAnnotations: MutableSet<String> = mutableSetOf(),
38 var throwAnnotations: MutableSet<String> = mutableSetOf(),
39 var removeAnnotations: MutableSet<String> = mutableSetOf(),
40 var ignoreAnnotations: MutableSet<String> = mutableSetOf(),
41 var keepClassAnnotations: MutableSet<String> = mutableSetOf(),
42 var partiallyAllowedAnnotations: MutableSet<String> = mutableSetOf(),
43 var redirectAnnotations: MutableSet<String> = mutableSetOf(),
44
45 var substituteAnnotations: MutableSet<String> = mutableSetOf(),
46 var redirectionClassAnnotations: MutableSet<String> = mutableSetOf(),
47 var classLoadHookAnnotations: MutableSet<String> = mutableSetOf(),
48 var keepStaticInitializerAnnotations: MutableSet<String> = mutableSetOf(),
49
50 var packageRedirects: MutableList<Pair<String, String>> = mutableListOf(),
51
52 var annotationAllowedClassesFile: SetOnce<String?> = SetOnce(null),
53
54 var defaultClassLoadHook: SetOnce<String?> = SetOnce(null),
55 var defaultMethodCallHook: SetOnce<String?> = SetOnce(null),
56
57 var policyOverrideFiles: MutableList<FileOrResource> = mutableListOf(),
58
59 var defaultPolicy: SetOnce<FilterPolicy> = SetOnce(FilterPolicy.Remove),
60
61 var deleteFinals: SetOnce<Boolean> = SetOnce(false),
62
63 var enableClassChecker: SetOnce<Boolean> = SetOnce(false),
64 var enablePreTrace: SetOnce<Boolean> = SetOnce(false),
65 var enablePostTrace: SetOnce<Boolean> = SetOnce(false),
66 ) : BaseOptions() {
67
68 private val allAnnotations = mutableSetOf<String>()
69
ensureUniqueAnnotationnull70 private fun ensureUniqueAnnotation(name: String): String {
71 if (!allAnnotations.add(name)) {
72 throw DuplicateAnnotationException(name)
73 }
74 return name
75 }
76
parseOptionnull77 override fun parseOption(option: String, args: ArgIterator): Boolean {
78 // Define some shorthands...
79 fun nextArg(): String = args.nextArgRequired(option)
80 fun MutableSet<String>.addUniqueAnnotationArg(): String =
81 nextArg().also { this += ensureUniqueAnnotation(it) }
82
83 when (option) {
84 "--policy-override-file" -> policyOverrideFiles.add(FileOrResource(nextArg()))
85
86 "--default-remove" -> defaultPolicy.set(FilterPolicy.Remove)
87 "--default-throw" -> defaultPolicy.set(FilterPolicy.Throw)
88 "--default-keep" -> defaultPolicy.set(FilterPolicy.Keep)
89
90 "--keep-annotation" ->
91 keepAnnotations.addUniqueAnnotationArg()
92
93 "--keep-class-annotation" ->
94 keepClassAnnotations.addUniqueAnnotationArg()
95
96 "--partially-allowed-annotation" ->
97 partiallyAllowedAnnotations.addUniqueAnnotationArg()
98
99 "--throw-annotation" ->
100 throwAnnotations.addUniqueAnnotationArg()
101
102 "--remove-annotation" ->
103 removeAnnotations.addUniqueAnnotationArg()
104
105 "--ignore-annotation" ->
106 ignoreAnnotations.addUniqueAnnotationArg()
107
108 "--substitute-annotation" ->
109 substituteAnnotations.addUniqueAnnotationArg()
110
111 "--redirect-annotation" ->
112 redirectAnnotations.addUniqueAnnotationArg()
113
114 "--redirection-class-annotation" ->
115 redirectionClassAnnotations.addUniqueAnnotationArg()
116
117 "--class-load-hook-annotation" ->
118 classLoadHookAnnotations.addUniqueAnnotationArg()
119
120 "--keep-static-initializer-annotation" ->
121 keepStaticInitializerAnnotations.addUniqueAnnotationArg()
122
123 "--package-redirect" ->
124 packageRedirects += parsePackageRedirect(nextArg())
125
126 "--annotation-allowed-classes-file" ->
127 annotationAllowedClassesFile.set(nextArg())
128
129 "--default-class-load-hook" ->
130 defaultClassLoadHook.set(nextArg())
131
132 "--default-method-call-hook" ->
133 defaultMethodCallHook.set(nextArg())
134
135 "--delete-finals" -> deleteFinals.set(true)
136
137 // Following options are for debugging.
138 "--enable-class-checker" -> enableClassChecker.set(true)
139 "--no-class-checker" -> enableClassChecker.set(false)
140
141 "--enable-pre-trace" -> enablePreTrace.set(true)
142 "--no-pre-trace" -> enablePreTrace.set(false)
143
144 "--enable-post-trace" -> enablePostTrace.set(true)
145 "--no-post-trace" -> enablePostTrace.set(false)
146
147 else -> return false
148 }
149
150 return true
151 }
152
dumpFieldsnull153 override fun dumpFields(): String {
154 return """
155 keepAnnotations=$keepAnnotations,
156 throwAnnotations=$throwAnnotations,
157 removeAnnotations=$removeAnnotations,
158 ignoreAnnotations=$ignoreAnnotations,
159 keepClassAnnotations=$keepClassAnnotations,
160 partiallyAllowedAnnotations=$partiallyAllowedAnnotations,
161 substituteAnnotations=$substituteAnnotations,
162 nativeSubstituteAnnotations=$redirectionClassAnnotations,
163 classLoadHookAnnotations=$classLoadHookAnnotations,
164 keepStaticInitializerAnnotations=$keepStaticInitializerAnnotations,
165 packageRedirects=$packageRedirects,
166 annotationAllowedClassesFile=$annotationAllowedClassesFile,
167 defaultClassLoadHook=$defaultClassLoadHook,
168 defaultMethodCallHook=$defaultMethodCallHook,
169 policyOverrideFiles=${policyOverrideFiles.toTypedArray().contentToString()},
170 defaultPolicy=$defaultPolicy,
171 deleteFinals=$deleteFinals,
172 enableClassChecker=$enableClassChecker,
173 enablePreTrace=$enablePreTrace,
174 enablePostTrace=$enablePostTrace,
175 """.trimIndent()
176 }
177 }
178