summaryrefslogtreecommitdiff
path: root/aconfig/java_aconfig_library.go
blob: eedb3c358bb21b787ea83d2d73d6dd466e207dde (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Copyright 2023 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package aconfig

import (
	"fmt"

	"android/soong/android"
	"android/soong/bazel"
	"android/soong/java"
	"github.com/google/blueprint"
	"github.com/google/blueprint/proptools"
)

type declarationsTagType struct {
	blueprint.BaseDependencyTag
}

var declarationsTag = declarationsTagType{}

var aconfigSupportedModes = []string{"production", "test", "exported"}

type JavaAconfigDeclarationsLibraryProperties struct {
	// name of the aconfig_declarations module to generate a library for
	Aconfig_declarations string

	// default mode is "production", the other accepted modes are:
	// "test": to generate test mode version of the library
	// "exported": to generate exported mode version of the library
	// an error will be thrown if the mode is not supported
	Mode *string
}

type JavaAconfigDeclarationsLibraryCallbacks struct {
	properties JavaAconfigDeclarationsLibraryProperties
}

func JavaDeclarationsLibraryFactory() android.Module {
	callbacks := &JavaAconfigDeclarationsLibraryCallbacks{}
	return java.GeneratedJavaLibraryModuleFactory("java_aconfig_library", callbacks, &callbacks.properties)
}

func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) DepsMutator(module *java.GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext) {
	declarations := callbacks.properties.Aconfig_declarations
	if len(declarations) == 0 {
		// TODO: Add test for this case
		ctx.PropertyErrorf("aconfig_declarations", "aconfig_declarations property required")
	} else {
		ctx.AddDependency(ctx.Module(), declarationsTag, declarations)
	}

	// Add aconfig-annotations-lib as a dependency for the optimization / code stripping annotations
	module.AddSharedLibrary("aconfig-annotations-lib")
	// TODO(b/303773055): Remove the annotation after access issue is resolved.
	module.AddSharedLibrary("unsupportedappusage")
}

func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(module *java.GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path {
	// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
	declarationsModules := ctx.GetDirectDepsWithTag(declarationsTag)
	if len(declarationsModules) != 1 {
		panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
	}
	declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData)

	// Generate the action to build the srcjar
	srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar")

	mode := proptools.StringDefault(callbacks.properties.Mode, "production")
	if !isModeSupported(mode) {
		ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
	}

	ctx.Build(pctx, android.BuildParams{
		Rule:        javaRule,
		Input:       declarations.IntermediatePath,
		Output:      srcJarPath,
		Description: "aconfig.srcjar",
		Args: map[string]string{
			"mode": mode,
		},
	})

	// Tell the java module about the .aconfig files, so they can be propagated up the dependency chain.
	// TODO: It would be nice to have that propagation code here instead of on java.Module and java.JavaInfo.
	module.AddAconfigIntermediate(declarations.IntermediatePath)

	return srcJarPath
}

func isModeSupported(mode string) bool {
	return android.InList(mode, aconfigSupportedModes)
}

type bazelJavaAconfigLibraryAttributes struct {
	Aconfig_declarations bazel.LabelAttribute
	Sdk_version          *string
	Libs                 bazel.LabelListAttribute
}

func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) Bp2build(ctx android.Bp2buildMutatorContext, module *java.GeneratedJavaLibraryModule) {
	if ctx.ModuleType() != "java_aconfig_library" {
		return
	}

	// By default, soong builds the aconfig java library with private_current, however
	// bazel currently doesn't support it so we default it to system_current. One reason
	// is that the dependency of all java_aconfig_library aconfig-annotations-lib is
	// built with system_current. For the java aconfig library itself it doesn't really
	// matter whether it uses private API or system API because the only module it uses
	// is DeviceConfig which is in system, and the rdeps of the java aconfig library
	// won't change its sdk version either, so this should be fine.
	// Ideally we should only use the default value if it is not set by the user, but
	// bazel only supports a limited sdk versions, for example, the java_aconfig_library
	// modules in framework/base use core_platform which is not supported by bazel yet.
	// TODO(b/302148527): change soong to default to system_current as well.
	sdkVersion := "system_current"

	var libs bazel.LabelListAttribute
	archVariantProps := module.GetArchVariantProperties(ctx, &java.CommonProperties{})
	for axis, configToProps := range archVariantProps {
		for config, p := range configToProps {
			if archProps, ok := p.(*java.CommonProperties); ok {
				var libLabels []bazel.Label
				for _, d := range archProps.Libs {
					neverlinkLabel := android.BazelLabelForModuleDepSingle(ctx, d)
					neverlinkLabel.Label = neverlinkLabel.Label + "-neverlink"
					libLabels = append(libLabels, neverlinkLabel)
				}
				libs.SetSelectValue(axis, config, (bazel.MakeLabelList(libLabels)))
			}
		}
	}

	attrs := bazelJavaAconfigLibraryAttributes{
		Aconfig_declarations: *bazel.MakeLabelAttribute(android.BazelLabelForModuleDepSingle(ctx, callbacks.properties.Aconfig_declarations).Label),
		Sdk_version:          &sdkVersion,
		Libs:                 libs,
	}
	props := bazel.BazelTargetModuleProperties{
		Rule_class:        "java_aconfig_library",
		Bzl_load_location: "//build/bazel/rules/java:java_aconfig_library.bzl",
	}

	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: ctx.ModuleName()}, &attrs)
}