Ejemplo n.º 1
0
def main(raw_args):
    options = _ParseArgs(raw_args)

    arsc_package, _ = resource_utils.ExtractArscPackage(
        options.aapt2_path, options.in_apk)
    # Extract version from the compiled manifest since it might have been set
    # via aapt, and not exist in the manifest's text form.
    version_code, version_name, manifest_package = (
        resource_utils.ExtractBinaryManifestValues(options.aapt2_path,
                                                   options.in_apk))

    new_manifest_data = _ProcessManifest(options.src_manifest, arsc_package,
                                         options.disable_isolated_processes)
    with tempfile.NamedTemporaryFile() as tmp_manifest, \
        tempfile.NamedTemporaryFile() as tmp_apk:
        tmp_manifest.write(new_manifest_data)
        tmp_manifest.flush()
        cmd = [
            options.aapt2_path, 'link', '-o', tmp_apk.name, '--manifest',
            tmp_manifest.name, '-I', options.in_apk, '--replace-version',
            '--version-code', version_code, '--version-name', version_name,
            '--rename-manifest-package', manifest_package, '--debug-mode'
        ]
        for j in options.android_sdk_jars:
            cmd += ['-I', j]
        subprocess.check_call(cmd)
        with zipfile.ZipFile(options.out_apk, 'w') as z:
            path_transform = lambda p: None if p != 'AndroidManifest.xml' else p
            build_utils.MergeZips(z, [tmp_apk.name],
                                  path_transform=path_transform)
            path_transform = lambda p: None if p == 'AndroidManifest.xml' else p
            build_utils.MergeZips(z, [options.in_apk],
                                  path_transform=path_transform)
Ejemplo n.º 2
0
def main(args):
    build_utils.InitLogging('RESOURCE_DEBUG')
    args = build_utils.ExpandFileArgs(args)
    options = _ParseArgs(args)

    path = options.arsc_path or options.proto_path
    debug_temp_resources_dir = os.environ.get('TEMP_RESOURCES_DIR')
    if debug_temp_resources_dir:
        path = os.path.join(debug_temp_resources_dir, os.path.basename(path))
    else:
        # Use a deterministic temp directory since .pb files embed the absolute
        # path of resources: crbug.com/939984
        path = path + '.tmpdir'
    build_utils.DeleteDirectory(path)
    build_utils.MakeDirectory(path)

    with resource_utils.BuildContext(
            temp_dir=path, keep_files=bool(debug_temp_resources_dir)) as build:
        manifest_package_name = _PackageApk(options, build)

        # If --shared-resources-whitelist is used, the all resources listed in
        # the corresponding R.txt file will be non-final, and an onResourcesLoaded()
        # will be generated to adjust them at runtime.
        #
        # Otherwise, if --shared-resources is used, the all resources will be
        # non-final, and an onResourcesLoaded() method will be generated too.
        #
        # Otherwise, all resources will be final, and no method will be generated.
        #
        rjava_build_options = resource_utils.RJavaBuildOptions()
        if options.shared_resources_whitelist:
            rjava_build_options.ExportSomeResources(
                options.shared_resources_whitelist)
            rjava_build_options.GenerateOnResourcesLoaded()
        elif options.shared_resources or options.app_as_shared_lib:
            rjava_build_options.ExportAllResources()
            rjava_build_options.GenerateOnResourcesLoaded()

        custom_root_package_name = options.r_java_root_package_name
        grandparent_custom_package_name = None

        if options.package_name and not options.arsc_package_name:
            # Feature modules have their own custom root package name and should
            # inherit from the appropriate base module package. This behaviour should
            # not be present for test apks with an apk under test. Thus,
            # arsc_package_name is used as it is only defined for test apks with an
            # apk under test.
            custom_root_package_name = options.package_name
            grandparent_custom_package_name = options.r_java_root_package_name

        if options.shared_resources or options.app_as_shared_lib:
            package_for_library = manifest_package_name
        else:
            package_for_library = None

        logging.debug('Creating R.srcjar')
        resource_utils.CreateRJavaFiles(
            build.srcjar_dir, package_for_library, build.r_txt_path,
            options.extra_res_packages, options.extra_r_text_files,
            rjava_build_options, options.srcjar_out, custom_root_package_name,
            grandparent_custom_package_name, options.extra_main_r_text_files)
        build_utils.ZipDir(build.srcjar_path, build.srcjar_dir)

        # Sanity check that the created resources have the expected package ID.
        logging.debug('Performing sanity check')
        if options.package_id:
            expected_id = options.package_id
        elif options.shared_resources:
            expected_id = 0
        else:
            expected_id = 127  # == '0x7f'.
        _, package_id = resource_utils.ExtractArscPackage(
            options.aapt2_path,
            build.arsc_path if options.arsc_path else build.proto_path)
        if package_id != expected_id:
            raise Exception('Invalid package ID 0x%x (expected 0x%x)' %
                            (package_id, expected_id))

        logging.debug('Copying outputs')
        _WriteOutputs(options, build)

    if options.depfile:
        build_utils.WriteDepfile(options.depfile,
                                 options.srcjar_out,
                                 inputs=options.dependencies_res_zips +
                                 options.extra_r_text_files,
                                 add_pydeps=False)
