Merge "Touch up manifest if there's no source code." am: 96eac767df

am: c831a0a895

Change-Id: I19cba0c3017eff6f309dae04aacdb7e0aee1613d
This commit is contained in:
Jaewoong Jung 2019-06-06 07:18:38 -07:00 committed by android-build-merger
commit c0ed71ccf8
7 changed files with 156 additions and 9 deletions

View File

@ -85,6 +85,7 @@ type aapt struct {
useEmbeddedDex bool useEmbeddedDex bool
usesNonSdkApis bool usesNonSdkApis bool
sdkLibraries []string sdkLibraries []string
hasNoCode bool
splitNames []string splitNames []string
splits []split splits []split
@ -204,7 +205,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, ex
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile) manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, sdkLibraries, 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...) a.transitiveManifestPaths = append(android.Paths{manifestPath}, transitiveStaticLibManifests...)

View File

@ -53,7 +53,7 @@ var optionalUsesLibs = []string{
// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string, 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 var args []string
if isLibrary { if isLibrary {
@ -87,6 +87,10 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext
} }
} }
if hasNoCode {
args = append(args, "--has-no-code")
}
var deps android.Paths var deps android.Paths
targetSdkVersion := sdkVersionOrDefault(ctx, sdkContext.targetSdkVersion()) targetSdkVersion := sdkVersionOrDefault(ctx, sdkContext.targetSdkVersion())
if targetSdkVersion == ctx.Config().PlatformSdkCodename() && if targetSdkVersion == ctx.Config().PlatformSdkCodename() &&

View File

@ -243,6 +243,9 @@ func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool {
func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis) 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{} aaptLinkFlags := []string{}
// Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided. // Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided.

View File

@ -1327,3 +1327,73 @@ func TestUsesLibraries(t *testing.T) {
t.Errorf("wanted %q in %q", w, cmd) 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)
}
})
}
}

View File

@ -969,8 +969,6 @@ func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaB
func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
hasSrcs := false
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs) j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
deps := j.collectDeps(ctx) deps := j.collectDeps(ctx)
@ -985,9 +983,6 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
} }
srcFiles = j.genSources(ctx, srcFiles, flags) srcFiles = j.genSources(ctx, srcFiles, flags)
if len(srcFiles) > 0 {
hasSrcs = true
}
srcJars := srcFiles.FilterByExt(".srcjar") srcJars := srcFiles.FilterByExt(".srcjar")
srcJars = append(srcJars, deps.srcJars...) srcJars = append(srcJars, deps.srcJars...)
@ -1184,7 +1179,6 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
if len(deps.staticJars) > 0 { if len(deps.staticJars) > 0 {
jars = append(jars, deps.staticJars...) jars = append(jars, deps.staticJars...)
hasSrcs = true
} }
manifest := j.overrideManifest manifest := j.overrideManifest
@ -1296,7 +1290,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
j.implementationAndResourcesJar = implementationAndResourcesJar j.implementationAndResourcesJar = implementationAndResourcesJar
if ctx.Device() && hasSrcs && if ctx.Device() && j.hasCode(ctx) &&
(Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) { (Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
// Dex compilation // Dex compilation
var dexOutputFile android.ModuleOutPath var dexOutputFile android.ModuleOutPath
@ -1501,6 +1495,11 @@ func (j *Module) CompilerDeps() []string {
return jdeps 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) // Java libraries (.jar file)
// //

View File

@ -59,6 +59,9 @@ def parse_args():
default=None, type=lambda x: (str(x).lower() == 'true'), default=None, type=lambda x: (str(x).lower() == 'true'),
help=('specify if the app wants to use embedded native libraries. Must not conflict ' help=('specify if the app wants to use embedded native libraries. Must not conflict '
'if already declared in the manifest.')) '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('input', help='input AndroidManifest.xml file')
parser.add_argument('output', help='output AndroidManifest.xml file') parser.add_argument('output', help='output AndroidManifest.xml file')
return parser.parse_args() return parser.parse_args()
@ -245,6 +248,28 @@ def add_extract_native_libs(doc, extract_native_libs):
(attr.value, value)) (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(): def main():
"""Program entry point.""" """Program entry point."""
try: try:
@ -269,6 +294,9 @@ def main():
if args.use_embedded_dex: if args.use_embedded_dex:
add_use_embedded_dex(doc) add_use_embedded_dex(doc)
if args.has_no_code:
set_has_code_to_false(doc)
if args.extract_native_libs is not None: if args.extract_native_libs is not None:
add_extract_native_libs(doc, args.extract_native_libs) add_extract_native_libs(doc, args.extract_native_libs)

View File

@ -424,5 +424,47 @@ class AddExtractNativeLibsTest(unittest.TestCase):
self.assertRaises(RuntimeError, self.run_test, manifest_input, False) 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__': if __name__ == '__main__':
unittest.main(verbosity=2) unittest.main(verbosity=2)