Merge "Add support for excluding libraries from class loader contexts"
This commit is contained in:
@@ -210,6 +210,34 @@ type ClassLoaderContext struct {
|
|||||||
Subcontexts []*ClassLoaderContext
|
Subcontexts []*ClassLoaderContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// excludeLibs excludes the libraries from this ClassLoaderContext.
|
||||||
|
//
|
||||||
|
// This treats the supplied context as being immutable (as it may come from a dependency). So, it
|
||||||
|
// implements copy-on-exclusion logic. That means that if any of the excluded libraries are used
|
||||||
|
// within this context then this will return a deep copy of this without those libraries.
|
||||||
|
//
|
||||||
|
// If this ClassLoaderContext matches one of the libraries to exclude then this returns (nil, true)
|
||||||
|
// to indicate that this context should be excluded from the containing list.
|
||||||
|
//
|
||||||
|
// If any of this ClassLoaderContext's Subcontexts reference the excluded libraries then this
|
||||||
|
// returns a pointer to a copy of this without the excluded libraries and true to indicate that this
|
||||||
|
// was copied.
|
||||||
|
//
|
||||||
|
// Otherwise, this returns a pointer to this and false to indicate that this was not copied.
|
||||||
|
func (c *ClassLoaderContext) excludeLibs(excludedLibs []string) (*ClassLoaderContext, bool) {
|
||||||
|
if android.InList(c.Name, excludedLibs) {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
|
||||||
|
if excludedList, modified := excludeLibsFromCLCList(c.Subcontexts, excludedLibs); modified {
|
||||||
|
clcCopy := *c
|
||||||
|
clcCopy.Subcontexts = excludedList
|
||||||
|
return &clcCopy, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, false
|
||||||
|
}
|
||||||
|
|
||||||
// ClassLoaderContextMap is a map from SDK version to CLC. There is a special entry with key
|
// ClassLoaderContextMap is a map from SDK version to CLC. There is a special entry with key
|
||||||
// AnySdkVersion that stores unconditional CLC that is added regardless of the target SDK version.
|
// AnySdkVersion that stores unconditional CLC that is added regardless of the target SDK version.
|
||||||
//
|
//
|
||||||
@@ -408,6 +436,67 @@ func (clcMap ClassLoaderContextMap) Dump() string {
|
|||||||
return string(bytes)
|
return string(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// excludeLibsFromCLCList excludes the libraries from the ClassLoaderContext in this list.
|
||||||
|
//
|
||||||
|
// This treats the supplied list as being immutable (as it may come from a dependency). So, it
|
||||||
|
// implements copy-on-exclusion logic. That means that if any of the excluded libraries are used
|
||||||
|
// within the contexts in the list then this will return a deep copy of the list without those
|
||||||
|
// libraries.
|
||||||
|
//
|
||||||
|
// If any of the ClassLoaderContext in the list reference the excluded libraries then this returns a
|
||||||
|
// copy of this list without the excluded libraries and true to indicate that this was copied.
|
||||||
|
//
|
||||||
|
// Otherwise, this returns the list and false to indicate that this was not copied.
|
||||||
|
func excludeLibsFromCLCList(clcList []*ClassLoaderContext, excludedLibs []string) ([]*ClassLoaderContext, bool) {
|
||||||
|
modifiedList := false
|
||||||
|
copiedList := make([]*ClassLoaderContext, 0, len(clcList))
|
||||||
|
for _, clc := range clcList {
|
||||||
|
resultClc, modifiedClc := clc.excludeLibs(excludedLibs)
|
||||||
|
if resultClc != nil {
|
||||||
|
copiedList = append(copiedList, resultClc)
|
||||||
|
}
|
||||||
|
modifiedList = modifiedList || modifiedClc
|
||||||
|
}
|
||||||
|
|
||||||
|
if modifiedList {
|
||||||
|
return copiedList, true
|
||||||
|
} else {
|
||||||
|
return clcList, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExcludeLibs excludes the libraries from the ClassLoaderContextMap.
|
||||||
|
//
|
||||||
|
// If the list o libraries is empty then this returns the ClassLoaderContextMap.
|
||||||
|
//
|
||||||
|
// This treats the ClassLoaderContextMap as being immutable (as it may come from a dependency). So,
|
||||||
|
// it implements copy-on-exclusion logic. That means that if any of the excluded libraries are used
|
||||||
|
// within the contexts in the map then this will return a deep copy of the map without those
|
||||||
|
// libraries.
|
||||||
|
//
|
||||||
|
// Otherwise, this returns the map unchanged.
|
||||||
|
func (clcMap ClassLoaderContextMap) ExcludeLibs(excludedLibs []string) ClassLoaderContextMap {
|
||||||
|
if len(excludedLibs) == 0 {
|
||||||
|
return clcMap
|
||||||
|
}
|
||||||
|
|
||||||
|
excludedClcMap := make(ClassLoaderContextMap)
|
||||||
|
modifiedMap := false
|
||||||
|
for sdkVersion, clcList := range clcMap {
|
||||||
|
excludedList, modifiedList := excludeLibsFromCLCList(clcList, excludedLibs)
|
||||||
|
if len(excludedList) != 0 {
|
||||||
|
excludedClcMap[sdkVersion] = excludedList
|
||||||
|
}
|
||||||
|
modifiedMap = modifiedMap || modifiedList
|
||||||
|
}
|
||||||
|
|
||||||
|
if modifiedMap {
|
||||||
|
return excludedClcMap
|
||||||
|
} else {
|
||||||
|
return clcMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Now that the full unconditional context is known, reconstruct conditional context.
|
// Now that the full unconditional context is known, reconstruct conditional context.
|
||||||
// Apply filters for individual libraries, mirroring what the PackageManager does when it
|
// Apply filters for individual libraries, mirroring what the PackageManager does when it
|
||||||
// constructs class loader context on device.
|
// constructs class loader context on device.
|
||||||
|
@@ -284,6 +284,111 @@ func TestCLCSdkVersionOrder(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCLCMExcludeLibs(t *testing.T) {
|
||||||
|
ctx := testContext()
|
||||||
|
const optional = false
|
||||||
|
const implicit = true
|
||||||
|
|
||||||
|
excludeLibs := func(t *testing.T, m ClassLoaderContextMap, excluded_libs ...string) ClassLoaderContextMap {
|
||||||
|
// Dump the CLCM before creating a new copy that excludes a specific set of libraries.
|
||||||
|
before := m.Dump()
|
||||||
|
|
||||||
|
// Create a new CLCM that excludes some libraries.
|
||||||
|
c := m.ExcludeLibs(excluded_libs)
|
||||||
|
|
||||||
|
// Make sure that the original CLCM was not changed.
|
||||||
|
after := m.Dump()
|
||||||
|
android.AssertStringEquals(t, "input CLCM modified", before, after)
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("exclude nothing", func(t *testing.T) {
|
||||||
|
m := make(ClassLoaderContextMap)
|
||||||
|
m.AddContext(ctx, 28, "a", optional, implicit, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
|
||||||
|
|
||||||
|
a := excludeLibs(t, m)
|
||||||
|
|
||||||
|
android.AssertStringEquals(t, "output CLCM ", `{
|
||||||
|
"28": [
|
||||||
|
{
|
||||||
|
"Name": "a",
|
||||||
|
"Optional": false,
|
||||||
|
"Implicit": true,
|
||||||
|
"Host": "out/soong/a.jar",
|
||||||
|
"Device": "/system/a.jar",
|
||||||
|
"Subcontexts": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`, a.Dump())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("one item from list", func(t *testing.T) {
|
||||||
|
m := make(ClassLoaderContextMap)
|
||||||
|
m.AddContext(ctx, 28, "a", optional, implicit, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
|
||||||
|
m.AddContext(ctx, 28, "b", optional, implicit, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
|
||||||
|
|
||||||
|
a := excludeLibs(t, m, "a")
|
||||||
|
|
||||||
|
expected := `{
|
||||||
|
"28": [
|
||||||
|
{
|
||||||
|
"Name": "b",
|
||||||
|
"Optional": false,
|
||||||
|
"Implicit": true,
|
||||||
|
"Host": "out/soong/b.jar",
|
||||||
|
"Device": "/system/b.jar",
|
||||||
|
"Subcontexts": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
android.AssertStringEquals(t, "output CLCM ", expected, a.Dump())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("all items from a list", func(t *testing.T) {
|
||||||
|
m := make(ClassLoaderContextMap)
|
||||||
|
m.AddContext(ctx, 28, "a", optional, implicit, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
|
||||||
|
m.AddContext(ctx, 28, "b", optional, implicit, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
|
||||||
|
|
||||||
|
a := excludeLibs(t, m, "a", "b")
|
||||||
|
|
||||||
|
android.AssertStringEquals(t, "output CLCM ", `{}`, a.Dump())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("items from a subcontext", func(t *testing.T) {
|
||||||
|
s := make(ClassLoaderContextMap)
|
||||||
|
s.AddContext(ctx, AnySdkVersion, "b", optional, implicit, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
|
||||||
|
s.AddContext(ctx, AnySdkVersion, "c", optional, implicit, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
|
||||||
|
|
||||||
|
m := make(ClassLoaderContextMap)
|
||||||
|
m.AddContext(ctx, 28, "a", optional, implicit, buildPath(ctx, "a"), installPath(ctx, "a"), s)
|
||||||
|
|
||||||
|
a := excludeLibs(t, m, "b")
|
||||||
|
|
||||||
|
android.AssertStringEquals(t, "output CLCM ", `{
|
||||||
|
"28": [
|
||||||
|
{
|
||||||
|
"Name": "a",
|
||||||
|
"Optional": false,
|
||||||
|
"Implicit": true,
|
||||||
|
"Host": "out/soong/a.jar",
|
||||||
|
"Device": "/system/a.jar",
|
||||||
|
"Subcontexts": [
|
||||||
|
{
|
||||||
|
"Name": "c",
|
||||||
|
"Optional": false,
|
||||||
|
"Implicit": true,
|
||||||
|
"Host": "out/soong/c.jar",
|
||||||
|
"Device": "/system/c.jar",
|
||||||
|
"Subcontexts": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`, a.Dump())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func checkError(t *testing.T, have error, want string) {
|
func checkError(t *testing.T, have error, want string) {
|
||||||
if have == nil {
|
if have == nil {
|
||||||
t.Errorf("\nwant error: '%s'\nhave: none", want)
|
t.Errorf("\nwant error: '%s'\nhave: none", want)
|
||||||
|
@@ -267,11 +267,15 @@ var extractAssetsRule = pctx.AndroidStaticRule("extractAssets",
|
|||||||
})
|
})
|
||||||
|
|
||||||
func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkContext,
|
func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkContext,
|
||||||
classLoaderContexts dexpreopt.ClassLoaderContextMap, extraLinkFlags ...string) {
|
classLoaderContexts dexpreopt.ClassLoaderContextMap, excludedLibs []string,
|
||||||
|
extraLinkFlags ...string) {
|
||||||
|
|
||||||
transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags :=
|
transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags :=
|
||||||
aaptLibs(ctx, sdkContext, classLoaderContexts)
|
aaptLibs(ctx, sdkContext, classLoaderContexts)
|
||||||
|
|
||||||
|
// Exclude any libraries from the supplied list.
|
||||||
|
classLoaderContexts = classLoaderContexts.ExcludeLibs(excludedLibs)
|
||||||
|
|
||||||
// App manifest file
|
// App manifest file
|
||||||
manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
|
manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
|
||||||
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
|
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
|
||||||
@@ -530,7 +534,7 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
|
|||||||
func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
a.aapt.isLibrary = true
|
a.aapt.isLibrary = true
|
||||||
a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
|
a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
|
||||||
a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts)
|
a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, nil)
|
||||||
|
|
||||||
a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
|
a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
|
||||||
|
|
||||||
|
20
java/app.go
20
java/app.go
@@ -425,7 +425,8 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
|
|||||||
|
|
||||||
a.aapt.splitNames = a.appProperties.Package_splits
|
a.aapt.splitNames = a.appProperties.Package_splits
|
||||||
a.aapt.LoggingParent = String(a.overridableAppProperties.Logging_parent)
|
a.aapt.LoggingParent = String(a.overridableAppProperties.Logging_parent)
|
||||||
a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, aaptLinkFlags...)
|
a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts,
|
||||||
|
a.usesLibraryProperties.Exclude_uses_libs, aaptLinkFlags...)
|
||||||
|
|
||||||
// apps manifests are handled by aapt, don't let Module see them
|
// apps manifests are handled by aapt, don't let Module see them
|
||||||
a.properties.Manifest = nil
|
a.properties.Manifest = nil
|
||||||
@@ -1211,6 +1212,23 @@ type UsesLibraryProperties struct {
|
|||||||
// libraries, because SDK ones are automatically picked up by Soong. The <uses-library> name
|
// libraries, because SDK ones are automatically picked up by Soong. The <uses-library> name
|
||||||
// normally is the same as the module name, but there are exceptions.
|
// normally is the same as the module name, but there are exceptions.
|
||||||
Provides_uses_lib *string
|
Provides_uses_lib *string
|
||||||
|
|
||||||
|
// A list of shared library names to exclude from the classpath of the APK. Adding a library here
|
||||||
|
// will prevent it from being used when precompiling the APK and prevent it from being implicitly
|
||||||
|
// added to the APK's manifest's <uses-library> elements.
|
||||||
|
//
|
||||||
|
// Care must be taken when using this as it could result in runtime errors if the APK actually
|
||||||
|
// uses classes provided by the library and which are not provided in any other way.
|
||||||
|
//
|
||||||
|
// This is primarily intended for use by various CTS tests that check the runtime handling of the
|
||||||
|
// android.test.base shared library (and related libraries) but which depend on some common
|
||||||
|
// libraries that depend on the android.test.base library. Without this those tests will end up
|
||||||
|
// with a <uses-library android:name="android.test.base"/> in their manifest which would either
|
||||||
|
// render the tests worthless (as they would be testing the wrong behavior), or would break the
|
||||||
|
// test altogether by providing access to classes that the tests were not expecting. Those tests
|
||||||
|
// provide the android.test.base statically and use jarjar to rename them so they do not collide
|
||||||
|
// with the classes provided by the android.test.base library.
|
||||||
|
Exclude_uses_libs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// usesLibrary provides properties and helper functions for AndroidApp and AndroidAppImport to verify that the
|
// usesLibrary provides properties and helper functions for AndroidApp and AndroidAppImport to verify that the
|
||||||
|
@@ -139,7 +139,7 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC
|
|||||||
aaptLinkFlags = append(aaptLinkFlags,
|
aaptLinkFlags = append(aaptLinkFlags,
|
||||||
"--rename-overlay-target-package "+*r.overridableProperties.Target_package_name)
|
"--rename-overlay-target-package "+*r.overridableProperties.Target_package_name)
|
||||||
}
|
}
|
||||||
r.aapt.buildActions(ctx, r, nil, aaptLinkFlags...)
|
r.aapt.buildActions(ctx, r, nil, nil, aaptLinkFlags...)
|
||||||
|
|
||||||
// Sign the built package
|
// Sign the built package
|
||||||
_, certificates := collectAppDeps(ctx, r, false, false)
|
_, certificates := collectAppDeps(ctx, r, false, false)
|
||||||
|
Reference in New Issue
Block a user