1// Copyright 2023 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14package java 15 16import ( 17 "android/soong/android" 18 "android/soong/tradefed" 19 20 "github.com/google/blueprint" 21 "github.com/google/blueprint/proptools" 22) 23 24func init() { 25 RegisterRavenwoodBuildComponents(android.InitRegistrationContext) 26} 27 28func RegisterRavenwoodBuildComponents(ctx android.RegistrationContext) { 29 ctx.RegisterModuleType("android_ravenwood_test", ravenwoodTestFactory) 30 ctx.RegisterModuleType("android_ravenwood_libgroup", ravenwoodLibgroupFactory) 31} 32 33var ravenwoodLibContentTag = dependencyTag{name: "ravenwoodlibcontent"} 34var ravenwoodUtilsTag = dependencyTag{name: "ravenwoodutils"} 35var ravenwoodRuntimeTag = dependencyTag{name: "ravenwoodruntime"} 36 37const ravenwoodUtilsName = "ravenwood-utils" 38const ravenwoodRuntimeName = "ravenwood-runtime" 39 40type ravenwoodLibgroupJniDepProviderInfo struct { 41 // All the jni_libs module names with transient dependencies. 42 names map[string]bool 43} 44 45var ravenwoodLibgroupJniDepProvider = blueprint.NewProvider[ravenwoodLibgroupJniDepProviderInfo]() 46 47func getLibPath(archType android.ArchType) string { 48 if archType.Multilib == "lib64" { 49 return "lib64" 50 } 51 return "lib" 52} 53 54type ravenwoodTestProperties struct { 55 Jni_libs []string 56} 57 58type ravenwoodTest struct { 59 Library 60 61 ravenwoodTestProperties ravenwoodTestProperties 62 63 testProperties testProperties 64 testConfig android.Path 65 66 forceOSType android.OsType 67 forceArchType android.ArchType 68} 69 70func ravenwoodTestFactory() android.Module { 71 module := &ravenwoodTest{} 72 73 module.addHostAndDeviceProperties() 74 module.AddProperties(&module.testProperties, &module.ravenwoodTestProperties) 75 76 module.Module.dexpreopter.isTest = true 77 module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) 78 79 module.testProperties.Test_suites = []string{ 80 "general-tests", 81 "ravenwood-tests", 82 } 83 module.testProperties.Test_options.Unit_test = proptools.BoolPtr(false) 84 85 InitJavaModule(module, android.DeviceSupported) 86 android.InitDefaultableModule(module) 87 88 return module 89} 90 91func (r *ravenwoodTest) InstallInTestcases() bool { return true } 92func (r *ravenwoodTest) InstallForceOS() (*android.OsType, *android.ArchType) { 93 return &r.forceOSType, &r.forceArchType 94} 95func (r *ravenwoodTest) TestSuites() []string { 96 return r.testProperties.Test_suites 97} 98 99func (r *ravenwoodTest) DepsMutator(ctx android.BottomUpMutatorContext) { 100 r.Library.DepsMutator(ctx) 101 102 // Generically depend on the runtime so that it's installed together with us 103 ctx.AddVariationDependencies(nil, ravenwoodRuntimeTag, ravenwoodRuntimeName) 104 105 // Directly depend on any utils so that we link against them 106 utils := ctx.AddVariationDependencies(nil, ravenwoodUtilsTag, ravenwoodUtilsName)[0] 107 if utils != nil { 108 for _, lib := range utils.(*ravenwoodLibgroup).ravenwoodLibgroupProperties.Libs { 109 ctx.AddVariationDependencies(nil, libTag, lib) 110 } 111 } 112 113 // Add jni libs 114 for _, lib := range r.ravenwoodTestProperties.Jni_libs { 115 ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib) 116 } 117} 118 119func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { 120 r.forceOSType = ctx.Config().BuildOS 121 r.forceArchType = ctx.Config().BuildArch 122 123 r.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{ 124 TestConfigProp: r.testProperties.Test_config, 125 TestConfigTemplateProp: r.testProperties.Test_config_template, 126 TestSuites: r.testProperties.Test_suites, 127 AutoGenConfig: r.testProperties.Auto_gen_config, 128 DeviceTemplate: "${RavenwoodTestConfigTemplate}", 129 HostTemplate: "${RavenwoodTestConfigTemplate}", 130 }) 131 132 r.Library.GenerateAndroidBuildActions(ctx) 133 134 // Start by depending on all files installed by dependencies 135 var installDeps android.InstallPaths 136 137 // All JNI libraries included in the runtime 138 var runtimeJniModuleNames map[string]bool 139 140 if utils := ctx.GetDirectDepsWithTag(ravenwoodUtilsTag)[0]; utils != nil { 141 for _, installFile := range utils.FilesToInstall() { 142 installDeps = append(installDeps, installFile) 143 } 144 jniDeps, ok := android.OtherModuleProvider(ctx, utils, ravenwoodLibgroupJniDepProvider) 145 if ok { 146 runtimeJniModuleNames = jniDeps.names 147 } 148 } 149 150 if runtime := ctx.GetDirectDepsWithTag(ravenwoodRuntimeTag)[0]; runtime != nil { 151 for _, installFile := range runtime.FilesToInstall() { 152 installDeps = append(installDeps, installFile) 153 } 154 jniDeps, ok := android.OtherModuleProvider(ctx, runtime, ravenwoodLibgroupJniDepProvider) 155 if ok { 156 runtimeJniModuleNames = jniDeps.names 157 } 158 } 159 160 // Also remember what JNI libs are in the runtime. 161 162 // Also depend on our config 163 installPath := android.PathForModuleInstall(ctx, r.BaseModuleName()) 164 installConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig) 165 installDeps = append(installDeps, installConfig) 166 167 // Depend on the JNI libraries, but don't install the ones that the runtime already 168 // contains. 169 soInstallPath := installPath.Join(ctx, getLibPath(r.forceArchType)) 170 for _, jniLib := range collectTransitiveJniDeps(ctx) { 171 if _, ok := runtimeJniModuleNames[jniLib.name]; ok { 172 continue // Runtime already includes it. 173 } 174 installJni := ctx.InstallFile(soInstallPath, jniLib.path.Base(), jniLib.path) 175 installDeps = append(installDeps, installJni) 176 } 177 178 // Install our JAR with all dependencies 179 ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...) 180} 181 182func (r *ravenwoodTest) AndroidMkEntries() []android.AndroidMkEntries { 183 entriesList := r.Library.AndroidMkEntries() 184 entries := &entriesList[0] 185 entries.ExtraEntries = append(entries.ExtraEntries, 186 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 187 entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) 188 entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", 189 "general-tests", "ravenwood-tests") 190 if r.testConfig != nil { 191 entries.SetPath("LOCAL_FULL_TEST_CONFIG", r.testConfig) 192 } 193 }) 194 return entriesList 195} 196 197type ravenwoodLibgroupProperties struct { 198 Libs []string 199 200 Jni_libs []string 201} 202 203type ravenwoodLibgroup struct { 204 android.ModuleBase 205 206 ravenwoodLibgroupProperties ravenwoodLibgroupProperties 207 208 forceOSType android.OsType 209 forceArchType android.ArchType 210} 211 212func ravenwoodLibgroupFactory() android.Module { 213 module := &ravenwoodLibgroup{} 214 module.AddProperties(&module.ravenwoodLibgroupProperties) 215 216 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) 217 return module 218} 219 220func (r *ravenwoodLibgroup) InstallInTestcases() bool { return true } 221func (r *ravenwoodLibgroup) InstallForceOS() (*android.OsType, *android.ArchType) { 222 return &r.forceOSType, &r.forceArchType 223} 224func (r *ravenwoodLibgroup) TestSuites() []string { 225 return []string{ 226 "general-tests", 227 "ravenwood-tests", 228 } 229} 230 231func (r *ravenwoodLibgroup) DepsMutator(ctx android.BottomUpMutatorContext) { 232 // Always depends on our underlying libs 233 for _, lib := range r.ravenwoodLibgroupProperties.Libs { 234 ctx.AddVariationDependencies(nil, ravenwoodLibContentTag, lib) 235 } 236 for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs { 237 ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib) 238 } 239} 240 241func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContext) { 242 r.forceOSType = ctx.Config().BuildOS 243 r.forceArchType = ctx.Config().BuildArch 244 245 // Collect the JNI dependencies, including the transitive deps. 246 jniDepNames := make(map[string]bool) 247 jniLibs := collectTransitiveJniDeps(ctx) 248 249 for _, jni := range jniLibs { 250 jniDepNames[jni.name] = true 251 } 252 android.SetProvider(ctx, ravenwoodLibgroupJniDepProvider, ravenwoodLibgroupJniDepProviderInfo{ 253 names: jniDepNames, 254 }) 255 256 // Install our runtime into expected location for packaging 257 installPath := android.PathForModuleInstall(ctx, r.BaseModuleName()) 258 for _, lib := range r.ravenwoodLibgroupProperties.Libs { 259 libModule := ctx.GetDirectDepWithTag(lib, ravenwoodLibContentTag) 260 libJar := android.OutputFileForModule(ctx, libModule, "") 261 ctx.InstallFile(installPath, lib+".jar", libJar) 262 } 263 soInstallPath := android.PathForModuleInstall(ctx, r.BaseModuleName()).Join(ctx, getLibPath(r.forceArchType)) 264 265 for _, jniLib := range jniLibs { 266 ctx.InstallFile(soInstallPath, jniLib.path.Base(), jniLib.path) 267 } 268 269 // Normal build should perform install steps 270 ctx.Phony(r.BaseModuleName(), android.PathForPhony(ctx, r.BaseModuleName()+"-install")) 271} 272 273// collectTransitiveJniDeps returns all JNI dependencies, including transitive 274// ones, including NDK / stub libs. (Because Ravenwood has no "preinstalled" libraries) 275func collectTransitiveJniDeps(ctx android.ModuleContext) []jniLib { 276 libs, _ := collectJniDeps(ctx, true, false, nil) 277 return libs 278} 279