• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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