Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e5ac15a1 authored by Artur Satayev's avatar Artur Satayev
Browse files

Check updatable APKs compile against managed SDKs.

As a follow up, this property will be set to APKs participating in mainline program.

Bug: 153333044
Test: m
Change-Id: I6ea2f3c1d26992259e4e9e6a6d8cecf091d39c43
Merged-In: I6ea2f3c1d26992259e4e9e6a6d8cecf091d39c43
(cherry picked from commit 2db1c3f1)
Exempt-From-Owner-Approval: clean cherry-pick
parent ee42b207
Loading
Loading
Loading
Loading
+16 −2
Original line number Diff line number Diff line
@@ -110,6 +110,10 @@ type appProperties struct {
	PreventInstall    bool `blueprint:"mutated"`
	HideFromMake      bool `blueprint:"mutated"`
	IsCoverageVariant bool `blueprint:"mutated"`

	// Whether this app is considered mainline updatable or not. When set to true, this will enforce
	// additional rules for making sure that the APK is truly updatable. Default is false.
	Updatable *bool
}

// android_app properties that can be overridden by override_android_app
@@ -242,11 +246,21 @@ func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleCon
}

func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	a.checkPlatformAPI(ctx)
	a.checkSdkVersion(ctx)
	a.checkAppSdkVersions(ctx)
	a.generateAndroidBuildActions(ctx)
}

func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
	if Bool(a.appProperties.Updatable) {
		if !a.sdkVersion().stable() {
			ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.sdkVersion())
		}
	}

	a.checkPlatformAPI(ctx)
	a.checkSdkVersions(ctx)
}

// Returns true if the native libraries should be stored in the APK uncompressed and the
// extractNativeLibs application flag should be set to false in the manifest.
func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool {
+102 −0
Original line number Diff line number Diff line
@@ -264,6 +264,108 @@ func TestAndroidAppLinkType(t *testing.T) {
	`)
}

func TestUpdatableApps(t *testing.T) {
	testCases := []struct {
		name          string
		bp            string
		expectedError string
	}{
		{
			name: "Stable public SDK",
			bp: `android_app {
					name: "foo",
					srcs: ["a.java"],
					sdk_version: "29",
					updatable: true,
				}`,
		},
		{
			name: "Stable system SDK",
			bp: `android_app {
					name: "foo",
					srcs: ["a.java"],
					sdk_version: "system_29",
					updatable: true,
				}`,
		},
		{
			name: "Current public SDK",
			bp: `android_app {
					name: "foo",
					srcs: ["a.java"],
					sdk_version: "current",
					updatable: true,
				}`,
		},
		{
			name: "Current system SDK",
			bp: `android_app {
					name: "foo",
					srcs: ["a.java"],
					sdk_version: "system_current",
					updatable: true,
				}`,
		},
		{
			name: "Current module SDK",
			bp: `android_app {
					name: "foo",
					srcs: ["a.java"],
					sdk_version: "module_current",
					updatable: true,
				}`,
		},
		{
			name: "Current core SDK",
			bp: `android_app {
					name: "foo",
					srcs: ["a.java"],
					sdk_version: "core_current",
					updatable: true,
				}`,
		},
		{
			name: "No Platform APIs",
			bp: `android_app {
					name: "foo",
					srcs: ["a.java"],
					platform_apis: true,
					updatable: true,
				}`,
			expectedError: "Updatable apps must use stable SDKs",
		},
		{
			name: "No Core Platform APIs",
			bp: `android_app {
					name: "foo",
					srcs: ["a.java"],
					sdk_version: "core_platform",
					updatable: true,
				}`,
			expectedError: "Updatable apps must use stable SDKs",
		},
		{
			name: "No unspecified APIs",
			bp: `android_app {
					name: "foo",
					srcs: ["a.java"],
					updatable: true,
				}`,
			expectedError: "Updatable apps must use stable SDK",
		},
	}

	for _, test := range testCases {
		t.Run(test.name, func(t *testing.T) {
			if test.expectedError == "" {
				testJava(t, test.bp)
			} else {
				testJavaError(t, test.expectedError, test.bp)
			}
		})
	}
}

func TestResourceDirs(t *testing.T) {
	testCases := []struct {
		name      string
+15 −11
Original line number Diff line number Diff line
@@ -80,7 +80,7 @@ func RegisterJavaBuildComponents(ctx android.RegistrationContext) {
	ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
}

func (j *Module) checkSdkVersion(ctx android.ModuleContext) {
func (j *Module) checkSdkVersions(ctx android.ModuleContext) {
	if j.SocSpecific() || j.DeviceSpecific() ||
		(j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
		if sc, ok := ctx.Module().(sdkContext); ok {
@@ -90,6 +90,18 @@ func (j *Module) checkSdkVersion(ctx android.ModuleContext) {
			}
		}
	}

	ctx.VisitDirectDeps(func(module android.Module) {
		tag := ctx.OtherModuleDependencyTag(module)
		switch module.(type) {
		// TODO(satayev): cover other types as well, e.g. imports
		case *Library, *AndroidLibrary:
			switch tag {
			case bootClasspathTag, libTag, staticLibTag, java9LibTag:
				checkLinkType(ctx, j, module.(linkTypeContext), tag.(dependencyTag))
			}
		}
	})
}

func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
@@ -892,15 +904,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
			// Handled by AndroidApp.collectAppDeps
			return
		}
		switch module.(type) {
		case *Library, *AndroidLibrary:
			if to, ok := module.(linkTypeContext); ok {
				switch tag {
				case bootClasspathTag, libTag, staticLibTag:
					checkLinkType(ctx, j, to, tag.(dependencyTag))
				}
			}
		}

		switch dep := module.(type) {
		case SdkLibraryDependency:
			switch tag {
@@ -1817,7 +1821,7 @@ func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bo
}

func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	j.checkSdkVersion(ctx)
	j.checkSdkVersions(ctx)
	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
	j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
	j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
+21 −0
Original line number Diff line number Diff line
@@ -147,6 +147,10 @@ type sdkSpec struct {
	raw     string
}

func (s sdkSpec) String() string {
	return fmt.Sprintf("%s_%s", s.kind, s.version)
}

// valid checks if this sdkSpec is well-formed. Note however that true doesn't mean that the
// specified SDK actually exists.
func (s sdkSpec) valid() bool {
@@ -158,6 +162,23 @@ func (s sdkSpec) specified() bool {
	return s.valid() && s.kind != sdkPrivate
}

// whether the API surface is managed and versioned, i.e. has .txt file that
// get frozen on SDK freeze and changes get reviewed by API council.
func (s sdkSpec) stable() bool {
	if !s.specified() {
		return false
	}
	switch s.kind {
	case sdkCore, sdkPublic, sdkSystem, sdkModule, sdkSystemServer:
		return true
	case sdkNone, sdkCorePlatform, sdkTest, sdkPrivate:
		return false
	default:
		panic(fmt.Errorf("unknown sdkKind=%v", s.kind))
	}
	return false
}

// prebuiltSdkAvailableForUnbundledBuilt tells whether this sdkSpec can have a prebuilt SDK
// that can be used for unbundled builds.
func (s sdkSpec) prebuiltSdkAvailableForUnbundledBuild() bool {