Add platform_apis property to APEX module type
The property is used to allow non-updatable APEXes to use platform APIs
(e.g. symbols marked as "# platform-only").
Bug: 191637950
Test: m com.android.virt com.android.compos
Merged-In: Id2410b4e38a78ec2146a42298840954381a7c472
Change-Id: Id2410b4e38a78ec2146a42298840954381a7c472
(cherry picked from commit fb63625a7f
)
This commit is contained in:
@@ -54,6 +54,10 @@ type ApexInfo struct {
|
||||
// True if this module comes from an updatable apexBundle.
|
||||
Updatable bool
|
||||
|
||||
// True if this module can use private platform APIs. Only non-updatable APEX can set this
|
||||
// to true.
|
||||
UsePlatformApis bool
|
||||
|
||||
// The list of SDK modules that the containing apexBundle depends on.
|
||||
RequiredSdks SdkRefs
|
||||
|
||||
@@ -91,12 +95,17 @@ var ApexInfoProvider = blueprint.NewMutatorProvider(ApexInfo{}, "apex")
|
||||
// of a module can be deduped into one variation. For example, if libfoo is included in both apex.a
|
||||
// and apex.b, and if the two APEXes have the same min_sdk_version (say 29), then libfoo doesn't
|
||||
// have to be built twice, but only once. In that case, the two apex variations apex.a and apex.b
|
||||
// are configured to have the same alias variation named apex29.
|
||||
// are configured to have the same alias variation named apex29. Whether platform APIs is allowed
|
||||
// or not also matters; if two APEXes don't have the same allowance, they get different names and
|
||||
// thus wouldn't be merged.
|
||||
func (i ApexInfo) mergedName(ctx PathContext) string {
|
||||
name := "apex" + strconv.Itoa(i.MinSdkVersion.FinalOrFutureInt())
|
||||
for _, sdk := range i.RequiredSdks {
|
||||
name += "_" + sdk.Name + "_" + sdk.Version
|
||||
}
|
||||
if i.UsePlatformApis {
|
||||
name += "_private"
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
@@ -527,6 +536,10 @@ func mergeApexVariations(ctx PathContext, apexInfos []ApexInfo) (merged []ApexIn
|
||||
merged[index].InApexModules = append(merged[index].InApexModules, apexInfo.InApexModules...)
|
||||
merged[index].ApexContents = append(merged[index].ApexContents, apexInfo.ApexContents...)
|
||||
merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable
|
||||
if merged[index].UsePlatformApis != apexInfo.UsePlatformApis {
|
||||
panic(fmt.Errorf("variants having different UsePlatformApis can't be merged"))
|
||||
}
|
||||
merged[index].UsePlatformApis = apexInfo.UsePlatformApis
|
||||
} else {
|
||||
seen[mergedName] = len(merged)
|
||||
apexInfo.ApexVariationName = mergedName
|
||||
|
@@ -33,10 +33,10 @@ func Test_mergeApexVariations(t *testing.T) {
|
||||
{
|
||||
name: "single",
|
||||
in: []ApexInfo{
|
||||
{"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"foo", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
},
|
||||
wantMerged: []ApexInfo{
|
||||
{"apex10000", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"apex10000", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
},
|
||||
wantAliases: [][2]string{
|
||||
{"foo", "apex10000"},
|
||||
@@ -45,11 +45,11 @@ func Test_mergeApexVariations(t *testing.T) {
|
||||
{
|
||||
name: "merge",
|
||||
in: []ApexInfo{
|
||||
{"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"bar", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
{"foo", FutureApiLevel, false, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"bar", FutureApiLevel, false, false, SdkRefs{{"baz", "1"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
},
|
||||
wantMerged: []ApexInfo{
|
||||
{"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false}},
|
||||
{"apex10000_baz_1", FutureApiLevel, false, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false}},
|
||||
wantAliases: [][2]string{
|
||||
{"bar", "apex10000_baz_1"},
|
||||
{"foo", "apex10000_baz_1"},
|
||||
@@ -58,12 +58,12 @@ func Test_mergeApexVariations(t *testing.T) {
|
||||
{
|
||||
name: "don't merge version",
|
||||
in: []ApexInfo{
|
||||
{"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"bar", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
{"foo", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"bar", uncheckedFinalApiLevel(30), false, false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
},
|
||||
wantMerged: []ApexInfo{
|
||||
{"apex30", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
{"apex10000", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"apex30", uncheckedFinalApiLevel(30), false, false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
{"apex10000", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
},
|
||||
wantAliases: [][2]string{
|
||||
{"bar", "apex30"},
|
||||
@@ -73,11 +73,11 @@ func Test_mergeApexVariations(t *testing.T) {
|
||||
{
|
||||
name: "merge updatable",
|
||||
in: []ApexInfo{
|
||||
{"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"bar", FutureApiLevel, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
{"foo", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"bar", FutureApiLevel, true, false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
},
|
||||
wantMerged: []ApexInfo{
|
||||
{"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
|
||||
{"apex10000", FutureApiLevel, true, false, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
|
||||
},
|
||||
wantAliases: [][2]string{
|
||||
{"bar", "apex10000"},
|
||||
@@ -87,12 +87,12 @@ func Test_mergeApexVariations(t *testing.T) {
|
||||
{
|
||||
name: "don't merge sdks",
|
||||
in: []ApexInfo{
|
||||
{"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"bar", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
{"foo", FutureApiLevel, false, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"bar", FutureApiLevel, false, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
},
|
||||
wantMerged: []ApexInfo{
|
||||
{"apex10000_baz_2", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
{"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"apex10000_baz_2", FutureApiLevel, false, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
{"apex10000_baz_1", FutureApiLevel, false, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
},
|
||||
wantAliases: [][2]string{
|
||||
{"bar", "apex10000_baz_2"},
|
||||
@@ -102,21 +102,36 @@ func Test_mergeApexVariations(t *testing.T) {
|
||||
{
|
||||
name: "don't merge when for prebuilt_apex",
|
||||
in: []ApexInfo{
|
||||
{"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"bar", FutureApiLevel, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
{"foo", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"bar", FutureApiLevel, true, false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
// This one should not be merged in with the others because it is for
|
||||
// a prebuilt_apex.
|
||||
{"baz", FutureApiLevel, true, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
|
||||
{"baz", FutureApiLevel, true, false, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
|
||||
},
|
||||
wantMerged: []ApexInfo{
|
||||
{"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
|
||||
{"baz", FutureApiLevel, true, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
|
||||
{"apex10000", FutureApiLevel, true, false, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
|
||||
{"baz", FutureApiLevel, true, false, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
|
||||
},
|
||||
wantAliases: [][2]string{
|
||||
{"bar", "apex10000"},
|
||||
{"foo", "apex10000"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "don't merge different UsePlatformApis",
|
||||
in: []ApexInfo{
|
||||
{"foo", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
{"bar", FutureApiLevel, false, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
},
|
||||
wantMerged: []ApexInfo{
|
||||
{"apex10000_private", FutureApiLevel, false, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
|
||||
{"apex10000", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
|
||||
},
|
||||
wantAliases: [][2]string{
|
||||
{"bar", "apex10000_private"},
|
||||
{"foo", "apex10000"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
12
apex/apex.go
12
apex/apex.go
@@ -130,6 +130,10 @@ type apexBundleProperties struct {
|
||||
// symlinking to the system libs. Default is true.
|
||||
Updatable *bool
|
||||
|
||||
// Whether this APEX can use platform APIs or not. Can be set to true only when `updatable:
|
||||
// false`. Default is false.
|
||||
Platform_apis *bool
|
||||
|
||||
// Whether this APEX is installable to one of the partitions like system, vendor, etc.
|
||||
// Default: true.
|
||||
Installable *bool
|
||||
@@ -908,6 +912,7 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) {
|
||||
MinSdkVersion: minSdkVersion,
|
||||
RequiredSdks: a.RequiredSdks(),
|
||||
Updatable: a.Updatable(),
|
||||
UsePlatformApis: a.UsePlatformApis(),
|
||||
InApexVariants: []string{mctx.ModuleName()}, // could be com.android.foo
|
||||
InApexModules: []string{a.Name()}, // could be com.mycompany.android.foo
|
||||
ApexContents: []*android.ApexContents{apexContents},
|
||||
@@ -1274,6 +1279,10 @@ func (a *apexBundle) Updatable() bool {
|
||||
return proptools.BoolDefault(a.properties.Updatable, true)
|
||||
}
|
||||
|
||||
func (a *apexBundle) UsePlatformApis() bool {
|
||||
return proptools.BoolDefault(a.properties.Platform_apis, false)
|
||||
}
|
||||
|
||||
// getCertString returns the name of the cert that should be used to sign this APEX. This is
|
||||
// basically from the "certificate" property, but could be overridden by the device config.
|
||||
func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string {
|
||||
@@ -2317,6 +2326,9 @@ func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) {
|
||||
if String(a.properties.Min_sdk_version) == "" {
|
||||
ctx.PropertyErrorf("updatable", "updatable APEXes should set min_sdk_version as well")
|
||||
}
|
||||
if a.UsePlatformApis() {
|
||||
ctx.PropertyErrorf("updatable", "updatable APEXes can't use platform APIs")
|
||||
}
|
||||
a.checkJavaStableSdkVersion(ctx)
|
||||
a.checkClasspathFragments(ctx)
|
||||
}
|
||||
|
@@ -957,6 +957,79 @@ func TestApexWithStubs(t *testing.T) {
|
||||
ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
|
||||
}
|
||||
|
||||
func TestApexCanUsePrivateApis(t *testing.T) {
|
||||
ctx := testApex(t, `
|
||||
apex {
|
||||
name: "myapex",
|
||||
key: "myapex.key",
|
||||
native_shared_libs: ["mylib"],
|
||||
binaries: ["foo.rust"],
|
||||
updatable: false,
|
||||
platform_apis: true,
|
||||
}
|
||||
|
||||
apex_key {
|
||||
name: "myapex.key",
|
||||
public_key: "testkey.avbpubkey",
|
||||
private_key: "testkey.pem",
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "mylib",
|
||||
srcs: ["mylib.cpp"],
|
||||
shared_libs: ["mylib2"],
|
||||
system_shared_libs: [],
|
||||
stl: "none",
|
||||
apex_available: [ "myapex" ],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "mylib2",
|
||||
srcs: ["mylib.cpp"],
|
||||
cflags: ["-include mylib.h"],
|
||||
system_shared_libs: [],
|
||||
stl: "none",
|
||||
stubs: {
|
||||
versions: ["1", "2", "3"],
|
||||
},
|
||||
}
|
||||
|
||||
rust_binary {
|
||||
name: "foo.rust",
|
||||
srcs: ["foo.rs"],
|
||||
shared_libs: ["libfoo.shared_from_rust"],
|
||||
prefer_rlib: true,
|
||||
apex_available: ["myapex"],
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "libfoo.shared_from_rust",
|
||||
srcs: ["mylib.cpp"],
|
||||
system_shared_libs: [],
|
||||
stl: "none",
|
||||
stubs: {
|
||||
versions: ["10", "11", "12"],
|
||||
},
|
||||
}
|
||||
`)
|
||||
|
||||
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
|
||||
copyCmds := apexRule.Args["copy_commands"]
|
||||
|
||||
// Ensure that indirect stubs dep is not included
|
||||
ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
|
||||
ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
|
||||
|
||||
// Ensure that we are using non-stub variants of mylib2 and libfoo.shared_from_rust (because
|
||||
// of the platform_apis: true)
|
||||
mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000_private").Rule("ld").Args["libFlags"]
|
||||
ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so")
|
||||
ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
|
||||
rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000_private").Rule("rustc").Args["linkFlags"]
|
||||
ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
|
||||
ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
|
||||
}
|
||||
|
||||
func TestApexWithStubsWithMinSdkVersion(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := testApex(t, `
|
||||
|
10
cc/cc.go
10
cc/cc.go
@@ -2904,11 +2904,11 @@ func ChooseStubOrImpl(ctx android.ModuleContext, dep android.Module) (SharedLibr
|
||||
// of apex sdk enforcement below to choose right version.
|
||||
useStubs = true
|
||||
}
|
||||
} else if apexInfo.IsForPlatform() {
|
||||
// If not building for APEX, use stubs only when it is from
|
||||
// an APEX (and not from platform)
|
||||
// However, for host, ramdisk, vendor_ramdisk, recovery or bootstrap modules,
|
||||
// always link to non-stub variant
|
||||
} else if apexInfo.IsForPlatform() || apexInfo.UsePlatformApis {
|
||||
// If not building for APEX or the containing APEX allows the use of
|
||||
// platform APIs, use stubs only when it is from an APEX (and not from
|
||||
// platform) However, for host, ramdisk, vendor_ramdisk, recovery or
|
||||
// bootstrap modules, always link to non-stub variant
|
||||
useStubs = dep.(android.ApexModule).NotInPlatform() && !bootstrap
|
||||
if useStubs {
|
||||
// Another exception: if this module is a test for an APEX, then
|
||||
|
Reference in New Issue
Block a user