Loading android/prebuilt.go +40 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android import ( "fmt" "reflect" "github.com/google/blueprint" "github.com/google/blueprint/proptools" Loading Loading @@ -43,7 +44,10 @@ type Prebuilt struct { properties PrebuiltProperties module Module srcs *[]string src *string // Metadata for single source Prebuilt modules. srcProps reflect.Value srcField reflect.StructField } func (p *Prebuilt) Name(name string) string { Loading Loading @@ -71,11 +75,16 @@ func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path { // sources. return PathForModuleSrc(ctx, (*p.srcs)[0]) } else { if proptools.String(p.src) == "" { ctx.PropertyErrorf("src", "missing prebuilt source file") if !p.srcProps.IsValid() { ctx.ModuleErrorf("prebuilt source was not set") } src := p.getSingleSourceFieldValue() if src == "" { ctx.PropertyErrorf(proptools.FieldNameForProperty(p.srcField.Name), "missing prebuilt source file") return nil } return PathForModuleSrc(ctx, *p.src) return PathForModuleSrc(ctx, src) } } Loading @@ -89,10 +98,12 @@ func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) { p.srcs = srcs } func InitSingleSourcePrebuiltModule(module PrebuiltInterface, src *string) { func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) { p := module.Prebuilt() module.AddProperties(&p.properties) p.src = src p.srcProps = reflect.ValueOf(srcProps).Elem() p.srcField, _ = p.srcProps.Type().FieldByName(srcField) p.checkSingleSourceProperties() } type PrebuiltInterface interface { Loading Loading @@ -129,7 +140,7 @@ func PrebuiltMutator(ctx BottomUpMutatorContext) { func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) { if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil { p := m.Prebuilt() if p.srcs == nil && p.src == nil { if p.srcs == nil && !p.srcProps.IsValid() { panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it")) } if !p.properties.SourceExists { Loading Loading @@ -172,7 +183,7 @@ func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool { return false } if p.src != nil && *p.src == "" { if p.srcProps.IsValid() && p.getSingleSourceFieldValue() == "" { return false } Loading @@ -183,3 +194,24 @@ func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool { return source == nil || !source.Enabled() } func (p *Prebuilt) checkSingleSourceProperties() { if !p.srcProps.IsValid() || p.srcField.Name == "" { panic(fmt.Errorf("invalid single source prebuilt %+v", p)) } if p.srcProps.Kind() != reflect.Struct && p.srcProps.Kind() != reflect.Interface { panic(fmt.Errorf("invalid single source prebuilt %+v", p.srcProps)) } } func (p *Prebuilt) getSingleSourceFieldValue() string { value := p.srcProps.FieldByIndex(p.srcField.Index) if value.Kind() == reflect.Ptr { value = value.Elem() } if value.Kind() != reflect.String { panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one", p.srcField.Name)) } return value.String() } apex/apex.go +1 −1 Original line number Diff line number Diff line Loading @@ -1520,7 +1520,7 @@ func (p *Prebuilt) AndroidMk() android.AndroidMkData { func PrebuiltFactory() android.Module { module := &Prebuilt{} module.AddProperties(&module.properties) android.InitSingleSourcePrebuiltModule(module, &module.properties.Source) android.InitSingleSourcePrebuiltModule(module, &module.properties, "Source") android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) return module } java/app.go +77 −70 Original line number Diff line number Diff line Loading @@ -30,8 +30,7 @@ import ( "android/soong/tradefed" ) var supportedDpis = [...]string{"Ldpi", "Mdpi", "Hdpi", "Xhdpi", "Xxhdpi", "Xxxhdpi"} var dpiVariantsStruct reflect.Type var supportedDpis = []string{"ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"} func init() { android.RegisterModuleType("android_app", AndroidAppFactory) Loading @@ -40,22 +39,6 @@ func init() { android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory) android.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory) android.RegisterModuleType("android_app_import", AndroidAppImportFactory) // Dynamically construct a struct for the dpi_variants property in android_app_import. perDpiStruct := reflect.StructOf([]reflect.StructField{ { Name: "Apk", Type: reflect.TypeOf((*string)(nil)), }, }) dpiVariantsFields := make([]reflect.StructField, len(supportedDpis)) for i, dpi := range supportedDpis { dpiVariantsFields[i] = reflect.StructField{ Name: string(dpi), Type: perDpiStruct, } } dpiVariantsStruct = reflect.StructOf(dpiVariantsFields) } // AndroidManifest.xml merging Loading Loading @@ -745,6 +728,7 @@ type AndroidAppImport struct { prebuilt android.Prebuilt properties AndroidAppImportProperties dpiVariants interface{} outputFile android.Path certificate *Certificate Loading @@ -756,27 +740,7 @@ type AndroidAppImport struct { type AndroidAppImportProperties struct { // A prebuilt apk to import Apk string // Per-DPI settings. This property makes it possible to specify a different source apk path for // each DPI. // // Example: // // android_app_import { // name: "example_import", // apk: "prebuilts/example.apk", // dpi_variants: { // mdpi: { // apk: "prebuilts/example_mdpi.apk", // }, // xhdpi: { // apk: "prebuilts/example_xhdpi.apk", // }, // }, // certificate: "PRESIGNED", // } Dpi_variants interface{} Apk *string // The name of a certificate in the default certificate directory, blank to use the default // product certificate, or an android_app_certificate module name in the form ":module". Loading @@ -799,39 +763,43 @@ type AndroidAppImportProperties struct { Overrides []string } func getApkPathForDpi(dpiVariantsValue reflect.Value, dpi string) string { dpiField := dpiVariantsValue.FieldByName(proptools.FieldNameForProperty(dpi)) if !dpiField.IsValid() { return "" } apkValue := dpiField.FieldByName("Apk").Elem() if apkValue.IsValid() { return apkValue.String() } return "" } // Chooses a source APK path to use based on the module's per-DPI settings and the product config. func (a *AndroidAppImport) getSrcApkPath(ctx android.ModuleContext) string { // Chooses a source APK path to use based on the module and product specs. func (a *AndroidAppImport) updateSrcApkPath(ctx android.LoadHookContext) { config := ctx.Config() dpiVariantsValue := reflect.ValueOf(a.properties.Dpi_variants).Elem() if !dpiVariantsValue.IsValid() { return a.properties.Apk dpiProps := reflect.ValueOf(a.dpiVariants).Elem().FieldByName("Dpi_variants") // Try DPI variant matches in the reverse-priority order so that the highest priority match // overwrites everything else. // TODO(jungjw): Can we optimize this by making it priority order? for i := len(config.ProductAAPTPrebuiltDPI()) - 1; i >= 0; i-- { dpi := config.ProductAAPTPrebuiltDPI()[i] if inList(dpi, supportedDpis) { MergePropertiesFromVariant(ctx, &a.properties, dpiProps, dpi, "dpi_variants") } } // Match PRODUCT_AAPT_PREF_CONFIG first and then PRODUCT_AAPT_PREBUILT_DPI. if config.ProductAAPTPreferredConfig() != "" { if apk := getApkPathForDpi(dpiVariantsValue, config.ProductAAPTPreferredConfig()); apk != "" { return apk dpi := config.ProductAAPTPreferredConfig() if inList(dpi, supportedDpis) { MergePropertiesFromVariant(ctx, &a.properties, dpiProps, dpi, "dpi_variants") } } for _, dpi := range config.ProductAAPTPrebuiltDPI() { if apk := getApkPathForDpi(dpiVariantsValue, dpi); apk != "" { return apk } func MergePropertiesFromVariant(ctx android.BaseModuleContext, dst interface{}, variantGroup reflect.Value, variant, variantGroupPath string) { src := variantGroup.FieldByName(proptools.FieldNameForProperty(variant)) if !src.IsValid() { ctx.ModuleErrorf("field %q does not exist", variantGroupPath+"."+variant) } // No match. Use the generic one. return a.properties.Apk err := proptools.ExtendMatchingProperties([]interface{}{dst}, src.Interface(), nil, proptools.OrderAppend) if err != nil { if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) } else { panic(err) } } } func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) { Loading Loading @@ -896,8 +864,7 @@ func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext // TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK // TODO: LOCAL_PACKAGE_SPLITS var srcApk android.Path srcApk = android.PathForModuleSrc(ctx, a.getSrcApkPath(ctx)) srcApk := a.prebuilt.SingleSourcePath(ctx) if a.usesLibrary.enforceUsesLibraries() { srcApk = a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk) Loading Loading @@ -959,16 +926,56 @@ func (a *AndroidAppImport) Name() string { return a.prebuilt.Name(a.ModuleBase.Name()) } // Populates dpi_variants property and its fields at creation time. func (a *AndroidAppImport) addDpiVariants() { // TODO(jungjw): Do we want to do some filtering here? props := reflect.ValueOf(&a.properties).Type() dpiFields := make([]reflect.StructField, len(supportedDpis)) for i, dpi := range supportedDpis { dpiFields[i] = reflect.StructField{ Name: proptools.FieldNameForProperty(dpi), Type: props, } } dpiStruct := reflect.StructOf(dpiFields) a.dpiVariants = reflect.New(reflect.StructOf([]reflect.StructField{ { Name: "Dpi_variants", Type: dpiStruct, }, })).Interface() a.AddProperties(a.dpiVariants) } // android_app_import imports a prebuilt apk with additional processing specified in the module. // DPI-specific apk source files can be specified using dpi_variants. Example: // // android_app_import { // name: "example_import", // apk: "prebuilts/example.apk", // dpi_variants: { // mdpi: { // apk: "prebuilts/example_mdpi.apk", // }, // xhdpi: { // apk: "prebuilts/example_xhdpi.apk", // }, // }, // certificate: "PRESIGNED", // } func AndroidAppImportFactory() android.Module { module := &AndroidAppImport{} module.properties.Dpi_variants = reflect.New(dpiVariantsStruct).Interface() module.AddProperties(&module.properties) module.AddProperties(&module.dexpreoptProperties) module.AddProperties(&module.usesLibrary.usesLibraryProperties) module.addDpiVariants() android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.updateSrcApkPath(ctx) }) InitJavaModule(module, android.DeviceSupported) android.InitSingleSourcePrebuiltModule(module, &module.properties.Apk) android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk") return module } Loading java/app_test.go +1 −1 Original line number Diff line number Diff line Loading @@ -1138,7 +1138,7 @@ func TestAndroidAppImport_DpiVariants(t *testing.T) { { name: "AAPTPreferredConfig matches", aaptPreferredConfig: proptools.StringPtr("xhdpi"), aaptPrebuiltDPI: []string{"xxhdpi", "lhdpi"}, aaptPrebuiltDPI: []string{"xxhdpi", "ldpi"}, expected: "prebuilts/apk/app_xhdpi.apk", }, { Loading Loading
android/prebuilt.go +40 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android import ( "fmt" "reflect" "github.com/google/blueprint" "github.com/google/blueprint/proptools" Loading Loading @@ -43,7 +44,10 @@ type Prebuilt struct { properties PrebuiltProperties module Module srcs *[]string src *string // Metadata for single source Prebuilt modules. srcProps reflect.Value srcField reflect.StructField } func (p *Prebuilt) Name(name string) string { Loading Loading @@ -71,11 +75,16 @@ func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path { // sources. return PathForModuleSrc(ctx, (*p.srcs)[0]) } else { if proptools.String(p.src) == "" { ctx.PropertyErrorf("src", "missing prebuilt source file") if !p.srcProps.IsValid() { ctx.ModuleErrorf("prebuilt source was not set") } src := p.getSingleSourceFieldValue() if src == "" { ctx.PropertyErrorf(proptools.FieldNameForProperty(p.srcField.Name), "missing prebuilt source file") return nil } return PathForModuleSrc(ctx, *p.src) return PathForModuleSrc(ctx, src) } } Loading @@ -89,10 +98,12 @@ func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) { p.srcs = srcs } func InitSingleSourcePrebuiltModule(module PrebuiltInterface, src *string) { func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) { p := module.Prebuilt() module.AddProperties(&p.properties) p.src = src p.srcProps = reflect.ValueOf(srcProps).Elem() p.srcField, _ = p.srcProps.Type().FieldByName(srcField) p.checkSingleSourceProperties() } type PrebuiltInterface interface { Loading Loading @@ -129,7 +140,7 @@ func PrebuiltMutator(ctx BottomUpMutatorContext) { func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) { if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil { p := m.Prebuilt() if p.srcs == nil && p.src == nil { if p.srcs == nil && !p.srcProps.IsValid() { panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it")) } if !p.properties.SourceExists { Loading Loading @@ -172,7 +183,7 @@ func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool { return false } if p.src != nil && *p.src == "" { if p.srcProps.IsValid() && p.getSingleSourceFieldValue() == "" { return false } Loading @@ -183,3 +194,24 @@ func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool { return source == nil || !source.Enabled() } func (p *Prebuilt) checkSingleSourceProperties() { if !p.srcProps.IsValid() || p.srcField.Name == "" { panic(fmt.Errorf("invalid single source prebuilt %+v", p)) } if p.srcProps.Kind() != reflect.Struct && p.srcProps.Kind() != reflect.Interface { panic(fmt.Errorf("invalid single source prebuilt %+v", p.srcProps)) } } func (p *Prebuilt) getSingleSourceFieldValue() string { value := p.srcProps.FieldByIndex(p.srcField.Index) if value.Kind() == reflect.Ptr { value = value.Elem() } if value.Kind() != reflect.String { panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one", p.srcField.Name)) } return value.String() }
apex/apex.go +1 −1 Original line number Diff line number Diff line Loading @@ -1520,7 +1520,7 @@ func (p *Prebuilt) AndroidMk() android.AndroidMkData { func PrebuiltFactory() android.Module { module := &Prebuilt{} module.AddProperties(&module.properties) android.InitSingleSourcePrebuiltModule(module, &module.properties.Source) android.InitSingleSourcePrebuiltModule(module, &module.properties, "Source") android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) return module }
java/app.go +77 −70 Original line number Diff line number Diff line Loading @@ -30,8 +30,7 @@ import ( "android/soong/tradefed" ) var supportedDpis = [...]string{"Ldpi", "Mdpi", "Hdpi", "Xhdpi", "Xxhdpi", "Xxxhdpi"} var dpiVariantsStruct reflect.Type var supportedDpis = []string{"ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"} func init() { android.RegisterModuleType("android_app", AndroidAppFactory) Loading @@ -40,22 +39,6 @@ func init() { android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory) android.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory) android.RegisterModuleType("android_app_import", AndroidAppImportFactory) // Dynamically construct a struct for the dpi_variants property in android_app_import. perDpiStruct := reflect.StructOf([]reflect.StructField{ { Name: "Apk", Type: reflect.TypeOf((*string)(nil)), }, }) dpiVariantsFields := make([]reflect.StructField, len(supportedDpis)) for i, dpi := range supportedDpis { dpiVariantsFields[i] = reflect.StructField{ Name: string(dpi), Type: perDpiStruct, } } dpiVariantsStruct = reflect.StructOf(dpiVariantsFields) } // AndroidManifest.xml merging Loading Loading @@ -745,6 +728,7 @@ type AndroidAppImport struct { prebuilt android.Prebuilt properties AndroidAppImportProperties dpiVariants interface{} outputFile android.Path certificate *Certificate Loading @@ -756,27 +740,7 @@ type AndroidAppImport struct { type AndroidAppImportProperties struct { // A prebuilt apk to import Apk string // Per-DPI settings. This property makes it possible to specify a different source apk path for // each DPI. // // Example: // // android_app_import { // name: "example_import", // apk: "prebuilts/example.apk", // dpi_variants: { // mdpi: { // apk: "prebuilts/example_mdpi.apk", // }, // xhdpi: { // apk: "prebuilts/example_xhdpi.apk", // }, // }, // certificate: "PRESIGNED", // } Dpi_variants interface{} Apk *string // The name of a certificate in the default certificate directory, blank to use the default // product certificate, or an android_app_certificate module name in the form ":module". Loading @@ -799,39 +763,43 @@ type AndroidAppImportProperties struct { Overrides []string } func getApkPathForDpi(dpiVariantsValue reflect.Value, dpi string) string { dpiField := dpiVariantsValue.FieldByName(proptools.FieldNameForProperty(dpi)) if !dpiField.IsValid() { return "" } apkValue := dpiField.FieldByName("Apk").Elem() if apkValue.IsValid() { return apkValue.String() } return "" } // Chooses a source APK path to use based on the module's per-DPI settings and the product config. func (a *AndroidAppImport) getSrcApkPath(ctx android.ModuleContext) string { // Chooses a source APK path to use based on the module and product specs. func (a *AndroidAppImport) updateSrcApkPath(ctx android.LoadHookContext) { config := ctx.Config() dpiVariantsValue := reflect.ValueOf(a.properties.Dpi_variants).Elem() if !dpiVariantsValue.IsValid() { return a.properties.Apk dpiProps := reflect.ValueOf(a.dpiVariants).Elem().FieldByName("Dpi_variants") // Try DPI variant matches in the reverse-priority order so that the highest priority match // overwrites everything else. // TODO(jungjw): Can we optimize this by making it priority order? for i := len(config.ProductAAPTPrebuiltDPI()) - 1; i >= 0; i-- { dpi := config.ProductAAPTPrebuiltDPI()[i] if inList(dpi, supportedDpis) { MergePropertiesFromVariant(ctx, &a.properties, dpiProps, dpi, "dpi_variants") } } // Match PRODUCT_AAPT_PREF_CONFIG first and then PRODUCT_AAPT_PREBUILT_DPI. if config.ProductAAPTPreferredConfig() != "" { if apk := getApkPathForDpi(dpiVariantsValue, config.ProductAAPTPreferredConfig()); apk != "" { return apk dpi := config.ProductAAPTPreferredConfig() if inList(dpi, supportedDpis) { MergePropertiesFromVariant(ctx, &a.properties, dpiProps, dpi, "dpi_variants") } } for _, dpi := range config.ProductAAPTPrebuiltDPI() { if apk := getApkPathForDpi(dpiVariantsValue, dpi); apk != "" { return apk } func MergePropertiesFromVariant(ctx android.BaseModuleContext, dst interface{}, variantGroup reflect.Value, variant, variantGroupPath string) { src := variantGroup.FieldByName(proptools.FieldNameForProperty(variant)) if !src.IsValid() { ctx.ModuleErrorf("field %q does not exist", variantGroupPath+"."+variant) } // No match. Use the generic one. return a.properties.Apk err := proptools.ExtendMatchingProperties([]interface{}{dst}, src.Interface(), nil, proptools.OrderAppend) if err != nil { if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) } else { panic(err) } } } func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) { Loading Loading @@ -896,8 +864,7 @@ func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext // TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK // TODO: LOCAL_PACKAGE_SPLITS var srcApk android.Path srcApk = android.PathForModuleSrc(ctx, a.getSrcApkPath(ctx)) srcApk := a.prebuilt.SingleSourcePath(ctx) if a.usesLibrary.enforceUsesLibraries() { srcApk = a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk) Loading Loading @@ -959,16 +926,56 @@ func (a *AndroidAppImport) Name() string { return a.prebuilt.Name(a.ModuleBase.Name()) } // Populates dpi_variants property and its fields at creation time. func (a *AndroidAppImport) addDpiVariants() { // TODO(jungjw): Do we want to do some filtering here? props := reflect.ValueOf(&a.properties).Type() dpiFields := make([]reflect.StructField, len(supportedDpis)) for i, dpi := range supportedDpis { dpiFields[i] = reflect.StructField{ Name: proptools.FieldNameForProperty(dpi), Type: props, } } dpiStruct := reflect.StructOf(dpiFields) a.dpiVariants = reflect.New(reflect.StructOf([]reflect.StructField{ { Name: "Dpi_variants", Type: dpiStruct, }, })).Interface() a.AddProperties(a.dpiVariants) } // android_app_import imports a prebuilt apk with additional processing specified in the module. // DPI-specific apk source files can be specified using dpi_variants. Example: // // android_app_import { // name: "example_import", // apk: "prebuilts/example.apk", // dpi_variants: { // mdpi: { // apk: "prebuilts/example_mdpi.apk", // }, // xhdpi: { // apk: "prebuilts/example_xhdpi.apk", // }, // }, // certificate: "PRESIGNED", // } func AndroidAppImportFactory() android.Module { module := &AndroidAppImport{} module.properties.Dpi_variants = reflect.New(dpiVariantsStruct).Interface() module.AddProperties(&module.properties) module.AddProperties(&module.dexpreoptProperties) module.AddProperties(&module.usesLibrary.usesLibraryProperties) module.addDpiVariants() android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.updateSrcApkPath(ctx) }) InitJavaModule(module, android.DeviceSupported) android.InitSingleSourcePrebuiltModule(module, &module.properties.Apk) android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk") return module } Loading
java/app_test.go +1 −1 Original line number Diff line number Diff line Loading @@ -1138,7 +1138,7 @@ func TestAndroidAppImport_DpiVariants(t *testing.T) { { name: "AAPTPreferredConfig matches", aaptPreferredConfig: proptools.StringPtr("xhdpi"), aaptPrebuiltDPI: []string{"xxhdpi", "lhdpi"}, aaptPrebuiltDPI: []string{"xxhdpi", "ldpi"}, expected: "prebuilts/apk/app_xhdpi.apk", }, { Loading