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

Commit c2ea958b authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes from topic "flag_application_manifest" into main

* changes:
  Support multiple <application> or <uses-sdk> elements in manifest_*.py
  Fix manifest_fixer.py warnings
parents 05d90690 e1ab849b
Loading
Loading
Loading
Loading
+32 −1
Original line number Diff line number Diff line
@@ -23,6 +23,37 @@ from xml.dom import minidom
android_ns = 'http://schemas.android.com/apk/res/android'


def get_or_create_applications(doc, manifest):
  """Get all <application> tags from the manifest, or create one if none exist.
  Multiple <application> tags may exist when manifest feature flagging is used.
  """
  applications = get_children_with_tag(manifest, 'application')
  if len(applications) == 0:
    application = doc.createElement('application')
    indent = get_indent(manifest.firstChild, 1)
    first = manifest.firstChild
    manifest.insertBefore(doc.createTextNode(indent), first)
    manifest.insertBefore(application, first)
    applications.append(application)
  return applications


def get_or_create_uses_sdks(doc, manifest):
  """Get all <uses-sdk> tags from the manifest, or create one if none exist.
  Multiple <uses-sdk> tags may exist when manifest feature flagging is used.
  """
  uses_sdks = get_children_with_tag(manifest, 'uses-sdk')
  if len(uses_sdks) == 0:
    uses_sdk = doc.createElement('uses-sdk')
    indent = get_indent(manifest.firstChild, 1)
    manifest.insertBefore(uses_sdk, manifest.firstChild)

    # Insert an indent before uses-sdk to line it up with the indentation of the
    # other children of the <manifest> tag.
    manifest.insertBefore(doc.createTextNode(indent), manifest.firstChild)
    uses_sdks.append(uses_sdk)
  return uses_sdks

def get_children_with_tag(parent, tag_name):
  children = []
  for child in parent.childNodes:
+8 −17
Original line number Diff line number Diff line
@@ -25,10 +25,7 @@ import subprocess
import sys
from xml.dom import minidom

from manifest import android_ns
from manifest import get_children_with_tag
from manifest import parse_manifest
from manifest import write_xml
from manifest import *


class ManifestMismatchError(Exception):
@@ -122,7 +119,7 @@ def enforce_uses_libraries(manifest, required, optional, missing_optional, relax
    # handles module names specified in Android.bp properties. However not all
    # <uses-library> entries in the manifest correspond to real modules: some of
    # the optional libraries may be missing at build time. Therefor this script
    # accepts raw module names as spelled in Android.bp/Amdroid.mk and trims the
    # accepts raw module names as spelled in Android.bp/Android.mk and trims the
    # optional namespace part manually.
    required = trim_namespace_parts(required)
    optional = trim_namespace_parts(optional)
@@ -205,15 +202,9 @@ def extract_uses_libs_xml(xml):
    """Extract <uses-library> tags from the manifest."""

    manifest = parse_manifest(xml)
    elems = get_children_with_tag(manifest, 'application')
    if len(elems) > 1:
        raise RuntimeError('found multiple <application> tags')
    if not elems:
        return [], [], []

    application = elems[0]

    libs = get_children_with_tag(application, 'uses-library')
    libs = [child
            for application in get_or_create_applications(xml, manifest)
            for child in get_children_with_tag(application, 'uses-library')]

    required = [uses_library_name(x) for x in libs if uses_library_required(x)]
    optional = [
@@ -376,7 +367,7 @@ def main():

            # Create a status file that is empty on success, or contains an
            # error message on failure. When exceptions are suppressed,
            # dexpreopt command command will check file size to determine if
            # dexpreopt command will check file size to determine if
            # the check has failed.
            if args.enforce_uses_libraries_status:
                with open(args.enforce_uses_libraries_status, 'w') as f:
+34 −8
Original line number Diff line number Diff line
@@ -44,8 +44,8 @@ def required_apk(value):
class EnforceUsesLibrariesTest(unittest.TestCase):
    """Unit tests for add_extract_native_libs function."""

    def run_test(self, xml, apk, uses_libraries=[], optional_uses_libraries=[],
                 missing_optional_uses_libraries=[]): #pylint: disable=dangerous-default-value
    def run_test(self, xml, apk, uses_libraries=(), optional_uses_libraries=(),
                 missing_optional_uses_libraries=()):  #pylint: disable=dangerous-default-value
        doc = minidom.parseString(xml)
        try:
            relax = False
@@ -114,14 +114,14 @@ class EnforceUsesLibrariesTest(unittest.TestCase):
        self.assertFalse(matches)

    def test_missing_uses_library(self):
        xml = self.xml_tmpl % ('')
        apk = self.apk_tmpl % ('')
        xml = self.xml_tmpl % ''
        apk = self.apk_tmpl % ''
        matches = self.run_test(xml, apk, uses_libraries=['foo'])
        self.assertFalse(matches)

    def test_missing_optional_uses_library(self):
        xml = self.xml_tmpl % ('')
        apk = self.apk_tmpl % ('')
        xml = self.xml_tmpl % ''
        apk = self.apk_tmpl % ''
        matches = self.run_test(xml, apk, optional_uses_libraries=['foo'])
        self.assertFalse(matches)

@@ -234,6 +234,32 @@ class EnforceUsesLibrariesTest(unittest.TestCase):
            optional_uses_libraries=['//x/y/z:bar'])
        self.assertTrue(matches)

    def test_multiple_applications(self):
        xml = """<?xml version="1.0" encoding="utf-8"?>
            <manifest xmlns:android="http://schemas.android.com/apk/res/android">
                <application android:featureFlag="foo">
                    <uses-library android:name="foo" />
                    <uses-library android:name="bar" android:required="false" />
                </application>
                <application android:featureFlag="!foo">
                    <uses-library android:name="foo" />
                    <uses-library android:name="qux" android:required="false" />
                </application>
            </manifest>
        """
        apk = self.apk_tmpl % ('\n'.join([
            uses_library_apk('foo'),
            uses_library_apk('bar', required_apk(False)),
            uses_library_apk('foo'),
            uses_library_apk('qux', required_apk(False))
        ]))
        matches = self.run_test(
            xml,
            apk,
            uses_libraries=['//x/y/z:foo'],
            optional_uses_libraries=['//x/y/z:bar', '//x/y/z:qux'])
        self.assertTrue(matches)


class ExtractTargetSdkVersionTest(unittest.TestCase):

@@ -256,12 +282,12 @@ class ExtractTargetSdkVersionTest(unittest.TestCase):
        "targetSdkVersion:'%s'\n"
        "uses-permission: name='android.permission.ACCESS_NETWORK_STATE'\n")

    def test_targert_sdk_version_28(self):
    def test_target_sdk_version_28(self):
        xml = self.xml_tmpl % '28'
        apk = self.apk_tmpl % '28'
        self.run_test(xml, apk, '28')

    def test_targert_sdk_version_29(self):
    def test_target_sdk_version_29(self):
        xml = self.xml_tmpl % '29'
        apk = self.apk_tmpl % '29'
        self.run_test(xml, apk, '29')
