• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 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 java
16
17import (
18	"strings"
19
20	"github.com/google/blueprint"
21
22	"android/soong/android"
23)
24
25var hiddenAPIGenerateCSVRule = pctx.AndroidStaticRule("hiddenAPIGenerateCSV", blueprint.RuleParams{
26	Command:     "${config.Class2Greylist} --stub-api-flags ${stubAPIFlags} $in $outFlag $out",
27	CommandDeps: []string{"${config.Class2Greylist}"},
28}, "outFlag", "stubAPIFlags")
29
30type hiddenAPI struct {
31	flagsCSVPath    android.Path
32	metadataCSVPath android.Path
33	bootDexJarPath  android.Path
34}
35
36func (h *hiddenAPI) flagsCSV() android.Path {
37	return h.flagsCSVPath
38}
39
40func (h *hiddenAPI) metadataCSV() android.Path {
41	return h.metadataCSVPath
42}
43
44func (h *hiddenAPI) bootDexJar() android.Path {
45	return h.bootDexJarPath
46}
47
48type hiddenAPIIntf interface {
49	flagsCSV() android.Path
50	metadataCSV() android.Path
51	bootDexJar() android.Path
52}
53
54var _ hiddenAPIIntf = (*hiddenAPI)(nil)
55
56func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, dexJar android.ModuleOutPath, implementationJar android.Path,
57	uncompressDex bool) android.ModuleOutPath {
58
59	if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
60		name := ctx.ModuleName()
61
62		// Modules whose names are of the format <x>-hiddenapi provide hiddenapi information
63		// for the boot jar module <x>. Otherwise, the module provides information for itself.
64		// Either way extract the name of the boot jar module.
65		bootJarName := strings.TrimSuffix(name, "-hiddenapi")
66
67		// If this module is on the boot jars list (or providing information for a module
68		// on the list) then extract the hiddenapi information from it, and if necessary
69		// encode that information in the generated dex file.
70		//
71		// It is important that hiddenapi information is only gathered for/from modules on
72		// that are actually on the boot jars list because the runtime only enforces access
73		// to the hidden API for the bootclassloader. If information is gathered for modules
74		// not on the list then that will cause failures in the CtsHiddenApiBlacklist...
75		// tests.
76		if inList(bootJarName, ctx.Config().BootJars()) {
77			// Derive the greylist from classes jar.
78			flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv")
79			metadataCSV := android.PathForModuleOut(ctx, "hiddenapi", "metadata.csv")
80			hiddenAPIGenerateCSV(ctx, flagsCSV, metadataCSV, implementationJar)
81			h.flagsCSVPath = flagsCSV
82			h.metadataCSVPath = metadataCSV
83
84			// If this module is actually on the boot jars list and not providing
85			// hiddenapi information for a module on the boot jars list then encode
86			// the gathered information in the generated dex file.
87			if name == bootJarName {
88				hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", name+".jar")
89				h.bootDexJarPath = dexJar
90				hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex)
91				dexJar = hiddenAPIJar
92			}
93		}
94	}
95
96	return dexJar
97}
98
99func hiddenAPIGenerateCSV(ctx android.ModuleContext, flagsCSV, metadataCSV android.WritablePath,
100	classesJar android.Path) {
101
102	stubFlagsCSV := hiddenAPISingletonPaths(ctx).stubFlags
103
104	ctx.Build(pctx, android.BuildParams{
105		Rule:        hiddenAPIGenerateCSVRule,
106		Description: "hiddenapi flags",
107		Input:       classesJar,
108		Output:      flagsCSV,
109		Implicit:    stubFlagsCSV,
110		Args: map[string]string{
111			"outFlag":      "--write-flags-csv",
112			"stubAPIFlags": stubFlagsCSV.String(),
113		},
114	})
115
116	ctx.Build(pctx, android.BuildParams{
117		Rule:        hiddenAPIGenerateCSVRule,
118		Description: "hiddenapi metadata",
119		Input:       classesJar,
120		Output:      metadataCSV,
121		Implicit:    stubFlagsCSV,
122		Args: map[string]string{
123			"outFlag":      "--write-metadata-csv",
124			"stubAPIFlags": stubFlagsCSV.String(),
125		},
126	})
127
128}
129
130var hiddenAPIEncodeDexRule = pctx.AndroidStaticRule("hiddenAPIEncodeDex", blueprint.RuleParams{
131	Command: `rm -rf $tmpDir && mkdir -p $tmpDir && mkdir $tmpDir/dex-input && mkdir $tmpDir/dex-output && ` +
132		`unzip -o -q $in 'classes*.dex' -d $tmpDir/dex-input && ` +
133		`for INPUT_DEX in $$(find $tmpDir/dex-input -maxdepth 1 -name 'classes*.dex' | sort); do ` +
134		`  echo "--input-dex=$${INPUT_DEX}"; ` +
135		`  echo "--output-dex=$tmpDir/dex-output/$$(basename $${INPUT_DEX})"; ` +
136		`done | xargs ${config.HiddenAPI} encode --api-flags=$flagsCsv $hiddenapiFlags && ` +
137		`${config.SoongZipCmd} $soongZipFlags -o $tmpDir/dex.jar -C $tmpDir/dex-output -f "$tmpDir/dex-output/classes*.dex" && ` +
138		`${config.MergeZipsCmd} -D -zipToNotStrip $tmpDir/dex.jar -stripFile "classes*.dex" $out $tmpDir/dex.jar $in`,
139	CommandDeps: []string{
140		"${config.HiddenAPI}",
141		"${config.SoongZipCmd}",
142		"${config.MergeZipsCmd}",
143	},
144}, "flagsCsv", "hiddenapiFlags", "tmpDir", "soongZipFlags")
145
146func hiddenAPIEncodeDex(ctx android.ModuleContext, output android.WritablePath, dexInput android.Path,
147	uncompressDex bool) {
148
149	flagsCSV := hiddenAPISingletonPaths(ctx).flags
150
151	// The encode dex rule requires unzipping and rezipping the classes.dex files, ensure that if it was uncompressed
152	// in the input it stays uncompressed in the output.
153	soongZipFlags := ""
154	hiddenapiFlags := ""
155	tmpOutput := output
156	tmpDir := android.PathForModuleOut(ctx, "hiddenapi", "dex")
157	if uncompressDex {
158		soongZipFlags = "-L 0"
159		tmpOutput = android.PathForModuleOut(ctx, "hiddenapi", "unaligned", "unaligned.jar")
160		tmpDir = android.PathForModuleOut(ctx, "hiddenapi", "unaligned")
161	}
162	// If frameworks/base doesn't exist we must be building with the 'master-art' manifest.
163	// Disable assertion that all methods/fields have hidden API flags assigned.
164	if !ctx.Config().FrameworksBaseDirExists(ctx) {
165		hiddenapiFlags = "--no-force-assign-all"
166	}
167
168	ctx.Build(pctx, android.BuildParams{
169		Rule:        hiddenAPIEncodeDexRule,
170		Description: "hiddenapi encode dex",
171		Input:       dexInput,
172		Output:      tmpOutput,
173		Implicit:    flagsCSV,
174		Args: map[string]string{
175			"flagsCsv":       flagsCSV.String(),
176			"tmpDir":         tmpDir.String(),
177			"soongZipFlags":  soongZipFlags,
178			"hiddenapiFlags": hiddenapiFlags,
179		},
180	})
181
182	if uncompressDex {
183		TransformZipAlign(ctx, output, tmpOutput)
184	}
185}
186