xref: /aosp_15_r20/build/soong/android/deapexer.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright (C) 2021 The Android Open Source Project
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 android
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	"github.com/google/blueprint"
21*333d2b36SAndroid Build Coastguard Worker)
22*333d2b36SAndroid Build Coastguard Worker
23*333d2b36SAndroid Build Coastguard Worker// Provides support for interacting with the `deapexer` module to which a `prebuilt_apex` module
24*333d2b36SAndroid Build Coastguard Worker// will delegate the work to export files from a prebuilt '.apex` file.
25*333d2b36SAndroid Build Coastguard Worker//
26*333d2b36SAndroid Build Coastguard Worker// The actual processing that is done is quite convoluted but it is all about combining information
27*333d2b36SAndroid Build Coastguard Worker// from multiple different sources in order to allow a prebuilt module to use a file extracted from
28*333d2b36SAndroid Build Coastguard Worker// an apex file. As follows:
29*333d2b36SAndroid Build Coastguard Worker//
30*333d2b36SAndroid Build Coastguard Worker// 1. A prebuilt module, e.g. prebuilt_bootclasspath_fragment or java_import needs to use a file
31*333d2b36SAndroid Build Coastguard Worker//    from a prebuilt_apex/apex_set. It knows the path of the file within the apex but does not know
32*333d2b36SAndroid Build Coastguard Worker//    where the apex file is or what apex to use.
33*333d2b36SAndroid Build Coastguard Worker//
34*333d2b36SAndroid Build Coastguard Worker// 2. The connection between the prebuilt module and the prebuilt_apex/apex_set is created through
35*333d2b36SAndroid Build Coastguard Worker//    use of an exported_... property on the latter. That causes four things to occur:
36*333d2b36SAndroid Build Coastguard Worker//    a. A `deapexer` mopdule is created by the prebuilt_apex/apex_set to extract files from the
37*333d2b36SAndroid Build Coastguard Worker//       apex file.
38*333d2b36SAndroid Build Coastguard Worker//    b. A dependency is added from the prebuilt_apex/apex_set modules onto the prebuilt modules
39*333d2b36SAndroid Build Coastguard Worker//       listed in those properties.
40*333d2b36SAndroid Build Coastguard Worker//    c. An APEX variant is created for each of those prebuilt modules.
41*333d2b36SAndroid Build Coastguard Worker//    d. A dependency is added from the prebuilt modules to the `deapexer` module.
42*333d2b36SAndroid Build Coastguard Worker//
43*333d2b36SAndroid Build Coastguard Worker// 3. The prebuilt_apex/apex_set modules do not know which files are available in the apex file.
44*333d2b36SAndroid Build Coastguard Worker//    That information could be specified on the prebuilt_apex/apex_set modules but without
45*333d2b36SAndroid Build Coastguard Worker//    automated generation of those modules it would be expensive to maintain. So, instead they
46*333d2b36SAndroid Build Coastguard Worker//    obtain that information from the prebuilt modules. They do not know what files are actually in
47*333d2b36SAndroid Build Coastguard Worker//    the apex file either but they know what files they need from it. So, the
48*333d2b36SAndroid Build Coastguard Worker//    prebuilt_apex/apex_set modules obtain the files that should be in the apex file from those
49*333d2b36SAndroid Build Coastguard Worker//    modules and then pass those onto the `deapexer` module.
50*333d2b36SAndroid Build Coastguard Worker//
51*333d2b36SAndroid Build Coastguard Worker// 4. The `deapexer` module's ninja rule extracts all the files from the apex file into an output
52*333d2b36SAndroid Build Coastguard Worker//    directory and checks that all the expected files are there. The expected files are declared as
53*333d2b36SAndroid Build Coastguard Worker//    the outputs of the ninja rule so they are available to other modules.
54*333d2b36SAndroid Build Coastguard Worker//
55*333d2b36SAndroid Build Coastguard Worker// 5. The prebuilt modules then retrieve the paths to the files that they needed from the `deapexer`
56*333d2b36SAndroid Build Coastguard Worker//    module.
57*333d2b36SAndroid Build Coastguard Worker//
58*333d2b36SAndroid Build Coastguard Worker// The files that are passed to `deapexer` and those that are passed back have a unique identifier
59*333d2b36SAndroid Build Coastguard Worker// that links them together. e.g. If the `deapexer` is passed something like this:
60*333d2b36SAndroid Build Coastguard Worker//     javalib/core-libart.jar -> javalib/core-libart.jar
61*333d2b36SAndroid Build Coastguard Worker// it will return something like this:
62*333d2b36SAndroid Build Coastguard Worker//     javalib/core-libart.jar -> out/soong/.....deapexer.../javalib/core-libart.jar
63*333d2b36SAndroid Build Coastguard Worker//
64*333d2b36SAndroid Build Coastguard Worker// The reason why the `deapexer` module is separate from the prebuilt_apex/apex_set is to avoid
65*333d2b36SAndroid Build Coastguard Worker// cycles. e.g.
66*333d2b36SAndroid Build Coastguard Worker//   prebuilt_apex "com.android.art" depends upon java_import "core-libart":
67*333d2b36SAndroid Build Coastguard Worker//       This is so it can create an APEX variant of the latter and obtain information about the
68*333d2b36SAndroid Build Coastguard Worker//       files that it needs from the apex file.
69*333d2b36SAndroid Build Coastguard Worker//   java_import "core-libart" depends upon `deapexer` module:
70*333d2b36SAndroid Build Coastguard Worker//       This is so it can retrieve the paths to the files it needs.
71*333d2b36SAndroid Build Coastguard Worker
72*333d2b36SAndroid Build Coastguard Worker// The information exported by the `deapexer` module, access it using `DeapxerInfoProvider`.
73*333d2b36SAndroid Build Coastguard Workertype DeapexerInfo struct {
74*333d2b36SAndroid Build Coastguard Worker	apexModuleName string
75*333d2b36SAndroid Build Coastguard Worker
76*333d2b36SAndroid Build Coastguard Worker	// map from the name of an exported file from a prebuilt_apex to the path to that file. The
77*333d2b36SAndroid Build Coastguard Worker	// exported file name is the apex relative path, e.g. javalib/core-libart.jar.
78*333d2b36SAndroid Build Coastguard Worker	//
79*333d2b36SAndroid Build Coastguard Worker	// See Prebuilt.ApexInfoMutator for more information.
80*333d2b36SAndroid Build Coastguard Worker	exports map[string]WritablePath
81*333d2b36SAndroid Build Coastguard Worker
82*333d2b36SAndroid Build Coastguard Worker	// name of the java libraries exported from the apex
83*333d2b36SAndroid Build Coastguard Worker	// e.g. core-libart
84*333d2b36SAndroid Build Coastguard Worker	exportedModuleNames []string
85*333d2b36SAndroid Build Coastguard Worker
86*333d2b36SAndroid Build Coastguard Worker	// name of the java libraries exported from the apex that should be dexpreopt'd with the .prof
87*333d2b36SAndroid Build Coastguard Worker	// file embedded in the apex
88*333d2b36SAndroid Build Coastguard Worker	dexpreoptProfileGuidedExportedModuleNames []string
89*333d2b36SAndroid Build Coastguard Worker}
90*333d2b36SAndroid Build Coastguard Worker
91*333d2b36SAndroid Build Coastguard Worker// ApexModuleName returns the name of the APEX module that provided the info.
92*333d2b36SAndroid Build Coastguard Workerfunc (i DeapexerInfo) ApexModuleName() string {
93*333d2b36SAndroid Build Coastguard Worker	return i.apexModuleName
94*333d2b36SAndroid Build Coastguard Worker}
95*333d2b36SAndroid Build Coastguard Worker
96*333d2b36SAndroid Build Coastguard Worker// PrebuiltExportPath provides the path, or nil if not available, of a file exported from the
97*333d2b36SAndroid Build Coastguard Worker// prebuilt_apex that created this ApexInfo.
98*333d2b36SAndroid Build Coastguard Worker//
99*333d2b36SAndroid Build Coastguard Worker// The exported file is identified by the apex relative path, e.g. "javalib/core-libart.jar".
100*333d2b36SAndroid Build Coastguard Worker//
101*333d2b36SAndroid Build Coastguard Worker// See apex/deapexer.go for more information.
102*333d2b36SAndroid Build Coastguard Workerfunc (i DeapexerInfo) PrebuiltExportPath(apexRelativePath string) WritablePath {
103*333d2b36SAndroid Build Coastguard Worker	path := i.exports[apexRelativePath]
104*333d2b36SAndroid Build Coastguard Worker	return path
105*333d2b36SAndroid Build Coastguard Worker}
106*333d2b36SAndroid Build Coastguard Worker
107*333d2b36SAndroid Build Coastguard Workerfunc (i DeapexerInfo) GetExportedModuleNames() []string {
108*333d2b36SAndroid Build Coastguard Worker	return i.exportedModuleNames
109*333d2b36SAndroid Build Coastguard Worker}
110*333d2b36SAndroid Build Coastguard Worker
111*333d2b36SAndroid Build Coastguard Worker// NewDeapexerInfo creates and initializes a DeapexerInfo that is suitable
112*333d2b36SAndroid Build Coastguard Worker// for use with a prebuilt_apex module.
113*333d2b36SAndroid Build Coastguard Worker//
114*333d2b36SAndroid Build Coastguard Worker// See apex/deapexer.go for more information.
115*333d2b36SAndroid Build Coastguard Workerfunc NewDeapexerInfo(apexModuleName string, exports map[string]WritablePath, moduleNames []string) DeapexerInfo {
116*333d2b36SAndroid Build Coastguard Worker	return DeapexerInfo{
117*333d2b36SAndroid Build Coastguard Worker		apexModuleName:      apexModuleName,
118*333d2b36SAndroid Build Coastguard Worker		exports:             exports,
119*333d2b36SAndroid Build Coastguard Worker		exportedModuleNames: moduleNames,
120*333d2b36SAndroid Build Coastguard Worker	}
121*333d2b36SAndroid Build Coastguard Worker}
122*333d2b36SAndroid Build Coastguard Worker
123*333d2b36SAndroid Build Coastguard Workerfunc (i *DeapexerInfo) GetDexpreoptProfileGuidedExportedModuleNames() []string {
124*333d2b36SAndroid Build Coastguard Worker	return i.dexpreoptProfileGuidedExportedModuleNames
125*333d2b36SAndroid Build Coastguard Worker}
126*333d2b36SAndroid Build Coastguard Worker
127*333d2b36SAndroid Build Coastguard Workerfunc (i *DeapexerInfo) AddDexpreoptProfileGuidedExportedModuleNames(names ...string) {
128*333d2b36SAndroid Build Coastguard Worker	i.dexpreoptProfileGuidedExportedModuleNames = append(i.dexpreoptProfileGuidedExportedModuleNames, names...)
129*333d2b36SAndroid Build Coastguard Worker}
130*333d2b36SAndroid Build Coastguard Worker
131*333d2b36SAndroid Build Coastguard Workertype deapexerTagStruct struct {
132*333d2b36SAndroid Build Coastguard Worker	blueprint.BaseDependencyTag
133*333d2b36SAndroid Build Coastguard Worker}
134*333d2b36SAndroid Build Coastguard Worker
135*333d2b36SAndroid Build Coastguard Worker// Mark this tag so dependencies that use it are excluded from APEX contents.
136*333d2b36SAndroid Build Coastguard Workerfunc (t deapexerTagStruct) ExcludeFromApexContents() {}
137*333d2b36SAndroid Build Coastguard Worker
138*333d2b36SAndroid Build Coastguard Workervar _ ExcludeFromApexContentsTag = DeapexerTag
139*333d2b36SAndroid Build Coastguard Worker
140*333d2b36SAndroid Build Coastguard Worker// A tag that is used for dependencies on the `deapexer` module.
141*333d2b36SAndroid Build Coastguard Workervar DeapexerTag = deapexerTagStruct{}
142*333d2b36SAndroid Build Coastguard Worker
143*333d2b36SAndroid Build Coastguard Worker// RequiredFilesFromPrebuiltApex must be implemented by modules that require files to be exported
144*333d2b36SAndroid Build Coastguard Worker// from a prebuilt_apex/apex_set.
145*333d2b36SAndroid Build Coastguard Workertype RequiredFilesFromPrebuiltApex interface {
146*333d2b36SAndroid Build Coastguard Worker	// RequiredFilesFromPrebuiltApex returns a list of the file paths (relative to the root of the
147*333d2b36SAndroid Build Coastguard Worker	// APEX's contents) that the implementing module requires from within a prebuilt .apex file.
148*333d2b36SAndroid Build Coastguard Worker	//
149*333d2b36SAndroid Build Coastguard Worker	// For each file path this will cause the file to be extracted out of the prebuilt .apex file, and
150*333d2b36SAndroid Build Coastguard Worker	// the path to the extracted file will be stored in the DeapexerInfo using the APEX relative file
151*333d2b36SAndroid Build Coastguard Worker	// path as the key, The path can then be retrieved using the PrebuiltExportPath(key) method.
152*333d2b36SAndroid Build Coastguard Worker	RequiredFilesFromPrebuiltApex(ctx BaseModuleContext) []string
153*333d2b36SAndroid Build Coastguard Worker
154*333d2b36SAndroid Build Coastguard Worker	// Returns true if a transitive dependency of an apex should use a .prof file to guide dexpreopt
155*333d2b36SAndroid Build Coastguard Worker	UseProfileGuidedDexpreopt() bool
156*333d2b36SAndroid Build Coastguard Worker}
157*333d2b36SAndroid Build Coastguard Worker
158*333d2b36SAndroid Build Coastguard Worker// Marker interface that identifies dependencies on modules that may require files from a prebuilt
159*333d2b36SAndroid Build Coastguard Worker// apex.
160*333d2b36SAndroid Build Coastguard Workertype RequiresFilesFromPrebuiltApexTag interface {
161*333d2b36SAndroid Build Coastguard Worker	blueprint.DependencyTag
162*333d2b36SAndroid Build Coastguard Worker
163*333d2b36SAndroid Build Coastguard Worker	// Method that differentiates this interface from others.
164*333d2b36SAndroid Build Coastguard Worker	RequiresFilesFromPrebuiltApex()
165*333d2b36SAndroid Build Coastguard Worker}
166*333d2b36SAndroid Build Coastguard Worker
167*333d2b36SAndroid Build Coastguard Worker// removeCompressedApexSuffix removes the _compressed suffix from the name if present.
168*333d2b36SAndroid Build Coastguard Workerfunc removeCompressedApexSuffix(name string) string {
169*333d2b36SAndroid Build Coastguard Worker	return strings.TrimSuffix(name, "_compressed")
170*333d2b36SAndroid Build Coastguard Worker}
171*333d2b36SAndroid Build Coastguard Worker
172*333d2b36SAndroid Build Coastguard Worker// equivalentDeapexerInfoProviders checks to make sure that the two DeapexerInfo structures are
173*333d2b36SAndroid Build Coastguard Worker// equivalent.
174*333d2b36SAndroid Build Coastguard Worker//
175*333d2b36SAndroid Build Coastguard Worker// At the moment <x> and <x>_compressed APEXes are treated as being equivalent.
176*333d2b36SAndroid Build Coastguard Worker//
177*333d2b36SAndroid Build Coastguard Worker// If they are not equivalent then this returns nil, otherwise, this returns the DeapexerInfo that
178*333d2b36SAndroid Build Coastguard Worker// should be used by the build, which is always the uncompressed one. That ensures that the behavior
179*333d2b36SAndroid Build Coastguard Worker// of the build is not dependent on which prebuilt APEX is visited first.
180*333d2b36SAndroid Build Coastguard Workerfunc equivalentDeapexerInfoProviders(p1 *DeapexerInfo, p2 *DeapexerInfo) *DeapexerInfo {
181*333d2b36SAndroid Build Coastguard Worker	n1 := removeCompressedApexSuffix(p1.ApexModuleName())
182*333d2b36SAndroid Build Coastguard Worker	n2 := removeCompressedApexSuffix(p2.ApexModuleName())
183*333d2b36SAndroid Build Coastguard Worker
184*333d2b36SAndroid Build Coastguard Worker	// If the names don't match then they are not equivalent.
185*333d2b36SAndroid Build Coastguard Worker	if n1 != n2 {
186*333d2b36SAndroid Build Coastguard Worker		return nil
187*333d2b36SAndroid Build Coastguard Worker	}
188*333d2b36SAndroid Build Coastguard Worker
189*333d2b36SAndroid Build Coastguard Worker	// Select the uncompressed APEX.
190*333d2b36SAndroid Build Coastguard Worker	if n1 == removeCompressedApexSuffix(n1) {
191*333d2b36SAndroid Build Coastguard Worker		return p1
192*333d2b36SAndroid Build Coastguard Worker	} else {
193*333d2b36SAndroid Build Coastguard Worker		return p2
194*333d2b36SAndroid Build Coastguard Worker	}
195*333d2b36SAndroid Build Coastguard Worker}
196