1// Copyright 2019 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. 14 15package java 16 17import ( 18 "fmt" 19 20 "android/soong/android" 21) 22 23func init() { 24 android.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) 25 android.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory) 26 android.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory) 27} 28 29type hiddenAPISingletonPathsStruct struct { 30 flags android.OutputPath 31 index android.OutputPath 32 metadata android.OutputPath 33 stubFlags android.OutputPath 34} 35 36var hiddenAPISingletonPathsKey = android.NewOnceKey("hiddenAPISingletonPathsKey") 37 38// hiddenAPISingletonPaths creates all the paths for singleton files the first time it is called, which may be 39// from a ModuleContext that needs to reference a file that will be created by a singleton rule that hasn't 40// yet been created. 41func hiddenAPISingletonPaths(ctx android.PathContext) hiddenAPISingletonPathsStruct { 42 return ctx.Config().Once(hiddenAPISingletonPathsKey, func() interface{} { 43 return hiddenAPISingletonPathsStruct{ 44 flags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-flags.csv"), 45 index: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-index.csv"), 46 metadata: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-greylist.csv"), 47 stubFlags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-stub-flags.txt"), 48 } 49 }).(hiddenAPISingletonPathsStruct) 50} 51 52func hiddenAPISingletonFactory() android.Singleton { 53 return &hiddenAPISingleton{} 54} 55 56type hiddenAPISingleton struct { 57 flags, metadata android.Path 58} 59 60// hiddenAPI singleton rules 61func (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) { 62 // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true 63 if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { 64 return 65 } 66 67 stubFlagsRule(ctx) 68 69 // These rules depend on files located in frameworks/base, skip them if running in a tree that doesn't have them. 70 if ctx.Config().FrameworksBaseDirExists(ctx) { 71 h.flags = flagsRule(ctx) 72 h.metadata = metadataRule(ctx) 73 } else { 74 h.flags = emptyFlagsRule(ctx) 75 } 76} 77 78// Export paths to Make. INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/. 79// Both paths are used to call dist-for-goals. 80func (h *hiddenAPISingleton) MakeVars(ctx android.MakeVarsContext) { 81 if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { 82 return 83 } 84 85 ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", h.flags.String()) 86 87 if h.metadata != nil { 88 ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA", h.metadata.String()) 89 } 90} 91 92// stubFlagsRule creates the rule to build hiddenapi-stub-flags.txt out of dex jars from stub modules and boot image 93// modules. 94func stubFlagsRule(ctx android.SingletonContext) { 95 // Public API stubs 96 publicStubModules := []string{ 97 "android_stubs_current", 98 } 99 100 // Add the android.test.base to the set of stubs only if the android.test.base module is on 101 // the boot jars list as the runtime will only enforce hiddenapi access against modules on 102 // that list. 103 if inList("android.test.base", ctx.Config().BootJars()) && !ctx.Config().UnbundledBuildUsePrebuiltSdks() { 104 publicStubModules = append(publicStubModules, "android.test.base.stubs") 105 } 106 107 // System API stubs 108 systemStubModules := []string{ 109 "android_system_stubs_current", 110 } 111 112 // Test API stubs 113 testStubModules := []string{ 114 "android_test_stubs_current", 115 } 116 117 // Core Platform API stubs 118 corePlatformStubModules := []string{ 119 "legacy.core.platform.api.stubs", 120 } 121 122 // Allow products to define their own stubs for custom product jars that apps can use. 123 publicStubModules = append(publicStubModules, ctx.Config().ProductHiddenAPIStubs()...) 124 systemStubModules = append(systemStubModules, ctx.Config().ProductHiddenAPIStubsSystem()...) 125 testStubModules = append(testStubModules, ctx.Config().ProductHiddenAPIStubsTest()...) 126 if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") { 127 publicStubModules = append(publicStubModules, "jacoco-stubs") 128 } 129 130 publicStubPaths := make(android.Paths, len(publicStubModules)) 131 systemStubPaths := make(android.Paths, len(systemStubModules)) 132 testStubPaths := make(android.Paths, len(testStubModules)) 133 corePlatformStubPaths := make(android.Paths, len(corePlatformStubModules)) 134 135 moduleListToPathList := map[*[]string]android.Paths{ 136 &publicStubModules: publicStubPaths, 137 &systemStubModules: systemStubPaths, 138 &testStubModules: testStubPaths, 139 &corePlatformStubModules: corePlatformStubPaths, 140 } 141 142 var bootDexJars android.Paths 143 144 ctx.VisitAllModules(func(module android.Module) { 145 // Collect dex jar paths for the modules listed above. 146 if j, ok := module.(Dependency); ok { 147 name := ctx.ModuleName(module) 148 for moduleList, pathList := range moduleListToPathList { 149 if i := android.IndexList(name, *moduleList); i != -1 { 150 pathList[i] = j.DexJarBuildPath() 151 } 152 } 153 } 154 155 // Collect dex jar paths for modules that had hiddenapi encode called on them. 156 if h, ok := module.(hiddenAPIIntf); ok { 157 if jar := h.bootDexJar(); jar != nil { 158 // For a java lib included in an APEX, only take the one built for 159 // the platform variant, and skip the variants for APEXes. 160 // Otherwise, the hiddenapi tool will complain about duplicated classes 161 if a, ok := module.(android.ApexModule); ok { 162 if android.InAnyApex(module.Name()) && !a.IsForPlatform() { 163 return 164 } 165 } 166 bootDexJars = append(bootDexJars, jar) 167 } 168 } 169 }) 170 171 var missingDeps []string 172 // Ensure all modules were converted to paths 173 for moduleList, pathList := range moduleListToPathList { 174 for i := range pathList { 175 if pathList[i] == nil { 176 pathList[i] = android.PathForOutput(ctx, "missing") 177 if ctx.Config().AllowMissingDependencies() { 178 missingDeps = append(missingDeps, (*moduleList)[i]) 179 } else { 180 ctx.Errorf("failed to find dex jar path for module %q", 181 (*moduleList)[i]) 182 } 183 } 184 } 185 } 186 187 // Singleton rule which applies hiddenapi on all boot class path dex files. 188 rule := android.NewRuleBuilder() 189 190 outputPath := hiddenAPISingletonPaths(ctx).stubFlags 191 tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp") 192 193 rule.MissingDeps(missingDeps) 194 195 rule.Command(). 196 Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")). 197 Text("list"). 198 FlagForEachInput("--boot-dex=", bootDexJars). 199 FlagWithInputList("--public-stub-classpath=", publicStubPaths, ":"). 200 FlagWithInputList("--system-stub-classpath=", systemStubPaths, ":"). 201 FlagWithInputList("--test-stub-classpath=", testStubPaths, ":"). 202 FlagWithInputList("--core-platform-stub-classpath=", corePlatformStubPaths, ":"). 203 FlagWithOutput("--out-api-flags=", tempPath) 204 205 commitChangeForRestat(rule, tempPath, outputPath) 206 207 rule.Build(pctx, ctx, "hiddenAPIStubFlagsFile", "hiddenapi stub flags") 208} 209 210// flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and 211// the unsupported API. 212func flagsRule(ctx android.SingletonContext) android.Path { 213 var flagsCSV android.Paths 214 var greylistRemovedApis android.Paths 215 216 ctx.VisitAllModules(func(module android.Module) { 217 if h, ok := module.(hiddenAPIIntf); ok { 218 if csv := h.flagsCSV(); csv != nil { 219 flagsCSV = append(flagsCSV, csv) 220 } 221 } else if ds, ok := module.(*Droidstubs); ok { 222 // Track @removed public and system APIs via corresponding droidstubs targets. 223 // These APIs are not present in the stubs, however, we have to keep allowing access 224 // to them at runtime. 225 if m := ctx.ModuleName(module); m == "api-stubs-docs" || m == "system-api-stubs-docs" { 226 greylistRemovedApis = append(greylistRemovedApis, ds.removedDexApiFile) 227 } 228 } 229 }) 230 231 combinedRemovedApis := android.PathForOutput(ctx, "hiddenapi", "combined-removed-dex.txt") 232 ctx.Build(pctx, android.BuildParams{ 233 Rule: android.Cat, 234 Inputs: greylistRemovedApis, 235 Output: combinedRemovedApis, 236 Description: "Combine removed apis for " + combinedRemovedApis.String(), 237 }) 238 239 rule := android.NewRuleBuilder() 240 241 outputPath := hiddenAPISingletonPaths(ctx).flags 242 tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp") 243 244 stubFlags := hiddenAPISingletonPaths(ctx).stubFlags 245 246 rule.Command(). 247 Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py")). 248 FlagWithInput("--csv ", stubFlags). 249 Inputs(flagsCSV). 250 FlagWithInput("--unsupported ", 251 android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist.txt")). 252 FlagWithInput("--unsupported-ignore-conflicts ", combinedRemovedApis). 253 FlagWithInput("--max-target-q ", 254 android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-q.txt")). 255 FlagWithInput("--max-target-p ", 256 android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-p.txt")). 257 FlagWithInput("--max-target-o-ignore-conflicts ", 258 android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-o.txt")). 259 FlagWithInput("--blocked ", 260 android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blacklist.txt")). 261 FlagWithInput("--unsupported-packages ", 262 android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-packages.txt")). 263 FlagWithOutput("--output ", tempPath) 264 265 commitChangeForRestat(rule, tempPath, outputPath) 266 267 rule.Build(pctx, ctx, "hiddenAPIFlagsFile", "hiddenapi flags") 268 269 return outputPath 270} 271 272// emptyFlagsRule creates a rule to build an empty hiddenapi-flags.csv, which is needed by master-art-host builds that 273// have a partial manifest without frameworks/base but still need to build a boot image. 274func emptyFlagsRule(ctx android.SingletonContext) android.Path { 275 rule := android.NewRuleBuilder() 276 277 outputPath := hiddenAPISingletonPaths(ctx).flags 278 279 rule.Command().Text("rm").Flag("-f").Output(outputPath) 280 rule.Command().Text("touch").Output(outputPath) 281 282 rule.Build(pctx, ctx, "emptyHiddenAPIFlagsFile", "empty hiddenapi flags") 283 284 return outputPath 285} 286 287// metadataRule creates a rule to build hiddenapi-greylist.csv out of the metadata.csv files generated for boot image 288// modules. 289func metadataRule(ctx android.SingletonContext) android.Path { 290 var metadataCSV android.Paths 291 292 ctx.VisitAllModules(func(module android.Module) { 293 if h, ok := module.(hiddenAPIIntf); ok { 294 if csv := h.metadataCSV(); csv != nil { 295 metadataCSV = append(metadataCSV, csv) 296 } 297 } 298 }) 299 300 rule := android.NewRuleBuilder() 301 302 outputPath := hiddenAPISingletonPaths(ctx).metadata 303 304 rule.Command(). 305 BuiltTool(ctx, "merge_csv"). 306 FlagWithOutput("--output=", outputPath). 307 Inputs(metadataCSV) 308 309 rule.Build(pctx, ctx, "hiddenAPIGreylistMetadataFile", "hiddenapi greylist metadata") 310 311 return outputPath 312} 313 314// commitChangeForRestat adds a command to a rule that updates outputPath from tempPath if they are different. It 315// also marks the rule as restat and marks the tempPath as a temporary file that should not be considered an output of 316// the rule. 317func commitChangeForRestat(rule *android.RuleBuilder, tempPath, outputPath android.WritablePath) { 318 rule.Restat() 319 rule.Temporary(tempPath) 320 rule.Command(). 321 Text("("). 322 Text("if"). 323 Text("cmp -s").Input(tempPath).Output(outputPath).Text(";"). 324 Text("then"). 325 Text("rm").Input(tempPath).Text(";"). 326 Text("else"). 327 Text("mv").Input(tempPath).Output(outputPath).Text(";"). 328 Text("fi"). 329 Text(")") 330} 331 332type hiddenAPIFlagsProperties struct { 333 // name of the file into which the flags will be copied. 334 Filename *string 335} 336 337type hiddenAPIFlags struct { 338 android.ModuleBase 339 340 properties hiddenAPIFlagsProperties 341 342 outputFilePath android.OutputPath 343} 344 345func (h *hiddenAPIFlags) GenerateAndroidBuildActions(ctx android.ModuleContext) { 346 filename := String(h.properties.Filename) 347 348 inputPath := hiddenAPISingletonPaths(ctx).flags 349 h.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath 350 351 // This ensures that outputFilePath has the correct name for others to 352 // use, as the source file may have a different name. 353 ctx.Build(pctx, android.BuildParams{ 354 Rule: android.Cp, 355 Output: h.outputFilePath, 356 Input: inputPath, 357 }) 358} 359 360func (h *hiddenAPIFlags) OutputFiles(tag string) (android.Paths, error) { 361 switch tag { 362 case "": 363 return android.Paths{h.outputFilePath}, nil 364 default: 365 return nil, fmt.Errorf("unsupported module reference tag %q", tag) 366 } 367} 368 369// hiddenapi-flags provides access to the hiddenapi-flags.csv file generated during the build. 370func hiddenAPIFlagsFactory() android.Module { 371 module := &hiddenAPIFlags{} 372 module.AddProperties(&module.properties) 373 android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon) 374 return module 375} 376 377func hiddenAPIIndexSingletonFactory() android.Singleton { 378 return &hiddenAPIIndexSingleton{} 379} 380 381type hiddenAPIIndexSingleton struct { 382 index android.Path 383} 384 385func (h *hiddenAPIIndexSingleton) GenerateBuildActions(ctx android.SingletonContext) { 386 // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true 387 if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { 388 return 389 } 390 391 indexes := android.Paths{} 392 ctx.VisitAllModules(func(module android.Module) { 393 if h, ok := module.(hiddenAPIIntf); ok { 394 if h.indexCSV() != nil { 395 indexes = append(indexes, h.indexCSV()) 396 } 397 } 398 }) 399 400 rule := android.NewRuleBuilder() 401 rule.Command(). 402 BuiltTool(ctx, "merge_csv"). 403 FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties"). 404 FlagWithOutput("--output=", hiddenAPISingletonPaths(ctx).index). 405 Inputs(indexes) 406 rule.Build(pctx, ctx, "singleton-merged-hiddenapi-index", "Singleton merged Hidden API index") 407 408 h.index = hiddenAPISingletonPaths(ctx).index 409} 410 411func (h *hiddenAPIIndexSingleton) MakeVars(ctx android.MakeVarsContext) { 412 if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { 413 return 414 } 415 416 ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_INDEX", h.index.String()) 417} 418