1*333d2b36SAndroid Build Coastguard Worker/* 2*333d2b36SAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project 3*333d2b36SAndroid Build Coastguard Worker * 4*333d2b36SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*333d2b36SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*333d2b36SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*333d2b36SAndroid Build Coastguard Worker * 8*333d2b36SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*333d2b36SAndroid Build Coastguard Worker * 10*333d2b36SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*333d2b36SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*333d2b36SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*333d2b36SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*333d2b36SAndroid Build Coastguard Worker * limitations under the License. 15*333d2b36SAndroid Build Coastguard Worker */ 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerpackage java 18*333d2b36SAndroid Build Coastguard Worker 19*333d2b36SAndroid Build Coastguard Workerimport ( 20*333d2b36SAndroid Build Coastguard Worker "fmt" 21*333d2b36SAndroid Build Coastguard Worker "strings" 22*333d2b36SAndroid Build Coastguard Worker 23*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint" 24*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint/proptools" 25*333d2b36SAndroid Build Coastguard Worker 26*333d2b36SAndroid Build Coastguard Worker "android/soong/android" 27*333d2b36SAndroid Build Coastguard Worker) 28*333d2b36SAndroid Build Coastguard Worker 29*333d2b36SAndroid Build Coastguard Worker// Build rules and utilities to generate individual packages/modules/common/proto/classpaths.proto 30*333d2b36SAndroid Build Coastguard Worker// config files based on build configuration to embed into /system and /apex on a device. 31*333d2b36SAndroid Build Coastguard Worker// 32*333d2b36SAndroid Build Coastguard Worker// See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables 33*333d2b36SAndroid Build Coastguard Worker// on the device. 34*333d2b36SAndroid Build Coastguard Worker 35*333d2b36SAndroid Build Coastguard Workertype classpathType int 36*333d2b36SAndroid Build Coastguard Worker 37*333d2b36SAndroid Build Coastguard Workerconst ( 38*333d2b36SAndroid Build Coastguard Worker // Matches definition in packages/modules/common/proto/classpaths.proto 39*333d2b36SAndroid Build Coastguard Worker BOOTCLASSPATH classpathType = iota 40*333d2b36SAndroid Build Coastguard Worker DEX2OATBOOTCLASSPATH 41*333d2b36SAndroid Build Coastguard Worker SYSTEMSERVERCLASSPATH 42*333d2b36SAndroid Build Coastguard Worker STANDALONE_SYSTEMSERVER_JARS 43*333d2b36SAndroid Build Coastguard Worker) 44*333d2b36SAndroid Build Coastguard Worker 45*333d2b36SAndroid Build Coastguard Workerfunc (c classpathType) String() string { 46*333d2b36SAndroid Build Coastguard Worker return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH", "STANDALONE_SYSTEMSERVER_JARS"}[c] 47*333d2b36SAndroid Build Coastguard Worker} 48*333d2b36SAndroid Build Coastguard Worker 49*333d2b36SAndroid Build Coastguard Workertype classpathFragmentProperties struct { 50*333d2b36SAndroid Build Coastguard Worker // Whether to generated classpaths.proto config instance for the fragment. If the config is not 51*333d2b36SAndroid Build Coastguard Worker // generated, then relevant boot jars are added to platform classpath, i.e. platform_bootclasspath 52*333d2b36SAndroid Build Coastguard Worker // or platform_systemserverclasspath. This is useful for non-updatable APEX boot jars, to keep 53*333d2b36SAndroid Build Coastguard Worker // them as part of dexopt on device. Defaults to true. 54*333d2b36SAndroid Build Coastguard Worker Generate_classpaths_proto *bool 55*333d2b36SAndroid Build Coastguard Worker} 56*333d2b36SAndroid Build Coastguard Worker 57*333d2b36SAndroid Build Coastguard Worker// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH 58*333d2b36SAndroid Build Coastguard Worker// variables at runtime. 59*333d2b36SAndroid Build Coastguard Workertype classpathFragment interface { 60*333d2b36SAndroid Build Coastguard Worker android.Module 61*333d2b36SAndroid Build Coastguard Worker 62*333d2b36SAndroid Build Coastguard Worker classpathFragmentBase() *ClasspathFragmentBase 63*333d2b36SAndroid Build Coastguard Worker} 64*333d2b36SAndroid Build Coastguard Worker 65*333d2b36SAndroid Build Coastguard Worker// ClasspathFragmentBase is meant to be embedded in any module types that implement classpathFragment; 66*333d2b36SAndroid Build Coastguard Worker// such modules are expected to call initClasspathFragment(). 67*333d2b36SAndroid Build Coastguard Workertype ClasspathFragmentBase struct { 68*333d2b36SAndroid Build Coastguard Worker properties classpathFragmentProperties 69*333d2b36SAndroid Build Coastguard Worker 70*333d2b36SAndroid Build Coastguard Worker classpathType classpathType 71*333d2b36SAndroid Build Coastguard Worker 72*333d2b36SAndroid Build Coastguard Worker outputFilepath android.OutputPath 73*333d2b36SAndroid Build Coastguard Worker installDirPath android.InstallPath 74*333d2b36SAndroid Build Coastguard Worker} 75*333d2b36SAndroid Build Coastguard Worker 76*333d2b36SAndroid Build Coastguard Workerfunc (c *ClasspathFragmentBase) classpathFragmentBase() *ClasspathFragmentBase { 77*333d2b36SAndroid Build Coastguard Worker return c 78*333d2b36SAndroid Build Coastguard Worker} 79*333d2b36SAndroid Build Coastguard Worker 80*333d2b36SAndroid Build Coastguard Worker// Initializes ClasspathFragmentBase struct. Must be called by all modules that include ClasspathFragmentBase. 81*333d2b36SAndroid Build Coastguard Workerfunc initClasspathFragment(c classpathFragment, classpathType classpathType) { 82*333d2b36SAndroid Build Coastguard Worker base := c.classpathFragmentBase() 83*333d2b36SAndroid Build Coastguard Worker base.classpathType = classpathType 84*333d2b36SAndroid Build Coastguard Worker c.AddProperties(&base.properties) 85*333d2b36SAndroid Build Coastguard Worker} 86*333d2b36SAndroid Build Coastguard Worker 87*333d2b36SAndroid Build Coastguard Worker// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto 88*333d2b36SAndroid Build Coastguard Workertype classpathJar struct { 89*333d2b36SAndroid Build Coastguard Worker path string 90*333d2b36SAndroid Build Coastguard Worker classpath classpathType 91*333d2b36SAndroid Build Coastguard Worker minSdkVersion string 92*333d2b36SAndroid Build Coastguard Worker maxSdkVersion string 93*333d2b36SAndroid Build Coastguard Worker} 94*333d2b36SAndroid Build Coastguard Worker 95*333d2b36SAndroid Build Coastguard Worker// gatherPossibleApexModuleNamesAndStems returns a set of module and stem names from the 96*333d2b36SAndroid Build Coastguard Worker// supplied contents that may be in the apex boot jars. 97*333d2b36SAndroid Build Coastguard Worker// 98*333d2b36SAndroid Build Coastguard Worker// The module names are included because sometimes the stem is set to just change the name of 99*333d2b36SAndroid Build Coastguard Worker// the installed file and it expects the configuration to still use the actual module name. 100*333d2b36SAndroid Build Coastguard Worker// 101*333d2b36SAndroid Build Coastguard Worker// The stem names are included because sometimes the stem is set to change the effective name of the 102*333d2b36SAndroid Build Coastguard Worker// module that is used in the configuration as well,e .g. when a test library is overriding an 103*333d2b36SAndroid Build Coastguard Worker// actual boot jar 104*333d2b36SAndroid Build Coastguard Workerfunc gatherPossibleApexModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string { 105*333d2b36SAndroid Build Coastguard Worker set := map[string]struct{}{} 106*333d2b36SAndroid Build Coastguard Worker for _, name := range contents { 107*333d2b36SAndroid Build Coastguard Worker dep := ctx.GetDirectDepWithTag(name, tag) 108*333d2b36SAndroid Build Coastguard Worker if dep == nil && ctx.Config().AllowMissingDependencies() { 109*333d2b36SAndroid Build Coastguard Worker // Ignore apex boot jars from dexpreopt if it does not exist, and missing deps are allowed. 110*333d2b36SAndroid Build Coastguard Worker continue 111*333d2b36SAndroid Build Coastguard Worker } 112*333d2b36SAndroid Build Coastguard Worker set[ModuleStemForDeapexing(dep)] = struct{}{} 113*333d2b36SAndroid Build Coastguard Worker if m, ok := dep.(ModuleWithStem); ok { 114*333d2b36SAndroid Build Coastguard Worker set[m.Stem()] = struct{}{} 115*333d2b36SAndroid Build Coastguard Worker } else { 116*333d2b36SAndroid Build Coastguard Worker ctx.PropertyErrorf("contents", "%v is not a ModuleWithStem", name) 117*333d2b36SAndroid Build Coastguard Worker } 118*333d2b36SAndroid Build Coastguard Worker } 119*333d2b36SAndroid Build Coastguard Worker return android.SortedKeys(set) 120*333d2b36SAndroid Build Coastguard Worker} 121*333d2b36SAndroid Build Coastguard Worker 122*333d2b36SAndroid Build Coastguard Worker// Converts android.ConfiguredJarList into a list of classpathJars for each given classpathType. 123*333d2b36SAndroid Build Coastguard Workerfunc configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, classpaths ...classpathType) []classpathJar { 124*333d2b36SAndroid Build Coastguard Worker paths := configuredJars.DevicePaths(ctx.Config(), android.Android) 125*333d2b36SAndroid Build Coastguard Worker jars := make([]classpathJar, 0, len(paths)*len(classpaths)) 126*333d2b36SAndroid Build Coastguard Worker for i := 0; i < len(paths); i++ { 127*333d2b36SAndroid Build Coastguard Worker for _, classpathType := range classpaths { 128*333d2b36SAndroid Build Coastguard Worker jar := classpathJar{ 129*333d2b36SAndroid Build Coastguard Worker classpath: classpathType, 130*333d2b36SAndroid Build Coastguard Worker path: paths[i], 131*333d2b36SAndroid Build Coastguard Worker } 132*333d2b36SAndroid Build Coastguard Worker ctx.VisitDirectDepsIf(func(m android.Module) bool { 133*333d2b36SAndroid Build Coastguard Worker return m.Name() == configuredJars.Jar(i) 134*333d2b36SAndroid Build Coastguard Worker }, func(m android.Module) { 135*333d2b36SAndroid Build Coastguard Worker if s, ok := m.(*SdkLibrary); ok { 136*333d2b36SAndroid Build Coastguard Worker minSdkVersion := s.MinSdkVersion(ctx) 137*333d2b36SAndroid Build Coastguard Worker maxSdkVersion := s.MaxSdkVersion(ctx) 138*333d2b36SAndroid Build Coastguard Worker // TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current" 139*333d2b36SAndroid Build Coastguard Worker if minSdkVersion.Specified() { 140*333d2b36SAndroid Build Coastguard Worker if minSdkVersion.IsCurrent() { 141*333d2b36SAndroid Build Coastguard Worker jar.minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String() 142*333d2b36SAndroid Build Coastguard Worker } else { 143*333d2b36SAndroid Build Coastguard Worker jar.minSdkVersion = minSdkVersion.String() 144*333d2b36SAndroid Build Coastguard Worker } 145*333d2b36SAndroid Build Coastguard Worker } 146*333d2b36SAndroid Build Coastguard Worker if maxSdkVersion.Specified() { 147*333d2b36SAndroid Build Coastguard Worker if maxSdkVersion.IsCurrent() { 148*333d2b36SAndroid Build Coastguard Worker jar.maxSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String() 149*333d2b36SAndroid Build Coastguard Worker } else { 150*333d2b36SAndroid Build Coastguard Worker jar.maxSdkVersion = maxSdkVersion.String() 151*333d2b36SAndroid Build Coastguard Worker } 152*333d2b36SAndroid Build Coastguard Worker } 153*333d2b36SAndroid Build Coastguard Worker } 154*333d2b36SAndroid Build Coastguard Worker }) 155*333d2b36SAndroid Build Coastguard Worker jars = append(jars, jar) 156*333d2b36SAndroid Build Coastguard Worker } 157*333d2b36SAndroid Build Coastguard Worker } 158*333d2b36SAndroid Build Coastguard Worker return jars 159*333d2b36SAndroid Build Coastguard Worker} 160*333d2b36SAndroid Build Coastguard Worker 161*333d2b36SAndroid Build Coastguard Workerfunc (c *ClasspathFragmentBase) outputFilename() string { 162*333d2b36SAndroid Build Coastguard Worker return strings.ToLower(c.classpathType.String()) + ".pb" 163*333d2b36SAndroid Build Coastguard Worker} 164*333d2b36SAndroid Build Coastguard Worker 165*333d2b36SAndroid Build Coastguard Workerfunc (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, jars []classpathJar) { 166*333d2b36SAndroid Build Coastguard Worker generateProto := proptools.BoolDefault(c.properties.Generate_classpaths_proto, true) 167*333d2b36SAndroid Build Coastguard Worker if generateProto { 168*333d2b36SAndroid Build Coastguard Worker outputFilename := c.outputFilename() 169*333d2b36SAndroid Build Coastguard Worker c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath 170*333d2b36SAndroid Build Coastguard Worker c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths") 171*333d2b36SAndroid Build Coastguard Worker 172*333d2b36SAndroid Build Coastguard Worker generatedTextproto := android.PathForModuleOut(ctx, outputFilename+".textproto") 173*333d2b36SAndroid Build Coastguard Worker writeClasspathsTextproto(ctx, generatedTextproto, jars) 174*333d2b36SAndroid Build Coastguard Worker 175*333d2b36SAndroid Build Coastguard Worker rule := android.NewRuleBuilder(pctx, ctx) 176*333d2b36SAndroid Build Coastguard Worker rule.Command(). 177*333d2b36SAndroid Build Coastguard Worker BuiltTool("conv_classpaths_proto"). 178*333d2b36SAndroid Build Coastguard Worker Flag("encode"). 179*333d2b36SAndroid Build Coastguard Worker Flag("--format=textproto"). 180*333d2b36SAndroid Build Coastguard Worker FlagWithInput("--input=", generatedTextproto). 181*333d2b36SAndroid Build Coastguard Worker FlagWithOutput("--output=", c.outputFilepath) 182*333d2b36SAndroid Build Coastguard Worker 183*333d2b36SAndroid Build Coastguard Worker rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String()) 184*333d2b36SAndroid Build Coastguard Worker } 185*333d2b36SAndroid Build Coastguard Worker 186*333d2b36SAndroid Build Coastguard Worker classpathProtoInfo := ClasspathFragmentProtoContentInfo{ 187*333d2b36SAndroid Build Coastguard Worker ClasspathFragmentProtoGenerated: generateProto, 188*333d2b36SAndroid Build Coastguard Worker ClasspathFragmentProtoContents: configuredJars, 189*333d2b36SAndroid Build Coastguard Worker ClasspathFragmentProtoInstallDir: c.installDirPath, 190*333d2b36SAndroid Build Coastguard Worker ClasspathFragmentProtoOutput: c.outputFilepath, 191*333d2b36SAndroid Build Coastguard Worker } 192*333d2b36SAndroid Build Coastguard Worker android.SetProvider(ctx, ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo) 193*333d2b36SAndroid Build Coastguard Worker} 194*333d2b36SAndroid Build Coastguard Worker 195*333d2b36SAndroid Build Coastguard Workerfunc (c *ClasspathFragmentBase) installClasspathProto(ctx android.ModuleContext) android.InstallPath { 196*333d2b36SAndroid Build Coastguard Worker return ctx.InstallFile(c.installDirPath, c.outputFilename(), c.outputFilepath) 197*333d2b36SAndroid Build Coastguard Worker} 198*333d2b36SAndroid Build Coastguard Worker 199*333d2b36SAndroid Build Coastguard Workerfunc writeClasspathsTextproto(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) { 200*333d2b36SAndroid Build Coastguard Worker var content strings.Builder 201*333d2b36SAndroid Build Coastguard Worker 202*333d2b36SAndroid Build Coastguard Worker for _, jar := range jars { 203*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(&content, "jars {\n") 204*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(&content, "path: \"%s\"\n", jar.path) 205*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(&content, "classpath: %s\n", jar.classpath) 206*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(&content, "min_sdk_version: \"%s\"\n", jar.minSdkVersion) 207*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(&content, "max_sdk_version: \"%s\"\n", jar.maxSdkVersion) 208*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(&content, "}\n") 209*333d2b36SAndroid Build Coastguard Worker } 210*333d2b36SAndroid Build Coastguard Worker 211*333d2b36SAndroid Build Coastguard Worker android.WriteFileRule(ctx, output, content.String()) 212*333d2b36SAndroid Build Coastguard Worker} 213*333d2b36SAndroid Build Coastguard Worker 214*333d2b36SAndroid Build Coastguard Worker// Returns AndroidMkEntries objects to install generated classpath.proto. 215*333d2b36SAndroid Build Coastguard Worker// Do not use this to install into APEXes as the injection of the generated files happen separately for APEXes. 216*333d2b36SAndroid Build Coastguard Workerfunc (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries { 217*333d2b36SAndroid Build Coastguard Worker return []android.AndroidMkEntries{{ 218*333d2b36SAndroid Build Coastguard Worker Class: "ETC", 219*333d2b36SAndroid Build Coastguard Worker OutputFile: android.OptionalPathForPath(c.outputFilepath), 220*333d2b36SAndroid Build Coastguard Worker ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 221*333d2b36SAndroid Build Coastguard Worker func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 222*333d2b36SAndroid Build Coastguard Worker entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.String()) 223*333d2b36SAndroid Build Coastguard Worker entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.outputFilepath.Base()) 224*333d2b36SAndroid Build Coastguard Worker }, 225*333d2b36SAndroid Build Coastguard Worker }, 226*333d2b36SAndroid Build Coastguard Worker }} 227*333d2b36SAndroid Build Coastguard Worker} 228*333d2b36SAndroid Build Coastguard Worker 229*333d2b36SAndroid Build Coastguard Workervar ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider[ClasspathFragmentProtoContentInfo]() 230*333d2b36SAndroid Build Coastguard Worker 231*333d2b36SAndroid Build Coastguard Workertype ClasspathFragmentProtoContentInfo struct { 232*333d2b36SAndroid Build Coastguard Worker // Whether the classpaths.proto config is generated for the fragment. 233*333d2b36SAndroid Build Coastguard Worker ClasspathFragmentProtoGenerated bool 234*333d2b36SAndroid Build Coastguard Worker 235*333d2b36SAndroid Build Coastguard Worker // ClasspathFragmentProtoContents contains a list of jars that are part of this classpath fragment. 236*333d2b36SAndroid Build Coastguard Worker ClasspathFragmentProtoContents android.ConfiguredJarList 237*333d2b36SAndroid Build Coastguard Worker 238*333d2b36SAndroid Build Coastguard Worker // ClasspathFragmentProtoOutput is an output path for the generated classpaths.proto config of this module. 239*333d2b36SAndroid Build Coastguard Worker // 240*333d2b36SAndroid Build Coastguard Worker // The file should be copied to a relevant place on device, see ClasspathFragmentProtoInstallDir 241*333d2b36SAndroid Build Coastguard Worker // for more details. 242*333d2b36SAndroid Build Coastguard Worker ClasspathFragmentProtoOutput android.OutputPath 243*333d2b36SAndroid Build Coastguard Worker 244*333d2b36SAndroid Build Coastguard Worker // ClasspathFragmentProtoInstallDir contains information about on device location for the generated classpaths.proto file. 245*333d2b36SAndroid Build Coastguard Worker // 246*333d2b36SAndroid Build Coastguard Worker // The path encodes expected sub-location within partitions, i.e. etc/classpaths/<proto-file>, 247*333d2b36SAndroid Build Coastguard Worker // for ClasspathFragmentProtoOutput. To get sub-location, instead of the full output / make path 248*333d2b36SAndroid Build Coastguard Worker // use android.InstallPath#Rel(). 249*333d2b36SAndroid Build Coastguard Worker // 250*333d2b36SAndroid Build Coastguard Worker // This is only relevant for APEX modules as they perform their own installation; while regular 251*333d2b36SAndroid Build Coastguard Worker // system files are installed via ClasspathFragmentBase#androidMkEntries(). 252*333d2b36SAndroid Build Coastguard Worker ClasspathFragmentProtoInstallDir android.InstallPath 253*333d2b36SAndroid Build Coastguard Worker} 254