Ejemplo n.º 3
0
def main(args):
    build_utils.InitLogging('RESOURCE_DEBUG')
    args = build_utils.ExpandFileArgs(args)
    options = _ParseArgs(args)

    if options.expected_file:
        actual_data = _CreateNormalizedManifestForVerification(options)
        diff_utils.CheckExpectations(actual_data, options)
        if options.only_verify_expectations:
            return

    path = options.arsc_path or options.proto_path
    debug_temp_resources_dir = os.environ.get('TEMP_RESOURCES_DIR')
    if debug_temp_resources_dir:
        path = os.path.join(debug_temp_resources_dir, os.path.basename(path))
    else:
        # Use a deterministic temp directory since .pb files embed the absolute
        # path of resources: crbug.com/939984
        path = path + '.tmpdir'
    build_utils.DeleteDirectory(path)

    with resource_utils.BuildContext(
            temp_dir=path, keep_files=bool(debug_temp_resources_dir)) as build:

        manifest_package_name = _PackageApk(options, build)

        # If --shared-resources-allowlist is used, all the resources listed in the
        # corresponding R.txt file will be non-final, and an onResourcesLoaded()
        # will be generated to adjust them at runtime.
        #
        # Otherwise, if --shared-resources is used, the all resources will be
        # non-final, and an onResourcesLoaded() method will be generated too.
        #
        # Otherwise, all resources will be final, and no method will be generated.
        #
        rjava_build_options = resource_utils.RJavaBuildOptions()
        if options.shared_resources_allowlist:
            rjava_build_options.ExportSomeResources(
                options.shared_resources_allowlist)
            rjava_build_options.GenerateOnResourcesLoaded()
            if options.shared_resources:
                # The final resources will only be used in WebLayer, so hardcode the
                # package ID to be what WebLayer expects.
                rjava_build_options.SetFinalPackageId(
                    protoresources.SHARED_LIBRARY_HARDCODED_ID)
        elif options.shared_resources or options.app_as_shared_lib:
            rjava_build_options.ExportAllResources()
            rjava_build_options.GenerateOnResourcesLoaded()

        custom_root_package_name = options.r_java_root_package_name
        grandparent_custom_package_name = None

        # Always generate an R.java file for the package listed in
        # AndroidManifest.xml because this is where Android framework looks to find
        # onResourcesLoaded() for shared library apks. While not actually necessary
        # for application apks, it also doesn't hurt.
        apk_package_name = manifest_package_name

        if options.package_name and not options.arsc_package_name:
            # Feature modules have their own custom root package name and should
            # inherit from the appropriate base module package. This behaviour should
            # not be present for test apks with an apk under test. Thus,
            # arsc_package_name is used as it is only defined for test apks with an
            # apk under test.
            custom_root_package_name = options.package_name
            grandparent_custom_package_name = options.r_java_root_package_name
            # Feature modules have the same manifest package as the base module but
            # they should not create an R.java for said manifest package because it
            # will be created in the base module.
            apk_package_name = None

        logging.debug('Creating R.srcjar')
        resource_utils.CreateRJavaFiles(
            build.srcjar_dir, apk_package_name, build.r_txt_path,
            options.extra_res_packages, rjava_build_options,
            options.srcjar_out, custom_root_package_name,
            grandparent_custom_package_name, options.extra_main_r_text_files)
        build_utils.ZipDir(build.srcjar_path, build.srcjar_dir)

        # Sanity check that the created resources have the expected package ID.
        logging.debug('Performing sanity check')
        if options.package_id:
            expected_id = options.package_id
        elif options.shared_resources:
            expected_id = 0
        else:
            expected_id = 127  # == '0x7f'.
        _, package_id = resource_utils.ExtractArscPackage(
            options.aapt2_path,
            build.arsc_path if options.arsc_path else build.proto_path)
        if package_id != expected_id:
            raise Exception('Invalid package ID 0x%x (expected 0x%x)' %
                            (package_id, expected_id))

        logging.debug('Copying outputs')
        _WriteOutputs(options, build)

    if options.depfile:
        depfile_deps = (options.dependencies_res_zips +
                        options.dependencies_res_zip_overlays +
                        options.extra_main_r_text_files +
                        options.include_resources)
        build_utils.WriteDepfile(options.depfile, options.srcjar_out,
                                 depfile_deps)
