def add_uses_libraries(doc, new_uses_libraries, required): """Add additional <uses-library> tags Args: doc: The XML document. May be modified by this function. new_uses_libraries: The names of libraries to be added by this function. required: The value of android:required attribute. Can be true or false. Raises: RuntimeError: Invalid manifest """ 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) indent = get_indent(application.firstChild, 2) last = application.lastChild if last is not None and last.nodeType != minidom.Node.TEXT_NODE: last = None for name in new_uses_libraries: if find_child_with_attribute(application, 'uses-library', android_ns, 'name', name) is not None: # If the uses-library tag of the same 'name' attribute value exists, # respect it. continue ul = doc.createElement('uses-library') ul.setAttributeNS(android_ns, 'android:name', name) ul.setAttributeNS(android_ns, 'android:required', str(required).lower()) application.insertBefore(doc.createTextNode(indent), last) application.insertBefore(ul, last) # align the closing tag with the opening tag if it's not # indented if application.lastChild.nodeType != minidom.Node.TEXT_NODE: indent = get_indent(application.previousSibling, 1) application.appendChild(doc.createTextNode(indent))
def add_uses_non_sdk_api(doc): """Add android:usesNonSdkApi=true attribute to <application>. Args: doc: The XML document. May be modified by this function. Raises: RuntimeError: Invalid manifest """ 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, 'usesNonSdkApi') if attr is None: attr = doc.createAttributeNS(android_ns, 'android:usesNonSdkApi') attr.value = 'true' application.setAttributeNode(attr)
def AddLoggingParent(android_manifest, logging_parent_value): """Add logging parent as an additional <meta-data> tag. Args: android_manifest: A string representing AndroidManifest.xml logging_parent_value: A string representing the logging parent value. Raises: RuntimeError: Invalid manifest Returns: A path to modified AndroidManifest.xml """ doc = minidom.parse(android_manifest) 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) indent = get_indent(application.firstChild, 2) last = application.lastChild if last is not None and last.nodeType != minidom.Node.TEXT_NODE: last = None if not find_child_with_attribute(application, 'meta-data', android_ns, 'name', logging_parent_key): ul = doc.createElement('meta-data') ul.setAttributeNS(android_ns, 'android:name', logging_parent_key) ul.setAttributeNS(android_ns, 'android:value', logging_parent_value) application.insertBefore(doc.createTextNode(indent), last) application.insertBefore(ul, last) last = application.lastChild if last and last.nodeType != minidom.Node.TEXT_NODE: indent = get_indent(application.previousSibling, 1) application.appendChild(doc.createTextNode(indent)) with tempfile.NamedTemporaryFile(delete=False) as temp: write_xml(temp, doc) return temp.name
def add_logging_parent(doc, logging_parent_value): """Add logging parent as an additional <meta-data> tag. Args: doc: The XML document. May be modified by this function. logging_parent_value: A string representing the logging parent value. Raises: RuntimeError: Invalid manifest """ 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) indent = get_indent(application.firstChild, 2) last = application.lastChild if last is not None and last.nodeType != minidom.Node.TEXT_NODE: last = None if not find_child_with_attribute(application, 'meta-data', android_ns, 'name', logging_parent_key): ul = doc.createElement('meta-data') ul.setAttributeNS(android_ns, 'android:name', logging_parent_key) ul.setAttributeNS(android_ns, 'android:value', logging_parent_value) application.insertBefore(doc.createTextNode(indent), last) application.insertBefore(ul, last) last = application.lastChild # align the closing tag with the opening tag if it's not # indented if last and last.nodeType != minidom.Node.TEXT_NODE: indent = get_indent(application.previousSibling, 1) application.appendChild(doc.createTextNode(indent))
def raise_min_sdk_version(doc, min_sdk_version, target_sdk_version, library): """Ensure the manifest contains a <uses-sdk> tag with a minSdkVersion. Args: doc: The XML document. May be modified by this function. min_sdk_version: The requested minSdkVersion attribute. target_sdk_version: The requested targetSdkVersion attribute. library: True if the manifest is for a library. Raises: RuntimeError: invalid manifest """ 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) # 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') if min_attr is None: min_attr = doc.createAttributeNS(android_ns, 'android:minSdkVersion') min_attr.value = min_sdk_version element.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') 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 # main manifest, but high enough that it doesn't cause implicit # permissions grants. target_attr.value = '15' else: target_attr.value = target_sdk_version element.setAttributeNode(target_attr)
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 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) attr = application.getAttributeNodeNS(android_ns, 'useEmbeddedDex') if attr is None: attr = doc.createAttributeNS(android_ns, 'android:useEmbeddedDex') attr.value = 'true' application.setAttributeNode(attr) elif attr.value != 'true': raise RuntimeError( 'existing attribute mismatches the option of --use-embedded-dex')
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) value = str(extract_native_libs).lower() attr = application.getAttributeNodeNS(android_ns, 'extractNativeLibs') if attr is None: attr = doc.createAttributeNS(android_ns, 'android:extractNativeLibs') attr.value = value application.setAttributeNode(attr) elif attr.value != value: raise RuntimeError( 'existing attribute extractNativeLibs="%s" conflicts with --extract-native-libs="%s"' % (attr.value, value))