Merge "Collect kythe, obj and tidy files using ModuleProxy." into main
diff --git a/android/Android.bp b/android/Android.bp
index cf707bd..a9a3564 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -31,6 +31,7 @@
srcs: [
"aconfig_providers.go",
"all_teams.go",
+ "android_info.go",
"androidmk.go",
"apex.go",
"apex_contributions.go",
@@ -121,6 +122,7 @@
"apex_test.go",
"arch_test.go",
"blueprint_e2e_test.go",
+ "build_prop_test.go",
"config_test.go",
"configured_jars_test.go",
"csuite_config_test.go",
diff --git a/android/android_info.go b/android/android_info.go
new file mode 100644
index 0000000..dd78ee4
--- /dev/null
+++ b/android/android_info.go
@@ -0,0 +1,77 @@
+// Copyright 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+ "github.com/google/blueprint/proptools"
+)
+
+type androidInfoProperties struct {
+ // Name of output file. Defaults to module name
+ Stem *string
+
+ // Paths of board-info.txt files.
+ Board_info_files []string `android:"path"`
+
+ // Name of bootloader board. If board_info_files is empty, `board={bootloader_board_name}` will
+ // be printed to output. Ignored if board_info_files is not empty.
+ Bootloader_board_name *string
+}
+
+type androidInfoModule struct {
+ ModuleBase
+
+ properties androidInfoProperties
+}
+
+func (p *androidInfoModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ if len(p.properties.Board_info_files) > 0 && p.properties.Bootloader_board_name != nil {
+ ctx.ModuleErrorf("Either Board_info_files or Bootloader_board_name should be set. Please remove one of them\n")
+ return
+ }
+ outName := proptools.StringDefault(p.properties.Stem, ctx.ModuleName()+".txt")
+ androidInfoTxt := PathForModuleOut(ctx, outName).OutputPath
+ androidInfoProp := androidInfoTxt.ReplaceExtension(ctx, "prop")
+
+ rule := NewRuleBuilder(pctx, ctx)
+
+ if boardInfoFiles := PathsForModuleSrc(ctx, p.properties.Board_info_files); len(boardInfoFiles) > 0 {
+ rule.Command().Text("cat").Inputs(boardInfoFiles).
+ Text(" | grep").FlagWithArg("-v ", "'#'").FlagWithOutput("> ", androidInfoTxt)
+ } else if bootloaderBoardName := proptools.String(p.properties.Bootloader_board_name); bootloaderBoardName != "" {
+ rule.Command().Text("echo").Text("'board="+bootloaderBoardName+"'").FlagWithOutput("> ", androidInfoTxt)
+ } else {
+ rule.Command().Text("echo").Text("''").FlagWithOutput("> ", androidInfoTxt)
+ }
+
+ rule.Build(ctx.ModuleName(), "generating android-info.prop")
+
+ // Create android_info.prop
+ rule = NewRuleBuilder(pctx, ctx)
+ rule.Command().Text("cat").Input(androidInfoTxt).
+ Text(" | grep 'require version-' | sed -e 's/require version-/ro.build.expect./g' >").Output(androidInfoProp)
+ rule.Build(ctx.ModuleName()+"prop", "generating android-info.prop")
+
+ ctx.SetOutputFiles(Paths{androidInfoProp}, "")
+}
+
+// android_info module generate a file named android-info.txt that contains various information
+// about the device we're building for. This file is typically packaged up with everything else.
+func AndroidInfoFactory() Module {
+ module := &androidInfoModule{}
+ module.AddProperties(&module.properties)
+ InitAndroidModule(module)
+ return module
+}
diff --git a/android/base_module_context.go b/android/base_module_context.go
index 223b534..02c0158 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -17,6 +17,7 @@
import (
"fmt"
"regexp"
+ "slices"
"strings"
"github.com/google/blueprint"
@@ -570,7 +571,7 @@
}
func (b *baseModuleContext) GetWalkPath() []Module {
- return b.walkPath
+ return slices.Clone(b.walkPath)
}
func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag {
diff --git a/android/build_prop.go b/android/build_prop.go
index 7c3c506..5547680 100644
--- a/android/build_prop.go
+++ b/android/build_prop.go
@@ -19,8 +19,12 @@
)
func init() {
- ctx := InitRegistrationContext
+ registerBuildPropComponents(InitRegistrationContext)
+}
+
+func registerBuildPropComponents(ctx RegistrationContext) {
ctx.RegisterModuleType("build_prop", BuildPropFactory)
+ ctx.RegisterModuleType("android_info", AndroidInfoFactory)
}
type buildPropProperties struct {
@@ -38,6 +42,10 @@
// Path to a JSON file containing product configs.
Product_config *string `android:"path"`
+ // Path to android-info.txt file containing board specific info.
+ // This is empty for build.prop of all partitions except vendor.
+ Android_info *string `android:"path"`
+
// Optional subdirectory under which this file is installed into
Relative_install_path *string
}
@@ -66,7 +74,10 @@
} else if partition == "odm" {
return ctx.Config().OdmPropFiles(ctx)
} else if partition == "vendor" {
- // TODO (b/375500423): Add android-info.txt to prop files
+ if p.properties.Android_info != nil {
+ androidInfo := PathForModuleSrc(ctx, proptools.String(p.properties.Android_info))
+ return append(ctx.Config().VendorPropFiles(ctx), androidInfo)
+ }
return ctx.Config().VendorPropFiles(ctx)
}
return nil
@@ -111,13 +122,12 @@
}
func (p *buildPropModule) GenerateAndroidBuildActions(ctx ModuleContext) {
- p.outputFilePath = PathForModuleOut(ctx, "build.prop").OutputPath
- if !ctx.Config().KatiEnabled() {
- WriteFileRule(ctx, p.outputFilePath, "# no build.prop if kati is disabled")
- ctx.SetOutputFiles(Paths{p.outputFilePath}, "")
- return
+ if !p.SocSpecific() && p.properties.Android_info != nil {
+ ctx.ModuleErrorf("Android_info cannot be set if build.prop is not installed in vendor partition")
}
+ p.outputFilePath = PathForModuleOut(ctx, "build.prop").OutputPath
+
partition := p.partition(ctx.DeviceConfig())
if !InList(partition, validPartitions) {
ctx.PropertyErrorf("partition", "unsupported partition %q: only %q are supported", partition, validPartitions)
diff --git a/android/build_prop_test.go b/android/build_prop_test.go
new file mode 100644
index 0000000..e75975a
--- /dev/null
+++ b/android/build_prop_test.go
@@ -0,0 +1,41 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+ "testing"
+)
+
+func TestPropFileInputs(t *testing.T) {
+ bp := `
+build_prop {
+ name: "vendor-build.prop",
+ stem: "build.prop",
+ vendor: true,
+ android_info: ":board-info",
+ //product_config: ":product_config",
+}
+android_info {
+ name: "board-info",
+ stem: "android-info.txt",
+}
+`
+
+ res := GroupFixturePreparers(
+ FixtureRegisterWithContext(registerBuildPropComponents),
+ ).RunTestWithBp(t, bp)
+ buildPropCmd := res.ModuleForTests("vendor-build.prop", "").Rule("vendor-build.prop_.vendor-build.prop").RuleParams.Command
+ AssertStringDoesContain(t, "Could not find android-info in prop files of vendor build.prop", buildPropCmd, "--prop-files=out/soong/.intermediates/board-info/android-info.prop")
+}
diff --git a/android/config.go b/android/config.go
index 16d77db..275c07f 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1522,6 +1522,13 @@
return "vendor"
}
+func (c *deviceConfig) VendorDlkmPath() string {
+ if c.config.productVariables.VendorDlkmPath != nil {
+ return *c.config.productVariables.VendorDlkmPath
+ }
+ return "vendor_dlkm"
+}
+
func (c *deviceConfig) BuildingVendorImage() bool {
return proptools.Bool(c.config.productVariables.BuildingVendorImage)
}
@@ -1553,6 +1560,13 @@
return proptools.Bool(c.config.productVariables.BuildingOdmImage)
}
+func (c *deviceConfig) OdmDlkmPath() string {
+ if c.config.productVariables.OdmDlkmPath != nil {
+ return *c.config.productVariables.OdmDlkmPath
+ }
+ return "odm_dlkm"
+}
+
func (c *deviceConfig) ProductPath() string {
if c.config.productVariables.ProductPath != nil {
return *c.config.productVariables.ProductPath
@@ -1571,6 +1585,20 @@
return "system_ext"
}
+func (c *deviceConfig) SystemDlkmPath() string {
+ if c.config.productVariables.SystemDlkmPath != nil {
+ return *c.config.productVariables.SystemDlkmPath
+ }
+ return "system_dlkm"
+}
+
+func (c *deviceConfig) OemPath() string {
+ if c.config.productVariables.OemPath != nil {
+ return *c.config.productVariables.OemPath
+ }
+ return "oem"
+}
+
func (c *deviceConfig) BtConfigIncludeDir() string {
return String(c.config.productVariables.BtConfigIncludeDir)
}
diff --git a/android/variable.go b/android/variable.go
index df9db7c..142fab9 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -339,12 +339,16 @@
HWASanExcludePaths []string `json:",omitempty"`
VendorPath *string `json:",omitempty"`
+ VendorDlkmPath *string `json:",omitempty"`
BuildingVendorImage *bool `json:",omitempty"`
OdmPath *string `json:",omitempty"`
BuildingOdmImage *bool `json:",omitempty"`
+ OdmDlkmPath *string `json:",omitempty"`
ProductPath *string `json:",omitempty"`
BuildingProductImage *bool `json:",omitempty"`
SystemExtPath *string `json:",omitempty"`
+ SystemDlkmPath *string `json:",omitempty"`
+ OemPath *string `json:",omitempty"`
ClangTidy *bool `json:",omitempty"`
TidyChecks *string `json:",omitempty"`
@@ -604,6 +608,9 @@
VendorLinkerConfigSrcs []string `json:",omitempty"`
ProductLinkerConfigSrcs []string `json:",omitempty"`
+ BoardInfoFiles []string `json:",omitempty"`
+ BootLoaderBoardName string `json:",omitempty"`
+
ProductCopyFiles map[string]string `json:",omitempty"`
BuildingSystemDlkmImage bool `json:",omitempty"`
diff --git a/apex/Android.bp b/apex/Android.bp
index 0e2f564..870ca7e 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -7,6 +7,7 @@
pkgPath: "android/soong/apex",
deps: [
"blueprint",
+ "blueprint-bpmodify",
"soong",
"soong-aconfig",
"soong-aconfig-codegen",
diff --git a/apex/apex.go b/apex/apex.go
index 80af9c5..587f63f 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -20,10 +20,12 @@
"fmt"
"path/filepath"
"regexp"
+ "slices"
"sort"
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/depset"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -464,6 +466,12 @@
// GenerateAndroidBuildActions.
filesInfo []apexFile
+ // List of files that were excluded by the unwanted_transitive_deps property.
+ unwantedTransitiveFilesInfo []apexFile
+
+ // List of files that were excluded due to conflicts with other variants of the same module.
+ duplicateTransitiveFilesInfo []apexFile
+
// List of other module names that should be installed when this APEX gets installed (LOCAL_REQUIRED_MODULES).
makeModulesToInstall []string
@@ -1877,6 +1885,14 @@
// visitor skips these from this list of module names
unwantedTransitiveDeps []string
+
+ // unwantedTransitiveFilesInfo contains files that would have been in the apex
+ // except that they were listed in unwantedTransitiveDeps.
+ unwantedTransitiveFilesInfo []apexFile
+
+ // duplicateTransitiveFilesInfo contains files that would ahve been in the apex
+ // except that another variant of the same module was already in the apex.
+ duplicateTransitiveFilesInfo []apexFile
}
func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) {
@@ -1887,6 +1903,7 @@
// Needs additional verification for the resulting APEX to ensure that skipped artifacts don't make problems.
// For example, DT_NEEDED modules should be found within the APEX unless they are marked in `requiredNativeLibs`.
if f.transitiveDep && f.module != nil && android.InList(mctx.OtherModuleName(f.module), vctx.unwantedTransitiveDeps) {
+ vctx.unwantedTransitiveFilesInfo = append(vctx.unwantedTransitiveFilesInfo, f)
continue
}
dest := filepath.Join(f.installDir, f.builtFile.Base())
@@ -1897,6 +1914,8 @@
mctx.ModuleErrorf("apex file %v is provided by two different files %v and %v",
dest, e.builtFile, f.builtFile)
return
+ } else {
+ vctx.duplicateTransitiveFilesInfo = append(vctx.duplicateTransitiveFilesInfo, f)
}
// If a module is directly included and also transitively depended on
// consider it as directly included.
@@ -1911,6 +1930,7 @@
for _, v := range encountered {
vctx.filesInfo = append(vctx.filesInfo, v)
}
+
sort.Slice(vctx.filesInfo, func(i, j int) bool {
// Sort by destination path so as to ensure consistent ordering even if the source of the files
// changes.
@@ -2341,6 +2361,8 @@
// 3) some fields in apexBundle struct are configured
a.installDir = android.PathForModuleInstall(ctx, "apex")
a.filesInfo = vctx.filesInfo
+ a.unwantedTransitiveFilesInfo = vctx.unwantedTransitiveFilesInfo
+ a.duplicateTransitiveFilesInfo = vctx.duplicateTransitiveFilesInfo
a.setPayloadFsType(ctx)
a.setSystemLibLink(ctx)
@@ -2367,6 +2389,8 @@
a.setOutputFiles(ctx)
a.enforcePartitionTagOnApexSystemServerJar(ctx)
+
+ a.verifyNativeImplementationLibs(ctx)
}
// Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file
@@ -2920,3 +2944,105 @@
func (a *apexBundle) IsTestApex() bool {
return a.testApex
}
+
+// verifyNativeImplementationLibs compares the list of transitive implementation libraries used to link native
+// libraries in the apex against the list of implementation libraries in the apex, ensuring that none of the
+// libraries in the apex have references to private APIs from outside the apex.
+func (a *apexBundle) verifyNativeImplementationLibs(ctx android.ModuleContext) {
+ var directImplementationLibs android.Paths
+ var transitiveImplementationLibs []depset.DepSet[android.Path]
+
+ if a.properties.IsCoverageVariant {
+ return
+ }
+
+ if a.testApex {
+ return
+ }
+
+ if a.UsePlatformApis() {
+ return
+ }
+
+ checkApexTag := func(tag blueprint.DependencyTag) bool {
+ switch tag {
+ case sharedLibTag, jniLibTag, executableTag, androidAppTag:
+ return true
+ default:
+ return false
+ }
+ }
+
+ checkTransitiveTag := func(tag blueprint.DependencyTag) bool {
+ switch {
+ case cc.IsSharedDepTag(tag), java.IsJniDepTag(tag), rust.IsRlibDepTag(tag), rust.IsDylibDepTag(tag), checkApexTag(tag):
+ return true
+ default:
+ return false
+ }
+ }
+
+ var appEmbeddedJNILibs android.Paths
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ tag := ctx.OtherModuleDependencyTag(dep)
+ if !checkApexTag(tag) {
+ return
+ }
+ if tag == sharedLibTag || tag == jniLibTag {
+ outputFile := android.OutputFileForModule(ctx, dep, "")
+ directImplementationLibs = append(directImplementationLibs, outputFile)
+ }
+ if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
+ transitiveImplementationLibs = append(transitiveImplementationLibs, info.ImplementationDeps)
+ }
+ if info, ok := android.OtherModuleProvider(ctx, dep, java.AppInfoProvider); ok {
+ appEmbeddedJNILibs = append(appEmbeddedJNILibs, info.EmbeddedJNILibs...)
+ }
+ })
+
+ depSet := depset.New(depset.PREORDER, directImplementationLibs, transitiveImplementationLibs)
+ allImplementationLibs := depSet.ToList()
+
+ allFileInfos := slices.Concat(a.filesInfo, a.unwantedTransitiveFilesInfo, a.duplicateTransitiveFilesInfo)
+
+ for _, lib := range allImplementationLibs {
+ inApex := slices.ContainsFunc(allFileInfos, func(fi apexFile) bool {
+ return fi.builtFile == lib
+ })
+ inApkInApex := slices.Contains(appEmbeddedJNILibs, lib)
+
+ if !inApex && !inApkInApex {
+ ctx.ModuleErrorf("library in apex transitively linked against implementation library %q not in apex", lib)
+ var depPath []android.Module
+ ctx.WalkDeps(func(child, parent android.Module) bool {
+ if depPath != nil {
+ return false
+ }
+
+ tag := ctx.OtherModuleDependencyTag(child)
+
+ if parent == ctx.Module() {
+ if !checkApexTag(tag) {
+ return false
+ }
+ }
+
+ if checkTransitiveTag(tag) {
+ if android.OutputFileForModule(ctx, child, "") == lib {
+ depPath = ctx.GetWalkPath()
+ }
+ return true
+ }
+
+ return false
+ })
+ if depPath != nil {
+ ctx.ModuleErrorf("dependency path:")
+ for _, m := range depPath {
+ ctx.ModuleErrorf(" %s", ctx.OtherModuleName(m))
+ }
+ return
+ }
+ }
+ }
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 988c1ce..54c1fac 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -20,6 +20,7 @@
"path/filepath"
"reflect"
"regexp"
+ "slices"
"sort"
"strconv"
"strings"
@@ -28,6 +29,7 @@
"android/soong/aconfig/codegen"
"github.com/google/blueprint"
+ "github.com/google/blueprint/bpmodify"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -225,6 +227,10 @@
"system/sepolicy/apex/myapex-file_contexts": nil,
})
+var prepareForTestWithOtherapex = android.FixtureMergeMockFs(android.MockFS{
+ "system/sepolicy/apex/otherapex-file_contexts": nil,
+})
+
// ensure that 'result' equals 'expected'
func ensureEquals(t *testing.T, result string, expected string) {
t.Helper()
@@ -12114,3 +12120,398 @@
fileList := android.ContentFromFileRuleForTests(t, result, partition.Output("fileList"))
android.AssertDeepEquals(t, "filesystem with apex", "apex/myapex.apex\n", fileList)
}
+
+func TestApexVerifyNativeImplementationLibs(t *testing.T) {
+ t.Parallel()
+
+ extractDepenencyPathFromErrors := func(errs []error) []string {
+ i := slices.IndexFunc(errs, func(err error) bool {
+ return strings.Contains(err.Error(), "dependency path:")
+ })
+ if i < 0 {
+ return nil
+ }
+ var dependencyPath []string
+ for _, err := range errs[i+1:] {
+ s := err.Error()
+ lastSpace := strings.LastIndexByte(s, ' ')
+ if lastSpace >= 0 {
+ dependencyPath = append(dependencyPath, s[lastSpace+1:])
+ }
+ }
+ return dependencyPath
+ }
+
+ checkErrors := func(wantDependencyPath []string) func(t *testing.T, result *android.TestResult) {
+ return func(t *testing.T, result *android.TestResult) {
+ t.Helper()
+ if len(result.Errs) == 0 {
+ t.Fatalf("expected errors")
+ }
+ t.Log("found errors:")
+ for _, err := range result.Errs {
+ t.Log(err)
+ }
+ if g, w := result.Errs[0].Error(), "library in apex transitively linked against implementation library"; !strings.Contains(g, w) {
+ t.Fatalf("expected error %q, got %q", w, g)
+ }
+ dependencyPath := extractDepenencyPathFromErrors(result.Errs)
+ if g, w := dependencyPath, wantDependencyPath; !slices.Equal(g, w) {
+ t.Errorf("expected dependency path %q, got %q", w, g)
+ }
+ }
+ }
+
+ addToSharedLibs := func(module, lib string) func(bp *bpmodify.Blueprint) {
+ return func(bp *bpmodify.Blueprint) {
+ m := bp.ModulesByName(module)
+ props, err := m.GetOrCreateProperty(bpmodify.List, "shared_libs")
+ if err != nil {
+ panic(err)
+ }
+ props.AddStringToList(lib)
+ }
+ }
+
+ bpTemplate := `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ rust_dyn_libs: ["libmyrust"],
+ binaries: ["mybin", "myrustbin"],
+ jni_libs: ["libjni"],
+ apps: ["myapp"],
+ updatable: false,
+ }
+
+ apex {
+ name: "otherapex",
+ key: "myapex.key",
+ native_shared_libs: ["libotherapex"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["foo.cpp"],
+ apex_available: ["myapex"],
+ }
+
+ cc_binary {
+ name: "mybin",
+ srcs: ["foo.cpp"],
+ apex_available: ["myapex"],
+ }
+
+ rust_library {
+ name: "libmyrust",
+ crate_name: "myrust",
+ srcs: ["src/lib.rs"],
+ rustlibs: ["libmyrust_transitive_dylib"],
+ rlibs: ["libmyrust_transitive_rlib"],
+ apex_available: ["myapex"],
+ }
+
+ rust_library{
+ name: "libmyrust_transitive_dylib",
+ crate_name: "myrust_transitive_dylib",
+ srcs: ["src/lib.rs"],
+ apex_available: ["myapex"],
+ }
+
+ rust_library {
+ name: "libmyrust_transitive_rlib",
+ crate_name: "myrust_transitive_rlib",
+ srcs: ["src/lib.rs"],
+ apex_available: ["myapex"],
+ }
+
+ rust_binary {
+ name: "myrustbin",
+ srcs: ["src/main.rs"],
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "libbar",
+ sdk_version: "current",
+ srcs: ["bar.cpp"],
+ apex_available: ["myapex"],
+ stl: "none",
+ }
+
+ android_app {
+ name: "myapp",
+ jni_libs: ["libembeddedjni"],
+ use_embedded_native_libs: true,
+ sdk_version: "current",
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "libembeddedjni",
+ sdk_version: "current",
+ srcs: ["bar.cpp"],
+ apex_available: ["myapex"],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libjni",
+ sdk_version: "current",
+ srcs: ["bar.cpp"],
+ apex_available: ["myapex"],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libotherapex",
+ sdk_version: "current",
+ srcs: ["otherapex.cpp"],
+ apex_available: ["otherapex"],
+ stubs: {
+ symbol_file: "libotherapex.map.txt",
+ versions: ["1", "2", "3"],
+ },
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libplatform",
+ sdk_version: "current",
+ srcs: ["libplatform.cpp"],
+ stubs: {
+ symbol_file: "libplatform.map.txt",
+ versions: ["1", "2", "3"],
+ },
+ stl: "none",
+ system_shared_libs: [],
+ }
+ `
+
+ testCases := []struct {
+ name string
+ bpModifier func(bp *bpmodify.Blueprint)
+ dependencyPath []string
+ }{
+ {
+ name: "library dependency in other apex",
+ bpModifier: addToSharedLibs("mylib", "libotherapex#impl"),
+ dependencyPath: []string{"myapex", "mylib", "libotherapex"},
+ },
+ {
+ name: "transitive library dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("mylib", "libbar")(bp)
+ addToSharedLibs("libbar", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "mylib", "libbar", "libotherapex"},
+ },
+ {
+ name: "library dependency in platform",
+ bpModifier: addToSharedLibs("mylib", "libplatform#impl"),
+ dependencyPath: []string{"myapex", "mylib", "libplatform"},
+ },
+ {
+ name: "jni library dependency in other apex",
+ bpModifier: addToSharedLibs("libjni", "libotherapex#impl"),
+ dependencyPath: []string{"myapex", "libjni", "libotherapex"},
+ },
+ {
+ name: "transitive jni library dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libjni", "libbar")(bp)
+ addToSharedLibs("libbar", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libjni", "libbar", "libotherapex"},
+ },
+ {
+ name: "jni library dependency in platform",
+ bpModifier: addToSharedLibs("libjni", "libplatform#impl"),
+ dependencyPath: []string{"myapex", "libjni", "libplatform"},
+ },
+ {
+ name: "transitive jni library dependency in platform",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libjni", "libbar")(bp)
+ addToSharedLibs("libbar", "libplatform#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libjni", "libbar", "libplatform"},
+ },
+ // TODO: embedded JNI in apps should be checked too, but Soong currently just packages the transitive
+ // JNI libraries even if they came from another apex.
+ //{
+ // name: "app jni library dependency in other apex",
+ // bpModifier: addToSharedLibs("libembeddedjni", "libotherapex#impl"),
+ // dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libotherapex"},
+ //},
+ //{
+ // name: "transitive app jni library dependency in other apex",
+ // bpModifier: func(bp *bpmodify.Blueprint) {
+ // addToSharedLibs("libembeddedjni", "libbar")(bp)
+ // addToSharedLibs("libbar", "libotherapex#impl")(bp)
+ // },
+ // dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libbar", "libotherapex"},
+ //},
+ //{
+ // name: "app jni library dependency in platform",
+ // bpModifier: addToSharedLibs("libembeddedjni", "libplatform#impl"),
+ // dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libplatform"},
+ //},
+ //{
+ // name: "transitive app jni library dependency in platform",
+ // bpModifier: func(bp *bpmodify.Blueprint) {
+ // addToSharedLibs("libembeddedjni", "libbar")(bp)
+ // addToSharedLibs("libbar", "libplatform#impl")(bp)
+ // },
+ // dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libbar", "libplatform"},
+ //},
+ {
+ name: "binary dependency in other apex",
+ bpModifier: addToSharedLibs("mybin", "libotherapex#impl"),
+ dependencyPath: []string{"myapex", "mybin", "libotherapex"},
+ },
+ {
+ name: "transitive binary dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("mybin", "libbar")(bp)
+ addToSharedLibs("libbar", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "mybin", "libbar", "libotherapex"},
+ },
+ {
+ name: "binary dependency in platform",
+ bpModifier: addToSharedLibs("mybin", "libplatform#impl"),
+ dependencyPath: []string{"myapex", "mybin", "libplatform"},
+ },
+ {
+ name: "transitive binary dependency in platform",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("mybin", "libbar")(bp)
+ addToSharedLibs("libbar", "libplatform#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "mybin", "libbar", "libplatform"},
+ },
+
+ {
+ name: "rust library dependency in other apex",
+ bpModifier: addToSharedLibs("libmyrust", "libotherapex#impl"),
+ dependencyPath: []string{"myapex", "libmyrust", "libotherapex"},
+ },
+ {
+ name: "transitive rust library dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libmyrust", "libbar")(bp)
+ addToSharedLibs("libbar", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libmyrust", "libbar", "libotherapex"},
+ },
+ {
+ name: "rust library dependency in platform",
+ bpModifier: addToSharedLibs("libmyrust", "libplatform#impl"),
+ dependencyPath: []string{"myapex", "libmyrust", "libplatform"},
+ },
+ {
+ name: "transitive rust library dependency in platform",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libmyrust", "libbar")(bp)
+ addToSharedLibs("libbar", "libplatform#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libmyrust", "libbar", "libplatform"},
+ },
+ {
+ name: "transitive rust library dylib dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libmyrust_transitive_dylib", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_dylib", "libotherapex"},
+ },
+ {
+ name: "transitive rust library dylib dependency in platform",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libmyrust_transitive_dylib", "libplatform#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_dylib", "libplatform"},
+ },
+ {
+ name: "transitive rust library rlib dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libmyrust_transitive_rlib", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_rlib", "libotherapex"},
+ },
+ {
+ name: "transitive rust library rlib dependency in platform",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("libmyrust_transitive_rlib", "libplatform#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_rlib", "libplatform"},
+ },
+ {
+ name: "rust binary dependency in other apex",
+ bpModifier: addToSharedLibs("myrustbin", "libotherapex#impl"),
+ dependencyPath: []string{"myapex", "myrustbin", "libotherapex"},
+ },
+ {
+ name: "transitive rust binary dependency in other apex",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("myrustbin", "libbar")(bp)
+ addToSharedLibs("libbar", "libotherapex#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "myrustbin", "libbar", "libotherapex"},
+ },
+ {
+ name: "rust binary dependency in platform",
+ bpModifier: addToSharedLibs("myrustbin", "libplatform#impl"),
+ dependencyPath: []string{"myapex", "myrustbin", "libplatform"},
+ },
+ {
+ name: "transitive rust binary dependency in platform",
+ bpModifier: func(bp *bpmodify.Blueprint) {
+ addToSharedLibs("myrustbin", "libbar")(bp)
+ addToSharedLibs("libbar", "libplatform#impl")(bp)
+ },
+ dependencyPath: []string{"myapex", "myrustbin", "libbar", "libplatform"},
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
+ bp, err := bpmodify.NewBlueprint("", []byte(bpTemplate))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if testCase.bpModifier != nil {
+ func() {
+ defer func() {
+ if r := recover(); r != nil {
+ t.Fatalf("panic in bpModifier: %v", r)
+ }
+ }()
+ testCase.bpModifier(bp)
+ }()
+ }
+ android.GroupFixturePreparers(
+ android.PrepareForTestWithAndroidBuildComponents,
+ cc.PrepareForTestWithCcBuildComponents,
+ java.PrepareForTestWithDexpreopt,
+ rust.PrepareForTestWithRustDefaultModules,
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ prepareForTestWithOtherapex,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BuildId = proptools.StringPtr("TEST.BUILD_ID")
+ }),
+ ).ExtendWithErrorHandler(android.FixtureCustomErrorHandler(checkErrors(testCase.dependencyPath))).
+ RunTestWithBp(t, bp.String())
+ })
+ }
+}
diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go
index f8e8899..f367174 100644
--- a/apex/classpath_element_test.go
+++ b/apex/classpath_element_test.go
@@ -45,10 +45,7 @@
prepareForTestWithPlatformBootclasspath,
prepareForTestWithArtApex,
prepareForTestWithMyapex,
- // For otherapex.
- android.FixtureMergeMockFs(android.MockFS{
- "system/sepolicy/apex/otherapex-file_contexts": nil,
- }),
+ prepareForTestWithOtherapex,
java.PrepareForTestWithJavaSdkLibraryFiles,
java.FixtureWithLastReleaseApis("foo", "othersdklibrary"),
java.FixtureConfigureApexBootJars("myapex:bar"),
diff --git a/cc/cc.go b/cc/cc.go
index 069a861..c6bc30e 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -19,8 +19,10 @@
// is handled in builder.go
import (
+ "errors"
"fmt"
"io"
+ "slices"
"strconv"
"strings"
@@ -229,6 +231,9 @@
// LLNDK headers for the ABI checker to check LLNDK implementation library.
LlndkIncludeDirs android.Paths
LlndkSystemIncludeDirs android.Paths
+
+ directImplementationDeps android.Paths
+ transitiveImplementationDeps []depset.DepSet[android.Path]
}
// LocalOrGlobalFlags contains flags that need to have values set globally by the build system or locally by the module
@@ -2052,6 +2057,10 @@
c.outputFile = android.OptionalPathForPath(outputFile)
c.maybeUnhideFromMake()
+
+ android.SetProvider(ctx, ImplementationDepInfoProvider, &ImplementationDepInfo{
+ ImplementationDeps: depset.New(depset.PREORDER, deps.directImplementationDeps, deps.transitiveImplementationDeps),
+ })
}
android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: deps.GeneratedSources.Strings()})
@@ -2292,6 +2301,10 @@
deps.RuntimeLibs = android.LastUniqueStrings(deps.RuntimeLibs)
deps.LlndkHeaderLibs = android.LastUniqueStrings(deps.LlndkHeaderLibs)
+ if err := checkConflictingExplicitVersions(deps.SharedLibs); err != nil {
+ ctx.PropertyErrorf("shared_libs", "%s", err.Error())
+ }
+
for _, lib := range deps.ReexportSharedLibHeaders {
if !inList(lib, deps.SharedLibs) {
ctx.PropertyErrorf("export_shared_lib_headers", "Shared library not in shared_libs: '%s'", lib)
@@ -2319,6 +2332,26 @@
return deps
}
+func checkConflictingExplicitVersions(libs []string) error {
+ withoutVersion := func(s string) string {
+ name, _ := StubsLibNameAndVersion(s)
+ return name
+ }
+ var errs []error
+ for i, lib := range libs {
+ libName := withoutVersion(lib)
+ libsToCompare := libs[i+1:]
+ j := slices.IndexFunc(libsToCompare, func(s string) bool {
+ return withoutVersion(s) == libName
+ })
+ if j >= 0 {
+ errs = append(errs, fmt.Errorf("duplicate shared libraries with different explicit versions: %q and %q",
+ lib, libsToCompare[j]))
+ }
+ }
+ return errors.Join(errs...)
+}
+
func (c *Module) beginMutator(actx android.BottomUpMutatorContext) {
ctx := &baseModuleContext{
BaseModuleContext: actx,
@@ -2380,6 +2413,9 @@
if version != "" && canBeOrLinkAgainstVersionVariants(mod) {
// Version is explicitly specified. i.e. libFoo#30
+ if version == "impl" {
+ version = ""
+ }
variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
if tag, ok := depTag.(libraryDependencyTag); ok {
tag.explicitlyVersioned = true
@@ -3078,6 +3114,13 @@
linkFile = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary)
depFile = sharedLibraryInfo.TableOfContents
+ if !sharedLibraryInfo.IsStubs {
+ depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, ""))
+ if info, ok := android.OtherModuleProvider(ctx, dep, ImplementationDepInfoProvider); ok {
+ depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
+ }
+ }
+
ptr = &depPaths.SharedLibs
switch libDepTag.Order {
case earlyLibraryDependency:
diff --git a/cc/cc_test.go b/cc/cc_test.go
index e906706..22f7c9f 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -3321,3 +3321,20 @@
t.Errorf("expected %q in cflags, got %q", "-Xclang -verify", cFlags_cv)
}
}
+
+func TestCheckConflictingExplicitVersions(t *testing.T) {
+ PrepareForIntegrationTestWithCc.
+ ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
+ `shared_libs: duplicate shared libraries with different explicit versions: "libbar" and "libbar#impl"`,
+ )).
+ RunTestWithBp(t, `
+ cc_library {
+ name: "libfoo",
+ shared_libs: ["libbar", "libbar#impl"],
+ }
+
+ cc_library {
+ name: "libbar",
+ }
+ `)
+}
diff --git a/cc/library.go b/cc/library.go
index 1f21614..7dffa72 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1194,6 +1194,7 @@
SharedLibrary: unstrippedOutputFile,
TransitiveStaticLibrariesForOrdering: transitiveStaticLibrariesForOrdering,
Target: ctx.Target(),
+ IsStubs: library.buildStubs(),
})
addStubDependencyProviders(ctx)
diff --git a/cc/linkable.go b/cc/linkable.go
index cd33e28..ef204eb 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -317,7 +317,9 @@
SharedLibrary android.Path
Target android.Target
- TableOfContents android.OptionalPath
+ TableOfContents android.OptionalPath
+ IsStubs bool
+ ImplementationDeps depset.DepSet[string]
// should be obtained from static analogue
TransitiveStaticLibrariesForOrdering depset.DepSet[android.Path]
@@ -386,3 +388,9 @@
}
var FlagExporterInfoProvider = blueprint.NewProvider[FlagExporterInfo]()
+
+var ImplementationDepInfoProvider = blueprint.NewProvider[*ImplementationDepInfo]()
+
+type ImplementationDepInfo struct {
+ ImplementationDeps depset.DepSet[android.Path]
+}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 7c87297..ba4c662 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -221,6 +221,7 @@
Target: ctx.Target(),
TableOfContents: p.tocFile,
+ IsStubs: p.buildStubs(),
})
return outputFile
@@ -232,6 +233,7 @@
android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
SharedLibrary: latestStub,
Target: ctx.Target(),
+ IsStubs: true,
})
return latestStub
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index e7dff40..4a2adf0 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -166,6 +166,7 @@
Target: ctx.Target(),
TableOfContents: p.tocFile,
+ IsStubs: false,
})
p.libraryDecorator.flagExporter.setProvider(ctx)
diff --git a/etc/adb_keys.go b/etc/adb_keys.go
index a2df41c..73bc347 100644
--- a/etc/adb_keys.go
+++ b/etc/adb_keys.go
@@ -36,6 +36,11 @@
func (m *AdbKeysModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
productVariables := ctx.Config().ProductVariables()
+
+ if !m.ProductSpecific() {
+ ctx.ModuleErrorf("adb_keys module type must set product_specific to true")
+ }
+
if !(android.Bool(productVariables.Debuggable) && len(android.String(productVariables.AdbKeys)) > 0) {
m.SkipInstall()
return
@@ -48,7 +53,7 @@
Output: m.outputPath,
Input: input.Path(),
})
- m.installPath = android.PathForModuleInPartitionInstall(ctx, ctx.DeviceConfig().ProductPath(), "etc/security")
+ m.installPath = android.PathForModuleInstall(ctx, "etc/security")
ctx.InstallFile(m.installPath, "adb_keys", m.outputPath)
}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 861ca3c..938f3bd 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -134,6 +134,18 @@
// Install symlinks to the installed file.
Symlinks []string `android:"arch_variant"`
+
+ // Install to partition system_dlkm when set to true.
+ System_dlkm_specific *bool `android:"arch_variant"`
+
+ // Install to partition vendor_dlkm when set to true.
+ Vendor_dlkm_specific *bool `android:"arch_variant"`
+
+ // Install to partition odm_dlkm when set to true.
+ Odm_dlkm_specific *bool `android:"arch_variant"`
+
+ // Install to partition oem when set to true.
+ Oem_specific *bool `android:"arch_variant"`
}
type prebuiltSubdirProperties struct {
@@ -371,6 +383,16 @@
ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
}
baseInstallDirPath := android.PathForModuleInstall(ctx, p.installBaseDir(ctx), p.SubDir())
+ // TODO(b/377304441)
+ if android.Bool(p.properties.System_dlkm_specific) {
+ baseInstallDirPath = android.PathForModuleInPartitionInstall(ctx, ctx.DeviceConfig().SystemDlkmPath(), p.installBaseDir(ctx), p.SubDir())
+ } else if android.Bool(p.properties.Vendor_dlkm_specific) {
+ baseInstallDirPath = android.PathForModuleInPartitionInstall(ctx, ctx.DeviceConfig().VendorDlkmPath(), p.installBaseDir(ctx), p.SubDir())
+ } else if android.Bool(p.properties.Odm_dlkm_specific) {
+ baseInstallDirPath = android.PathForModuleInPartitionInstall(ctx, ctx.DeviceConfig().OdmDlkmPath(), p.installBaseDir(ctx), p.SubDir())
+ } else if android.Bool(p.properties.Oem_specific) {
+ baseInstallDirPath = android.PathForModuleInPartitionInstall(ctx, ctx.DeviceConfig().OemPath(), p.installBaseDir(ctx), p.SubDir())
+ }
filename := proptools.String(p.properties.Filename)
filenameFromSrc := proptools.Bool(p.properties.Filename_from_src)
diff --git a/fsgen/Android.bp b/fsgen/Android.bp
index e3cbdb3..690ad28 100644
--- a/fsgen/Android.bp
+++ b/fsgen/Android.bp
@@ -14,6 +14,8 @@
],
srcs: [
"filesystem_creator.go",
+ "fsgen_mutators.go",
+ "prebuilt_etc_modules_gen.go",
],
testSrcs: [
"filesystem_creator_test.go",
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index d8f679f..bdffabf 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -18,13 +18,10 @@
"crypto/sha256"
"fmt"
"path/filepath"
- "slices"
"strconv"
"strings"
- "sync"
"android/soong/android"
- "android/soong/etc"
"android/soong/filesystem"
"android/soong/kernel"
@@ -44,597 +41,6 @@
ctx.PreDepsMutators(RegisterCollectFileSystemDepsMutators)
}
-func RegisterCollectFileSystemDepsMutators(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("fs_collect_deps", collectDepsMutator).MutatesGlobalState()
- ctx.BottomUp("fs_set_deps", setDepsMutator)
-}
-
-var fsGenStateOnceKey = android.NewOnceKey("FsGenState")
-var fsGenRemoveOverridesOnceKey = android.NewOnceKey("FsGenRemoveOverrides")
-
-// Map of partition module name to its partition that may be generated by Soong.
-// Note that it is not guaranteed that all modules returned by this function are successfully
-// created.
-func getAllSoongGeneratedPartitionNames(config android.Config, partitions []string) map[string]string {
- ret := map[string]string{}
- for _, partition := range partitions {
- ret[generatedModuleNameForPartition(config, partition)] = partition
- }
- return ret
-}
-
-type depCandidateProps struct {
- Namespace string
- Multilib string
- Arch []android.ArchType
-}
-
-// Map of module name to depCandidateProps
-type multilibDeps map[string]*depCandidateProps
-
-// Information necessary to generate the filesystem modules, including details about their
-// dependencies
-type FsGenState struct {
- // List of modules in `PRODUCT_PACKAGES` and `PRODUCT_PACKAGES_DEBUG`
- depCandidates []string
- // Map of names of partition to the information of modules to be added as deps
- fsDeps map[string]*multilibDeps
- // List of name of partitions to be generated by the filesystem_creator module
- soongGeneratedPartitions []string
- // Mutex to protect the fsDeps
- fsDepsMutex sync.Mutex
- // Map of _all_ soong module names to their corresponding installation properties
- moduleToInstallationProps map[string]installationProperties
-}
-
-type installationProperties struct {
- Required []string
- Overrides []string
-}
-
-func defaultDepCandidateProps(config android.Config) *depCandidateProps {
- return &depCandidateProps{
- Namespace: ".",
- Arch: []android.ArchType{config.BuildArch},
- }
-}
-
-type srcBaseFileInstallBaseFileTuple struct {
- srcBaseFile string
- installBaseFile string
-}
-
-// prebuilt src files grouped by the install partitions.
-// Each groups are a mapping of the relative install path to the name of the files
-type prebuiltSrcGroupByInstallPartition struct {
- system map[string][]srcBaseFileInstallBaseFileTuple
- system_ext map[string][]srcBaseFileInstallBaseFileTuple
- product map[string][]srcBaseFileInstallBaseFileTuple
- vendor map[string][]srcBaseFileInstallBaseFileTuple
-}
-
-func newPrebuiltSrcGroupByInstallPartition() *prebuiltSrcGroupByInstallPartition {
- return &prebuiltSrcGroupByInstallPartition{
- system: map[string][]srcBaseFileInstallBaseFileTuple{},
- system_ext: map[string][]srcBaseFileInstallBaseFileTuple{},
- product: map[string][]srcBaseFileInstallBaseFileTuple{},
- vendor: map[string][]srcBaseFileInstallBaseFileTuple{},
- }
-}
-
-func isSubdirectory(parent, child string) bool {
- rel, err := filepath.Rel(parent, child)
- if err != nil {
- return false
- }
- return !strings.HasPrefix(rel, "..")
-}
-
-func appendIfCorrectInstallPartition(partitionToInstallPathList []partitionToInstallPath, destPath, srcPath string, srcGroup *prebuiltSrcGroupByInstallPartition) {
- for _, part := range partitionToInstallPathList {
- partition := part.name
- installPath := part.installPath
-
- if isSubdirectory(installPath, destPath) {
- relativeInstallPath, _ := filepath.Rel(installPath, destPath)
- relativeInstallDir := filepath.Dir(relativeInstallPath)
- var srcMap map[string][]srcBaseFileInstallBaseFileTuple
- switch partition {
- case "system":
- srcMap = srcGroup.system
- case "system_ext":
- srcMap = srcGroup.system_ext
- case "product":
- srcMap = srcGroup.product
- case "vendor":
- srcMap = srcGroup.vendor
- }
- if srcMap != nil {
- srcMap[relativeInstallDir] = append(srcMap[relativeInstallDir], srcBaseFileInstallBaseFileTuple{
- srcBaseFile: filepath.Base(srcPath),
- installBaseFile: filepath.Base(destPath),
- })
- }
- return
- }
- }
-}
-
-func uniqueExistingProductCopyFileMap(ctx android.LoadHookContext) map[string]string {
- seen := make(map[string]bool)
- filtered := make(map[string]string)
-
- for src, dest := range ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.ProductCopyFiles {
- if _, ok := seen[dest]; !ok {
- if optionalPath := android.ExistentPathForSource(ctx, src); optionalPath.Valid() {
- seen[dest] = true
- filtered[src] = dest
- }
- }
- }
-
- return filtered
-}
-
-type partitionToInstallPath struct {
- name string
- installPath string
-}
-
-func processProductCopyFiles(ctx android.LoadHookContext) map[string]*prebuiltSrcGroupByInstallPartition {
- // Filter out duplicate dest entries and non existing src entries
- productCopyFileMap := uniqueExistingProductCopyFileMap(ctx)
-
- // System is intentionally added at the last to consider the scenarios where
- // non-system partitions are installed as part of the system partition
- partitionToInstallPathList := []partitionToInstallPath{
- {name: "vendor", installPath: ctx.DeviceConfig().VendorPath()},
- {name: "product", installPath: ctx.DeviceConfig().ProductPath()},
- {name: "system_ext", installPath: ctx.DeviceConfig().SystemExtPath()},
- {name: "system", installPath: "system"},
- }
-
- groupedSources := map[string]*prebuiltSrcGroupByInstallPartition{}
- for _, src := range android.SortedKeys(productCopyFileMap) {
- dest := productCopyFileMap[src]
- srcFileDir := filepath.Dir(src)
- if _, ok := groupedSources[srcFileDir]; !ok {
- groupedSources[srcFileDir] = newPrebuiltSrcGroupByInstallPartition()
- }
- appendIfCorrectInstallPartition(partitionToInstallPathList, dest, filepath.Base(src), groupedSources[srcFileDir])
- }
-
- return groupedSources
-}
-
-type prebuiltModuleProperties struct {
- Name *string
-
- Soc_specific *bool
- Product_specific *bool
- System_ext_specific *bool
-
- Srcs []string
- Dsts []string
-
- No_full_install *bool
-
- NamespaceExportedToMake bool
-
- Visibility []string
-}
-
-// Split relative_install_path to a separate struct, because it is not supported for every
-// modules listed in [etcInstallPathToFactoryMap]
-type prebuiltSubdirProperties struct {
- // If the base file name of the src and dst all match, dsts property does not need to be
- // set, and only relative_install_path can be set.
- Relative_install_path *string
-}
-
-var (
- etcInstallPathToFactoryList = map[string]android.ModuleFactory{
- "": etc.PrebuiltRootFactory,
- "avb": etc.PrebuiltAvbFactory,
- "bin": etc.PrebuiltBinaryFactory,
- "bt_firmware": etc.PrebuiltBtFirmwareFactory,
- "cacerts": etc.PrebuiltEtcCaCertsFactory,
- "dsp": etc.PrebuiltDSPFactory,
- "etc": etc.PrebuiltEtcFactory,
- "etc/dsp": etc.PrebuiltDSPFactory,
- "etc/firmware": etc.PrebuiltFirmwareFactory,
- "firmware": etc.PrebuiltFirmwareFactory,
- "fonts": etc.PrebuiltFontFactory,
- "framework": etc.PrebuiltFrameworkFactory,
- "lib": etc.PrebuiltRenderScriptBitcodeFactory,
- "lib64": etc.PrebuiltRenderScriptBitcodeFactory,
- "lib/rfsa": etc.PrebuiltRFSAFactory,
- "media": etc.PrebuiltMediaFactory,
- "odm": etc.PrebuiltOdmFactory,
- "overlay": etc.PrebuiltOverlayFactory,
- "priv-app": etc.PrebuiltPrivAppFactory,
- "res": etc.PrebuiltResFactory,
- "rfs": etc.PrebuiltRfsFactory,
- "tts": etc.PrebuiltVoicepackFactory,
- "usr/share": etc.PrebuiltUserShareFactory,
- "usr/hyphen-data": etc.PrebuiltUserHyphenDataFactory,
- "usr/keylayout": etc.PrebuiltUserKeyLayoutFactory,
- "usr/keychars": etc.PrebuiltUserKeyCharsFactory,
- "usr/srec": etc.PrebuiltUserSrecFactory,
- "usr/idc": etc.PrebuiltUserIdcFactory,
- "vendor_dlkm": etc.PrebuiltVendorDlkmFactory,
- "wallpaper": etc.PrebuiltWallpaperFactory,
- "wlc_upt": etc.PrebuiltWlcUptFactory,
- }
-)
-
-func createPrebuiltEtcModule(ctx android.LoadHookContext, partition, srcDir, destDir string, destFiles []srcBaseFileInstallBaseFileTuple) string {
- moduleProps := &prebuiltModuleProperties{}
- propsList := []interface{}{moduleProps}
-
- // generated module name follows the pattern:
- // <install partition>-<src file path>-<relative install path from partition root>-<install file extension>
- // Note that all path separators are replaced with "_" in the name
- moduleName := partition
- if !android.InList(srcDir, []string{"", "."}) {
- moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(srcDir, string(filepath.Separator), "_"))
- }
- if !android.InList(destDir, []string{"", "."}) {
- moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(destDir, string(filepath.Separator), "_"))
- }
- if len(destFiles) > 0 {
- if ext := filepath.Ext(destFiles[0].srcBaseFile); ext != "" {
- moduleName += fmt.Sprintf("-%s", strings.TrimPrefix(ext, "."))
- }
- }
- moduleProps.Name = proptools.StringPtr(moduleName)
-
- allCopyFileNamesUnchanged := true
- var srcBaseFiles, installBaseFiles []string
- for _, tuple := range destFiles {
- if tuple.srcBaseFile != tuple.installBaseFile {
- allCopyFileNamesUnchanged = false
- }
- srcBaseFiles = append(srcBaseFiles, tuple.srcBaseFile)
- installBaseFiles = append(installBaseFiles, tuple.installBaseFile)
- }
-
- // Find out the most appropriate module type to generate
- var etcInstallPathKey string
- for _, etcInstallPath := range android.SortedKeys(etcInstallPathToFactoryList) {
- // Do not break when found but iterate until the end to find a module with more
- // specific install path
- if strings.HasPrefix(destDir, etcInstallPath) {
- etcInstallPathKey = etcInstallPath
- }
- }
- destDir, _ = filepath.Rel(etcInstallPathKey, destDir)
-
- // Set partition specific properties
- switch partition {
- case "system_ext":
- moduleProps.System_ext_specific = proptools.BoolPtr(true)
- case "product":
- moduleProps.Product_specific = proptools.BoolPtr(true)
- case "vendor":
- moduleProps.Soc_specific = proptools.BoolPtr(true)
- }
-
- // Set appropriate srcs, dsts, and releative_install_path based on
- // the source and install file names
- if allCopyFileNamesUnchanged {
- moduleProps.Srcs = srcBaseFiles
-
- // Specify relative_install_path if it is not installed in the root directory of the
- // partition
- if !android.InList(destDir, []string{"", "."}) {
- propsList = append(propsList, &prebuiltSubdirProperties{
- Relative_install_path: proptools.StringPtr(destDir),
- })
- }
- } else {
- moduleProps.Srcs = srcBaseFiles
- dsts := []string{}
- for _, installBaseFile := range installBaseFiles {
- dsts = append(dsts, filepath.Join(destDir, installBaseFile))
- }
- moduleProps.Dsts = dsts
- }
-
- moduleProps.No_full_install = proptools.BoolPtr(true)
- moduleProps.NamespaceExportedToMake = true
- moduleProps.Visibility = []string{"//visibility:public"}
-
- ctx.CreateModuleInDirectory(etcInstallPathToFactoryList[etcInstallPathKey], srcDir, propsList...)
-
- return moduleName
-}
-
-func createPrebuiltEtcModulesForPartition(ctx android.LoadHookContext, partition, srcDir string, destDirFilesMap map[string][]srcBaseFileInstallBaseFileTuple) (ret []string) {
- for _, destDir := range android.SortedKeys(destDirFilesMap) {
- ret = append(ret, createPrebuiltEtcModule(ctx, partition, srcDir, destDir, destDirFilesMap[destDir]))
- }
- return ret
-}
-
-// Creates prebuilt_* modules based on the install paths and returns the list of generated
-// module names
-func createPrebuiltEtcModules(ctx android.LoadHookContext) (ret []string) {
- groupedSources := processProductCopyFiles(ctx)
- for _, srcDir := range android.SortedKeys(groupedSources) {
- groupedSource := groupedSources[srcDir]
- ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system", srcDir, groupedSource.system)...)
- ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system_ext", srcDir, groupedSource.system_ext)...)
- ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "product", srcDir, groupedSource.product)...)
- ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "vendor", srcDir, groupedSource.vendor)...)
- }
-
- return ret
-}
-
-func generatedPartitions(ctx android.LoadHookContext) []string {
- generatedPartitions := []string{"system"}
- if ctx.DeviceConfig().SystemExtPath() == "system_ext" {
- generatedPartitions = append(generatedPartitions, "system_ext")
- }
- if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" {
- generatedPartitions = append(generatedPartitions, "vendor")
- }
- if ctx.DeviceConfig().BuildingProductImage() && ctx.DeviceConfig().ProductPath() == "product" {
- generatedPartitions = append(generatedPartitions, "product")
- }
- if ctx.DeviceConfig().BuildingOdmImage() && ctx.DeviceConfig().OdmPath() == "odm" {
- generatedPartitions = append(generatedPartitions, "odm")
- }
- if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingSystemDlkmImage {
- generatedPartitions = append(generatedPartitions, "system_dlkm")
- }
- return generatedPartitions
-}
-
-func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNames []string) *FsGenState {
- return ctx.Config().Once(fsGenStateOnceKey, func() interface{} {
- partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
- candidates := android.FirstUniqueStrings(android.Concat(partitionVars.ProductPackages, partitionVars.ProductPackagesDebug))
- candidates = android.Concat(candidates, generatedPrebuiltEtcModuleNames)
-
- return &FsGenState{
- depCandidates: candidates,
- fsDeps: map[string]*multilibDeps{
- // These additional deps are added according to the cuttlefish system image bp.
- "system": {
- "com.android.apex.cts.shim.v1_prebuilt": defaultDepCandidateProps(ctx.Config()),
- "dex_bootjars": defaultDepCandidateProps(ctx.Config()),
- "framework_compatibility_matrix.device.xml": defaultDepCandidateProps(ctx.Config()),
- "init.environ.rc-soong": defaultDepCandidateProps(ctx.Config()),
- "libclang_rt.asan": defaultDepCandidateProps(ctx.Config()),
- "libcompiler_rt": defaultDepCandidateProps(ctx.Config()),
- "libdmabufheap": defaultDepCandidateProps(ctx.Config()),
- "libgsi": defaultDepCandidateProps(ctx.Config()),
- "llndk.libraries.txt": defaultDepCandidateProps(ctx.Config()),
- "logpersist.start": defaultDepCandidateProps(ctx.Config()),
- "update_engine_sideload": defaultDepCandidateProps(ctx.Config()),
- },
- "vendor": {
- "fs_config_files_vendor": defaultDepCandidateProps(ctx.Config()),
- "fs_config_dirs_vendor": defaultDepCandidateProps(ctx.Config()),
- generatedModuleName(ctx.Config(), "vendor-build.prop"): defaultDepCandidateProps(ctx.Config()),
- },
- "odm": {
- // fs_config_* files are automatically installed for all products with odm partitions.
- // https://cs.android.com/android/_/android/platform/build/+/e4849e87ab660b59a6501b3928693db065ee873b:tools/fs_config/Android.mk;l=34;drc=8d6481b92c4b4e9b9f31a61545b6862090fcc14b;bpv=1;bpt=0
- "fs_config_files_odm": defaultDepCandidateProps(ctx.Config()),
- "fs_config_dirs_odm": defaultDepCandidateProps(ctx.Config()),
- },
- "product": {},
- "system_ext": {
- // VNDK apexes are automatically included.
- // This hardcoded list will need to be updated if `PRODUCT_EXTRA_VNDK_VERSIONS` is updated.
- // https://cs.android.com/android/_/android/platform/build/+/adba533072b00c53ac0f198c550a3cbd7a00e4cd:core/main.mk;l=984;bpv=1;bpt=0;drc=174db7b179592cf07cbfd2adb0119486fda911e7
- "com.android.vndk.v30": defaultDepCandidateProps(ctx.Config()),
- "com.android.vndk.v31": defaultDepCandidateProps(ctx.Config()),
- "com.android.vndk.v32": defaultDepCandidateProps(ctx.Config()),
- "com.android.vndk.v33": defaultDepCandidateProps(ctx.Config()),
- "com.android.vndk.v34": defaultDepCandidateProps(ctx.Config()),
- },
- "system_dlkm": {},
- },
- soongGeneratedPartitions: generatedPartitions(ctx),
- fsDepsMutex: sync.Mutex{},
- moduleToInstallationProps: map[string]installationProperties{},
- }
- }).(*FsGenState)
-}
-
-func checkDepModuleInMultipleNamespaces(mctx android.BottomUpMutatorContext, foundDeps multilibDeps, module string, partitionName string) {
- otherNamespace := mctx.Namespace().Path
- if val, found := foundDeps[module]; found && otherNamespace != "." && !android.InList(val.Namespace, []string{".", otherNamespace}) {
- mctx.ModuleErrorf("found in multiple namespaces(%s and %s) when including in %s partition", val.Namespace, otherNamespace, partitionName)
- }
-}
-
-func appendDepIfAppropriate(mctx android.BottomUpMutatorContext, deps *multilibDeps, installPartition string) {
- checkDepModuleInMultipleNamespaces(mctx, *deps, mctx.Module().Name(), installPartition)
- if _, ok := (*deps)[mctx.Module().Name()]; ok {
- // Prefer the namespace-specific module over the platform module
- if mctx.Namespace().Path != "." {
- (*deps)[mctx.Module().Name()].Namespace = mctx.Namespace().Path
- }
- (*deps)[mctx.Module().Name()].Arch = append((*deps)[mctx.Module().Name()].Arch, mctx.Module().Target().Arch.ArchType)
- } else {
- multilib, _ := mctx.Module().DecodeMultilib(mctx)
- (*deps)[mctx.Module().Name()] = &depCandidateProps{
- Namespace: mctx.Namespace().Path,
- Multilib: multilib,
- Arch: []android.ArchType{mctx.Module().Target().Arch.ArchType},
- }
- }
-}
-
-func collectDepsMutator(mctx android.BottomUpMutatorContext) {
- fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
-
- m := mctx.Module()
- if m.Target().Os.Class == android.Device && slices.Contains(fsGenState.depCandidates, m.Name()) {
- installPartition := m.PartitionTag(mctx.DeviceConfig())
- fsGenState.fsDepsMutex.Lock()
- // Only add the module as dependency when:
- // - its enabled
- // - its namespace is included in PRODUCT_SOONG_NAMESPACES
- if m.Enabled(mctx) && m.ExportedToMake() {
- appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition)
- }
- fsGenState.fsDepsMutex.Unlock()
- }
- // store the map of module to (required,overrides) even if the module is not in PRODUCT_PACKAGES.
- // the module might be installed transitively.
- if m.Target().Os.Class == android.Device && m.Enabled(mctx) && m.ExportedToMake() {
- fsGenState.fsDepsMutex.Lock()
- fsGenState.moduleToInstallationProps[m.Name()] = installationProperties{
- Required: m.RequiredModuleNames(mctx),
- Overrides: m.Overrides(),
- }
- fsGenState.fsDepsMutex.Unlock()
- }
-}
-
-type depsStruct struct {
- Deps []string
-}
-
-type multilibDepsStruct struct {
- Common depsStruct
- Lib32 depsStruct
- Lib64 depsStruct
- Both depsStruct
- Prefer32 depsStruct
-}
-
-type packagingPropsStruct struct {
- High_priority_deps []string
- Deps []string
- Multilib multilibDepsStruct
-}
-
-func fullyQualifiedModuleName(moduleName, namespace string) string {
- if namespace == "." {
- return moduleName
- }
- return fmt.Sprintf("//%s:%s", namespace, moduleName)
-}
-
-func getBitness(archTypes []android.ArchType) (ret []string) {
- for _, archType := range archTypes {
- if archType.Multilib == "" {
- ret = append(ret, android.COMMON_VARIANT)
- } else {
- ret = append(ret, archType.Bitness())
- }
- }
- return ret
-}
-
-func setDepsMutator(mctx android.BottomUpMutatorContext) {
- removeOverriddenDeps(mctx)
- fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
- fsDeps := fsGenState.fsDeps
- soongGeneratedPartitionMap := getAllSoongGeneratedPartitionNames(mctx.Config(), fsGenState.soongGeneratedPartitions)
- m := mctx.Module()
- if partition, ok := soongGeneratedPartitionMap[m.Name()]; ok {
- depsStruct := generateDepStruct(*fsDeps[partition])
- if err := proptools.AppendMatchingProperties(m.GetProperties(), depsStruct, nil); err != nil {
- mctx.ModuleErrorf(err.Error())
- }
- }
-}
-
-// removeOverriddenDeps collects PRODUCT_PACKAGES and (transitive) required deps.
-// it then removes any modules which appear in `overrides` of the above list.
-func removeOverriddenDeps(mctx android.BottomUpMutatorContext) {
- mctx.Config().Once(fsGenRemoveOverridesOnceKey, func() interface{} {
- fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
- fsDeps := fsGenState.fsDeps
- overridden := map[string]bool{}
- allDeps := []string{}
-
- // Step 1: Initialization: Append PRODUCT_PACKAGES to the queue
- for _, fsDep := range fsDeps {
- for depName, _ := range *fsDep {
- allDeps = append(allDeps, depName)
- }
- }
-
- // Step 2: Process the queue, and add required modules to the queue.
- i := 0
- for {
- if i == len(allDeps) {
- break
- }
- depName := allDeps[i]
- for _, overrides := range fsGenState.moduleToInstallationProps[depName].Overrides {
- overridden[overrides] = true
- }
- // add required dep to the queue.
- allDeps = append(allDeps, fsGenState.moduleToInstallationProps[depName].Required...)
- i += 1
- }
-
- // Step 3: Delete all the overridden modules.
- for overridden, _ := range overridden {
- for partition, _ := range fsDeps {
- delete(*fsDeps[partition], overridden)
- }
- }
- return nil
- })
-}
-
-var HighPriorityDeps = []string{}
-
-func generateDepStruct(deps map[string]*depCandidateProps) *packagingPropsStruct {
- depsStruct := packagingPropsStruct{}
- for depName, depProps := range deps {
- bitness := getBitness(depProps.Arch)
- fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace)
- if android.InList(depName, HighPriorityDeps) {
- depsStruct.High_priority_deps = append(depsStruct.High_priority_deps, fullyQualifiedDepName)
- } else if android.InList("32", bitness) && android.InList("64", bitness) {
- // If both 32 and 64 bit variants are enabled for this module
- switch depProps.Multilib {
- case string(android.MultilibBoth):
- depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
- case string(android.MultilibCommon), string(android.MultilibFirst):
- depsStruct.Deps = append(depsStruct.Deps, fullyQualifiedDepName)
- case "32":
- depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
- case "64", "darwin_universal":
- depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
- case "prefer32", "first_prefer32":
- depsStruct.Multilib.Prefer32.Deps = append(depsStruct.Multilib.Prefer32.Deps, fullyQualifiedDepName)
- default:
- depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
- }
- } else if android.InList("64", bitness) {
- // If only 64 bit variant is enabled
- depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
- } else if android.InList("32", bitness) {
- // If only 32 bit variant is enabled
- depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
- } else {
- // If only common variant is enabled
- depsStruct.Multilib.Common.Deps = append(depsStruct.Multilib.Common.Deps, fullyQualifiedDepName)
- }
- }
- depsStruct.Deps = android.SortedUniqueStrings(depsStruct.Deps)
- depsStruct.Multilib.Lib32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib32.Deps)
- depsStruct.Multilib.Lib64.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib64.Deps)
- depsStruct.Multilib.Prefer32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Prefer32.Deps)
- depsStruct.Multilib.Both.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Both.Deps)
- depsStruct.Multilib.Common.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Common.Deps)
-
- return &depsStruct
-}
-
type filesystemCreatorProps struct {
Generated_partition_types []string `blueprint:"mutated"`
Unsupported_partition_types []string `blueprint:"mutated"`
@@ -799,23 +205,7 @@
}
module.HideFromMake()
if partitionType == "vendor" {
- // Create a build prop for vendor
- vendorBuildProps := &struct {
- Name *string
- Vendor *bool
- Stem *string
- Product_config *string
- }{
- Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "vendor-build.prop")),
- Vendor: proptools.BoolPtr(true),
- Stem: proptools.StringPtr("build.prop"),
- Product_config: proptools.StringPtr(":product_config"),
- }
- vendorBuildProp := ctx.CreateModule(
- android.BuildPropFactory,
- vendorBuildProps,
- )
- vendorBuildProp.HideFromMake()
+ f.createVendorBuildProp(ctx)
}
return true
}
@@ -855,6 +245,50 @@
}
}
+// Create a build_prop and android_info module. This will be used to create /vendor/build.prop
+func (f *filesystemCreator) createVendorBuildProp(ctx android.LoadHookContext) {
+ // Create a android_info for vendor
+ // The board info files might be in a directory outside the root soong namespace, so create
+ // the module in "."
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ androidInfoProps := &struct {
+ Name *string
+ Board_info_files []string
+ Bootloader_board_name *string
+ }{
+ Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "android-info.prop")),
+ Board_info_files: partitionVars.BoardInfoFiles,
+ }
+ if len(androidInfoProps.Board_info_files) == 0 {
+ androidInfoProps.Bootloader_board_name = proptools.StringPtr(partitionVars.BootLoaderBoardName)
+ }
+ androidInfoProp := ctx.CreateModuleInDirectory(
+ android.AndroidInfoFactory,
+ ".",
+ androidInfoProps,
+ )
+ androidInfoProp.HideFromMake()
+ // Create a build prop for vendor
+ vendorBuildProps := &struct {
+ Name *string
+ Vendor *bool
+ Stem *string
+ Product_config *string
+ Android_info *string
+ }{
+ Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "vendor-build.prop")),
+ Vendor: proptools.BoolPtr(true),
+ Stem: proptools.StringPtr("build.prop"),
+ Product_config: proptools.StringPtr(":product_config"),
+ Android_info: proptools.StringPtr(":" + androidInfoProp.Name()),
+ }
+ vendorBuildProp := ctx.CreateModule(
+ android.BuildPropFactory,
+ vendorBuildProps,
+ )
+ vendorBuildProp.HideFromMake()
+}
+
// createLinkerConfigSourceFilegroups creates filegroup modules to generate linker.config.pb for the following partitions
// 1. vendor: Using PRODUCT_VENDOR_LINKER_CONFIG_FRAGMENTS (space separated file list)
// 1. product: Using PRODUCT_PRODUCT_LINKER_CONFIG_FRAGMENTS (space separated file list)
@@ -1048,9 +482,6 @@
if !fsTypeSupported {
return ""
}
- if partitionType == "vendor" || partitionType == "odm" {
- return "" // TODO: Handle struct props
- }
baseProps := generateBaseProps(proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), partitionType)))
deps := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).fsDeps[partitionType]
@@ -1058,7 +489,8 @@
result, err := proptools.RepackProperties([]interface{}{baseProps, fsProps, depProps})
if err != nil {
- ctx.ModuleErrorf(err.Error())
+ ctx.ModuleErrorf("%s", err.Error())
+ return ""
}
moduleType := "android_filesystem"
diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go
new file mode 100644
index 0000000..bf07ab3
--- /dev/null
+++ b/fsgen/fsgen_mutators.go
@@ -0,0 +1,343 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package fsgen
+
+import (
+ "android/soong/android"
+ "fmt"
+ "slices"
+ "sync"
+
+ "github.com/google/blueprint/proptools"
+)
+
+func RegisterCollectFileSystemDepsMutators(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("fs_collect_deps", collectDepsMutator).MutatesGlobalState()
+ ctx.BottomUp("fs_set_deps", setDepsMutator)
+}
+
+var fsGenStateOnceKey = android.NewOnceKey("FsGenState")
+var fsGenRemoveOverridesOnceKey = android.NewOnceKey("FsGenRemoveOverrides")
+
+// Map of partition module name to its partition that may be generated by Soong.
+// Note that it is not guaranteed that all modules returned by this function are successfully
+// created.
+func getAllSoongGeneratedPartitionNames(config android.Config, partitions []string) map[string]string {
+ ret := map[string]string{}
+ for _, partition := range partitions {
+ ret[generatedModuleNameForPartition(config, partition)] = partition
+ }
+ return ret
+}
+
+type depCandidateProps struct {
+ Namespace string
+ Multilib string
+ Arch []android.ArchType
+}
+
+// Map of module name to depCandidateProps
+type multilibDeps map[string]*depCandidateProps
+
+// Information necessary to generate the filesystem modules, including details about their
+// dependencies
+type FsGenState struct {
+ // List of modules in `PRODUCT_PACKAGES` and `PRODUCT_PACKAGES_DEBUG`
+ depCandidates []string
+ // Map of names of partition to the information of modules to be added as deps
+ fsDeps map[string]*multilibDeps
+ // List of name of partitions to be generated by the filesystem_creator module
+ soongGeneratedPartitions []string
+ // Mutex to protect the fsDeps
+ fsDepsMutex sync.Mutex
+ // Map of _all_ soong module names to their corresponding installation properties
+ moduleToInstallationProps map[string]installationProperties
+}
+
+type installationProperties struct {
+ Required []string
+ Overrides []string
+}
+
+func defaultDepCandidateProps(config android.Config) *depCandidateProps {
+ return &depCandidateProps{
+ Namespace: ".",
+ Arch: []android.ArchType{config.BuildArch},
+ }
+}
+
+func generatedPartitions(ctx android.LoadHookContext) []string {
+ generatedPartitions := []string{"system"}
+ if ctx.DeviceConfig().SystemExtPath() == "system_ext" {
+ generatedPartitions = append(generatedPartitions, "system_ext")
+ }
+ if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" {
+ generatedPartitions = append(generatedPartitions, "vendor")
+ }
+ if ctx.DeviceConfig().BuildingProductImage() && ctx.DeviceConfig().ProductPath() == "product" {
+ generatedPartitions = append(generatedPartitions, "product")
+ }
+ if ctx.DeviceConfig().BuildingOdmImage() && ctx.DeviceConfig().OdmPath() == "odm" {
+ generatedPartitions = append(generatedPartitions, "odm")
+ }
+ if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingSystemDlkmImage {
+ generatedPartitions = append(generatedPartitions, "system_dlkm")
+ }
+ return generatedPartitions
+}
+
+func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNames []string) *FsGenState {
+ return ctx.Config().Once(fsGenStateOnceKey, func() interface{} {
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ candidates := android.FirstUniqueStrings(android.Concat(partitionVars.ProductPackages, partitionVars.ProductPackagesDebug))
+ candidates = android.Concat(candidates, generatedPrebuiltEtcModuleNames)
+
+ return &FsGenState{
+ depCandidates: candidates,
+ fsDeps: map[string]*multilibDeps{
+ // These additional deps are added according to the cuttlefish system image bp.
+ "system": {
+ "com.android.apex.cts.shim.v1_prebuilt": defaultDepCandidateProps(ctx.Config()),
+ "dex_bootjars": defaultDepCandidateProps(ctx.Config()),
+ "framework_compatibility_matrix.device.xml": defaultDepCandidateProps(ctx.Config()),
+ "init.environ.rc-soong": defaultDepCandidateProps(ctx.Config()),
+ "libclang_rt.asan": defaultDepCandidateProps(ctx.Config()),
+ "libcompiler_rt": defaultDepCandidateProps(ctx.Config()),
+ "libdmabufheap": defaultDepCandidateProps(ctx.Config()),
+ "libgsi": defaultDepCandidateProps(ctx.Config()),
+ "llndk.libraries.txt": defaultDepCandidateProps(ctx.Config()),
+ "logpersist.start": defaultDepCandidateProps(ctx.Config()),
+ "update_engine_sideload": defaultDepCandidateProps(ctx.Config()),
+ },
+ "vendor": {
+ "fs_config_files_vendor": defaultDepCandidateProps(ctx.Config()),
+ "fs_config_dirs_vendor": defaultDepCandidateProps(ctx.Config()),
+ generatedModuleName(ctx.Config(), "vendor-build.prop"): defaultDepCandidateProps(ctx.Config()),
+ },
+ "odm": {
+ // fs_config_* files are automatically installed for all products with odm partitions.
+ // https://cs.android.com/android/_/android/platform/build/+/e4849e87ab660b59a6501b3928693db065ee873b:tools/fs_config/Android.mk;l=34;drc=8d6481b92c4b4e9b9f31a61545b6862090fcc14b;bpv=1;bpt=0
+ "fs_config_files_odm": defaultDepCandidateProps(ctx.Config()),
+ "fs_config_dirs_odm": defaultDepCandidateProps(ctx.Config()),
+ },
+ "product": {},
+ "system_ext": {
+ // VNDK apexes are automatically included.
+ // This hardcoded list will need to be updated if `PRODUCT_EXTRA_VNDK_VERSIONS` is updated.
+ // https://cs.android.com/android/_/android/platform/build/+/adba533072b00c53ac0f198c550a3cbd7a00e4cd:core/main.mk;l=984;bpv=1;bpt=0;drc=174db7b179592cf07cbfd2adb0119486fda911e7
+ "com.android.vndk.v30": defaultDepCandidateProps(ctx.Config()),
+ "com.android.vndk.v31": defaultDepCandidateProps(ctx.Config()),
+ "com.android.vndk.v32": defaultDepCandidateProps(ctx.Config()),
+ "com.android.vndk.v33": defaultDepCandidateProps(ctx.Config()),
+ "com.android.vndk.v34": defaultDepCandidateProps(ctx.Config()),
+ },
+ "system_dlkm": {},
+ },
+ soongGeneratedPartitions: generatedPartitions(ctx),
+ fsDepsMutex: sync.Mutex{},
+ moduleToInstallationProps: map[string]installationProperties{},
+ }
+ }).(*FsGenState)
+}
+
+func checkDepModuleInMultipleNamespaces(mctx android.BottomUpMutatorContext, foundDeps multilibDeps, module string, partitionName string) {
+ otherNamespace := mctx.Namespace().Path
+ if val, found := foundDeps[module]; found && otherNamespace != "." && !android.InList(val.Namespace, []string{".", otherNamespace}) {
+ mctx.ModuleErrorf("found in multiple namespaces(%s and %s) when including in %s partition", val.Namespace, otherNamespace, partitionName)
+ }
+}
+
+func appendDepIfAppropriate(mctx android.BottomUpMutatorContext, deps *multilibDeps, installPartition string) {
+ moduleName := mctx.ModuleName()
+ checkDepModuleInMultipleNamespaces(mctx, *deps, moduleName, installPartition)
+ if _, ok := (*deps)[moduleName]; ok {
+ // Prefer the namespace-specific module over the platform module
+ if mctx.Namespace().Path != "." {
+ (*deps)[moduleName].Namespace = mctx.Namespace().Path
+ }
+ (*deps)[moduleName].Arch = append((*deps)[moduleName].Arch, mctx.Module().Target().Arch.ArchType)
+ } else {
+ multilib, _ := mctx.Module().DecodeMultilib(mctx)
+ (*deps)[moduleName] = &depCandidateProps{
+ Namespace: mctx.Namespace().Path,
+ Multilib: multilib,
+ Arch: []android.ArchType{mctx.Module().Target().Arch.ArchType},
+ }
+ }
+}
+
+func collectDepsMutator(mctx android.BottomUpMutatorContext) {
+ fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
+
+ m := mctx.Module()
+ if m.Target().Os.Class == android.Device && slices.Contains(fsGenState.depCandidates, mctx.ModuleName()) {
+ installPartition := m.PartitionTag(mctx.DeviceConfig())
+ fsGenState.fsDepsMutex.Lock()
+ // Only add the module as dependency when:
+ // - its enabled
+ // - its namespace is included in PRODUCT_SOONG_NAMESPACES
+ if m.Enabled(mctx) && m.ExportedToMake() {
+ appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition)
+ }
+ fsGenState.fsDepsMutex.Unlock()
+ }
+ // store the map of module to (required,overrides) even if the module is not in PRODUCT_PACKAGES.
+ // the module might be installed transitively.
+ if m.Target().Os.Class == android.Device && m.Enabled(mctx) && m.ExportedToMake() {
+ fsGenState.fsDepsMutex.Lock()
+ fsGenState.moduleToInstallationProps[m.Name()] = installationProperties{
+ Required: m.RequiredModuleNames(mctx),
+ Overrides: m.Overrides(),
+ }
+ fsGenState.fsDepsMutex.Unlock()
+ }
+}
+
+type depsStruct struct {
+ Deps []string
+}
+
+type multilibDepsStruct struct {
+ Common depsStruct
+ Lib32 depsStruct
+ Lib64 depsStruct
+ Both depsStruct
+ Prefer32 depsStruct
+}
+
+type packagingPropsStruct struct {
+ High_priority_deps []string
+ Deps []string
+ Multilib multilibDepsStruct
+}
+
+func fullyQualifiedModuleName(moduleName, namespace string) string {
+ if namespace == "." {
+ return moduleName
+ }
+ return fmt.Sprintf("//%s:%s", namespace, moduleName)
+}
+
+func getBitness(archTypes []android.ArchType) (ret []string) {
+ for _, archType := range archTypes {
+ if archType.Multilib == "" {
+ ret = append(ret, android.COMMON_VARIANT)
+ } else {
+ ret = append(ret, archType.Bitness())
+ }
+ }
+ return ret
+}
+
+func setDepsMutator(mctx android.BottomUpMutatorContext) {
+ removeOverriddenDeps(mctx)
+ fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
+ fsDeps := fsGenState.fsDeps
+ soongGeneratedPartitionMap := getAllSoongGeneratedPartitionNames(mctx.Config(), fsGenState.soongGeneratedPartitions)
+ m := mctx.Module()
+ if partition, ok := soongGeneratedPartitionMap[m.Name()]; ok {
+ depsStruct := generateDepStruct(*fsDeps[partition])
+ if err := proptools.AppendMatchingProperties(m.GetProperties(), depsStruct, nil); err != nil {
+ mctx.ModuleErrorf(err.Error())
+ }
+ }
+}
+
+// removeOverriddenDeps collects PRODUCT_PACKAGES and (transitive) required deps.
+// it then removes any modules which appear in `overrides` of the above list.
+func removeOverriddenDeps(mctx android.BottomUpMutatorContext) {
+ mctx.Config().Once(fsGenRemoveOverridesOnceKey, func() interface{} {
+ fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
+ fsDeps := fsGenState.fsDeps
+ overridden := map[string]bool{}
+ allDeps := []string{}
+
+ // Step 1: Initialization: Append PRODUCT_PACKAGES to the queue
+ for _, fsDep := range fsDeps {
+ for depName, _ := range *fsDep {
+ allDeps = append(allDeps, depName)
+ }
+ }
+
+ // Step 2: Process the queue, and add required modules to the queue.
+ i := 0
+ for {
+ if i == len(allDeps) {
+ break
+ }
+ depName := allDeps[i]
+ for _, overrides := range fsGenState.moduleToInstallationProps[depName].Overrides {
+ overridden[overrides] = true
+ }
+ // add required dep to the queue.
+ allDeps = append(allDeps, fsGenState.moduleToInstallationProps[depName].Required...)
+ i += 1
+ }
+
+ // Step 3: Delete all the overridden modules.
+ for overridden, _ := range overridden {
+ for partition, _ := range fsDeps {
+ delete(*fsDeps[partition], overridden)
+ }
+ }
+ return nil
+ })
+}
+
+var HighPriorityDeps = []string{}
+
+func generateDepStruct(deps map[string]*depCandidateProps) *packagingPropsStruct {
+ depsStruct := packagingPropsStruct{}
+ for depName, depProps := range deps {
+ bitness := getBitness(depProps.Arch)
+ fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace)
+ if android.InList(depName, HighPriorityDeps) {
+ depsStruct.High_priority_deps = append(depsStruct.High_priority_deps, fullyQualifiedDepName)
+ } else if android.InList("32", bitness) && android.InList("64", bitness) {
+ // If both 32 and 64 bit variants are enabled for this module
+ switch depProps.Multilib {
+ case string(android.MultilibBoth):
+ depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
+ case string(android.MultilibCommon), string(android.MultilibFirst):
+ depsStruct.Deps = append(depsStruct.Deps, fullyQualifiedDepName)
+ case "32":
+ depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
+ case "64", "darwin_universal":
+ depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
+ case "prefer32", "first_prefer32":
+ depsStruct.Multilib.Prefer32.Deps = append(depsStruct.Multilib.Prefer32.Deps, fullyQualifiedDepName)
+ default:
+ depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
+ }
+ } else if android.InList("64", bitness) {
+ // If only 64 bit variant is enabled
+ depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
+ } else if android.InList("32", bitness) {
+ // If only 32 bit variant is enabled
+ depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
+ } else {
+ // If only common variant is enabled
+ depsStruct.Multilib.Common.Deps = append(depsStruct.Multilib.Common.Deps, fullyQualifiedDepName)
+ }
+ }
+ depsStruct.Deps = android.SortedUniqueStrings(depsStruct.Deps)
+ depsStruct.Multilib.Lib32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib32.Deps)
+ depsStruct.Multilib.Lib64.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib64.Deps)
+ depsStruct.Multilib.Prefer32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Prefer32.Deps)
+ depsStruct.Multilib.Both.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Both.Deps)
+ depsStruct.Multilib.Common.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Common.Deps)
+
+ return &depsStruct
+}
diff --git a/fsgen/prebuilt_etc_modules_gen.go b/fsgen/prebuilt_etc_modules_gen.go
new file mode 100644
index 0000000..1df7ec8
--- /dev/null
+++ b/fsgen/prebuilt_etc_modules_gen.go
@@ -0,0 +1,298 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package fsgen
+
+import (
+ "android/soong/android"
+ "android/soong/etc"
+ "fmt"
+ "path/filepath"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+)
+
+type srcBaseFileInstallBaseFileTuple struct {
+ srcBaseFile string
+ installBaseFile string
+}
+
+// prebuilt src files grouped by the install partitions.
+// Each groups are a mapping of the relative install path to the name of the files
+type prebuiltSrcGroupByInstallPartition struct {
+ system map[string][]srcBaseFileInstallBaseFileTuple
+ system_ext map[string][]srcBaseFileInstallBaseFileTuple
+ product map[string][]srcBaseFileInstallBaseFileTuple
+ vendor map[string][]srcBaseFileInstallBaseFileTuple
+}
+
+func newPrebuiltSrcGroupByInstallPartition() *prebuiltSrcGroupByInstallPartition {
+ return &prebuiltSrcGroupByInstallPartition{
+ system: map[string][]srcBaseFileInstallBaseFileTuple{},
+ system_ext: map[string][]srcBaseFileInstallBaseFileTuple{},
+ product: map[string][]srcBaseFileInstallBaseFileTuple{},
+ vendor: map[string][]srcBaseFileInstallBaseFileTuple{},
+ }
+}
+
+func isSubdirectory(parent, child string) bool {
+ rel, err := filepath.Rel(parent, child)
+ if err != nil {
+ return false
+ }
+ return !strings.HasPrefix(rel, "..")
+}
+
+func appendIfCorrectInstallPartition(partitionToInstallPathList []partitionToInstallPath, destPath, srcPath string, srcGroup *prebuiltSrcGroupByInstallPartition) {
+ for _, part := range partitionToInstallPathList {
+ partition := part.name
+ installPath := part.installPath
+
+ if isSubdirectory(installPath, destPath) {
+ relativeInstallPath, _ := filepath.Rel(installPath, destPath)
+ relativeInstallDir := filepath.Dir(relativeInstallPath)
+ var srcMap map[string][]srcBaseFileInstallBaseFileTuple
+ switch partition {
+ case "system":
+ srcMap = srcGroup.system
+ case "system_ext":
+ srcMap = srcGroup.system_ext
+ case "product":
+ srcMap = srcGroup.product
+ case "vendor":
+ srcMap = srcGroup.vendor
+ }
+ if srcMap != nil {
+ srcMap[relativeInstallDir] = append(srcMap[relativeInstallDir], srcBaseFileInstallBaseFileTuple{
+ srcBaseFile: filepath.Base(srcPath),
+ installBaseFile: filepath.Base(destPath),
+ })
+ }
+ return
+ }
+ }
+}
+
+func uniqueExistingProductCopyFileMap(ctx android.LoadHookContext) map[string]string {
+ seen := make(map[string]bool)
+ filtered := make(map[string]string)
+
+ for src, dest := range ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.ProductCopyFiles {
+ if _, ok := seen[dest]; !ok {
+ if optionalPath := android.ExistentPathForSource(ctx, src); optionalPath.Valid() {
+ seen[dest] = true
+ filtered[src] = dest
+ }
+ }
+ }
+
+ return filtered
+}
+
+type partitionToInstallPath struct {
+ name string
+ installPath string
+}
+
+func processProductCopyFiles(ctx android.LoadHookContext) map[string]*prebuiltSrcGroupByInstallPartition {
+ // Filter out duplicate dest entries and non existing src entries
+ productCopyFileMap := uniqueExistingProductCopyFileMap(ctx)
+
+ // System is intentionally added at the last to consider the scenarios where
+ // non-system partitions are installed as part of the system partition
+ partitionToInstallPathList := []partitionToInstallPath{
+ {name: "vendor", installPath: ctx.DeviceConfig().VendorPath()},
+ {name: "product", installPath: ctx.DeviceConfig().ProductPath()},
+ {name: "system_ext", installPath: ctx.DeviceConfig().SystemExtPath()},
+ {name: "system", installPath: "system"},
+ }
+
+ groupedSources := map[string]*prebuiltSrcGroupByInstallPartition{}
+ for _, src := range android.SortedKeys(productCopyFileMap) {
+ dest := productCopyFileMap[src]
+ srcFileDir := filepath.Dir(src)
+ if _, ok := groupedSources[srcFileDir]; !ok {
+ groupedSources[srcFileDir] = newPrebuiltSrcGroupByInstallPartition()
+ }
+ appendIfCorrectInstallPartition(partitionToInstallPathList, dest, filepath.Base(src), groupedSources[srcFileDir])
+ }
+
+ return groupedSources
+}
+
+type prebuiltModuleProperties struct {
+ Name *string
+
+ Soc_specific *bool
+ Product_specific *bool
+ System_ext_specific *bool
+
+ Srcs []string
+ Dsts []string
+
+ No_full_install *bool
+
+ NamespaceExportedToMake bool
+
+ Visibility []string
+}
+
+// Split relative_install_path to a separate struct, because it is not supported for every
+// modules listed in [etcInstallPathToFactoryMap]
+type prebuiltSubdirProperties struct {
+ // If the base file name of the src and dst all match, dsts property does not need to be
+ // set, and only relative_install_path can be set.
+ Relative_install_path *string
+}
+
+var (
+ etcInstallPathToFactoryList = map[string]android.ModuleFactory{
+ "": etc.PrebuiltRootFactory,
+ "avb": etc.PrebuiltAvbFactory,
+ "bin": etc.PrebuiltBinaryFactory,
+ "bt_firmware": etc.PrebuiltBtFirmwareFactory,
+ "cacerts": etc.PrebuiltEtcCaCertsFactory,
+ "dsp": etc.PrebuiltDSPFactory,
+ "etc": etc.PrebuiltEtcFactory,
+ "etc/dsp": etc.PrebuiltDSPFactory,
+ "etc/firmware": etc.PrebuiltFirmwareFactory,
+ "firmware": etc.PrebuiltFirmwareFactory,
+ "fonts": etc.PrebuiltFontFactory,
+ "framework": etc.PrebuiltFrameworkFactory,
+ "lib": etc.PrebuiltRenderScriptBitcodeFactory,
+ "lib64": etc.PrebuiltRenderScriptBitcodeFactory,
+ "lib/rfsa": etc.PrebuiltRFSAFactory,
+ "media": etc.PrebuiltMediaFactory,
+ "odm": etc.PrebuiltOdmFactory,
+ "overlay": etc.PrebuiltOverlayFactory,
+ "priv-app": etc.PrebuiltPrivAppFactory,
+ "res": etc.PrebuiltResFactory,
+ "rfs": etc.PrebuiltRfsFactory,
+ "tts": etc.PrebuiltVoicepackFactory,
+ "usr/share": etc.PrebuiltUserShareFactory,
+ "usr/hyphen-data": etc.PrebuiltUserHyphenDataFactory,
+ "usr/keylayout": etc.PrebuiltUserKeyLayoutFactory,
+ "usr/keychars": etc.PrebuiltUserKeyCharsFactory,
+ "usr/srec": etc.PrebuiltUserSrecFactory,
+ "usr/idc": etc.PrebuiltUserIdcFactory,
+ "vendor_dlkm": etc.PrebuiltVendorDlkmFactory,
+ "wallpaper": etc.PrebuiltWallpaperFactory,
+ "wlc_upt": etc.PrebuiltWlcUptFactory,
+ }
+)
+
+func createPrebuiltEtcModule(ctx android.LoadHookContext, partition, srcDir, destDir string, destFiles []srcBaseFileInstallBaseFileTuple) string {
+ moduleProps := &prebuiltModuleProperties{}
+ propsList := []interface{}{moduleProps}
+
+ // generated module name follows the pattern:
+ // <install partition>-<src file path>-<relative install path from partition root>-<install file extension>
+ // Note that all path separators are replaced with "_" in the name
+ moduleName := partition
+ if !android.InList(srcDir, []string{"", "."}) {
+ moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(srcDir, string(filepath.Separator), "_"))
+ }
+ if !android.InList(destDir, []string{"", "."}) {
+ moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(destDir, string(filepath.Separator), "_"))
+ }
+ if len(destFiles) > 0 {
+ if ext := filepath.Ext(destFiles[0].srcBaseFile); ext != "" {
+ moduleName += fmt.Sprintf("-%s", strings.TrimPrefix(ext, "."))
+ }
+ }
+ moduleProps.Name = proptools.StringPtr(moduleName)
+
+ allCopyFileNamesUnchanged := true
+ var srcBaseFiles, installBaseFiles []string
+ for _, tuple := range destFiles {
+ if tuple.srcBaseFile != tuple.installBaseFile {
+ allCopyFileNamesUnchanged = false
+ }
+ srcBaseFiles = append(srcBaseFiles, tuple.srcBaseFile)
+ installBaseFiles = append(installBaseFiles, tuple.installBaseFile)
+ }
+
+ // Find out the most appropriate module type to generate
+ var etcInstallPathKey string
+ for _, etcInstallPath := range android.SortedKeys(etcInstallPathToFactoryList) {
+ // Do not break when found but iterate until the end to find a module with more
+ // specific install path
+ if strings.HasPrefix(destDir, etcInstallPath) {
+ etcInstallPathKey = etcInstallPath
+ }
+ }
+ destDir, _ = filepath.Rel(etcInstallPathKey, destDir)
+
+ // Set partition specific properties
+ switch partition {
+ case "system_ext":
+ moduleProps.System_ext_specific = proptools.BoolPtr(true)
+ case "product":
+ moduleProps.Product_specific = proptools.BoolPtr(true)
+ case "vendor":
+ moduleProps.Soc_specific = proptools.BoolPtr(true)
+ }
+
+ // Set appropriate srcs, dsts, and releative_install_path based on
+ // the source and install file names
+ if allCopyFileNamesUnchanged {
+ moduleProps.Srcs = srcBaseFiles
+
+ // Specify relative_install_path if it is not installed in the root directory of the
+ // partition
+ if !android.InList(destDir, []string{"", "."}) {
+ propsList = append(propsList, &prebuiltSubdirProperties{
+ Relative_install_path: proptools.StringPtr(destDir),
+ })
+ }
+ } else {
+ moduleProps.Srcs = srcBaseFiles
+ dsts := []string{}
+ for _, installBaseFile := range installBaseFiles {
+ dsts = append(dsts, filepath.Join(destDir, installBaseFile))
+ }
+ moduleProps.Dsts = dsts
+ }
+
+ moduleProps.No_full_install = proptools.BoolPtr(true)
+ moduleProps.NamespaceExportedToMake = true
+ moduleProps.Visibility = []string{"//visibility:public"}
+
+ ctx.CreateModuleInDirectory(etcInstallPathToFactoryList[etcInstallPathKey], srcDir, propsList...)
+
+ return moduleName
+}
+
+func createPrebuiltEtcModulesForPartition(ctx android.LoadHookContext, partition, srcDir string, destDirFilesMap map[string][]srcBaseFileInstallBaseFileTuple) (ret []string) {
+ for _, destDir := range android.SortedKeys(destDirFilesMap) {
+ ret = append(ret, createPrebuiltEtcModule(ctx, partition, srcDir, destDir, destDirFilesMap[destDir]))
+ }
+ return ret
+}
+
+// Creates prebuilt_* modules based on the install paths and returns the list of generated
+// module names
+func createPrebuiltEtcModules(ctx android.LoadHookContext) (ret []string) {
+ groupedSources := processProductCopyFiles(ctx)
+ for _, srcDir := range android.SortedKeys(groupedSources) {
+ groupedSource := groupedSources[srcDir]
+ ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system", srcDir, groupedSource.system)...)
+ ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system_ext", srcDir, groupedSource.system_ext)...)
+ ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "product", srcDir, groupedSource.product)...)
+ ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "vendor", srcDir, groupedSource.vendor)...)
+ }
+
+ return ret
+}
diff --git a/java/app.go b/java/app.go
index e01a2ba..6572dbd 100644
--- a/java/app.go
+++ b/java/app.go
@@ -67,6 +67,9 @@
// TestHelperApp is true if the module is a android_test_helper_app
TestHelperApp bool
+
+ // EmbeddedJNILibs is the list of paths to JNI libraries that were embedded in the APK.
+ EmbeddedJNILibs android.Paths
}
var AppInfoProvider = blueprint.NewProvider[*AppInfo]()
@@ -405,9 +408,18 @@
a.checkEmbedJnis(ctx)
a.generateAndroidBuildActions(ctx)
a.generateJavaUsedByApex(ctx)
+
+ var embeddedJniLibs []android.Path
+
+ if a.embeddedJniLibs {
+ for _, jni := range a.jniLibs {
+ embeddedJniLibs = append(embeddedJniLibs, jni.path)
+ }
+ }
android.SetProvider(ctx, AppInfoProvider, &AppInfo{
- Updatable: Bool(a.appProperties.Updatable),
- TestHelperApp: false,
+ Updatable: Bool(a.appProperties.Updatable),
+ TestHelperApp: false,
+ EmbeddedJNILibs: embeddedJniLibs,
})
}
@@ -1070,12 +1082,12 @@
app.SdkVersion(ctx).Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx)
}
jniLib, prebuiltJniPackages := collectJniDeps(ctx, shouldCollectRecursiveNativeDeps,
- checkNativeSdkVersion, func(dep cc.LinkableInterface) bool {
- return !dep.IsNdk(ctx.Config()) && !dep.IsStubs()
- })
+ checkNativeSdkVersion, func(dep cc.LinkableInterface) bool { return !dep.IsNdk(ctx.Config()) && !dep.IsStubs() })
var certificates []Certificate
+ var directImplementationDeps android.Paths
+ var transitiveImplementationDeps []depset.DepSet[android.Path]
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
@@ -1087,7 +1099,18 @@
ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName)
}
}
+
+ if IsJniDepTag(tag) {
+ directImplementationDeps = append(directImplementationDeps, android.OutputFileForModule(ctx, module, ""))
+ if info, ok := android.OtherModuleProvider(ctx, module, cc.ImplementationDepInfoProvider); ok {
+ transitiveImplementationDeps = append(transitiveImplementationDeps, info.ImplementationDeps)
+ }
+ }
})
+ android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{
+ ImplementationDeps: depset.New(depset.PREORDER, directImplementationDeps, transitiveImplementationDeps),
+ })
+
return jniLib, prebuiltJniPackages, certificates
}
diff --git a/java/java.go b/java/java.go
index 53b3481..86f7845 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1610,6 +1610,8 @@
j.data = append(j.data, android.OutputFileForModule(ctx, dep, ""))
})
+ var directImplementationDeps android.Paths
+ var transitiveImplementationDeps []depset.DepSet[android.Path]
ctx.VisitDirectDepsWithTag(jniLibTag, func(dep android.Module) {
sharedLibInfo, _ := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider)
if sharedLibInfo.SharedLibrary != nil {
@@ -1628,11 +1630,20 @@
Output: relocatedLib,
})
j.data = append(j.data, relocatedLib)
+
+ directImplementationDeps = append(directImplementationDeps, android.OutputFileForModule(ctx, dep, ""))
+ if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
+ transitiveImplementationDeps = append(transitiveImplementationDeps, info.ImplementationDeps)
+ }
} else {
ctx.PropertyErrorf("jni_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
}
})
+ android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{
+ ImplementationDeps: depset.New(depset.PREORDER, directImplementationDeps, transitiveImplementationDeps),
+ })
+
j.Library.GenerateAndroidBuildActions(ctx)
}
diff --git a/rust/library.go b/rust/library.go
index 20cd2af..bd3359b 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -617,6 +617,9 @@
TableOfContents: android.OptionalPathForPath(tocFile),
SharedLibrary: outputFile,
Target: ctx.Target(),
+ // TODO: when rust supports stubs uses the stubs state rather than inferring it from
+ // apex_exclude.
+ IsStubs: Bool(library.Properties.Apex_exclude),
})
}
diff --git a/rust/rust.go b/rust/rust.go
index 9e06cd4..ed38ad7 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -454,6 +454,9 @@
// Paths to generated source files
SrcDeps android.Paths
srcProviderFiles android.Paths
+
+ directImplementationDeps android.Paths
+ transitiveImplementationDeps []depset.DepSet[android.Path]
}
type RustLibraries []RustLibrary
@@ -991,6 +994,10 @@
}
+ android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{
+ ImplementationDeps: depset.New(depset.PREORDER, deps.directImplementationDeps, deps.transitiveImplementationDeps),
+ })
+
ctx.Phony("rust", ctx.RustModule().OutputFile().Path())
}
@@ -1244,6 +1251,11 @@
mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, makeLibName)
mod.Properties.SnapshotDylibs = append(mod.Properties.SnapshotDylibs, cc.BaseLibName(depName))
+ depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, ""))
+ if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
+ depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
+ }
+
case depTag == rlibDepTag:
rlib, ok := rustDep.compiler.(libraryInterface)
if !ok || !rlib.rlib() {
@@ -1259,6 +1271,11 @@
depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(rustDep.OutputFile().Path()))
+ // rlibs are not installed, so don't add the output file to directImplementationDeps
+ if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
+ depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
+ }
+
case depTag == procMacroDepTag:
directProcMacroDeps = append(directProcMacroDeps, rustDep)
mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName)
@@ -1391,6 +1408,13 @@
// dependency crosses the APEX boundaries).
sharedLibraryInfo, exportedInfo := cc.ChooseStubOrImpl(ctx, dep)
+ if !sharedLibraryInfo.IsStubs {
+ depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, ""))
+ if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
+ depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
+ }
+ }
+
// Re-get linkObject as ChooseStubOrImpl actually tells us which
// object (either from stub or non-stub) to use.
linkObject = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary)
diff --git a/tests/lib.sh b/tests/lib.sh
index 4c320d0..0e26de5 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -91,7 +91,6 @@
}
function create_mock_soong {
- create_mock_bazel
copy_directory build/blueprint
copy_directory build/soong
copy_directory build/make
@@ -143,41 +142,6 @@
USE_RBE=false TARGET_PRODUCT=aosp_arm TARGET_RELEASE=trunk_staging TARGET_BUILD_VARIANT=userdebug build/soong/soong_ui.bash --make-mode --skip-ninja --skip-config --soong-only --skip-soong-tests "$@"
}
-function create_mock_bazel {
- copy_directory build/bazel
- copy_directory build/bazel_common_rules
-
- # This requires pulling more tools into the mock top to build partitions
- delete_directory build/bazel/examples/partitions
-
- symlink_directory packages/modules/common/build
- symlink_directory prebuilts/bazel
- symlink_directory prebuilts/clang
- symlink_directory prebuilts/jdk
- symlink_directory external/bazel-skylib
- symlink_directory external/bazelbuild-rules_android
- symlink_directory external/bazelbuild-rules_go
- symlink_directory external/bazelbuild-rules_license
- symlink_directory external/bazelbuild-kotlin-rules
- symlink_directory external/bazelbuild-rules_cc
- symlink_directory external/bazelbuild-rules_python
- symlink_directory external/bazelbuild-rules_java
- symlink_directory external/bazelbuild-rules_rust
- symlink_directory external/bazelbuild-rules_testing
- symlink_directory external/rust/crates/tinyjson
-
- symlink_file WORKSPACE
- symlink_file BUILD
-}
-
-function run_bazel {
- # Remove the ninja_build output marker file to communicate to buildbot that this is not a regular Ninja build, and its
- # output should not be parsed as such.
- rm -rf out/ninja_build
-
- build/bazel/bin/bazel "$@"
-}
-
function run_ninja {
build/soong/soong_ui.bash --make-mode --skip-config --soong-only --skip-soong-tests "$@"
}