Ejemplo n.º 4
0
def main(args):
    args = build_utils.ExpandFileArgs(args)
    options = _ParseArgs(args)

    debug_temp_resources_dir = os.environ.get(_ENV_DEBUG_VARIABLE)
    if debug_temp_resources_dir:
        debug_temp_resources_dir = os.path.join(
            debug_temp_resources_dir, os.path.basename(options.arsc_path))
        build_utils.DeleteDirectory(debug_temp_resources_dir)
        build_utils.MakeDirectory(debug_temp_resources_dir)

    with resource_utils.BuildContext(debug_temp_resources_dir) as build:
        _PackageApk(options, build)

        # If --shared-resources-whitelist is used, the all resources listed in
        # the corresponding R.txt file will be non-final, and an onResourcesLoaded()
        # will be generated to adjust them at runtime.
        #
        # Otherwise, if --shared-resources is used, the all resources will be
        # non-final, and an onResourcesLoaded() method will be generated too.
        #
        # Otherwise, all resources will be final, and no method will be generated.
        #
        rjava_build_options = resource_utils.RJavaBuildOptions()
        if options.shared_resources_whitelist:
            rjava_build_options.ExportSomeResources(
                options.shared_resources_whitelist)
            rjava_build_options.GenerateOnResourcesLoaded()
        elif options.shared_resources or options.app_as_shared_lib:
            rjava_build_options.ExportAllResources()
            rjava_build_options.GenerateOnResourcesLoaded()

        custom_root_package_name = None
        grandparent_custom_package_name = None

        if options.arsc_package_name:
            # This is for test apks with an apk under test. If we have an apk under
            # test we don't want to name the resources for both the test apk and the
            # under test apk "base". This special case lets us name the test apk's
            # resources "test".
            custom_root_package_name = 'test'
        elif options.package_name:
            # If there exists a custom package name such as vr for a feature module,
            # pass the name and base for the parent_custom_root_package_name.
            custom_root_package_name = options.package_name
            grandparent_custom_package_name = 'base'
        else:
            # No grandparent_custom_package_name for base module
            custom_root_package_name = 'base'

        resource_utils.CreateRJavaFiles(
            build.srcjar_dir, None, build.r_txt_path,
            options.extra_res_packages, options.extra_r_text_files,
            rjava_build_options, options.srcjar_out, custom_root_package_name,
            grandparent_custom_package_name)

        build_utils.ZipDir(build.srcjar_path, build.srcjar_dir)

        # Sanity check that the created resources have the expected package ID.
        expected_id = _PackageIdFromOptions(options)
        if expected_id is None:
            expected_id = '0x00' if options.shared_resources else '0x7f'
        expected_id = int(expected_id, 16)
        _, package_id = resource_utils.ExtractArscPackage(
            options.aapt2_path,
            build.arsc_path if options.arsc_path else build.proto_path)
        if package_id != expected_id:
            raise Exception('Invalid package ID 0x%x (expected 0x%x)' %
                            (package_id, expected_id))

        _WriteOutputs(options, build)

    if options.depfile:
        build_utils.WriteDepfile(options.depfile,
                                 options.srcjar_out,
                                 inputs=options.dependencies_res_zips +
                                 options.extra_r_text_files,
                                 add_pydeps=False)
