Loading dexpreopt/class_loader_context.go +89 −0 Original line number Diff line number Diff line Loading @@ -210,6 +210,34 @@ type ClassLoaderContext struct { 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 // AnySdkVersion that stores unconditional CLC that is added regardless of the target SDK version. // Loading Loading @@ -408,6 +436,67 @@ func (clcMap ClassLoaderContextMap) Dump() string { 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. // Apply filters for individual libraries, mirroring what the PackageManager does when it // constructs class loader context on device. Loading dexpreopt/class_loader_context_test.go +105 −0 Original line number Diff line number Diff line Loading @@ -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) { if have == nil { t.Errorf("\nwant error: '%s'\nhave: none", want) Loading java/aar.go +6 −2 Original line number Diff line number Diff line Loading @@ -267,11 +267,15 @@ var extractAssetsRule = pctx.AndroidStaticRule("extractAssets", }) 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 := aaptLibs(ctx, sdkContext, classLoaderContexts) // Exclude any libraries from the supplied list. classLoaderContexts = classLoaderContexts.ExcludeLibs(excludedLibs) // App manifest file manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile) Loading Loading @@ -530,7 +534,7 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.aapt.isLibrary = true 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() Loading java/app.go +19 −1 Original line number Diff line number Diff line Loading @@ -425,7 +425,8 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { a.aapt.splitNames = a.appProperties.Package_splits 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 a.properties.Manifest = nil Loading Loading @@ -1211,6 +1212,23 @@ type UsesLibraryProperties struct { // 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. 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 Loading java/rro.go +1 −1 Original line number Diff line number Diff line Loading @@ -139,7 +139,7 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC aaptLinkFlags = append(aaptLinkFlags, "--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 _, certificates := collectAppDeps(ctx, r, false, false) Loading Loading
dexpreopt/class_loader_context.go +89 −0 Original line number Diff line number Diff line Loading @@ -210,6 +210,34 @@ type ClassLoaderContext struct { 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 // AnySdkVersion that stores unconditional CLC that is added regardless of the target SDK version. // Loading Loading @@ -408,6 +436,67 @@ func (clcMap ClassLoaderContextMap) Dump() string { 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. // Apply filters for individual libraries, mirroring what the PackageManager does when it // constructs class loader context on device. Loading
dexpreopt/class_loader_context_test.go +105 −0 Original line number Diff line number Diff line Loading @@ -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) { if have == nil { t.Errorf("\nwant error: '%s'\nhave: none", want) Loading
java/aar.go +6 −2 Original line number Diff line number Diff line Loading @@ -267,11 +267,15 @@ var extractAssetsRule = pctx.AndroidStaticRule("extractAssets", }) 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 := aaptLibs(ctx, sdkContext, classLoaderContexts) // Exclude any libraries from the supplied list. classLoaderContexts = classLoaderContexts.ExcludeLibs(excludedLibs) // App manifest file manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile) Loading Loading @@ -530,7 +534,7 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.aapt.isLibrary = true 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() Loading
java/app.go +19 −1 Original line number Diff line number Diff line Loading @@ -425,7 +425,8 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { a.aapt.splitNames = a.appProperties.Package_splits 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 a.properties.Manifest = nil Loading Loading @@ -1211,6 +1212,23 @@ type UsesLibraryProperties struct { // 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. 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 Loading
java/rro.go +1 −1 Original line number Diff line number Diff line Loading @@ -139,7 +139,7 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC aaptLinkFlags = append(aaptLinkFlags, "--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 _, certificates := collectAppDeps(ctx, r, false, false) Loading