From 688de9af5d4089f58a8f98ad8594595bd7ff3688 Mon Sep 17 00:00:00 2001 From: Songchun Fan Date: Tue, 24 Mar 2020 20:32:24 -0700 Subject: [soong] new field in Android.bp to request APK signing V4 If "v4_signature: true" is set, the v4 signature file, named [outputApkFile].idsig will be generated along side the outputApkFile. Test: m nothing Test: atest PackageManagerShellCommandIncrementalTest BUG: 149354175 Change-Id: Ie84725a15406f96f65042ea9909460e4eb34d57f --- java/app_test.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'java/app_test.go') diff --git a/java/app_test.go b/java/app_test.go index dfd85711b..10503e727 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -1073,6 +1073,66 @@ func TestCertificates(t *testing.T) { } } +func TestRequestV4SigningFlag(t *testing.T) { + testCases := []struct { + name string + bp string + expected string + }{ + { + name: "default", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + } + `, + expected: "", + }, + { + name: "default", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + v4_signature: false, + } + `, + expected: "", + }, + { + name: "module certificate property", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + v4_signature: true, + } + `, + expected: "--enable-v4", + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + config := testAppConfig(nil, test.bp, nil) + ctx := testContext() + + run(t, ctx, config) + foo := ctx.ModuleForTests("foo", "android_common") + + signapk := foo.Output("foo.apk") + signFlags := signapk.Args["flags"] + if test.expected != signFlags { + t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expected, signFlags) + } + }) + } +} + func TestPackageNameOverride(t *testing.T) { testCases := []struct { name string -- cgit v1.2.3-59-g8ed1b From ca095d786acf53a2b628f44791e4ba954aeba169 Mon Sep 17 00:00:00 2001 From: Jaewoong Jung Date: Thu, 9 Apr 2020 16:15:30 -0700 Subject: Add libs properties to runtime_resource_overlay. Test: app_test.go Test: Converted an existing RRO module. Bug: 148788111 Change-Id: I723c7175760da019d38893e54f236c45f4c973ea --- java/app.go | 9 +++++++++ java/app_test.go | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) (limited to 'java/app_test.go') diff --git a/java/app.go b/java/app.go index c64f1f73c..1ad81fe84 100755 --- a/java/app.go +++ b/java/app.go @@ -1345,6 +1345,12 @@ type RuntimeResourceOverlayProperties struct { // if not blank, set the minimum version of the sdk that the compiled artifacts will run against. // Defaults to sdk_version if not set. Min_sdk_version *string + + // list of android_library modules whose resources are extracted and linked against statically + Static_libs []string + + // list of android_app modules whose resources are extracted and linked against + Resource_libs []string } func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -1357,6 +1363,9 @@ func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) if cert != "" { ctx.AddDependency(ctx.Module(), certificateTag, cert) } + + ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs...) + ctx.AddVariationDependencies(nil, libTag, r.properties.Resource_libs...) } func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) { diff --git a/java/app_test.go b/java/app_test.go index 10503e727..c259fe2d7 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2342,11 +2342,17 @@ func checkAapt2LinkFlag(t *testing.T, aapt2Flags, flagName, expectedValue string } func TestRuntimeResourceOverlay(t *testing.T) { - ctx, config := testJava(t, ` + fs := map[string][]byte{ + "baz/res/res/values/strings.xml": nil, + "bar/res/res/values/strings.xml": nil, + } + bp := ` runtime_resource_overlay { name: "foo", certificate: "platform", product_specific: true, + static_libs: ["bar"], + resource_libs: ["baz"], aaptflags: ["--keep-raw-values"], } @@ -2356,7 +2362,21 @@ func TestRuntimeResourceOverlay(t *testing.T) { product_specific: true, theme: "faza", } - `) + + android_library { + name: "bar", + resource_dirs: ["bar/res"], + } + + android_app { + name: "baz", + sdk_version: "current", + resource_dirs: ["baz/res"], + } + ` + config := testAppConfig(nil, bp, fs) + ctx := testContext() + run(t, ctx, config) m := ctx.ModuleForTests("foo", "android_common") @@ -2368,6 +2388,19 @@ func TestRuntimeResourceOverlay(t *testing.T) { t.Errorf("expected values, %q are missing in aapt2 link flags, %q", absentFlags, aapt2Flags) } + // Check overlay.list output for static_libs dependency. + overlayList := m.Output("aapt2/overlay.list").Inputs.Strings() + staticLibPackage := buildDir + "/.intermediates/bar/android_common/package-res.apk" + if !inList(staticLibPackage, overlayList) { + t.Errorf("Stactic lib res package %q missing in overlay list: %q", staticLibPackage, overlayList) + } + + // Check AAPT2 link flags for resource_libs dependency. + resourceLibFlag := "-I " + buildDir + "/.intermediates/baz/android_common/package-res.apk" + if !strings.Contains(aapt2Flags, resourceLibFlag) { + t.Errorf("Resource lib flag %q missing in aapt2 link flags: %q", resourceLibFlag, aapt2Flags) + } + // Check cert signing flag. signedApk := m.Output("signed/foo.apk") signingFlag := signedApk.Args["certificates"] -- cgit v1.2.3-59-g8ed1b From e5ac15a1b74094e38e65db7b3dee29e422e15b2b Mon Sep 17 00:00:00 2001 From: Artur Satayev Date: Wed, 8 Apr 2020 19:09:30 +0100 Subject: Check updatable APKs compile against managed SDKs. As a follow up, this property will be set to APKs participating in mainline program. Bug: 153333044 Test: m Change-Id: I6ea2f3c1d26992259e4e9e6a6d8cecf091d39c43 Merged-In: I6ea2f3c1d26992259e4e9e6a6d8cecf091d39c43 (cherry picked from commit 2db1c3f1c432740f734917e04b2b847066c8d508) Exempt-From-Owner-Approval: clean cherry-pick --- java/app.go | 18 ++++++++-- java/app_test.go | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ java/java.go | 26 ++++++++------ java/sdk.go | 21 ++++++++++++ 4 files changed, 154 insertions(+), 13 deletions(-) (limited to 'java/app_test.go') diff --git a/java/app.go b/java/app.go index f9992d885..8e11b0388 100755 --- a/java/app.go +++ b/java/app.go @@ -110,6 +110,10 @@ type appProperties struct { PreventInstall bool `blueprint:"mutated"` HideFromMake bool `blueprint:"mutated"` IsCoverageVariant bool `blueprint:"mutated"` + + // Whether this app is considered mainline updatable or not. When set to true, this will enforce + // additional rules for making sure that the APK is truly updatable. Default is false. + Updatable *bool } // android_app properties that can be overridden by override_android_app @@ -242,11 +246,21 @@ func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleCon } func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { - a.checkPlatformAPI(ctx) - a.checkSdkVersion(ctx) + a.checkAppSdkVersions(ctx) a.generateAndroidBuildActions(ctx) } +func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { + if Bool(a.appProperties.Updatable) { + if !a.sdkVersion().stable() { + ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.sdkVersion()) + } + } + + a.checkPlatformAPI(ctx) + a.checkSdkVersions(ctx) +} + // Returns true if the native libraries should be stored in the APK uncompressed and the // extractNativeLibs application flag should be set to false in the manifest. func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool { diff --git a/java/app_test.go b/java/app_test.go index 10503e727..0968c9a33 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -264,6 +264,108 @@ func TestAndroidAppLinkType(t *testing.T) { `) } +func TestUpdatableApps(t *testing.T) { + testCases := []struct { + name string + bp string + expectedError string + }{ + { + name: "Stable public SDK", + bp: `android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "29", + updatable: true, + }`, + }, + { + name: "Stable system SDK", + bp: `android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "system_29", + updatable: true, + }`, + }, + { + name: "Current public SDK", + bp: `android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + updatable: true, + }`, + }, + { + name: "Current system SDK", + bp: `android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "system_current", + updatable: true, + }`, + }, + { + name: "Current module SDK", + bp: `android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "module_current", + updatable: true, + }`, + }, + { + name: "Current core SDK", + bp: `android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "core_current", + updatable: true, + }`, + }, + { + name: "No Platform APIs", + bp: `android_app { + name: "foo", + srcs: ["a.java"], + platform_apis: true, + updatable: true, + }`, + expectedError: "Updatable apps must use stable SDKs", + }, + { + name: "No Core Platform APIs", + bp: `android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "core_platform", + updatable: true, + }`, + expectedError: "Updatable apps must use stable SDKs", + }, + { + name: "No unspecified APIs", + bp: `android_app { + name: "foo", + srcs: ["a.java"], + updatable: true, + }`, + expectedError: "Updatable apps must use stable SDK", + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + if test.expectedError == "" { + testJava(t, test.bp) + } else { + testJavaError(t, test.expectedError, test.bp) + } + }) + } +} + func TestResourceDirs(t *testing.T) { testCases := []struct { name string diff --git a/java/java.go b/java/java.go index d67ff874d..79568131d 100644 --- a/java/java.go +++ b/java/java.go @@ -80,7 +80,7 @@ func RegisterJavaBuildComponents(ctx android.RegistrationContext) { ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory) } -func (j *Module) checkSdkVersion(ctx android.ModuleContext) { +func (j *Module) checkSdkVersions(ctx android.ModuleContext) { if j.SocSpecific() || j.DeviceSpecific() || (j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) { if sc, ok := ctx.Module().(sdkContext); ok { @@ -90,6 +90,18 @@ func (j *Module) checkSdkVersion(ctx android.ModuleContext) { } } } + + ctx.VisitDirectDeps(func(module android.Module) { + tag := ctx.OtherModuleDependencyTag(module) + switch module.(type) { + // TODO(satayev): cover other types as well, e.g. imports + case *Library, *AndroidLibrary: + switch tag { + case bootClasspathTag, libTag, staticLibTag, java9LibTag: + checkLinkType(ctx, j, module.(linkTypeContext), tag.(dependencyTag)) + } + } + }) } func (j *Module) checkPlatformAPI(ctx android.ModuleContext) { @@ -892,15 +904,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { // Handled by AndroidApp.collectAppDeps return } - switch module.(type) { - case *Library, *AndroidLibrary: - if to, ok := module.(linkTypeContext); ok { - switch tag { - case bootClasspathTag, libTag, staticLibTag: - checkLinkType(ctx, j, to, tag.(dependencyTag)) - } - } - } + switch dep := module.(type) { case SdkLibraryDependency: switch tag { @@ -1817,7 +1821,7 @@ func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bo } func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { - j.checkSdkVersion(ctx) + j.checkSdkVersions(ctx) j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar") j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter) diff --git a/java/sdk.go b/java/sdk.go index 4c9ba2b55..2b5a21d89 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -147,6 +147,10 @@ type sdkSpec struct { raw string } +func (s sdkSpec) String() string { + return fmt.Sprintf("%s_%s", s.kind, s.version) +} + // valid checks if this sdkSpec is well-formed. Note however that true doesn't mean that the // specified SDK actually exists. func (s sdkSpec) valid() bool { @@ -158,6 +162,23 @@ func (s sdkSpec) specified() bool { return s.valid() && s.kind != sdkPrivate } +// whether the API surface is managed and versioned, i.e. has .txt file that +// get frozen on SDK freeze and changes get reviewed by API council. +func (s sdkSpec) stable() bool { + if !s.specified() { + return false + } + switch s.kind { + case sdkCore, sdkPublic, sdkSystem, sdkModule, sdkSystemServer: + return true + case sdkNone, sdkCorePlatform, sdkTest, sdkPrivate: + return false + default: + panic(fmt.Errorf("unknown sdkKind=%v", s.kind)) + } + return false +} + // prebuiltSdkAvailableForUnbundledBuilt tells whether this sdkSpec can have a prebuilt SDK // that can be used for unbundled builds. func (s sdkSpec) prebuiltSdkAvailableForUnbundledBuild() bool { -- cgit v1.2.3-59-g8ed1b From bfc6ac009670b8e3f5e33aa4bdd888baeb4ef5e9 Mon Sep 17 00:00:00 2001 From: Jaewoong Jung Date: Fri, 24 Apr 2020 15:22:40 -0700 Subject: Add overrides to runtime_resource_overlay Bug: 154928457 Test: app_test.go Change-Id: Ia52bb9fd18c22b1a02d7b36afd41561cec0473f0 --- java/androidmk.go | 1 + java/app.go | 7 +++++++ java/app_test.go | 15 ++++++++++++--- 3 files changed, 20 insertions(+), 3 deletions(-) (limited to 'java/app_test.go') diff --git a/java/androidmk.go b/java/androidmk.go index 7d575253b..6f24f34de 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -671,6 +671,7 @@ func (r *RuntimeResourceOverlay) AndroidMkEntries() []android.AndroidMkEntries { func(entries *android.AndroidMkEntries) { entries.SetString("LOCAL_CERTIFICATE", r.certificate.AndroidMkString()) entries.SetPath("LOCAL_MODULE_PATH", r.installDir.ToMakePath()) + entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", r.properties.Overrides...) }, }, }} diff --git a/java/app.go b/java/app.go index 55a758f02..f80c366ca 100755 --- a/java/app.go +++ b/java/app.go @@ -1365,6 +1365,13 @@ type RuntimeResourceOverlayProperties struct { // list of android_app modules whose resources are extracted and linked against Resource_libs []string + + // Names of modules to be overridden. Listed modules can only be other overlays + // (in Make or Soong). + // This does not completely prevent installation of the overridden overlays, but if both + // overlays would be installed by default (in PRODUCT_PACKAGES) the other overlay will be removed + // from PRODUCT_PACKAGES. + Overrides []string } func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) { diff --git a/java/app_test.go b/java/app_test.go index 4458d4e4e..b1c8b63df 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2463,6 +2463,7 @@ func TestRuntimeResourceOverlay(t *testing.T) { certificate: "platform", product_specific: true, theme: "faza", + overrides: ["foo"], } android_library { @@ -2510,14 +2511,15 @@ func TestRuntimeResourceOverlay(t *testing.T) { if expected != signingFlag { t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) } - path := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_CERTIFICATE"] + androidMkEntries := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0] + path := androidMkEntries.EntryMap["LOCAL_CERTIFICATE"] expectedPath := []string{"build/make/target/product/security/platform.x509.pem"} if !reflect.DeepEqual(path, expectedPath) { t.Errorf("Unexpected LOCAL_CERTIFICATE value: %v, expected: %v", path, expectedPath) } // Check device location. - path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"] + path = androidMkEntries.EntryMap["LOCAL_MODULE_PATH"] expectedPath = []string{"/tmp/target/product/test_device/product/overlay"} if !reflect.DeepEqual(path, expectedPath) { t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath) @@ -2525,9 +2527,16 @@ func TestRuntimeResourceOverlay(t *testing.T) { // A themed module has a different device location m = ctx.ModuleForTests("foo_themed", "android_common") - path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"] + androidMkEntries = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0] + path = androidMkEntries.EntryMap["LOCAL_MODULE_PATH"] expectedPath = []string{"/tmp/target/product/test_device/product/overlay/faza"} if !reflect.DeepEqual(path, expectedPath) { t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath) } + + overrides := androidMkEntries.EntryMap["LOCAL_OVERRIDES_PACKAGES"] + expectedOverrides := []string{"foo"} + if !reflect.DeepEqual(overrides, expectedOverrides) { + t.Errorf("Unexpected LOCAL_OVERRIDES_PACKAGES value: %v, expected: %v", overrides, expectedOverrides) + } } -- cgit v1.2.3-59-g8ed1b From 062ed7eaa11123cca7dcd608df5148718b7e4fca Mon Sep 17 00:00:00 2001 From: Jaewoong Jung Date: Sun, 26 Apr 2020 15:10:51 -0700 Subject: Add defaults support to runtime_resource_overlay. Bug: 154956723 Test: app_test.go Change-Id: Ida29035ef45ec188c95a07a8bccaaa77eea486d7 --- java/app_test.go | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ java/java.go | 1 + 2 files changed, 60 insertions(+) (limited to 'java/app_test.go') diff --git a/java/app_test.go b/java/app_test.go index b1c8b63df..39460dce6 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2540,3 +2540,62 @@ func TestRuntimeResourceOverlay(t *testing.T) { t.Errorf("Unexpected LOCAL_OVERRIDES_PACKAGES value: %v, expected: %v", overrides, expectedOverrides) } } + +func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) { + ctx, config := testJava(t, ` + java_defaults { + name: "rro_defaults", + theme: "default_theme", + product_specific: true, + aaptflags: ["--keep-raw-values"], + } + + runtime_resource_overlay { + name: "foo_with_defaults", + defaults: ["rro_defaults"], + } + + runtime_resource_overlay { + name: "foo_barebones", + } + `) + + // + // RRO module with defaults + // + m := ctx.ModuleForTests("foo_with_defaults", "android_common") + + // Check AAPT2 link flags. + aapt2Flags := strings.Split(m.Output("package-res.apk").Args["flags"], " ") + expectedFlags := []string{"--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"} + absentFlags := android.RemoveListFromList(expectedFlags, aapt2Flags) + if len(absentFlags) > 0 { + t.Errorf("expected values, %q are missing in aapt2 link flags, %q", absentFlags, aapt2Flags) + } + + // Check device location. + path := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"] + expectedPath := []string{"/tmp/target/product/test_device/product/overlay/default_theme"} + if !reflect.DeepEqual(path, expectedPath) { + t.Errorf("Unexpected LOCAL_MODULE_PATH value: %q, expected: %q", path, expectedPath) + } + + // + // RRO module without defaults + // + m = ctx.ModuleForTests("foo_barebones", "android_common") + + // Check AAPT2 link flags. + aapt2Flags = strings.Split(m.Output("package-res.apk").Args["flags"], " ") + unexpectedFlags := "--keep-raw-values" + if inList(unexpectedFlags, aapt2Flags) { + t.Errorf("unexpected value, %q is present in aapt2 link flags, %q", unexpectedFlags, aapt2Flags) + } + + // Check device location. + path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"] + expectedPath = []string{"/tmp/target/product/test_device/system/overlay"} + if !reflect.DeepEqual(path, expectedPath) { + t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath) + } +} diff --git a/java/java.go b/java/java.go index 1c2e22a51..5d7780720 100644 --- a/java/java.go +++ b/java/java.go @@ -2745,6 +2745,7 @@ func DefaultsFactory() android.Module { &sdkLibraryProperties{}, &DexImportProperties{}, &android.ApexProperties{}, + &RuntimeResourceOverlayProperties{}, ) android.InitDefaultsModule(module) -- cgit v1.2.3-59-g8ed1b From 11962107189926357839510be5ed583e093f363a Mon Sep 17 00:00:00 2001 From: Artur Satayev Date: Thu, 16 Apr 2020 13:43:02 +0100 Subject: Do not allow updatable apps without min_sdk_version. All updatable modules are expected to declare their earliest platform version they support. Bug: 153539598 Test: m Change-Id: I6243d276e5ab25a1007187ad34789ca1b4cc87bf Merged-In: I6243d276e5ab25a1007187ad34789ca1b4cc87bf Exempt-From-Owner-Approval: cherry-pick from aosp (cherry picked from commit f40fc858a2684d546a786684d78e24e5514e29e7) --- java/app.go | 7 ++++++- java/app_test.go | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'java/app_test.go') diff --git a/java/app.go b/java/app.go index 55a758f02..8e21182b6 100755 --- a/java/app.go +++ b/java/app.go @@ -112,7 +112,9 @@ type appProperties struct { IsCoverageVariant bool `blueprint:"mutated"` // Whether this app is considered mainline updatable or not. When set to true, this will enforce - // additional rules for making sure that the APK is truly updatable. Default is false. + // additional rules to make sure an app can safely be updated. Default is false. + // Prefer using other specific properties if build behaviour must be changed; avoid using this + // flag for anything but neverallow rules (unless the behaviour change is invisible to owners). Updatable *bool } @@ -255,6 +257,9 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { if !a.sdkVersion().stable() { ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.sdkVersion()) } + if String(a.deviceProperties.Min_sdk_version) == "" { + ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.") + } } a.checkPlatformAPI(ctx) diff --git a/java/app_test.go b/java/app_test.go index 4458d4e4e..134f1710b 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -276,6 +276,7 @@ func TestUpdatableApps(t *testing.T) { name: "foo", srcs: ["a.java"], sdk_version: "29", + min_sdk_version: "29", updatable: true, }`, }, @@ -285,6 +286,7 @@ func TestUpdatableApps(t *testing.T) { name: "foo", srcs: ["a.java"], sdk_version: "system_29", + min_sdk_version: "29", updatable: true, }`, }, @@ -294,6 +296,7 @@ func TestUpdatableApps(t *testing.T) { name: "foo", srcs: ["a.java"], sdk_version: "current", + min_sdk_version: "29", updatable: true, }`, }, @@ -303,6 +306,7 @@ func TestUpdatableApps(t *testing.T) { name: "foo", srcs: ["a.java"], sdk_version: "system_current", + min_sdk_version: "29", updatable: true, }`, }, @@ -312,6 +316,7 @@ func TestUpdatableApps(t *testing.T) { name: "foo", srcs: ["a.java"], sdk_version: "module_current", + min_sdk_version: "29", updatable: true, }`, }, @@ -321,6 +326,7 @@ func TestUpdatableApps(t *testing.T) { name: "foo", srcs: ["a.java"], sdk_version: "core_current", + min_sdk_version: "29", updatable: true, }`, }, @@ -330,6 +336,7 @@ func TestUpdatableApps(t *testing.T) { name: "foo", srcs: ["a.java"], platform_apis: true, + min_sdk_version: "29", updatable: true, }`, expectedError: "Updatable apps must use stable SDKs", @@ -340,6 +347,7 @@ func TestUpdatableApps(t *testing.T) { name: "foo", srcs: ["a.java"], sdk_version: "core_platform", + min_sdk_version: "29", updatable: true, }`, expectedError: "Updatable apps must use stable SDKs", @@ -350,9 +358,20 @@ func TestUpdatableApps(t *testing.T) { name: "foo", srcs: ["a.java"], updatable: true, + min_sdk_version: "29", }`, expectedError: "Updatable apps must use stable SDK", }, + { + name: "Must specify min_sdk_version", + bp: `android_app { + name: "app_without_min_sdk_version", + srcs: ["a.java"], + sdk_version: "29", + updatable: true, + }`, + expectedError: "updatable apps must set min_sdk_version.", + }, } for _, test := range testCases { -- cgit v1.2.3-59-g8ed1b From 1c93c299fb0036b823e821237a8e52febe82679a Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Sat, 15 Feb 2020 10:38:00 -0800 Subject: Require apps built against the SDK to use JNI built against the NDK Apps that expect to run on older platforms should use JNI libraries that will also run on older platforms. Require that apps that set sdk_version have jni_libs modules that also set sdk_version, or set jni_uses_platform_apis: true to bypass the check. Fixes: 149591057 Test: app_test.go Change-Id: I76b9b45fb5773bc4dfc10520108f4f3578723909 Merged-In: I76b9b45fb5773bc4dfc10520108f4f3578723909 --- apex/apex_test.go | 6 ++++-- java/app.go | 21 +++++++++++++++++---- java/app_test.go | 2 ++ 3 files changed, 23 insertions(+), 6 deletions(-) (limited to 'java/app_test.go') diff --git a/apex/apex_test.go b/apex/apex_test.go index 350579ea9..056153f78 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -3323,18 +3323,20 @@ func TestApexWithApps(t *testing.T) { android_app { name: "AppFoo", srcs: ["foo/bar/MyClass.java"], - sdk_version: "none", + sdk_version: "current", system_modules: "none", jni_libs: ["libjni"], + stl: "none", apex_available: [ "myapex" ], } android_app { name: "AppFooPriv", srcs: ["foo/bar/MyClass.java"], - sdk_version: "none", + sdk_version: "current", system_modules: "none", privileged: true, + stl: "none", apex_available: [ "myapex" ], } diff --git a/java/app.go b/java/app.go index 0ec2502ba..d93765407 100755 --- a/java/app.go +++ b/java/app.go @@ -542,7 +542,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { dexJarFile := a.dexBuildActions(ctx) - jniLibs, certificateDeps := collectAppDeps(ctx, a.shouldEmbedJnis(ctx)) + jniLibs, certificateDeps := collectAppDeps(ctx, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis)) jniJarFile := a.jniBuildActions(jniLibs, ctx) if ctx.Failed() { @@ -592,7 +592,8 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } } -func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps bool) ([]jniLib, []Certificate) { +func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps bool, + checkNativeSdkVersion bool) ([]jniLib, []Certificate) { var jniLibs []jniLib var certificates []Certificate seenModulePaths := make(map[string]bool) @@ -614,6 +615,18 @@ func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps } seenModulePaths[path.String()] = true + if checkNativeSdkVersion { + if app, ok := ctx.Module().(interface{ sdkVersion() sdkSpec }); ok { + if app.sdkVersion().specified() && + app.sdkVersion().kind != sdkCorePlatform && + dep.SdkVersion() == "" { + ctx.PropertyErrorf("jni_libs", + "JNI dependency %q uses platform APIs, but this module does not", + otherName) + } + } + } + if lib.Valid() { jniLibs = append(jniLibs, jniLib{ name: ctx.OtherModuleName(module), @@ -1133,7 +1146,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set") } - _, certificates := collectAppDeps(ctx, false) + _, certificates := collectAppDeps(ctx, false, false) // TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK // TODO: LOCAL_PACKAGE_SPLITS @@ -1405,7 +1418,7 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC r.aapt.buildActions(ctx, r, "--no-resource-deduping", "--no-resource-removal") // Sign the built package - _, certificates := collectAppDeps(ctx, false) + _, certificates := collectAppDeps(ctx, false, false) certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx) signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk") SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil) diff --git a/java/app_test.go b/java/app_test.go index 39460dce6..388014f46 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -1005,6 +1005,7 @@ func TestJNIPackaging(t *testing.T) { name: "libjni", system_shared_libs: [], stl: "none", + sdk_version: "current", } android_app { @@ -2274,6 +2275,7 @@ func TestEmbedNotice(t *testing.T) { system_shared_libs: [], stl: "none", notice: "LIB_NOTICE", + sdk_version: "current", } java_library { -- cgit v1.2.3-59-g8ed1b From 01fd7ccbc71c9eee7c56c73f05c4e7833a795aac Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 19 Feb 2020 16:54:04 -0800 Subject: Add sdk mutator for native modules Compiling native modules against the NDK disables platform features like ASAN. For anything shipped on the system image there is no reason to compile against the NDK. Add a new mutator to Soong that creates a platform and an SDK variant for modules that set sdk_version, and ignore sdk_version for the platform variant. The SDK variant will be used for embedding in APKs that may be installed on older platforms. Apexes use their own variants that enforce backwards compatibility. Test: sdk_test.go Test: TestJNIPackaging Bug: 149591340 Change-Id: I7d72934aaee2e1326cc0ba5f29f51f14feec4521 Merged-In: I7d72934aaee2e1326cc0ba5f29f51f14feec4521 (cherry picked from commit 82e192c3aeae55337e335101ba83126decd4ddac) --- Android.bp | 1 + android/neverallow.go | 44 +++++++++++++++++++ android/neverallow_test.go | 50 ++++++++++++++++++++++ apex/apex_test.go | 2 +- apex/vndk_test.go | 2 + cc/androidmk.go | 26 ++++++++++++ cc/cc.go | 46 ++++++++++++++++---- cc/library.go | 2 +- cc/linkable.go | 2 + cc/linker.go | 11 +++++ cc/ndk_library.go | 3 ++ cc/ndk_prebuilt.go | 12 ++++-- cc/sdk.go | 65 +++++++++++++++++++++++++++++ cc/sdk_test.go | 102 +++++++++++++++++++++++++++++++++++++++++++++ cc/stl.go | 6 ++- cc/testing.go | 15 +++++++ cc/toolchain_library.go | 1 + java/app.go | 7 ++++ java/app_test.go | 13 ++++-- rust/rust.go | 8 ++++ 20 files changed, 400 insertions(+), 18 deletions(-) create mode 100644 cc/sdk.go create mode 100644 cc/sdk_test.go (limited to 'java/app_test.go') diff --git a/Android.bp b/Android.bp index 062147526..21f29f5b4 100644 --- a/Android.bp +++ b/Android.bp @@ -186,6 +186,7 @@ bootstrap_go_package { "cc/rs.go", "cc/sanitize.go", "cc/sabi.go", + "cc/sdk.go", "cc/snapshot_utils.go", "cc/stl.go", "cc/strip.go", diff --git a/android/neverallow.go b/android/neverallow.go index 4d3a16fb0..cf09792e0 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -54,6 +54,7 @@ func init() { AddNeverAllowRules(createLibcoreRules()...) AddNeverAllowRules(createMediaRules()...) AddNeverAllowRules(createJavaDeviceForHostRules()...) + AddNeverAllowRules(createCcSdkVariantRules()...) } // Add a NeverAllow rule to the set of rules to apply. @@ -177,6 +178,37 @@ func createJavaDeviceForHostRules() []Rule { } } +func createCcSdkVariantRules() []Rule { + sdkVersionOnlyWhitelist := []string{ + // derive_sdk_prefer32 has stem: "derive_sdk" which conflicts with the derive_sdk. + // This sometimes works because the APEX modules that contain derive_sdk and + // derive_sdk_prefer32 suppress the platform installation rules, but fails when + // the APEX modules contain the SDK variant and the platform variant still exists. + "frameworks/base/apex/sdkextensions/derive_sdk", + } + + platformVariantPropertiesWhitelist := []string{ + // android_native_app_glue and libRSSupport use native_window.h but target old + // sdk versions (minimum and 9 respectively) where libnativewindow didn't exist, + // so they can't add libnativewindow to shared_libs to get the header directory + // for the platform variant. Allow them to use the platform variant + // property to set shared_libs. + "prebuilts/ndk", + "frameworks/rs", + } + + return []Rule{ + NeverAllow(). + NotIn(sdkVersionOnlyWhitelist...). + WithMatcher("sdk_variant_only", isSetMatcherInstance). + Because("sdk_variant_only can only be used in whitelisted projects"), + NeverAllow(). + NotIn(platformVariantPropertiesWhitelist...). + WithMatcher("platform.shared_libs", isSetMatcherInstance). + Because("platform variant properties can only be used in whitelisted projects"), + } +} + func neverallowMutator(ctx BottomUpMutatorContext) { m, ok := ctx.Module().(Module) if !ok { @@ -268,6 +300,18 @@ func (m *regexMatcher) String() string { return ".regexp(" + m.re.String() + ")" } +type isSetMatcher struct{} + +func (m *isSetMatcher) Test(value string) bool { + return value != "" +} + +func (m *isSetMatcher) String() string { + return ".is-set" +} + +var isSetMatcherInstance = &isSetMatcher{} + type ruleProperty struct { fields []string // e.x.: Vndk.Enabled matcher ValueMatcher diff --git a/android/neverallow_test.go b/android/neverallow_test.go index 83b225090..2fc42e31f 100644 --- a/android/neverallow_test.go +++ b/android/neverallow_test.go @@ -259,6 +259,50 @@ var neverallowTests = []struct { }`), }, }, + // CC sdk rule tests + { + name: `"sdk_variant_only" outside whitelist`, + fs: map[string][]byte{ + "Android.bp": []byte(` + cc_library { + name: "outside_whitelist", + sdk_version: "current", + sdk_variant_only: true, + }`), + }, + expectedErrors: []string{ + `module "outside_whitelist": violates neverallow`, + }, + }, + { + name: `"sdk_variant_only: false" outside whitelist`, + fs: map[string][]byte{ + "Android.bp": []byte(` + cc_library { + name: "outside_whitelist", + sdk_version: "current", + sdk_variant_only: false, + }`), + }, + expectedErrors: []string{ + `module "outside_whitelist": violates neverallow`, + }, + }, + { + name: `"platform" outside whitelist`, + fs: map[string][]byte{ + "Android.bp": []byte(` + cc_library { + name: "outside_whitelist", + platform: { + shared_libs: ["libfoo"], + }, + }`), + }, + expectedErrors: []string{ + `module "outside_whitelist": violates neverallow`, + }, + }, } func TestNeverallow(t *testing.T) { @@ -299,6 +343,8 @@ type mockCcLibraryProperties struct { Include_dirs []string Vendor_available *bool Static_libs []string + Sdk_version *string + Sdk_variant_only *bool Vndk struct { Enabled *bool @@ -315,6 +361,10 @@ type mockCcLibraryProperties struct { Cflags []string } } + + Platform struct { + Shared_libs []string + } } type mockCcLibraryModule struct { diff --git a/apex/apex_test.go b/apex/apex_test.go index 056153f78..4c0eadab0 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -3373,7 +3373,7 @@ func TestApexWithApps(t *testing.T) { } // JNI libraries including transitive deps are for _, jni := range []string{"libjni", "libfoo"} { - jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module).OutputFile() + jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_myapex").Module().(*cc.Module).OutputFile() // ... embedded inside APK (jnilibs.zip) ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String()) // ... and not directly inside the APEX diff --git a/apex/vndk_test.go b/apex/vndk_test.go index 54447fa79..523ac2630 100644 --- a/apex/vndk_test.go +++ b/apex/vndk_test.go @@ -143,6 +143,7 @@ func TestVndkApexUsesVendorVariant(t *testing.T) { system_shared_libs: [], stl: "none", notice: "custom_notice", + sdk_version: "current", } cc_library { name: "libprofile-clang-extras_ndk", @@ -151,6 +152,7 @@ func TestVndkApexUsesVendorVariant(t *testing.T) { system_shared_libs: [], stl: "none", notice: "custom_notice", + sdk_version: "current", } `, func(fs map[string][]byte, config android.Config) { config.TestProductVariables.Native_coverage = proptools.BoolPtr(true) diff --git a/cc/androidmk.go b/cc/androidmk.go index 1c90aaf79..5438b149d 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -29,6 +29,7 @@ var ( vendorSuffix = ".vendor" ramdiskSuffix = ".ramdisk" recoverySuffix = ".recovery" + sdkSuffix = ".sdk" ) type AndroidMkContext interface { @@ -103,6 +104,28 @@ func (c *Module) AndroidMkEntries() []android.AndroidMkEntries { } } } + if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake { + // Make the SDK variant uninstallable so that there are not two rules to install + // to the same location. + entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) + // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite + // dependencies to the .sdk suffix when building a module that uses the SDK. + entries.SetString("SOONG_SDK_VARIANT_MODULES", + "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))") + } + }, + }, + ExtraFooters: []android.AndroidMkExtraFootersFunc{ + func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { + if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake && + c.CcLibraryInterface() && c.Shared() { + // Using the SDK variant as a JNI library needs a copy of the .so that + // is not named .sdk.so so that it can be packaged into the APK with + // the right name. + fmt.Fprintln(w, "$(eval $(call copy-one-file,", + "$(LOCAL_BUILT_MODULE),", + "$(patsubst %.sdk.so,%.so,$(LOCAL_BUILT_MODULE))))") + } }, }, } @@ -397,6 +420,9 @@ func (library *toolchainLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, } func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { + if installer.path == (android.InstallPath{}) { + return + } // Soong installation is only supported for host modules. Have Make // installation trigger Soong installation. if ctx.Target().Os.Class == android.Host { diff --git a/cc/cc.go b/cc/cc.go index 9baecebdb..39848092a 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -42,6 +42,7 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("cc_defaults", defaultsFactory) ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("sdk", sdkMutator).Parallel() ctx.BottomUp("vndk", VndkMutator).Parallel() ctx.BottomUp("link", LinkageMutator).Parallel() ctx.BottomUp("ndk_api", NdkApiMutator).Parallel() @@ -208,12 +209,16 @@ type BaseProperties struct { // Deprecated. true is the default, false is invalid. Clang *bool `android:"arch_variant"` - // Minimum sdk version supported when compiling against the ndk + // Minimum sdk version supported when compiling against the ndk. Setting this property causes + // two variants to be built, one for the platform and one for apps. Sdk_version *string // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX). Min_sdk_version *string + // If true, always create an sdk variant and don't create a platform variant. + Sdk_variant_only *bool + AndroidMkSharedLibs []string `blueprint:"mutated"` AndroidMkStaticLibs []string `blueprint:"mutated"` AndroidMkRuntimeLibs []string `blueprint:"mutated"` @@ -255,6 +260,16 @@ type BaseProperties struct { SnapshotRuntimeLibs []string `blueprint:"mutated"` Installable *bool + + // Set by factories of module types that can only be referenced from variants compiled against + // the SDK. + AlwaysSdk bool `blueprint:"mutated"` + + // Variant is an SDK variant created by sdkMutator + IsSdkVariant bool `blueprint:"mutated"` + // Set when both SDK and platform variants are exported to Make to trigger renaming the SDK + // variant to have a ".sdk" suffix. + SdkAndPlatformVariantVisibleToMake bool `blueprint:"mutated"` } type VendorProperties struct { @@ -534,7 +549,10 @@ func (c *Module) Shared() bool { } func (c *Module) SelectedStl() string { - return c.stl.Properties.SelectedStl + if c.stl != nil { + return c.stl.Properties.SelectedStl + } + return "" } func (c *Module) ToolchainLibrary() bool { @@ -562,6 +580,10 @@ func (c *Module) SdkVersion() string { return String(c.Properties.Sdk_version) } +func (c *Module) AlwaysSdk() bool { + return c.Properties.AlwaysSdk || Bool(c.Properties.Sdk_variant_only) +} + func (c *Module) IncludeDirs() android.Paths { if c.linker != nil { if library, ok := c.linker.(exportedFlagsProducer); ok { @@ -821,6 +843,17 @@ func (c *Module) UseVndk() bool { return c.Properties.VndkVersion != "" } +func (c *Module) canUseSdk() bool { + return c.Os() == android.Android && !c.UseVndk() && !c.InRamdisk() && !c.InRecovery() +} + +func (c *Module) UseSdk() bool { + if c.canUseSdk() { + return String(c.Properties.Sdk_version) != "" + } + return false +} + func (c *Module) isCoverageVariant() bool { return c.coverage.Properties.IsCoverageVariant } @@ -1078,14 +1111,11 @@ func (ctx *moduleContextImpl) header() bool { } func (ctx *moduleContextImpl) canUseSdk() bool { - return ctx.ctx.Device() && !ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && !ctx.ctx.Fuchsia() + return ctx.mod.canUseSdk() } func (ctx *moduleContextImpl) useSdk() bool { - if ctx.canUseSdk() { - return String(ctx.mod.Properties.Sdk_version) != "" - } - return false + return ctx.mod.UseSdk() } func (ctx *moduleContextImpl) sdkVersion() string { @@ -1404,6 +1434,8 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { c.Properties.SubName += ramdiskSuffix } else if c.InRecovery() && !c.OnlyInRecovery() { c.Properties.SubName += recoverySuffix + } else if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake { + c.Properties.SubName += sdkSuffix } ctx := &moduleContext{ diff --git a/cc/library.go b/cc/library.go index c3b20b699..ce814b11c 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1224,7 +1224,7 @@ func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) { if Bool(library.Properties.Static_ndk_lib) && library.static() && !ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && ctx.Device() && library.baseLinker.sanitize.isUnsanitizedVariant() && - !library.buildStubs() { + !library.buildStubs() && ctx.sdkVersion() == "" { installPath := getNdkSysrootBase(ctx).Join( ctx, "usr/lib", config.NDKTriple(ctx.toolchain()), file.Base()) diff --git a/cc/linkable.go b/cc/linkable.go index 9147681d0..4a70d48f7 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -47,12 +47,14 @@ type LinkableInterface interface { InRecovery() bool OnlyInRecovery() bool + UseSdk() bool UseVndk() bool MustUseVendorVariant() bool IsVndk() bool HasVendorVariant() bool SdkVersion() string + AlwaysSdk() bool ToolchainLibrary() bool NdkPrebuiltStl() bool diff --git a/cc/linker.go b/cc/linker.go index aa2d0ab24..9b2c1e71e 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -158,6 +158,13 @@ type BaseLinkerProperties struct { // the ramdisk variant of the C/C++ module. Exclude_static_libs []string } + Platform struct { + // list of shared libs that should be use to build the platform variant + // of a module that sets sdk_version. This should rarely be necessary, + // in most cases the same libraries are available for the SDK and platform + // variants. + Shared_libs []string + } } // make android::build:GetBuildNumber() available containing the build ID. @@ -255,6 +262,10 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs) } + if !ctx.useSdk() { + deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Target.Platform.Shared_libs...) + } + if ctx.toolchain().Bionic() { // libclang_rt.builtins and libatomic have to be last on the command line if !Bool(linker.Properties.No_libcrt) { diff --git a/cc/ndk_library.go b/cc/ndk_library.go index eb8e9d3be..119ca403d 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -385,6 +385,9 @@ func newStubLibrary() *Module { module.linker = stub module.installer = stub + module.Properties.AlwaysSdk = true + module.Properties.Sdk_version = StringPtr("current") + module.AddProperties(&stub.properties, &library.MutatedProperties) return module diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go index 3a630d2c0..c4d770837 100644 --- a/cc/ndk_prebuilt.go +++ b/cc/ndk_prebuilt.go @@ -76,6 +76,8 @@ func NdkPrebuiltObjectFactory() android.Module { baseLinker: NewBaseLinker(nil), }, } + module.Properties.AlwaysSdk = true + module.Properties.Sdk_version = StringPtr("current") module.Properties.HideFromMake = true return module.Init() } @@ -125,10 +127,9 @@ func NdkPrebuiltSharedStlFactory() android.Module { libraryDecorator: library, } module.installer = nil - minVersionString := "minimum" - noStlString := "none" - module.Properties.Sdk_version = &minVersionString - module.stl.Properties.Stl = &noStlString + module.Properties.Sdk_version = StringPtr("minimum") + module.Properties.AlwaysSdk = true + module.stl.Properties.Stl = StringPtr("none") return module.Init() } @@ -145,6 +146,9 @@ func NdkPrebuiltStaticStlFactory() android.Module { } module.installer = nil module.Properties.HideFromMake = true + module.Properties.AlwaysSdk = true + module.Properties.Sdk_version = StringPtr("current") + module.stl.Properties.Stl = StringPtr("none") module.ModuleBase.EnableNativeBridgeSupportByDefault() return module.Init() } diff --git a/cc/sdk.go b/cc/sdk.go new file mode 100644 index 000000000..d05a04a12 --- /dev/null +++ b/cc/sdk.go @@ -0,0 +1,65 @@ +// Copyright 2020 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cc + +import ( + "android/soong/android" + "android/soong/genrule" +) + +// sdkMutator sets a creates a platform and an SDK variant for modules +// that set sdk_version, and ignores sdk_version for the platform +// variant. The SDK variant will be used for embedding in APKs +// that may be installed on older platforms. Apexes use their own +// variants that enforce backwards compatibility. +func sdkMutator(ctx android.BottomUpMutatorContext) { + if ctx.Os() != android.Android { + return + } + + switch m := ctx.Module().(type) { + case LinkableInterface: + if m.AlwaysSdk() { + if !m.UseSdk() { + ctx.ModuleErrorf("UseSdk() must return true when AlwaysSdk is set, did the factory forget to set Sdk_version?") + } + ctx.CreateVariations("sdk") + } else if m.UseSdk() { + modules := ctx.CreateVariations("", "sdk") + modules[0].(*Module).Properties.Sdk_version = nil + modules[1].(*Module).Properties.IsSdkVariant = true + + if ctx.Config().UnbundledBuild() { + modules[0].(*Module).Properties.HideFromMake = true + } else { + modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true + modules[1].(*Module).Properties.PreventInstall = true + } + ctx.AliasVariation("") + } else { + ctx.CreateVariations("") + ctx.AliasVariation("") + } + case *genrule.Module: + if p, ok := m.Extra.(*GenruleExtraProperties); ok { + if String(p.Sdk_version) != "" { + ctx.CreateVariations("", "sdk") + } else { + ctx.CreateVariations("") + } + ctx.AliasVariation("") + } + } +} diff --git a/cc/sdk_test.go b/cc/sdk_test.go new file mode 100644 index 000000000..5a3c181dc --- /dev/null +++ b/cc/sdk_test.go @@ -0,0 +1,102 @@ +// Copyright 2020 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cc + +import ( + "testing" + + "android/soong/android" +) + +func TestSdkMutator(t *testing.T) { + bp := ` + cc_library { + name: "libsdk", + shared_libs: ["libsdkdep"], + sdk_version: "current", + stl: "c++_shared", + } + + cc_library { + name: "libsdkdep", + sdk_version: "current", + stl: "c++_shared", + } + + cc_library { + name: "libplatform", + shared_libs: ["libsdk"], + stl: "libc++", + } + + cc_binary { + name: "platformbinary", + shared_libs: ["libplatform"], + stl: "libc++", + } + + cc_binary { + name: "sdkbinary", + shared_libs: ["libsdk"], + sdk_version: "current", + stl: "libc++", + } + ` + + assertDep := func(t *testing.T, from, to android.TestingModule) { + t.Helper() + found := false + + var toFile android.Path + m := to.Module().(*Module) + if toc := m.Toc(); toc.Valid() { + toFile = toc.Path() + } else { + toFile = m.outputFile.Path() + } + + rule := from.Description("link") + for _, dep := range rule.Implicits { + if dep.String() == toFile.String() { + found = true + } + } + if !found { + t.Errorf("expected %q in %q", toFile.String(), rule.Implicits.Strings()) + } + } + + ctx := testCc(t, bp) + + libsdkNDK := ctx.ModuleForTests("libsdk", "android_arm64_armv8-a_sdk_shared") + libsdkPlatform := ctx.ModuleForTests("libsdk", "android_arm64_armv8-a_shared") + libsdkdepNDK := ctx.ModuleForTests("libsdkdep", "android_arm64_armv8-a_sdk_shared") + libsdkdepPlatform := ctx.ModuleForTests("libsdkdep", "android_arm64_armv8-a_shared") + libplatform := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_shared") + platformbinary := ctx.ModuleForTests("platformbinary", "android_arm64_armv8-a") + sdkbinary := ctx.ModuleForTests("sdkbinary", "android_arm64_armv8-a_sdk") + + libcxxNDK := ctx.ModuleForTests("ndk_libc++_shared", "android_arm64_armv8-a_sdk_shared") + libcxxPlatform := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared") + + assertDep(t, libsdkNDK, libsdkdepNDK) + assertDep(t, libsdkPlatform, libsdkdepPlatform) + assertDep(t, libplatform, libsdkPlatform) + assertDep(t, platformbinary, libplatform) + assertDep(t, sdkbinary, libsdkNDK) + + assertDep(t, libsdkNDK, libcxxNDK) + assertDep(t, libsdkPlatform, libcxxPlatform) +} diff --git a/cc/stl.go b/cc/stl.go index eda8a4ffc..34ff30c52 100644 --- a/cc/stl.go +++ b/cc/stl.go @@ -115,9 +115,13 @@ func (stl *stl) begin(ctx BaseModuleContext) { switch s { case "libc++", "libc++_static": return s + case "c++_shared": + return "libc++" + case "c++_static": + return "libc++_static" case "none": return "" - case "": + case "", "system": if ctx.static() { return "libc++_static" } else { diff --git a/cc/testing.go b/cc/testing.go index f85795b33..53f09955a 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -152,6 +152,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { name: "libgcc_stripped", vendor_available: true, recovery_available: true, + sdk_version: "current", src: "", } @@ -169,6 +170,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { llndk_library { name: "libc", symbol_file: "", + sdk_version: "current", } cc_library { name: "libm", @@ -188,6 +190,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { llndk_library { name: "libm", symbol_file: "", + sdk_version: "current", } cc_library { name: "libdl", @@ -207,6 +210,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { llndk_library { name: "libdl", symbol_file: "", + sdk_version: "current", } cc_library { name: "libft2", @@ -219,6 +223,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { name: "libft2", symbol_file: "", vendor_available: false, + sdk_version: "current", } cc_library { name: "libc++_static", @@ -375,6 +380,16 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { sdk_version: "27", } + ndk_prebuilt_object { + name: "ndk_crtbegin_dynamic.27", + sdk_version: "27", + } + + ndk_prebuilt_object { + name: "ndk_crtend_android.27", + sdk_version: "27", + } + ndk_prebuilt_shared_stl { name: "ndk_libc++_shared", } diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go index dfc6f7679..042e012d9 100644 --- a/cc/toolchain_library.go +++ b/cc/toolchain_library.go @@ -67,6 +67,7 @@ func ToolchainLibraryFactory() android.Module { module.stl = nil module.sanitize = nil module.installer = nil + module.Properties.Sdk_version = StringPtr("current") return module.Init() } diff --git a/java/app.go b/java/app.go index d93765407..f81a7646b 100755 --- a/java/app.go +++ b/java/app.go @@ -218,6 +218,13 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { for _, jniTarget := range ctx.MultiTargets() { variation := append(jniTarget.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"}) + + // If the app builds against an Android SDK use the SDK variant of JNI dependencies + // unless jni_uses_platform_apis is set. + if a.sdkVersion().specified() && a.sdkVersion().kind != sdkCorePlatform && + !Bool(a.appProperties.Jni_uses_platform_apis) { + variation = append(variation, blueprint.Variation{Mutator: "sdk", Variation: "sdk"}) + } ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...) } diff --git a/java/app_test.go b/java/app_test.go index 388014f46..49dbd1270 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -893,6 +893,7 @@ func TestJNIABI(t *testing.T) { cc_library { name: "libjni", system_shared_libs: [], + sdk_version: "current", stl: "none", } @@ -1030,26 +1031,26 @@ func TestJNIPackaging(t *testing.T) { android_test { name: "test", - sdk_version: "core_platform", + sdk_version: "current", jni_libs: ["libjni"], } android_test { name: "test_noembed", - sdk_version: "core_platform", + sdk_version: "current", jni_libs: ["libjni"], use_embedded_native_libs: false, } android_test_helper_app { name: "test_helper", - sdk_version: "core_platform", + sdk_version: "current", jni_libs: ["libjni"], } android_test_helper_app { name: "test_helper_noembed", - sdk_version: "core_platform", + sdk_version: "current", jni_libs: ["libjni"], use_embedded_native_libs: false, } @@ -1081,6 +1082,10 @@ func TestJNIPackaging(t *testing.T) { if g, w := !strings.Contains(jniLibZip.Args["jarArgs"], "-L 0"), test.compressed; g != w { t.Errorf("expected jni compressed %v, got %v", w, g) } + + if !strings.Contains(jniLibZip.Implicits[0].String(), "_sdk_") { + t.Errorf("expected input %q to use sdk variant", jniLibZip.Implicits[0].String()) + } } }) } diff --git a/rust/rust.go b/rust/rust.go index 17734f9d3..5cc884572 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -164,6 +164,10 @@ func (mod *Module) OnlyInRecovery() bool { return false } +func (mod *Module) UseSdk() bool { + return false +} + func (mod *Module) UseVndk() bool { return false } @@ -184,6 +188,10 @@ func (mod *Module) SdkVersion() string { return "" } +func (mod *Module) AlwaysSdk() bool { + return false +} + func (mod *Module) ToolchainLibrary() bool { return false } -- cgit v1.2.3-59-g8ed1b From b830796ca4fe07dc8aa9b41090d795b6c1c970ca Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 27 Apr 2020 09:42:27 -0700 Subject: soong: Add support for override_runtime_resource_overlay Bug: 154960712 Test: go test ./... -test.v -run TestOverrideAndroidApp Change-Id: I8ca9d173b6ab7f9306c83c2b434107111aa2ca88 --- java/app.go | 59 ++++++++++++++++++++++++++++++++++++++++---- java/app_test.go | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 5 deletions(-) (limited to 'java/app_test.go') diff --git a/java/app.go b/java/app.go index 0ec2502ba..4468dc543 100755 --- a/java/app.go +++ b/java/app.go @@ -45,6 +45,7 @@ func RegisterAppBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory) ctx.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory) ctx.RegisterModuleType("override_android_test", OverrideAndroidTestModuleFactory) + ctx.RegisterModuleType("override_runtime_resource_overlay", OverrideRuntimeResourceOverlayModuleFactory) ctx.RegisterModuleType("android_app_import", AndroidAppImportFactory) ctx.RegisterModuleType("android_test_import", AndroidTestImportFactory) ctx.RegisterModuleType("runtime_resource_overlay", RuntimeResourceOverlayFactory) @@ -129,6 +130,15 @@ type overridableAppProperties struct { Logging_parent *string } +// runtime_resource_overlay properties that can be overridden by override_runtime_resource_overlay +type OverridableRuntimeResourceOverlayProperties struct { + // the package name of this app. The package name in the manifest file is used if one was not given. + Package_name *string + + // the target package name of this overlay app. The target package name in the manifest file is used if one was not given. + Target_package_name *string +} + type AndroidApp struct { Library aapt @@ -959,6 +969,27 @@ func OverrideAndroidTestModuleFactory() android.Module { return m } +type OverrideRuntimeResourceOverlay struct { + android.ModuleBase + android.OverrideModuleBase +} + +func (i *OverrideRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // All the overrides happen in the base module. + // TODO(jungjw): Check the base module type. +} + +// override_runtime_resource_overlay is used to create a module based on another +// runtime_resource_overlay module by overriding some of its properties. +func OverrideRuntimeResourceOverlayModuleFactory() android.Module { + m := &OverrideRuntimeResourceOverlay{} + m.AddProperties(&OverridableRuntimeResourceOverlayProperties{}) + + android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon) + android.InitOverrideModule(m) + return m +} + type AndroidAppImport struct { android.ModuleBase android.DefaultableModuleBase @@ -1342,9 +1373,11 @@ func AndroidTestImportFactory() android.Module { type RuntimeResourceOverlay struct { android.ModuleBase android.DefaultableModuleBase + android.OverridableModuleBase aapt - properties RuntimeResourceOverlayProperties + properties RuntimeResourceOverlayProperties + overridableProperties OverridableRuntimeResourceOverlayProperties certificate Certificate @@ -1402,7 +1435,21 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC // Compile and link resources r.aapt.hasNoCode = true // Do not remove resources without default values nor dedupe resource configurations with the same value - r.aapt.buildActions(ctx, r, "--no-resource-deduping", "--no-resource-removal") + aaptLinkFlags := []string{"--no-resource-deduping", "--no-resource-removal"} + // Allow the override of "package name" and "overlay target package name" + manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName()) + if overridden || r.overridableProperties.Package_name != nil { + // The product override variable has a priority over the package_name property. + if !overridden { + manifestPackageName = *r.overridableProperties.Package_name + } + aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName) + } + if r.overridableProperties.Target_package_name != nil { + aaptLinkFlags = append(aaptLinkFlags, + "--rename-overlay-target-package "+*r.overridableProperties.Target_package_name) + } + r.aapt.buildActions(ctx, r, aaptLinkFlags...) // Sign the built package _, certificates := collectAppDeps(ctx, false) @@ -1441,10 +1488,12 @@ func RuntimeResourceOverlayFactory() android.Module { module := &RuntimeResourceOverlay{} module.AddProperties( &module.properties, - &module.aaptProperties) - - InitJavaModule(module, android.DeviceSupported) + &module.aaptProperties, + &module.overridableProperties) + android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + android.InitOverridableModule(module, &module.properties.Overrides) return module } diff --git a/java/app_test.go b/java/app_test.go index 39460dce6..5b1e37007 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2599,3 +2599,78 @@ func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) { t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath) } } + +func TestOverrideRuntimeResourceOverlay(t *testing.T) { + ctx, _ := testJava(t, ` + runtime_resource_overlay { + name: "foo_overlay", + certificate: "platform", + product_specific: true, + sdk_version: "current", + } + + override_runtime_resource_overlay { + name: "bar_overlay", + base: "foo_overlay", + package_name: "com.android.bar.overlay", + target_package_name: "com.android.bar", + } + `) + + expectedVariants := []struct { + moduleName string + variantName string + apkPath string + overrides []string + targetVariant string + packageFlag string + targetPackageFlag string + }{ + { + variantName: "android_common", + apkPath: "/target/product/test_device/product/overlay/foo_overlay.apk", + overrides: nil, + targetVariant: "android_common", + packageFlag: "", + targetPackageFlag: "", + }, + { + variantName: "android_common_bar_overlay", + apkPath: "/target/product/test_device/product/overlay/bar_overlay.apk", + overrides: []string{"foo_overlay"}, + targetVariant: "android_common_bar", + packageFlag: "com.android.bar.overlay", + targetPackageFlag: "com.android.bar", + }, + } + for _, expected := range expectedVariants { + variant := ctx.ModuleForTests("foo_overlay", expected.variantName) + + // Check the final apk name + outputs := variant.AllOutputs() + expectedApkPath := buildDir + expected.apkPath + found := false + for _, o := range outputs { + if o == expectedApkPath { + found = true + break + } + } + if !found { + t.Errorf("Can't find %q in output files.\nAll outputs:%v", expectedApkPath, outputs) + } + + // Check if the overrides field values are correctly aggregated. + mod := variant.Module().(*RuntimeResourceOverlay) + if !reflect.DeepEqual(expected.overrides, mod.properties.Overrides) { + t.Errorf("Incorrect overrides property value, expected: %q, got: %q", + expected.overrides, mod.properties.Overrides) + } + + // Check aapt2 flags. + res := variant.Output("package-res.apk") + aapt2Flags := res.Args["flags"] + checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) + checkAapt2LinkFlag(t, aapt2Flags, "rename-overlay-target-package", expected.targetPackageFlag) + } +} -- cgit v1.2.3-59-g8ed1b From 70dd74dde78f03f420c0e99cdeb5b60b02d95b56 Mon Sep 17 00:00:00 2001 From: Liz Kammer Date: Thu, 7 May 2020 13:24:05 -0700 Subject: Add signing certificate lineage support to soong Test: app_test Bug: 153366049 Change-Id: I65a92d6c40057dcc01950991fb7be485de1c9080 --- java/app.go | 15 ++++++++--- java/app_builder.go | 16 +++++++----- java/app_test.go | 71 ++++++++++++++++++++++++++++++++++++++++++----------- java/testing.go | 1 + 4 files changed, 78 insertions(+), 25 deletions(-) (limited to 'java/app_test.go') diff --git a/java/app.go b/java/app.go index 4c4b83c82..531b46a66 100755 --- a/java/app.go +++ b/java/app.go @@ -129,6 +129,9 @@ type overridableAppProperties struct { // or an android_app_certificate module name in the form ":module". Certificate *string + // Name of the signing certificate lineage file. + Lineage *string + // the package name of this app. The package name in the manifest file is used if one was not given. Package_name *string @@ -586,7 +589,11 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { if v4SigningRequested { v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+".apk.idsig") } - CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile) + var lineageFile android.Path + if lineage := String(a.overridableAppProperties.Lineage); lineage != "" { + lineageFile = android.PathForModuleSrc(ctx, lineage) + } + CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile) a.outputFile = packageFile if v4SigningRequested { a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) @@ -598,7 +605,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { if v4SigningRequested { v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig") } - CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile) + CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile) a.extraOutputFiles = append(a.extraOutputFiles, packageFile) if v4SigningRequested { a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) @@ -1249,7 +1256,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext } a.certificate = certificates[0] signed := android.PathForModuleOut(ctx, "signed", apkFilename) - SignAppPackage(ctx, signed, dexOutput, certificates, nil) + SignAppPackage(ctx, signed, dexOutput, certificates, nil, nil) a.outputFile = signed } else { alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename) @@ -1486,7 +1493,7 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC _, certificates := collectAppDeps(ctx, false, false) certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx) signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk") - SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil) + SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, nil) r.certificate = certificates[0] r.outputFile = signed diff --git a/java/app_builder.go b/java/app_builder.go index b2780bc90..e8c16c23f 100644 --- a/java/app_builder.go +++ b/java/app_builder.go @@ -45,7 +45,7 @@ var combineApk = pctx.AndroidStaticRule("combineApk", }) func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath, - packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath) { + packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path) { unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk" unsignedApk := android.PathForModuleOut(ctx, unsignedApkName) @@ -66,10 +66,10 @@ func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.Writa Implicits: deps, }) - SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile) + SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile) } -func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, v4SignatureFile android.WritablePath) { +func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, v4SignatureFile android.WritablePath, lineageFile android.Path) { var certificateArgs []string var deps android.Paths @@ -79,10 +79,14 @@ func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, u } outputFiles := android.WritablePaths{signedApk} - var flag string = "" + var flags []string if v4SignatureFile != nil { outputFiles = append(outputFiles, v4SignatureFile) - flag = "--enable-v4" + flags = append(flags, "--enable-v4") + } + + if lineageFile != nil { + flags = append(flags, "--lineage", lineageFile.String()) } ctx.Build(pctx, android.BuildParams{ @@ -93,7 +97,7 @@ func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, u Implicits: deps, Args: map[string]string{ "certificates": strings.Join(certificateArgs, " "), - "flags": flag, + "flags": strings.Join(flags, " "), }, }) } diff --git a/java/app_test.go b/java/app_test.go index f2cbbfb71..75d1c90e5 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -1115,7 +1115,8 @@ func TestCertificates(t *testing.T) { name string bp string certificateOverride string - expected string + expectedLineage string + expectedCertificate string }{ { name: "default", @@ -1127,7 +1128,8 @@ func TestCertificates(t *testing.T) { } `, certificateOverride: "", - expected: "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8", + expectedLineage: "", + expectedCertificate: "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8", }, { name: "module certificate property", @@ -1145,7 +1147,8 @@ func TestCertificates(t *testing.T) { } `, certificateOverride: "", - expected: "cert/new_cert.x509.pem cert/new_cert.pk8", + expectedLineage: "", + expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8", }, { name: "path certificate property", @@ -1158,7 +1161,8 @@ func TestCertificates(t *testing.T) { } `, certificateOverride: "", - expected: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + expectedLineage: "", + expectedCertificate: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", }, { name: "certificate overrides", @@ -1176,7 +1180,28 @@ func TestCertificates(t *testing.T) { } `, certificateOverride: "foo:new_certificate", - expected: "cert/new_cert.x509.pem cert/new_cert.pk8", + expectedLineage: "", + expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8", + }, + { + name: "certificate lineage", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + certificate: ":new_certificate", + lineage: "lineage.bin", + sdk_version: "current", + } + + android_app_certificate { + name: "new_certificate", + certificate: "cert/new_cert", + } + `, + certificateOverride: "", + expectedLineage: "--lineage lineage.bin", + expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8", }, } @@ -1192,9 +1217,14 @@ func TestCertificates(t *testing.T) { foo := ctx.ModuleForTests("foo", "android_common") signapk := foo.Output("foo.apk") - signFlags := signapk.Args["certificates"] - if test.expected != signFlags { - t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expected, signFlags) + signCertificateFlags := signapk.Args["certificates"] + if test.expectedCertificate != signCertificateFlags { + t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expectedCertificate, signCertificateFlags) + } + + signFlags := signapk.Args["flags"] + if test.expectedLineage != signFlags { + t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expectedLineage, signFlags) } }) } @@ -1368,6 +1398,7 @@ func TestOverrideAndroidApp(t *testing.T) { name: "bar", base: "foo", certificate: ":new_certificate", + lineage: "lineage.bin", logging_parent: "bah", } @@ -1388,7 +1419,8 @@ func TestOverrideAndroidApp(t *testing.T) { variantName string apkName string apkPath string - signFlag string + certFlag string + lineageFlag string overrides []string aaptFlag string logging_parent string @@ -1397,7 +1429,8 @@ func TestOverrideAndroidApp(t *testing.T) { moduleName: "foo", variantName: "android_common", apkPath: "/target/product/test_device/system/app/foo/foo.apk", - signFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", overrides: []string{"qux"}, aaptFlag: "", logging_parent: "", @@ -1406,7 +1439,8 @@ func TestOverrideAndroidApp(t *testing.T) { moduleName: "bar", variantName: "android_common_bar", apkPath: "/target/product/test_device/system/app/bar/bar.apk", - signFlag: "cert/new_cert.x509.pem cert/new_cert.pk8", + certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8", + lineageFlag: "--lineage lineage.bin", overrides: []string{"qux", "foo"}, aaptFlag: "", logging_parent: "bah", @@ -1415,7 +1449,8 @@ func TestOverrideAndroidApp(t *testing.T) { moduleName: "baz", variantName: "android_common_baz", apkPath: "/target/product/test_device/system/app/baz/baz.apk", - signFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", overrides: []string{"qux", "foo"}, aaptFlag: "--rename-manifest-package org.dandroid.bp", logging_parent: "", @@ -1440,9 +1475,15 @@ func TestOverrideAndroidApp(t *testing.T) { // Check the certificate paths signapk := variant.Output(expected.moduleName + ".apk") - signFlag := signapk.Args["certificates"] - if expected.signFlag != signFlag { - t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected.signFlag, signFlag) + certFlag := signapk.Args["certificates"] + if expected.certFlag != certFlag { + t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected.certFlag, certFlag) + } + + // Check the lineage flags + lineageFlag := signapk.Args["flags"] + if expected.lineageFlag != lineageFlag { + t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected.lineageFlag, lineageFlag) } // Check if the overrides field values are correctly aggregated. diff --git a/java/testing.go b/java/testing.go index 28c1a2691..dd3565313 100644 --- a/java/testing.go +++ b/java/testing.go @@ -114,6 +114,7 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string "cert/new_cert.x509.pem": nil, "cert/new_cert.pk8": nil, + "lineage.bin": nil, "testdata/data": nil, -- cgit v1.2.3-59-g8ed1b From 1dd9c446be8311b6188de9332f94f5144025bdc5 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 8 May 2020 11:20:24 -0700 Subject: Add error checking and tests for jni_uses_sdk_apis and jni_uses_platform_apis Check that jni_uses_sdk_apis and jni_uses_platform_apis are consistent with sdk_version, and add tests that they select the right variant. Bug: 154665579 Test: app_test.go Change-Id: I544a4f881ba16dacd7e74cd480c095091b3cf667 Merged-In: I544a4f881ba16dacd7e74cd480c095091b3cf667 (cherry picked from commit 3c007704c74a891bf2c5dba60bf82bd789659762) --- java/app.go | 13 ++++++-- java/app_test.go | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 107 insertions(+), 4 deletions(-) (limited to 'java/app_test.go') diff --git a/java/app.go b/java/app.go index eac76fdab..baae97a9a 100755 --- a/java/app.go +++ b/java/app.go @@ -230,6 +230,16 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { a.aapt.deps(ctx, sdkDep) } + usesSDK := a.sdkVersion().specified() && a.sdkVersion().kind != sdkCorePlatform + + if usesSDK && Bool(a.appProperties.Jni_uses_sdk_apis) { + ctx.PropertyErrorf("jni_uses_sdk_apis", + "can only be set for modules that do not set sdk_version") + } else if !usesSDK && Bool(a.appProperties.Jni_uses_platform_apis) { + ctx.PropertyErrorf("jni_uses_platform_apis", + "can only be set for modules that set sdk_version") + } + tag := &jniDependencyTag{} for _, jniTarget := range ctx.MultiTargets() { variation := append(jniTarget.Variations(), @@ -237,8 +247,7 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { // If the app builds against an Android SDK use the SDK variant of JNI dependencies // unless jni_uses_platform_apis is set. - if a.sdkVersion().specified() && a.sdkVersion().kind != sdkCorePlatform && - !Bool(a.appProperties.Jni_uses_platform_apis) || + if (usesSDK && !Bool(a.appProperties.Jni_uses_platform_apis)) || Bool(a.appProperties.Jni_uses_sdk_apis) { variation = append(variation, blueprint.Variation{Mutator: "sdk", Variation: "sdk"}) } diff --git a/java/app_test.go b/java/app_test.go index f2cbbfb71..248cc8959 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -1110,6 +1110,100 @@ func TestJNIPackaging(t *testing.T) { } } +func TestJNISDK(t *testing.T) { + ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` + cc_library { + name: "libjni", + system_shared_libs: [], + stl: "none", + sdk_version: "current", + } + + android_test { + name: "app_platform", + jni_libs: ["libjni"], + platform_apis: true, + } + + android_test { + name: "app_sdk", + jni_libs: ["libjni"], + sdk_version: "current", + } + + android_test { + name: "app_force_platform", + jni_libs: ["libjni"], + sdk_version: "current", + jni_uses_platform_apis: true, + } + + android_test { + name: "app_force_sdk", + jni_libs: ["libjni"], + platform_apis: true, + jni_uses_sdk_apis: true, + } + `) + + testCases := []struct { + name string + sdkJNI bool + }{ + {"app_platform", false}, + {"app_sdk", true}, + {"app_force_platform", false}, + {"app_force_sdk", true}, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + app := ctx.ModuleForTests(test.name, "android_common") + platformJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_shared"). + Output("libjni.so").Output.String() + sdkJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared"). + Output("libjni.so").Output.String() + + jniLibZip := app.MaybeOutput("jnilibs.zip") + if len(jniLibZip.Implicits) != 1 { + t.Fatalf("expected exactly one jni library, got %q", jniLibZip.Implicits.Strings()) + } + gotJNI := jniLibZip.Implicits[0].String() + + if test.sdkJNI { + if gotJNI != sdkJNI { + t.Errorf("expected SDK JNI library %q, got %q", sdkJNI, gotJNI) + } + } else { + if gotJNI != platformJNI { + t.Errorf("expected platform JNI library %q, got %q", platformJNI, gotJNI) + } + } + }) + } + + t.Run("jni_uses_platform_apis_error", func(t *testing.T) { + testJavaError(t, `jni_uses_platform_apis: can only be set for modules that set sdk_version`, ` + android_test { + name: "app_platform", + platform_apis: true, + jni_uses_platform_apis: true, + } + `) + }) + + t.Run("jni_uses_sdk_apis_error", func(t *testing.T) { + testJavaError(t, `jni_uses_sdk_apis: can only be set for modules that do not set sdk_version`, ` + android_test { + name: "app_sdk", + sdk_version: "current", + jni_uses_sdk_apis: true, + } + `) + }) + +} + func TestCertificates(t *testing.T) { testCases := []struct { name string @@ -1141,7 +1235,7 @@ func TestCertificates(t *testing.T) { android_app_certificate { name: "new_certificate", - certificate: "cert/new_cert", + certificate: "cert/new_cert", } `, certificateOverride: "", @@ -1172,7 +1266,7 @@ func TestCertificates(t *testing.T) { android_app_certificate { name: "new_certificate", - certificate: "cert/new_cert", + certificate: "cert/new_cert", } `, certificateOverride: "foo:new_certificate", -- cgit v1.2.3-59-g8ed1b From eb03296b57a414b5c327ae6b4057f279f6903439 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 13 May 2020 11:05:02 -0700 Subject: Don't use SDK variant for vendor JNI libraries Vendor JNI libraries already have stable APIs enforced by the VNDK, they shouldn't use SDK variants. Bug: 156225490 Test: TestJNISDK Change-Id: I21ba67e8e9fb05016caf5888129adc1a939545c2 Merged-In: I21ba67e8e9fb05016caf5888129adc1a939545c2 (cherry picked from commit c2d24050c5e3a09b7bc5236d15f24afa2405911f) --- android/module.go | 7 +++++++ java/app.go | 47 ++++++++++++++++++++++++++++++++--------------- java/app_test.go | 43 +++++++++++++++++++++++++++++++++---------- java/java.go | 3 +-- 4 files changed, 73 insertions(+), 27 deletions(-) (limited to 'java/app_test.go') diff --git a/android/module.go b/android/module.go index f16407272..baf348aaf 100644 --- a/android/module.go +++ b/android/module.go @@ -886,6 +886,13 @@ func (m *ModuleBase) SystemExtSpecific() bool { return Bool(m.commonProperties.System_ext_specific) } +// RequiresStableAPIs returns true if the module will be installed to a partition that may +// be updated separately from the system image. +func (m *ModuleBase) RequiresStableAPIs(ctx BaseModuleContext) bool { + return m.SocSpecific() || m.DeviceSpecific() || + (m.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) +} + func (m *ModuleBase) PartitionTag(config DeviceConfig) string { partition := "system" if m.SocSpecific() { diff --git a/java/app.go b/java/app.go index 156deb8f9..f9ce4bf0e 100755 --- a/java/app.go +++ b/java/app.go @@ -252,7 +252,10 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { // If the app builds against an Android SDK use the SDK variant of JNI dependencies // unless jni_uses_platform_apis is set. - if (usesSDK && !Bool(a.appProperties.Jni_uses_platform_apis)) || + // Don't require the SDK variant for apps that are shipped on vendor, etc., as they already + // have stable APIs through the VNDK. + if (usesSDK && !a.RequiresStableAPIs(ctx) && + !Bool(a.appProperties.Jni_uses_platform_apis)) || Bool(a.appProperties.Jni_uses_sdk_apis) { variation = append(variation, blueprint.Variation{Mutator: "sdk", Variation: "sdk"}) } @@ -583,7 +586,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { dexJarFile := a.dexBuildActions(ctx) - jniLibs, certificateDeps := collectAppDeps(ctx, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis)) + jniLibs, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis)) jniJarFile := a.jniBuildActions(jniLibs, ctx) if ctx.Failed() { @@ -639,12 +642,25 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.buildAppDependencyInfo(ctx) } -func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps bool, +type appDepsInterface interface { + sdkVersion() sdkSpec + minSdkVersion() sdkSpec + RequiresStableAPIs(ctx android.BaseModuleContext) bool +} + +func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, + shouldCollectRecursiveNativeDeps bool, checkNativeSdkVersion bool) ([]jniLib, []Certificate) { + var jniLibs []jniLib var certificates []Certificate seenModulePaths := make(map[string]bool) + if checkNativeSdkVersion { + checkNativeSdkVersion = app.sdkVersion().specified() && + app.sdkVersion().kind != sdkCorePlatform && !app.RequiresStableAPIs(ctx) + } + ctx.WalkDeps(func(module android.Module, parent android.Module) bool { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -662,16 +678,9 @@ func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps } seenModulePaths[path.String()] = true - if checkNativeSdkVersion { - if app, ok := ctx.Module().(interface{ sdkVersion() sdkSpec }); ok { - if app.sdkVersion().specified() && - app.sdkVersion().kind != sdkCorePlatform && - dep.SdkVersion() == "" { - ctx.PropertyErrorf("jni_libs", - "JNI dependency %q uses platform APIs, but this module does not", - otherName) - } - } + if checkNativeSdkVersion && dep.SdkVersion() == "" { + ctx.PropertyErrorf("jni_libs", "JNI dependency %q uses platform APIs, but this module does not", + otherName) } if lib.Valid() { @@ -1257,7 +1266,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set") } - _, certificates := collectAppDeps(ctx, false, false) + _, certificates := collectAppDeps(ctx, a, false, false) // TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK // TODO: LOCAL_PACKAGE_SPLITS @@ -1374,6 +1383,14 @@ func (a *AndroidAppImport) Privileged() bool { return Bool(a.properties.Privileged) } +func (a *AndroidAppImport) sdkVersion() sdkSpec { + return sdkSpecFrom("") +} + +func (a *AndroidAppImport) minSdkVersion() sdkSpec { + return sdkSpecFrom("") +} + func createVariantGroupType(variants []string, variantGroupName string) reflect.Type { props := reflect.TypeOf((*AndroidAppImportProperties)(nil)) @@ -1548,7 +1565,7 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC r.aapt.buildActions(ctx, r, aaptLinkFlags...) // Sign the built package - _, certificates := collectAppDeps(ctx, false, false) + _, certificates := collectAppDeps(ctx, r, false, false) certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx) signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk") SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, nil) diff --git a/java/app_test.go b/java/app_test.go index be9815099..7d47a5c2f 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -1144,25 +1144,44 @@ func TestJNISDK(t *testing.T) { platform_apis: true, jni_uses_sdk_apis: true, } + + cc_library { + name: "libvendorjni", + system_shared_libs: [], + stl: "none", + vendor: true, + } + + android_test { + name: "app_vendor", + jni_libs: ["libvendorjni"], + sdk_version: "current", + vendor: true, + } `) testCases := []struct { - name string - sdkJNI bool + name string + sdkJNI bool + vendorJNI bool }{ - {"app_platform", false}, - {"app_sdk", true}, - {"app_force_platform", false}, - {"app_force_sdk", true}, + {name: "app_platform"}, + {name: "app_sdk", sdkJNI: true}, + {name: "app_force_platform"}, + {name: "app_force_sdk", sdkJNI: true}, + {name: "app_vendor", vendorJNI: true}, } + platformJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_shared"). + Output("libjni.so").Output.String() + sdkJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared"). + Output("libjni.so").Output.String() + vendorJNI := ctx.ModuleForTests("libvendorjni", "android_arm64_armv8-a_shared"). + Output("libvendorjni.so").Output.String() + for _, test := range testCases { t.Run(test.name, func(t *testing.T) { app := ctx.ModuleForTests(test.name, "android_common") - platformJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_shared"). - Output("libjni.so").Output.String() - sdkJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared"). - Output("libjni.so").Output.String() jniLibZip := app.MaybeOutput("jnilibs.zip") if len(jniLibZip.Implicits) != 1 { @@ -1174,6 +1193,10 @@ func TestJNISDK(t *testing.T) { if gotJNI != sdkJNI { t.Errorf("expected SDK JNI library %q, got %q", sdkJNI, gotJNI) } + } else if test.vendorJNI { + if gotJNI != vendorJNI { + t.Errorf("expected platform JNI library %q, got %q", vendorJNI, gotJNI) + } } else { if gotJNI != platformJNI { t.Errorf("expected platform JNI library %q, got %q", platformJNI, gotJNI) diff --git a/java/java.go b/java/java.go index 38cde2afe..066e09afb 100644 --- a/java/java.go +++ b/java/java.go @@ -95,8 +95,7 @@ func (j *Module) CheckStableSdkVersion() error { } func (j *Module) checkSdkVersions(ctx android.ModuleContext) { - if j.SocSpecific() || j.DeviceSpecific() || - (j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) { + if j.RequiresStableAPIs(ctx) { if sc, ok := ctx.Module().(sdkContext); ok { if !sc.sdkVersion().specified() { ctx.PropertyErrorf("sdk_version", -- cgit v1.2.3-59-g8ed1b From 4de27a57577e6cf1a0924fdc33b319fc49c9b36c Mon Sep 17 00:00:00 2001 From: Sasha Smundak Date: Thu, 23 Apr 2020 09:49:59 -0700 Subject: Implement android_app_set module Bug: 152319766 Test: manual and builtin Change-Id: Id0877476f9ae23311d92c0b59a9c568140ab4119 Merged-In: Id0877476f9ae23311d92c0b59a9c568140ab4119 --- java/androidmk.go | 17 +++++++ java/app.go | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++ java/app_test.go | 88 ++++++++++++++++++++++++++++++++++++ java/builder.go | 12 +++++ java/config/config.go | 2 +- java/testing.go | 2 + 6 files changed, 242 insertions(+), 1 deletion(-) (limited to 'java/app_test.go') diff --git a/java/androidmk.go b/java/androidmk.go index 6f24f34de..41a3dc7e9 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -676,3 +676,20 @@ func (r *RuntimeResourceOverlay) AndroidMkEntries() []android.AndroidMkEntries { }, }} } + +func (apkSet *AndroidAppSet) AndroidMkEntries() []android.AndroidMkEntries { + return []android.AndroidMkEntries{ + android.AndroidMkEntries{ + Class: "APPS", + OutputFile: android.OptionalPathForPath(apkSet.packedOutput), + Include: "$(BUILD_SYSTEM)/soong_android_app_set.mk", + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { + entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", apkSet.Privileged()) + entries.SetString("LOCAL_APK_SET_MASTER_FILE", apkSet.masterFile) + entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...) + }, + }, + }, + } +} diff --git a/java/app.go b/java/app.go index 156deb8f9..89f48c36e 100755 --- a/java/app.go +++ b/java/app.go @@ -20,6 +20,7 @@ import ( "path/filepath" "reflect" "sort" + "strconv" "strings" "github.com/google/blueprint" @@ -49,6 +50,127 @@ func RegisterAppBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("android_app_import", AndroidAppImportFactory) ctx.RegisterModuleType("android_test_import", AndroidTestImportFactory) ctx.RegisterModuleType("runtime_resource_overlay", RuntimeResourceOverlayFactory) + ctx.RegisterModuleType("android_app_set", AndroidApkSetFactory) +} + +type AndroidAppSetProperties struct { + // APK Set path + Set *string + + // Specifies that this app should be installed to the priv-app directory, + // where the system will grant it additional privileges not available to + // normal apps. + Privileged *bool + + // APKs in this set use prerelease SDK version + Prerelease *bool + + // Names of modules to be overridden. Listed modules can only be other apps + // (in Make or Soong). + Overrides []string +} + +type AndroidAppSet struct { + android.ModuleBase + android.DefaultableModuleBase + prebuilt android.Prebuilt + + properties AndroidAppSetProperties + packedOutput android.WritablePath + masterFile string +} + +func (as *AndroidAppSet) Name() string { + return as.prebuilt.Name(as.ModuleBase.Name()) +} + +func (as *AndroidAppSet) IsInstallable() bool { + return true +} + +func (as *AndroidAppSet) Prebuilt() *android.Prebuilt { + return &as.prebuilt +} + +func (as *AndroidAppSet) Privileged() bool { + return Bool(as.properties.Privileged) +} + +var targetCpuAbi = map[string]string{ + "arm": "ARMEABI_V7A", + "arm64": "ARM64_V8A", + "x86": "X86", + "x86_64": "X86_64", +} + +func supportedAbis(ctx android.ModuleContext) []string { + abiName := func(archVar string, deviceArch string) string { + if abi, found := targetCpuAbi[deviceArch]; found { + return abi + } + ctx.ModuleErrorf("Invalid %s: %s", archVar, deviceArch) + return "BAD_ABI" + } + + result := []string{abiName("TARGET_ARCH", ctx.DeviceConfig().DeviceArch())} + if s := ctx.DeviceConfig().DeviceSecondaryArch(); s != "" { + result = append(result, abiName("TARGET_2ND_ARCH", s)) + } + return result +} + +func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { + as.packedOutput = android.PathForModuleOut(ctx, "extracted.zip") + // We are assuming here that the master file in the APK + // set has `.apk` suffix. If it doesn't the build will fail. + // APK sets containing APEX files are handled elsewhere. + as.masterFile = ctx.ModuleName() + ".apk" + screenDensities := "all" + if dpis := ctx.Config().ProductAAPTPrebuiltDPI(); len(dpis) > 0 { + screenDensities = strings.ToUpper(strings.Join(dpis, ",")) + } + // TODO(asmundak): handle locales. + // TODO(asmundak): do we support device features + ctx.Build(pctx, + android.BuildParams{ + Rule: extractMatchingApks, + Description: "Extract APKs from APK set", + Output: as.packedOutput, + Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)}, + Args: map[string]string{ + "abis": strings.Join(supportedAbis(ctx), ","), + "allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)), + "screen-densities": screenDensities, + "sdk-version": ctx.Config().PlatformSdkVersion(), + "stem": ctx.ModuleName(), + }, + }) + // TODO(asmundak): add this (it's wrong now, will cause copying extracted.zip) + /* + var installDir android.InstallPath + if Bool(as.properties.Privileged) { + installDir = android.PathForModuleInstall(ctx, "priv-app", as.BaseModuleName()) + } else if ctx.InstallInTestcases() { + installDir = android.PathForModuleInstall(ctx, as.BaseModuleName(), ctx.DeviceConfig().DeviceArch()) + } else { + installDir = android.PathForModuleInstall(ctx, "app", as.BaseModuleName()) + } + ctx.InstallFile(installDir, as.masterFile", as.packedOutput) + */ +} + +// android_app_set extracts a set of APKs based on the target device +// configuration and installs this set as "split APKs". +// The set will always contain `base-master.apk` and every APK built +// to the target device. All density-specific APK will be included, too, +// unless PRODUCT_APPT_PREBUILT_DPI is defined (should contain comma-sepearated +// list of density names (LDPI, MDPI, HDPI, etc.) +func AndroidApkSetFactory() android.Module { + module := &AndroidAppSet{} + module.AddProperties(&module.properties) + InitJavaModule(module, android.DeviceSupported) + android.InitSingleSourcePrebuiltModule(module, &module.properties, "Set") + return module } // AndroidManifest.xml merging diff --git a/java/app_test.go b/java/app_test.go index be9815099..e9014bc54 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -141,6 +141,94 @@ func TestAppSplits(t *testing.T) { } } +func TestAndroidAppSet(t *testing.T) { + ctx, config := testJava(t, ` + android_app_set { + name: "foo", + set: "prebuilts/apks/app.apks", + prerelease: true, + }`) + module := ctx.ModuleForTests("foo", "android_common") + const packedSplitApks = "extracted.zip" + params := module.Output(packedSplitApks) + if params.Rule == nil { + t.Errorf("expected output %s is missing", packedSplitApks) + } + if s := params.Args["allow-prereleased"]; s != "true" { + t.Errorf("wrong allow-prereleased value: '%s', expected 'true'", s) + } + mkEntries := android.AndroidMkEntriesForTest(t, config, "", module.Module())[0] + actualMaster := mkEntries.EntryMap["LOCAL_APK_SET_MASTER_FILE"] + expectedMaster := []string{"foo.apk"} + if !reflect.DeepEqual(actualMaster, expectedMaster) { + t.Errorf("Unexpected LOCAL_APK_SET_MASTER_FILE value: '%s', expected: '%s',", + actualMaster, expectedMaster) + } +} + +func TestAndroidAppSet_Variants(t *testing.T) { + bp := ` + android_app_set { + name: "foo", + set: "prebuilts/apks/app.apks", + }` + testCases := []struct { + name string + deviceArch *string + deviceSecondaryArch *string + aaptPrebuiltDPI []string + sdkVersion int + expected map[string]string + }{ + { + name: "One", + deviceArch: proptools.StringPtr("x86"), + aaptPrebuiltDPI: []string{"ldpi", "xxhdpi"}, + sdkVersion: 29, + expected: map[string]string{ + "abis": "X86", + "allow-prereleased": "false", + "screen-densities": "LDPI,XXHDPI", + "sdk-version": "29", + "stem": "foo", + }, + }, + { + name: "Two", + deviceArch: proptools.StringPtr("x86_64"), + deviceSecondaryArch: proptools.StringPtr("x86"), + aaptPrebuiltDPI: nil, + sdkVersion: 30, + expected: map[string]string{ + "abis": "X86_64,X86", + "allow-prereleased": "false", + "screen-densities": "all", + "sdk-version": "30", + "stem": "foo", + }, + }, + } + + for _, test := range testCases { + config := testAppConfig(nil, bp, nil) + config.TestProductVariables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI + config.TestProductVariables.Platform_sdk_version = &test.sdkVersion + config.TestProductVariables.DeviceArch = test.deviceArch + config.TestProductVariables.DeviceSecondaryArch = test.deviceSecondaryArch + ctx := testContext() + run(t, ctx, config) + module := ctx.ModuleForTests("foo", "android_common") + const packedSplitApks = "extracted.zip" + params := module.Output(packedSplitApks) + for k, v := range test.expected { + if actual := params.Args[k]; actual != v { + t.Errorf("%s: bad build arg value for '%s': '%s', expected '%s'", + test.name, k, actual, v) + } + } + } +} + func TestPlatformAPIs(t *testing.T) { testJava(t, ` android_app { diff --git a/java/builder.go b/java/builder.go index ad9afee81..714d76aa5 100644 --- a/java/builder.go +++ b/java/builder.go @@ -99,6 +99,18 @@ var ( "javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir", "outDir", "annoDir", "javaVersion") + extractMatchingApks = pctx.StaticRule( + "extractMatchingApks", + blueprint.RuleParams{ + Command: `rm -rf "$out" && ` + + `${config.ExtractApksCmd} -o "${out}" -allow-prereleased=${allow-prereleased} ` + + `-sdk-version=${sdk-version} -abis=${abis} ` + + `--screen-densities=${screen-densities} --stem=${stem} ` + + `${in}`, + CommandDeps: []string{"${config.ExtractApksCmd}"}, + }, + "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem") + turbine = pctx.AndroidStaticRule("turbine", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + diff --git a/java/config/config.go b/java/config/config.go index 487dc0496..9ac5a50cb 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -123,7 +123,7 @@ func init() { pctx.HostBinToolVariable("D8Cmd", "d8") pctx.HostBinToolVariable("R8Cmd", "r8-compat-proguard") pctx.HostBinToolVariable("HiddenAPICmd", "hiddenapi") - + pctx.HostBinToolVariable("ExtractApksCmd", "extract_apks") pctx.VariableFunc("TurbineJar", func(ctx android.PackageVarContext) string { turbine := "turbine.jar" if ctx.Config().UnbundledBuild() { diff --git a/java/testing.go b/java/testing.go index dd3565313..e2d183eee 100644 --- a/java/testing.go +++ b/java/testing.go @@ -90,6 +90,8 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string "prebuilts/apk/app_xhdpi.apk": nil, "prebuilts/apk/app_xxhdpi.apk": nil, + "prebuilts/apks/app.apks": nil, + // For framework-res, which is an implicit dependency for framework "AndroidManifest.xml": nil, "build/make/target/product/security/testkey": nil, -- cgit v1.2.3-59-g8ed1b From 2bc57f6afe31061ea16ec9d3982d3514172abc69 Mon Sep 17 00:00:00 2001 From: Liz Kammer Date: Wed, 13 May 2020 15:49:21 -0700 Subject: Add signing linage support for android_app_import Test: app_test Bug: 153366049 Change-Id: I260f198637a1a0f8b3373250413356785c56588a --- java/app.go | 9 ++++++++- java/app_test.go | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) (limited to 'java/app_test.go') diff --git a/java/app.go b/java/app.go index 756203c56..86cf7471d 100755 --- a/java/app.go +++ b/java/app.go @@ -1245,6 +1245,9 @@ type AndroidAppImportProperties struct { // be set for presigned modules. Presigned *bool + // Name of the signing certificate lineage file. + Lineage *string + // Sign with the default system dev certificate. Must be used judiciously. Most imported apps // need to either specify a specific certificate or be presigned. Default_dev_cert *bool @@ -1443,7 +1446,11 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext } a.certificate = certificates[0] signed := android.PathForModuleOut(ctx, "signed", apkFilename) - SignAppPackage(ctx, signed, dexOutput, certificates, nil, nil) + var lineageFile android.Path + if lineage := String(a.properties.Lineage); lineage != "" { + lineageFile = android.PathForModuleSrc(ctx, lineage) + } + SignAppPackage(ctx, signed, dexOutput, certificates, nil, lineageFile) a.outputFile = signed } else { alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename) diff --git a/java/app_test.go b/java/app_test.go index 80f45677a..c731a1713 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2010,6 +2010,27 @@ func TestAndroidAppImport_Presigned(t *testing.T) { } } +func TestAndroidAppImport_SigningLineage(t *testing.T) { + ctx, _ := testJava(t, ` + android_app_import { + name: "foo", + apk: "prebuilts/apk/app.apk", + certificate: "platform", + lineage: "lineage.bin", + } + `) + + variant := ctx.ModuleForTests("foo", "android_common") + + // Check cert signing lineage flag. + signedApk := variant.Output("signed/foo.apk") + signingFlag := signedApk.Args["flags"] + expected := "--lineage lineage.bin" + if expected != signingFlag { + t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) + } +} + func TestAndroidAppImport_DefaultDevCert(t *testing.T) { ctx, _ := testJava(t, ` android_app_import { -- cgit v1.2.3-59-g8ed1b From 7fe241f62312b180a2e93607b672d1d1217181ba Mon Sep 17 00:00:00 2001 From: Liz Kammer Date: Tue, 19 May 2020 16:15:25 -0700 Subject: Add signing lineage for runtime_resource_overlay Add ability to specify a signing lineage file for runtime_resource_overlay. Test: app_test.go Bug: 153366049 Change-Id: I68286bc0caa9daad6ef74db39f7750924f1d93dd --- java/app.go | 9 ++++++++- java/app_test.go | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'java/app_test.go') diff --git a/java/app.go b/java/app.go index 86cf7471d..dddaa1a07 100755 --- a/java/app.go +++ b/java/app.go @@ -1632,6 +1632,9 @@ type RuntimeResourceOverlayProperties struct { // module name in the form ":module". Certificate *string + // Name of the signing certificate lineage file. + Lineage *string + // optional theme name. If specified, the overlay package will be applied // only when the ro.boot.vendor.overlay.theme system property is set to the same value. Theme *string @@ -1697,7 +1700,11 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC _, certificates := collectAppDeps(ctx, r, false, false) certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx) signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk") - SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, nil) + var lineageFile android.Path + if lineage := String(r.properties.Lineage); lineage != "" { + lineageFile = android.PathForModuleSrc(ctx, lineage) + } + SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile) r.certificate = certificates[0] r.outputFile = signed diff --git a/java/app_test.go b/java/app_test.go index c731a1713..a4ddb9592 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2745,6 +2745,7 @@ func TestRuntimeResourceOverlay(t *testing.T) { runtime_resource_overlay { name: "foo", certificate: "platform", + lineage: "lineage.bin", product_specific: true, static_libs: ["bar"], resource_libs: ["baz"], @@ -2799,6 +2800,11 @@ func TestRuntimeResourceOverlay(t *testing.T) { // Check cert signing flag. signedApk := m.Output("signed/foo.apk") + lineageFlag := signedApk.Args["flags"] + expectedLineageFlag := "--lineage lineage.bin" + if expectedLineageFlag != lineageFlag { + t.Errorf("Incorrect signing lineage flags, expected: %q, got: %q", expectedLineageFlag, lineageFlag) + } signingFlag := signedApk.Args["certificates"] expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8" if expected != signingFlag { -- cgit v1.2.3-59-g8ed1b From 442a47552193e2893dbbc1b67a9a1bbd08903314 Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Fri, 15 May 2020 10:20:31 +0100 Subject: Improve tracking of exported sdk libraries The build tracks the java_sdk_library/_import modules that are referenced by libraries so that it can ensure that any Android app that includes code that depends on one of those modules has the appropriate entry in their manifest. Unfortunately, there were a couple of issues with that: 1) It only tracks direct references to the java_sdk_library module itself, e.g. android.test.mock. Direct references to the stubs module, e.g. android.test.mock.stubs were not tracked. Making it possible for Android apps to reference libraries which would not be available at runtime. 2) The logic for determining whether something was a java_sdk_library was repeated in a number of places making it difficult to allow java_sdk_library/_import instances to determine whether they should be treated as an Android shared library. 3) It tracks (and could use) even those java_sdk_library instances which do not represent a shared library, e.g. the ones that set api_only: true. While this change will simplifty fixing that the actual issue will be fixed in a follow up change. Changes: * Added EmbeddableSdkLibraryComponent and embedded it into java_sdk_library/_import, java_library and java_import. It provides the common code to minimize duplication. It contains an SdkLibraryToImplicitlyTrack field that if set will cause any references to the containing module to add the SdkLibraryParent to the list of implicit sdk libraries being tracked. * Changed code that assumed that anything that implemented SdkLibraryDependency required tracking to use the OptionalImplicitSdkLibrary() method to get the optional name of the sdk library to track. That will allow a follow up change to return nil from that method to exclude an sdk library from being tracked. * Moved SdkLibraryDependency from java.go to sdk_library.go as that is a better place for it to be. * Changed the stubs java_library/java_import creation code to initialize the SdkLibraryToImplicitlyTrack field with the name of the creating module. * Initialized the SdkLibraryToImplicitlyTrack field in the java_sdk_library/_import so that direct references to them will be tracked too. * Added tests to verify that direct access to the .stubs child of both java_sdk_library and java_sdk_library_import are tracked properly. Test: atest CtsProviderTestCases - which relies on android.test.mock being implicitly tracked to verify that I had not broken anything. Used aapt2 dump badging to read the manifest. m nothing - to run the new tests which failed before fixing the code. Bug: 156723295 Merged-In: Ia99def91e9b74d2ed0a777de04b476c00ea0393d Change-Id: Ia99def91e9b74d2ed0a777de04b476c00ea0393d (cherry picked from commit 859fe961b015259368e9994969b569eb34f54ddc) --- java/aar.go | 7 ++-- java/app_test.go | 24 ++++++++++++++ java/java.go | 33 +++++++++++++++---- java/java_test.go | 22 ++++++++++--- java/sdk_library.go | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 166 insertions(+), 14 deletions(-) (limited to 'java/app_test.go') diff --git a/java/aar.go b/java/aar.go index 0e103f248..c8daf835b 100644 --- a/java/aar.go +++ b/java/aar.go @@ -379,8 +379,11 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati sharedLibs = append(sharedLibs, exportPackage) } - if _, ok := module.(SdkLibraryDependency); ok { - sdkLibraries = append(sdkLibraries, ctx.OtherModuleName(module)) + // If the module is (or possibly could be) a component of a java_sdk_library + // (including the java_sdk_library) itself then append any implicit sdk library + // names to the list of sdk libraries to be added to the manifest. + if component, ok := module.(SdkLibraryComponentDependency); ok { + sdkLibraries = append(sdkLibraries, component.OptionalImplicitSdkLibrary()...) } case frameworkResTag: diff --git a/java/app_test.go b/java/app_test.go index c731a1713..12b935ed3 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2382,6 +2382,20 @@ func TestUsesLibraries(t *testing.T) { sdk_version: "current", } + java_sdk_library { + name: "qux", + srcs: ["a.java"], + api_packages: ["qux"], + sdk_version: "current", + } + + java_sdk_library { + name: "quuz", + srcs: ["a.java"], + api_packages: ["quuz"], + sdk_version: "current", + } + java_sdk_library { name: "bar", srcs: ["a.java"], @@ -2392,6 +2406,7 @@ func TestUsesLibraries(t *testing.T) { android_app { name: "app", srcs: ["a.java"], + libs: ["qux", "quuz.stubs"], uses_libs: ["foo"], sdk_version: "current", optional_uses_libs: [ @@ -2422,6 +2437,15 @@ func TestUsesLibraries(t *testing.T) { app := ctx.ModuleForTests("app", "android_common") prebuilt := ctx.ModuleForTests("prebuilt", "android_common") + // Test that implicit dependencies on java_sdk_library instances are passed to the manifest. + manifestFixerArgs := app.Output("manifest_fixer/AndroidManifest.xml").Args["args"] + if w := "--uses-library qux"; !strings.Contains(manifestFixerArgs, w) { + t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs) + } + if w := "--uses-library quuz"; !strings.Contains(manifestFixerArgs, w) { + t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs) + } + // Test that all libraries are verified cmd := app.Rule("verify_uses_libraries").RuleParams.Command if w := "--uses-library foo"; !strings.Contains(cmd, w) { diff --git a/java/java.go b/java/java.go index da9bd3dfe..00b11f77a 100644 --- a/java/java.go +++ b/java/java.go @@ -355,7 +355,17 @@ func (me *CompilerDeviceProperties) EffectiveOptimizeEnabled() bool { } // Functionality common to Module and Import +// +// It is embedded in Module so its functionality can be used by methods in Module +// but it is currently only initialized by Import and Library. type embeddableInModuleAndImport struct { + + // Functionality related to this being used as a component of a java_sdk_library. + EmbeddableSdkLibraryComponent +} + +func (e *embeddableInModuleAndImport) initModuleAndImport(moduleBase *android.ModuleBase) { + e.initSdkLibraryComponent(moduleBase) } // Module/Import's DepIsInSameApex(...) delegates to this method. @@ -496,11 +506,6 @@ type Dependency interface { JacocoReportClassesFile() android.Path } -type SdkLibraryDependency interface { - SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths - SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths -} - type xref interface { XrefJavaFiles() android.Paths } @@ -930,6 +935,12 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } } + // If this is a component library (stubs, etc.) for a java_sdk_library then + // add the name of that java_sdk_library to the exported sdk libs to make sure + // that, if necessary, a element for that java_sdk_library is + // added to the Android manifest. + j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...) + ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -949,7 +960,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case libTag: deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) // names of sdk libs that are directly depended are exported - j.exportedSdkLibs = append(j.exportedSdkLibs, otherName) + j.exportedSdkLibs = append(j.exportedSdkLibs, dep.OptionalImplicitSdkLibrary()...) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } @@ -1990,6 +2001,8 @@ func LibraryFactory() android.Module { &module.Module.protoProperties, &module.libraryProperties) + module.initModuleAndImport(&module.ModuleBase) + android.InitApexModule(module) android.InitSdkAwareModule(module) InitJavaModule(module, android.HostAndDeviceSupported) @@ -2451,6 +2464,12 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } j.combinedClasspathFile = outputFile + // If this is a component library (impl, stubs, etc.) for a java_sdk_library then + // add the name of that java_sdk_library to the exported sdk libs to make sure + // that, if necessary, a element for that java_sdk_library is + // added to the Android manifest. + j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...) + ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -2567,6 +2586,8 @@ func ImportFactory() android.Module { module.AddProperties(&module.properties) + module.initModuleAndImport(&module.ModuleBase) + android.InitPrebuiltModule(module, &module.properties.Jars) android.InitApexModule(module) android.InitSdkAwareModule(module) diff --git a/java/java_test.go b/java/java_test.go index 4f3a803ff..4c085cf0f 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -19,6 +19,7 @@ import ( "os" "path/filepath" "reflect" + "sort" "strconv" "strings" "testing" @@ -1153,13 +1154,25 @@ func TestJavaSdkLibrary(t *testing.T) { java_library { name: "baz", srcs: ["c.java"], - libs: ["foo", "bar"], + libs: ["foo", "bar.stubs"], sdk_version: "system_current", } + java_sdk_library_import { + name: "quuz", + public: { + jars: ["c.jar"], + }, + } + java_sdk_library_import { + name: "fred", + public: { + jars: ["b.jar"], + }, + } java_library { name: "qux", srcs: ["c.java"], - libs: ["baz"], + libs: ["baz", "fred", "quuz.stubs"], sdk_version: "system_current", } java_library { @@ -1224,8 +1237,9 @@ func TestJavaSdkLibrary(t *testing.T) { qux := ctx.ModuleForTests("qux", "android_common") if quxLib, ok := qux.Module().(*Library); ok { sdkLibs := quxLib.ExportedSdkLibs() - if len(sdkLibs) != 2 || !android.InList("foo", sdkLibs) || !android.InList("bar", sdkLibs) { - t.Errorf("qux should export \"foo\" and \"bar\" but exports %v", sdkLibs) + sort.Strings(sdkLibs) + if w := []string{"bar", "foo", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) { + t.Errorf("qux should export %q but exports %q", w, sdkLibs) } } } diff --git a/java/sdk_library.go b/java/sdk_library.go index 5efb4d045..0334f80d3 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -543,12 +543,18 @@ type commonToSdkLibraryAndImport struct { namingScheme sdkLibraryComponentNamingScheme commonProperties commonToSdkLibraryAndImportProperties + + // Functionality related to this being used as a component of a java_sdk_library. + EmbeddableSdkLibraryComponent } func (c *commonToSdkLibraryAndImport) initCommon(moduleBase *android.ModuleBase) { c.moduleBase = moduleBase moduleBase.AddProperties(&c.commonProperties) + + // Initialize this as an sdk library component. + c.initSdkLibraryComponent(moduleBase) } func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android.DefaultableHookContext) bool { @@ -563,6 +569,9 @@ func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android return false } + // Use the name specified in the module definition as the owner. + c.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack = proptools.StringPtr(c.moduleBase.BaseModuleName()) + return true } @@ -728,6 +737,84 @@ func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android. return paths.stubsHeaderPath } +func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} { + componentProps := &struct { + SdkLibraryToImplicitlyTrack *string + }{ + // Mark the stubs library as being components of this java_sdk_library so that + // any app that includes code which depends (directly or indirectly) on the stubs + // library will have the appropriate invocation inserted into its + // manifest if necessary. + SdkLibraryToImplicitlyTrack: proptools.StringPtr(c.moduleBase.BaseModuleName()), + } + + return componentProps +} + +// Properties related to the use of a module as an component of a java_sdk_library. +type SdkLibraryComponentProperties struct { + + // The name of the java_sdk_library/_import to add to a entry + // in the AndroidManifest.xml of any Android app that includes code that references + // this module. If not set then no java_sdk_library/_import is tracked. + SdkLibraryToImplicitlyTrack *string `blueprint:"mutated"` +} + +// Structure to be embedded in a module struct that needs to support the +// SdkLibraryComponentDependency interface. +type EmbeddableSdkLibraryComponent struct { + sdkLibraryComponentProperties SdkLibraryComponentProperties +} + +func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(moduleBase *android.ModuleBase) { + moduleBase.AddProperties(&e.sdkLibraryComponentProperties) +} + +// to satisfy SdkLibraryComponentDependency +func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() []string { + if e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack != nil { + return []string{*e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack} + } + return nil +} + +// Implemented by modules that are (or possibly could be) a component of a java_sdk_library +// (including the java_sdk_library) itself. +type SdkLibraryComponentDependency interface { + // The optional name of the sdk library that should be implicitly added to the + // AndroidManifest of an app that contains code which references the sdk library. + // + // Returns an array containing 0 or 1 items rather than a *string to make it easier + // to append this to the list of exported sdk libraries. + OptionalImplicitSdkLibrary() []string +} + +// Make sure that all the module types that are components of java_sdk_library/_import +// and which can be referenced (directly or indirectly) from an android app implement +// the SdkLibraryComponentDependency interface. +var _ SdkLibraryComponentDependency = (*Library)(nil) +var _ SdkLibraryComponentDependency = (*Import)(nil) +var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil) +var _ SdkLibraryComponentDependency = (*sdkLibraryImport)(nil) + +// Provides access to sdk_version related header and implentation jars. +type SdkLibraryDependency interface { + SdkLibraryComponentDependency + + // Get the header jars appropriate for the supplied sdk_version. + // + // These are turbine generated jars so they only change if the externals of the + // class changes but it does not contain and implementation or JavaDoc. + SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths + + // Get the implementation jars appropriate for the supplied sdk version. + // + // These are either the implementation jar for the whole sdk library or the implementation + // jars for the stubs. The latter should only be needed when generating JavaDoc as otherwise + // they are identical to the corresponding header jars. + SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths +} + type SdkLibrary struct { Library @@ -978,7 +1065,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext props.Dist.Tag = proptools.StringPtr(".jar") } - mctx.CreateModule(LibraryFactory, &props) + mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) } // Creates a droidstubs module that creates stubs source files from the given full source @@ -1321,6 +1408,8 @@ func (module *SdkLibrary) InitSdkLibraryProperties() { &module.protoProperties, ) + module.initSdkLibraryComponent(&module.ModuleBase) + module.properties.Installable = proptools.BoolPtr(true) module.deviceProperties.IsSDKLibrary = true } @@ -1569,7 +1658,8 @@ func (module *sdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl // The imports are preferred if the java_sdk_library_import is preferred. props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer()) - mctx.CreateModule(ImportFactory, &props) + + mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary()) } func (module *sdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { -- cgit v1.2.3-59-g8ed1b From 98c71228f1f81cba80f17a73df6e7ace57e83a30 Mon Sep 17 00:00:00 2001 From: David Srbecky Date: Wed, 20 May 2020 22:20:28 +0100 Subject: Allow the user to explicitly set the java Uncompress_dex property. ART tests need to explicitly control the compression. Bug: 157239179 Test: "atest ArtGtestsTarget" with http://go/aog/1302773 Change-Id: I4490aa0a61fa71f830feb6a46dffd8d20fccfc66 --- android/neverallow.go | 10 ++++++++++ android/neverallow_test.go | 28 ++++++++++++++++++++++++++-- java/app.go | 9 +++++---- java/app_test.go | 26 ++++++++++++++++++++++++++ java/dex.go | 5 +++-- java/java.go | 20 ++++++++++++++------ 6 files changed, 84 insertions(+), 14 deletions(-) (limited to 'java/app_test.go') diff --git a/android/neverallow.go b/android/neverallow.go index f9fc03caa..9e075b719 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -55,6 +55,7 @@ func init() { AddNeverAllowRules(createMediaRules()...) AddNeverAllowRules(createJavaDeviceForHostRules()...) AddNeverAllowRules(createCcSdkVariantRules()...) + AddNeverAllowRules(createUncompressDexRules()...) } // Add a NeverAllow rule to the set of rules to apply. @@ -210,6 +211,15 @@ func createCcSdkVariantRules() []Rule { } } +func createUncompressDexRules() []Rule { + return []Rule{ + NeverAllow(). + NotIn("art"). + WithMatcher("uncompress_dex", isSetMatcherInstance). + Because("uncompress_dex is only allowed for certain jars for test in art."), + } +} + func neverallowMutator(ctx BottomUpMutatorContext) { m, ok := ctx.Module().(Module) if !ok { diff --git a/android/neverallow_test.go b/android/neverallow_test.go index 2fc42e31f..85c8c5908 100644 --- a/android/neverallow_test.go +++ b/android/neverallow_test.go @@ -303,6 +303,29 @@ var neverallowTests = []struct { `module "outside_whitelist": violates neverallow`, }, }, + { + name: "uncompress_dex inside art", + fs: map[string][]byte{ + "art/Android.bp": []byte(` + java_library { + name: "inside_art_libraries", + uncompress_dex: true, + }`), + }, + }, + { + name: "uncompress_dex outside art", + fs: map[string][]byte{ + "other/Android.bp": []byte(` + java_library { + name: "outside_art_libraries", + uncompress_dex: true, + }`), + }, + expectedErrors: []string{ + "module \"outside_art_libraries\": violates neverallow", + }, + }, } func TestNeverallow(t *testing.T) { @@ -396,8 +419,9 @@ func (p *mockCcLibraryModule) GenerateAndroidBuildActions(ModuleContext) { } type mockJavaLibraryProperties struct { - Libs []string - Sdk_version *string + Libs []string + Sdk_version *string + Uncompress_dex *bool } type mockJavaLibraryModule struct { diff --git a/java/app.go b/java/app.go index 86cf7471d..5c694b984 100755 --- a/java/app.go +++ b/java/app.go @@ -540,16 +540,17 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { installDir = filepath.Join("app", a.installApkName) } a.dexpreopter.installPath = android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk") - a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx) - + if a.deviceProperties.Uncompress_dex == nil { + // If the value was not force-set by the user, use reasonable default based on the module. + a.deviceProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx)) + } + a.dexpreopter.uncompressedDex = *a.deviceProperties.Uncompress_dex a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries() a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx) a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx) a.dexpreopter.manifestFile = a.mergedManifestFile - a.deviceProperties.UncompressDex = a.dexpreopter.uncompressedDex - if ctx.ModuleName() != "framework-res" { a.Module.compile(ctx, a.aaptSrcJar) } diff --git a/java/app_test.go b/java/app_test.go index c731a1713..ec9d51b4a 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2682,6 +2682,32 @@ func TestUncompressDex(t *testing.T) { uncompressedPlatform: true, uncompressedUnbundled: true, }, + { + name: "normal_uncompress_dex_true", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + uncompress_dex: true, + } + `, + uncompressedPlatform: true, + uncompressedUnbundled: true, + }, + { + name: "normal_uncompress_dex_false", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + uncompress_dex: false, + } + `, + uncompressedPlatform: false, + uncompressedUnbundled: false, + }, } test := func(t *testing.T, bp string, want bool, unbundled bool) { diff --git a/java/dex.go b/java/dex.go index 6afdb6dc4..62f17c6d8 100644 --- a/java/dex.go +++ b/java/dex.go @@ -18,6 +18,7 @@ import ( "strings" "github.com/google/blueprint" + "github.com/google/blueprint/proptools" "android/soong/android" ) @@ -177,7 +178,7 @@ func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, outDir := android.PathForModuleOut(ctx, "dex") zipFlags := "--ignore_missing_files" - if j.deviceProperties.UncompressDex { + if proptools.Bool(j.deviceProperties.Uncompress_dex) { zipFlags += " -L 0" } @@ -214,7 +215,7 @@ func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, }, }) } - if j.deviceProperties.UncompressDex { + if proptools.Bool(j.deviceProperties.Uncompress_dex) { alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", jarName) TransformZipAlign(ctx, alignedJavalibJar, javalibJar) javalibJar = alignedJavalibJar diff --git a/java/java.go b/java/java.go index da9bd3dfe..26b785c9e 100644 --- a/java/java.go +++ b/java/java.go @@ -342,8 +342,13 @@ type CompilerDeviceProperties struct { // set the name of the output Stem *string - UncompressDex bool `blueprint:"mutated"` - IsSDKLibrary bool `blueprint:"mutated"` + // Keep the data uncompressed. We always need uncompressed dex for execution, + // so this might actually save space by avoiding storing the same data twice. + // This defaults to reasonable value based on module and should not be set. + // It exists only to support ART tests. + Uncompress_dex *bool + + IsSDKLibrary bool `blueprint:"mutated"` // If true, generate the signature file of APK Signing Scheme V4, along side the signed APK file. // Defaults to false. @@ -1560,7 +1565,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // Hidden API CSV generation and dex encoding dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, dexOutputFile, j.implementationJarFile, - j.deviceProperties.UncompressDex) + proptools.Bool(j.deviceProperties.Uncompress_dex)) // merge dex jar with resources if necessary if j.resourceJar != nil { @@ -1568,7 +1573,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { combinedJar := android.PathForModuleOut(ctx, "dex-withres", jarName) TransformJarsToJar(ctx, combinedJar, "for dex resources", jars, android.OptionalPath{}, false, nil, nil) - if j.deviceProperties.UncompressDex { + if *j.deviceProperties.Uncompress_dex { combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName) TransformZipAlign(ctx, combinedAlignedJar, combinedJar) dexOutputFile = combinedAlignedJar @@ -1845,8 +1850,11 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.checkSdkVersions(ctx) j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar") j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary - j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter) - j.deviceProperties.UncompressDex = j.dexpreopter.uncompressedDex + if j.deviceProperties.Uncompress_dex == nil { + // If the value was not force-set by the user, use reasonable default based on the module. + j.deviceProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter)) + } + j.dexpreopter.uncompressedDex = *j.deviceProperties.Uncompress_dex j.compile(ctx, nil) exclusivelyForApex := android.InAnyApex(ctx.ModuleName()) && !j.IsForPlatform() -- cgit v1.2.3-59-g8ed1b From 7e20ddae4a0a08c02366f969d4dd12000e99226c Mon Sep 17 00:00:00 2001 From: Liz Kammer Date: Wed, 20 May 2020 14:36:30 -0700 Subject: Add preprocessed property for android_test_import If set to true, preprocessed indicates that the prebuilt apk is installable as is and does not need any further processing (e.g. zipaligning, signing). (This is a cherry pick.) Test: app_test.go Bug: 155412211 Merged-In: If0c27c1e340c1bdb270064f636dc6bf33a0fc949 Change-Id: If0c27c1e340c1bdb270064f636dc6bf33a0fc949 --- java/app.go | 24 ++++++++++++++++++++---- java/app_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) (limited to 'java/app_test.go') diff --git a/java/app.go b/java/app.go index 86cf7471d..5d45d3335 100755 --- a/java/app.go +++ b/java/app.go @@ -1230,6 +1230,8 @@ type AndroidAppImport struct { usesLibrary usesLibrary + preprocessed bool + installPath android.InstallPath } @@ -1322,7 +1324,7 @@ func (a *AndroidAppImport) uncompressEmbeddedJniLibs( ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) { // Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing // with them may invalidate pre-existing signature data. - if ctx.InstallInTestcases() && Bool(a.properties.Presigned) { + if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || a.preprocessed) { ctx.Build(pctx, android.BuildParams{ Rule: android.Cp, Output: outputPath, @@ -1343,7 +1345,7 @@ func (a *AndroidAppImport) uncompressEmbeddedJniLibs( // Returns whether this module should have the dex file stored uncompressed in the APK. func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool { - if ctx.Config().UnbundledBuild() { + if ctx.Config().UnbundledBuild() || a.preprocessed { return false } @@ -1435,9 +1437,13 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext apkFilename := proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk") - // Sign or align the package // TODO: Handle EXTERNAL - if !Bool(a.properties.Presigned) { + + // Sign or align the package if package has not been preprocessed + if a.preprocessed { + a.outputFile = srcApk + a.certificate = presignedCertificate + } else if !Bool(a.properties.Presigned) { // If the certificate property is empty at this point, default_dev_cert must be set to true. // Which makes processMainCert's behavior for the empty cert string WAI. certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx) @@ -1572,15 +1578,24 @@ func AndroidAppImportFactory() android.Module { return module } +type androidTestImportProperties struct { + // Whether the prebuilt apk can be installed without additional processing. Default is false. + Preprocessed *bool +} + type AndroidTestImport struct { AndroidAppImport testProperties testProperties + testImportProperties androidTestImportProperties + data android.Paths } func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { + a.preprocessed = Bool(a.testImportProperties.Preprocessed) + a.generateAndroidBuildActions(ctx) a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data) @@ -1598,6 +1613,7 @@ func AndroidTestImportFactory() android.Module { module.AddProperties(&module.dexpreoptProperties) module.AddProperties(&module.usesLibrary.usesLibraryProperties) module.AddProperties(&module.testProperties) + module.AddProperties(&module.testImportProperties) module.populateAllVariantStructs() android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.processVariants(ctx) diff --git a/java/app_test.go b/java/app_test.go index c731a1713..b10fefa1a 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2308,6 +2308,45 @@ func TestAndroidTestImport_NoJinUncompressForPresigned(t *testing.T) { if jniRule != android.Cp.String() { t.Errorf("Unexpected JNI uncompress rule: " + jniRule) } + if variant.MaybeOutput("zip-aligned/foo_presigned.apk").Rule == nil { + t.Errorf("Presigned test apk should be aligned") + } +} + +func TestAndroidTestImport_Preprocessed(t *testing.T) { + ctx, _ := testJava(t, ` + android_test_import { + name: "foo", + apk: "prebuilts/apk/app.apk", + presigned: true, + preprocessed: true, + } + + android_test_import { + name: "foo_cert", + apk: "prebuilts/apk/app.apk", + certificate: "cert/new_cert", + preprocessed: true, + } + `) + + testModules := []string{"foo", "foo_cert"} + for _, m := range testModules { + apkName := m + ".apk" + variant := ctx.ModuleForTests(m, "android_common") + jniRule := variant.Output("jnis-uncompressed/" + apkName).BuildParams.Rule.String() + if jniRule != android.Cp.String() { + t.Errorf("Unexpected JNI uncompress rule: " + jniRule) + } + + // Make sure signing and aligning were skipped. + if variant.MaybeOutput("signed/"+apkName).Rule != nil { + t.Errorf("signing rule shouldn't be included for preprocessed.") + } + if variant.MaybeOutput("zip-aligned/"+apkName).Rule != nil { + t.Errorf("aligning rule shouldn't be for preprocessed") + } + } } func TestStl(t *testing.T) { -- cgit v1.2.3-59-g8ed1b From ed0314270d226d5a8769439a607f79b8c974f793 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 25 May 2020 01:55:59 +0000 Subject: Revert "Improve tracking of exported sdk libraries" Revert submission 11569833 Reason for revert: Broke presubmit: b/157231582 Reverted Changes: Ia99def91e:Improve tracking of exported sdk libraries If91b4d106:java_sdk_library: Do not expose stubs implementati... Id6d76e56c:java_sdk_library: Access outputs using tags Change-Id: I3a07d412e795df512c430e4d2ed221f4d17e904a --- java/aar.go | 7 ++-- java/app_test.go | 24 -------------- java/java.go | 33 ++++--------------- java/java_test.go | 22 +++---------- java/sdk_library.go | 94 ++--------------------------------------------------- 5 files changed, 14 insertions(+), 166 deletions(-) (limited to 'java/app_test.go') diff --git a/java/aar.go b/java/aar.go index c8daf835b..0e103f248 100644 --- a/java/aar.go +++ b/java/aar.go @@ -379,11 +379,8 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati sharedLibs = append(sharedLibs, exportPackage) } - // If the module is (or possibly could be) a component of a java_sdk_library - // (including the java_sdk_library) itself then append any implicit sdk library - // names to the list of sdk libraries to be added to the manifest. - if component, ok := module.(SdkLibraryComponentDependency); ok { - sdkLibraries = append(sdkLibraries, component.OptionalImplicitSdkLibrary()...) + if _, ok := module.(SdkLibraryDependency); ok { + sdkLibraries = append(sdkLibraries, ctx.OtherModuleName(module)) } case frameworkResTag: diff --git a/java/app_test.go b/java/app_test.go index 12b935ed3..c731a1713 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2382,20 +2382,6 @@ func TestUsesLibraries(t *testing.T) { sdk_version: "current", } - java_sdk_library { - name: "qux", - srcs: ["a.java"], - api_packages: ["qux"], - sdk_version: "current", - } - - java_sdk_library { - name: "quuz", - srcs: ["a.java"], - api_packages: ["quuz"], - sdk_version: "current", - } - java_sdk_library { name: "bar", srcs: ["a.java"], @@ -2406,7 +2392,6 @@ func TestUsesLibraries(t *testing.T) { android_app { name: "app", srcs: ["a.java"], - libs: ["qux", "quuz.stubs"], uses_libs: ["foo"], sdk_version: "current", optional_uses_libs: [ @@ -2437,15 +2422,6 @@ func TestUsesLibraries(t *testing.T) { app := ctx.ModuleForTests("app", "android_common") prebuilt := ctx.ModuleForTests("prebuilt", "android_common") - // Test that implicit dependencies on java_sdk_library instances are passed to the manifest. - manifestFixerArgs := app.Output("manifest_fixer/AndroidManifest.xml").Args["args"] - if w := "--uses-library qux"; !strings.Contains(manifestFixerArgs, w) { - t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs) - } - if w := "--uses-library quuz"; !strings.Contains(manifestFixerArgs, w) { - t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs) - } - // Test that all libraries are verified cmd := app.Rule("verify_uses_libraries").RuleParams.Command if w := "--uses-library foo"; !strings.Contains(cmd, w) { diff --git a/java/java.go b/java/java.go index 00b11f77a..da9bd3dfe 100644 --- a/java/java.go +++ b/java/java.go @@ -355,17 +355,7 @@ func (me *CompilerDeviceProperties) EffectiveOptimizeEnabled() bool { } // Functionality common to Module and Import -// -// It is embedded in Module so its functionality can be used by methods in Module -// but it is currently only initialized by Import and Library. type embeddableInModuleAndImport struct { - - // Functionality related to this being used as a component of a java_sdk_library. - EmbeddableSdkLibraryComponent -} - -func (e *embeddableInModuleAndImport) initModuleAndImport(moduleBase *android.ModuleBase) { - e.initSdkLibraryComponent(moduleBase) } // Module/Import's DepIsInSameApex(...) delegates to this method. @@ -506,6 +496,11 @@ type Dependency interface { JacocoReportClassesFile() android.Path } +type SdkLibraryDependency interface { + SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths + SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths +} + type xref interface { XrefJavaFiles() android.Paths } @@ -935,12 +930,6 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } } - // If this is a component library (stubs, etc.) for a java_sdk_library then - // add the name of that java_sdk_library to the exported sdk libs to make sure - // that, if necessary, a element for that java_sdk_library is - // added to the Android manifest. - j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...) - ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -960,7 +949,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case libTag: deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) // names of sdk libs that are directly depended are exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.OptionalImplicitSdkLibrary()...) + j.exportedSdkLibs = append(j.exportedSdkLibs, otherName) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } @@ -2001,8 +1990,6 @@ func LibraryFactory() android.Module { &module.Module.protoProperties, &module.libraryProperties) - module.initModuleAndImport(&module.ModuleBase) - android.InitApexModule(module) android.InitSdkAwareModule(module) InitJavaModule(module, android.HostAndDeviceSupported) @@ -2464,12 +2451,6 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } j.combinedClasspathFile = outputFile - // If this is a component library (impl, stubs, etc.) for a java_sdk_library then - // add the name of that java_sdk_library to the exported sdk libs to make sure - // that, if necessary, a element for that java_sdk_library is - // added to the Android manifest. - j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...) - ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -2586,8 +2567,6 @@ func ImportFactory() android.Module { module.AddProperties(&module.properties) - module.initModuleAndImport(&module.ModuleBase) - android.InitPrebuiltModule(module, &module.properties.Jars) android.InitApexModule(module) android.InitSdkAwareModule(module) diff --git a/java/java_test.go b/java/java_test.go index 4c085cf0f..4f3a803ff 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -19,7 +19,6 @@ import ( "os" "path/filepath" "reflect" - "sort" "strconv" "strings" "testing" @@ -1154,25 +1153,13 @@ func TestJavaSdkLibrary(t *testing.T) { java_library { name: "baz", srcs: ["c.java"], - libs: ["foo", "bar.stubs"], + libs: ["foo", "bar"], sdk_version: "system_current", } - java_sdk_library_import { - name: "quuz", - public: { - jars: ["c.jar"], - }, - } - java_sdk_library_import { - name: "fred", - public: { - jars: ["b.jar"], - }, - } java_library { name: "qux", srcs: ["c.java"], - libs: ["baz", "fred", "quuz.stubs"], + libs: ["baz"], sdk_version: "system_current", } java_library { @@ -1237,9 +1224,8 @@ func TestJavaSdkLibrary(t *testing.T) { qux := ctx.ModuleForTests("qux", "android_common") if quxLib, ok := qux.Module().(*Library); ok { sdkLibs := quxLib.ExportedSdkLibs() - sort.Strings(sdkLibs) - if w := []string{"bar", "foo", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) { - t.Errorf("qux should export %q but exports %q", w, sdkLibs) + if len(sdkLibs) != 2 || !android.InList("foo", sdkLibs) || !android.InList("bar", sdkLibs) { + t.Errorf("qux should export \"foo\" and \"bar\" but exports %v", sdkLibs) } } } diff --git a/java/sdk_library.go b/java/sdk_library.go index 0334f80d3..5efb4d045 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -543,18 +543,12 @@ type commonToSdkLibraryAndImport struct { namingScheme sdkLibraryComponentNamingScheme commonProperties commonToSdkLibraryAndImportProperties - - // Functionality related to this being used as a component of a java_sdk_library. - EmbeddableSdkLibraryComponent } func (c *commonToSdkLibraryAndImport) initCommon(moduleBase *android.ModuleBase) { c.moduleBase = moduleBase moduleBase.AddProperties(&c.commonProperties) - - // Initialize this as an sdk library component. - c.initSdkLibraryComponent(moduleBase) } func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android.DefaultableHookContext) bool { @@ -569,9 +563,6 @@ func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android return false } - // Use the name specified in the module definition as the owner. - c.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack = proptools.StringPtr(c.moduleBase.BaseModuleName()) - return true } @@ -737,84 +728,6 @@ func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android. return paths.stubsHeaderPath } -func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} { - componentProps := &struct { - SdkLibraryToImplicitlyTrack *string - }{ - // Mark the stubs library as being components of this java_sdk_library so that - // any app that includes code which depends (directly or indirectly) on the stubs - // library will have the appropriate invocation inserted into its - // manifest if necessary. - SdkLibraryToImplicitlyTrack: proptools.StringPtr(c.moduleBase.BaseModuleName()), - } - - return componentProps -} - -// Properties related to the use of a module as an component of a java_sdk_library. -type SdkLibraryComponentProperties struct { - - // The name of the java_sdk_library/_import to add to a entry - // in the AndroidManifest.xml of any Android app that includes code that references - // this module. If not set then no java_sdk_library/_import is tracked. - SdkLibraryToImplicitlyTrack *string `blueprint:"mutated"` -} - -// Structure to be embedded in a module struct that needs to support the -// SdkLibraryComponentDependency interface. -type EmbeddableSdkLibraryComponent struct { - sdkLibraryComponentProperties SdkLibraryComponentProperties -} - -func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(moduleBase *android.ModuleBase) { - moduleBase.AddProperties(&e.sdkLibraryComponentProperties) -} - -// to satisfy SdkLibraryComponentDependency -func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() []string { - if e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack != nil { - return []string{*e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack} - } - return nil -} - -// Implemented by modules that are (or possibly could be) a component of a java_sdk_library -// (including the java_sdk_library) itself. -type SdkLibraryComponentDependency interface { - // The optional name of the sdk library that should be implicitly added to the - // AndroidManifest of an app that contains code which references the sdk library. - // - // Returns an array containing 0 or 1 items rather than a *string to make it easier - // to append this to the list of exported sdk libraries. - OptionalImplicitSdkLibrary() []string -} - -// Make sure that all the module types that are components of java_sdk_library/_import -// and which can be referenced (directly or indirectly) from an android app implement -// the SdkLibraryComponentDependency interface. -var _ SdkLibraryComponentDependency = (*Library)(nil) -var _ SdkLibraryComponentDependency = (*Import)(nil) -var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil) -var _ SdkLibraryComponentDependency = (*sdkLibraryImport)(nil) - -// Provides access to sdk_version related header and implentation jars. -type SdkLibraryDependency interface { - SdkLibraryComponentDependency - - // Get the header jars appropriate for the supplied sdk_version. - // - // These are turbine generated jars so they only change if the externals of the - // class changes but it does not contain and implementation or JavaDoc. - SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths - - // Get the implementation jars appropriate for the supplied sdk version. - // - // These are either the implementation jar for the whole sdk library or the implementation - // jars for the stubs. The latter should only be needed when generating JavaDoc as otherwise - // they are identical to the corresponding header jars. - SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths -} - type SdkLibrary struct { Library @@ -1065,7 +978,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext props.Dist.Tag = proptools.StringPtr(".jar") } - mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) + mctx.CreateModule(LibraryFactory, &props) } // Creates a droidstubs module that creates stubs source files from the given full source @@ -1408,8 +1321,6 @@ func (module *SdkLibrary) InitSdkLibraryProperties() { &module.protoProperties, ) - module.initSdkLibraryComponent(&module.ModuleBase) - module.properties.Installable = proptools.BoolPtr(true) module.deviceProperties.IsSDKLibrary = true } @@ -1658,8 +1569,7 @@ func (module *sdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl // The imports are preferred if the java_sdk_library_import is preferred. props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer()) - - mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary()) + mctx.CreateModule(ImportFactory, &props) } func (module *sdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { -- cgit v1.2.3-59-g8ed1b From 64e61997569dde18f70abac001942ee677bccab0 Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Fri, 15 May 2020 10:20:31 +0100 Subject: Retry: "Improve tracking of exported sdk libraries" The build tracks the java_sdk_library/_import modules that are referenced by libraries so that it can ensure that any Android app that includes code that depends on one of those modules has the appropriate entry in their manifest. Unfortunately, there were a couple of issues with that: 1) It only tracks direct references to the java_sdk_library module itself, e.g. android.test.mock. Direct references to the stubs module, e.g. android.test.mock.stubs were not tracked. Making it possible for Android apps to reference libraries which would not be available at runtime. 2) The logic for determining whether something was a java_sdk_library was repeated in a number of places making it difficult to allow java_sdk_library/_import instances to determine whether they should be treated as an Android shared library. 3) It tracks (and could use) even those java_sdk_library instances which do not represent a shared library, e.g. the ones that set api_only: true. While this change will simplifty fixing that the actual issue will be fixed in a follow up change. Changes: * Added EmbeddableSdkLibraryComponent and embedded it into java_sdk_library/_import, java_library and java_import. It provides the common code to minimize duplication. It contains an SdkLibraryToImplicitlyTrack field that if set will cause any references to the containing module to add the SdkLibraryParent to the list of implicit sdk libraries being tracked. * Changed code that assumed that anything that implemented SdkLibraryDependency required tracking to use the OptionalImplicitSdkLibrary() method to get the optional name of the sdk library to track. That will allow a follow up change to return nil from that method to exclude an sdk library from being tracked. * Moved SdkLibraryDependency from java.go to sdk_library.go as that is a better place for it to be. * Changed the stubs java_library/java_import creation code to initialize the SdkLibraryToImplicitlyTrack field with the name of the creating module. * Initialized the SdkLibraryToImplicitlyTrack field in the java_sdk_library/_import so that direct references to them will be tracked too. * Added tests to verify that direct access to the .stubs child of both java_sdk_library and java_sdk_library_import are tracked properly. Test: atest CtsProviderTestCases - which relies on android.test.mock being implicitly tracked to verify that I had not broken anything. Used aapt2 dump badging to read the manifest. m nothing - to run the new tests which failed before fixing the code. Bug: 156723295 (cherry picked from commit 859fe961b015259368e9994969b569eb34f54ddc) Change-Id: I760a9ac72856e3a07a497ce40db70c7e70106837 --- java/aar.go | 7 ++-- java/app_test.go | 24 ++++++++++++++ java/java.go | 33 +++++++++++++++---- java/java_test.go | 22 ++++++++++--- java/sdk_library.go | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 166 insertions(+), 14 deletions(-) (limited to 'java/app_test.go') diff --git a/java/aar.go b/java/aar.go index 0e103f248..c8daf835b 100644 --- a/java/aar.go +++ b/java/aar.go @@ -379,8 +379,11 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati sharedLibs = append(sharedLibs, exportPackage) } - if _, ok := module.(SdkLibraryDependency); ok { - sdkLibraries = append(sdkLibraries, ctx.OtherModuleName(module)) + // If the module is (or possibly could be) a component of a java_sdk_library + // (including the java_sdk_library) itself then append any implicit sdk library + // names to the list of sdk libraries to be added to the manifest. + if component, ok := module.(SdkLibraryComponentDependency); ok { + sdkLibraries = append(sdkLibraries, component.OptionalImplicitSdkLibrary()...) } case frameworkResTag: diff --git a/java/app_test.go b/java/app_test.go index c731a1713..12b935ed3 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2382,6 +2382,20 @@ func TestUsesLibraries(t *testing.T) { sdk_version: "current", } + java_sdk_library { + name: "qux", + srcs: ["a.java"], + api_packages: ["qux"], + sdk_version: "current", + } + + java_sdk_library { + name: "quuz", + srcs: ["a.java"], + api_packages: ["quuz"], + sdk_version: "current", + } + java_sdk_library { name: "bar", srcs: ["a.java"], @@ -2392,6 +2406,7 @@ func TestUsesLibraries(t *testing.T) { android_app { name: "app", srcs: ["a.java"], + libs: ["qux", "quuz.stubs"], uses_libs: ["foo"], sdk_version: "current", optional_uses_libs: [ @@ -2422,6 +2437,15 @@ func TestUsesLibraries(t *testing.T) { app := ctx.ModuleForTests("app", "android_common") prebuilt := ctx.ModuleForTests("prebuilt", "android_common") + // Test that implicit dependencies on java_sdk_library instances are passed to the manifest. + manifestFixerArgs := app.Output("manifest_fixer/AndroidManifest.xml").Args["args"] + if w := "--uses-library qux"; !strings.Contains(manifestFixerArgs, w) { + t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs) + } + if w := "--uses-library quuz"; !strings.Contains(manifestFixerArgs, w) { + t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs) + } + // Test that all libraries are verified cmd := app.Rule("verify_uses_libraries").RuleParams.Command if w := "--uses-library foo"; !strings.Contains(cmd, w) { diff --git a/java/java.go b/java/java.go index da9bd3dfe..00b11f77a 100644 --- a/java/java.go +++ b/java/java.go @@ -355,7 +355,17 @@ func (me *CompilerDeviceProperties) EffectiveOptimizeEnabled() bool { } // Functionality common to Module and Import +// +// It is embedded in Module so its functionality can be used by methods in Module +// but it is currently only initialized by Import and Library. type embeddableInModuleAndImport struct { + + // Functionality related to this being used as a component of a java_sdk_library. + EmbeddableSdkLibraryComponent +} + +func (e *embeddableInModuleAndImport) initModuleAndImport(moduleBase *android.ModuleBase) { + e.initSdkLibraryComponent(moduleBase) } // Module/Import's DepIsInSameApex(...) delegates to this method. @@ -496,11 +506,6 @@ type Dependency interface { JacocoReportClassesFile() android.Path } -type SdkLibraryDependency interface { - SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths - SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths -} - type xref interface { XrefJavaFiles() android.Paths } @@ -930,6 +935,12 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } } + // If this is a component library (stubs, etc.) for a java_sdk_library then + // add the name of that java_sdk_library to the exported sdk libs to make sure + // that, if necessary, a element for that java_sdk_library is + // added to the Android manifest. + j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...) + ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -949,7 +960,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case libTag: deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) // names of sdk libs that are directly depended are exported - j.exportedSdkLibs = append(j.exportedSdkLibs, otherName) + j.exportedSdkLibs = append(j.exportedSdkLibs, dep.OptionalImplicitSdkLibrary()...) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } @@ -1990,6 +2001,8 @@ func LibraryFactory() android.Module { &module.Module.protoProperties, &module.libraryProperties) + module.initModuleAndImport(&module.ModuleBase) + android.InitApexModule(module) android.InitSdkAwareModule(module) InitJavaModule(module, android.HostAndDeviceSupported) @@ -2451,6 +2464,12 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } j.combinedClasspathFile = outputFile + // If this is a component library (impl, stubs, etc.) for a java_sdk_library then + // add the name of that java_sdk_library to the exported sdk libs to make sure + // that, if necessary, a element for that java_sdk_library is + // added to the Android manifest. + j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...) + ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -2567,6 +2586,8 @@ func ImportFactory() android.Module { module.AddProperties(&module.properties) + module.initModuleAndImport(&module.ModuleBase) + android.InitPrebuiltModule(module, &module.properties.Jars) android.InitApexModule(module) android.InitSdkAwareModule(module) diff --git a/java/java_test.go b/java/java_test.go index 4f3a803ff..4c085cf0f 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -19,6 +19,7 @@ import ( "os" "path/filepath" "reflect" + "sort" "strconv" "strings" "testing" @@ -1153,13 +1154,25 @@ func TestJavaSdkLibrary(t *testing.T) { java_library { name: "baz", srcs: ["c.java"], - libs: ["foo", "bar"], + libs: ["foo", "bar.stubs"], sdk_version: "system_current", } + java_sdk_library_import { + name: "quuz", + public: { + jars: ["c.jar"], + }, + } + java_sdk_library_import { + name: "fred", + public: { + jars: ["b.jar"], + }, + } java_library { name: "qux", srcs: ["c.java"], - libs: ["baz"], + libs: ["baz", "fred", "quuz.stubs"], sdk_version: "system_current", } java_library { @@ -1224,8 +1237,9 @@ func TestJavaSdkLibrary(t *testing.T) { qux := ctx.ModuleForTests("qux", "android_common") if quxLib, ok := qux.Module().(*Library); ok { sdkLibs := quxLib.ExportedSdkLibs() - if len(sdkLibs) != 2 || !android.InList("foo", sdkLibs) || !android.InList("bar", sdkLibs) { - t.Errorf("qux should export \"foo\" and \"bar\" but exports %v", sdkLibs) + sort.Strings(sdkLibs) + if w := []string{"bar", "foo", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) { + t.Errorf("qux should export %q but exports %q", w, sdkLibs) } } } diff --git a/java/sdk_library.go b/java/sdk_library.go index b215a76f7..de30635b4 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -543,12 +543,18 @@ type commonToSdkLibraryAndImport struct { namingScheme sdkLibraryComponentNamingScheme commonProperties commonToSdkLibraryAndImportProperties + + // Functionality related to this being used as a component of a java_sdk_library. + EmbeddableSdkLibraryComponent } func (c *commonToSdkLibraryAndImport) initCommon(moduleBase *android.ModuleBase) { c.moduleBase = moduleBase moduleBase.AddProperties(&c.commonProperties) + + // Initialize this as an sdk library component. + c.initSdkLibraryComponent(moduleBase) } func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android.DefaultableHookContext) bool { @@ -563,6 +569,9 @@ func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android return false } + // Use the name specified in the module definition as the owner. + c.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack = proptools.StringPtr(c.moduleBase.BaseModuleName()) + return true } @@ -728,6 +737,84 @@ func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android. return paths.stubsHeaderPath } +func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} { + componentProps := &struct { + SdkLibraryToImplicitlyTrack *string + }{ + // Mark the stubs library as being components of this java_sdk_library so that + // any app that includes code which depends (directly or indirectly) on the stubs + // library will have the appropriate invocation inserted into its + // manifest if necessary. + SdkLibraryToImplicitlyTrack: proptools.StringPtr(c.moduleBase.BaseModuleName()), + } + + return componentProps +} + +// Properties related to the use of a module as an component of a java_sdk_library. +type SdkLibraryComponentProperties struct { + + // The name of the java_sdk_library/_import to add to a entry + // in the AndroidManifest.xml of any Android app that includes code that references + // this module. If not set then no java_sdk_library/_import is tracked. + SdkLibraryToImplicitlyTrack *string `blueprint:"mutated"` +} + +// Structure to be embedded in a module struct that needs to support the +// SdkLibraryComponentDependency interface. +type EmbeddableSdkLibraryComponent struct { + sdkLibraryComponentProperties SdkLibraryComponentProperties +} + +func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(moduleBase *android.ModuleBase) { + moduleBase.AddProperties(&e.sdkLibraryComponentProperties) +} + +// to satisfy SdkLibraryComponentDependency +func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() []string { + if e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack != nil { + return []string{*e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack} + } + return nil +} + +// Implemented by modules that are (or possibly could be) a component of a java_sdk_library +// (including the java_sdk_library) itself. +type SdkLibraryComponentDependency interface { + // The optional name of the sdk library that should be implicitly added to the + // AndroidManifest of an app that contains code which references the sdk library. + // + // Returns an array containing 0 or 1 items rather than a *string to make it easier + // to append this to the list of exported sdk libraries. + OptionalImplicitSdkLibrary() []string +} + +// Make sure that all the module types that are components of java_sdk_library/_import +// and which can be referenced (directly or indirectly) from an android app implement +// the SdkLibraryComponentDependency interface. +var _ SdkLibraryComponentDependency = (*Library)(nil) +var _ SdkLibraryComponentDependency = (*Import)(nil) +var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil) +var _ SdkLibraryComponentDependency = (*sdkLibraryImport)(nil) + +// Provides access to sdk_version related header and implentation jars. +type SdkLibraryDependency interface { + SdkLibraryComponentDependency + + // Get the header jars appropriate for the supplied sdk_version. + // + // These are turbine generated jars so they only change if the externals of the + // class changes but it does not contain and implementation or JavaDoc. + SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths + + // Get the implementation jars appropriate for the supplied sdk version. + // + // These are either the implementation jar for the whole sdk library or the implementation + // jars for the stubs. The latter should only be needed when generating JavaDoc as otherwise + // they are identical to the corresponding header jars. + SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths +} + type SdkLibrary struct { Library @@ -981,7 +1068,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext props.Dist.Tag = proptools.StringPtr(".jar") } - mctx.CreateModule(LibraryFactory, &props) + mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) } // Creates a droidstubs module that creates stubs source files from the given full source @@ -1326,6 +1413,8 @@ func (module *SdkLibrary) InitSdkLibraryProperties() { &module.protoProperties, ) + module.initSdkLibraryComponent(&module.ModuleBase) + module.properties.Installable = proptools.BoolPtr(true) module.deviceProperties.IsSDKLibrary = true } @@ -1574,7 +1663,8 @@ func (module *sdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl // The imports are preferred if the java_sdk_library_import is preferred. props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer()) - mctx.CreateModule(ImportFactory, &props) + + mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary()) } func (module *sdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { -- cgit v1.2.3-59-g8ed1b From af7f91fc9d56dd1db790d09051b8a9a2dcdb151a Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Wed, 29 Apr 2020 14:01:06 +0900 Subject: Reland "enforce sdk_version for JNI libs for updatable APKs" JNI libs for "updatable" APKs or APKs in "updatable" APEXes should set sdk_version which is equal to or less than APK's min_sdk_version. In fact, we'd better check if min_sdk_version of JNI libs matches(or is earlier than) min_sdk_version of the APK. But for now the build system can't handle sdk_version/min_sdk_version correctly for JNI libs. That's why sdk_version of JNI libs is enforced to match with min_sdk_version of APK in this change. (original commit: 98c4750f39577abd42e70dfd777ea6f5e1af3111) Bug: 145796956 Test: m Merged-In: I08543ccee7dfda0559a1fca108ceb5c28f84943f Change-Id: I08543ccee7dfda0559a1fca108ceb5c28f84943f (cherry picked from commit bbc3fb780b859ccd2c4550a8bc6b87f36d64dfd9) --- java/app.go | 28 +++++++++++++ java/app_test.go | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) (limited to 'java/app_test.go') diff --git a/java/app.go b/java/app.go index e44b87d92..40101c512 100755 --- a/java/app.go +++ b/java/app.go @@ -421,12 +421,40 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { if String(a.deviceProperties.Min_sdk_version) == "" { ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.") } + if minSdkVersion, err := a.minSdkVersion().effectiveVersion(ctx); err == nil { + a.checkJniLibsSdkVersion(ctx, minSdkVersion) + } else { + ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) + } } a.checkPlatformAPI(ctx) a.checkSdkVersions(ctx) } +// If an updatable APK sets min_sdk_version, min_sdk_vesion of JNI libs should match with it. +// This check is enforced for "updatable" APKs (including APK-in-APEX). +// b/155209650: until min_sdk_version is properly supported, use sdk_version instead. +// because, sdk_version is overridden by min_sdk_version (if set as smaller) +// and linkType is checked with dependencies so we can be sure that the whole dependency tree +// will meet the requirements. +func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion sdkVersion) { + // It's enough to check direct JNI deps' sdk_version because all transitive deps from JNI deps are checked in cc.checkLinkType() + ctx.VisitDirectDeps(func(m android.Module) { + if !IsJniDepTag(ctx.OtherModuleDependencyTag(m)) { + return + } + dep, _ := m.(*cc.Module) + jniSdkVersion, err := android.ApiStrToNum(ctx, dep.SdkVersion()) + if err != nil || int(minSdkVersion) < jniSdkVersion { + ctx.OtherModuleErrorf(dep, "sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)", + dep.SdkVersion(), minSdkVersion, ctx.ModuleName()) + return + } + + }) +} + // Returns true if the native libraries should be stored in the APK uncompressed and the // extractNativeLibs application flag should be set to false in the manifest. func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool { diff --git a/java/app_test.go b/java/app_test.go index 8afd97d9e..e686f2780 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -473,6 +473,127 @@ func TestUpdatableApps(t *testing.T) { } } +func TestUpdatableApps_JniLibsShouldShouldSupportMinSdkVersion(t *testing.T) { + testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` + android_app { + name: "foo", + srcs: ["a.java"], + updatable: true, + sdk_version: "current", + min_sdk_version: "current", + jni_libs: ["libjni"], + } + + cc_library { + name: "libjni", + stl: "none", + system_shared_libs: [], + sdk_version: "current", + } + `) +} + +func TestUpdatableApps_JniLibShouldBeBuiltAgainstMinSdkVersion(t *testing.T) { + bp := cc.GatherRequiredDepsForTest(android.Android) + ` + android_app { + name: "foo", + srcs: ["a.java"], + updatable: true, + sdk_version: "current", + min_sdk_version: "29", + jni_libs: ["libjni"], + } + + cc_library { + name: "libjni", + stl: "none", + system_shared_libs: [], + sdk_version: "29", + } + + ndk_prebuilt_object { + name: "ndk_crtbegin_so.29", + sdk_version: "29", + } + + ndk_prebuilt_object { + name: "ndk_crtend_so.29", + sdk_version: "29", + } + ` + fs := map[string][]byte{ + "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtbegin_so.o": nil, + "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtend_so.o": nil, + "prebuilts/ndk/current/platforms/android-29/arch-arm/usr/lib/crtbegin_so.o": nil, + "prebuilts/ndk/current/platforms/android-29/arch-arm/usr/lib/crtend_so.o": nil, + } + + ctx, _ := testJavaWithConfig(t, testConfig(nil, bp, fs)) + + inputs := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").Description("link").Implicits + var crtbeginFound, crtendFound bool + for _, input := range inputs { + switch input.String() { + case "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtbegin_so.o": + crtbeginFound = true + case "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtend_so.o": + crtendFound = true + } + } + if !crtbeginFound || !crtendFound { + t.Error("should link with ndk_crtbegin_so.29 and ndk_crtend_so.29") + } +} + +func TestUpdatableApps_ErrorIfJniLibDoesntSupportMinSdkVersion(t *testing.T) { + bp := cc.GatherRequiredDepsForTest(android.Android) + ` + android_app { + name: "foo", + srcs: ["a.java"], + updatable: true, + sdk_version: "current", + min_sdk_version: "29", // this APK should support 29 + jni_libs: ["libjni"], + } + + cc_library { + name: "libjni", + stl: "none", + sdk_version: "current", + } + ` + testJavaError(t, `"libjni" .*: sdk_version\(current\) is higher than min_sdk_version\(29\)`, bp) +} + +func TestUpdatableApps_ErrorIfDepSdkVersionIsHigher(t *testing.T) { + bp := cc.GatherRequiredDepsForTest(android.Android) + ` + android_app { + name: "foo", + srcs: ["a.java"], + updatable: true, + sdk_version: "current", + min_sdk_version: "29", // this APK should support 29 + jni_libs: ["libjni"], + } + + cc_library { + name: "libjni", + stl: "none", + shared_libs: ["libbar"], + system_shared_libs: [], + sdk_version: "27", + } + + cc_library { + name: "libbar", + stl: "none", + system_shared_libs: [], + sdk_version: "current", + } + ` + testJavaError(t, `"libjni" .*: links "libbar" built against newer API version "current"`, bp) +} + func TestResourceDirs(t *testing.T) { testCases := []struct { name string -- cgit v1.2.3-59-g8ed1b From c4f0ff1d6cd68d20e4716119a7d6fbbacd428fe6 Mon Sep 17 00:00:00 2001 From: Sasha Smundak Date: Wed, 27 May 2020 16:36:07 -0700 Subject: Cherrypick aosp/1318079 and aosp/1324841 Allow apex module to have android_app_set as its constituent. Fix android_app_set documentation Fixes: 157166068 Test: treehugger & manual Change-Id: I9f91f1b761286f489d175eb0772f78f702e8a2d6 Merged-In: I9f91f1b761286f489d175eb0772f78f702e8a2d6 Merged-In: Id9b296d9301902deb463b299413491bc66d58944 --- apex/androidmk.go | 30 +++++++++++++++++++----------- apex/apex.go | 12 +++++++++++- apex/apex_test.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- apex/builder.go | 35 +++++++++++++++++++++++++++-------- java/app.go | 45 ++++++++++++++++++++++----------------------- java/app_test.go | 4 ++-- 6 files changed, 129 insertions(+), 49 deletions(-) (limited to 'java/app_test.go') diff --git a/apex/androidmk.go b/apex/androidmk.go index d1c2a649f..9371338ca 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -79,7 +79,7 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo } for _, fi := range a.filesInfo { - if cc, ok := fi.module.(*cc.Module); ok && cc.Properties.HideFromMake { + if ccMod, ok := fi.module.(*cc.Module); ok && ccMod.Properties.HideFromMake { continue } @@ -165,7 +165,8 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo if fi.jacocoReportClassesFile != nil { fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", fi.jacocoReportClassesFile.String()) } - if fi.class == javaSharedLib { + switch fi.class { + case javaSharedLib: javaModule := fi.module.(java.Dependency) // soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar Therefore // we need to remove the suffix from LOCAL_MODULE_STEM, otherwise @@ -176,7 +177,7 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String()) fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false") fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk") - } else if fi.class == app { + case app: fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", fi.certificate.AndroidMkString()) // soong_app_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .apk Therefore // we need to remove the suffix from LOCAL_MODULE_STEM, otherwise @@ -186,19 +187,26 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", strings.Join(app.JniCoverageOutputs().Strings(), " ")) } fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_app_prebuilt.mk") - } else if fi.class == nativeSharedLib || fi.class == nativeExecutable || fi.class == nativeTest { + case appSet: + as, ok := fi.module.(*java.AndroidAppSet) + if !ok { + panic(fmt.Sprintf("Expected %s to be AndroidAppSet", fi.module)) + } + fmt.Fprintln(w, "LOCAL_APK_SET_MASTER_FILE :=", as.MasterFile()) + fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk") + case nativeSharedLib, nativeExecutable, nativeTest: fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.Stem()) - if cc, ok := fi.module.(*cc.Module); ok { - if cc.UnstrippedOutputFile() != nil { - fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", cc.UnstrippedOutputFile().String()) + if ccMod, ok := fi.module.(*cc.Module); ok { + if ccMod.UnstrippedOutputFile() != nil { + fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", ccMod.UnstrippedOutputFile().String()) } - cc.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w) - if cc.CoverageOutputFile().Valid() { - fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", cc.CoverageOutputFile().String()) + ccMod.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w) + if ccMod.CoverageOutputFile().Valid() { + fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", ccMod.CoverageOutputFile().String()) } } fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk") - } else { + default: fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.Stem()) if fi.builtFile == a.manifestPbOut && apexType == flattenedApex { if a.primaryApexType { diff --git a/apex/apex.go b/apex/apex.go index b974bcdea..4a8bfc25d 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -1150,6 +1150,7 @@ const ( javaSharedLib nativeTest app + appSet ) func (class apexFileClass) NameInMake() string { @@ -1164,7 +1165,7 @@ func (class apexFileClass) NameInMake() string { return "JAVA_LIBRARIES" case nativeTest: return "NATIVE_TESTS" - case app: + case app, appSet: // b/142537672 Why isn't this APP? We want to have full control over // the paths and file names of the apk file under the flattend APEX. // If this is set to APP, then the paths and file names are modified @@ -1981,6 +1982,15 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap)) } else if ap, ok := child.(*java.AndroidTestHelperApp); ok { filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap)) + } else if ap, ok := child.(*java.AndroidAppSet); ok { + appDir := "app" + if ap.Privileged() { + appDir = "priv-app" + } + af := newApexFile(ctx, ap.OutputFile(), ap.Name(), + filepath.Join(appDir, ap.BaseModuleName()), appSet, ap) + af.certificate = java.PresignedCertificate + filesInfo = append(filesInfo, af) } else { ctx.PropertyErrorf("apps", "%q is not an android_app module", depName) } diff --git a/apex/apex_test.go b/apex/apex_test.go index a98f6c610..24b93ecfd 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -97,15 +97,15 @@ func withManifestPackageNameOverrides(specs []string) testCustomizer { } } -func withBinder32bit(fs map[string][]byte, config android.Config) { +func withBinder32bit(_ map[string][]byte, config android.Config) { config.TestProductVariables.Binder32bit = proptools.BoolPtr(true) } -func withUnbundledBuild(fs map[string][]byte, config android.Config) { +func withUnbundledBuild(_ map[string][]byte, config android.Config) { config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) } -func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) { +func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) { android.ClearApexDependency() bp = bp + ` @@ -166,6 +166,7 @@ func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*andr "build/make/core/proguard.flags": nil, "build/make/core/proguard_basic_keeps.flags": nil, "dummy.txt": nil, + "AppSet.apks": nil, } cc.GatherRequiredFilesForTest(fs) @@ -237,7 +238,7 @@ func setUp() { } func tearDown() { - os.RemoveAll(buildDir) + _ = os.RemoveAll(buildDir) } // ensure that 'result' contains 'expected' @@ -256,6 +257,17 @@ func ensureNotContains(t *testing.T, result string, notExpected string) { } } +func ensureMatches(t *testing.T, result string, expectedRex string) { + ok, err := regexp.MatchString(expectedRex, result) + if err != nil { + t.Fatalf("regexp failure trying to match %s against `%s` expression: %s", result, expectedRex, err) + return + } + if !ok { + t.Errorf("%s does not match regular expession %s", result, expectedRex) + } +} + func ensureListContains(t *testing.T, result []string, expected string) { t.Helper() if !android.InList(expected, result) { @@ -4444,6 +4456,38 @@ func TestAppBundle(t *testing.T) { ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo/AppFoo.apk"}]}`) } +func TestAppSetBundle(t *testing.T) { + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + apps: ["AppSet"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + android_app_set { + name: "AppSet", + set: "AppSet.apks", + }`) + mod := ctx.ModuleForTests("myapex", "android_common_myapex_image") + bundleConfigRule := mod.Description("Bundle Config") + content := bundleConfigRule.Args["content"] + ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`) + s := mod.Rule("apexRule").Args["copy_commands"] + copyCmds := regexp.MustCompile(" *&& *").Split(s, -1) + if len(copyCmds) != 3 { + t.Fatalf("Expected 3 commands, got %d in:\n%s", len(copyCmds), s) + } + ensureMatches(t, copyCmds[0], "^rm -rf .*/app/AppSet$") + ensureMatches(t, copyCmds[1], "^mkdir -p .*/app/AppSet$") + ensureMatches(t, copyCmds[2], "^unzip .*-d .*/app/AppSet .*/AppSet.zip$") +} + func testNoUpdatableJarsInBootImage(t *testing.T, errmsg, bp string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) { t.Helper() diff --git a/apex/builder.go b/apex/builder.go index fce250365..5f0620d2b 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -69,11 +69,14 @@ var ( // by default set to (uid/gid/mode) = (1000/1000/0644) // TODO(b/113082813) make this configurable using config.fs syntax generateFsConfig = pctx.StaticRule("generateFsConfig", blueprint.RuleParams{ - Command: `echo '/ 1000 1000 0755' > ${out} && ` + - `echo ${ro_paths} | tr ' ' '\n' | awk '{print "/"$$1 " 1000 1000 0644"}' >> ${out} && ` + - `echo ${exec_paths} | tr ' ' '\n' | awk '{print "/"$$1 " 0 2000 0755"}' >> ${out}`, - Description: "fs_config ${out}", - }, "ro_paths", "exec_paths") + Command: `( echo '/ 1000 1000 0755' ` + + `&& for i in ${ro_paths}; do echo "/$$i 1000 1000 0644"; done ` + + `&& for i in ${exec_paths}; do echo "/$$i 0 2000 0755"; done ` + + `&& ( tr ' ' '\n' <${out}.apklist | for i in ${apk_paths}; do read apk; echo "/$$i 0 2000 0755"; zipinfo -1 $$apk | sed "s:\(.*\):/$$i/\1 1000 1000 0644:"; done ) ) > ${out}`, + Description: "fs_config ${out}", + Rspfile: "$out.apklist", + RspfileContent: "$in", + }, "ro_paths", "exec_paths", "apk_paths") apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{ Command: `rm -f $out && ${jsonmodify} $in ` + @@ -278,7 +281,7 @@ func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.Output // collect the manifest names and paths of android apps // if their manifest names are overridden for _, fi := range a.filesInfo { - if fi.class != app { + if fi.class != app && fi.class != appSet { continue } packageName := fi.overriddenPackageName @@ -328,13 +331,22 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { var copyCommands []string for _, fi := range a.filesInfo { destPath := android.PathForModuleOut(ctx, "image"+suffix, fi.Path()).String() - copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(destPath)) + destPathDir := filepath.Dir(destPath) + if fi.class == appSet { + copyCommands = append(copyCommands, "rm -rf "+destPathDir) + } + copyCommands = append(copyCommands, "mkdir -p "+destPathDir) if a.linkToSystemLib && fi.transitiveDep && fi.AvailableToPlatform() { // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here pathOnDevice := filepath.Join("/system", fi.Path()) copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath) } else { - copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath) + if fi.class == appSet { + copyCommands = append(copyCommands, + fmt.Sprintf("unzip -q -d %s %s", destPathDir, fi.builtFile.String())) + } else { + copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath) + } implicitInputs = append(implicitInputs, fi.builtFile) } // create additional symlinks pointing the file inside the APEX @@ -394,6 +406,8 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { // files and dirs that will be created in APEX var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"} var executablePaths []string // this also includes dirs + var extractedAppSetPaths android.Paths + var extractedAppSetDirs []string for _, f := range a.filesInfo { pathInApex := f.Path() if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") { @@ -401,6 +415,9 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { for _, s := range f.symlinks { executablePaths = append(executablePaths, filepath.Join(f.installDir, s)) } + } else if f.class == appSet { + extractedAppSetPaths = append(extractedAppSetPaths, f.builtFile) + extractedAppSetDirs = append(extractedAppSetDirs, f.installDir) } else { readOnlyPaths = append(readOnlyPaths, pathInApex) } @@ -421,9 +438,11 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { Rule: generateFsConfig, Output: cannedFsConfig, Description: "generate fs config", + Inputs: extractedAppSetPaths, Args: map[string]string{ "ro_paths": strings.Join(readOnlyPaths, " "), "exec_paths": strings.Join(executablePaths, " "), + "apk_paths": strings.Join(extractedAppSetDirs, " "), }, }) diff --git a/java/app.go b/java/app.go index 5bc09ff4d..9f024410a 100755 --- a/java/app.go +++ b/java/app.go @@ -96,6 +96,14 @@ func (as *AndroidAppSet) Privileged() bool { return Bool(as.properties.Privileged) } +func (as *AndroidAppSet) OutputFile() android.Path { + return as.packedOutput +} + +func (as *AndroidAppSet) MasterFile() string { + return as.masterFile +} + var TargetCpuAbi = map[string]string{ "arm": "ARMEABI_V7A", "arm64": "ARM64_V8A", @@ -120,7 +128,7 @@ func SupportedAbis(ctx android.ModuleContext) []string { } func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { - as.packedOutput = android.PathForModuleOut(ctx, "extracted.zip") + as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip") // We are assuming here that the master file in the APK // set has `.apk` suffix. If it doesn't the build will fail. // APK sets containing APEX files are handled elsewhere. @@ -145,26 +153,17 @@ func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) "stem": ctx.ModuleName(), }, }) - // TODO(asmundak): add this (it's wrong now, will cause copying extracted.zip) - /* - var installDir android.InstallPath - if Bool(as.properties.Privileged) { - installDir = android.PathForModuleInstall(ctx, "priv-app", as.BaseModuleName()) - } else if ctx.InstallInTestcases() { - installDir = android.PathForModuleInstall(ctx, as.BaseModuleName(), ctx.DeviceConfig().DeviceArch()) - } else { - installDir = android.PathForModuleInstall(ctx, "app", as.BaseModuleName()) - } - ctx.InstallFile(installDir, as.masterFile", as.packedOutput) - */ } // android_app_set extracts a set of APKs based on the target device // configuration and installs this set as "split APKs". -// The set will always contain `base-master.apk` and every APK built -// to the target device. All density-specific APK will be included, too, -// unless PRODUCT_APPT_PREBUILT_DPI is defined (should contain comma-sepearated -// list of density names (LDPI, MDPI, HDPI, etc.) +// The extracted set always contains 'master' APK whose name is +// _module_name_.apk and every split APK matching target device. +// The extraction of the density-specific splits depends on +// PRODUCT_AAPT_PREBUILT_DPI variable. If present (its value should +// be a list density names: LDPI, MDPI, HDPI, etc.), only listed +// splits will be extracted. Otherwise all density-specific splits +// will be extracted. func AndroidApkSetFactory() android.Module { module := &AndroidAppSet{} module.AddProperties(&module.properties) @@ -335,7 +334,7 @@ type Certificate struct { presigned bool } -var presignedCertificate = Certificate{presigned: true} +var PresignedCertificate = Certificate{presigned: true} func (c Certificate) AndroidMkString() string { if c.presigned { @@ -1196,7 +1195,7 @@ type OverrideAndroidApp struct { android.OverrideModuleBase } -func (i *OverrideAndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { +func (i *OverrideAndroidApp) GenerateAndroidBuildActions(_ android.ModuleContext) { // All the overrides happen in the base module. // TODO(jungjw): Check the base module type. } @@ -1217,7 +1216,7 @@ type OverrideAndroidTest struct { android.OverrideModuleBase } -func (i *OverrideAndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { +func (i *OverrideAndroidTest) GenerateAndroidBuildActions(_ android.ModuleContext) { // All the overrides happen in the base module. // TODO(jungjw): Check the base module type. } @@ -1239,7 +1238,7 @@ type OverrideRuntimeResourceOverlay struct { android.OverrideModuleBase } -func (i *OverrideRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) { +func (i *OverrideRuntimeResourceOverlay) GenerateAndroidBuildActions(_ android.ModuleContext) { // All the overrides happen in the base module. // TODO(jungjw): Check the base module type. } @@ -1483,7 +1482,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext // Sign or align the package if package has not been preprocessed if a.preprocessed { a.outputFile = srcApk - a.certificate = presignedCertificate + a.certificate = PresignedCertificate } else if !Bool(a.properties.Presigned) { // If the certificate property is empty at this point, default_dev_cert must be set to true. // Which makes processMainCert's behavior for the empty cert string WAI. @@ -1503,7 +1502,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename) TransformZipAlign(ctx, alignedApk, dexOutput) a.outputFile = alignedApk - a.certificate = presignedCertificate + a.certificate = PresignedCertificate } // TODO: Optionally compress the output apk. diff --git a/java/app_test.go b/java/app_test.go index e686f2780..956cbab86 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -149,7 +149,7 @@ func TestAndroidAppSet(t *testing.T) { prerelease: true, }`) module := ctx.ModuleForTests("foo", "android_common") - const packedSplitApks = "extracted.zip" + const packedSplitApks = "foo.zip" params := module.Output(packedSplitApks) if params.Rule == nil { t.Errorf("expected output %s is missing", packedSplitApks) @@ -218,7 +218,7 @@ func TestAndroidAppSet_Variants(t *testing.T) { ctx := testContext() run(t, ctx, config) module := ctx.ModuleForTests("foo", "android_common") - const packedSplitApks = "extracted.zip" + const packedSplitApks = "foo.zip" params := module.Output(packedSplitApks) for k, v := range test.expected { if actual := params.Args[k]; actual != v { -- cgit v1.2.3-59-g8ed1b From 829b7135f3d9b0287b03c01761da60cf2b194688 Mon Sep 17 00:00:00 2001 From: Jaewoong Jung Date: Wed, 10 Jun 2020 12:23:32 -0700 Subject: Use Targets[Android] instead of DeviceArch funcs. NDK prebuit script doesn't set device arch product variables, and so causes SupportedAbis to panic. Fixes: 158673325 Test: app_test.go, apex_test.go Test: build-ndk-prebuilts.sh Change-Id: I8331ef5bca12301318510ec9712770fd8d3a26a9 --- apex/apex_test.go | 6 ++++-- java/app.go | 10 +++++----- java/app_test.go | 32 +++++++++++++++++--------------- 3 files changed, 26 insertions(+), 22 deletions(-) (limited to 'java/app_test.go') diff --git a/apex/apex_test.go b/apex/apex_test.go index 24b93ecfd..ff2d7f98a 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -4786,8 +4786,10 @@ func TestApexSet(t *testing.T) { } `, func(fs map[string][]byte, config android.Config) { config.TestProductVariables.Platform_sdk_version = intPtr(30) - config.TestProductVariables.DeviceArch = proptools.StringPtr("arm") - config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm64") + config.Targets[android.Android] = []android.Target{ + {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}}, + {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}}, + } }) m := ctx.ModuleForTests("myapex", "android_common") diff --git a/java/app.go b/java/app.go index 9f024410a..ba0565751 100755 --- a/java/app.go +++ b/java/app.go @@ -112,17 +112,17 @@ var TargetCpuAbi = map[string]string{ } func SupportedAbis(ctx android.ModuleContext) []string { - abiName := func(archVar string, deviceArch string) string { + abiName := func(targetIdx int, deviceArch string) string { if abi, found := TargetCpuAbi[deviceArch]; found { return abi } - ctx.ModuleErrorf("Invalid %s: %s", archVar, deviceArch) + ctx.ModuleErrorf("Target %d has invalid Arch: %s", targetIdx, deviceArch) return "BAD_ABI" } - result := []string{abiName("TARGET_ARCH", ctx.DeviceConfig().DeviceArch())} - if s := ctx.DeviceConfig().DeviceSecondaryArch(); s != "" { - result = append(result, abiName("TARGET_2ND_ARCH", s)) + var result []string + for i, target := range ctx.Config().Targets[android.Android] { + result = append(result, abiName(i, target.Arch.ArchType.String())) } return result } diff --git a/java/app_test.go b/java/app_test.go index 956cbab86..1123d84d9 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -173,16 +173,17 @@ func TestAndroidAppSet_Variants(t *testing.T) { set: "prebuilts/apks/app.apks", }` testCases := []struct { - name string - deviceArch *string - deviceSecondaryArch *string - aaptPrebuiltDPI []string - sdkVersion int - expected map[string]string + name string + targets []android.Target + aaptPrebuiltDPI []string + sdkVersion int + expected map[string]string }{ { - name: "One", - deviceArch: proptools.StringPtr("x86"), + name: "One", + targets: []android.Target{ + {Os: android.Android, Arch: android.Arch{ArchType: android.X86}}, + }, aaptPrebuiltDPI: []string{"ldpi", "xxhdpi"}, sdkVersion: 29, expected: map[string]string{ @@ -194,11 +195,13 @@ func TestAndroidAppSet_Variants(t *testing.T) { }, }, { - name: "Two", - deviceArch: proptools.StringPtr("x86_64"), - deviceSecondaryArch: proptools.StringPtr("x86"), - aaptPrebuiltDPI: nil, - sdkVersion: 30, + name: "Two", + targets: []android.Target{ + {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64}}, + {Os: android.Android, Arch: android.Arch{ArchType: android.X86}}, + }, + aaptPrebuiltDPI: nil, + sdkVersion: 30, expected: map[string]string{ "abis": "X86_64,X86", "allow-prereleased": "false", @@ -213,8 +216,7 @@ func TestAndroidAppSet_Variants(t *testing.T) { config := testAppConfig(nil, bp, nil) config.TestProductVariables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI config.TestProductVariables.Platform_sdk_version = &test.sdkVersion - config.TestProductVariables.DeviceArch = test.deviceArch - config.TestProductVariables.DeviceSecondaryArch = test.deviceSecondaryArch + config.Targets[android.Android] = test.targets ctx := testContext() run(t, ctx, config) module := ctx.ModuleForTests("foo", "android_common") -- cgit v1.2.3-59-g8ed1b From f5f663b0c392a0a0ed3b9872bb0b3d3b2bb47fba Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Sun, 7 Jun 2020 16:58:18 -0700 Subject: Remove most paths from java.TestConfig Now that tests don't need to specify every path passed to PathForSource or PathForModuleSrc, remove most of them from java.TestConfig. Leave a few that are globbed by lots of tests, and move a few that are globbed by a single test into the tests. Bug: 153485543 Test: all soong tests Change-Id: Ica91d7203a6a7dbca0fd4fed84c78f149b8699e1 Merged-In: Ica91d7203a6a7dbca0fd4fed84c78f149b8699e1 (cherry picked from commit 238c1f3903eef027c7f1f9448bb6bcc6d4c669cd) --- java/app_test.go | 9 +++++++-- java/droiddoc.go | 2 +- java/java_test.go | 46 +++++++++++++++++++++++++++++++----------- java/testing.go | 60 ------------------------------------------------------- 4 files changed, 42 insertions(+), 75 deletions(-) (limited to 'java/app_test.go') diff --git a/java/app_test.go b/java/app_test.go index 1123d84d9..4d47496d2 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2719,7 +2719,7 @@ func TestCodelessApp(t *testing.T) { } func TestEmbedNotice(t *testing.T) { - ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` + ctx, _ := testJavaWithFS(t, cc.GatherRequiredDepsForTest(android.Android)+` android_app { name: "foo", srcs: ["a.java"], @@ -2775,7 +2775,12 @@ func TestEmbedNotice(t *testing.T) { srcs: ["b.java"], notice: "TOOL_NOTICE", } - `) + `, map[string][]byte{ + "APP_NOTICE": nil, + "GENRULE_NOTICE": nil, + "LIB_NOTICE": nil, + "TOOL_NOTICE": nil, + }) // foo has NOTICE files to process, and embed_notices is true. foo := ctx.ModuleForTests("foo", "android_common") diff --git a/java/droiddoc.go b/java/droiddoc.go index 6e986505e..8db688fec 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -1471,7 +1471,7 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi FlagWithInput("@", srcJarList). FlagWithOutput("--strict-input-files:warn ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt")) - if implicitsRsp.String() != "" { + if implicitsRsp != nil { cmd.FlagWithArg("--strict-input-files-exempt ", "@"+implicitsRsp.String()) } diff --git a/java/java_test.go b/java/java_test.go index 99f67ae74..f0de52fb9 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -142,9 +142,14 @@ func testJavaErrorWithConfig(t *testing.T, pattern string, config android.Config return ctx, config } +func testJavaWithFS(t *testing.T, bp string, fs map[string][]byte) (*android.TestContext, android.Config) { + t.Helper() + return testJavaWithConfig(t, testConfig(nil, bp, fs)) +} + func testJava(t *testing.T, bp string) (*android.TestContext, android.Config) { t.Helper() - return testJavaWithConfig(t, testConfig(nil, bp, nil)) + return testJavaWithFS(t, bp, nil) } func testJavaWithConfig(t *testing.T, config android.Config) (*android.TestContext, android.Config) { @@ -740,7 +745,7 @@ func TestResources(t *testing.T) { for _, test := range table { t.Run(test.name, func(t *testing.T) { - ctx, _ := testJava(t, ` + ctx, _ := testJavaWithFS(t, ` java_library { name: "foo", srcs: [ @@ -750,7 +755,13 @@ func TestResources(t *testing.T) { ], `+test.prop+`, } - `+test.extra) + `+test.extra, + map[string][]byte{ + "java-res/a/a": nil, + "java-res/b/b": nil, + "java-res2/a": nil, + }, + ) foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar") fooRes := ctx.ModuleForTests("foo", "android_common").Output("res/foo.jar") @@ -769,7 +780,7 @@ func TestResources(t *testing.T) { } func TestIncludeSrcs(t *testing.T) { - ctx, _ := testJava(t, ` + ctx, _ := testJavaWithFS(t, ` java_library { name: "foo", srcs: [ @@ -790,7 +801,11 @@ func TestIncludeSrcs(t *testing.T) { java_resource_dirs: ["java-res"], include_srcs: true, } - `) + `, map[string][]byte{ + "java-res/a/a": nil, + "java-res/b/b": nil, + "java-res2/a": nil, + }) // Test a library with include_srcs: true foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar") @@ -832,7 +847,7 @@ func TestIncludeSrcs(t *testing.T) { } func TestGeneratedSources(t *testing.T) { - ctx, _ := testJava(t, ` + ctx, _ := testJavaWithFS(t, ` java_library { name: "foo", srcs: [ @@ -847,7 +862,10 @@ func TestGeneratedSources(t *testing.T) { tool_files: ["java-res/a"], out: ["gen.java"], } - `) + `, map[string][]byte{ + "a.java": nil, + "b.java": nil, + }) javac := ctx.ModuleForTests("foo", "android_common").Rule("javac") genrule := ctx.ModuleForTests("gen", "").Rule("generator") @@ -932,7 +950,7 @@ func TestSharding(t *testing.T) { } func TestDroiddoc(t *testing.T) { - ctx, _ := testJava(t, ` + ctx, _ := testJavaWithFS(t, ` droiddoc_exported_dir { name: "droiddoc-templates-sdk", path: ".", @@ -945,7 +963,7 @@ func TestDroiddoc(t *testing.T) { droiddoc { name: "bar-doc", srcs: [ - "bar-doc/*.java", + "bar-doc/a.java", "bar-doc/IFoo.aidl", ":bar-doc-aidl-srcs", ], @@ -963,7 +981,11 @@ func TestDroiddoc(t *testing.T) { todo_file: "libcore-docs-todo.html", args: "-offlinemode -title \"libcore\"", } - `) + `, + map[string][]byte{ + "bar-doc/a.java": nil, + "bar-doc/b.java": nil, + }) barDoc := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc") var javaSrcs []string @@ -989,7 +1011,7 @@ func TestDroidstubsWithSystemModules(t *testing.T) { droidstubs { name: "stubs-source-system-modules", srcs: [ - "bar-doc/*.java", + "bar-doc/a.java", ], sdk_version: "none", system_modules: "source-system-modules", @@ -1010,7 +1032,7 @@ func TestDroidstubsWithSystemModules(t *testing.T) { droidstubs { name: "stubs-prebuilt-system-modules", srcs: [ - "bar-doc/*.java", + "bar-doc/a.java", ], sdk_version: "none", system_modules: "prebuilt-system-modules", diff --git a/java/testing.go b/java/testing.go index 552055efd..48e449f34 100644 --- a/java/testing.go +++ b/java/testing.go @@ -25,33 +25,12 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string bp += GatherRequiredDepsForTest() mockFS := map[string][]byte{ - "a.java": nil, - "b.java": nil, - "c.java": nil, - "b.kt": nil, - "a.jar": nil, - "b.jar": nil, - "c.jar": nil, - "APP_NOTICE": nil, - "GENRULE_NOTICE": nil, - "LIB_NOTICE": nil, - "TOOL_NOTICE": nil, - "AndroidTest.xml": nil, - "java-res/a/a": nil, - "java-res/b/b": nil, - "java-res2/a": nil, - "java-fg/a.java": nil, - "java-fg/b.java": nil, - "java-fg/c.java": nil, "api/current.txt": nil, "api/removed.txt": nil, "api/system-current.txt": nil, "api/system-removed.txt": nil, "api/test-current.txt": nil, "api/test-removed.txt": nil, - "framework/aidl/a.aidl": nil, - "assets_a/a": nil, - "assets_b/b": nil, "prebuilts/sdk/14/public/android.jar": nil, "prebuilts/sdk/14/public/framework.aidl": nil, @@ -102,45 +81,6 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string "prebuilts/sdk/tools/core-lambda-stubs.jar": nil, "prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"],}`), - "prebuilts/apk/app.apk": nil, - "prebuilts/apk/app_arm.apk": nil, - "prebuilts/apk/app_arm64.apk": nil, - "prebuilts/apk/app_xhdpi.apk": nil, - "prebuilts/apk/app_xxhdpi.apk": nil, - - "prebuilts/apks/app.apks": nil, - - // For framework-res, which is an implicit dependency for framework - "AndroidManifest.xml": nil, - "build/make/target/product/security/testkey": nil, - - "build/soong/scripts/jar-wrapper.sh": nil, - - "build/make/core/verify_uses_libraries.sh": nil, - - "build/make/core/proguard.flags": nil, - "build/make/core/proguard_basic_keeps.flags": nil, - - "jdk8/jre/lib/jce.jar": nil, - "jdk8/jre/lib/rt.jar": nil, - "jdk8/lib/tools.jar": nil, - - "bar-doc/a.java": nil, - "bar-doc/b.java": nil, - "bar-doc/IFoo.aidl": nil, - "bar-doc/IBar.aidl": nil, - "bar-doc/known_oj_tags.txt": nil, - "external/doclava/templates-sdk": nil, - - "cert/new_cert.x509.pem": nil, - "cert/new_cert.pk8": nil, - "lineage.bin": nil, - - "testdata/data": nil, - - "stubs-sources/foo/Foo.java": nil, - "stubs/sources/foo/Foo.java": nil, - // For java_sdk_library "api/module-lib-current.txt": nil, "api/module-lib-removed.txt": nil, -- cgit v1.2.3-59-g8ed1b From 8bec026e3ad643fa5c8a65e8e75df6138518e340 Mon Sep 17 00:00:00 2001 From: Jaewoong Jung Date: Mon, 29 Jun 2020 19:18:44 -0700 Subject: Output apkcerts file for android_app_set. Soong and Make have no ways to figure out what splits will be outputted from a given android_app_set, so it's impossible for them to provide full PACKAGES.$(LOCAL_MODULE).CERTIFICATE entries, which are required to build a final apkcerts.txt. This change makes extract_apks produce apkcerts.txt files for each input modules instead. The Make-side counterpart of this change merges all local apkcerts.txt into a final one. Fixes: 160119159 Test: main_test.go Test: m apkcerts-list Change-Id: I321e80fd636a955213761f56a3ac64bfe7f7f7c0 --- cmd/extract_apks/main.go | 39 ++++++++++++++++++++++++++++++++------- cmd/extract_apks/main_test.go | 38 +++++++++++++++++++++++++++----------- java/androidmk.go | 1 + java/app.go | 13 +++++++++---- java/app_test.go | 5 ++++- java/builder.go | 3 ++- 6 files changed, 75 insertions(+), 24 deletions(-) (limited to 'java/app_test.go') diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go index e9a850ee8..db54ffbaf 100644 --- a/cmd/extract_apks/main.go +++ b/cmd/extract_apks/main.go @@ -24,6 +24,7 @@ import ( "math" "os" "regexp" + "sort" "strings" "github.com/golang/protobuf/proto" @@ -355,7 +356,7 @@ type Zip2ZipWriter interface { // Writes out selected entries, renaming them as needed func (apkSet *ApkSet) writeApks(selected SelectionResult, config TargetConfig, - writer Zip2ZipWriter) error { + writer Zip2ZipWriter, partition string) ([]string, error) { // Renaming rules: // splits/MODULE-master.apk to STEM.apk // else @@ -389,10 +390,11 @@ func (apkSet *ApkSet) writeApks(selected SelectionResult, config TargetConfig, } entryOrigin := make(map[string]string) // output entry to input entry + var apkcerts []string for _, apk := range selected.entries { apkFile, ok := apkSet.entries[apk] if !ok { - return fmt.Errorf("TOC refers to an entry %s which does not exist", apk) + return nil, fmt.Errorf("TOC refers to an entry %s which does not exist", apk) } inName := apkFile.Name outName, ok := renamer(inName) @@ -405,10 +407,15 @@ func (apkSet *ApkSet) writeApks(selected SelectionResult, config TargetConfig, } entryOrigin[outName] = inName if err := writer.CopyFrom(apkFile, outName); err != nil { - return err + return nil, err + } + if partition != "" { + apkcerts = append(apkcerts, fmt.Sprintf( + `name="%s" certificate="PRESIGNED" private_key="" partition="%s"`, outName, partition)) } } - return nil + sort.Strings(apkcerts) + return apkcerts, nil } func (apkSet *ApkSet) extractAndCopySingle(selected SelectionResult, outFile *os.File) error { @@ -433,6 +440,9 @@ var ( } extractSingle = flag.Bool("extract-single", false, "extract a single target and output it uncompressed. only available for standalone apks and apexes.") + apkcertsOutput = flag.String("apkcerts", "", + "optional apkcerts.txt output file containing signing info of all outputted apks") + partition = flag.String("partition", "", "partition string. required when -apkcerts is used.") ) // Parse abi values @@ -485,7 +495,8 @@ func (s screenDensityFlagValue) Set(densityList string) error { func processArgs() { flag.Usage = func() { fmt.Fprintln(os.Stderr, `usage: extract_apks -o -sdk-version value -abis value `+ - `-screen-densities value {-stem value | -extract-single} [-allow-prereleased] `) + `-screen-densities value {-stem value | -extract-single} [-allow-prereleased] `+ + `[-apkcerts -partition ] `) flag.PrintDefaults() os.Exit(2) } @@ -498,7 +509,8 @@ func processArgs() { "allow prereleased") flag.StringVar(&targetConfig.stem, "stem", "", "output entries base name in the output zip file") flag.Parse() - if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 || (targetConfig.stem == "" && !*extractSingle) { + if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 || + (targetConfig.stem == "" && !*extractSingle) || (*apkcertsOutput != "" && *partition == "") { flag.Usage() } targetConfig.sdkVersion = int32(*version) @@ -536,7 +548,20 @@ func main() { log.Fatal(err) } }() - err = apkSet.writeApks(sel, targetConfig, writer) + apkcerts, err := apkSet.writeApks(sel, targetConfig, writer, *partition) + if err == nil && *apkcertsOutput != "" { + apkcertsFile, err := os.Create(*apkcertsOutput) + if err != nil { + log.Fatal(err) + } + defer apkcertsFile.Close() + for _, a := range apkcerts { + _, err = apkcertsFile.WriteString(a + "\n") + if err != nil { + log.Fatal(err) + } + } + } } if err != nil { log.Fatal(err) diff --git a/cmd/extract_apks/main_test.go b/cmd/extract_apks/main_test.go index bdd4becce..c3e6a2def 100644 --- a/cmd/extract_apks/main_test.go +++ b/cmd/extract_apks/main_test.go @@ -16,10 +16,11 @@ package main import ( "fmt" - "github.com/golang/protobuf/proto" "reflect" "testing" + "github.com/golang/protobuf/proto" + bp "android/soong/cmd/extract_apks/bundle_proto" "android/soong/third_party/zip" ) @@ -430,48 +431,63 @@ func (w testZip2ZipWriter) CopyFrom(file *zip.File, out string) error { return nil } -type testCaseWriteZip struct { +type testCaseWriteApks struct { name string moduleName string stem string + partition string // what we write from what - expected map[string]string + expectedZipEntries map[string]string + expectedApkcerts []string } -func TestWriteZip(t *testing.T) { - testCases := []testCaseWriteZip{ +func TestWriteApks(t *testing.T) { + testCases := []testCaseWriteApks{ { name: "splits", moduleName: "mybase", stem: "Foo", - expected: map[string]string{ + partition: "system", + expectedZipEntries: map[string]string{ "Foo.apk": "splits/mybase-master.apk", "Foo-xhdpi.apk": "splits/mybase-xhdpi.apk", }, + expectedApkcerts: []string{ + `name="Foo-xhdpi.apk" certificate="PRESIGNED" private_key="" partition="system"`, + `name="Foo.apk" certificate="PRESIGNED" private_key="" partition="system"`, + }, }, { name: "universal", moduleName: "base", stem: "Bar", - expected: map[string]string{ + partition: "product", + expectedZipEntries: map[string]string{ "Bar.apk": "universal.apk", }, + expectedApkcerts: []string{ + `name="Bar.apk" certificate="PRESIGNED" private_key="" partition="product"`, + }, }, } for _, testCase := range testCases { apkSet := ApkSet{entries: make(map[string]*zip.File)} sel := SelectionResult{moduleName: testCase.moduleName} - for _, in := range testCase.expected { + for _, in := range testCase.expectedZipEntries { apkSet.entries[in] = &zip.File{FileHeader: zip.FileHeader{Name: in}} sel.entries = append(sel.entries, in) } writer := testZip2ZipWriter{make(map[string]string)} config := TargetConfig{stem: testCase.stem} - if err := apkSet.writeApks(sel, config, writer); err != nil { + apkcerts, err := apkSet.writeApks(sel, config, writer, testCase.partition) + if err != nil { t.Error(err) } - if !reflect.DeepEqual(testCase.expected, writer.entries) { - t.Errorf("expected %v, got %v", testCase.expected, writer.entries) + if !reflect.DeepEqual(testCase.expectedZipEntries, writer.entries) { + t.Errorf("expected zip entries %v, got %v", testCase.expectedZipEntries, writer.entries) + } + if !reflect.DeepEqual(testCase.expectedApkcerts, apkcerts) { + t.Errorf("expected apkcerts %v, got %v", testCase.expectedApkcerts, apkcerts) } } } diff --git a/java/androidmk.go b/java/androidmk.go index 75fb5fb02..8953c31c1 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -716,6 +716,7 @@ func (apkSet *AndroidAppSet) AndroidMkEntries() []android.AndroidMkEntries { func(entries *android.AndroidMkEntries) { entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", apkSet.Privileged()) entries.SetString("LOCAL_APK_SET_MASTER_FILE", apkSet.masterFile) + entries.SetPath("LOCAL_APKCERTS_FILE", apkSet.apkcertsFile) entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...) }, }, diff --git a/java/app.go b/java/app.go index e2e3a53d7..3f12e91c0 100755 --- a/java/app.go +++ b/java/app.go @@ -78,6 +78,7 @@ type AndroidAppSet struct { properties AndroidAppSetProperties packedOutput android.WritablePath masterFile string + apkcertsFile android.ModuleOutPath } func (as *AndroidAppSet) Name() string { @@ -129,6 +130,7 @@ func SupportedAbis(ctx android.ModuleContext) []string { func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip") + as.apkcertsFile = android.PathForModuleOut(ctx, "apkcerts.txt") // We are assuming here that the master file in the APK // set has `.apk` suffix. If it doesn't the build will fail. // APK sets containing APEX files are handled elsewhere. @@ -141,16 +143,19 @@ func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) // TODO(asmundak): do we support device features ctx.Build(pctx, android.BuildParams{ - Rule: extractMatchingApks, - Description: "Extract APKs from APK set", - Output: as.packedOutput, - Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)}, + Rule: extractMatchingApks, + Description: "Extract APKs from APK set", + Output: as.packedOutput, + ImplicitOutput: as.apkcertsFile, + Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)}, Args: map[string]string{ "abis": strings.Join(SupportedAbis(ctx), ","), "allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)), "screen-densities": screenDensities, "sdk-version": ctx.Config().PlatformSdkVersion(), "stem": as.BaseModuleName(), + "apkcerts": as.apkcertsFile.String(), + "partition": as.PartitionTag(ctx.DeviceConfig()), }, }) } diff --git a/java/app_test.go b/java/app_test.go index 4d47496d2..8ef315206 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -147,7 +147,7 @@ func TestAndroidAppSet(t *testing.T) { name: "foo", set: "prebuilts/apks/app.apks", prerelease: true, - }`) + }`) module := ctx.ModuleForTests("foo", "android_common") const packedSplitApks = "foo.zip" params := module.Output(packedSplitApks) @@ -157,6 +157,9 @@ func TestAndroidAppSet(t *testing.T) { if s := params.Args["allow-prereleased"]; s != "true" { t.Errorf("wrong allow-prereleased value: '%s', expected 'true'", s) } + if s := params.Args["partition"]; s != "system" { + t.Errorf("wrong partition value: '%s', expected 'system'", s) + } mkEntries := android.AndroidMkEntriesForTest(t, config, "", module.Module())[0] actualMaster := mkEntries.EntryMap["LOCAL_APK_SET_MASTER_FILE"] expectedMaster := []string{"foo.apk"} diff --git a/java/builder.go b/java/builder.go index a27e5c390..7318fcbad 100644 --- a/java/builder.go +++ b/java/builder.go @@ -120,10 +120,11 @@ var ( `${config.ExtractApksCmd} -o "${out}" -allow-prereleased=${allow-prereleased} ` + `-sdk-version=${sdk-version} -abis=${abis} ` + `--screen-densities=${screen-densities} --stem=${stem} ` + + `-apkcerts=${apkcerts} -partition=${partition} ` + `${in}`, CommandDeps: []string{"${config.ExtractApksCmd}"}, }, - "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem") + "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition") turbine, turbineRE = remoteexec.StaticRules(pctx, "turbine", blueprint.RuleParams{ -- cgit v1.2.3-59-g8ed1b From 9f9fd0236348b3c148727912f6db529b7951a2b8 Mon Sep 17 00:00:00 2001 From: Liz Kammer Date: Thu, 18 Jun 2020 19:44:06 +0000 Subject: Add android app property rename_resources_package This relands I70a43c2163709afc90262d74f975ce14a556cf55 with a property to disable renaming of the package in resource files to support compatibility with packages that would be infeasible to change without causing failures. When rename_resources_package is true, uses aapt2 flag to change the package name encoded in the resources table for override apps. Test: app_test.go Bug: 147434671 Change-Id: I3a051ddeb5979f9c0838d176656a1b5cf2677a9b --- java/app.go | 20 ++++++- java/app_test.go | 158 +++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 136 insertions(+), 42 deletions(-) (limited to 'java/app_test.go') diff --git a/java/app.go b/java/app.go index 5a0c637cc..517ffbf2d 100755 --- a/java/app.go +++ b/java/app.go @@ -268,6 +268,9 @@ type overridableAppProperties struct { // the logging parent of this app. Logging_parent *string + + // Whether to rename the package in resources to the override name rather than the base name. Defaults to true. + Rename_resources_package *bool } // runtime_resource_overlay properties that can be overridden by override_runtime_resource_overlay @@ -505,10 +508,23 @@ func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool { !a.IsForPlatform() || a.appProperties.AlwaysPackageNativeLibs } +func generateAaptRenamePackageFlags(packageName string, renameResourcesPackage bool) []string { + aaptFlags := []string{"--rename-manifest-package " + packageName} + if renameResourcesPackage { + // Required to rename the package name in the resources table. + aaptFlags = append(aaptFlags, "--rename-resources-package "+packageName) + } + return aaptFlags +} + func (a *AndroidApp) OverriddenManifestPackageName() string { return a.overriddenManifestPackageName } +func (a *AndroidApp) renameResourcesPackage() bool { + return proptools.BoolDefault(a.overridableAppProperties.Rename_resources_package, true) +} + func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis) @@ -541,7 +557,7 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { if !overridden { manifestPackageName = *a.overridableAppProperties.Package_name } - aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName) + aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, a.renameResourcesPackage())...) a.overriddenManifestPackageName = manifestPackageName } @@ -1784,7 +1800,7 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC if !overridden { manifestPackageName = *r.overridableProperties.Package_name } - aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName) + aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, false)...) } if r.overridableProperties.Target_package_name != nil { aaptLinkFlags = append(aaptLinkFlags, diff --git a/java/app_test.go b/java/app_test.go index 389f79b28..6b83cd2e1 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -1761,52 +1761,125 @@ func TestOverrideAndroidApp(t *testing.T) { base: "foo", package_name: "org.dandroid.bp", } + + override_android_app { + name: "baz_no_rename_resources", + base: "foo", + package_name: "org.dandroid.bp", + rename_resources_package: false, + } + + android_app { + name: "foo_no_rename_resources", + srcs: ["a.java"], + certificate: "expiredkey", + overrides: ["qux"], + rename_resources_package: false, + sdk_version: "current", + } + + override_android_app { + name: "baz_base_no_rename_resources", + base: "foo_no_rename_resources", + package_name: "org.dandroid.bp", + } + + override_android_app { + name: "baz_override_base_rename_resources", + base: "foo_no_rename_resources", + package_name: "org.dandroid.bp", + rename_resources_package: true, + } `) expectedVariants := []struct { - moduleName string - variantName string - apkName string - apkPath string - certFlag string - lineageFlag string - overrides []string - aaptFlag string - logging_parent string + name string + moduleName string + variantName string + apkName string + apkPath string + certFlag string + lineageFlag string + overrides []string + packageFlag string + renameResources bool + logging_parent string }{ { - moduleName: "foo", - variantName: "android_common", - apkPath: "/target/product/test_device/system/app/foo/foo.apk", - certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", - lineageFlag: "", - overrides: []string{"qux"}, - aaptFlag: "", - logging_parent: "", - }, - { - moduleName: "bar", - variantName: "android_common_bar", - apkPath: "/target/product/test_device/system/app/bar/bar.apk", - certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8", - lineageFlag: "--lineage lineage.bin", - overrides: []string{"qux", "foo"}, - aaptFlag: "", - logging_parent: "bah", - }, - { - moduleName: "baz", - variantName: "android_common_baz", - apkPath: "/target/product/test_device/system/app/baz/baz.apk", - certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", - lineageFlag: "", - overrides: []string{"qux", "foo"}, - aaptFlag: "--rename-manifest-package org.dandroid.bp", - logging_parent: "", + name: "foo", + moduleName: "foo", + variantName: "android_common", + apkPath: "/target/product/test_device/system/app/foo/foo.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux"}, + packageFlag: "", + renameResources: false, + logging_parent: "", + }, + { + name: "foo", + moduleName: "bar", + variantName: "android_common_bar", + apkPath: "/target/product/test_device/system/app/bar/bar.apk", + certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8", + lineageFlag: "--lineage lineage.bin", + overrides: []string{"qux", "foo"}, + packageFlag: "", + renameResources: false, + logging_parent: "bah", + }, + { + name: "foo", + moduleName: "baz", + variantName: "android_common_baz", + apkPath: "/target/product/test_device/system/app/baz/baz.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux", "foo"}, + packageFlag: "org.dandroid.bp", + renameResources: true, + logging_parent: "", + }, + { + name: "foo", + moduleName: "baz_no_rename_resources", + variantName: "android_common_baz_no_rename_resources", + apkPath: "/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux", "foo"}, + packageFlag: "org.dandroid.bp", + renameResources: false, + logging_parent: "", + }, + { + name: "foo_no_rename_resources", + moduleName: "baz_base_no_rename_resources", + variantName: "android_common_baz_base_no_rename_resources", + apkPath: "/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux", "foo_no_rename_resources"}, + packageFlag: "org.dandroid.bp", + renameResources: false, + logging_parent: "", + }, + { + name: "foo_no_rename_resources", + moduleName: "baz_override_base_rename_resources", + variantName: "android_common_baz_override_base_rename_resources", + apkPath: "/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux", "foo_no_rename_resources"}, + packageFlag: "org.dandroid.bp", + renameResources: true, + logging_parent: "", }, } for _, expected := range expectedVariants { - variant := ctx.ModuleForTests("foo", expected.variantName) + variant := ctx.ModuleForTests(expected.name, expected.variantName) // Check the final apk name outputs := variant.AllOutputs() @@ -1852,9 +1925,12 @@ func TestOverrideAndroidApp(t *testing.T) { // Check the package renaming flag, if exists. res := variant.Output("package-res.apk") aapt2Flags := res.Args["flags"] - if !strings.Contains(aapt2Flags, expected.aaptFlag) { - t.Errorf("package renaming flag, %q is missing in aapt2 link flags, %q", expected.aaptFlag, aapt2Flags) + checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) + expectedPackage := expected.packageFlag + if !expected.renameResources { + expectedPackage = "" } + checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expectedPackage) } } @@ -1991,6 +2067,7 @@ func TestOverrideAndroidTest(t *testing.T) { res := variant.Output("package-res.apk") aapt2Flags := res.Args["flags"] checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) + checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expected.packageFlag) checkAapt2LinkFlag(t, aapt2Flags, "rename-instrumentation-target-package", expected.targetPackageFlag) } } @@ -3208,6 +3285,7 @@ func TestOverrideRuntimeResourceOverlay(t *testing.T) { res := variant.Output("package-res.apk") aapt2Flags := res.Args["flags"] checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) + checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", "") checkAapt2LinkFlag(t, aapt2Flags, "rename-overlay-target-package", expected.targetPackageFlag) } } -- cgit v1.2.3-59-g8ed1b