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

Commit 0b3e45ab authored by satayev's avatar satayev Committed by Gerrit Code Review
Browse files

Merge "Check updatable APKs compile against managed SDKs."

parents 7f64ed9d 2db1c3f1
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
@@ -249,11 +253,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
@@ -86,7 +86,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 {
@@ -96,6 +96,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) {
@@ -898,15 +910,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 {
@@ -1818,7 +1822,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 {