• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2019 The Android Open Source Project
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 apex
16
17import (
18	"strings"
19
20	"android/soong/android"
21	"android/soong/cc"
22
23	"github.com/google/blueprint/proptools"
24)
25
26const (
27	vndkApexName       = "com.android.vndk"
28	vndkApexNamePrefix = vndkApexName + ".v"
29)
30
31// apex_vndk creates a special variant of apex modules which contains only VNDK libraries.
32// If `vndk_version` is specified, the VNDK libraries of the specified VNDK version are gathered automatically.
33// If not specified, then the "current" versions are gathered.
34func vndkApexBundleFactory() android.Module {
35	bundle := newApexBundle()
36	bundle.vndkApex = true
37	bundle.AddProperties(&bundle.vndkProperties)
38	android.AddLoadHook(bundle, func(ctx android.LoadHookContext) {
39		ctx.AppendProperties(&struct {
40			Compile_multilib *string
41		}{
42			proptools.StringPtr("both"),
43		})
44	})
45	return bundle
46}
47
48func (a *apexBundle) vndkVersion(config android.DeviceConfig) string {
49	vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current")
50	if vndkVersion == "current" {
51		vndkVersion = config.PlatformVndkVersion()
52	}
53	return vndkVersion
54}
55
56type apexVndkProperties struct {
57	// Indicates VNDK version of which this VNDK APEX bundles VNDK libs. Default is Platform VNDK Version.
58	Vndk_version *string
59}
60
61func apexVndkMutator(mctx android.TopDownMutatorContext) {
62	if ab, ok := mctx.Module().(*apexBundle); ok && ab.vndkApex {
63		if ab.IsNativeBridgeSupported() {
64			mctx.PropertyErrorf("native_bridge_supported", "%q doesn't support native bridge binary.", mctx.ModuleType())
65		}
66
67		vndkVersion := ab.vndkVersion(mctx.DeviceConfig())
68		apiLevel, err := android.ApiLevelFromUser(mctx, vndkVersion)
69		if err != nil {
70			mctx.PropertyErrorf("vndk_version", "%s", err.Error())
71			return
72		}
73
74		targets := mctx.MultiTargets()
75		if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) &&
76			vndkVersion != mctx.DeviceConfig().PlatformVndkVersion() {
77			// Disable VNDK APEXes for VNDK versions less than the minimum supported API
78			// level for the primary architecture. This validation is skipped if the VNDK
79			// version matches the platform VNDK version, which can occur when the device
80			// config targets the 'current' VNDK (see `vndkVersion`).
81			ab.Disable()
82		}
83	}
84}
85
86func apexVndkDepsMutator(mctx android.BottomUpMutatorContext) {
87	if m, ok := mctx.Module().(*cc.Module); ok && cc.IsForVndkApex(mctx, m) {
88		vndkVersion := m.VndkVersion()
89		// For VNDK-Lite device, we gather core-variants of VNDK-Sp libraries, which doesn't have VNDK version defined
90		if vndkVersion == "" {
91			vndkVersion = mctx.DeviceConfig().PlatformVndkVersion()
92		}
93		if vndkVersion == mctx.DeviceConfig().PlatformVndkVersion() {
94			vndkVersion = "current"
95		} else {
96			vndkVersion = "v" + vndkVersion
97		}
98
99		vndkApexName := "com.android.vndk." + vndkVersion
100
101		if mctx.OtherModuleExists(vndkApexName) {
102			mctx.AddReverseDependency(mctx.Module(), sharedLibTag, vndkApexName)
103		}
104	} else if a, ok := mctx.Module().(*apexBundle); ok && a.vndkApex {
105		vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current")
106		mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion)...)
107	}
108}
109
110// name is module.BaseModuleName() which is used as LOCAL_MODULE_NAME and also LOCAL_OVERRIDES_*
111func makeCompatSymlinks(name string, ctx android.ModuleContext, primaryApex bool) (symlinks android.InstallPaths) {
112	// small helper to add symlink commands
113	addSymlink := func(target string, dir android.InstallPath, linkName string) {
114		if primaryApex {
115			symlinks = append(symlinks, ctx.InstallAbsoluteSymlink(dir, linkName, target))
116		} else {
117			symlinks = append(symlinks, dir.Join(ctx, linkName))
118		}
119	}
120
121	// TODO(b/142911355): [VNDK APEX] Fix hard-coded references to /system/lib/vndk
122	// When all hard-coded references are fixed, remove symbolic links
123	// Note that  we should keep following symlinks for older VNDKs (<=29)
124	// Since prebuilt vndk libs still depend on system/lib/vndk path
125	if strings.HasPrefix(name, vndkApexNamePrefix) {
126		vndkVersion := strings.TrimPrefix(name, vndkApexNamePrefix)
127		if ver, err := android.ApiLevelFromUser(ctx, vndkVersion); err != nil {
128			ctx.ModuleErrorf("apex_vndk should be named as %v<ver:number>: %s", vndkApexNamePrefix, name)
129			return
130		} else if ver.GreaterThan(android.SdkVersion_Android10) {
131			return
132		}
133		// the name of vndk apex is formatted "com.android.vndk.v" + version
134		apexName := vndkApexNamePrefix + vndkVersion
135		if ctx.Config().Android64() {
136			dir := android.PathForModuleInPartitionInstall(ctx, "system", "lib64")
137			addSymlink("/apex/"+apexName+"/lib64", dir, "vndk-sp-"+vndkVersion)
138			addSymlink("/apex/"+apexName+"/lib64", dir, "vndk-"+vndkVersion)
139		}
140		if !ctx.Config().Android64() || ctx.DeviceConfig().DeviceSecondaryArch() != "" {
141			dir := android.PathForModuleInPartitionInstall(ctx, "system", "lib")
142			addSymlink("/apex/"+apexName+"/lib", dir, "vndk-sp-"+vndkVersion)
143			addSymlink("/apex/"+apexName+"/lib", dir, "vndk-"+vndkVersion)
144		}
145	}
146
147	// http://b/121248172 - create a link from /system/usr/icu to
148	// /apex/com.android.i18n/etc/icu so that apps can find the ICU .dat file.
149	// A symlink can't overwrite a directory and the /system/usr/icu directory once
150	// existed so the required structure must be created whatever we find.
151	if name == "com.android.i18n" {
152		dir := android.PathForModuleInPartitionInstall(ctx, "system", "usr")
153		addSymlink("/apex/com.android.i18n/etc/icu", dir, "icu")
154	}
155
156	return symlinks
157}
158