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

Commit 75d65f36 authored by Gurpreet Singh's avatar Gurpreet Singh
Browse files

Add testOnly attribute to AndroidManifest file of apex_test

If the build file contains the apex_test module, add the
testOnly attribute to the application element of the
corresponding AndroidManifest file and set its value to true.
If the testOnly attribute is already present and has value
false, then do nothing.

Tests added in manifest_fixer_test.py to check if the updated
AndroidManifest file has the testOnly attribute set to true or not.

Bug: 213310150
Test: atest --host manifest_fixer_test
Test: m nothing
Test: manually checked the AndroidManifest file generated
Change-Id: I36247dbe0261c342d451a4422c314fd8fe0c2369
parent 2d305010
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -397,6 +397,22 @@ func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.Output
	return output.OutputPath
}

func markManifestTestOnly(ctx android.ModuleContext, androidManifestFile android.Path) android.Path {
	return java.ManifestFixer(java.ManifestFixerParams{
		Ctx:                   ctx,
		Manifest:              androidManifestFile,
		SdkContext:            nil,
		ClassLoaderContexts:   nil,
		IsLibrary:             false,
		UseEmbeddedNativeLibs: false,
		UsesNonSdkApis:        false,
		UseEmbeddedDex:        false,
		HasNoCode:             false,
		TestOnly:              true,
		LoggingParent:         "",
	})
}

// buildUnflattendApex creates build rules to build an APEX using apexer.
func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
	apexType := a.properties.ApexType
@@ -595,6 +611,11 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {

		if a.properties.AndroidManifest != nil {
			androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))

			if a.testApex {
				androidManifestFile = markManifestTestOnly(ctx, androidManifestFile)
			}

			implicitInputs = append(implicitInputs, androidManifestFile)
			optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
		}
+13 −3
Original line number Diff line number Diff line
@@ -276,9 +276,19 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
	manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
	manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)

	manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, classLoaderContexts,
		a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode,
		a.LoggingParent)
	manifestPath := ManifestFixer(ManifestFixerParams{
		Ctx:                   ctx,
		Manifest:              manifestSrcPath,
		SdkContext:            sdkContext,
		ClassLoaderContexts:   classLoaderContexts,
		IsLibrary:             a.isLibrary,
		UseEmbeddedNativeLibs: a.useEmbeddedNativeLibs,
		UsesNonSdkApis:        a.usesNonSdkApis,
		UseEmbeddedDex:        a.useEmbeddedDex,
		HasNoCode:             a.hasNoCode,
		TestOnly:              false,
		LoggingParent:         a.LoggingParent,
	})

	// Add additional manifest files to transitive manifests.
	additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests)
+74 −51
Original line number Diff line number Diff line
@@ -28,13 +28,10 @@ import (
var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer",
	blueprint.RuleParams{
		Command: `${config.ManifestFixerCmd} ` +
			`--minSdkVersion ${minSdkVersion} ` +
			`--targetSdkVersion ${targetSdkVersion} ` +
			`--raise-min-sdk-version ` +
			`$args $in $out`,
		CommandDeps: []string{"${config.ManifestFixerCmd}"},
	},
	"minSdkVersion", "targetSdkVersion", "args")
	"args")

