1// Copyright 2018 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 android
16
17import (
18	"fmt"
19	"sort"
20	"strconv"
21	"strings"
22	"sync"
23
24	"github.com/google/blueprint"
25)
26
27const (
28	SdkVersion_Android10 = 29
29)
30
31type ApexInfo struct {
32	// Name of the apex variant that this module is mutated into
33	ApexName string
34
35	MinSdkVersion int
36	Updatable     bool
37}
38
39// Extracted from ApexModule to make it easier to define custom subsets of the
40// ApexModule interface and improve code navigation within the IDE.
41type DepIsInSameApex interface {
42	// DepIsInSameApex tests if the other module 'dep' is installed to the same
43	// APEX as this module
44	DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
45}
46
47// ApexModule is the interface that a module type is expected to implement if
48// the module has to be built differently depending on whether the module
49// is destined for an apex or not (installed to one of the regular partitions).
50//
51// Native shared libraries are one such module type; when it is built for an
52// APEX, it should depend only on stable interfaces such as NDK, stable AIDL,
53// or C APIs from other APEXs.
54//
55// A module implementing this interface will be mutated into multiple
56// variations by apex.apexMutator if it is directly or indirectly included
57// in one or more APEXs. Specifically, if a module is included in apex.foo and
58// apex.bar then three apex variants are created: platform, apex.foo and
59// apex.bar. The platform variant is for the regular partitions
60// (e.g., /system or /vendor, etc.) while the other two are for the APEXs,
61// respectively.
62type ApexModule interface {
63	Module
64	DepIsInSameApex
65
66	apexModuleBase() *ApexModuleBase
67
68	// Marks that this module should be built for the specified APEX.
69	// Call this before apex.apexMutator is run.
70	BuildForApex(apex ApexInfo)
71
72	// Returns the APEXes that this module will be built for
73	ApexVariations() []ApexInfo
74
75	// Returns the name of APEX that this module will be built for. Empty string
76	// is returned when 'IsForPlatform() == true'. Note that a module can be
77	// included in multiple APEXes, in which case, the module is mutated into
78	// multiple modules each of which for an APEX. This method returns the
79	// name of the APEX that a variant module is for.
80	// Call this after apex.apexMutator is run.
81	ApexName() string
82
83	// Tests whether this module will be built for the platform or not.
84	// This is a shortcut for ApexName() == ""
85	IsForPlatform() bool
86
87	// Tests if this module could have APEX variants. APEX variants are
88	// created only for the modules that returns true here. This is useful
89	// for not creating APEX variants for certain types of shared libraries
90	// such as NDK stubs.
91	CanHaveApexVariants() bool
92
93	// Tests if this module can be installed to APEX as a file. For example,
94	// this would return true for shared libs while return false for static
95	// libs.
96	IsInstallableToApex() bool
97
98	// Mutate this module into one or more variants each of which is built
99	// for an APEX marked via BuildForApex().
100	CreateApexVariations(mctx BottomUpMutatorContext) []Module
101
102	// Tests if this module is available for the specified APEX or ":platform"
103	AvailableFor(what string) bool
104
105	// Return true if this module is not available to platform (i.e. apex_available
106	// property doesn't have "//apex_available:platform"), or shouldn't be available
107	// to platform, which is the case when this module depends on other module that
108	// isn't available to platform.
109	NotAvailableForPlatform() bool
110
111	// Mark that this module is not available to platform. Set by the
112	// check-platform-availability mutator in the apex package.
113	SetNotAvailableForPlatform()
114
115	// Returns the highest version which is <= maxSdkVersion.
116	// For example, with maxSdkVersion is 10 and versionList is [9,11]
117	// it returns 9 as string
118	ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error)
119
120	// Tests if the module comes from an updatable APEX.
121	Updatable() bool
122
123	// List of APEXes that this module tests. The module has access to
124	// the private part of the listed APEXes even when it is not included in the
125	// APEXes.
126	TestFor() []string
127
128	// Returns nil if this module supports sdkVersion
129	// Otherwise, returns error with reason
130	ShouldSupportSdkVersion(ctx BaseModuleContext, sdkVersion int) error
131}
132
133type ApexProperties struct {
134	// Availability of this module in APEXes. Only the listed APEXes can contain
135	// this module. If the module has stubs then other APEXes and the platform may
136	// access it through them (subject to visibility).
137	//
138	// "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX.
139	// "//apex_available:platform" refers to non-APEX partitions like "system.img".
140	// Default is ["//apex_available:platform"].
141	Apex_available []string
142
143	Info ApexInfo `blueprint:"mutated"`
144
145	NotAvailableForPlatform bool `blueprint:"mutated"`
146}
147
148// Marker interface that identifies dependencies that are excluded from APEX
149// contents.
150type ExcludeFromApexContentsTag interface {
151	blueprint.DependencyTag
152
153	// Method that differentiates this interface from others.
154	ExcludeFromApexContents()
155}
156
157// Provides default implementation for the ApexModule interface. APEX-aware
158// modules are expected to include this struct and call InitApexModule().
159type ApexModuleBase struct {
160	ApexProperties ApexProperties
161
162	canHaveApexVariants bool
163
164	apexVariationsLock sync.Mutex // protects apexVariations during parallel apexDepsMutator
165	apexVariations     []ApexInfo
166}
167
168func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase {
169	return m
170}
171
172func (m *ApexModuleBase) ApexAvailable() []string {
173	return m.ApexProperties.Apex_available
174}
175
176func (m *ApexModuleBase) TestFor() []string {
177	// To be implemented by concrete types inheriting ApexModuleBase
178	return nil
179}
180
181func (m *ApexModuleBase) BuildForApex(apex ApexInfo) {
182	m.apexVariationsLock.Lock()
183	defer m.apexVariationsLock.Unlock()
184	for _, v := range m.apexVariations {
185		if v.ApexName == apex.ApexName {
186			return
187		}
188	}
189	m.apexVariations = append(m.apexVariations, apex)
190}
191
192func (m *ApexModuleBase) ApexVariations() []ApexInfo {
193	return m.apexVariations
194}
195
196func (m *ApexModuleBase) ApexName() string {
197	return m.ApexProperties.Info.ApexName
198}
199
200func (m *ApexModuleBase) IsForPlatform() bool {
201	return m.ApexProperties.Info.ApexName == ""
202}
203
204func (m *ApexModuleBase) CanHaveApexVariants() bool {
205	return m.canHaveApexVariants
206}
207
208func (m *ApexModuleBase) IsInstallableToApex() bool {
209	// should be overriden if needed
210	return false
211}
212
213const (
214	AvailableToPlatform = "//apex_available:platform"
215	AvailableToAnyApex  = "//apex_available:anyapex"
216)
217
218func CheckAvailableForApex(what string, apex_available []string) bool {
219	if len(apex_available) == 0 {
220		// apex_available defaults to ["//apex_available:platform"],
221		// which means 'available to the platform but no apexes'.
222		return what == AvailableToPlatform
223	}
224	return InList(what, apex_available) ||
225		(what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available))
226}
227
228func (m *ApexModuleBase) AvailableFor(what string) bool {
229	return CheckAvailableForApex(what, m.ApexProperties.Apex_available)
230}
231
232func (m *ApexModuleBase) NotAvailableForPlatform() bool {
233	return m.ApexProperties.NotAvailableForPlatform
234}
235
236func (m *ApexModuleBase) SetNotAvailableForPlatform() {
237	m.ApexProperties.NotAvailableForPlatform = true
238}
239
240func (m *ApexModuleBase) DepIsInSameApex(ctx BaseModuleContext, dep Module) bool {
241	// By default, if there is a dependency from A to B, we try to include both in the same APEX,
242	// unless B is explicitly from outside of the APEX (i.e. a stubs lib). Thus, returning true.
243	// This is overridden by some module types like apex.ApexBundle, cc.Module, java.Module, etc.
244	return true
245}
246
247func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error) {
248	for i := range versionList {
249		ver, _ := strconv.Atoi(versionList[len(versionList)-i-1])
250		if ver <= maxSdkVersion {
251			return versionList[len(versionList)-i-1], nil
252		}
253	}
254	return "", fmt.Errorf("not found a version(<=%d) in versionList: %v", maxSdkVersion, versionList)
255}
256
257func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
258	for _, n := range m.ApexProperties.Apex_available {
259		if n == AvailableToPlatform || n == AvailableToAnyApex {
260			continue
261		}
262		if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() {
263			mctx.PropertyErrorf("apex_available", "%q is not a valid module name", n)
264		}
265	}
266}
267
268func (m *ApexModuleBase) Updatable() bool {
269	return m.ApexProperties.Info.Updatable
270}
271
272type byApexName []ApexInfo
273
274func (a byApexName) Len() int           { return len(a) }
275func (a byApexName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
276func (a byApexName) Less(i, j int) bool { return a[i].ApexName < a[j].ApexName }
277
278func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Module {
279	if len(m.apexVariations) > 0 {
280		m.checkApexAvailableProperty(mctx)
281
282		sort.Sort(byApexName(m.apexVariations))
283		variations := []string{}
284		variations = append(variations, "") // Original variation for platform
285		for _, apex := range m.apexVariations {
286			variations = append(variations, apex.ApexName)
287		}
288
289		defaultVariation := ""
290		mctx.SetDefaultDependencyVariation(&defaultVariation)
291
292		modules := mctx.CreateVariations(variations...)
293		for i, mod := range modules {
294			platformVariation := i == 0
295			if platformVariation && !mctx.Host() && !mod.(ApexModule).AvailableFor(AvailableToPlatform) {
296				mod.SkipInstall()
297			}
298			if !platformVariation {
299				mod.(ApexModule).apexModuleBase().ApexProperties.Info = m.apexVariations[i-1]
300			}
301		}
302		return modules
303	}
304	return nil
305}
306
307var apexData OncePer
308var apexNamesMapMutex sync.Mutex
309var apexNamesKey = NewOnceKey("apexNames")
310
311// This structure maintains the global mapping in between modules and APEXes.
312// Examples:
313//
314// apexNamesMap()["foo"]["bar"] == true: module foo is directly depended on by APEX bar
315// apexNamesMap()["foo"]["bar"] == false: module foo is indirectly depended on by APEX bar
316// apexNamesMap()["foo"]["bar"] doesn't exist: foo is not built for APEX bar
317func apexNamesMap() map[string]map[string]bool {
318	return apexData.Once(apexNamesKey, func() interface{} {
319		return make(map[string]map[string]bool)
320	}).(map[string]map[string]bool)
321}
322
323// Update the map to mark that a module named moduleName is directly or indirectly
324// depended on by the specified APEXes. Directly depending means that a module
325// is explicitly listed in the build definition of the APEX via properties like
326// native_shared_libs, java_libs, etc.
327func UpdateApexDependency(apex ApexInfo, moduleName string, directDep bool) {
328	apexNamesMapMutex.Lock()
329	defer apexNamesMapMutex.Unlock()
330	apexesForModule, ok := apexNamesMap()[moduleName]
331	if !ok {
332		apexesForModule = make(map[string]bool)
333		apexNamesMap()[moduleName] = apexesForModule
334	}
335	apexesForModule[apex.ApexName] = apexesForModule[apex.ApexName] || directDep
336}
337
338// TODO(b/146393795): remove this when b/146393795 is fixed
339func ClearApexDependency() {
340	m := apexNamesMap()
341	for k := range m {
342		delete(m, k)
343	}
344}
345
346// Tests whether a module named moduleName is directly depended on by an APEX
347// named apexName.
348func DirectlyInApex(apexName string, moduleName string) bool {
349	apexNamesMapMutex.Lock()
350	defer apexNamesMapMutex.Unlock()
351	if apexNames, ok := apexNamesMap()[moduleName]; ok {
352		return apexNames[apexName]
353	}
354	return false
355}
356
357type hostContext interface {
358	Host() bool
359}
360
361// Tests whether a module named moduleName is directly depended on by any APEX.
362func DirectlyInAnyApex(ctx hostContext, moduleName string) bool {
363	if ctx.Host() {
364		// Host has no APEX.
365		return false
366	}
367	apexNamesMapMutex.Lock()
368	defer apexNamesMapMutex.Unlock()
369	if apexNames, ok := apexNamesMap()[moduleName]; ok {
370		for an := range apexNames {
371			if apexNames[an] {
372				return true
373			}
374		}
375	}
376	return false
377}
378
379// Tests whether a module named module is depended on (including both
380// direct and indirect dependencies) by any APEX.
381func InAnyApex(moduleName string) bool {
382	apexNamesMapMutex.Lock()
383	defer apexNamesMapMutex.Unlock()
384	apexNames, ok := apexNamesMap()[moduleName]
385	return ok && len(apexNames) > 0
386}
387
388func GetApexesForModule(moduleName string) []string {
389	ret := []string{}
390	apexNamesMapMutex.Lock()
391	defer apexNamesMapMutex.Unlock()
392	if apexNames, ok := apexNamesMap()[moduleName]; ok {
393		for an := range apexNames {
394			ret = append(ret, an)
395		}
396	}
397	return ret
398}
399
400func InitApexModule(m ApexModule) {
401	base := m.apexModuleBase()
402	base.canHaveApexVariants = true
403
404	m.AddProperties(&base.ApexProperties)
405}
406
407// A dependency info for a single ApexModule, either direct or transitive.
408type ApexModuleDepInfo struct {
409	// Name of the dependency
410	To string
411	// List of dependencies To belongs to. Includes APEX itself, if a direct dependency.
412	From []string
413	// Whether the dependency belongs to the final compiled APEX.
414	IsExternal bool
415	// min_sdk_version of the ApexModule
416	MinSdkVersion string
417}
418
419// A map of a dependency name to its ApexModuleDepInfo
420type DepNameToDepInfoMap map[string]ApexModuleDepInfo
421
422type ApexBundleDepsInfo struct {
423	flatListPath OutputPath
424	fullListPath OutputPath
425}
426
427type ApexBundleDepsInfoIntf interface {
428	Updatable() bool
429	FlatListPath() Path
430	FullListPath() Path
431}
432
433func (d *ApexBundleDepsInfo) FlatListPath() Path {
434	return d.flatListPath
435}
436
437func (d *ApexBundleDepsInfo) FullListPath() Path {
438	return d.fullListPath
439}
440
441// Generate two module out files:
442// 1. FullList with transitive deps and their parents in the dep graph
443// 2. FlatList with a flat list of transitive deps
444func (d *ApexBundleDepsInfo) BuildDepsInfoLists(ctx ModuleContext, minSdkVersion string, depInfos DepNameToDepInfoMap) {
445	var fullContent strings.Builder
446	var flatContent strings.Builder
447
448	fmt.Fprintf(&flatContent, "%s(minSdkVersion:%s):\\n", ctx.ModuleName(), minSdkVersion)
449	for _, key := range FirstUniqueStrings(SortedStringKeys(depInfos)) {
450		info := depInfos[key]
451		toName := fmt.Sprintf("%s(minSdkVersion:%s)", info.To, info.MinSdkVersion)
452		if info.IsExternal {
453			toName = toName + " (external)"
454		}
455		fmt.Fprintf(&fullContent, "%s <- %s\\n", toName, strings.Join(SortedUniqueStrings(info.From), ", "))
456		fmt.Fprintf(&flatContent, "  %s\\n", toName)
457	}
458
459	d.fullListPath = PathForModuleOut(ctx, "depsinfo", "fulllist.txt").OutputPath
460	ctx.Build(pctx, BuildParams{
461		Rule:        WriteFile,
462		Description: "Full Dependency Info",
463		Output:      d.fullListPath,
464		Args: map[string]string{
465			"content": fullContent.String(),
466		},
467	})
468
469	d.flatListPath = PathForModuleOut(ctx, "depsinfo", "flatlist.txt").OutputPath
470	ctx.Build(pctx, BuildParams{
471		Rule:        WriteFile,
472		Description: "Flat Dependency Info",
473		Output:      d.flatListPath,
474		Args: map[string]string{
475			"content": flatContent.String(),
476		},
477	})
478}
479
480// TODO(b/158059172): remove minSdkVersion allowlist
481var minSdkVersionAllowlist = map[string]int{
482	"adbd":                  30,
483	"android.net.ipsec.ike": 30,
484	"androidx-constraintlayout_constraintlayout-solver": 30,
485	"androidx.annotation_annotation":                    28,
486	"androidx.arch.core_core-common":                    28,
487	"androidx.collection_collection":                    28,
488	"androidx.lifecycle_lifecycle-common":               28,
489	"apache-commons-compress":                           29,
490	"bouncycastle_ike_digests":                          30,
491	"brotli-java":                                       29,
492	"captiveportal-lib":                                 28,
493	"flatbuffer_headers":                                30,
494	"framework-permission":                              30,
495	"framework-statsd":                                  30,
496	"gemmlowp_headers":                                  30,
497	"ike-internals":                                     30,
498	"kotlinx-coroutines-android":                        28,
499	"kotlinx-coroutines-core":                           28,
500	"libadb_crypto":                                     30,
501	"libadb_pairing_auth":                               30,
502	"libadb_pairing_connection":                         30,
503	"libadb_pairing_server":                             30,
504	"libadb_protos":                                     30,
505	"libadb_tls_connection":                             30,
506	"libadbconnection_client":                           30,
507	"libadbconnection_server":                           30,
508	"libadbd_core":                                      30,
509	"libadbd_services":                                  30,
510	"libadbd":                                           30,
511	"libapp_processes_protos_lite":                      30,
512	"libasyncio":                                        30,
513	"libbrotli":                                         30,
514	"libbuildversion":                                   30,
515	"libcrypto_static":                                  30,
516	"libcrypto_utils":                                   30,
517	"libdiagnose_usb":                                   30,
518	"libeigen":                                          30,
519	"liblz4":                                            30,
520	"libmdnssd":                                         30,
521	"libneuralnetworks_common":                          30,
522	"libneuralnetworks_headers":                         30,
523	"libneuralnetworks":                                 30,
524	"libprocpartition":                                  30,
525	"libprotobuf-java-lite":                             30,
526	"libprotoutil":                                      30,
527	"libqemu_pipe":                                      30,
528	"libstats_jni":                                      30,
529	"libstatslog_statsd":                                30,
530	"libstatsmetadata":                                  30,
531	"libstatspull":                                      30,
532	"libstatssocket":                                    30,
533	"libsync":                                           30,
534	"libtextclassifier_hash_headers":                    30,
535	"libtextclassifier_hash_static":                     30,
536	"libtflite_kernel_utils":                            30,
537	"libwatchdog":                                       29,
538	"libzstd":                                           30,
539	"metrics-constants-protos":                          28,
540	"net-utils-framework-common":                        29,
541	"permissioncontroller-statsd":                       28,
542	"philox_random_headers":                             30,
543	"philox_random":                                     30,
544	"service-permission":                                30,
545	"service-statsd":                                    30,
546	"statsd-aidl-ndk_platform":                          30,
547	"statsd":                                            30,
548	"tensorflow_headers":                                30,
549	"xz-java":                                           29,
550}
551
552// Function called while walking an APEX's payload dependencies.
553//
554// Return true if the `to` module should be visited, false otherwise.
555type PayloadDepsCallback func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool
556
557// UpdatableModule represents updatable APEX/APK
558type UpdatableModule interface {
559	Module
560	WalkPayloadDeps(ctx ModuleContext, do PayloadDepsCallback)
561}
562
563// CheckMinSdkVersion checks if every dependency of an updatable module sets min_sdk_version accordingly
564func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion int) {
565	// do not enforce min_sdk_version for host
566	if ctx.Host() {
567		return
568	}
569
570	// do not enforce for coverage build
571	if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") || ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled() {
572		return
573	}
574
575	// do not enforce deps.min_sdk_version if APEX/APK doesn't set min_sdk_version or
576	// min_sdk_version is not finalized (e.g. current or codenames)
577	if minSdkVersion == FutureApiLevel {
578		return
579	}
580
581	m.WalkPayloadDeps(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool {
582		if externalDep {
583			// external deps are outside the payload boundary, which is "stable" interface.
584			// We don't have to check min_sdk_version for external dependencies.
585			return false
586		}
587		if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
588			return false
589		}
590		if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil {
591			toName := ctx.OtherModuleName(to)
592			if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver > minSdkVersion {
593				ctx.OtherModuleErrorf(to, "should support min_sdk_version(%v) for %q: %v. Dependency path: %s",
594					minSdkVersion, ctx.ModuleName(), err.Error(), ctx.GetPathString(false))
595				return false
596			}
597		}
598		return true
599	})
600}
601