Ejemplo n.º 5
0
def main(args):
    args = build_utils.ExpandFileArgs(args)
    options = _ParseArgs(args)

    debug_temp_resources_dir = os.environ.get(_ENV_DEBUG_VARIABLE)
    if debug_temp_resources_dir:
        debug_temp_resources_dir = os.path.join(
            debug_temp_resources_dir, os.path.basename(options.apk_path))
        build_utils.DeleteDirectory(debug_temp_resources_dir)
        build_utils.MakeDirectory(debug_temp_resources_dir)

    with resource_utils.BuildContext(debug_temp_resources_dir) as build:
        dep_subdirs = resource_utils.ExtractDeps(options.dependencies_res_zips,
                                                 build.deps_dir)

        _PackageApk(options, dep_subdirs, build.temp_dir, build.gen_dir,
                    build.r_txt_path)

        r_txt_path = _WriteFinalRTxtFile(options, build.r_txt_path)

        # If --shared-resources-whitelist is used, the all resources listed in
        # the corresponding R.txt file will be non-final, and an onResourcesLoaded()
        # will be generated to adjust them at runtime.
        #
        # Otherwise, if --shared-resources is used, the all resources will be
        # non-final, and an onResourcesLoaded() method will be generated too.
        #
        # Otherwise, all resources will be final, and no method will be generated.
        #
        rjava_build_options = resource_utils.RJavaBuildOptions()
        if options.shared_resources_whitelist:
            rjava_build_options.ExportSomeResources(
                options.shared_resources_whitelist)
            rjava_build_options.GenerateOnResourcesLoaded()
        elif options.shared_resources or options.app_as_shared_lib:
            rjava_build_options.ExportAllResources()
            rjava_build_options.GenerateOnResourcesLoaded()

        resource_utils.CreateRJavaFiles(build.srcjar_dir, None, r_txt_path,
                                        options.extra_res_packages,
                                        options.extra_r_text_files,
                                        rjava_build_options)

        if options.srcjar_out:
            build_utils.ZipDir(options.srcjar_out, build.srcjar_dir)

        # Sanity check that the created resources have the expected package ID.
        expected_id = _PackageIdFromOptions(options)
        if expected_id is None:
            expected_id = '0x00' if options.shared_resources else '0x7f'
        expected_id = int(expected_id, 16)
        _, package_id = resource_utils.ExtractArscPackage(
            options.aapt2_path, options.apk_path)
        if package_id != expected_id:
            raise Exception('Invalid package ID 0x%x (expected 0x%x)' %
                            (package_id, expected_id))

    if options.depfile:
        build_utils.WriteDepfile(options.depfile,
                                 options.apk_path,
                                 inputs=options.dependencies_res_zips +
                                 options.extra_r_text_files,
                                 add_pydeps=False)
