1// Copyright 2023 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package codegen 16 17import ( 18 "android/soong/android" 19 "android/soong/java" 20 21 "github.com/google/blueprint" 22 "github.com/google/blueprint/proptools" 23) 24 25type declarationsTagType struct { 26 blueprint.BaseDependencyTag 27} 28 29var declarationsTag = declarationsTagType{} 30 31var aconfigSupportedModes = []string{"production", "test", "exported", "force-read-only"} 32 33type JavaAconfigDeclarationsLibraryProperties struct { 34 // name of the aconfig_declarations module to generate a library for 35 Aconfig_declarations string 36 37 // default mode is "production", the other accepted modes are: 38 // "test": to generate test mode version of the library 39 // "exported": to generate exported mode version of the library 40 // "force-read-only": to generate force-read-only mode version of the library 41 // an error will be thrown if the mode is not supported 42 Mode *string 43} 44 45type JavaAconfigDeclarationsLibraryCallbacks struct { 46 properties JavaAconfigDeclarationsLibraryProperties 47} 48 49func JavaDeclarationsLibraryFactory() android.Module { 50 callbacks := &JavaAconfigDeclarationsLibraryCallbacks{} 51 return java.GeneratedJavaLibraryModuleFactory("java_aconfig_library", callbacks, &callbacks.properties) 52} 53 54func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) DepsMutator(module *java.GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext) { 55 declarations := callbacks.properties.Aconfig_declarations 56 if len(declarations) == 0 { 57 // TODO: Add test for this case 58 ctx.PropertyErrorf("aconfig_declarations", "aconfig_declarations property required") 59 } else { 60 ctx.AddDependency(ctx.Module(), declarationsTag, declarations) 61 } 62 63 // "libcore_aconfig_flags_lib" module has a circular dependency because the shared libraries 64 // are built on core_current and the module is used to flag the APIs in the core_current. 65 // http://b/316554963#comment2 has the details of the circular dependency chain. 66 // If a java_aconfig_library uses "none" sdk_version, it should include and build these 67 // annotation files as the shared library themselves. 68 var addLibraries bool = module.Library.Module.SdkVersion(ctx).Kind != android.SdkNone 69 if addLibraries { 70 // Add aconfig-annotations-lib as a dependency for the optimization / code stripping annotations 71 module.AddSharedLibrary("aconfig-annotations-lib") 72 // TODO(b/303773055): Remove the annotation after access issue is resolved. 73 module.AddSharedLibrary("unsupportedappusage") 74 } 75} 76 77func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(module *java.GeneratedJavaLibraryModule, ctx android.ModuleContext) (android.Path, android.Path) { 78 // Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag 79 declarationsModules := ctx.GetDirectDepsWithTag(declarationsTag) 80 if len(declarationsModules) != 1 { 81 panic("Exactly one aconfig_declarations property required") 82 } 83 declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey) 84 85 // Generate the action to build the srcjar 86 srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar") 87 88 mode := proptools.StringDefault(callbacks.properties.Mode, "production") 89 if !isModeSupported(mode) { 90 ctx.PropertyErrorf("mode", "%q is not a supported mode", mode) 91 } 92 93 if mode == "exported" && !declarations.Exportable { 94 // if mode is exported, the corresponding aconfig_declaration must mark its 95 // exportable property true 96 ctx.PropertyErrorf("mode", "exported mode requires its aconfig_declaration has exportable prop true") 97 } 98 99 ctx.Build(pctx, android.BuildParams{ 100 Rule: javaRule, 101 Input: declarations.IntermediateCacheOutputPath, 102 Output: srcJarPath, 103 Description: "aconfig.srcjar", 104 Args: map[string]string{ 105 "mode": mode, 106 }, 107 }) 108 109 if declarations.Exportable { 110 // Mark our generated code as possibly needing jarjar repackaging 111 // The repackaging only happens when the corresponding aconfig_declaration 112 // has property exportable true 113 module.AddJarJarRenameRule(declarations.Package+".Flags", "") 114 module.AddJarJarRenameRule(declarations.Package+".FeatureFlags", "") 115 module.AddJarJarRenameRule(declarations.Package+".FeatureFlagsImpl", "") 116 module.AddJarJarRenameRule(declarations.Package+".CustomFeatureFlags", "") 117 module.AddJarJarRenameRule(declarations.Package+".FakeFeatureFlagsImpl", "") 118 } 119 120 android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{ 121 AconfigDeclarations: []string{declarationsModules[0].Name()}, 122 IntermediateCacheOutputPaths: android.Paths{declarations.IntermediateCacheOutputPath}, 123 Srcjars: android.Paths{srcJarPath}, 124 ModeInfos: map[string]android.ModeInfo{ 125 ctx.ModuleName(): { 126 Container: declarations.Container, 127 Mode: mode, 128 }}, 129 }) 130 131 return srcJarPath, declarations.IntermediateCacheOutputPath 132} 133 134func isModeSupported(mode string) bool { 135 return android.InList(mode, aconfigSupportedModes) 136} 137