Merge "Touch up manifest if there's no source code."
diff --git a/java/aar.go b/java/aar.go
index 65a7c2a..1b84a47 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -85,6 +85,7 @@
useEmbeddedDex bool
usesNonSdkApis bool
sdkLibraries []string
+ hasNoCode bool
splitNames []string
splits []split
@@ -204,7 +205,7 @@
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, sdkLibraries,
- a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex)
+ a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode)
a.transitiveManifestPaths = append(android.Paths{manifestPath}, transitiveStaticLibManifests...)
diff --git a/java/android_manifest.go b/java/android_manifest.go
index b5921be..021883e 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -53,7 +53,7 @@
// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string,
- isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex bool) android.Path {
+ isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool) android.Path {
var args []string
if isLibrary {
@@ -87,6 +87,10 @@
}
}
+ if hasNoCode {
+ args = append(args, "--has-no-code")
+ }
+
var deps android.Paths
targetSdkVersion := sdkVersionOrDefault(ctx, sdkContext.targetSdkVersion())
if targetSdkVersion == ctx.Config().PlatformSdkCodename() &&
diff --git a/java/app.go b/java/app.go
index 8624a74..3c8f847 100644
--- a/java/app.go
+++ b/java/app.go
@@ -243,6 +243,9 @@
func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis)
+ // Ask manifest_fixer to add or update the application element indicating this app has no code.
+ a.aapt.hasNoCode = !a.hasCode(ctx)
+
aaptLinkFlags := []string{}
// Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided.
diff --git a/java/app_test.go b/java/app_test.go
index 0f2c1cf..bb39c16 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1327,3 +1327,73 @@
t.Errorf("wanted %q in %q", w, cmd)
}
}
+
+func TestCodelessApp(t *testing.T) {
+ testCases := []struct {
+ name string
+ bp string
+ noCode bool
+ }{
+ {
+ name: "normal",
+ bp: `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ }
+ `,
+ noCode: false,
+ },
+ {
+ name: "app without sources",
+ bp: `
+ android_app {
+ name: "foo",
+ }
+ `,
+ noCode: true,
+ },
+ {
+ name: "app with libraries",
+ bp: `
+ android_app {
+ name: "foo",
+ static_libs: ["lib"],
+ }
+
+ java_library {
+ name: "lib",
+ srcs: ["a.java"],
+ }
+ `,
+ noCode: false,
+ },
+ {
+ name: "app with sourceless libraries",
+ bp: `
+ android_app {
+ name: "foo",
+ static_libs: ["lib"],
+ }
+
+ java_library {
+ name: "lib",
+ }
+ `,
+ // TODO(jungjw): this should probably be true
+ noCode: false,
+ },
+ }
+
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ ctx := testApp(t, test.bp)
+
+ foo := ctx.ModuleForTests("foo", "android_common")
+ manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+ if strings.Contains(manifestFixerArgs, "--has-no-code") != test.noCode {
+ t.Errorf("unexpected manifest_fixer args: %q", manifestFixerArgs)
+ }
+ })
+ }
+}
diff --git a/java/java.go b/java/java.go
index 0bccb67..5544f57 100644
--- a/java/java.go
+++ b/java/java.go
@@ -969,8 +969,6 @@
func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
- hasSrcs := false
-
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
deps := j.collectDeps(ctx)
@@ -985,9 +983,6 @@
}
srcFiles = j.genSources(ctx, srcFiles, flags)
- if len(srcFiles) > 0 {
- hasSrcs = true
- }
srcJars := srcFiles.FilterByExt(".srcjar")
srcJars = append(srcJars, deps.srcJars...)
@@ -1184,7 +1179,6 @@
if len(deps.staticJars) > 0 {
jars = append(jars, deps.staticJars...)
- hasSrcs = true
}
manifest := j.overrideManifest
@@ -1296,7 +1290,7 @@
j.implementationAndResourcesJar = implementationAndResourcesJar
- if ctx.Device() && hasSrcs &&
+ if ctx.Device() && j.hasCode(ctx) &&
(Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
// Dex compilation
var dexOutputFile android.ModuleOutPath
@@ -1501,6 +1495,11 @@
return jdeps
}
+func (j *Module) hasCode(ctx android.ModuleContext) bool {
+ srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
+ return len(srcFiles) > 0 || len(ctx.GetDirectDepsWithTag(staticLibTag)) > 0
+}
+
//
// Java libraries (.jar file)
//
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index bb14851..945bc18 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -59,6 +59,9 @@
default=None, type=lambda x: (str(x).lower() == 'true'),
help=('specify if the app wants to use embedded native libraries. Must not conflict '
'if already declared in the manifest.'))
+ 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('input', help='input AndroidManifest.xml file')
parser.add_argument('output', help='output AndroidManifest.xml file')
return parser.parse_args()
@@ -245,6 +248,28 @@
(attr.value, value))
+def set_has_code_to_false(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, 'hasCode')
+ if attr is not None:
+ # Do nothing if the application already has a hasCode attribute.
+ return
+ attr = doc.createAttributeNS(android_ns, 'android:hasCode')
+ attr.value = 'false'
+ application.setAttributeNode(attr)
+
+
def main():
"""Program entry point."""
try:
@@ -269,6 +294,9 @@
if args.use_embedded_dex:
add_use_embedded_dex(doc)
+ if args.has_no_code:
+ set_has_code_to_false(doc)
+
if args.extract_native_libs is not None:
add_extract_native_libs(doc, args.extract_native_libs)
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 2035421..ea8095e 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -424,5 +424,47 @@
self.assertRaises(RuntimeError, self.run_test, manifest_input, False)
+class AddNoCodeApplicationTest(unittest.TestCase):
+ """Unit tests for set_has_code_to_false function."""
+
+ def run_test(self, input_manifest):
+ doc = minidom.parseString(input_manifest)
+ manifest_fixer.set_has_code_to_false(doc)
+ output = StringIO.StringIO()
+ manifest_fixer.write_xml(output, doc)
+ return output.getvalue()
+
+ manifest_tmpl = (
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+ '%s'
+ '</manifest>\n')
+
+ def test_no_application(self):
+ manifest_input = self.manifest_tmpl % ''
+ expected = self.manifest_tmpl % ' <application android:hasCode="false"/>\n'
+ output = self.run_test(manifest_input)
+ self.assertEqual(output, expected)
+
+ def test_has_application_no_has_code(self):
+ manifest_input = self.manifest_tmpl % ' <application/>\n'
+ expected = self.manifest_tmpl % ' <application android:hasCode="false"/>\n'
+ output = self.run_test(manifest_input)
+ self.assertEqual(output, expected)
+
+ def test_has_application_has_code_false(self):
+ """ Do nothing if there's already an application elemeent. """
+ manifest_input = self.manifest_tmpl % ' <application android:hasCode="false"/>\n'
+ output = self.run_test(manifest_input)
+ self.assertEqual(output, manifest_input)
+
+ def test_has_application_has_code_true(self):
+ """ Do nothing if there's already an application elemeent even if its
+ hasCode attribute is true. """
+ manifest_input = self.manifest_tmpl % ' <application android:hasCode="true"/>\n'
+ output = self.run_test(manifest_input)
+ self.assertEqual(output, manifest_input)
+
+
if __name__ == '__main__':
unittest.main(verbosity=2)