xref: /aosp_15_r20/build/soong/java/hiddenapi_singleton.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2019 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage java
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"strings"
19*333d2b36SAndroid Build Coastguard Worker
20*333d2b36SAndroid Build Coastguard Worker	"android/soong/android"
21*333d2b36SAndroid Build Coastguard Worker)
22*333d2b36SAndroid Build Coastguard Worker
23*333d2b36SAndroid Build Coastguard Workerfunc init() {
24*333d2b36SAndroid Build Coastguard Worker	RegisterHiddenApiSingletonComponents(android.InitRegistrationContext)
25*333d2b36SAndroid Build Coastguard Worker}
26*333d2b36SAndroid Build Coastguard Worker
27*333d2b36SAndroid Build Coastguard Workerfunc RegisterHiddenApiSingletonComponents(ctx android.RegistrationContext) {
28*333d2b36SAndroid Build Coastguard Worker	ctx.RegisterParallelSingletonType("hiddenapi", hiddenAPISingletonFactory)
29*333d2b36SAndroid Build Coastguard Worker}
30*333d2b36SAndroid Build Coastguard Worker
31*333d2b36SAndroid Build Coastguard Workervar PrepareForTestWithHiddenApiBuildComponents = android.FixtureRegisterWithContext(RegisterHiddenApiSingletonComponents)
32*333d2b36SAndroid Build Coastguard Worker
33*333d2b36SAndroid Build Coastguard Workertype hiddenAPISingletonPathsStruct struct {
34*333d2b36SAndroid Build Coastguard Worker	// The path to the CSV file that contains the flags that will be encoded into the dex boot jars.
35*333d2b36SAndroid Build Coastguard Worker	//
36*333d2b36SAndroid Build Coastguard Worker	// It is created by the generate_hiddenapi_lists.py tool that is passed the stubFlags along with
37*333d2b36SAndroid Build Coastguard Worker	// a number of additional files that are used to augment the information in the stubFlags with
38*333d2b36SAndroid Build Coastguard Worker	// manually curated data.
39*333d2b36SAndroid Build Coastguard Worker	flags android.OutputPath
40*333d2b36SAndroid Build Coastguard Worker
41*333d2b36SAndroid Build Coastguard Worker	// The path to the CSV index file that contains mappings from Java signature to source location
42*333d2b36SAndroid Build Coastguard Worker	// information for all Java elements annotated with the UnsupportedAppUsage annotation in the
43*333d2b36SAndroid Build Coastguard Worker	// source of all the boot jars.
44*333d2b36SAndroid Build Coastguard Worker	//
45*333d2b36SAndroid Build Coastguard Worker	// It is created by the merge_csv tool which merges all the hiddenAPI.indexCSVPath files that have
46*333d2b36SAndroid Build Coastguard Worker	// been created by the rest of the build. That includes the index files generated for
47*333d2b36SAndroid Build Coastguard Worker	// <x>-hiddenapi modules.
48*333d2b36SAndroid Build Coastguard Worker	index android.OutputPath
49*333d2b36SAndroid Build Coastguard Worker
50*333d2b36SAndroid Build Coastguard Worker	// The path to the CSV metadata file that contains mappings from Java signature to the value of
51*333d2b36SAndroid Build Coastguard Worker	// properties specified on UnsupportedAppUsage annotations in the source of all the boot jars.
52*333d2b36SAndroid Build Coastguard Worker	//
53*333d2b36SAndroid Build Coastguard Worker	// It is created by the merge_csv tool which merges all the hiddenAPI.metadataCSVPath files that
54*333d2b36SAndroid Build Coastguard Worker	// have been created by the rest of the build. That includes the metadata files generated for
55*333d2b36SAndroid Build Coastguard Worker	// <x>-hiddenapi modules.
56*333d2b36SAndroid Build Coastguard Worker	metadata android.OutputPath
57*333d2b36SAndroid Build Coastguard Worker
58*333d2b36SAndroid Build Coastguard Worker	// The path to the CSV metadata file that contains mappings from Java signature to flags obtained
59*333d2b36SAndroid Build Coastguard Worker	// from the public, system and test API stubs.
60*333d2b36SAndroid Build Coastguard Worker	//
61*333d2b36SAndroid Build Coastguard Worker	// This is created by the hiddenapi tool which is given dex files for the public, system and test
62*333d2b36SAndroid Build Coastguard Worker	// API stubs (including product specific stubs) along with dex boot jars, so does not include
63*333d2b36SAndroid Build Coastguard Worker	// <x>-hiddenapi modules. For each API surface (i.e. public, system, test) it records which
64*333d2b36SAndroid Build Coastguard Worker	// members in the dex boot jars match a member in the dex stub jars for that API surface and then
65*333d2b36SAndroid Build Coastguard Worker	// outputs a file containing the signatures of all members in the dex boot jars along with the
66*333d2b36SAndroid Build Coastguard Worker	// flags that indicate which API surface it belongs, if any.
67*333d2b36SAndroid Build Coastguard Worker	//
68*333d2b36SAndroid Build Coastguard Worker	// e.g. a dex member that matches a member in the public dex stubs would have flags
69*333d2b36SAndroid Build Coastguard Worker	// "public-api,system-api,test-api" set (as system and test are both supersets of public). A dex
70*333d2b36SAndroid Build Coastguard Worker	// member that didn't match a member in any of the dex stubs is still output it just has an empty
71*333d2b36SAndroid Build Coastguard Worker	// set of flags.
72*333d2b36SAndroid Build Coastguard Worker	//
73*333d2b36SAndroid Build Coastguard Worker	// The notion of matching is quite complex, it is not restricted to just exact matching but also
74*333d2b36SAndroid Build Coastguard Worker	// follows the Java inheritance rules. e.g. if a method is public then all overriding/implementing
75*333d2b36SAndroid Build Coastguard Worker	// methods are also public. If an interface method is public and a class inherits an
76*333d2b36SAndroid Build Coastguard Worker	// implementation of that method from a super class then that super class method is also public.
77*333d2b36SAndroid Build Coastguard Worker	// That ensures that any method that can be called directly by an App through a public method is
78*333d2b36SAndroid Build Coastguard Worker	// visible to that App.
79*333d2b36SAndroid Build Coastguard Worker	//
80*333d2b36SAndroid Build Coastguard Worker	// Propagating the visibility of members across the inheritance hierarchy at build time will cause
81*333d2b36SAndroid Build Coastguard Worker	// problems when modularizing and unbundling as it that propagation can cross module boundaries.
82*333d2b36SAndroid Build Coastguard Worker	// e.g. Say that a private framework class implements a public interface and inherits an
83*333d2b36SAndroid Build Coastguard Worker	// implementation of one of its methods from a core platform ART class. In that case the ART
84*333d2b36SAndroid Build Coastguard Worker	// implementation method needs to be marked as public which requires the build to have access to
85*333d2b36SAndroid Build Coastguard Worker	// the framework implementation classes at build time. The work to rectify this is being tracked
86*333d2b36SAndroid Build Coastguard Worker	// at http://b/178693149.
87*333d2b36SAndroid Build Coastguard Worker	//
88*333d2b36SAndroid Build Coastguard Worker	// This file (or at least those items marked as being in the public-api) is used by hiddenapi when
89*333d2b36SAndroid Build Coastguard Worker	// creating the metadata and flags for the individual modules in order to perform consistency
90*333d2b36SAndroid Build Coastguard Worker	// checks and filter out bridge methods that are part of the public API. The latter relies on the
91*333d2b36SAndroid Build Coastguard Worker	// propagation of visibility across the inheritance hierarchy.
92*333d2b36SAndroid Build Coastguard Worker	stubFlags android.OutputPath
93*333d2b36SAndroid Build Coastguard Worker}
94*333d2b36SAndroid Build Coastguard Worker
95*333d2b36SAndroid Build Coastguard Workervar hiddenAPISingletonPathsKey = android.NewOnceKey("hiddenAPISingletonPathsKey")
96*333d2b36SAndroid Build Coastguard Worker
97*333d2b36SAndroid Build Coastguard Worker// hiddenAPISingletonPaths creates all the paths for singleton files the first time it is called, which may be
98*333d2b36SAndroid Build Coastguard Worker// from a ModuleContext that needs to reference a file that will be created by a singleton rule that hasn't
99*333d2b36SAndroid Build Coastguard Worker// yet been created.
100*333d2b36SAndroid Build Coastguard Workerfunc hiddenAPISingletonPaths(ctx android.PathContext) hiddenAPISingletonPathsStruct {
101*333d2b36SAndroid Build Coastguard Worker	return ctx.Config().Once(hiddenAPISingletonPathsKey, func() interface{} {
102*333d2b36SAndroid Build Coastguard Worker		// Make the paths relative to the out/soong/hiddenapi directory instead of to the out/soong/
103*333d2b36SAndroid Build Coastguard Worker		// directory. This ensures that if they are used as java_resources they do not end up in a
104*333d2b36SAndroid Build Coastguard Worker		// hiddenapi directory in the resulting APK.
105*333d2b36SAndroid Build Coastguard Worker		hiddenapiDir := android.PathForOutput(ctx, "hiddenapi")
106*333d2b36SAndroid Build Coastguard Worker		return hiddenAPISingletonPathsStruct{
107*333d2b36SAndroid Build Coastguard Worker			flags:     hiddenapiDir.Join(ctx, "hiddenapi-flags.csv"),
108*333d2b36SAndroid Build Coastguard Worker			index:     hiddenapiDir.Join(ctx, "hiddenapi-index.csv"),
109*333d2b36SAndroid Build Coastguard Worker			metadata:  hiddenapiDir.Join(ctx, "hiddenapi-unsupported.csv"),
110*333d2b36SAndroid Build Coastguard Worker			stubFlags: hiddenapiDir.Join(ctx, "hiddenapi-stub-flags.txt"),
111*333d2b36SAndroid Build Coastguard Worker		}
112*333d2b36SAndroid Build Coastguard Worker	}).(hiddenAPISingletonPathsStruct)
113*333d2b36SAndroid Build Coastguard Worker}
114*333d2b36SAndroid Build Coastguard Worker
115*333d2b36SAndroid Build Coastguard Workerfunc hiddenAPISingletonFactory() android.Singleton {
116*333d2b36SAndroid Build Coastguard Worker	return &hiddenAPISingleton{}
117*333d2b36SAndroid Build Coastguard Worker}
118*333d2b36SAndroid Build Coastguard Worker
119*333d2b36SAndroid Build Coastguard Workertype hiddenAPISingleton struct {
120*333d2b36SAndroid Build Coastguard Worker}
121*333d2b36SAndroid Build Coastguard Worker
122*333d2b36SAndroid Build Coastguard Worker// hiddenAPI singleton rules
123*333d2b36SAndroid Build Coastguard Workerfunc (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) {
124*333d2b36SAndroid Build Coastguard Worker	// Don't run any hiddenapi rules if hiddenapi checks are disabled
125*333d2b36SAndroid Build Coastguard Worker	if ctx.Config().DisableHiddenApiChecks() {
126*333d2b36SAndroid Build Coastguard Worker		return
127*333d2b36SAndroid Build Coastguard Worker	}
128*333d2b36SAndroid Build Coastguard Worker
129*333d2b36SAndroid Build Coastguard Worker	// If there is a prebuilt hiddenapi dir, generate rules to use the
130*333d2b36SAndroid Build Coastguard Worker	// files within. Generally, we build the hiddenapi files from source
131*333d2b36SAndroid Build Coastguard Worker	// during the build, ensuring consistency. It's possible, in a split
132*333d2b36SAndroid Build Coastguard Worker	// build (framework and vendor) scenario, for the vendor build to use
133*333d2b36SAndroid Build Coastguard Worker	// prebuilt hiddenapi files from the framework build. In this scenario,
134*333d2b36SAndroid Build Coastguard Worker	// the framework and vendor builds must use the same source to ensure
135*333d2b36SAndroid Build Coastguard Worker	// consistency.
136*333d2b36SAndroid Build Coastguard Worker
137*333d2b36SAndroid Build Coastguard Worker	if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" {
138*333d2b36SAndroid Build Coastguard Worker		prebuiltFlagsRule(ctx)
139*333d2b36SAndroid Build Coastguard Worker		prebuiltIndexRule(ctx)
140*333d2b36SAndroid Build Coastguard Worker		return
141*333d2b36SAndroid Build Coastguard Worker	}
142*333d2b36SAndroid Build Coastguard Worker}
143*333d2b36SAndroid Build Coastguard Worker
144*333d2b36SAndroid Build Coastguard Worker// Checks to see whether the supplied module variant is in the list of boot jars.
145*333d2b36SAndroid Build Coastguard Worker//
146*333d2b36SAndroid Build Coastguard Worker// TODO(b/179354495): Avoid having to perform this type of check.
147*333d2b36SAndroid Build Coastguard Workerfunc isModuleInConfiguredList(ctx android.BaseModuleContext, module android.Module, configuredBootJars android.ConfiguredJarList) bool {
148*333d2b36SAndroid Build Coastguard Worker	name := ctx.OtherModuleName(module)
149*333d2b36SAndroid Build Coastguard Worker
150*333d2b36SAndroid Build Coastguard Worker	// Strip a prebuilt_ prefix so that this can match a prebuilt module that has not been renamed.
151*333d2b36SAndroid Build Coastguard Worker	name = android.RemoveOptionalPrebuiltPrefix(name)
152*333d2b36SAndroid Build Coastguard Worker
153*333d2b36SAndroid Build Coastguard Worker	// Strip the ".impl" suffix, so that the implementation library of the java_sdk_library is
154*333d2b36SAndroid Build Coastguard Worker	// treated identical to the top level java_sdk_library.
155*333d2b36SAndroid Build Coastguard Worker	name = strings.TrimSuffix(name, ".impl")
156*333d2b36SAndroid Build Coastguard Worker
157*333d2b36SAndroid Build Coastguard Worker	// Ignore any module that is not listed in the boot image configuration.
158*333d2b36SAndroid Build Coastguard Worker	index := configuredBootJars.IndexOfJar(name)
159*333d2b36SAndroid Build Coastguard Worker	if index == -1 {
160*333d2b36SAndroid Build Coastguard Worker		return false
161*333d2b36SAndroid Build Coastguard Worker	}
162*333d2b36SAndroid Build Coastguard Worker
163*333d2b36SAndroid Build Coastguard Worker	// It is an error if the module is not an ApexModule.
164*333d2b36SAndroid Build Coastguard Worker	if _, ok := module.(android.ApexModule); !ok {
165*333d2b36SAndroid Build Coastguard Worker		ctx.ModuleErrorf("%s is configured in boot jars but does not support being added to an apex", ctx.OtherModuleName(module))
166*333d2b36SAndroid Build Coastguard Worker		return false
167*333d2b36SAndroid Build Coastguard Worker	}
168*333d2b36SAndroid Build Coastguard Worker
169*333d2b36SAndroid Build Coastguard Worker	apexInfo, _ := android.OtherModuleProvider(ctx, module, android.ApexInfoProvider)
170*333d2b36SAndroid Build Coastguard Worker
171*333d2b36SAndroid Build Coastguard Worker	// Now match the apex part of the boot image configuration.
172*333d2b36SAndroid Build Coastguard Worker	requiredApex := configuredBootJars.Apex(index)
173*333d2b36SAndroid Build Coastguard Worker	if android.IsConfiguredJarForPlatform(requiredApex) {
174*333d2b36SAndroid Build Coastguard Worker		if len(apexInfo.InApexVariants) != 0 {
175*333d2b36SAndroid Build Coastguard Worker			// A platform variant is required but this is for an apex so ignore it.
176*333d2b36SAndroid Build Coastguard Worker			return false
177*333d2b36SAndroid Build Coastguard Worker		}
178*333d2b36SAndroid Build Coastguard Worker	} else if !apexInfo.InApexVariant(requiredApex) {
179*333d2b36SAndroid Build Coastguard Worker		// An apex variant for a specific apex is required but this is the wrong apex.
180*333d2b36SAndroid Build Coastguard Worker		return false
181*333d2b36SAndroid Build Coastguard Worker	}
182*333d2b36SAndroid Build Coastguard Worker
183*333d2b36SAndroid Build Coastguard Worker	return true
184*333d2b36SAndroid Build Coastguard Worker}
185*333d2b36SAndroid Build Coastguard Worker
186*333d2b36SAndroid Build Coastguard Workerfunc prebuiltFlagsRule(ctx android.SingletonContext) {
187*333d2b36SAndroid Build Coastguard Worker	outputPath := hiddenAPISingletonPaths(ctx).flags
188*333d2b36SAndroid Build Coastguard Worker	inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-flags.csv")
189*333d2b36SAndroid Build Coastguard Worker
190*333d2b36SAndroid Build Coastguard Worker	ctx.Build(pctx, android.BuildParams{
191*333d2b36SAndroid Build Coastguard Worker		Rule:   android.Cp,
192*333d2b36SAndroid Build Coastguard Worker		Output: outputPath,
193*333d2b36SAndroid Build Coastguard Worker		Input:  inputPath,
194*333d2b36SAndroid Build Coastguard Worker	})
195*333d2b36SAndroid Build Coastguard Worker}
196*333d2b36SAndroid Build Coastguard Worker
197*333d2b36SAndroid Build Coastguard Workerfunc prebuiltIndexRule(ctx android.SingletonContext) {
198*333d2b36SAndroid Build Coastguard Worker	outputPath := hiddenAPISingletonPaths(ctx).index
199*333d2b36SAndroid Build Coastguard Worker	inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-index.csv")
200*333d2b36SAndroid Build Coastguard Worker
201*333d2b36SAndroid Build Coastguard Worker	ctx.Build(pctx, android.BuildParams{
202*333d2b36SAndroid Build Coastguard Worker		Rule:   android.Cp,
203*333d2b36SAndroid Build Coastguard Worker		Output: outputPath,
204*333d2b36SAndroid Build Coastguard Worker		Input:  inputPath,
205*333d2b36SAndroid Build Coastguard Worker	})
206*333d2b36SAndroid Build Coastguard Worker}
207*333d2b36SAndroid Build Coastguard Worker
208*333d2b36SAndroid Build Coastguard Worker// tempPathForRestat creates a path of the same type as the supplied type but with a name of
209*333d2b36SAndroid Build Coastguard Worker// <path>.tmp.
210*333d2b36SAndroid Build Coastguard Worker//
211*333d2b36SAndroid Build Coastguard Worker// e.g. If path is an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv then this will return
212*333d2b36SAndroid Build Coastguard Worker// an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv.tmp
213*333d2b36SAndroid Build Coastguard Workerfunc tempPathForRestat(ctx android.PathContext, path android.WritablePath) android.WritablePath {
214*333d2b36SAndroid Build Coastguard Worker	extWithoutLeadingDot := strings.TrimPrefix(path.Ext(), ".")
215*333d2b36SAndroid Build Coastguard Worker	return path.ReplaceExtension(ctx, extWithoutLeadingDot+".tmp")
216*333d2b36SAndroid Build Coastguard Worker}
217*333d2b36SAndroid Build Coastguard Worker
218*333d2b36SAndroid Build Coastguard Worker// commitChangeForRestat adds a command to a rule that updates outputPath from tempPath if they are different.  It
219*333d2b36SAndroid Build Coastguard Worker// also marks the rule as restat and marks the tempPath as a temporary file that should not be considered an output of
220*333d2b36SAndroid Build Coastguard Worker// the rule.
221*333d2b36SAndroid Build Coastguard Workerfunc commitChangeForRestat(rule *android.RuleBuilder, tempPath, outputPath android.WritablePath) {
222*333d2b36SAndroid Build Coastguard Worker	rule.Restat()
223*333d2b36SAndroid Build Coastguard Worker	rule.Temporary(tempPath)
224*333d2b36SAndroid Build Coastguard Worker	rule.Command().
225*333d2b36SAndroid Build Coastguard Worker		Text("(").
226*333d2b36SAndroid Build Coastguard Worker		Text("if").
227*333d2b36SAndroid Build Coastguard Worker		Text("cmp -s").Input(tempPath).Output(outputPath).Text(";").
228*333d2b36SAndroid Build Coastguard Worker		Text("then").
229*333d2b36SAndroid Build Coastguard Worker		Text("rm").Input(tempPath).Text(";").
230*333d2b36SAndroid Build Coastguard Worker		Text("else").
231*333d2b36SAndroid Build Coastguard Worker		Text("mv").Input(tempPath).Output(outputPath).Text(";").
232*333d2b36SAndroid Build Coastguard Worker		Text("fi").
233*333d2b36SAndroid Build Coastguard Worker		Text(")")
234*333d2b36SAndroid Build Coastguard Worker}
235