+116 −203
Original line number Diff line number Diff line
@@ -23,15 +23,7 @@ import sys
from xml.dom import minidom


from manifest import android_ns
from manifest import compare_version_gt
from manifest import ensure_manifest_android_ns
from manifest import find_child_with_attribute
from manifest import get_children_with_tag
from manifest import get_indent
from manifest import parse_manifest
from manifest import write_xml

from manifest import *

def parse_args():
  """Parse commandline arguments."""
@@ -48,9 +40,9 @@ def parse_args():
  parser.add_argument('--library', dest='library', action='store_true',
                      help='manifest is for a static library')
  parser.add_argument('--uses-library', dest='uses_libraries', action='append',
                      help='specify additional <uses-library> tag to add. android:requred is set to true')
                      help='specify additional <uses-library> tag to add. android:required is set to true')
  parser.add_argument('--optional-uses-library', dest='optional_uses_libraries', action='append',
                      help='specify additional <uses-library> tag to add. android:requred is set to false')
                      help='specify additional <uses-library> tag to add. android:required is set to false')
  parser.add_argument('--uses-non-sdk-api', dest='uses_non_sdk_api', action='store_true',
                      help='manifest is for a package built against the platform')
  parser.add_argument('--logging-parent', dest='logging_parent', default='',
@@ -91,47 +83,33 @@ def raise_min_sdk_version(doc, min_sdk_version, target_sdk_version, library):

  manifest = parse_manifest(doc)

  # Get or insert the uses-sdk element
  uses_sdk = get_children_with_tag(manifest, 'uses-sdk')
  if len(uses_sdk) > 1:
    raise RuntimeError('found multiple uses-sdk elements')
  elif len(uses_sdk) == 1:
    element = uses_sdk[0]
  else:
    element = doc.createElement('uses-sdk')
    indent = get_indent(manifest.firstChild, 1)
    manifest.insertBefore(element, manifest.firstChild)

    # Insert an indent before uses-sdk to line it up with the indentation of the
    # other children of the <manifest> tag.
    manifest.insertBefore(doc.createTextNode(indent), manifest.firstChild)

  for uses_sdk in get_or_create_uses_sdks(doc, manifest):
    # Get or insert the minSdkVersion attribute.  If it is already present, make
    # sure it as least the requested value.
  min_attr = element.getAttributeNodeNS(android_ns, 'minSdkVersion')
    min_attr = uses_sdk.getAttributeNodeNS(android_ns, 'minSdkVersion')
    if min_attr is None:
      min_attr = doc.createAttributeNS(android_ns, 'android:minSdkVersion')
      min_attr.value = min_sdk_version
    element.setAttributeNode(min_attr)
      uses_sdk.setAttributeNode(min_attr)
    else:
      if compare_version_gt(min_sdk_version, min_attr.value):
        min_attr.value = min_sdk_version

    # Insert the targetSdkVersion attribute if it is missing.  If it is already
    # present leave it as is.
  target_attr = element.getAttributeNodeNS(android_ns, 'targetSdkVersion')
    target_attr = uses_sdk.getAttributeNodeNS(android_ns, 'targetSdkVersion')
    if target_attr is None:
      target_attr = doc.createAttributeNS(android_ns, 'android:targetSdkVersion')
      if library:
        # TODO(b/117122200): libraries shouldn't set targetSdkVersion at all, but
        # ManifestMerger treats minSdkVersion="Q" as targetSdkVersion="Q" if it
      # is empty.  Set it to something low so that it will be overriden by the
        # is empty.  Set it to something low so that it will be overridden by the
        # main manifest, but high enough that it doesn't cause implicit
        # permissions grants.
        target_attr.value = '16'
      else:
        target_attr.value = target_sdk_version
    element.setAttributeNode(target_attr)
      uses_sdk.setAttributeNode(target_attr)


def add_logging_parent(doc, logging_parent_value):
@@ -147,17 +125,7 @@ def add_logging_parent(doc, logging_parent_value):
  manifest = parse_manifest(doc)

  logging_parent_key = 'android.content.pm.LOGGING_PARENT'
  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)

  for application in get_or_create_applications(doc, manifest):
    indent = get_indent(application.firstChild, 2)

    last = application.lastChild