var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger",
	blueprint.RuleParams{
@@ -58,84 +55,110 @@ func targetSdkVersionForManifestFixer(ctx android.ModuleContext, sdkContext andr
	return targetSdkVersion
}

// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext android.SdkContext,
	classLoaderContexts dexpreopt.ClassLoaderContextMap, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis,
	useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
type ManifestFixerParams struct {
	Ctx                   android.ModuleContext
	Manifest              android.Path
	SdkContext            android.SdkContext
	ClassLoaderContexts   dexpreopt.ClassLoaderContextMap
	IsLibrary             bool
	UseEmbeddedNativeLibs bool
	UsesNonSdkApis        bool
	UseEmbeddedDex        bool
	HasNoCode             bool
	TestOnly              bool
	LoggingParent         string
}

// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
func ManifestFixer(params ManifestFixerParams) android.Path {
	var args []string
	if isLibrary {

	if params.IsLibrary {
		args = append(args, "--library")
	} else {
		minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersion(ctx)
	} else if params.SdkContext != nil {
		minSdkVersion, err := params.SdkContext.MinSdkVersion(params.Ctx).EffectiveVersion(params.Ctx)
		if err != nil {
			ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
			params.Ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
		}
		if minSdkVersion.FinalOrFutureInt() >= 23 {
			args = append(args, fmt.Sprintf("--extract-native-libs=%v", !useEmbeddedNativeLibs))
		} else if useEmbeddedNativeLibs {
			ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
			args = append(args, fmt.Sprintf("--extract-native-libs=%v", !params.UseEmbeddedNativeLibs))
		} else if params.UseEmbeddedNativeLibs {
			params.Ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
				minSdkVersion)
		}
	}

	if usesNonSdkApis {
	if params.UsesNonSdkApis {
		args = append(args, "--uses-non-sdk-api")
	}

	if useEmbeddedDex {
	if params.UseEmbeddedDex {
		args = append(args, "--use-embedded-dex")
	}

	if params.ClassLoaderContexts != nil {
		// manifest_fixer should add only the implicit SDK libraries inferred by Soong, not those added
		// explicitly via `uses_libs`/`optional_uses_libs`.
	requiredUsesLibs, optionalUsesLibs := classLoaderContexts.ImplicitUsesLibs()
		requiredUsesLibs, optionalUsesLibs := params.ClassLoaderContexts.ImplicitUsesLibs()

		for _, usesLib := range requiredUsesLibs {
			args = append(args, "--uses-library", usesLib)
		}
		for _, usesLib := range optionalUsesLibs {
			args = append(args, "--optional-uses-library", usesLib)
		}
	}

	if hasNoCode {
	if params.HasNoCode {
		args = append(args, "--has-no-code")
	}

	if loggingParent != "" {
		args = append(args, "--logging-parent", loggingParent)
	if params.TestOnly {
		args = append(args, "--test-only")
	}

	if params.LoggingParent != "" {
		args = append(args, "--logging-parent", params.LoggingParent)
	}
	var deps android.Paths
	targetSdkVersion := targetSdkVersionForManifestFixer(ctx, sdkContext)
	var argsMapper = make(map[string]string)

	if params.SdkContext != nil {
		targetSdkVersion := targetSdkVersionForManifestFixer(params.Ctx, params.SdkContext)
		args = append(args, "--targetSdkVersion ", targetSdkVersion)

	if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
		targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
		deps = append(deps, ApiFingerprintPath(ctx))
		if UseApiFingerprint(params.Ctx) && params.Ctx.ModuleName() != "framework-res" {
			targetSdkVersion = params.Ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(params.Ctx).String())
			deps = append(deps, ApiFingerprintPath(params.Ctx))
		}

	minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx)
		minSdkVersion, err := params.SdkContext.MinSdkVersion(params.Ctx).EffectiveVersionString(params.Ctx)
		if err != nil {
		ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
			params.Ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
		}
	if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
		minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
		deps = append(deps, ApiFingerprintPath(ctx))

		if UseApiFingerprint(params.Ctx) && params.Ctx.ModuleName() != "framework-res" {
			minSdkVersion = params.Ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(params.Ctx).String())
			deps = append(deps, ApiFingerprintPath(params.Ctx))
		}

	fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
		if err != nil {
		ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
			params.Ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
		}
	ctx.Build(pctx, android.BuildParams{
		args = append(args, "--minSdkVersion ", minSdkVersion)
		args = append(args, "--raise-min-sdk-version")
	}

	fixedManifest := android.PathForModuleOut(params.Ctx, "manifest_fixer", "AndroidManifest.xml")
	argsMapper["args"] = strings.Join(args, " ")

	params.Ctx.Build(pctx, android.BuildParams{
		Rule:        manifestFixerRule,
		Description: "fix manifest",
		Input:       manifest,
		Input:       params.Manifest,
		Implicits:   deps,
		Output:      fixedManifest,
		Args: map[string]string{
			"minSdkVersion":    minSdkVersion,
			"targetSdkVersion": targetSdkVersion,
			"args":             strings.Join(args, " "),
		},
		Args:        argsMapper,
	})

	return fixedManifest.WithoutRel()
+3 −3
Original line number Diff line number Diff line
@@ -2512,7 +2512,7 @@ func TestUsesLibraries(t *testing.T) {
		`--uses-library qux ` +
		`--uses-library quuz ` +
		`--uses-library runtime-library`
	android.AssertStringEquals(t, "manifest_fixer args", expectManifestFixerArgs, actualManifestFixerArgs)
	android.AssertStringDoesContain(t, "manifest_fixer args", actualManifestFixerArgs, expectManifestFixerArgs)

	// Test that all libraries are verified (library order matters).
	verifyCmd := app.Rule("verify_uses_libraries").RuleParams.Command
@@ -3055,7 +3055,7 @@ func TestTargetSdkVersionManifestFixer(t *testing.T) {
		result := fixture.RunTestWithBp(t, bp)
		foo := result.ModuleForTests("foo", "android_common")

		manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args
		android.AssertStringEquals(t, testCase.name, testCase.targetSdkVersionExpected, manifestFixerArgs["targetSdkVersion"])
		manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
		android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion  "+testCase.targetSdkVersionExpected)
	}
}
+26 −0
Original line number Diff line number Diff line
@@ -65,6 +65,9 @@ def parse_args():
  parser.add_argument('--has-no-code', dest='has_no_code', action='store_true',
                      help=('adds hasCode="false" attribute to application. Ignored if application elem '
                            'already has a hasCode attribute.'))
  parser.add_argument('--test-only', dest='test_only', action='store_true',
                      help=('adds testOnly="true" attribute to application. Assign true value if application elem '
                            'already has a testOnly attribute.'))
  parser.add_argument('input', help='input AndroidManifest.xml file')
  parser.add_argument('output', help='output AndroidManifest.xml file')
  return parser.parse_args()
@@ -318,6 +321,26 @@ def set_has_code_to_false(doc):
  attr.value = 'false'
  application.setAttributeNode(attr)

def set_test_only_flag_to_true(doc):
  manifest = parse_manifest(doc)
  elems = get_children_with_tag(manifest, 'application')
  application = elems[0] if len(elems) == 1 else None
  if len(elems) > 1:
    raise RuntimeError('found multiple <application> tags')
  elif not elems:
    application = doc.createElement('application')
    indent = get_indent(manifest.firstChild, 1)
    first = manifest.firstChild
    manifest.insertBefore(doc.createTextNode(indent), first)
    manifest.insertBefore(application, first)

  attr = application.getAttributeNodeNS(android_ns, 'testOnly')
  if attr is not None:
    # Do nothing If the application already has a testOnly attribute.
    return
  attr = doc.createAttributeNS(android_ns, 'android:testOnly')
  attr.value = 'true'
  application.setAttributeNode(attr)

def main():
  """Program entry point."""
@@ -349,6 +372,9 @@ def main():
    if args.has_no_code:
      set_has_code_to_false(doc)

    if args.test_only:
      set_test_only_flag_to_true(doc)

    if args.extract_native_libs is not None:
      add_extract_native_libs(doc, args.extract_native_libs)

Loading