Ejemplo n.º 6
0
def main(args):
    args = build_utils.ExpandFileArgs(args)
    options = _ParseArgs(args)

    debug_temp_resources_dir = os.environ.get(_ENV_DEBUG_VARIABLE)
    if debug_temp_resources_dir:
        debug_temp_resources_dir = os.path.join(
            debug_temp_resources_dir, os.path.basename(options.arsc_path))
        build_utils.DeleteDirectory(debug_temp_resources_dir)
        build_utils.MakeDirectory(debug_temp_resources_dir)

    with resource_utils.BuildContext(debug_temp_resources_dir) as build:
        _PackageApk(options, build)

        # If --shared-resources-whitelist is used, the all resources listed in
        # the corresponding R.txt file will be non-final, and an onResourcesLoaded()
        # will be generated to adjust them at runtime.
        #
        # Otherwise, if --shared-resources is used, the all resources will be
        # non-final, and an onResourcesLoaded() method will be generated too.
        #
        # Otherwise, all resources will be final, and no method will be generated.
        #
        rjava_build_options = resource_utils.RJavaBuildOptions()
        if options.shared_resources_whitelist:
            rjava_build_options.ExportSomeResources(
                options.shared_resources_whitelist)
            rjava_build_options.GenerateOnResourcesLoaded()
        elif options.shared_resources or options.app_as_shared_lib:
            rjava_build_options.ExportAllResources()
            rjava_build_options.GenerateOnResourcesLoaded()

        custom_root_package_name = options.r_java_root_package_name
        grandparent_custom_package_name = None

        if options.package_name and not options.arsc_package_name:
            # Feature modules have their own custom root package name and should
            # inherit from the appropriate base module package. This behaviour should
            # not be present for test apks with an apk under test. Thus,
            # arsc_package_name is used as it is only defined for test apks with an
            # apk under test.
            custom_root_package_name = options.package_name
            grandparent_custom_package_name = options.r_java_root_package_name

        resource_utils.CreateRJavaFiles(
            build.srcjar_dir, None, build.r_txt_path,
            options.extra_res_packages, options.extra_r_text_files,
            rjava_build_options, options.srcjar_out, custom_root_package_name,
            grandparent_custom_package_name, options.extra_main_r_text_files)

        build_utils.ZipDir(build.srcjar_path, build.srcjar_dir)

        # Sanity check that the created resources have the expected package ID.
        expected_id = _PackageIdFromOptions(options)
        if expected_id is None:
            expected_id = '0x00' if options.shared_resources else '0x7f'
        expected_id = int(expected_id, 16)
        _, package_id = resource_utils.ExtractArscPackage(
            options.aapt2_path,
            build.arsc_path if options.arsc_path else build.proto_path)
        if package_id != expected_id:
            raise Exception('Invalid package ID 0x%x (expected 0x%x)' %
                            (package_id, expected_id))

        _WriteOutputs(options, build)

    if options.depfile:
        build_utils.WriteDepfile(options.depfile,
                                 options.srcjar_out,
                                 inputs=options.dependencies_res_zips +
                                 options.extra_r_text_files,
                                 add_pydeps=False)