@@ -192,17 +160,7 @@ def add_uses_libraries(doc, new_uses_libraries, required):
  """

  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)

  for application in get_or_create_applications(doc, manifest):
    indent = get_indent(application.firstChild, 2)

    last = application.lastChild
@@ -240,17 +198,7 @@ def add_uses_non_sdk_api(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)

  for application in get_or_create_applications(doc, manifest):
    attr = application.getAttributeNodeNS(android_ns, 'usesNonSdkApi')
    if attr is None:
      attr = doc.createAttributeNS(android_ns, 'android:usesNonSdkApi')
@@ -260,17 +208,7 @@ def add_uses_non_sdk_api(doc):

def add_use_embedded_dex(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)

  for application in get_or_create_applications(doc, manifest):
    attr = application.getAttributeNodeNS(android_ns, 'useEmbeddedDex')
    if attr is None:
      attr = doc.createAttributeNS(android_ns, 'android:useEmbeddedDex')
@@ -282,17 +220,7 @@ def add_use_embedded_dex(doc):

def add_extract_native_libs(doc, extract_native_libs):
  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)

  for application in get_or_create_applications(doc, manifest):
    value = str(extract_native_libs).lower()
    attr = application.getAttributeNodeNS(android_ns, 'extractNativeLibs')
    if attr is None:
@@ -306,46 +234,28 @@ def add_extract_native_libs(doc, extract_native_libs):

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)

  for application in get_or_create_applications(doc, manifest):
    attr = application.getAttributeNodeNS(android_ns, 'hasCode')
    if attr is not None:
      # Do nothing if the application already has a hasCode attribute.
    return
      continue
    attr = doc.createAttributeNS(android_ns, 'android:hasCode')
    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)

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


def set_max_sdk_version(doc, max_sdk_version):
  """Replace the maxSdkVersion attribute value for permission and
  uses-permission tags if the value was originally set to 'current'.
@@ -364,6 +274,7 @@ def set_max_sdk_version(doc, max_sdk_version):
      if max_attr and max_attr.value == 'current':
        max_attr.value = max_sdk_version


def override_placeholder_version(doc, new_version):
  """Replace the versionCode attribute value if it\'s currently
  set to the placeholder version of 0.
@@ -374,9 +285,10 @@ def override_placeholder_version(doc, new_version):
  """
  manifest = parse_manifest(doc)
  version = manifest.getAttribute("android:versionCode")
  if (version == '0'):
  if version == '0':
    manifest.setAttribute("android:versionCode", new_version)


def main():
  """Program entry point."""
  try:
@@ -427,5 +339,6 @@ def main():
    print('error: ' + str(err), file=sys.stderr)
    sys.exit(-1)


if __name__ == '__main__':
  main()
+138 −64

File changed.

Preview size limit exceeded, changes collapsed.