diff options
| -rw-r--r-- | Android.bp | 2 | ||||
| -rw-r--r-- | android/util.go | 25 | ||||
| -rw-r--r-- | apex/apex.go | 325 | ||||
| -rw-r--r-- | apex/apex_test.go | 124 | ||||
| -rw-r--r-- | cc/cc.go | 51 | ||||
| -rw-r--r-- | cc/cc_test.go | 80 | ||||
| -rw-r--r-- | cc/compiler.go | 3 | ||||
| -rw-r--r-- | cc/fuzz.go | 4 | ||||
| -rw-r--r-- | cc/library.go | 21 | ||||
| -rw-r--r-- | cc/makevars.go | 29 | ||||
| -rw-r--r-- | cc/sabi.go | 2 | ||||
| -rw-r--r-- | cc/sanitize.go | 2 | ||||
| -rw-r--r-- | cc/test.go | 13 | ||||
| -rw-r--r-- | cc/vndk.go | 258 | ||||
| -rw-r--r-- | rust/androidmk.go | 7 | ||||
| -rw-r--r-- | rust/binary_test.go | 17 | ||||
| -rw-r--r-- | rust/rust.go | 9 | ||||
| -rw-r--r-- | rust/test.go | 116 | ||||
| -rw-r--r-- | rust/test_test.go | 43 | ||||
| -rw-r--r-- | rust/testing.go | 3 | ||||
| -rw-r--r-- | sdk/sdk.go | 16 | ||||
| -rw-r--r-- | sdk/update.go | 415 |
22 files changed, 1081 insertions, 484 deletions
diff --git a/Android.bp b/Android.bp index 05972fd36..8d0c1ea6a 100644 --- a/Android.bp +++ b/Android.bp @@ -366,6 +366,7 @@ bootstrap_go_package { "rust/prebuilt.go", "rust/proc_macro.go", "rust/rust.go", + "rust/test.go", "rust/testing.go", ], testSrcs: [ @@ -373,6 +374,7 @@ bootstrap_go_package { "rust/compiler_test.go", "rust/library_test.go", "rust/rust_test.go", + "rust/test_test.go", ], pluginFor: ["soong_build"], } diff --git a/android/util.go b/android/util.go index 71ded5e07..81f481d5f 100644 --- a/android/util.go +++ b/android/util.go @@ -93,6 +93,20 @@ func SortedStringKeys(m interface{}) []string { return s } +func SortedStringMapValues(m interface{}) []string { + v := reflect.ValueOf(m) + if v.Kind() != reflect.Map { + panic(fmt.Sprintf("%#v is not a map", m)) + } + keys := v.MapKeys() + s := make([]string, 0, len(keys)) + for _, key := range keys { + s = append(s, v.MapIndex(key).String()) + } + sort.Strings(s) + return s +} + func IndexList(s string, list []string) int { for i, l := range list { if l == s { @@ -352,3 +366,14 @@ func ShardStrings(s []string, shardSize int) [][]string { } return ret } + +func CheckDuplicate(values []string) (duplicate string, found bool) { + seen := make(map[string]string) + for _, v := range values { + if duplicate, found = seen[v]; found { + return + } + seen[v] = v + } + return +} diff --git a/apex/apex.go b/apex/apex.go index 4ad268060..4e6827f62 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -129,9 +129,11 @@ var ( const ( imageApexSuffix = ".apex" zipApexSuffix = ".zipapex" + flattenedSuffix = ".flattened" - imageApexType = "image" - zipApexType = "zip" + imageApexType = "image" + zipApexType = "zip" + flattenedApexType = "flattened" vndkApexNamePrefix = "com.android.vndk.v" ) @@ -316,13 +318,30 @@ func addApexFileContextsInfos(ctx android.BaseModuleContext, a *apexBundle) { func apexFlattenedMutator(mctx android.BottomUpMutatorContext) { if ab, ok := mctx.Module().(*apexBundle); ok { - if !mctx.Config().FlattenApex() || mctx.Config().UnbundledBuild() { - modules := mctx.CreateLocalVariations("", "flattened") - modules[0].(*apexBundle).SetFlattened(false) - modules[1].(*apexBundle).SetFlattened(true) - } else { - ab.SetFlattened(true) - ab.SetFlattenedConfigValue() + var variants []string + switch proptools.StringDefault(ab.properties.Payload_type, "image") { + case "image": + variants = append(variants, imageApexType, flattenedApexType) + case "zip": + variants = append(variants, zipApexType) + case "both": + variants = append(variants, imageApexType, zipApexType, flattenedApexType) + default: + mctx.PropertyErrorf("type", "%q is not one of \"image\" or \"zip\".", *ab.properties.Payload_type) + return + } + + modules := mctx.CreateLocalVariations(variants...) + + for i, v := range variants { + switch v { + case imageApexType: + modules[i].(*apexBundle).properties.ApexType = imageApex + case zipApexType: + modules[i].(*apexBundle).properties.ApexType = zipApex + case flattenedApexType: + modules[i].(*apexBundle).properties.ApexType = flattenedApex + } } } } @@ -333,6 +352,34 @@ func apexUsesMutator(mctx android.BottomUpMutatorContext) { } } +var ( + useVendorWhitelistKey = android.NewOnceKey("useVendorWhitelist") +) + +// useVendorWhitelist returns the list of APEXes which are allowed to use_vendor. +// When use_vendor is used, native modules are built with __ANDROID_VNDK__ and __ANDROID_APEX__, +// which may cause compatibility issues. (e.g. libbinder) +// Even though libbinder restricts its availability via 'apex_available' property and relies on +// yet another macro __ANDROID_APEX_<NAME>__, we restrict usage of "use_vendor:" from other APEX modules +// to avoid similar problems. +func useVendorWhitelist(config android.Config) []string { + return config.Once(useVendorWhitelistKey, func() interface{} { + return []string{ + // swcodec uses "vendor" variants for smaller size + "com.android.media.swcodec", + "test_com.android.media.swcodec", + } + }).([]string) +} + +// setUseVendorWhitelistForTest overrides useVendorWhitelist and must be +// called before the first call to useVendorWhitelist() +func setUseVendorWhitelistForTest(config android.Config, whitelist []string) { + config.Once(useVendorWhitelistKey, func() interface{} { + return whitelist + }) +} + type apexNativeDependencies struct { // List of native libraries Native_shared_libs []string @@ -438,13 +485,9 @@ type apexBundleProperties struct { // List of APKs to package inside APEX Apps []string - // To distinguish between flattened and non-flattened apex. - // if set true, then output files are flattened. - Flattened bool `blueprint:"mutated"` - - // if true, it means that TARGET_FLATTEN_APEX is true and - // TARGET_BUILD_APPS is false - FlattenedConfigValue bool `blueprint:"mutated"` + // package format of this apex variant; could be non-flattened, flattened, or zip. + // imageApex, zipApex or flattened + ApexType apexPackaging `blueprint:"mutated"` // List of SDKs that are used to build this APEX. A reference to an SDK should be either // `name#version` or `name` which is an alias for `name#current`. If left empty, `platform#current` @@ -501,33 +544,16 @@ type apexPackaging int const ( imageApex apexPackaging = iota zipApex - both + flattenedApex ) -func (a apexPackaging) image() bool { - switch a { - case imageApex, both: - return true - } - return false -} - -func (a apexPackaging) zip() bool { - switch a { - case zipApex, both: - return true - } - return false -} - +// The suffix for the output "file", not the module func (a apexPackaging) suffix() string { switch a { case imageApex: return imageApexSuffix case zipApex: return zipApexSuffix - case both: - panic(fmt.Errorf("must be either zip or image")) default: panic(fmt.Errorf("unknown APEX type %d", a)) } @@ -539,8 +565,6 @@ func (a apexPackaging) name() string { return imageApexType case zipApex: return zipApexType - case both: - panic(fmt.Errorf("must be either zip or image")) default: panic(fmt.Errorf("unknown APEX type %d", a)) } @@ -590,11 +614,8 @@ type apexBundle struct { targetProperties apexTargetBundleProperties vndkProperties apexVndkProperties - apexTypes apexPackaging - bundleModuleFile android.WritablePath - outputFiles map[apexPackaging]android.WritablePath - flattenedOutput android.InstallPath + outputFile android.WritablePath installDir android.InstallPath prebuiltFileToDelete string @@ -611,8 +632,9 @@ type apexBundle struct { // list of module names that this APEX is depending on externalDeps []string - testApex bool - vndkApex bool + testApex bool + vndkApex bool + primaryApexType bool // intermediate path for apex_manifest.json manifestOut android.WritablePath @@ -622,6 +644,10 @@ type apexBundle struct { // apex package itself(for unflattened build) or apex_manifest.json(for flattened build) // so that compat symlinks are always installed regardless of TARGET_FLATTEN_APEX setting. compatSymlinks []string + + // Suffix of module name in Android.mk + // ".flattened", ".apex", ".zipapex", or "" + suffix string } func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, @@ -661,6 +687,10 @@ func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) { } func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { + if proptools.Bool(a.properties.Use_vendor) && !android.InList(a.Name(), useVendorWhitelist(ctx.Config())) { + ctx.PropertyErrorf("use_vendor", "not allowed to set use_vendor: true") + } + targets := ctx.MultiTargets() config := ctx.DeviceConfig() @@ -808,18 +838,7 @@ func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string { func (a *apexBundle) OutputFiles(tag string) (android.Paths, error) { switch tag { case "": - if file, ok := a.outputFiles[imageApex]; ok { - return android.Paths{file}, nil - } else { - return nil, nil - } - case ".flattened": - if a.properties.Flattened { - flattenedApexPath := a.flattenedOutput - return android.Paths{flattenedApexPath}, nil - } else { - return nil, nil - } + return android.Paths{a.outputFile}, nil default: return nil, fmt.Errorf("unsupported module reference tag %q", tag) } @@ -876,24 +895,6 @@ func (a *apexBundle) HideFromMake() { a.properties.HideFromMake = true } -func (a *apexBundle) SetFlattened(flattened bool) { - a.properties.Flattened = flattened -} - -func (a *apexBundle) SetFlattenedConfigValue() { - a.properties.FlattenedConfigValue = true -} - -// isFlattenedVariant returns true when the current module is the flattened -// variant of an apex that has both a flattened and an unflattened variant. -// It returns false when the current module is flattened but there is no -// unflattened variant, which occurs when ctx.Config().FlattenedApex() returns -// true. It can be used to avoid collisions between the install paths of the -// flattened and unflattened variants. -func (a *apexBundle) isFlattenedVariant() bool { - return a.properties.Flattened && !a.properties.FlattenedConfigValue -} - func getCopyManifestForNativeLibrary(ccMod *cc.Module, config android.Config, handleSpecialLibs bool) (fileToCopy android.Path, dirInApex string) { // Decide the APEX-local directory by the multilib of the library // In the future, we may query this to the module. @@ -1012,15 +1013,29 @@ func (c *flattenedApexContext) InstallBypassMake() bool { func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { filesInfo := []apexFile{} - if a.properties.Payload_type == nil || *a.properties.Payload_type == "image" { - a.apexTypes = imageApex - } else if *a.properties.Payload_type == "zip" { - a.apexTypes = zipApex - } else if *a.properties.Payload_type == "both" { - a.apexTypes = both - } else { - ctx.PropertyErrorf("type", "%q is not one of \"image\", \"zip\", or \"both\".", *a.properties.Payload_type) - return + buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild() + switch a.properties.ApexType { + case imageApex: + if buildFlattenedAsDefault { + a.suffix = imageApexSuffix + } else { + a.suffix = "" + a.primaryApexType = true + } + case zipApex: + if proptools.String(a.properties.Payload_type) == "zip" { + a.suffix = "" + a.primaryApexType = true + } else { + a.suffix = zipApexSuffix + } + case flattenedApex: + if buildFlattenedAsDefault { + a.suffix = "" + a.primaryApexType = true + } else { + a.suffix = flattenedSuffix + } } if len(a.properties.Tests) > 0 && !a.testApex { @@ -1266,7 +1281,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // prepend the name of this APEX to the module names. These names will be the names of // modules that will be defined if the APEX is flattened. for i := range filesInfo { - filesInfo[i].moduleName = filesInfo[i].moduleName + "." + ctx.ModuleName() + filesInfo[i].moduleName = filesInfo[i].moduleName + "." + ctx.ModuleName() + a.suffix } a.installDir = android.PathForModuleInstall(ctx, "apex") @@ -1297,27 +1312,14 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { }, }) - // Temporarily wrap the original `ctx` into a `flattenedApexContext` to have it - // reply true to `InstallBypassMake()` (thus making the call - // `android.PathForModuleInstall` below use `android.pathForInstallInMakeDir` - // instead of `android.PathForOutput`) to return the correct path to the flattened - // APEX (as its contents is installed by Make, not Soong). - factx := flattenedApexContext{ctx} - apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName()) - a.flattenedOutput = android.PathForModuleInstall(&factx, "apex", apexName) - - if a.apexTypes.zip() { - a.buildUnflattenedApex(ctx, zipApex) - } - if a.apexTypes.image() { - // Build rule for unflattened APEX is created even when ctx.Config().FlattenApex() - // is true. This is to support referencing APEX via ":<module_name>" syntax - // in other modules. It is in AndroidMk where the selection of flattened - // or unflattened APEX is made. - a.buildUnflattenedApex(ctx, imageApex) + a.setCertificateAndPrivateKey(ctx) + if a.properties.ApexType == flattenedApex { a.buildFlattenedApex(ctx) + } else { + a.buildUnflattenedApex(ctx) } + apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName()) a.compatSymlinks = makeCompatSymlinks(apexName, ctx) } @@ -1343,18 +1345,7 @@ func (a *apexBundle) buildNoticeFile(ctx android.ModuleContext, apexFileName str return android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.FirstUniquePaths(noticeFiles)).HtmlGzOutput } -func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType apexPackaging) { - cert := String(a.properties.Certificate) - if cert != "" && android.SrcIsModule(cert) == "" { - defaultDir := ctx.Config().DefaultAppCertificateDir(ctx) - a.container_certificate_file = defaultDir.Join(ctx, cert+".x509.pem") - a.container_private_key_file = defaultDir.Join(ctx, cert+".pk8") - } else if cert == "" { - pem, key := ctx.Config().DefaultAppCertificate(ctx) - a.container_certificate_file = pem - a.container_private_key_file = key - } - +func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { var abis []string for _, target := range ctx.MultiTargets() { if len(target.Arch.Abi) > 0 { @@ -1364,6 +1355,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap abis = android.FirstUniqueStrings(abis) + apexType := a.properties.ApexType suffix := apexType.suffix() unsignedOutputFile := android.PathForModuleOut(ctx, ctx.ModuleName()+suffix+".unsigned") @@ -1424,7 +1416,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String() prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin") - if apexType.image() { + if apexType == imageApex { // files and dirs that will be created in APEX var readOnlyPaths []string var executablePaths []string // this also includes dirs @@ -1570,11 +1562,11 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap }) } - a.outputFiles[apexType] = android.PathForModuleOut(ctx, ctx.ModuleName()+suffix) + a.outputFile = android.PathForModuleOut(ctx, ctx.ModuleName()+suffix) ctx.Build(pctx, android.BuildParams{ Rule: java.Signapk, Description: "signapk", - Output: a.outputFiles[apexType], + Output: a.outputFile, Input: unsignedOutputFile, Implicits: []android.Path{ a.container_certificate_file, @@ -1587,16 +1579,43 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap }) // Install to $OUT/soong/{target,host}/.../apex - if a.installable() && (!ctx.Config().FlattenApex() || apexType.zip()) && !a.isFlattenedVariant() { - ctx.InstallFile(a.installDir, ctx.ModuleName()+suffix, a.outputFiles[apexType]) + if a.installable() { + ctx.InstallFile(a.installDir, ctx.ModuleName()+suffix, a.outputFile) } + a.buildFilesInfo(ctx) } func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) { + // Temporarily wrap the original `ctx` into a `flattenedApexContext` to have it + // reply true to `InstallBypassMake()` (thus making the call + // `android.PathForModuleInstall` below use `android.pathForInstallInMakeDir` + // instead of `android.PathForOutput`) to return the correct path to the flattened + // APEX (as its contents is installed by Make, not Soong). + factx := flattenedApexContext{ctx} + apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName()) + a.outputFile = android.PathForModuleInstall(&factx, "apex", apexName) + + a.buildFilesInfo(ctx) +} + +func (a *apexBundle) setCertificateAndPrivateKey(ctx android.ModuleContext) { + cert := String(a.properties.Certificate) + if cert != "" && android.SrcIsModule(cert) == "" { + defaultDir := ctx.Config().DefaultAppCertificateDir(ctx) + a.container_certificate_file = defaultDir.Join(ctx, cert+".x509.pem") + a.container_private_key_file = defaultDir.Join(ctx, cert+".pk8") + } else if cert == "" { + pem, key := ctx.Config().DefaultAppCertificate(ctx) + a.container_certificate_file = pem + a.container_private_key_file = key + } +} + +func (a *apexBundle) buildFilesInfo(ctx android.ModuleContext) { if a.installable() { // For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along // with other ordinary files. - a.filesInfo = append(a.filesInfo, apexFile{a.manifestOut, "apex_manifest.json." + ctx.ModuleName(), ".", etc, nil, nil}) + a.filesInfo = append(a.filesInfo, apexFile{a.manifestOut, "apex_manifest.json." + ctx.ModuleName() + a.suffix, ".", etc, nil, nil}) // rename to apex_pubkey copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey") @@ -1605,9 +1624,9 @@ func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) { Input: a.public_key_file, Output: copiedPubkey, }) - a.filesInfo = append(a.filesInfo, apexFile{copiedPubkey, "apex_pubkey." + ctx.ModuleName(), ".", etc, nil, nil}) + a.filesInfo = append(a.filesInfo, apexFile{copiedPubkey, "apex_pubkey." + ctx.ModuleName() + a.suffix, ".", etc, nil, nil}) - if ctx.Config().FlattenApex() { + if a.properties.ApexType == flattenedApex { apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName()) for _, fi := range a.filesInfo { dir := filepath.Join("apex", apexName, fi.installDir) @@ -1627,12 +1646,7 @@ func (a *apexBundle) AndroidMk() android.AndroidMkData { } } writers := []android.AndroidMkData{} - if a.apexTypes.image() { - writers = append(writers, a.androidMkForType(imageApex)) - } - if a.apexTypes.zip() { - writers = append(writers, a.androidMkForType(zipApex)) - } + writers = append(writers, a.androidMkForType()) return android.AndroidMkData{ Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { for _, data := range writers { @@ -1641,36 +1655,35 @@ func (a *apexBundle) AndroidMk() android.AndroidMkData { }} } -func (a *apexBundle) androidMkForFiles(w io.Writer, apexName, moduleDir string, apexType apexPackaging) []string { +func (a *apexBundle) androidMkForFiles(w io.Writer, apexName, moduleDir string) []string { moduleNames := []string{} + apexType := a.properties.ApexType + // To avoid creating duplicate build rules, run this function only when primaryApexType is true + // to install symbol files in $(PRODUCT_OUT}/apex. + // And if apexType is flattened, run this function to install files in $(PRODUCT_OUT}/system/apex. + if !a.primaryApexType && apexType != flattenedApex { + return moduleNames + } for _, fi := range a.filesInfo { if cc, ok := fi.module.(*cc.Module); ok && cc.Properties.HideFromMake { continue } - if a.properties.Flattened && !apexType.image() { - continue - } - - var suffix string - if a.isFlattenedVariant() { - suffix = ".flattened" - } if !android.InList(fi.moduleName, moduleNames) { - moduleNames = append(moduleNames, fi.moduleName+suffix) + moduleNames = append(moduleNames, fi.moduleName) } fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) - fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName+suffix) + fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName) // /apex/<apex_name>/{lib|framework|...} pathWhenActivated := filepath.Join("$(PRODUCT_OUT)", "apex", apexName, fi.installDir) - if a.properties.Flattened && apexType.image() { + if apexType == flattenedApex { // /system/apex/<name>/{lib|framework|...} fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join(a.installDir.ToMakePath().String(), apexName, fi.installDir)) - if !a.isFlattenedVariant() { + if a.primaryApexType { fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated) } if len(fi.symlinks) > 0 { @@ -1739,7 +1752,7 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexName, moduleDir string, } else { fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base()) // For flattened apexes, compat symlinks are attached to apex_manifest.json which is guaranteed for every apex - if !a.isFlattenedVariant() && fi.builtFile.Base() == "apex_manifest.json" && len(a.compatSymlinks) > 0 { + if a.primaryApexType && fi.builtFile.Base() == "apex_manifest.json" && len(a.compatSymlinks) > 0 { fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(a.compatSymlinks, " && ")) } fmt.Fprintln(w, "include $(BUILD_PREBUILT)") @@ -1748,41 +1761,33 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexName, moduleDir string, return moduleNames } -func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkData { +func (a *apexBundle) androidMkForType() android.AndroidMkData { return android.AndroidMkData{ Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { moduleNames := []string{} + apexType := a.properties.ApexType if a.installable() { apexName := proptools.StringDefault(a.properties.Apex_name, name) - moduleNames = a.androidMkForFiles(w, apexName, moduleDir, apexType) - } - - if a.isFlattenedVariant() { - name = name + ".flattened" + moduleNames = a.androidMkForFiles(w, apexName, moduleDir) } - if a.properties.Flattened && apexType.image() { + if apexType == flattenedApex { // Only image APEXes can be flattened. fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) - fmt.Fprintln(w, "LOCAL_MODULE :=", name) + fmt.Fprintln(w, "LOCAL_MODULE :=", name+a.suffix) if len(moduleNames) > 0 { fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " ")) } fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)") - fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): .KATI_IMPLICIT_OUTPUTS :=", a.flattenedOutput.String()) + fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): .KATI_IMPLICIT_OUTPUTS :=", a.outputFile.String()) - } else if !a.isFlattenedVariant() { - // zip-apex is the less common type so have the name refer to the image-apex - // only and use {name}.zip if you want the zip-apex - if apexType == zipApex && a.apexTypes == both { - name = name + ".zip" - } + } else { fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) - fmt.Fprintln(w, "LOCAL_MODULE :=", name) + fmt.Fprintln(w, "LOCAL_MODULE :=", name+a.suffix) fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class? - fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFiles[apexType].String()) + fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String()) fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String()) fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix()) fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable()) @@ -1812,9 +1817,7 @@ func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkD } func newApexBundle() *apexBundle { - module := &apexBundle{ - outputFiles: map[apexPackaging]android.WritablePath{}, - } + module := &apexBundle{} module.AddProperties(&module.properties) module.AddProperties(&module.targetProperties) module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool { diff --git a/apex/apex_test.go b/apex/apex_test.go index ffbee8694..77c1fb035 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -455,12 +455,12 @@ func TestBasicApex(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") optFlags := apexRule.Args["opt_flags"] ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey") // Ensure that the NOTICE output is being packaged as an asset. - ensureContains(t, optFlags, "--assets_dir "+buildDir+"/.intermediates/myapex/android_common_myapex/NOTICE") + ensureContains(t, optFlags, "--assets_dir "+buildDir+"/.intermediates/myapex/android_common_myapex_image/NOTICE") copyCmds := apexRule.Args["copy_commands"] @@ -508,7 +508,7 @@ func TestBasicApex(t *testing.T) { t.Errorf("Could not find all expected symlinks! foo: %t, foo_link_64: %t. Command was %s", found_foo, found_foo_link_64, copyCmds) } - mergeNoticesRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("mergeNoticesRule") + mergeNoticesRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("mergeNoticesRule") noticeInputs := mergeNoticesRule.Inputs.Strings() if len(noticeInputs) != 2 { t.Errorf("number of input notice files: expected = 2, actual = %q", len(noticeInputs)) @@ -548,7 +548,7 @@ func TestBasicZipApex(t *testing.T) { } `) - zipApexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("zipApexRule") + zipApexRule := ctx.ModuleForTests("myapex", "android_common_myapex_zip").Rule("zipApexRule") copyCmds := zipApexRule.Args["copy_commands"] // Ensure that main rule creates an output @@ -617,7 +617,7 @@ func TestApexWithStubs(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -691,7 +691,7 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -765,7 +765,7 @@ func TestApexWithRuntimeLibsDependency(t *testing.T) { `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -777,7 +777,7 @@ func TestApexWithRuntimeLibsDependency(t *testing.T) { // Ensure that runtime_libs dep in included ensureContains(t, copyCmds, "image.apex/lib64/libbar.so") - apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") + apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"])) ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.so") @@ -818,16 +818,17 @@ func TestApexDependencyToLLNDK(t *testing.T) { name: "libbar", symbol_file: "", } + `, func(fs map[string][]byte, config android.Config) { + setUseVendorWhitelistForTest(config, []string{"myapex"}) + }) - `) - - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that LLNDK dep is not included ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so") - apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") + apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"])) // Ensure that LLNDK dep is required @@ -904,7 +905,7 @@ func TestApexWithSystemLibsStubs(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that mylib, libm, libdl are included. @@ -997,7 +998,7 @@ func TestFilesInSubDir(t *testing.T) { } `) - generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("generateFsConfig") + generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("generateFsConfig") dirs := strings.Split(generateFsRule.Args["exec_paths"], " ") // Ensure that the subdirectories are all listed @@ -1047,10 +1048,12 @@ func TestUseVendor(t *testing.T) { vendor_available: true, stl: "none", } - `) + `, func(fs map[string][]byte, config android.Config) { + setUseVendorWhitelistForTest(config, []string{"myapex"}) + }) inputsList := []string{} - for _, i := range ctx.ModuleForTests("myapex", "android_common_myapex").Module().BuildParamsForTests() { + for _, i := range ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().BuildParamsForTests() { for _, implicit := range i.Implicits { inputsList = append(inputsList, implicit.String()) } @@ -1066,6 +1069,38 @@ func TestUseVendor(t *testing.T) { ensureNotContains(t, inputsString, "android_arm64_armv8-a_core_shared_myapex/mylib2.so") } +func TestUseVendorRestriction(t *testing.T) { + testApexError(t, `module "myapex" .*: use_vendor: not allowed`, ` + apex { + name: "myapex", + key: "myapex.key", + use_vendor: true, + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + `, func(fs map[string][]byte, config android.Config) { + setUseVendorWhitelistForTest(config, []string{""}) + }) + // no error with whitelist + testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + use_vendor: true, + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + `, func(fs map[string][]byte, config android.Config) { + setUseVendorWhitelistForTest(config, []string{"myapex"}) + }) +} + func TestUseVendorFailsIfNotVendorAvailable(t *testing.T) { testApexError(t, `dependency "mylib" of "myapex" missing variant:\n.*image:vendor`, ` apex { @@ -1177,7 +1212,7 @@ func TestKeys(t *testing.T) { } // check the APK certs. It should be overridden to myapex.certificate.override - certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk").Args["certificates"] + certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk").Args["certificates"] if certs != "testkey.override.x509.pem testkey.override.pk8" { t.Errorf("cert and private key %q are not %q", certs, "testkey.override.509.pem testkey.override.pk8") @@ -1212,24 +1247,21 @@ func TestMacro(t *testing.T) { } `) - // non-APEX variant does not have __ANDROID__APEX__ defined + // non-APEX variant does not have __ANDROID_APEX(_NAME)__ defined mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_static").Rule("cc").Args["cFlags"] - ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=myapex") - ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=otherapex") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") - // APEX variant has __ANDROID_APEX__=<apexname> defined + // APEX variant has __ANDROID_APEX(_NAME)__ defined mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_static_myapex").Rule("cc").Args["cFlags"] - ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__=myapex") - ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=otherapex") + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") - // APEX variant has __ANDROID_APEX__=<apexname> defined + // APEX variant has __ANDROID_APEX(_NAME)__ defined mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_static_otherapex").Rule("cc").Args["cFlags"] - ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=myapex") - ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__=otherapex") + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") } @@ -1284,7 +1316,7 @@ func TestHeaderLibsDependency(t *testing.T) { func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName string, files []string) { t.Helper() - apexRule := ctx.ModuleForTests(moduleName, "android_common_"+moduleName).Rule("apexRule") + apexRule := ctx.ModuleForTests(moduleName, "android_common_"+moduleName+"_image").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] imageApexDir := "/image.apex/" dstFiles := []string{} @@ -1578,7 +1610,7 @@ func TestVndkApexNameRule(t *testing.T) { }`) assertApexName := func(expected, moduleName string) { - bundle := ctx.ModuleForTests(moduleName, "android_common_"+moduleName).Module().(*apexBundle) + bundle := ctx.ModuleForTests(moduleName, "android_common_"+moduleName+"_image").Module().(*apexBundle) actual := proptools.String(bundle.properties.Apex_name) if !reflect.DeepEqual(actual, expected) { t.Errorf("Got '%v', expected '%v'", actual, expected) @@ -1793,25 +1825,25 @@ func TestDependenciesInApexManifest(t *testing.T) { var apexManifestRule android.TestingBuildParams var provideNativeLibs, requireNativeLibs []string - apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("apexManifestRule") + apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep_image").Rule("apexManifestRule") provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListEmpty(t, provideNativeLibs) ensureListEmpty(t, requireNativeLibs) - apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("apexManifestRule") + apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep_image").Rule("apexManifestRule") provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListEmpty(t, provideNativeLibs) ensureListContains(t, requireNativeLibs, "libfoo.so") - apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("apexManifestRule") + apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider_image").Rule("apexManifestRule") provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListContains(t, provideNativeLibs, "libfoo.so") ensureListEmpty(t, requireNativeLibs) - apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("apexManifestRule") + apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained_image").Rule("apexManifestRule") provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListContains(t, provideNativeLibs, "libfoo.so") @@ -1833,7 +1865,7 @@ func TestApexName(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests("myapex", "android_common_myapex_image") apexManifestRule := module.Rule("apexManifestRule") ensureContains(t, apexManifestRule.Args["opt"], "-v name com.android.myapex") apexRule := module.Rule("apexRule") @@ -1862,7 +1894,7 @@ func TestNonTestApex(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests("myapex", "android_common_myapex_image") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -1913,7 +1945,7 @@ func TestTestApex(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests("myapex", "android_common_myapex_image") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -1997,7 +2029,7 @@ func TestApexWithTarget(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that main rule creates an output @@ -2041,7 +2073,7 @@ func TestApexWithShBinary(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] ensureContains(t, copyCmds, "image.apex/bin/script/myscript.sh") @@ -2071,7 +2103,7 @@ func TestApexInProductPartition(t *testing.T) { } `) - apex := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + apex := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) expected := buildDir + "/target/product/test_device/product/apex" actual := apex.installDir.String() if actual != expected { @@ -2215,7 +2247,7 @@ func TestApexWithTests(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that test dep is copied into apex. @@ -2227,7 +2259,7 @@ func TestApexWithTests(t *testing.T) { ensureContains(t, copyCmds, "image.apex/bin/test/mytest3") // Ensure the module is correctly translated. - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, config, "", apexBundle) name := apexBundle.BaseModuleName() prefix := "TARGET_" @@ -2281,11 +2313,11 @@ func TestApexUsesOtherApex(t *testing.T) { } `) - module1 := ctx.ModuleForTests("myapex", "android_common_myapex") + module1 := ctx.ModuleForTests("myapex", "android_common_myapex_image") apexRule1 := module1.Rule("apexRule") copyCmds1 := apexRule1.Args["copy_commands"] - module2 := ctx.ModuleForTests("commonapex", "android_common_commonapex") + module2 := ctx.ModuleForTests("commonapex", "android_common_commonapex_image") apexRule2 := module2.Rule("apexRule") copyCmds2 := apexRule2.Args["copy_commands"] @@ -2356,7 +2388,9 @@ func TestApexUsesFailsIfUseVenderMismatch(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", } - `) + `, func(fs map[string][]byte, config android.Config) { + setUseVendorWhitelistForTest(config, []string{"myapex"}) + }) } func TestErrorsIfDepsAreNotEnabled(t *testing.T) { @@ -2437,7 +2471,7 @@ func TestApexWithApps(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests("myapex", "android_common_myapex_image") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -2482,7 +2516,7 @@ func TestApexWithAppImports(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests("myapex", "android_common_myapex_image") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -745,17 +745,18 @@ func (c *Module) isNdk() bool { func (c *Module) isLlndk(config android.Config) bool { // Returns true for both LLNDK (public) and LLNDK-private libs. - return inList(c.BaseModuleName(), *llndkLibraries(config)) + return isLlndkLibrary(c.BaseModuleName(), config) } func (c *Module) isLlndkPublic(config android.Config) bool { // Returns true only for LLNDK (public) libs. - return c.isLlndk(config) && !c.isVndkPrivate(config) + name := c.BaseModuleName() + return isLlndkLibrary(name, config) && !isVndkPrivateLibrary(name, config) } func (c *Module) isVndkPrivate(config android.Config) bool { // Returns true for LLNDK-private, VNDK-SP-private, and VNDK-core-private. - return inList(c.BaseModuleName(), *vndkPrivateLibraries(config)) + return isVndkPrivateLibrary(c.BaseModuleName(), config) } func (c *Module) IsVndk() bool { @@ -853,6 +854,27 @@ func (c *Module) nativeCoverage() bool { return c.linker != nil && c.linker.nativeCoverage() } +func (c *Module) ExportedIncludeDirs() android.Paths { + if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok { + return flagsProducer.exportedDirs() + } + return []android.Path{} +} + +func (c *Module) ExportedSystemIncludeDirs() android.Paths { + if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok { + return flagsProducer.exportedSystemDirs() + } + return []android.Path{} +} + +func (c *Module) ExportedFlags() []string { + if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok { + return flagsProducer.exportedFlags() + } + return []string{} +} + func isBionic(name string) bool { switch name { case "libc", "libm", "libdl", "linker": @@ -1456,7 +1478,7 @@ func (c *Module) beginMutator(actx android.BottomUpMutatorContext) { } // Split name#version into name and version -func stubsLibNameAndVersion(name string) (string, string) { +func StubsLibNameAndVersion(name string) (string, string) { if sharp := strings.LastIndex(name, "#"); sharp != -1 && sharp != len(name)-1 { version := name[sharp+1:] libname := name[:sharp] @@ -1496,21 +1518,20 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { // The caller can then know to add the variantLibs dependencies differently from the // nonvariantLibs - llndkLibraries := llndkLibraries(actx.Config()) vendorPublicLibraries := vendorPublicLibraries(actx.Config()) rewriteNdkLibs := func(list []string) (nonvariantLibs []string, variantLibs []string) { variantLibs = []string{} nonvariantLibs = []string{} for _, entry := range list { // strip #version suffix out - name, _ := stubsLibNameAndVersion(entry) + name, _ := StubsLibNameAndVersion(entry) if ctx.useSdk() && inList(name, ndkPrebuiltSharedLibraries) { if !inList(name, ndkMigratedLibs) { nonvariantLibs = append(nonvariantLibs, name+".ndk."+version) } else { variantLibs = append(variantLibs, name+ndkLibrarySuffix) } - } else if ctx.useVndk() && inList(name, *llndkLibraries) { + } else if ctx.useVndk() && isLlndkLibrary(name, ctx.Config()) { nonvariantLibs = append(nonvariantLibs, name+llndkLibrarySuffix) } else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, *vendorPublicLibraries) { vendorPublicLib := name + vendorPublicLibrarySuffix @@ -1609,7 +1630,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { // If the version is not specified, add dependency to the latest stubs library. // The stubs library will be used when the depending module is built for APEX and // the dependent module is not in the same APEX. - latestVersion := latestStubsVersionFor(actx.Config(), name) + latestVersion := LatestStubsVersionFor(actx.Config(), name) if version == "" && latestVersion != "" && versionVariantAvail { actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "shared"}, @@ -1632,7 +1653,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { lib = impl } - name, version := stubsLibNameAndVersion(lib) + name, version := StubsLibNameAndVersion(lib) sharedLibNames = append(sharedLibNames, name) addSharedLibDependencies(depTag, name, version) @@ -1820,7 +1841,6 @@ func checkLinkType(ctx android.ModuleContext, from LinkableInterface, to Linkabl // it is subject to be double loaded. Such lib should be explicitly marked as double_loadable: true // or as vndk-sp (vndk: { enabled: true, support_system_process: true}). func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) { - llndkLibraries := llndkLibraries(ctx.Config()) check := func(child, parent android.Module) bool { to, ok := child.(*Module) if !ok { @@ -1837,7 +1857,7 @@ func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) { return true } - if to.isVndkSp() || inList(child.Name(), *llndkLibraries) || Bool(to.VendorProperties.Double_loadable) { + if to.isVndkSp() || to.isLlndk(ctx.Config()) || Bool(to.VendorProperties.Double_loadable) { return false } @@ -1852,7 +1872,7 @@ func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) { } if module, ok := ctx.Module().(*Module); ok { if lib, ok := module.linker.(*libraryDecorator); ok && lib.shared() { - if inList(ctx.ModuleName(), *llndkLibraries) || Bool(module.VendorProperties.Double_loadable) { + if module.isLlndk(ctx.Config()) || Bool(module.VendorProperties.Double_loadable) { ctx.WalkDeps(check) } } @@ -1866,7 +1886,6 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { directStaticDeps := []LinkableInterface{} directSharedDeps := []LinkableInterface{} - llndkLibraries := llndkLibraries(ctx.Config()) vendorPublicLibraries := vendorPublicLibraries(ctx.Config()) reexportExporter := func(exporter exportedFlagsProducer) { @@ -2138,7 +2157,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { libName := strings.TrimSuffix(depName, llndkLibrarySuffix) libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix) libName = strings.TrimPrefix(libName, "prebuilt_") - isLLndk := inList(libName, *llndkLibraries) + isLLndk := isLlndkLibrary(libName, ctx.Config()) isVendorPublicLib := inList(libName, *vendorPublicLibraries) bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk @@ -2329,7 +2348,9 @@ func (c *Module) IsInstallableToApex() bool { if shared, ok := c.linker.(interface { shared() bool }); ok { - return shared.shared() + // Stub libs and prebuilt libs in a versioned SDK are not + // installable to APEX even though they are shared libs. + return shared.shared() && !c.IsStubs() && c.ContainingSdk().Unversioned() } else if _, ok := c.linker.(testPerSrc); ok { return true } diff --git a/cc/cc_test.go b/cc/cc_test.go index 064b1a25c..808968cf8 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -293,6 +293,7 @@ func TestVndk(t *testing.T) { enabled: true, }, nocrt: true, + stem: "libvndk-private", } cc_library { @@ -303,6 +304,7 @@ func TestVndk(t *testing.T) { support_system_process: true, }, nocrt: true, + suffix: "-x", } cc_library { @@ -313,6 +315,11 @@ func TestVndk(t *testing.T) { support_system_process: true, }, nocrt: true, + target: { + vendor: { + suffix: "-x", + }, + }, } `, config) @@ -345,9 +352,9 @@ func TestVndk(t *testing.T) { checkVndkSnapshot(t, ctx, "libvndk_sp", vndkSpLib2ndPath, variant2nd) checkVndkOutput(t, ctx, "vndk/llndk.libraries.txt", []string{"libc.so", "libdl.so", "libft2.so", "libm.so"}) - checkVndkOutput(t, ctx, "vndk/vndkcore.libraries.txt", []string{"libvndk.so", "libvndk_private.so"}) - checkVndkOutput(t, ctx, "vndk/vndkprivate.libraries.txt", []string{"libft2.so", "libvndk_private.so", "libvndk_sp_private.so"}) - checkVndkOutput(t, ctx, "vndk/vndksp.libraries.txt", []string{"libc++.so", "libvndk_sp.so", "libvndk_sp_private.so"}) + checkVndkOutput(t, ctx, "vndk/vndkcore.libraries.txt", []string{"libvndk-private.so", "libvndk.so"}) + checkVndkOutput(t, ctx, "vndk/vndkprivate.libraries.txt", []string{"libft2.so", "libvndk-private.so", "libvndk_sp_private-x.so"}) + checkVndkOutput(t, ctx, "vndk/vndksp.libraries.txt", []string{"libc++.so", "libvndk_sp-x.so", "libvndk_sp_private-x.so"}) checkVndkOutput(t, ctx, "vndk/vndkcorevariant.libraries.txt", nil) // merged & tagged & filtered-out(libclang_rt) checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{ @@ -356,14 +363,27 @@ func TestVndk(t *testing.T) { "LLNDK: libft2.so", "LLNDK: libm.so", "VNDK-SP: libc++.so", - "VNDK-SP: libvndk_sp.so", - "VNDK-SP: libvndk_sp_private.so", + "VNDK-SP: libvndk_sp-x.so", + "VNDK-SP: libvndk_sp_private-x.so", + "VNDK-core: libvndk-private.so", "VNDK-core: libvndk.so", - "VNDK-core: libvndk_private.so", "VNDK-private: libft2.so", - "VNDK-private: libvndk_private.so", - "VNDK-private: libvndk_sp_private.so", + "VNDK-private: libvndk-private.so", + "VNDK-private: libvndk_sp_private-x.so", + }) + checkVndkOutput(t, ctx, "vndk/llndk.libraries.txt", []string{ + "libc.so", "libdl.so", "libft2.so", "libm.so", }) + checkVndkOutput(t, ctx, "vndk/vndkcore.libraries.txt", []string{ + "libvndk-private.so", "libvndk.so", + }) + checkVndkOutput(t, ctx, "vndk/vndksp.libraries.txt", []string{ + "libc++.so", "libvndk_sp-x.so", "libvndk_sp_private-x.so", + }) + checkVndkOutput(t, ctx, "vndk/vndkprivate.libraries.txt", []string{ + "libft2.so", "libvndk-private.so", "libvndk_sp_private-x.so", + }) + checkVndkOutput(t, ctx, "vndk/vndkcorevariant.libraries.txt", []string{}) } func TestVndkUsingCoreVariant(t *testing.T) { @@ -405,7 +425,36 @@ func TestVndkUsingCoreVariant(t *testing.T) { `, config) checkVndkOutput(t, ctx, "vndk/vndkcore.libraries.txt", []string{"libvndk.so", "libvndk2.so"}) - checkVndkOutput(t, ctx, "vndk/vndkcorevariant.libraries.txt", []string{"libvndk2.so"}) + checkVndkOutput(t, ctx, "vndk/vndkcorevariant.libraries.txt", []string{ + "libc++.so", "libvndk2.so", "libvndk_sp.so", + }) +} + +func TestVndkWhenVndkVersionIsNotSet(t *testing.T) { + config := android.TestArchConfig(buildDir, nil) + config.TestProductVariables.DeviceVndkVersion = nil + config.TestProductVariables.Platform_vndk_version = nil + + ctx := testCcWithConfig(t, ` + cc_library { + name: "libvndk", + vendor_available: true, + vndk: { + enabled: true, + }, + nocrt: true, + } + `, config) + + checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{ + "LLNDK: libc.so", + "LLNDK: libdl.so", + "LLNDK: libft2.so", + "LLNDK: libm.so", + "VNDK-SP: libc++.so", + "VNDK-core: libvndk.so", + "VNDK-private: libft2.so", + }) } func TestVndkDepError(t *testing.T) { @@ -1431,13 +1480,13 @@ func TestMakeLinkType(t *testing.T) { symbol_file: "", }`, config) - assertArrayString(t, *vndkCoreLibraries(config), + assertMapKeys(t, vndkCoreLibraries(config), []string{"libvndk", "libvndkprivate"}) - assertArrayString(t, *vndkSpLibraries(config), + assertMapKeys(t, vndkSpLibraries(config), []string{"libc++", "libvndksp"}) - assertArrayString(t, *llndkLibraries(config), + assertMapKeys(t, llndkLibraries(config), []string{"libc", "libdl", "libft2", "libllndk", "libllndkprivate", "libm"}) - assertArrayString(t, *vndkPrivateLibraries(config), + assertMapKeys(t, vndkPrivateLibraries(config), []string{"libft2", "libllndkprivate", "libvndkprivate"}) vendorVariant27 := "android_arm64_armv8-a_vendor.27_shared" @@ -2419,6 +2468,11 @@ func assertArrayString(t *testing.T, got, expected []string) { } } +func assertMapKeys(t *testing.T, m map[string]string, expected []string) { + t.Helper() + assertArrayString(t, android.SortedStringKeys(m), expected) +} + func TestDefaults(t *testing.T) { ctx := testCc(t, ` cc_defaults { diff --git a/cc/compiler.go b/cc/compiler.go index 438dee701..ff681017e 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -320,8 +320,7 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps } if ctx.apexName() != "" { - // TODO(b/142582178): remove the value for __ANDROID_APEX__ - flags.GlobalFlags = append(flags.GlobalFlags, "-D__ANDROID_APEX__="+ctx.apexName()) + flags.GlobalFlags = append(flags.GlobalFlags, "-D__ANDROID_APEX__") flags.GlobalFlags = append(flags.GlobalFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexName())+"__") } diff --git a/cc/fuzz.go b/cc/fuzz.go index 2c3b973e4..577fa704e 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -149,7 +149,7 @@ func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) { } if fuzz.Properties.Fuzz_config != nil { - configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.txt") + configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json") ctx.Build(pctx, android.BuildParams{ Rule: android.WriteFile, Description: "fuzzer infrastructure configuration", @@ -259,7 +259,7 @@ func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { // The executable. archDirs[archDir] = append(archDirs[archDir], - fileToZip{ccModule.outputFile.Path(), ccModule.Name()}) + fileToZip{ccModule.UnstrippedOutputFile(), ccModule.Name()}) // The corpora. for _, corpusEntry := range fuzzModule.corpus { diff --git a/cc/library.go b/cc/library.go index 5a08879a5..8d90cd8bb 100644 --- a/cc/library.go +++ b/cc/library.go @@ -158,6 +158,10 @@ type FlagExporterProperties struct { // listed in local_include_dirs. Export_include_dirs []string `android:"arch_variant"` + // list of directories that will be added to the system include path + // using -isystem for this module and any module that links against this module. + Export_system_include_dirs []string `android:"arch_variant"` + Target struct { Vendor struct { // list of exported include directories, like @@ -245,10 +249,13 @@ func (f *flagExporter) exportedIncludes(ctx ModuleContext) android.Paths { func (f *flagExporter) exportIncludes(ctx ModuleContext) { f.dirs = append(f.dirs, f.exportedIncludes(ctx)...) + f.systemDirs = append(f.systemDirs, android.PathsForModuleSrc(ctx, f.Properties.Export_system_include_dirs)...) } func (f *flagExporter) exportIncludesAsSystem(ctx ModuleContext) { + // all dirs are force exported as system f.systemDirs = append(f.systemDirs, f.exportedIncludes(ctx)...) + f.systemDirs = append(f.systemDirs, android.PathsForModuleSrc(ctx, f.Properties.Export_system_include_dirs)...) } func (f *flagExporter) reexportDirs(dirs ...android.Path) { @@ -579,24 +586,28 @@ type libraryInterface interface { availableFor(string) bool } -func (library *libraryDecorator) getLibName(ctx BaseModuleContext) string { +func (library *libraryDecorator) getLibNameHelper(baseModuleName string, useVndk bool) string { name := library.libName if name == "" { name = String(library.Properties.Stem) if name == "" { - name = ctx.baseModuleName() + name = baseModuleName } } suffix := "" - if ctx.useVndk() { + if useVndk { suffix = String(library.Properties.Target.Vendor.Suffix) } if suffix == "" { suffix = String(library.Properties.Suffix) } - name += suffix + return name + suffix +} + +func (library *libraryDecorator) getLibName(ctx BaseModuleContext) string { + name := library.getLibNameHelper(ctx.baseModuleName(), ctx.useVndk()) if ctx.isVndkExt() { // vndk-ext lib should have the same name with original lib @@ -1294,7 +1305,7 @@ func stubsVersionsFor(config android.Config) map[string][]string { var stubsVersionsLock sync.Mutex -func latestStubsVersionFor(config android.Config, name string) string { +func LatestStubsVersionFor(config android.Config, name string) string { versions, ok := stubsVersionsFor(config)[name] if ok && len(versions) > 0 { // the versions are alreay sorted in ascending order diff --git a/cc/makevars.go b/cc/makevars.go index f9c58b931..e8cedf0f6 100644 --- a/cc/makevars.go +++ b/cc/makevars.go @@ -101,35 +101,6 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion()) - ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(*vndkCoreLibraries(ctx.Config()), " ")) - ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(*vndkSpLibraries(ctx.Config()), " ")) - - // Make uses LLNDK_LIBRARIES to determine which libraries to install. - // HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN. - // Therefore, by removing the library here, we cause it to only be installed if libc - // depends on it. - installedLlndkLibraries := []string{} - - // Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if - // they been moved to an apex. - movedToApexLlndkLibraries := []string{} - for _, lib := range *llndkLibraries(ctx.Config()) { - if strings.HasPrefix(lib, "libclang_rt.hwasan-") { - continue - } - installedLlndkLibraries = append(installedLlndkLibraries, lib) - - // Skip bionic libs, they are handled in different manner - if android.DirectlyInAnyApex(¬OnHostContext{}, lib) && !isBionic(lib) { - movedToApexLlndkLibraries = append(movedToApexLlndkLibraries, lib) - } - } - ctx.Strict("LLNDK_LIBRARIES", strings.Join(installedLlndkLibraries, " ")) - ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", strings.Join(movedToApexLlndkLibraries, " ")) - - ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(*vndkPrivateLibraries(ctx.Config()), " ")) - ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(*vndkUsingCoreVariantLibraries(ctx.Config()), " ")) - // Filter vendor_public_library that are exported to make exportedVendorPublicLibraries := []string{} ctx.VisitAllModules(func(module android.Module) { diff --git a/cc/sabi.go b/cc/sabi.go index 8a9eff026..4760313e6 100644 --- a/cc/sabi.go +++ b/cc/sabi.go @@ -78,7 +78,7 @@ func (sabimod *sabi) flags(ctx ModuleContext, flags Flags) Flags { func sabiDepsMutator(mctx android.TopDownMutatorContext) { if c, ok := mctx.Module().(*Module); ok && - ((c.IsVndk() && c.UseVndk()) || inList(c.Name(), *llndkLibraries(mctx.Config())) || + ((c.IsVndk() && c.UseVndk()) || c.isLlndk(mctx.Config()) || (c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) { mctx.VisitDirectDeps(func(m android.Module) { tag := mctx.OtherModuleDependencyTag(m) diff --git a/cc/sanitize.go b/cc/sanitize.go index e4c6b1c06..a3b4e8ebd 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -873,7 +873,7 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { } if mctx.Device() && runtimeLibrary != "" { - if inList(runtimeLibrary, *llndkLibraries(mctx.Config())) && !c.static() && c.UseVndk() { + if isLlndkLibrary(runtimeLibrary, mctx.Config()) && !c.static() && c.UseVndk() { runtimeLibrary = runtimeLibrary + llndkLibrarySuffix } diff --git a/cc/test.go b/cc/test.go index 0e66e288e..5c49d6e2b 100644 --- a/cc/test.go +++ b/cc/test.go @@ -173,7 +173,7 @@ func TestPerSrcMutator(mctx android.BottomUpMutatorContext) { if test, ok := m.linker.(testPerSrc); ok { numTests := len(test.srcs()) if test.testPerSrc() && numTests > 0 { - if duplicate, found := checkDuplicate(test.srcs()); found { + if duplicate, found := android.CheckDuplicate(test.srcs()); found { mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate) return } @@ -206,17 +206,6 @@ func TestPerSrcMutator(mctx android.BottomUpMutatorContext) { } } -func checkDuplicate(values []string) (duplicate string, found bool) { - seen := make(map[string]string) - for _, v := range values { - if duplicate, found = seen[v]; found { - return - } - seen[v] = v - } - return -} - type testDecorator struct { Properties TestProperties linker *baseLinker diff --git a/cc/vndk.go b/cc/vndk.go index 47c3177ce..d6c2f6ff9 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -17,8 +17,8 @@ package cc import ( "encoding/json" "errors" + "fmt" "path/filepath" - "sort" "strings" "sync" @@ -207,34 +207,44 @@ var ( headerExts = []string{".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"} ) -func vndkCoreLibraries(config android.Config) *[]string { +func vndkCoreLibraries(config android.Config) map[string]string { return config.Once(vndkCoreLibrariesKey, func() interface{} { - return &[]string{} - }).(*[]string) + return make(map[string]string) + }).(map[string]string) } -func vndkSpLibraries(config android.Config) *[]string { +func vndkSpLibraries(config android.Config) map[string]string { return config.Once(vndkSpLibrariesKey, func() interface{} { - return &[]string{} - }).(*[]string) + return make(map[string]string) + }).(map[string]string) } -func llndkLibraries(config android.Config) *[]string { +func isLlndkLibrary(baseModuleName string, config android.Config) bool { + _, ok := llndkLibraries(config)[baseModuleName] + return ok +} + +func llndkLibraries(config android.Config) map[string]string { return config.Once(llndkLibrariesKey, func() interface{} { - return &[]string{} - }).(*[]string) + return make(map[string]string) + }).(map[string]string) +} + +func isVndkPrivateLibrary(baseModuleName string, config android.Config) bool { + _, ok := vndkPrivateLibraries(config)[baseModuleName] + return ok } -func vndkPrivateLibraries(config android.Config) *[]string { +func vndkPrivateLibraries(config android.Config) map[string]string { return config.Once(vndkPrivateLibrariesKey, func() interface{} { - return &[]string{} - }).(*[]string) + return make(map[string]string) + }).(map[string]string) } -func vndkUsingCoreVariantLibraries(config android.Config) *[]string { +func vndkUsingCoreVariantLibraries(config android.Config) map[string]string { return config.Once(vndkUsingCoreVariantLibrariesKey, func() interface{} { - return &[]string{} - }).(*[]string) + return make(map[string]string) + }).(map[string]string) } func modulePaths(config android.Config) map[string]string { @@ -265,63 +275,44 @@ func setVndkMustUseVendorVariantListForTest(config android.Config, mustUseVendor func processLlndkLibrary(mctx android.BottomUpMutatorContext, m *Module) { lib := m.linker.(*llndkStubDecorator) - name := strings.TrimSuffix(m.Name(), llndkLibrarySuffix) + name := m.BaseModuleName() + filename := m.BaseModuleName() + ".so" vndkLibrariesLock.Lock() defer vndkLibrariesLock.Unlock() - llndkLibraries := llndkLibraries(mctx.Config()) - if !inList(name, *llndkLibraries) { - *llndkLibraries = append(*llndkLibraries, name) - sort.Strings(*llndkLibraries) - } + llndkLibraries(mctx.Config())[name] = filename if !Bool(lib.Properties.Vendor_available) { - vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config()) - if !inList(name, *vndkPrivateLibraries) { - *vndkPrivateLibraries = append(*vndkPrivateLibraries, name) - sort.Strings(*vndkPrivateLibraries) - } + vndkPrivateLibraries(mctx.Config())[name] = filename } } func processVndkLibrary(mctx android.BottomUpMutatorContext, m *Module) { - name := strings.TrimPrefix(m.Name(), "prebuilt_") + name := m.BaseModuleName() + filename, err := getVndkFileName(m) + if err != nil { + panic(err) + } vndkLibrariesLock.Lock() defer vndkLibrariesLock.Unlock() - modulePaths := modulePaths(mctx.Config()) + modulePaths(mctx.Config())[name] = mctx.ModuleDir() + if inList(name, vndkMustUseVendorVariantList(mctx.Config())) { m.Properties.MustUseVendorVariant = true } - if mctx.DeviceConfig().VndkUseCoreVariant() && !inList(name, vndkMustUseVendorVariantList(mctx.Config())) { - vndkUsingCoreVariantLibraries := vndkUsingCoreVariantLibraries(mctx.Config()) - if !inList(name, *vndkUsingCoreVariantLibraries) { - *vndkUsingCoreVariantLibraries = append(*vndkUsingCoreVariantLibraries, name) - sort.Strings(*vndkUsingCoreVariantLibraries) - } + if mctx.DeviceConfig().VndkUseCoreVariant() && !m.Properties.MustUseVendorVariant { + vndkUsingCoreVariantLibraries(mctx.Config())[name] = filename } + if m.vndkdep.isVndkSp() { - vndkSpLibraries := vndkSpLibraries(mctx.Config()) - if !inList(name, *vndkSpLibraries) { - *vndkSpLibraries = append(*vndkSpLibraries, name) - sort.Strings(*vndkSpLibraries) - modulePaths[name] = mctx.ModuleDir() - } + vndkSpLibraries(mctx.Config())[name] = filename } else { - vndkCoreLibraries := vndkCoreLibraries(mctx.Config()) - if !inList(name, *vndkCoreLibraries) { - *vndkCoreLibraries = append(*vndkCoreLibraries, name) - sort.Strings(*vndkCoreLibraries) - modulePaths[name] = mctx.ModuleDir() - } + vndkCoreLibraries(mctx.Config())[name] = filename } if !Bool(m.VendorProperties.Vendor_available) { - vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config()) - if !inList(name, *vndkPrivateLibraries) { - *vndkPrivateLibraries = append(*vndkPrivateLibraries, name) - sort.Strings(*vndkPrivateLibraries) - } + vndkPrivateLibraries(mctx.Config())[name] = filename } } @@ -395,9 +386,20 @@ func VndkSnapshotSingleton() android.Singleton { return &vndkSnapshotSingleton{} } -type vndkSnapshotSingleton struct{} +type vndkSnapshotSingleton struct { + installedLlndkLibraries []string + llnkdLibrariesFile android.Path + vndkSpLibrariesFile android.Path + vndkCoreLibrariesFile android.Path + vndkPrivateLibrariesFile android.Path + vndkCoreVariantLibrariesFile android.Path + vndkLibrariesFile android.Path +} func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { + // build these files even if PlatformVndkVersion or BoardVndkVersion is not set + c.buildVndkLibrariesTxtFiles(ctx) + // BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot. if ctx.DeviceConfig().VndkVersion() != "current" { return @@ -411,8 +413,6 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex return } - c.buildVndkLibrariesTxtFiles(ctx) - outputs := vndkSnapshotOutputs(ctx.Config()) snapshotDir := "vndk-snapshot" @@ -481,9 +481,9 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex } } - vndkCoreLibraries := vndkCoreLibraries(ctx.Config()) - vndkSpLibraries := vndkSpLibraries(ctx.Config()) - vndkPrivateLibraries := vndkPrivateLibraries(ctx.Config()) + vndkCoreLibraries := android.SortedStringKeys(vndkCoreLibraries(ctx.Config())) + vndkSpLibraries := android.SortedStringKeys(vndkSpLibraries(ctx.Config())) + vndkPrivateLibraries := android.SortedStringKeys(vndkPrivateLibraries(ctx.Config())) var generatedHeaders android.Paths includeDirs := make(map[string]bool) @@ -540,9 +540,9 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex return nil, "", false } name := ctx.ModuleName(m) - if inList(name, *vndkCoreLibraries) { + if inList(name, vndkCoreLibraries) { return l, filepath.Join("shared", "vndk-core"), true - } else if inList(name, *vndkSpLibraries) { + } else if inList(name, vndkSpLibraries) { return l, filepath.Join("shared", "vndk-sp"), true } else { return nil, "", false @@ -628,9 +628,9 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex } } - installSnapshotFileFromContent(android.JoinWithSuffix(*vndkCoreLibraries, ".so", "\\n"), + installSnapshotFileFromContent(android.JoinWithSuffix(vndkCoreLibraries, ".so", "\\n"), filepath.Join(configsDir, "vndkcore.libraries.txt")) - installSnapshotFileFromContent(android.JoinWithSuffix(*vndkPrivateLibraries, ".so", "\\n"), + installSnapshotFileFromContent(android.JoinWithSuffix(vndkPrivateLibraries, ".so", "\\n"), filepath.Join(configsDir, "vndkprivate.libraries.txt")) var modulePathTxtBuilder strings.Builder @@ -653,75 +653,60 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex filepath.Join(configsDir, "module_paths.txt")) } -func installListFile(ctx android.SingletonContext, list []string, pathComponents ...string) android.OutputPath { - out := android.PathForOutput(ctx, pathComponents...) - ctx.Build(pctx, android.BuildParams{ - Rule: android.WriteFile, - Output: out, - Description: "Writing " + out.String(), - Args: map[string]string{ - "content": strings.Join(list, "\\n"), - }, - }) - return out +func getVndkFileName(m *Module) (string, error) { + if library, ok := m.linker.(*libraryDecorator); ok { + return library.getLibNameHelper(m.BaseModuleName(), true) + ".so", nil + } + if prebuilt, ok := m.linker.(*prebuiltLibraryLinker); ok { + return prebuilt.libraryDecorator.getLibNameHelper(m.BaseModuleName(), true) + ".so", nil + } + return "", fmt.Errorf("VNDK library should have libraryDecorator or prebuiltLibraryLinker as linker: %T", m.linker) } func (c *vndkSnapshotSingleton) buildVndkLibrariesTxtFiles(ctx android.SingletonContext) { - var ( - llndk, vndkcore, vndksp, vndkprivate, vndkcorevariant, merged []string - ) - vndkVersion := ctx.DeviceConfig().PlatformVndkVersion() - config := ctx.Config() - ctx.VisitAllModules(func(m android.Module) { - if !m.Enabled() { - return - } - c, ok := m.(*Module) - if !ok || c.Os().Class != android.Device { - return - } - lib, ok := c.linker.(interface{ shared() bool }) - if !ok || !lib.shared() { - return + // Make uses LLNDK_LIBRARIES to determine which libraries to install. + // HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN. + // Therefore, by removing the library here, we cause it to only be installed if libc + // depends on it. + installedLlndkLibraries := make(map[string]string) + for lib, filename := range llndkLibraries(ctx.Config()) { + if strings.HasPrefix(lib, "libclang_rt.hwasan-") { + continue } + installedLlndkLibraries[lib] = filename + } - if !c.OutputFile().Valid() { - return - } + installListFile := func(list []string, fileName string) android.Path { + out := android.PathForOutput(ctx, "vndk", fileName) + ctx.Build(pctx, android.BuildParams{ + Rule: android.WriteFile, + Output: out, + Description: "Writing " + out.String(), + Args: map[string]string{ + "content": strings.Join(list, "\\n"), + }, + }) + return out + } - filename := c.OutputFile().Path().Base() - if c.isLlndk(config) { - llndk = append(llndk, filename) - if c.isVndkPrivate(config) { - vndkprivate = append(vndkprivate, filename) - } - } else if c.vndkVersion() == vndkVersion && c.IsVndk() && !c.isVndkExt() { - if c.isVndkSp() { - vndksp = append(vndksp, filename) - } else { - vndkcore = append(vndkcore, filename) - } - if c.isVndkPrivate(config) { - vndkprivate = append(vndkprivate, filename) - } - if ctx.DeviceConfig().VndkUseCoreVariant() && !c.MustUseVendorVariant() { - vndkcorevariant = append(vndkcorevariant, filename) - } - } - }) - llndk = android.SortedUniqueStrings(llndk) - vndkcore = android.SortedUniqueStrings(vndkcore) - vndksp = android.SortedUniqueStrings(vndksp) - vndkprivate = android.SortedUniqueStrings(vndkprivate) - vndkcorevariant = android.SortedUniqueStrings(vndkcorevariant) - - installListFile(ctx, llndk, "vndk", "llndk.libraries.txt") - installListFile(ctx, vndkcore, "vndk", "vndkcore.libraries.txt") - installListFile(ctx, vndksp, "vndk", "vndksp.libraries.txt") - installListFile(ctx, vndkprivate, "vndk", "vndkprivate.libraries.txt") - installListFile(ctx, vndkcorevariant, "vndk", "vndkcorevariant.libraries.txt") + c.installedLlndkLibraries = android.SortedStringKeys(installedLlndkLibraries) + + llndk := android.SortedStringMapValues(installedLlndkLibraries) + vndkcore := android.SortedStringMapValues(vndkCoreLibraries(ctx.Config())) + vndksp := android.SortedStringMapValues(vndkSpLibraries(ctx.Config())) + vndkprivate := android.SortedStringMapValues(vndkPrivateLibraries(ctx.Config())) + vndkcorevariant := android.SortedStringMapValues(vndkUsingCoreVariantLibraries(ctx.Config())) + + c.llnkdLibrariesFile = installListFile(llndk, "llndk.libraries.txt") + c.vndkCoreLibrariesFile = installListFile(vndkcore, "vndkcore.libraries.txt") + c.vndkSpLibrariesFile = installListFile(vndksp, "vndksp.libraries.txt") + c.vndkPrivateLibrariesFile = installListFile(vndkprivate, "vndkprivate.libraries.txt") + c.vndkCoreVariantLibrariesFile = installListFile(vndkcorevariant, "vndkcorevariant.libraries.txt") // merged & tagged & filtered-out(libclang_rt) + // Since each target have different set of libclang_rt.* files, + // keep the common set of files in vndk.libraries.txt + var merged []string filterOutLibClangRt := func(libList []string) (filtered []string) { for _, lib := range libList { if !strings.HasPrefix(lib, "libclang_rt.") { @@ -734,6 +719,31 @@ func (c *vndkSnapshotSingleton) buildVndkLibrariesTxtFiles(ctx android.Singleton merged = append(merged, addPrefix(vndksp, "VNDK-SP: ")...) merged = append(merged, addPrefix(filterOutLibClangRt(vndkcore), "VNDK-core: ")...) merged = append(merged, addPrefix(vndkprivate, "VNDK-private: ")...) + c.vndkLibrariesFile = installListFile(merged, "vndk.libraries.txt") +} - installListFile(ctx, merged, "vndk", "vndk.libraries.txt") +func (c *vndkSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) { + // Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if + // they been moved to an apex. + movedToApexLlndkLibraries := []string{} + for _, lib := range c.installedLlndkLibraries { + // Skip bionic libs, they are handled in different manner + if android.DirectlyInAnyApex(¬OnHostContext{}, lib) && !isBionic(lib) { + movedToApexLlndkLibraries = append(movedToApexLlndkLibraries, lib) + } + } + ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", strings.Join(movedToApexLlndkLibraries, " ")) + ctx.Strict("LLNDK_LIBRARIES", strings.Join(c.installedLlndkLibraries, " ")) + ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(android.SortedStringKeys(vndkCoreLibraries(ctx.Config())), " ")) + ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(android.SortedStringKeys(vndkSpLibraries(ctx.Config())), " ")) + ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(android.SortedStringKeys(vndkPrivateLibraries(ctx.Config())), " ")) + ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(android.SortedStringKeys(vndkUsingCoreVariantLibraries(ctx.Config())), " ")) + + ctx.Strict("LLNDK_LIBRARIES_FILE", c.llnkdLibrariesFile.String()) + ctx.Strict("VNDKCORE_LIBRARIES_FILE", c.vndkCoreLibrariesFile.String()) + ctx.Strict("VNDKSP_LIBRARIES_FILE", c.vndkSpLibrariesFile.String()) + ctx.Strict("VNDKPRIVATE_LIBRARIES_FILE", c.vndkPrivateLibrariesFile.String()) + ctx.Strict("VNDKCOREVARIANT_LIBRARIES_FILE", c.vndkCoreVariantLibrariesFile.String()) + + ctx.Strict("VNDK_LIBRARIES_FILE", c.vndkLibrariesFile.String()) } diff --git a/rust/androidmk.go b/rust/androidmk.go index f933cfbcf..49115f219 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -72,6 +72,8 @@ func (mod *Module) AndroidMk() android.AndroidMkData { mod.subAndroidMk(&ret, mod.compiler) + ret.SubName += mod.Properties.SubName + return ret } @@ -85,6 +87,11 @@ func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.Andr }) } +func (test *testBinaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + test.binaryDecorator.AndroidMk(ctx, ret) + ret.SubName = "_" + String(test.baseCompiler.Properties.Stem) +} + func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { ctx.subAndroidMk(ret, library.baseCompiler) diff --git a/rust/binary_test.go b/rust/binary_test.go index cd41fcfae..ab2dae153 100644 --- a/rust/binary_test.go +++ b/rust/binary_test.go @@ -36,11 +36,20 @@ func TestPreferDynamicBinary(t *testing.T) { fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz") fizzBuzzDynamic := ctx.ModuleForTests("fizz-buzz-dynamic", "linux_glibc_x86_64").Output("fizz-buzz-dynamic") - if !strings.Contains(fizzBuzzDynamic.Args["rustcFlags"], "prefer-dynamic") { - t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", fizzBuzzDynamic.Args["rustcFlags"]) + // Do not compile binary modules with the --test flag. + flags := fizzBuzzDynamic.Args["rustcFlags"] + if strings.Contains(flags, "--test") { + t.Errorf("extra --test flag, rustcFlags: %#v", flags) + } + if !strings.Contains(flags, "prefer-dynamic") { + t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", flags) } - if strings.Contains(fizzBuzz.Args["rustcFlags"], "prefer-dynamic") { - t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", fizzBuzz.Args["rustcFlags"]) + flags = fizzBuzz.Args["rustcFlags"] + if strings.Contains(flags, "--test") { + t.Errorf("extra --test flag, rustcFlags: %#v", flags) + } + if strings.Contains(flags, "prefer-dynamic") { + t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", flags) } } diff --git a/rust/rust.go b/rust/rust.go index ce81b9152..ec3b59086 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -39,6 +39,7 @@ func init() { android.RegisterModuleType("rust_defaults", defaultsFactory) android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("rust_libraries", LibraryMutator).Parallel() + ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel() }) pctx.Import("android/soong/rust/config") } @@ -58,6 +59,7 @@ type BaseProperties struct { AndroidMkProcMacroLibs []string AndroidMkSharedLibs []string AndroidMkStaticLibs []string + SubName string `blueprint:"mutated"` } type Module struct { @@ -495,9 +497,10 @@ type dependencyTag struct { } var ( - rlibDepTag = dependencyTag{name: "rlibTag", library: true} - dylibDepTag = dependencyTag{name: "dylib", library: true} - procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true} + rlibDepTag = dependencyTag{name: "rlibTag", library: true} + dylibDepTag = dependencyTag{name: "dylib", library: true} + procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true} + testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"} ) func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { diff --git a/rust/test.go b/rust/test.go new file mode 100644 index 000000000..816e3c731 --- /dev/null +++ b/rust/test.go @@ -0,0 +1,116 @@ +// Copyright 2019 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 rust + +import ( + "path/filepath" + "strings" + + "android/soong/android" +) + +// A test module is a binary module with extra --test compiler flag +// and different default installation directory. +// In golang, inheriance is written as a component. +type testBinaryDecorator struct { + *binaryDecorator +} + +func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testBinaryDecorator) { + module := newModule(hod, android.MultilibFirst) + + test := &testBinaryDecorator{ + binaryDecorator: &binaryDecorator{ + // TODO(chh): set up dir64? + baseCompiler: NewBaseCompiler("testcases", ""), + }, + } + + module.compiler = test + + return module, test +} + +func (test *testBinaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { + flags = test.binaryDecorator.compilerFlags(ctx, flags) + flags.RustFlags = append(flags.RustFlags, "--test") + return flags +} + +func init() { + // Rust tests are binary files built with --test. + android.RegisterModuleType("rust_test", RustTestFactory) + android.RegisterModuleType("rust_test_host", RustTestHostFactory) +} + +func RustTestFactory() android.Module { + module, _ := NewRustTest(android.HostAndDeviceSupported) + return module.Init() +} + +func RustTestHostFactory() android.Module { + module, _ := NewRustTest(android.HostSupported) + return module.Init() +} + +func (test *testBinaryDecorator) testPerSrc() bool { + return true +} + +func (test *testBinaryDecorator) srcs() []string { + return test.Properties.Srcs +} + +func (test *testBinaryDecorator) setSrc(name, src string) { + test.Properties.Srcs = []string{src} + test.baseCompiler.Properties.Stem = StringPtr(name) +} + +func (test *testBinaryDecorator) unsetSrc() { + test.Properties.Srcs = nil + test.baseCompiler.Properties.Stem = StringPtr("") +} + +type testPerSrc interface { + testPerSrc() bool + srcs() []string + setSrc(string, string) + unsetSrc() +} + +var _ testPerSrc = (*testBinaryDecorator)(nil) + +func TestPerSrcMutator(mctx android.BottomUpMutatorContext) { + if m, ok := mctx.Module().(*Module); ok { + if test, ok := m.compiler.(testPerSrc); ok { + numTests := len(test.srcs()) + if test.testPerSrc() && numTests > 0 { + if duplicate, found := android.CheckDuplicate(test.srcs()); found { + mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate) + return + } + testNames := make([]string, numTests) + for i, src := range test.srcs() { + testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src)) + } + // TODO(chh): Add an "all tests" variation like cc/test.go? + tests := mctx.CreateLocalVariations(testNames...) + for i, src := range test.srcs() { + tests[i].(*Module).compiler.(testPerSrc).setSrc(testNames[i], src) + } + } + } + } +} diff --git a/rust/test_test.go b/rust/test_test.go new file mode 100644 index 000000000..aa4c3c8cb --- /dev/null +++ b/rust/test_test.go @@ -0,0 +1,43 @@ +// Copyright 2019 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 rust + +import ( + "strings" + "testing" +) + +// Check if rust_test_host accepts multiple source files and applies --test flag. +func TestRustTest(t *testing.T) { + ctx := testRust(t, ` + rust_test_host { + name: "my_test", + srcs: ["foo.rs", "src/bar.rs"], + relative_install_path: "rust/my-test", + }`) + + for _, name := range []string{"foo", "bar"} { + testingModule := ctx.ModuleForTests("my_test", "linux_glibc_x86_64_"+name) + testingBuildParams := testingModule.Output(name) + rustcFlags := testingBuildParams.Args["rustcFlags"] + if !strings.Contains(rustcFlags, "--test") { + t.Errorf("%v missing --test flag, rustcFlags: %#v", name, rustcFlags) + } + outPath := "/my_test/linux_glibc_x86_64_" + name + "/" + name + if !strings.Contains(testingBuildParams.Output.String(), outPath) { + t.Errorf("wrong output: %v expect: %v", testingBuildParams.Output, outPath) + } + } +} diff --git a/rust/testing.go b/rust/testing.go index cd6308434..24defa634 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -168,6 +168,8 @@ func CreateTestContext(bp string) *android.TestContext { ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory)) ctx.RegisterModuleType("rust_binary", android.ModuleFactoryAdaptor(RustBinaryFactory)) ctx.RegisterModuleType("rust_binary_host", android.ModuleFactoryAdaptor(RustBinaryHostFactory)) + ctx.RegisterModuleType("rust_test", android.ModuleFactoryAdaptor(RustTestFactory)) + ctx.RegisterModuleType("rust_test_host", android.ModuleFactoryAdaptor(RustTestHostFactory)) ctx.RegisterModuleType("rust_library", android.ModuleFactoryAdaptor(RustLibraryFactory)) ctx.RegisterModuleType("rust_library_host", android.ModuleFactoryAdaptor(RustLibraryHostFactory)) ctx.RegisterModuleType("rust_library_host_rlib", android.ModuleFactoryAdaptor(RustLibraryRlibHostFactory)) @@ -190,6 +192,7 @@ func CreateTestContext(bp string) *android.TestContext { // rust mutators ctx.BottomUp("rust_libraries", LibraryMutator).Parallel() + ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel() }) bp = bp + GatherRequiredDepsForTest() diff --git a/sdk/sdk.go b/sdk/sdk.go index d189043f8..002fb5dc7 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -24,6 +24,7 @@ import ( // This package doesn't depend on the apex package, but import it to make its mutators to be // registered before mutators in this package. See RegisterPostDepsMutators for more details. _ "android/soong/apex" + "android/soong/cc" ) func init() { @@ -148,10 +149,17 @@ func memberMutator(mctx android.BottomUpMutatorContext) { targets := mctx.MultiTargets() for _, target := range targets { - mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ - {Mutator: "image", Variation: "core"}, - {Mutator: "link", Variation: "shared"}, - }...), sdkMemberDepTag, m.properties.Native_shared_libs...) + for _, lib := range m.properties.Native_shared_libs { + name, version := cc.StubsLibNameAndVersion(lib) + if version == "" { + version = cc.LatestStubsVersionFor(mctx.Config(), name) + } + mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ + {Mutator: "image", Variation: "core"}, + {Mutator: "link", Variation: "shared"}, + {Mutator: "version", Variation: version}, + }...), sdkMemberDepTag, name) + } } } } diff --git a/sdk/update.go b/sdk/update.go index 5235c9ef4..ce6082799 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -24,6 +24,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/cc" "android/soong/java" ) @@ -32,21 +33,31 @@ var pctx = android.NewPackageContext("android/soong/sdk") // generatedFile abstracts operations for writing contents into a file and emit a build rule // for the file. type generatedFile struct { - path android.OutputPath - content strings.Builder + path android.OutputPath + content strings.Builder + indentLevel int } func newGeneratedFile(ctx android.ModuleContext, name string) *generatedFile { return &generatedFile{ - path: android.PathForModuleOut(ctx, name).OutputPath, + path: android.PathForModuleOut(ctx, name).OutputPath, + indentLevel: 0, } } +func (gf *generatedFile) indent() { + gf.indentLevel++ +} + +func (gf *generatedFile) dedent() { + gf.indentLevel-- +} + func (gf *generatedFile) printfln(format string, args ...interface{}) { // ninja consumes newline characters in rspfile_content. Prevent it by // escaping the backslash in the newline character. The extra backshash // is removed when the rspfile is written to the actual script file - fmt.Fprintf(&(gf.content), format+"\\n", args...) + fmt.Fprintf(&(gf.content), strings.Repeat(" ", gf.indentLevel)+format+"\\n", args...) } func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderContext, implicits android.Paths) { @@ -61,34 +72,187 @@ func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderC rb.Build(pctx, ctx, gf.path.Base(), "Build "+gf.path.Base()) } -func (s *sdk) javaMemberNames(ctx android.ModuleContext) []string { - result := []string{} +func (s *sdk) javaLibs(ctx android.ModuleContext) []*java.Library { + result := []*java.Library{} ctx.VisitDirectDeps(func(m android.Module) { - if _, ok := m.(*java.Library); ok { - result = append(result, m.Name()) + if j, ok := m.(*java.Library); ok { + result = append(result, j) } }) return result } -// buildAndroidBp creates the blueprint file that defines prebuilt modules for each of -// the SDK members, and the sdk_snapshot module for the specified version -func (s *sdk) buildAndroidBp(ctx android.ModuleContext, version string) android.OutputPath { - bp := newGeneratedFile(ctx, "blueprint-"+version+".sh") +// archSpecificNativeLibInfo represents an arch-specific variant of a native lib +type archSpecificNativeLibInfo struct { + name string + archType string + exportedIncludeDirs android.Paths + exportedSystemIncludeDirs android.Paths + exportedFlags []string + outputFile android.Path +} + +func (lib *archSpecificNativeLibInfo) signature() string { + return fmt.Sprintf("%v %v %v %v", + lib.name, + lib.exportedIncludeDirs.Strings(), + lib.exportedSystemIncludeDirs.Strings(), + lib.exportedFlags) +} + +// nativeLibInfo represents a collection of arch-specific modules having the same name +type nativeLibInfo struct { + name string + archVariants []archSpecificNativeLibInfo + // hasArchSpecificFlags is set to true if modules for each architecture all have the same + // include dirs, flags, etc, in which case only those of the first arch is selected. + hasArchSpecificFlags bool +} + +// nativeMemberInfos collects all cc.Modules that are member of an SDK. +func (s *sdk) nativeMemberInfos(ctx android.ModuleContext) []*nativeLibInfo { + infoMap := make(map[string]*nativeLibInfo) + + // Collect cc.Modules + ctx.VisitDirectDeps(func(m android.Module) { + ccModule, ok := m.(*cc.Module) + if !ok { + return + } + depName := ctx.OtherModuleName(m) + + if _, ok := infoMap[depName]; !ok { + infoMap[depName] = &nativeLibInfo{name: depName} + } + + info := infoMap[depName] + info.archVariants = append(info.archVariants, archSpecificNativeLibInfo{ + name: ccModule.BaseModuleName(), + archType: ccModule.Target().Arch.ArchType.String(), + exportedIncludeDirs: ccModule.ExportedIncludeDirs(), + exportedSystemIncludeDirs: ccModule.ExportedSystemIncludeDirs(), + exportedFlags: ccModule.ExportedFlags(), + outputFile: ccModule.OutputFile().Path(), + }) + }) - makePrebuiltName := func(name string) string { - return ctx.ModuleName() + "_" + name + string(android.SdkVersionSeparator) + version + // Determine if include dirs and flags for each module are different across arch-specific + // modules or not. And set hasArchSpecificFlags accordingly + for _, info := range infoMap { + // by default, include paths and flags are assumed to be the same across arches + info.hasArchSpecificFlags = false + oldSignature := "" + for _, av := range info.archVariants { + newSignature := av.signature() + if oldSignature == "" { + oldSignature = newSignature + } + if oldSignature != newSignature { + info.hasArchSpecificFlags = true + break + } + } + } + + var list []*nativeLibInfo + for _, v := range infoMap { + list = append(list, v) } + return list +} + +// SDK directory structure +// <sdk_root>/ +// Android.bp : definition of a 'sdk' module is here. This is a hand-made one. +// <api_ver>/ : below this directory are all auto-generated +// Android.bp : definition of 'sdk_snapshot' module is here +// aidl/ +// frameworks/base/core/..../IFoo.aidl : an exported AIDL file +// java/ +// java/<module_name>/stub.jar : a stub jar for a java library 'module_name' +// include/ +// bionic/libc/include/stdlib.h : an exported header file +// include_gen/ +// com/android/.../IFoo.h : a generated header file +// <arch>/include/ : arch-specific exported headers +// <arch>/include_gen/ : arch-specific generated headers +// <arch>/lib/ +// libFoo.so : a stub library + +const ( + aidlIncludeDir = "aidl" + javaStubDir = "java" + javaStubFile = "stub.jar" + nativeIncludeDir = "include" + nativeGeneratedIncludeDir = "include_gen" + nativeStubDir = "lib" + nativeStubFileSuffix = ".so" +) + +// path to the stub file of a java library. Relative to <sdk_root>/<api_dir> +func javaStubFilePathFor(javaLib *java.Library) string { + return filepath.Join(javaStubDir, javaLib.Name(), javaStubFile) +} + +// path to the stub file of a native shared library. Relative to <sdk_root>/<api_dir> +func nativeStubFilePathFor(lib archSpecificNativeLibInfo) string { + return filepath.Join(lib.archType, + nativeStubDir, lib.name+nativeStubFileSuffix) +} + +// paths to the include dirs of a native shared library. Relative to <sdk_root>/<api_dir> +func nativeIncludeDirPathsFor(ctx android.ModuleContext, lib archSpecificNativeLibInfo, + systemInclude bool, archSpecific bool) []string { + var result []string + buildDir := ctx.Config().BuildDir() + var includeDirs []android.Path + if !systemInclude { + includeDirs = lib.exportedIncludeDirs + } else { + includeDirs = lib.exportedSystemIncludeDirs + } + for _, dir := range includeDirs { + var path string + if gen := strings.HasPrefix(dir.String(), buildDir); gen { + path = filepath.Join(nativeGeneratedIncludeDir, dir.Rel()) + } else { + path = filepath.Join(nativeIncludeDir, dir.String()) + } + if archSpecific { + path = filepath.Join(lib.archType, path) + } + result = append(result, path) + } + return result +} - javaLibs := s.javaMemberNames(ctx) - for _, name := range javaLibs { - prebuiltName := makePrebuiltName(name) - jar := filepath.Join("java", name, "stub.jar") +// A name that uniquely identifies an prebuilt SDK member for a version of SDK snapshot +// This isn't visible to users, so could be changed in future. +func versionedSdkMemberName(ctx android.ModuleContext, memberName string, version string) string { + return ctx.ModuleName() + "_" + memberName + string(android.SdkVersionSeparator) + version +} + +// arm64, arm, x86, x86_64, etc. +func archTypeOf(module android.Module) string { + return module.Target().Arch.ArchType.String() +} + +// buildAndroidBp creates the blueprint file that defines prebuilt modules for each of +// the SDK members, and the entire sdk_snapshot module for the specified version +func (s *sdk) buildAndroidBp(ctx android.ModuleContext, version string) android.OutputPath { + bp := newGeneratedFile(ctx, "blueprint-"+version+".bp") + bp.printfln("// This is auto-generated. DO NOT EDIT.") + bp.printfln("") + javaLibModules := s.javaLibs(ctx) + for _, m := range javaLibModules { + name := m.Name() bp.printfln("java_import {") - bp.printfln(" name: %q,", prebuiltName) - bp.printfln(" jars: [%q],", jar) - bp.printfln(" sdk_member_name: %q,", name) + bp.indent() + bp.printfln("name: %q,", versionedSdkMemberName(ctx, name, version)) + bp.printfln("sdk_member_name: %q,", name) + bp.printfln("jars: [%q],", javaStubFilePathFor(m)) + bp.dedent() bp.printfln("}") bp.printfln("") @@ -96,25 +260,92 @@ func (s *sdk) buildAndroidBp(ctx android.ModuleContext, version string) android. // doesn't exist (i.e. building in an unbundled tree). "prefer:" is set to false // so that this module does not eclipse the unversioned module if it exists. bp.printfln("java_import {") - bp.printfln(" name: %q,", name) - bp.printfln(" jars: [%q],", jar) - bp.printfln(" prefer: false,") + bp.indent() + bp.printfln("name: %q,", name) + bp.printfln("jars: [%q],", javaStubFilePathFor(m)) + bp.printfln("prefer: false,") + bp.dedent() bp.printfln("}") bp.printfln("") - } - // TODO(jiyong): emit cc_prebuilt_library_shared for the native libs + nativeLibInfos := s.nativeMemberInfos(ctx) + for _, info := range nativeLibInfos { + bp.printfln("cc_prebuilt_library_shared {") + bp.indent() + bp.printfln("name: %q,", versionedSdkMemberName(ctx, info.name, version)) + bp.printfln("sdk_member_name: %q,", info.name) + + // a function for emitting include dirs + printExportedDirsForNativeLibs := func(lib archSpecificNativeLibInfo, systemInclude bool) { + includeDirs := nativeIncludeDirPathsFor(ctx, lib, systemInclude, info.hasArchSpecificFlags) + if len(includeDirs) == 0 { + return + } + if !systemInclude { + bp.printfln("export_include_dirs: [") + } else { + bp.printfln("export_system_include_dirs: [") + } + bp.indent() + for _, dir := range includeDirs { + bp.printfln("%q,", dir) + } + bp.dedent() + bp.printfln("],") + } + + if !info.hasArchSpecificFlags { + printExportedDirsForNativeLibs(info.archVariants[0], false /*systemInclude*/) + printExportedDirsForNativeLibs(info.archVariants[0], true /*systemInclude*/) + } + + bp.printfln("arch: {") + bp.indent() + for _, av := range info.archVariants { + bp.printfln("%s: {", av.archType) + bp.indent() + bp.printfln("srcs: [%q],", nativeStubFilePathFor(av)) + if info.hasArchSpecificFlags { + // export_* properties are added inside the arch: {<arch>: {...}} block + printExportedDirsForNativeLibs(av, false /*systemInclude*/) + printExportedDirsForNativeLibs(av, true /*systemInclude*/) + } + bp.dedent() + bp.printfln("},") // <arch> + } + bp.dedent() + bp.printfln("},") // arch + bp.printfln("stl: \"none\",") + bp.printfln("system_shared_libs: [],") + bp.dedent() + bp.printfln("}") // cc_prebuilt_library_shared + bp.printfln("") + } bp.printfln("sdk_snapshot {") - bp.printfln(" name: %q,", ctx.ModuleName()+string(android.SdkVersionSeparator)+version) - bp.printfln(" java_libs: [") - for _, n := range javaLibs { - bp.printfln(" %q,", makePrebuiltName(n)) - } - bp.printfln(" ],") - // TODO(jiyong): emit native_shared_libs - bp.printfln("}") + bp.indent() + bp.printfln("name: %q,", ctx.ModuleName()+string(android.SdkVersionSeparator)+version) + if len(javaLibModules) > 0 { + bp.printfln("java_libs: [") + bp.indent() + for _, m := range javaLibModules { + bp.printfln("%q,", versionedSdkMemberName(ctx, m.Name(), version)) + } + bp.dedent() + bp.printfln("],") // java_libs + } + if len(nativeLibInfos) > 0 { + bp.printfln("native_shared_libs: [") + bp.indent() + for _, info := range nativeLibInfos { + bp.printfln("%q,", versionedSdkMemberName(ctx, info.name, version)) + } + bp.dedent() + bp.printfln("],") // native_shared_libs + } + bp.dedent() + bp.printfln("}") // sdk_snapshot bp.printfln("") bp.build(pctx, ctx, nil) @@ -123,46 +354,104 @@ func (s *sdk) buildAndroidBp(ctx android.ModuleContext, version string) android. func (s *sdk) buildScript(ctx android.ModuleContext, version string) android.OutputPath { sh := newGeneratedFile(ctx, "update_prebuilt-"+version+".sh") + buildDir := ctx.Config().BuildDir() - snapshotRoot := filepath.Join(ctx.ModuleDir(), version) - aidlIncludeDir := filepath.Join(snapshotRoot, "aidl") - javaStubsDir := filepath.Join(snapshotRoot, "java") + snapshotPath := func(paths ...string) string { + return filepath.Join(ctx.ModuleDir(), version, filepath.Join(paths...)) + } + // TODO(jiyong) instead of creating script, create a zip file having the Android.bp, the headers, + // and the stubs and put it to the dist directory. The dist'ed zip file then would be downloaded, + // unzipped and then uploaded to gerrit again. sh.printfln("#!/bin/bash") - sh.printfln("echo Updating snapshot of %s in %s", ctx.ModuleName(), snapshotRoot) + sh.printfln("echo Updating snapshot of %s in %s", ctx.ModuleName(), snapshotPath()) sh.printfln("pushd $ANDROID_BUILD_TOP > /dev/null") - sh.printfln("rm -rf %s", snapshotRoot) - sh.printfln("mkdir -p %s", aidlIncludeDir) - sh.printfln("mkdir -p %s", javaStubsDir) - // TODO(jiyong): mkdir the 'native' dir + sh.printfln("mkdir -p %s", snapshotPath(aidlIncludeDir)) + sh.printfln("mkdir -p %s", snapshotPath(javaStubDir)) + sh.printfln("mkdir -p %s", snapshotPath(nativeIncludeDir)) + sh.printfln("mkdir -p %s", snapshotPath(nativeGeneratedIncludeDir)) + for _, target := range ctx.MultiTargets() { + arch := target.Arch.ArchType.String() + sh.printfln("mkdir -p %s", snapshotPath(arch, nativeStubDir)) + sh.printfln("mkdir -p %s", snapshotPath(arch, nativeIncludeDir)) + sh.printfln("mkdir -p %s", snapshotPath(arch, nativeGeneratedIncludeDir)) + } var implicits android.Paths - ctx.VisitDirectDeps(func(m android.Module) { - if javaLib, ok := m.(*java.Library); ok { - headerJars := javaLib.HeaderJars() - if len(headerJars) != 1 { - panic(fmt.Errorf("there must be only one header jar from %q", m.Name())) + for _, m := range s.javaLibs(ctx) { + headerJars := m.HeaderJars() + if len(headerJars) != 1 { + panic(fmt.Errorf("there must be only one header jar from %q", m.Name())) + } + implicits = append(implicits, headerJars...) + + exportedAidlIncludeDirs := m.AidlIncludeDirs() + for _, dir := range exportedAidlIncludeDirs { + // Using tar to copy with the directory structure + // TODO(jiyong): copy parcelable declarations only + sh.printfln("find %s -name \"*.aidl\" | tar cf - -T - | (cd %s; tar xf -)", + dir.String(), snapshotPath(aidlIncludeDir)) + } + + copyTarget := snapshotPath(javaStubFilePathFor(m)) + sh.printfln("mkdir -p %s && cp %s %s", + filepath.Dir(copyTarget), headerJars[0].String(), copyTarget) + } + + nativeLibInfos := s.nativeMemberInfos(ctx) + for _, info := range nativeLibInfos { + + // a function for emitting include dirs + printExportedDirCopyCommandsForNativeLibs := func(lib archSpecificNativeLibInfo) { + includeDirs := lib.exportedIncludeDirs + includeDirs = append(includeDirs, lib.exportedSystemIncludeDirs...) + if len(includeDirs) == 0 { + return } - implicits = append(implicits, headerJars...) - - exportedAidlIncludeDirs := javaLib.AidlIncludeDirs() - for _, dir := range exportedAidlIncludeDirs { - // Using tar to copy with the directory structure - // TODO(jiyong): copy parcelable declarations only - sh.printfln("find %s -name \"*.aidl\" | tar cf - -T - | (cd %s; tar xf -)", - dir.String(), aidlIncludeDir) + for _, dir := range includeDirs { + gen := strings.HasPrefix(dir.String(), buildDir) + targetDir := nativeIncludeDir + if gen { + targetDir = nativeGeneratedIncludeDir + } + if info.hasArchSpecificFlags { + targetDir = filepath.Join(lib.archType, targetDir) + } + targetDir = snapshotPath(targetDir) + + sourceDirRoot := "." + sourceDirRel := dir.String() + if gen { + // ex) out/soong/.intermediate/foo/bar/gen/aidl + sourceDirRoot = strings.TrimSuffix(dir.String(), dir.Rel()) + sourceDirRel = dir.Rel() + } + // TODO(jiyong) copy headers having other suffixes + sh.printfln("(cd %s; find %s -name \"*.h\" | tar cf - -T - ) | (cd %s; tar xf -)", + sourceDirRoot, sourceDirRel, targetDir) } + } - copiedHeaderJar := filepath.Join(javaStubsDir, m.Name(), "stub.jar") - sh.printfln("mkdir -p $(dirname %s) && cp %s %s", - copiedHeaderJar, headerJars[0].String(), copiedHeaderJar) + if !info.hasArchSpecificFlags { + printExportedDirCopyCommandsForNativeLibs(info.archVariants[0]) } - // TODO(jiyong): emit the commands for copying the headers and stub libraries for native libs - }) + + // for each architecture + for _, av := range info.archVariants { + stub := av.outputFile + implicits = append(implicits, stub) + copiedStub := snapshotPath(nativeStubFilePathFor(av)) + sh.printfln("cp %s %s", stub.String(), copiedStub) + + if info.hasArchSpecificFlags { + printExportedDirCopyCommandsForNativeLibs(av) + } + } + } bp := s.buildAndroidBp(ctx, version) implicits = append(implicits, bp) - sh.printfln("cp %s %s", bp.String(), filepath.Join(snapshotRoot, "Android.bp")) + sh.printfln("cp %s %s", bp.String(), snapshotPath("Android.bp")) sh.printfln("popd > /dev/null") sh.printfln("rm -- \"$0\"") // self deleting so that stale script is not used @@ -218,8 +507,8 @@ func (s *sdk) androidMkEntriesForScript() android.AndroidMkEntries { fmt.Fprintln(w, "$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)") fmt.Fprintln(w, " touch $@") fmt.Fprintln(w, " echo ##################################################") - fmt.Fprintln(w, " echo To update current SDK: execute", s.updateScript.String()) - fmt.Fprintln(w, " echo To freeze current SDK: execute", s.freezeScript.String()) + fmt.Fprintln(w, " echo To update current SDK: execute", filepath.Join("\\$$ANDROID_BUILD_TOP", s.updateScript.String())) + fmt.Fprintln(w, " echo To freeze current SDK: execute", filepath.Join("\\$$ANDROID_BUILD_TOP", s.freezeScript.String())) fmt.Fprintln(w, " echo ##################################################") }, }, |