Loading android/apex.go +35 −4 Original line number Diff line number Diff line Loading @@ -280,6 +280,7 @@ type ApexProperties struct { // // "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX. // "//apex_available:platform" refers to non-APEX partitions like "system.img". // Prefix pattern (com.foo.*) can be used to match with any APEX name with the prefix(com.foo.). // Default is ["//apex_available:platform"]. Apex_available []string Loading Loading @@ -491,10 +492,27 @@ func CheckAvailableForApex(what string, apex_available []string) bool { if len(apex_available) == 0 { return what == AvailableToPlatform } return InList(what, apex_available) || (what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available)) || (what == "com.google.mainline.primary.libs") || // TODO b/248601389 (what == "com.google.mainline.go.primary.libs") // TODO b/248601389 // TODO b/248601389 if what == "com.google.mainline.primary.libs" || what == "com.google.mainline.go.primary.libs" { return true } for _, apex_name := range apex_available { // exact match. if apex_name == what { return true } // //apex_available:anyapex matches with any apex name, but not //apex_available:platform if apex_name == AvailableToAnyApex && what != AvailableToPlatform { return true } // prefix match. if strings.HasSuffix(apex_name, ".*") && strings.HasPrefix(what, strings.TrimSuffix(apex_name, "*")) { return true } } return false } // Implements ApexModule Loading Loading @@ -523,6 +541,19 @@ func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) { if n == AvailableToPlatform || n == AvailableToAnyApex { continue } // Prefix pattern should end with .* and has at least two components. if strings.Contains(n, "*") { if !strings.HasSuffix(n, ".*") { mctx.PropertyErrorf("apex_available", "Wildcard should end with .* like com.foo.*") } if strings.Count(n, ".") < 2 { mctx.PropertyErrorf("apex_available", "Wildcard requires two or more components like com.foo.*") } if strings.Count(n, "*") != 1 { mctx.PropertyErrorf("apex_available", "Wildcard is not allowed in the middle.") } continue } if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() { mctx.PropertyErrorf("apex_available", "%q is not a valid module name", n) } Loading apex/apex.go +13 −2 Original line number Diff line number Diff line Loading @@ -2767,10 +2767,21 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { if to.AvailableFor(apexName) || baselineApexAvailable(apexName, toName) { return true } // Let's give some hint for apex_available hint := fmt.Sprintf("%q", apexName) if strings.HasPrefix(apexName, "com.") && !strings.HasPrefix(apexName, "com.android.") && strings.Count(apexName, ".") >= 2 { // In case of a partner APEX, prefix format might be an option. components := strings.Split(apexName, ".") components[len(components)-1] = "*" hint += fmt.Sprintf(" or %q", strings.Join(components, ".")) } ctx.ModuleErrorf("%q requires %q that doesn't list the APEX under 'apex_available'."+ "\n\nDependency path:%s\n\n"+ "Consider adding %q to 'apex_available' property of %q", fromName, toName, ctx.GetPathString(true), apexName, toName) "Consider adding %s to 'apex_available' property of %q", fromName, toName, ctx.GetPathString(true), hint, toName) // Visit this module's dependencies to check and report any issues with their availability. return true }) Loading apex/apex_test.go +93 −0 Original line number Diff line number Diff line Loading @@ -6722,6 +6722,99 @@ func TestApexAvailable_CreatedForApex(t *testing.T) { } } func TestApexAvailable_PrefixMatch(t *testing.T) { for _, tc := range []struct { name string apexAvailable string expectedError string }{ { name: "prefix matches correctly", apexAvailable: "com.foo.*", }, { name: "prefix doesn't match", apexAvailable: "com.bar.*", expectedError: `Consider .* "com.foo\.\*"`, }, { name: "short prefix", apexAvailable: "com.*", expectedError: "requires two or more components", }, { name: "wildcard not in the end", apexAvailable: "com.*.foo", expectedError: "should end with .*", }, { name: "wildcard in the middle", apexAvailable: "com.foo*.*", expectedError: "not allowed in the middle", }, { name: "hint with prefix pattern", apexAvailable: "//apex_available:platform", expectedError: "Consider adding \"com.foo.bar\" or \"com.foo.*\"", }, } { t.Run(tc.name, func(t *testing.T) { errorHandler := android.FixtureExpectsNoErrors if tc.expectedError != "" { errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(tc.expectedError) } context := android.GroupFixturePreparers( prepareForApexTest, android.FixtureMergeMockFs(android.MockFS{ "system/sepolicy/apex/com.foo.bar-file_contexts": nil, }), ).ExtendWithErrorHandler(errorHandler) context.RunTestWithBp(t, ` apex { name: "com.foo.bar", key: "myapex.key", native_shared_libs: ["libfoo"], updatable: false, } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "libfoo", stl: "none", system_shared_libs: [], apex_available: ["`+tc.apexAvailable+`"], }`) }) } testApexError(t, `Consider adding "com.foo" to`, ` apex { name: "com.foo", // too short for a partner apex key: "myapex.key", native_shared_libs: ["libfoo"], updatable: false, } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "libfoo", stl: "none", system_shared_libs: [], } `) } func TestOverrideApex(t *testing.T) { ctx := testApex(t, ` apex { Loading Loading
android/apex.go +35 −4 Original line number Diff line number Diff line Loading @@ -280,6 +280,7 @@ type ApexProperties struct { // // "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX. // "//apex_available:platform" refers to non-APEX partitions like "system.img". // Prefix pattern (com.foo.*) can be used to match with any APEX name with the prefix(com.foo.). // Default is ["//apex_available:platform"]. Apex_available []string Loading Loading @@ -491,10 +492,27 @@ func CheckAvailableForApex(what string, apex_available []string) bool { if len(apex_available) == 0 { return what == AvailableToPlatform } return InList(what, apex_available) || (what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available)) || (what == "com.google.mainline.primary.libs") || // TODO b/248601389 (what == "com.google.mainline.go.primary.libs") // TODO b/248601389 // TODO b/248601389 if what == "com.google.mainline.primary.libs" || what == "com.google.mainline.go.primary.libs" { return true } for _, apex_name := range apex_available { // exact match. if apex_name == what { return true } // //apex_available:anyapex matches with any apex name, but not //apex_available:platform if apex_name == AvailableToAnyApex && what != AvailableToPlatform { return true } // prefix match. if strings.HasSuffix(apex_name, ".*") && strings.HasPrefix(what, strings.TrimSuffix(apex_name, "*")) { return true } } return false } // Implements ApexModule Loading Loading @@ -523,6 +541,19 @@ func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) { if n == AvailableToPlatform || n == AvailableToAnyApex { continue } // Prefix pattern should end with .* and has at least two components. if strings.Contains(n, "*") { if !strings.HasSuffix(n, ".*") { mctx.PropertyErrorf("apex_available", "Wildcard should end with .* like com.foo.*") } if strings.Count(n, ".") < 2 { mctx.PropertyErrorf("apex_available", "Wildcard requires two or more components like com.foo.*") } if strings.Count(n, "*") != 1 { mctx.PropertyErrorf("apex_available", "Wildcard is not allowed in the middle.") } continue } if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() { mctx.PropertyErrorf("apex_available", "%q is not a valid module name", n) } Loading
apex/apex.go +13 −2 Original line number Diff line number Diff line Loading @@ -2767,10 +2767,21 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { if to.AvailableFor(apexName) || baselineApexAvailable(apexName, toName) { return true } // Let's give some hint for apex_available hint := fmt.Sprintf("%q", apexName) if strings.HasPrefix(apexName, "com.") && !strings.HasPrefix(apexName, "com.android.") && strings.Count(apexName, ".") >= 2 { // In case of a partner APEX, prefix format might be an option. components := strings.Split(apexName, ".") components[len(components)-1] = "*" hint += fmt.Sprintf(" or %q", strings.Join(components, ".")) } ctx.ModuleErrorf("%q requires %q that doesn't list the APEX under 'apex_available'."+ "\n\nDependency path:%s\n\n"+ "Consider adding %q to 'apex_available' property of %q", fromName, toName, ctx.GetPathString(true), apexName, toName) "Consider adding %s to 'apex_available' property of %q", fromName, toName, ctx.GetPathString(true), hint, toName) // Visit this module's dependencies to check and report any issues with their availability. return true }) Loading
apex/apex_test.go +93 −0 Original line number Diff line number Diff line Loading @@ -6722,6 +6722,99 @@ func TestApexAvailable_CreatedForApex(t *testing.T) { } } func TestApexAvailable_PrefixMatch(t *testing.T) { for _, tc := range []struct { name string apexAvailable string expectedError string }{ { name: "prefix matches correctly", apexAvailable: "com.foo.*", }, { name: "prefix doesn't match", apexAvailable: "com.bar.*", expectedError: `Consider .* "com.foo\.\*"`, }, { name: "short prefix", apexAvailable: "com.*", expectedError: "requires two or more components", }, { name: "wildcard not in the end", apexAvailable: "com.*.foo", expectedError: "should end with .*", }, { name: "wildcard in the middle", apexAvailable: "com.foo*.*", expectedError: "not allowed in the middle", }, { name: "hint with prefix pattern", apexAvailable: "//apex_available:platform", expectedError: "Consider adding \"com.foo.bar\" or \"com.foo.*\"", }, } { t.Run(tc.name, func(t *testing.T) { errorHandler := android.FixtureExpectsNoErrors if tc.expectedError != "" { errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(tc.expectedError) } context := android.GroupFixturePreparers( prepareForApexTest, android.FixtureMergeMockFs(android.MockFS{ "system/sepolicy/apex/com.foo.bar-file_contexts": nil, }), ).ExtendWithErrorHandler(errorHandler) context.RunTestWithBp(t, ` apex { name: "com.foo.bar", key: "myapex.key", native_shared_libs: ["libfoo"], updatable: false, } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "libfoo", stl: "none", system_shared_libs: [], apex_available: ["`+tc.apexAvailable+`"], }`) }) } testApexError(t, `Consider adding "com.foo" to`, ` apex { name: "com.foo", // too short for a partner apex key: "myapex.key", native_shared_libs: ["libfoo"], updatable: false, } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "libfoo", stl: "none", system_shared_libs: [], } `) } func TestOverrideApex(t *testing.T) { ctx := testApex(t, ` apex { Loading