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