1// Copyright (C) 2019 The Android Open Source Project 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 selinux 16 17import ( 18 "fmt" 19 "io" 20 21 "github.com/google/blueprint" 22 "github.com/google/blueprint/proptools" 23 24 "android/soong/android" 25 "android/soong/sysprop" 26) 27 28type selinuxContextsProperties struct { 29 // Filenames under sepolicy directories, which will be used to generate contexts file. 30 Srcs []string `android:"path"` 31 32 // Output file name. Defaults to module name 33 Stem *string 34 35 Product_variables struct { 36 Address_sanitize struct { 37 Srcs []string `android:"path"` 38 } 39 } 40 41 // Whether the comments in generated contexts file will be removed or not. 42 Remove_comment *bool 43 44 // Whether the result context file is sorted with fc_sort or not. 45 Fc_sort *bool 46 47 // Make this module available when building for recovery 48 Recovery_available *bool 49 50 // Board api level of policy files. Set "current" for RELEASE_BOARD_API_LEVEL, or a direct 51 // version string (e.g. "202404"). Defaults to "current" 52 Board_api_level *string 53} 54 55type seappProperties struct { 56 // Files containing neverallow rules. 57 Neverallow_files []string `android:"path"` 58 59 // Precompiled sepolicy binary file which will be fed to checkseapp. 60 Sepolicy *string `android:"path"` 61} 62 63type selinuxContextsModule struct { 64 android.ModuleBase 65 android.DefaultableModuleBase 66 flaggableModuleBase 67 68 properties selinuxContextsProperties 69 seappProperties seappProperties 70 build func(ctx android.ModuleContext, inputs android.Paths) android.Path 71 deps func(ctx android.BottomUpMutatorContext) 72 outputPath android.Path 73 installPath android.InstallPath 74} 75 76var _ flaggableModule = (*selinuxContextsModule)(nil) 77 78var ( 79 reuseContextsDepTag = dependencyTag{name: "reuseContexts"} 80 syspropLibraryDepTag = dependencyTag{name: "sysprop_library"} 81) 82 83func init() { 84 pctx.HostBinToolVariable("fc_sort", "fc_sort") 85 86 android.RegisterModuleType("contexts_defaults", contextsDefaultsFactory) 87 android.RegisterModuleType("file_contexts", fileFactory) 88 android.RegisterModuleType("hwservice_contexts", hwServiceFactory) 89 android.RegisterModuleType("property_contexts", propertyFactory) 90 android.RegisterModuleType("service_contexts", serviceFactory) 91 android.RegisterModuleType("keystore2_key_contexts", keystoreKeyFactory) 92 android.RegisterModuleType("seapp_contexts", seappFactory) 93 android.RegisterModuleType("vndservice_contexts", vndServiceFactory) 94 android.RegisterModuleType("tee_service_contexts", teeServiceFactory) 95 96 android.RegisterModuleType("file_contexts_test", fileContextsTestFactory) 97 android.RegisterModuleType("property_contexts_test", propertyContextsTestFactory) 98 android.RegisterModuleType("hwservice_contexts_test", hwserviceContextsTestFactory) 99 android.RegisterModuleType("service_contexts_test", serviceContextsTestFactory) 100 android.RegisterModuleType("vndservice_contexts_test", vndServiceContextsTestFactory) 101} 102 103func (m *selinuxContextsModule) InstallInRoot() bool { 104 return m.InRecovery() 105} 106 107func (m *selinuxContextsModule) InstallInRecovery() bool { 108 // ModuleBase.InRecovery() checks the image variant 109 return m.InRecovery() 110} 111 112func (m *selinuxContextsModule) onlyInRecovery() bool { 113 // ModuleBase.InstallInRecovery() checks commonProperties.Recovery property 114 return m.ModuleBase.InstallInRecovery() 115} 116 117func (m *selinuxContextsModule) DepsMutator(ctx android.BottomUpMutatorContext) { 118 m.flagDeps(ctx) 119 120 if m.deps != nil { 121 m.deps(ctx) 122 } 123 124 if m.InRecovery() && !m.onlyInRecovery() { 125 ctx.AddFarVariationDependencies([]blueprint.Variation{ 126 {Mutator: "image", Variation: android.CoreVariation}, 127 }, reuseContextsDepTag, ctx.ModuleName()) 128 } 129} 130 131func (m *selinuxContextsModule) propertyContextsDeps(ctx android.BottomUpMutatorContext) { 132 for _, lib := range sysprop.SyspropLibraries(ctx.Config()) { 133 ctx.AddFarVariationDependencies([]blueprint.Variation{}, syspropLibraryDepTag, lib) 134 } 135} 136 137func (m *selinuxContextsModule) stem() string { 138 return proptools.StringDefault(m.properties.Stem, m.Name()) 139} 140 141func (m *selinuxContextsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 142 if m.InRecovery() { 143 // Installing context files at the root of the recovery partition 144 m.installPath = android.PathForModuleInstall(ctx) 145 } else { 146 m.installPath = android.PathForModuleInstall(ctx, "etc", "selinux") 147 } 148 149 if m.InRecovery() && !m.onlyInRecovery() { 150 dep := ctx.GetDirectDepWithTag(m.Name(), reuseContextsDepTag) 151 152 if reuseDeps, ok := dep.(*selinuxContextsModule); ok { 153 m.outputPath = reuseDeps.outputPath 154 ctx.InstallFile(m.installPath, m.stem(), m.outputPath) 155 return 156 } 157 } 158 159 m.outputPath = m.build(ctx, android.PathsForModuleSrc(ctx, m.properties.Srcs)) 160 ctx.InstallFile(m.installPath, m.stem(), m.outputPath) 161 162 ctx.SetOutputFiles([]android.Path{m.outputPath}, "") 163} 164 165func newModule() *selinuxContextsModule { 166 m := &selinuxContextsModule{} 167 m.AddProperties( 168 &m.properties, 169 &m.seappProperties, 170 ) 171 initFlaggableModule(m) 172 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) 173 android.InitDefaultableModule(m) 174 android.AddLoadHook(m, func(ctx android.LoadHookContext) { 175 m.selinuxContextsHook(ctx) 176 }) 177 return m 178} 179 180type contextsDefaults struct { 181 android.ModuleBase 182 android.DefaultsModuleBase 183} 184 185// contexts_defaults provides a set of properties that can be inherited by other contexts modules. 186// (file_contexts, property_contexts, seapp_contexts, etc.) A module can use the properties from a 187// contexts_defaults using `defaults: ["<:default_module_name>"]`. Properties of both modules are 188// erged (when possible) by prepending the default module's values to the depending module's values. 189func contextsDefaultsFactory() android.Module { 190 m := &contextsDefaults{} 191 m.AddProperties( 192 &selinuxContextsProperties{}, 193 &seappProperties{}, 194 &flaggableModuleProperties{}, 195 ) 196 android.InitDefaultsModule(m) 197 return m 198} 199 200func (m *selinuxContextsModule) selinuxContextsHook(ctx android.LoadHookContext) { 201 // TODO: clean this up to use build/soong/android/variable.go after b/79249983 202 var srcs []string 203 204 for _, sanitize := range ctx.Config().SanitizeDevice() { 205 if sanitize == "address" { 206 srcs = append(srcs, m.properties.Product_variables.Address_sanitize.Srcs...) 207 break 208 } 209 } 210 211 m.properties.Srcs = append(m.properties.Srcs, srcs...) 212} 213 214func (m *selinuxContextsModule) AndroidMk() android.AndroidMkData { 215 nameSuffix := "" 216 if m.InRecovery() && !m.onlyInRecovery() { 217 nameSuffix = ".recovery" 218 } 219 return android.AndroidMkData{ 220 Class: "ETC", 221 OutputFile: android.OptionalPathForPath(m.outputPath), 222 SubName: nameSuffix, 223 Extra: []android.AndroidMkExtraFunc{ 224 func(w io.Writer, outputFile android.Path) { 225 fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", m.installPath.String()) 226 fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", m.stem()) 227 }, 228 }, 229 } 230} 231 232func (m *selinuxContextsModule) ImageMutatorBegin(ctx android.ImageInterfaceContext) { 233 if proptools.Bool(m.properties.Recovery_available) && m.ModuleBase.InstallInRecovery() { 234 ctx.PropertyErrorf("recovery_available", 235 "doesn't make sense at the same time as `recovery: true`") 236 } 237} 238 239func (m *selinuxContextsModule) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool { 240 return false 241} 242 243func (m *selinuxContextsModule) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool { 244 return false 245} 246 247func (m *selinuxContextsModule) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool { 248 return !m.ModuleBase.InstallInRecovery() 249} 250 251func (m *selinuxContextsModule) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool { 252 return false 253} 254 255func (m *selinuxContextsModule) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool { 256 return false 257} 258 259func (m *selinuxContextsModule) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool { 260 return false 261} 262 263func (m *selinuxContextsModule) RecoveryVariantNeeded(ctx android.ImageInterfaceContext) bool { 264 return m.ModuleBase.InstallInRecovery() || proptools.Bool(m.properties.Recovery_available) 265} 266 267func (m *selinuxContextsModule) ExtraImageVariations(ctx android.ImageInterfaceContext) []string { 268 return nil 269} 270 271func (m *selinuxContextsModule) SetImageVariation(ctx android.ImageInterfaceContext, variation string) { 272} 273 274var _ android.ImageInterface = (*selinuxContextsModule)(nil) 275 276func (m *selinuxContextsModule) buildGeneralContexts(ctx android.ModuleContext, inputs android.Paths) android.Path { 277 builtContext := pathForModuleOut(ctx, ctx.ModuleName()+"_m4out") 278 279 rule := android.NewRuleBuilder(pctx, ctx) 280 281 newlineFile := pathForModuleOut(ctx, "newline") 282 283 rule.Command().Text("echo").FlagWithOutput("> ", newlineFile) 284 rule.Temporary(newlineFile) 285 286 var inputsWithNewline android.Paths 287 for _, input := range inputs { 288 inputsWithNewline = append(inputsWithNewline, input, newlineFile) 289 } 290 291 flags := m.getBuildFlags(ctx) 292 rule.Command(). 293 Tool(ctx.Config().PrebuiltBuildTool(ctx, "m4")). 294 Text("--fatal-warnings -s"). 295 FlagForEachArg("-D", ctx.DeviceConfig().SepolicyM4Defs()). 296 Flag(boardApiLevelToM4Macro(ctx, m.properties.Board_api_level)). 297 Flags(flagsToM4Macros(flags)). 298 Inputs(inputsWithNewline). 299 FlagWithOutput("> ", builtContext) 300 301 if proptools.Bool(m.properties.Remove_comment) { 302 rule.Temporary(builtContext) 303 304 remove_comment_output := pathForModuleOut(ctx, ctx.ModuleName()+"_remove_comment") 305 306 rule.Command(). 307 Text("sed -e 's/#.*$//' -e '/^$/d'"). 308 Input(builtContext). 309 FlagWithOutput("> ", remove_comment_output) 310 311 builtContext = remove_comment_output 312 } 313 314 if proptools.Bool(m.properties.Fc_sort) { 315 rule.Temporary(builtContext) 316 317 sorted_output := pathForModuleOut(ctx, ctx.ModuleName()+"_sorted") 318 319 rule.Command(). 320 Tool(ctx.Config().HostToolPath(ctx, "fc_sort")). 321 FlagWithInput("-i ", builtContext). 322 FlagWithOutput("-o ", sorted_output) 323 324 builtContext = sorted_output 325 } 326 327 ret := pathForModuleOut(ctx, m.stem()) 328 rule.Temporary(builtContext) 329 rule.Command().Text("cp").Input(builtContext).Output(ret) 330 331 rule.DeleteTemporaryFiles() 332 rule.Build("selinux_contexts", "building contexts: "+m.Name()) 333 334 return ret 335} 336 337func (m *selinuxContextsModule) buildFileContexts(ctx android.ModuleContext, inputs android.Paths) android.Path { 338 if m.properties.Remove_comment == nil { 339 m.properties.Remove_comment = proptools.BoolPtr(true) 340 } 341 return m.buildGeneralContexts(ctx, inputs) 342} 343 344func fileFactory() android.Module { 345 m := newModule() 346 m.build = m.buildFileContexts 347 return m 348} 349 350func (m *selinuxContextsModule) buildServiceContexts(ctx android.ModuleContext, inputs android.Paths) android.Path { 351 if m.properties.Remove_comment == nil { 352 m.properties.Remove_comment = proptools.BoolPtr(true) 353 } 354 355 return m.buildGeneralContexts(ctx, inputs) 356} 357 358func (m *selinuxContextsModule) checkVendorPropertyNamespace(ctx android.ModuleContext, input android.Path) android.Path { 359 shippingApiLevel := ctx.DeviceConfig().ShippingApiLevel() 360 ApiLevelR := android.ApiLevelOrPanic(ctx, "R") 361 362 rule := android.NewRuleBuilder(pctx, ctx) 363 364 // This list is from vts_treble_sys_prop_test. 365 allowedPropertyPrefixes := []string{ 366 "ctl.odm.", 367 "ctl.vendor.", 368 "ctl.start$odm.", 369 "ctl.start$vendor.", 370 "ctl.stop$odm.", 371 "ctl.stop$vendor.", 372 "init.svc.odm.", 373 "init.svc.vendor.", 374 "ro.boot.", 375 "ro.hardware.", 376 "ro.odm.", 377 "ro.vendor.", 378 "odm.", 379 "persist.odm.", 380 "persist.vendor.", 381 "vendor.", 382 } 383 384 // persist.camera is also allowed for devices launching with R or eariler 385 if shippingApiLevel.LessThanOrEqualTo(ApiLevelR) { 386 allowedPropertyPrefixes = append(allowedPropertyPrefixes, "persist.camera.") 387 } 388 389 var allowedContextPrefixes []string 390 391 if shippingApiLevel.GreaterThanOrEqualTo(ApiLevelR) { 392 // This list is from vts_treble_sys_prop_test. 393 allowedContextPrefixes = []string{ 394 "vendor_", 395 "odm_", 396 } 397 } 398 399 cmd := rule.Command(). 400 BuiltTool("check_prop_prefix"). 401 FlagWithInput("--property-contexts ", input). 402 FlagForEachArg("--allowed-property-prefix ", proptools.ShellEscapeList(allowedPropertyPrefixes)). // contains shell special character '$' 403 FlagForEachArg("--allowed-context-prefix ", allowedContextPrefixes) 404 405 if !ctx.DeviceConfig().BuildBrokenVendorPropertyNamespace() { 406 cmd.Flag("--strict") 407 } 408 409 out := pathForModuleOut(ctx, ctx.ModuleName()+"_namespace_checked") 410 rule.Command().Text("cp -f").Input(input).Output(out) 411 rule.Build("check_namespace", "checking namespace of "+ctx.ModuleName()) 412 return out 413} 414 415func (m *selinuxContextsModule) buildPropertyContexts(ctx android.ModuleContext, inputs android.Paths) android.Path { 416 // vendor/odm properties are enforced for devices launching with Android Q or later. So, if 417 // vendor/odm, make sure that only vendor/odm properties exist. 418 builtCtxFile := m.buildGeneralContexts(ctx, inputs) 419 420 shippingApiLevel := ctx.DeviceConfig().ShippingApiLevel() 421 ApiLevelQ := android.ApiLevelOrPanic(ctx, "Q") 422 if (ctx.SocSpecific() || ctx.DeviceSpecific()) && shippingApiLevel.GreaterThanOrEqualTo(ApiLevelQ) { 423 builtCtxFile = m.checkVendorPropertyNamespace(ctx, builtCtxFile) 424 } 425 426 var apiFiles android.Paths 427 ctx.VisitDirectDepsWithTag(syspropLibraryDepTag, func(c android.Module) { 428 i, ok := c.(interface{ CurrentSyspropApiFile() android.OptionalPath }) 429 if !ok { 430 panic(fmt.Errorf("unknown dependency %q for %q", ctx.OtherModuleName(c), ctx.ModuleName())) 431 } 432 if api := i.CurrentSyspropApiFile(); api.Valid() { 433 apiFiles = append(apiFiles, api.Path()) 434 } 435 }) 436 437 // check compatibility with sysprop_library 438 if len(apiFiles) > 0 { 439 out := pathForModuleOut(ctx, ctx.ModuleName()+"_api_checked") 440 rule := android.NewRuleBuilder(pctx, ctx) 441 442 msg := `\n******************************\n` + 443 `API of sysprop_library doesn't match with property_contexts\n` + 444 `Please fix the breakage and rebuild.\n` + 445 `******************************\n` 446 447 rule.Command(). 448 Text("( "). 449 BuiltTool("sysprop_type_checker"). 450 FlagForEachInput("--api ", apiFiles). 451 FlagWithInput("--context ", builtCtxFile). 452 Text(" || ( echo").Flag("-e"). 453 Flag(`"` + msg + `"`). 454 Text("; exit 38) )") 455 456 rule.Command().Text("cp -f").Input(builtCtxFile).Output(out) 457 rule.Build("property_contexts_check_api", "checking API: "+m.Name()) 458 builtCtxFile = out 459 } 460 461 return builtCtxFile 462} 463 464func (m *selinuxContextsModule) shouldCheckCoredomain(ctx android.ModuleContext) bool { 465 if !ctx.SocSpecific() && !ctx.DeviceSpecific() { 466 return false 467 } 468 469 return ctx.DeviceConfig().CheckVendorSeappViolations() 470} 471 472func (m *selinuxContextsModule) buildSeappContexts(ctx android.ModuleContext, inputs android.Paths) android.Path { 473 neverallowFile := pathForModuleOut(ctx, "neverallow") 474 ret := pathForModuleOut(ctx, "checkseapp", m.stem()) 475 476 // Step 1. Generate a M4 processed neverallow file 477 flags := m.getBuildFlags(ctx) 478 m4NeverallowFile := pathForModuleOut(ctx, "neverallow.m4out") 479 rule := android.NewRuleBuilder(pctx, ctx) 480 rule.Command(). 481 Tool(ctx.Config().PrebuiltBuildTool(ctx, "m4")). 482 Flag("--fatal-warnings"). 483 FlagForEachArg("-D", ctx.DeviceConfig().SepolicyM4Defs()). 484 Flags(flagsToM4Macros(flags)). 485 Inputs(android.PathsForModuleSrc(ctx, m.seappProperties.Neverallow_files)). 486 FlagWithOutput("> ", m4NeverallowFile) 487 488 rule.Temporary(m4NeverallowFile) 489 rule.Command(). 490 Text("( grep"). 491 Flag("-ihe"). 492 Text("'^neverallow'"). 493 Input(m4NeverallowFile). 494 Text(">"). 495 Output(neverallowFile). 496 Text("|| true )") // to make ninja happy even when result is empty 497 498 // Step 2. Generate a M4 processed contexts file 499 builtCtx := m.buildGeneralContexts(ctx, inputs) 500 501 // Step 3. checkseapp 502 rule.Temporary(neverallowFile) 503 checkCmd := rule.Command().BuiltTool("checkseapp"). 504 FlagWithInput("-p ", android.PathForModuleSrc(ctx, proptools.String(m.seappProperties.Sepolicy))). 505 FlagWithOutput("-o ", ret). 506 Input(builtCtx). 507 Input(neverallowFile) 508 509 if m.shouldCheckCoredomain(ctx) { 510 checkCmd.Flag("-c") // check coredomain for vendor contexts 511 } 512 513 rule.Build("seapp_contexts", "Building seapp_contexts: "+m.Name()) 514 return ret 515} 516 517func hwServiceFactory() android.Module { 518 m := newModule() 519 m.build = m.buildServiceContexts 520 return m 521} 522 523func propertyFactory() android.Module { 524 m := newModule() 525 m.build = m.buildPropertyContexts 526 m.deps = m.propertyContextsDeps 527 return m 528} 529 530func serviceFactory() android.Module { 531 m := newModule() 532 m.build = m.buildServiceContexts 533 return m 534} 535 536func keystoreKeyFactory() android.Module { 537 m := newModule() 538 m.build = m.buildGeneralContexts 539 return m 540} 541 542func teeServiceFactory() android.Module { 543 m := newModule() 544 m.build = m.buildGeneralContexts 545 return m 546} 547 548func seappFactory() android.Module { 549 m := newModule() 550 m.build = m.buildSeappContexts 551 return m 552} 553 554func vndServiceFactory() android.Module { 555 m := newModule() 556 m.build = m.buildGeneralContexts 557 android.AddLoadHook(m, func(ctx android.LoadHookContext) { 558 if !ctx.SocSpecific() { 559 ctx.ModuleErrorf(m.Name(), "must set vendor: true") 560 return 561 } 562 }) 563 return m 564} 565 566type contextsTestProperties struct { 567 // Contexts files to be tested. 568 Srcs []string `android:"path"` 569 570 // Precompiled sepolicy binary to be tesed together. 571 Sepolicy *string `android:"path"` 572} 573 574type fileContextsTestProperties struct { 575 // Test data. File passed to `checkfc -t` to validate how contexts are resolved. 576 Test_data *string `android:"path"` 577} 578 579type contextsTestModule struct { 580 android.ModuleBase 581 582 // The type of context. 583 context contextType 584 585 properties contextsTestProperties 586 fileProperties fileContextsTestProperties 587 testTimestamp android.OutputPath 588} 589 590type contextType int 591 592const ( 593 FileContext contextType = iota 594 PropertyContext 595 ServiceContext 596 HwServiceContext 597 VndServiceContext 598) 599 600// checkfc parses a context file and checks for syntax errors. 601// If -s is specified, the service backend is used to verify binder services. 602// If -l is specified, the service backend is used to verify hwbinder services. 603// Otherwise, context_file is assumed to be a file_contexts file 604// If -e is specified, then the context_file is allowed to be empty. 605 606// file_contexts_test tests given file_contexts files with checkfc. 607func fileContextsTestFactory() android.Module { 608 m := &contextsTestModule{context: FileContext} 609 m.AddProperties(&m.properties) 610 m.AddProperties(&m.fileProperties) 611 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) 612 return m 613} 614 615// property_contexts_test tests given property_contexts files with property_info_checker. 616func propertyContextsTestFactory() android.Module { 617 m := &contextsTestModule{context: PropertyContext} 618 m.AddProperties(&m.properties) 619 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) 620 return m 621} 622 623// hwservice_contexts_test tests given hwservice_contexts files with checkfc. 624func hwserviceContextsTestFactory() android.Module { 625 m := &contextsTestModule{context: HwServiceContext} 626 m.AddProperties(&m.properties) 627 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) 628 return m 629} 630 631// service_contexts_test tests given service_contexts files with checkfc. 632func serviceContextsTestFactory() android.Module { 633 // checkfc -s: service_contexts test 634 m := &contextsTestModule{context: ServiceContext} 635 m.AddProperties(&m.properties) 636 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) 637 return m 638} 639 640// vndservice_contexts_test tests given vndservice_contexts files with checkfc. 641func vndServiceContextsTestFactory() android.Module { 642 m := &contextsTestModule{context: VndServiceContext} 643 m.AddProperties(&m.properties) 644 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) 645 return m 646} 647 648func (m *contextsTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 649 tool := "checkfc" 650 if m.context == PropertyContext { 651 tool = "property_info_checker" 652 } 653 654 if len(m.properties.Srcs) == 0 { 655 ctx.PropertyErrorf("srcs", "can't be empty") 656 return 657 } 658 659 validateWithPolicy := true 660 if proptools.String(m.properties.Sepolicy) == "" { 661 if m.context == FileContext { 662 if proptools.String(m.fileProperties.Test_data) == "" { 663 ctx.PropertyErrorf("test_data", "Either test_data or sepolicy should be provided") 664 return 665 } 666 validateWithPolicy = false 667 } else { 668 ctx.PropertyErrorf("sepolicy", "can't be empty") 669 return 670 } 671 } 672 673 flags := []string(nil) 674 switch m.context { 675 case FileContext: 676 if !validateWithPolicy { 677 flags = []string{"-t"} 678 } 679 case ServiceContext: 680 flags = []string{"-s" /* binder services */} 681 case HwServiceContext: 682 flags = []string{"-e" /* allow empty */, "-l" /* hwbinder services */} 683 case VndServiceContext: 684 flags = []string{"-e" /* allow empty */, "-v" /* vnd service */} 685 } 686 687 srcs := android.PathsForModuleSrc(ctx, m.properties.Srcs) 688 rule := android.NewRuleBuilder(pctx, ctx) 689 690 if validateWithPolicy { 691 sepolicy := android.PathForModuleSrc(ctx, proptools.String(m.properties.Sepolicy)) 692 rule.Command().BuiltTool(tool). 693 Flags(flags). 694 Input(sepolicy). 695 Inputs(srcs) 696 } else { 697 test_data := android.PathForModuleSrc(ctx, proptools.String(m.fileProperties.Test_data)) 698 rule.Command().BuiltTool(tool). 699 Flags(flags). 700 Inputs(srcs). 701 Input(test_data) 702 } 703 704 m.testTimestamp = pathForModuleOut(ctx, "timestamp") 705 rule.Command().Text("touch").Output(m.testTimestamp) 706 rule.Build("contexts_test", "running contexts test: "+ctx.ModuleName()) 707} 708 709func (m *contextsTestModule) AndroidMkEntries() []android.AndroidMkEntries { 710 return []android.AndroidMkEntries{android.AndroidMkEntries{ 711 Class: "FAKE", 712 // OutputFile is needed, even though BUILD_PHONY_PACKAGE doesn't use it. 713 // Without OutputFile this module won't be exported to Makefile. 714 OutputFile: android.OptionalPathForPath(m.testTimestamp), 715 Include: "$(BUILD_PHONY_PACKAGE)", 716 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 717 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 718 entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", m.testTimestamp.String()) 719 }, 720 }, 721 }} 722} 723 724// contextsTestModule implements ImageInterface to be able to include recovery_available contexts 725// modules as its sources. 726func (m *contextsTestModule) ImageMutatorBegin(ctx android.ImageInterfaceContext) { 727} 728 729func (m *contextsTestModule) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool { 730 return false 731} 732 733func (m *contextsTestModule) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool { 734 return false 735} 736 737func (m *contextsTestModule) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool { 738 return true 739} 740 741func (m *contextsTestModule) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool { 742 return false 743} 744 745func (m *contextsTestModule) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool { 746 return false 747} 748 749func (m *contextsTestModule) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool { 750 return false 751} 752 753func (m *contextsTestModule) RecoveryVariantNeeded(ctx android.ImageInterfaceContext) bool { 754 return false 755} 756 757func (m *contextsTestModule) ExtraImageVariations(ctx android.ImageInterfaceContext) []string { 758 return nil 759} 760 761func (m *contextsTestModule) SetImageVariation(ctx android.ImageInterfaceContext, variation string) { 762} 763 764var _ android.ImageInterface = (*contextsTestModule)(nil) 765