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 "strconv" 24) 25 26type declarationsTagType struct { 27 blueprint.BaseDependencyTag 28} 29 30var declarationsTag = declarationsTagType{} 31 32var aconfigSupportedModes = []string{"production", "test", "exported", "force-read-only"} 33 34type JavaAconfigDeclarationsLibraryProperties struct { 35 // name of the aconfig_declarations module to generate a library for 36 Aconfig_declarations string 37 38 // default mode is "production", the other accepted modes are: 39 // "test": to generate test mode version of the library 40 // "exported": to generate exported mode version of the library 41 // "force-read-only": to generate force-read-only mode version of the library 42 // an error will be thrown if the mode is not supported 43 Mode *string 44} 45 46type JavaAconfigDeclarationsLibraryCallbacks struct { 47 properties JavaAconfigDeclarationsLibraryProperties 48} 49 50func JavaDeclarationsLibraryFactory() android.Module { 51 callbacks := &JavaAconfigDeclarationsLibraryCallbacks{} 52 return java.GeneratedJavaLibraryModuleFactory("java_aconfig_library", callbacks, &callbacks.properties) 53} 54 55func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) DepsMutator(module *java.GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext) { 56 declarations := callbacks.properties.Aconfig_declarations 57 if len(declarations) == 0 { 58 // TODO: Add test for this case 59 ctx.PropertyErrorf("aconfig_declarations", "aconfig_declarations property required") 60 } else { 61 ctx.AddDependency(ctx.Module(), declarationsTag, declarations) 62 } 63 64 // "libcore_aconfig_flags_lib" module has a circular dependency because the shared libraries 65 // are built on core_current and the module is used to flag the APIs in the core_current. 66 // http://b/316554963#comment2 has the details of the circular dependency chain. 67 // If a java_aconfig_library uses "none" sdk_version, it should include and build these 68 // annotation files as the shared library themselves. 69 var addLibraries bool = module.Library.Module.SdkVersion(ctx).Kind != android.SdkNone 70 if addLibraries { 71 // Add aconfig-annotations-lib as a dependency for the optimization / code stripping annotations 72 module.AddSharedLibrary("aconfig-annotations-lib") 73 // TODO(b/303773055): Remove the annotation after access issue is resolved. 74 module.AddSharedLibrary("unsupportedappusage") 75 module.AddSharedLibrary("aconfig_storage_stub") 76 } 77} 78 79func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(module *java.GeneratedJavaLibraryModule, ctx android.ModuleContext) (android.Path, android.Path) { 80 // Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag 81 declarationsModules := ctx.GetDirectDepsWithTag(declarationsTag) 82 if len(declarationsModules) != 1 { 83 panic("Exactly one aconfig_declarations property required") 84 } 85 declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey) 86 87 // Generate the action to build the srcjar 88 srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar") 89 90 mode := proptools.StringDefault(callbacks.properties.Mode, "production") 91 if !isModeSupported(mode) { 92 ctx.PropertyErrorf("mode", "%q is not a supported mode", mode) 93 } 94 95 if mode == "exported" && !declarations.Exportable { 96 // if mode is exported, the corresponding aconfig_declaration must mark its 97 // exportable property true 98 ctx.PropertyErrorf("mode", "exported mode requires its aconfig_declaration has exportable prop true") 99 } 100 101 ctx.Build(pctx, android.BuildParams{ 102 Rule: javaRule, 103 Input: declarations.IntermediateCacheOutputPath, 104 Output: srcJarPath, 105 Description: "aconfig.srcjar", 106 Args: map[string]string{ 107 "mode": mode, 108 "debug": strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()), 109 }, 110 }) 111 112 if declarations.Exportable { 113 // Mark our generated code as possibly needing jarjar repackaging 114 // The repackaging only happens when the corresponding aconfig_declaration 115 // has property exportable true 116 module.AddJarJarRenameRule(declarations.Package+".Flags", "") 117 module.AddJarJarRenameRule(declarations.Package+".FeatureFlags", "") 118 module.AddJarJarRenameRule(declarations.Package+".FeatureFlagsImpl", "") 119 module.AddJarJarRenameRule(declarations.Package+".CustomFeatureFlags", "") 120 module.AddJarJarRenameRule(declarations.Package+".FakeFeatureFlagsImpl", "") 121 } 122 123 android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{ 124 AconfigDeclarations: []string{declarationsModules[0].Name()}, 125 IntermediateCacheOutputPaths: android.Paths{declarations.IntermediateCacheOutputPath}, 126 Srcjars: android.Paths{srcJarPath}, 127 ModeInfos: map[string]android.ModeInfo{ 128 ctx.ModuleName(): { 129 Container: declarations.Container, 130 Mode: mode, 131 }}, 132 }) 133 134 return srcJarPath, declarations.IntermediateCacheOutputPath 135} 136 137func isModeSupported(mode string) bool { 138 return android.InList(mode, aconfigSupportedModes) 139} 140