Ejemplo n.º 7
0
def _PackageApk(options, build):
    """Compile and link resources with aapt2.

  Args:
    options: The command-line options.
    build: BuildContext object.
  Returns:
    The manifest package name for the APK.
  """
    logging.debug('Extracting resource .zips')
    dep_subdirs = []
    dep_subdir_overlay_set = set()
    for dependency_res_zip in options.dependencies_res_zips:
        extracted_dep_subdirs = resource_utils.ExtractDeps(
            [dependency_res_zip], build.deps_dir)
        dep_subdirs += extracted_dep_subdirs
        if dependency_res_zip in options.dependencies_res_zip_overlays:
            dep_subdir_overlay_set.update(extracted_dep_subdirs)

    logging.debug('Applying locale transformations')
    path_info = resource_utils.ResourceInfoFile()
    _RenameLocaleResourceDirs(dep_subdirs, path_info)

    logging.debug('Applying file-based exclusions')
    keep_predicate = _CreateKeepPredicate(
        options.resource_exclusion_regex,
        options.resource_exclusion_exceptions)
    png_paths = _FilterResourceFiles(dep_subdirs, keep_predicate)

    if options.locale_allowlist or options.shared_resources_allowlist_locales:
        logging.debug('Applying locale-based string exclusions')
        _RemoveUnwantedLocalizedStrings(dep_subdirs, options)

    if png_paths and options.png_to_webp:
        logging.debug('Converting png->webp')
        _ConvertToWebP(options.webp_binary, png_paths, path_info,
                       options.webp_cache_dir)
    logging.debug('Applying drawable transformations')
    for directory in dep_subdirs:
        _MoveImagesToNonMdpiFolders(directory, path_info)
        _RemoveImageExtensions(directory, path_info)

    logging.debug('Running aapt2 compile')
    exclusion_rules = [x.split(':', 1) for x in options.values_filter_rules]
    partials = _CompileDeps(options.aapt2_path, dep_subdirs,
                            dep_subdir_overlay_set, build.temp_dir,
                            exclusion_rules)

    link_command = [
        options.aapt2_path,
        'link',
        '--auto-add-overlay',
        '--no-version-vectors',
        # Set SDK versions in case they are not set in the Android manifest.
        '--min-sdk-version',
        options.min_sdk_version,
        '--target-sdk-version',
        options.target_sdk_version,
        '--output-text-symbols',
        build.r_txt_path,
    ]

    for j in options.include_resources:
        link_command += ['-I', j]
    if options.version_code:
        link_command += ['--version-code', options.version_code]
    if options.version_name:
        link_command += ['--version-name', options.version_name]
    if options.proguard_file:
        link_command += ['--proguard', build.proguard_path]
        link_command += ['--proguard-minimal-keep-rules']
    if options.proguard_file_main_dex:
        link_command += ['--proguard-main-dex', build.proguard_main_dex_path]
    if options.emit_ids_out:
        link_command += ['--emit-ids', build.emit_ids_path]

    # Note: only one of --proto-format, --shared-lib or --app-as-shared-lib
    #       can be used with recent versions of aapt2.
    if options.shared_resources:
        link_command.append('--shared-lib')

    if options.no_xml_namespaces:
        link_command.append('--no-xml-namespaces')

    if options.package_id:
        link_command += [
            '--package-id',
            '0x%02x' % options.package_id,
            '--allow-reserved-package-id',
        ]

    fixed_manifest, desired_manifest_package_name, fixed_manifest_package = (
        _FixManifest(options, build.temp_dir))
    if options.rename_manifest_package:
        desired_manifest_package_name = options.rename_manifest_package

    link_command += [
        '--manifest', fixed_manifest, '--rename-manifest-package',
        desired_manifest_package_name
    ]

    if options.package_id is not None:
        package_id = options.package_id
    elif options.shared_resources:
        package_id = 0
    else:
        package_id = 0x7f
    _CreateStableIdsFile(options.use_resource_ids_path, build.stable_ids_path,
                         fixed_manifest_package, package_id)
    link_command += ['--stable-ids', build.stable_ids_path]

    link_command += partials

    # We always create a binary arsc file first, then convert to proto, so flags
    # such as --shared-lib can be supported.
    link_command += ['-o', build.arsc_path]

    logging.debug('Starting: aapt2 link')
    link_proc = subprocess.Popen(link_command)

    # Create .res.info file in parallel.
    _CreateResourceInfoFile(path_info, build.info_path,
                            options.dependencies_res_zips)
    logging.debug('Created .res.info file')

    exit_code = link_proc.wait()
    assert exit_code == 0, f'aapt2 link cmd failed with {exit_code=}'
    logging.debug('Finished: aapt2 link')

    if options.shared_resources:
        logging.debug('Resolving styleables in R.txt')
        # Need to resolve references because unused resource removal tool does not
        # support references in R.txt files.
        resource_utils.ResolveStyleableReferences(build.r_txt_path)

    if exit_code:
        raise subprocess.CalledProcessError(exit_code, link_command)

    if options.proguard_file and (options.shared_resources
                                  or options.app_as_shared_lib):
        # Make sure the R class associated with the manifest package does not have
        # its onResourcesLoaded method obfuscated or removed, so that the framework
        # can call it in the case where the APK is being loaded as a library.
        with open(build.proguard_path, 'a') as proguard_file:
            keep_rule = '''
                  -keep,allowoptimization class {package}.R {{
                    public static void onResourcesLoaded(int);
                  }}
                  '''.format(package=desired_manifest_package_name)
            proguard_file.write(textwrap.dedent(keep_rule))

    logging.debug('Running aapt2 convert')
    build_utils.CheckOutput([
        options.aapt2_path, 'convert', '--output-format', 'proto', '-o',
        build.proto_path, build.arsc_path
    ])

    # Workaround for b/147674078. This is only needed for WebLayer and does not
    # affect WebView usage, since WebView does not used dynamic attributes.
    if options.shared_resources:
        logging.debug('Hardcoding dynamic attributes')
        protoresources.HardcodeSharedLibraryDynamicAttributes(
            build.proto_path, options.is_bundle_module,
            options.shared_resources_allowlist)

        build_utils.CheckOutput([
            options.aapt2_path, 'convert', '--output-format', 'binary', '-o',
            build.arsc_path, build.proto_path
        ])

    # Sanity check that the created resources have the expected package ID.
    logging.debug('Performing sanity check')
    _, actual_package_id = resource_utils.ExtractArscPackage(
        options.aapt2_path,
        build.arsc_path if options.arsc_path else build.proto_path)
    # When there are no resources, ExtractArscPackage returns (None, None), in
    # this case there is no need to check for matching package ID.
    if actual_package_id is not None and actual_package_id != package_id:
        raise Exception('Invalid package ID 0x%x (expected 0x%x)' %
                        (actual_package_id, package_id))

    return desired_manifest_package_name