# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # Do not add any imports to non-//build directories here. # Some projects (e.g. V8) do not have non-build directories DEPS'ed in. import("//build/config/android/channel.gni") import("//build/config/android/config.gni") import("//build/config/android/internal_rules.gni") import("//build/config/clang/clang.gni") import("//build/config/compiler/compiler.gni") import("//build/config/coverage/coverage.gni") import("//build/config/dcheck_always_on.gni") import("//build/config/python.gni") import("//build/config/zip.gni") import("//build/toolchain/toolchain.gni") assert(is_android) declare_args() { enable_jni_tracing = false } if (target_cpu == "arm") { _sanitizer_arch = "arm" } else if (target_cpu == "arm64") { _sanitizer_arch = "aarch64" } else if (target_cpu == "x86") { _sanitizer_arch = "i686" } _sanitizer_runtimes = [] if (use_cfi_diag || is_ubsan || is_ubsan_security || is_ubsan_vptr) { _sanitizer_runtimes = [ "$clang_base_path/lib/clang/$clang_version/lib/linux/libclang_rt.ubsan_standalone-$_sanitizer_arch-android.so" ] } # Creates a dist directory for a native executable. # # Running a native executable on a device requires all the shared library # dependencies of that executable. To make it easier to install and run such an # executable, this will create a directory containing the native exe and all # it's library dependencies. # # Note: It's usually better to package things as an APK than as a native # executable. # # Variables # dist_dir: Directory for the exe and libraries. Everything in this directory # will be deleted before copying in the exe and libraries. # binary: Path to (stripped) executable. # extra_files: List of extra files to copy in (optional). # # Example # create_native_executable_dist("foo_dist") { # dist_dir = "$root_build_dir/foo_dist" # binary = "$root_build_dir/foo" # deps = [ ":the_thing_that_makes_foo" ] # } template("create_native_executable_dist") { forward_variables_from(invoker, [ "testonly" ]) _libraries_list = "${target_gen_dir}/${target_name}_library_dependencies.list" _sanitizer_runtimes_target_name = "${target_name}__sanitizer_runtimes" group(_sanitizer_runtimes_target_name) { metadata = { shared_libraries = _sanitizer_runtimes } } generated_file("${target_name}__library_list") { forward_variables_from(invoker, [ "deps" ]) if (!defined(deps)) { deps = [] } deps += [ ":${_sanitizer_runtimes_target_name}" ] output_conversion = "json" outputs = [ _libraries_list ] data_keys = [ "shared_libraries" ] walk_keys = [ "shared_libraries_barrier" ] rebase = root_build_dir } copy_ex(target_name) { inputs = [ _libraries_list, invoker.binary, ] dest = invoker.dist_dir data = [ "${invoker.dist_dir}/" ] _rebased_libraries_list = rebase_path(_libraries_list, root_build_dir) _rebased_binaries_list = rebase_path([ invoker.binary ], root_build_dir) args = [ "--clear", "--files=@FileArg($_rebased_libraries_list)", "--files=$_rebased_binaries_list", ] if (defined(invoker.extra_files)) { _rebased_extra_files = rebase_path(invoker.extra_files, root_build_dir) args += [ "--files=$_rebased_extra_files" ] } _depfile = "$target_gen_dir/$target_name.d" _stamp_file = "$target_gen_dir/$target_name.stamp" outputs = [ _stamp_file ] args += [ "--depfile", rebase_path(_depfile, root_build_dir), "--stamp", rebase_path(_stamp_file, root_build_dir), ] deps = [ ":${target_name}__library_list" ] if (defined(invoker.deps)) { deps += invoker.deps } } } if (enable_java_templates) { import("//build/config/sanitizers/sanitizers.gni") import("//tools/grit/grit_rule.gni") # JNI target implementation. See generate_jni or generate_jar_jni for usage. template("generate_jni_impl") { set_sources_assignment_filter([]) _jni_output_dir = "${target_gen_dir}/${target_name}" if (defined(invoker.jni_generator_include)) { _jni_generator_include = invoker.jni_generator_include _jni_generator_include_deps = [] } else { _jni_generator_include = "//base/android/jni_generator/jni_generator_helper.h" _jni_generator_include_deps = [ # Using //base/android/jni_generator/jni_generator_helper.h introduces # a dependency on buildflags targets indirectly through # base/android/jni_android.h, which is part of the //base target. # This can't depend directly on //base without causing a dependency # cycle, though. "//base:debugging_buildflags", "//base:logging_buildflags", ] } action_with_pydeps(target_name) { # The sources aren't compiled so don't check their dependencies. check_includes = false script = "//base/android/jni_generator/jni_generator.py" forward_variables_from(invoker, [ "deps", "public_deps", "visibility", "testonly", ]) if (!defined(public_deps)) { public_deps = [] } public_deps += _jni_generator_include_deps inputs = [] args = [ "--ptr_type=long", "--includes", rebase_path(_jni_generator_include, _jni_output_dir), ] if (defined(invoker.classes)) { if (defined(invoker.jar_file)) { _jar_file = invoker.jar_file } else { _jar_file = android_sdk_jar } inputs += [ _jar_file ] args += [ "--jar_file", rebase_path(_jar_file, root_build_dir), ] _input_args = invoker.classes _input_names = invoker.classes if (defined(invoker.always_mangle) && invoker.always_mangle) { args += [ "--always_mangle" ] } } else { assert(defined(invoker.sources)) inputs += invoker.sources _input_args = rebase_path(invoker.sources, root_build_dir) _input_names = invoker.sources if (use_hashed_jni_names) { args += [ "--use_proxy_hash" ] } if (defined(invoker.namespace)) { args += [ "-n ${invoker.namespace}" ] } } outputs = [] foreach(_name, _input_names) { _name_part = get_path_info(_name, "name") outputs += [ "${_jni_output_dir}/${_name_part}_jni.h" ] } # Avoid passing GN lists because not all webrtc embedders use //build. foreach(_output, outputs) { args += [ "--output_file", rebase_path(_output, root_build_dir), ] } foreach(_input, _input_args) { args += [ "--input_file=$_input" ] } if (enable_profiling) { args += [ "--enable_profiling" ] } if (enable_jni_tracing) { args += [ "--enable_tracing" ] } if (defined(invoker.feature_list_file)) { file_path = rebase_path(invoker.feature_list_file, root_build_dir) args += [ "--feature_list_file=$file_path" ] } } } # Declare a jni target # # This target generates the native jni bindings for a set of .java files. # # See base/android/jni_generator/jni_generator.py for more info about the # format of generating JNI bindings. # # Variables # sources: list of .java files to generate jni for # namespace: Specify the namespace for the generated header file. # deps, public_deps: As normal # # Example # # Target located in base/BUILD.gn. # generate_jni("foo_jni") { # # Generates gen/base/foo_jni/Foo_jni.h # # To use: #include "base/foo_jni/Foo_jni.h" # sources = [ # "android/java/src/org/chromium/foo/Foo.java", # ..., # ] # } template("generate_jni") { generate_jni_impl(target_name) { forward_variables_from(invoker, "*") } } # Declare a jni target for a prebuilt jar # # This target generates the native jni bindings for a set of classes in a .jar. # # See base/android/jni_generator/jni_generator.py for more info about the # format of generating JNI bindings. # # Variables # classes: list of .class files in the jar to generate jni for. These should # include the full path to the .class file. # jar_file: the path to the .jar. If not provided, will default to the sdk's # android.jar # always_mangle: Mangle all generated method names. By default, the script # only mangles methods that cause ambiguity due to method overload. # deps, public_deps: As normal # # Example # # Target located in base/BUILD.gn. # generate_jar_jni("foo_jni") { # # Generates gen/base/foo_jni/Runnable_jni.h # # To use: #include "base/foo_jni/Runnable_jni.h" # classes = [ # "android/view/Foo.class", # ] # } template("generate_jar_jni") { generate_jni_impl(target_name) { forward_variables_from(invoker, "*") } } # Declare a jni registration target. # # This target generates a srcjar containing a copy of GEN_JNI.java, which has # the native methods of all dependent java files. It can also create a .h file # for use with manual JNI registration. # # The script does not scan any generated sources (those within .srcjars, or # within root_build_dir). This could be fixed by adding deps & logic to scan # .srcjars, but isn't currently needed. # # See base/android/jni_generator/jni_registration_generator.py for more info # about the format of the header file. # # Variables # targets: List of .build_config supported targets to provide java sources. # header_output: Path to the generated .h file (optional). # sources_exclusions: List of .java files that should be skipped. (optional) # namespace: Registration functions will be wrapped into this. (optional) # require_native_mocks: Enforce that any native calls using # org.chromium.base.annotations.NativeMethods must have a mock set # (optional). # enable_native_mocks: Allow native calls using # org.chromium.base.annotations.NativeMethods to be mocked in tests # (optional). # no_transitive_deps: Generate registration for only the Java source in the # specified target(s). This is useful for generating registration for # feature modules, without including base module dependencies. # # Example # generate_jni_registration("chrome_jni_registration") { # targets = [ ":chrome_public_apk" ] # header_output = "$target_gen_dir/$target_name.h" # sources_exclusions = [ # "//path/to/Exception.java", # ] # } template("generate_jni_registration") { action_with_pydeps(target_name) { forward_variables_from(invoker, [ "testonly" ]) script = "//base/android/jni_generator/jni_registration_generator.py" inputs = [] deps = [] _srcjar_output = "$target_gen_dir/$target_name.srcjar" outputs = [ _srcjar_output ] depfile = "$target_gen_dir/$target_name.d" args = [ "--srcjar-path", rebase_path(_srcjar_output, root_build_dir), "--depfile", rebase_path(depfile, root_build_dir), ] foreach(_target, invoker.targets) { deps += [ "${_target}$build_config_target_suffix($default_toolchain)" ] _build_config = get_label_info("${_target}($default_toolchain)", "target_gen_dir") + "/" + get_label_info("${_target}($default_toolchain)", "name") + ".build_config" _rebased_build_config = rebase_path(_build_config, root_build_dir) inputs += [ _build_config ] if (defined(invoker.no_transitive_deps) && invoker.no_transitive_deps) { args += [ "--sources-files=@FileArg($_rebased_build_config:deps_info:java_sources_file)" ] } else { args += [ # This is a list of .sources files. "--sources-files=@FileArg($_rebased_build_config:deps_info:jni:all_source)", ] } } if (use_hashed_jni_names) { args += [ "--use_proxy_hash" ] } if (defined(invoker.enable_native_mocks) && invoker.enable_native_mocks) { args += [ "--enable_proxy_mocks" ] if (defined(invoker.require_native_mocks) && invoker.require_native_mocks) { args += [ "--require_mocks" ] } } if (defined(invoker.header_output)) { outputs += [ invoker.header_output ] args += [ "--header-path", rebase_path(invoker.header_output, root_build_dir), ] } if (defined(invoker.sources_exclusions)) { _rebase_sources_exclusions = rebase_path(invoker.sources_exclusions, root_build_dir) args += [ "--sources-exclusions=$_rebase_sources_exclusions" ] } if (defined(invoker.namespace)) { args += [ "--namespace=${invoker.namespace}" ] } } } # Declare a target for c-preprocessor-generated java files # # NOTE: For generating Java conterparts to enums prefer using the java_cpp_enum # rule instead. # # This target generates java files using the host C pre-processor. Each file in # sources will be compiled using the C pre-processor. If include_path is # specified, it will be passed (with --I) to the pre-processor. # # This target will create a single .srcjar. Adding this target to an # android_library target's srcjar_deps will make the generated java files be # included in that library's final outputs. # # Variables # sources: list of files to be processed by the C pre-processor. For each # file in sources, there will be one .java file in the final .srcjar. For a # file named FooBar.template, a java file will be created with name # FooBar.java. # inputs: additional compile-time dependencies. Any files # `#include`-ed in the templates should be listed here. # package_path: this will be the subdirectory for each .java file in the # .srcjar. # # Example # java_cpp_template("foo_generated_enum") { # sources = [ # "android/java/templates/Foo.template", # ] # inputs = [ # "android/java/templates/native_foo_header.h", # ] # # package_path = "org/chromium/base/library_loader" # include_path = "android/java/templates" # } template("java_cpp_template") { set_sources_assignment_filter([]) forward_variables_from(invoker, [ "testonly" ]) _include_path = "//" if (defined(invoker.include_path)) { _include_path = invoker.include_path } _apply_gcc_target_name = "${target_name}__apply_gcc" _base_gen_dir = "${target_gen_dir}/${target_name}/java_cpp_template" _package_path = invoker.package_path action_foreach_with_pydeps(_apply_gcc_target_name) { forward_variables_from(invoker, [ "deps", "inputs", "public_deps", "data_deps", ]) script = "//build/android/gyp/gcc_preprocess.py" depfile = "${target_gen_dir}/${invoker.target_name}_{{source_name_part}}.d" sources = invoker.sources outputs = [ "$_base_gen_dir/${_package_path}/{{source_name_part}}.java" ] args = [ "--depfile", rebase_path(depfile, root_build_dir), "--include-path", rebase_path(_include_path, root_build_dir), "--output", rebase_path(outputs[0], root_build_dir), "--template={{source}}", ] if (defined(invoker.defines)) { foreach(_def, invoker.defines) { args += [ "--defines", _def, ] } } } # Filter out .d files. sources = [] foreach(_output, get_target_outputs(":$_apply_gcc_target_name")) { if (get_path_info(_output, "extension") != "d") { sources += [ _output ] } } zip(target_name) { forward_variables_from(invoker, [ "visibility" ]) inputs = sources output = "${target_gen_dir}/${target_name}.srcjar" base_dir = _base_gen_dir deps = [ ":$_apply_gcc_target_name" ] } } # Declare a target for generating Java classes from C++ enums. # # This target generates Java files from C++ enums using a script. # # This target will create a single .srcjar. Adding this target to an # android_library target's srcjar_deps will make the generated java files be # included in that library's final outputs. # # Variables # sources: list of files to be processed by the script. For each annotated # enum contained in the sources files the script will generate a .java # file with the same name as the name of the enum. # # Example # java_cpp_enum("foo_generated_enum") { # sources = [ # "src/native_foo_header.h", # ] # } template("java_cpp_enum") { set_sources_assignment_filter([]) action_with_pydeps(target_name) { forward_variables_from(invoker, [ "sources", "testonly", "visibility", ]) # The sources aren't compiled so don't check their dependencies. check_includes = false script = "//build/android/gyp/java_cpp_enum.py" _srcjar_path = "${target_gen_dir}/${target_name}.srcjar" _rebased_srcjar_path = rebase_path(_srcjar_path, root_build_dir) _rebased_sources = rebase_path(invoker.sources, root_build_dir) args = [ "--srcjar=$_rebased_srcjar_path" ] + _rebased_sources outputs = [ _srcjar_path ] } } # Declare a target for generating Java classes with string constants matching # those found in C++ files using a python script. # # This target will create a single .srcjar. Adding this target to an # android_library target's srcjar_deps will make the generated java files be # included in that library's final outputs. # # Variables # sources: list of files to be processed by the script. For each string # constant in the source files, the script will add a corresponding # Java string to the specified template file. # Example # java_cpp_strings("foo_switches") { # sources = [ # "src/foo_switches.cc", # ] # template = "src/templates/FooSwitches.java.tmpl # } # # foo_switches.cc: # # // A switch. # const char kASwitch = "a-switch"; # # FooSwitches.java.tmpl # # // Copyright {YEAR} The Chromium Authors. All rights reserved. # // Use of this source code is governed by a BSD-style license that can be # // found in the LICENSE file. # # // This file is autogenerated by # // {SCRIPT_NAME} # // From # // {SOURCE_PATH}, and # // {TEMPLATE_PATH} # # package my.java.package; # # public abstract class FooSwitches {{ # // ...snip... # {NATIVE_STRINGS} # // ...snip... # }} # # result: # A FooSwitches.java file, defining a class named FooSwitches in the package # my.java.package. template("java_cpp_strings") { set_sources_assignment_filter([]) action_with_pydeps(target_name) { forward_variables_from(invoker, [ "sources", "testonly", "visibility", ]) # The sources aren't compiled so don't check their dependencies. check_includes = false script = "//build/android/gyp/java_cpp_strings.py" _srcjar_path = "${target_gen_dir}/${target_name}.srcjar" _rebased_srcjar_path = rebase_path(_srcjar_path, root_build_dir) _rebased_sources = rebase_path(invoker.sources, root_build_dir) _rebased_template = rebase_path(invoker.template, root_build_dir) args = [ "--srcjar=$_rebased_srcjar_path", "--template=$_rebased_template", ] args += _rebased_sources sources += [ invoker.template ] outputs = [ _srcjar_path ] } } # Declare a target for processing a Jinja template. # # Variables # input: The template file to be processed. # includes: List of files {% include %}'ed by input. # output: Where to save the result. # variables: (Optional) A list of variables to make available to the template # processing environment, e.g. ["name=foo", "color=red"]. # # Example # jinja_template("chrome_public_manifest") { # input = "java/AndroidManifest.xml" # output = "$target_gen_dir/AndroidManifest.xml" # } template("jinja_template") { action_with_pydeps(target_name) { forward_variables_from(invoker, [ "visibility", "deps", "testonly", ]) inputs = [ invoker.input ] if (defined(invoker.includes)) { inputs += invoker.includes } script = "//build/android/gyp/jinja_template.py" outputs = [ invoker.output ] args = [ "--loader-base-dir", rebase_path("//", root_build_dir), "--inputs", rebase_path(invoker.input, root_build_dir), "--output", rebase_path(invoker.output, root_build_dir), "--check-includes", ] if (defined(invoker.includes)) { _rebased_includes = rebase_path(invoker.includes, root_build_dir) args += [ "--includes=$_rebased_includes" ] } if (defined(invoker.variables)) { args += [ "--variables=${invoker.variables}" ] } } } # Writes native libraries to a NativeLibaries.java file. # # This target will create a single .srcjar. Adding this target to an # android_library target's srcjar_deps will make the generated java files be # included in that library's final outputs. # # Variables: # native_libraries_list_file: (Optional) Path to file listing all native # libraries to write. # version_number: (Optional) String of expected version of 'main' native # library. # enable_chromium_linker: (Optional) Whether to use the Chromium linker. # load_library_from_apk: (Optional) Whether libraries should be loaded from # the APK without uncompressing. # use_final_fields: True to use final fields. When false, all other # variables must not be set. template("write_native_libraries_java") { _native_libraries_file = "$target_gen_dir/$target_name.srcjar" if (current_cpu == "arm" || current_cpu == "arm64") { _cpu_family = "CPU_FAMILY_ARM" } else if (current_cpu == "x86" || current_cpu == "x64") { _cpu_family = "CPU_FAMILY_X86" } else if (current_cpu == "mipsel" || current_cpu == "mips64el") { _cpu_family = "CPU_FAMILY_MIPS" } else { assert(false, "Unsupported CPU family") } action_with_pydeps(target_name) { forward_variables_from(invoker, [ "deps", "testonly", ]) script = "//build/android/gyp/write_native_libraries_java.py" outputs = [ _native_libraries_file ] args = [ "--output", rebase_path(_native_libraries_file, root_build_dir), "--cpu-family", _cpu_family, ] if (invoker.use_final_fields) { # Write native_libraries_list_file via depfile rather than specifyin it # as a dep in order allow R8 to run in parallel with native compilation. depfile = "$target_gen_dir/$target_name.d" args += [ "--final", "--depfile", rebase_path(depfile, root_build_dir), "--native-libraries-list", rebase_path(invoker.native_libraries_list_file, root_build_dir), ] if (defined(invoker.version_number)) { args += [ "--version-number", invoker.version_number, ] } if (defined(invoker.main_component_library)) { args += [ "--main-component-library", invoker.main_component_library, ] } if (defined(invoker.enable_chromium_linker) && invoker.enable_chromium_linker) { args += [ "--enable-chromium-linker" ] } if (defined(invoker.load_library_from_apk) && invoker.load_library_from_apk) { args += [ "--load-library-from-apk" ] } if (defined(invoker.use_modern_linker) && invoker.use_modern_linker) { args += [ "--use-modern-linker" ] } } } } # Declare a target for a set of Android resources generated at build # time and stored in a single zip archive. The content of the archive # should match the layout of a regular Android res/ folder (but the # archive should not include a top-level res/ directory). # # Note that there is no associated .srcjar, R.txt or package name # associated with this target. # # Variables: # generated_resources_zip: Generated zip archive path. # generating_target_name: Name of the target generating # generated_resources_zip. This rule will check that it is part # of its outputs. # deps: Specifies the dependencies of this target. Any Android resources # listed here will be also be included *after* this one when compiling # all resources for a final apk or junit binary. This is useful to # ensure that the resources of the current target override those of the # dependency as well (and would not work if you have these deps to the # generating target's dependencies). # # Example # _zip_archive = "$target_gen_dir/${target_name}.resources_zip" # # action("my_resources__create_zip") { # _depfile = "$target_gen_dir/${target_name}.d" # script = "//build/path/to/create_my_resources_zip.py" # args = [ # "--depfile", rebase_path(_depfile, root_build_dir), # "--output-zip", rebase_path(_zip_archive, root_build_dir), # ] # inputs = [] # outputs = _zip_archive # depfile = _depfile # } # # android_generated_resources("my_resources") { # generated_resources_zip = _zip_archive # generating_target_name = ":my_resources__create_zip" # } # template("android_generated_resources") { forward_variables_from(invoker, [ "testonly" ]) _build_config = "$target_gen_dir/${target_name}.build_config" write_build_config("$target_name$build_config_target_suffix") { forward_variables_from(invoker, [ "resource_overlay" ]) build_config = _build_config resources_zip = invoker.generated_resources_zip type = "android_resources" if (defined(invoker.deps)) { possible_config_deps = invoker.deps } } group(target_name) { public_deps = [ ":$target_name$build_config_target_suffix", invoker.generating_target_name, ] } } # Declare a target for processing Android resources as Jinja templates. # # This takes an Android resource directory where each resource is a Jinja # template, processes each template, then packages the results in a zip file # which can be consumed by an android resources, library, or apk target. # # If this target is included in the deps of an android resources/library/apk, # the resources will be included with that target. # # Variables # resources: The list of resources files to process. # res_dir: The resource directory containing the resources. # variables: (Optional) A list of variables to make available to the template # processing environment, e.g. ["name=foo", "color=red"]. # # Example # jinja_template_resources("chrome_public_template_resources") { # res_dir = "res_template" # resources = ["res_template/xml/syncable.xml"] # variables = ["color=red"] # } template("jinja_template_resources") { _resources_zip = "$target_out_dir/${target_name}.resources.zip" _generating_target_name = "${target_name}__template" action_with_pydeps(_generating_target_name) { forward_variables_from(invoker, [ "deps", "testonly", ]) inputs = invoker.resources script = "//build/android/gyp/jinja_template.py" outputs = [ _resources_zip ] _rebased_resources = rebase_path(invoker.resources, root_build_dir) args = [ "--inputs=${_rebased_resources}", "--inputs-base-dir", rebase_path(invoker.res_dir, root_build_dir), "--outputs-zip", rebase_path(_resources_zip, root_build_dir), "--check-includes", ] if (defined(invoker.variables)) { variables = invoker.variables args += [ "--variables=${variables}" ] } } android_generated_resources(target_name) { forward_variables_from(invoker, [ "deps", "resource_overlay", "testonly", ]) generating_target_name = ":$_generating_target_name" generated_resources_zip = _resources_zip } } # Declare an Android resources target # # This creates a resources zip file that will be used when building an Android # library or apk and included into a final apk. # # To include these resources in a library/apk, this target should be listed in # the library's deps. A library/apk will also include any resources used by its # own dependencies. # # Variables # sources: List of resource files for this target. # deps: Specifies the dependencies of this target. Any Android resources # listed in deps will be included by libraries/apks that depend on this # target. # alternative_android_sdk_dep: Optional. Alternative Android system # android java target to use. # android_manifest: AndroidManifest.xml for this target (optional). Will be # merged into apks that directly or indirectly depend on this target. # android_manifest_dep: Target that generates AndroidManifest (if applicable) # custom_package: java package for generated .java files. # shared_resources: If true make a resource package that can be loaded by a # different application at runtime to access the package's resources. # resource_overlay: Whether the resources in 'sources' should override # resources with the same name. Does not affect the behaviour of any # android_resources() deps of this target. If a target with # resource_overlay=true depends on another target with # resource_overlay=true the target with the dependency overrides the # other. # r_text_file: (optional) path to pre-generated R.txt to be used when # generating R.java instead of resource-based aapt-generated one. # create_srcjar: If false, does not create an R.java file. Needed only for # prebuilts that have R.txt files that do not match their res/ # (Play Services). # # Example: # android_resources("foo_resources") { # deps = [":foo_strings_grd"] # sources = [ # "res/drawable/foo1.xml", # "res/drawable/foo2.xml", # ] # custom_package = "org.chromium.foo" # } # # android_resources("foo_resources_overrides") { # deps = [":foo_resources"] # sources = [ # "res_overrides/drawable/foo1.xml", # "res_overrides/drawable/foo2.xml", # ] # } template("android_resources") { forward_variables_from(invoker, [ "testonly" ]) _base_path = "$target_gen_dir/$target_name" if (defined(invoker.v14_skip)) { not_needed(invoker, [ "v14_skip" ]) } assert(!defined(invoker.resource_dirs) || defined(invoker.sources), "resource_dirs in android_resources is deprecated. Please use " + "sources=[] and list resource files instead. Details: " + "https://crbug.com/1026378") _res_sources_path = "$target_gen_dir/${invoker.target_name}.res.sources" _resources_zip = "$target_out_dir/$target_name.resources.zip" _r_text_out_path = _base_path + "_R.txt" _build_config = _base_path + ".build_config" _build_config_target_name = "$target_name$build_config_target_suffix" if (!defined(invoker.create_srcjar) || invoker.create_srcjar) { _srcjar_path = _base_path + ".srcjar" } _deps = [] if (defined(invoker.deps)) { _deps += invoker.deps } if (defined(invoker.alternative_android_sdk_dep)) { _deps += [ invoker.alternative_android_sdk_dep ] } else { _deps += [ "//third_party/android_sdk:android_sdk_java" ] } _resource_files = [] if (defined(invoker.sources)) { _resource_files += invoker.sources } _rebased_resource_files = rebase_path(_resource_files, root_build_dir) write_file(_res_sources_path, _rebased_resource_files) # This is necessary so we only lint chromium resources. if (defined(invoker.chromium_code)) { _chromium_code = invoker.chromium_code } else { # Default based on whether target is in third_party. _chromium_code = filter_exclude([ get_label_info(":$target_name", "dir") ], [ "*\bthird_party\b*" ]) != [] } write_build_config(_build_config_target_name) { type = "android_resources" build_config = _build_config resources_zip = _resources_zip res_sources_path = _res_sources_path chromium_code = _chromium_code forward_variables_from(invoker, [ "android_manifest", "android_manifest_dep", "custom_package", "resource_overlay", ]) # No package means resources override their deps. if (defined(custom_package) || defined(android_manifest)) { r_text = _r_text_out_path } if (defined(_srcjar_path)) { srcjar = _srcjar_path } possible_config_deps = _deps } prepare_resources(target_name) { forward_variables_from(invoker, [ "android_manifest", "custom_package", "strip_drawables", ]) deps = _deps deps += [ ":$_build_config_target_name" ] if (defined(invoker.android_manifest_dep)) { deps += [ invoker.android_manifest_dep ] } res_sources_path = _res_sources_path sources = _resource_files build_config = _build_config resources_zip = _resources_zip r_text_out_path = _r_text_out_path if (defined(invoker.r_text_file)) { r_text_in_path = invoker.r_text_file } if (defined(_srcjar_path)) { srcjar_path = _srcjar_path } # Always generate R.onResourcesLoaded() method, it is required for # compiling ResourceRewriter, there is no side effect because the # generated R.class isn't used in final apk. shared_resources = true } } # Declare an Android assets target. # # Defines a set of files to include as assets in a dependent apk. # # To include these assets in an apk, this target should be listed in # the apk's deps, or in the deps of a library target used by an apk. # # Variables # deps: Specifies the dependencies of this target. Any Android assets # listed in deps will be included by libraries/apks that depend on this # target. # sources: List of files to include as assets. # renaming_sources: List of files to include as assets and be renamed. # renaming_destinations: List of asset paths for files in renaming_sources. # disable_compression: Whether to disable compression for files that are # known to be compressable (default: false). # treat_as_locale_paks: Causes base's BuildConfig.java to consider these # assets to be locale paks. # # Example: # android_assets("content_shell_assets") { # deps = [ # ":generates_foo", # ":other_assets", # ] # sources = [ # "//path/asset1.png", # "//path/asset2.png", # "$target_gen_dir/foo.dat", # ] # } # # android_assets("overriding_content_shell_assets") { # deps = [ ":content_shell_assets" ] # # Override foo.dat from content_shell_assets. # sources = [ "//custom/foo.dat" ] # renaming_sources = [ "//path/asset2.png" ] # renaming_destinations = [ "renamed/asset2.png" ] # } template("android_assets") { forward_variables_from(invoker, [ "testonly" ]) _build_config = "$target_gen_dir/$target_name.build_config" _build_config_target_name = "$target_name$build_config_target_suffix" write_build_config(_build_config_target_name) { type = "android_assets" build_config = _build_config forward_variables_from(invoker, [ "disable_compression", "treat_as_locale_paks", ]) if (defined(invoker.deps)) { possible_config_deps = invoker.deps } if (defined(invoker.sources)) { asset_sources = invoker.sources } if (defined(invoker.renaming_sources)) { assert(defined(invoker.renaming_destinations)) _source_count = 0 foreach(_, invoker.renaming_sources) { _source_count += 1 } _dest_count = 0 foreach(_, invoker.renaming_destinations) { _dest_count += 1 } assert( _source_count == _dest_count, "android_assets() renaming_sources.length != renaming_destinations.length") asset_renaming_sources = invoker.renaming_sources asset_renaming_destinations = invoker.renaming_destinations } } group(target_name) { forward_variables_from(invoker, [ "deps", "visibility", ]) public_deps = [ ":$_build_config_target_name" ] } } # Declare a group() that supports forwarding java dependency information. # # Example # java_group("conditional_deps") { # if (enable_foo) { # deps = [":foo_java"] # } # } template("java_group") { forward_variables_from(invoker, [ "testonly" ]) write_build_config("$target_name$build_config_target_suffix") { forward_variables_from(invoker, [ "input_jars_paths" ]) type = "group" build_config = "$target_gen_dir/${invoker.target_name}.build_config" supports_android = true if (defined(invoker.deps)) { possible_config_deps = invoker.deps } } foreach(_group_name, [ "header", "impl", "assetres", ]) { java_lib_group("${target_name}__${_group_name}") { forward_variables_from(invoker, [ "deps" ]) group_name = _group_name } } group(target_name) { forward_variables_from(invoker, "*") if (!defined(deps)) { deps = [] } deps += [ ":$target_name$build_config_target_suffix" ] } } # Declare a target that generates localized strings.xml from a .grd file. # # If this target is included in the deps of an android resources/library/apk, # the strings.xml will be included with that target. # # Variables # deps: Specifies the dependencies of this target. # grd_file: Path to the .grd file to generate strings.xml from. # outputs: Expected grit outputs (see grit rule). # # Example # java_strings_grd("foo_strings_grd") { # grd_file = "foo_strings.grd" # } template("java_strings_grd") { forward_variables_from(invoker, [ "testonly" ]) _resources_zip = "$target_out_dir/$target_name.resources.zip" _grit_target_name = "${target_name}__grit" _grit_output_dir = "$target_gen_dir/${target_name}_grit_output" grit(_grit_target_name) { forward_variables_from(invoker, [ "deps", "defines", ]) grit_flags = [ "-E", "ANDROID_JAVA_TAGGED_ONLY=false", ] output_dir = _grit_output_dir resource_ids = "" source = invoker.grd_file outputs = invoker.outputs } _zip_target_name = "${target_name}__zip" zip(_zip_target_name) { base_dir = _grit_output_dir # This needs to get outputs from grit's internal target, not the final # source_set. inputs = filter_exclude(get_target_outputs(":${_grit_target_name}_grit"), [ "*.stamp" ]) output = _resources_zip deps = [ ":$_grit_target_name" ] } android_generated_resources(target_name) { generating_target_name = ":$_zip_target_name" generated_resources_zip = _resources_zip } } # Declare a target that packages strings.xml generated from a grd file. # # If this target is included in the deps of an android resources/library/apk, # the strings.xml will be included with that target. # # Variables # grit_output_dir: directory containing grit-generated files. # generated_files: list of android resource files to package. # # Example # java_strings_grd_prebuilt("foo_strings_grd") { # grit_output_dir = "$root_gen_dir/foo/grit" # generated_files = [ # "values/strings.xml" # ] # } template("java_strings_grd_prebuilt") { forward_variables_from(invoker, [ "testonly" ]) _resources_zip = "$target_out_dir/$target_name.resources.zip" _zip_target_name = "${target_name}__zip" zip(_zip_target_name) { forward_variables_from(invoker, [ "visibility" ]) base_dir = invoker.grit_output_dir inputs = rebase_path(invoker.generated_files, ".", base_dir) output = _resources_zip if (defined(invoker.deps)) { deps = invoker.deps } } android_generated_resources(target_name) { generating_target_name = ":$_zip_target_name" generated_resources_zip = _resources_zip } } # Declare a Java executable target # # Same as java_library, but also creates a wrapper script within # $root_out_dir/bin. # # Supports all variables of java_library(), plus: # main_class: When specified, a wrapper script is created within # $root_build_dir/bin to launch the binary with the given class as the # entrypoint. # wrapper_script_name: Filename for the wrapper script (default=target_name) # wrapper_script_args: List of additional arguments for the wrapper script. # # Example # java_binary("foo") { # sources = [ "org/chromium/foo/FooMain.java" ] # deps = [ ":bar_java" ] # main_class = "org.chromium.foo.FooMain" # } # # java_binary("foo") { # jar_path = "lib/prebuilt.jar" # deps = [ ":bar_java" ] # main_class = "org.chromium.foo.FooMain" # } template("java_binary") { java_library_impl(target_name) { forward_variables_from(invoker, "*") type = "java_binary" if (!defined(data_deps)) { data_deps = [] } data_deps += [ "//third_party/jdk:java_data" ] } } # Declare a Java Annotation Processor. # # Supports all variables of java_library(), plus: # jar_path: Path to a prebuilt jar. Mutually exclusive with sources & # srcjar_deps. # main_class: The fully-quallified class name of the processor's entry # point. # # Example # java_annotation_processor("foo_processor") { # sources = [ "org/chromium/foo/FooProcessor.java" ] # deps = [ ":bar_java" ] # main_class = "org.chromium.foo.FooProcessor" # } # # java_annotation_processor("foo_processor") { # jar_path = "lib/prebuilt.jar" # main_class = "org.chromium.foo.FooMain" # } # # java_library("...") { # annotation_processor_deps = [":foo_processor"] # } # template("java_annotation_processor") { java_library_impl(target_name) { forward_variables_from(invoker, "*") type = "java_annotation_processor" } } # Declare a Junit executable target # # This target creates an executable from java code for running as a junit test # suite. The executable will be in the output folder's /bin/ directory. # # Supports all variables of java_binary(). # # Example # junit_binary("foo") { # sources = [ "org/chromium/foo/FooTest.java" ] # deps = [ ":bar_java" ] # } template("junit_binary") { testonly = true _java_binary_target_name = "${target_name}__java_binary" _test_runner_target_name = "${target_name}__test_runner_script" _main_class = "org.chromium.testing.local.JunitTestMain" _build_config = "$target_gen_dir/$target_name.build_config" _build_config_target_name = "$target_name$build_config_target_suffix" _deps = [ "//testing/android/junit:junit_test_support", "//third_party/android_deps:robolectric_all_java", "//third_party/junit", "//third_party/mockito:mockito_java", ] if (defined(invoker.deps)) { _deps += invoker.deps } if (defined(invoker.alternative_android_sdk_dep)) { _android_sdk_dep = invoker.alternative_android_sdk_dep } else { _android_sdk_dep = "//third_party/android_sdk:android_sdk_java" } # a package name or a manifest is required to have resources. This is # added so that junit tests that do not care about the package name can # still use resources without having to explicitly set one. if (defined(invoker.package_name)) { _package_name = invoker.package_name } else if (!defined(invoker.android_manifest)) { _package_name = "org.chromium.test" } _resource_arsc_output = "${target_gen_dir}/${target_name}.ap_" _compile_resources_target = "${target_name}__compile_resources" compile_resources(_compile_resources_target) { forward_variables_from(invoker, [ "android_manifest" ]) deps = _deps android_sdk_dep = _android_sdk_dep build_config_dep = ":$_build_config_target_name" build_config = _build_config if (defined(_package_name)) { rename_manifest_package = _package_name } if (!defined(android_manifest)) { android_manifest = "//build/android/AndroidManifest.xml" } arsc_output = _resource_arsc_output min_sdk_version = default_min_sdk_version target_sdk_version = android_sdk_version } _jni_srcjar_target = "${target_name}__final_jni" _outer_target_name = target_name generate_jni_registration(_jni_srcjar_target) { enable_native_mocks = true require_native_mocks = true targets = [ ":$_outer_target_name" ] } java_library_impl(_java_binary_target_name) { forward_variables_from(invoker, "*", [ "deps" ]) type = "junit_binary" main_target_name = invoker.target_name # Include the android SDK jar(s) for resource processing. include_android_sdk = true # Robolectric can handle deps that set !supports_android as well those # that set requires_android. bypass_platform_checks = true deps = _deps testonly = true main_class = _main_class wrapper_script_name = "helper/$main_target_name" if (!defined(srcjar_deps)) { srcjar_deps = [] } srcjar_deps += [ ":$_compile_resources_target", ":$_jni_srcjar_target", # This dep is required for any targets that depend on //base:base_java. "//base:base_build_config_gen", ] } test_runner_script(_test_runner_target_name) { test_name = invoker.target_name test_suite = invoker.target_name test_type = "junit" ignore_all_data_deps = true resource_apk = _resource_arsc_output } group(target_name) { forward_variables_from(invoker, [ "assert_no_deps" ]) public_deps = [ ":$_build_config_target_name", ":$_java_binary_target_name", ":$_test_runner_target_name", ] } } # Declare a java library target # # Variables # deps: Specifies the dependencies of this target. Java targets in this list # will be added to the javac classpath. # annotation_processor_deps: List of java_annotation_processor targets to # use when compiling. # # jar_path: Path to a prebuilt jar. Mutually exclusive with sources & # srcjar_deps. # sources: List of .java files included in this library. # srcjar_deps: List of srcjar dependencies. The .java files in the srcjars # will be added to sources and be included in this library. # # input_jars_paths: A list of paths to the jars that should be included # in the compile-time classpath. These are in addition to library .jars # that appear in deps. # # chromium_code: If true, extra analysis warning/errors will be enabled. # enable_errorprone: If true, enables the errorprone compiler. # # jar_excluded_patterns: List of patterns of .class files to exclude. # jar_included_patterns: List of patterns of .class files to include. # When omitted, all classes not matched by jar_excluded_patterns are # included. When specified, all non-matching .class files are stripped. # # output_name: File name for the output .jar (not including extension). # Defaults to the input .jar file name. # # proguard_configs: List of proguard configs to use in final apk step for # any apk that depends on this library. # # supports_android: If true, Android targets (android_library, android_apk) # may depend on this target. Note: if true, this target must only use the # subset of Java available on Android. # bypass_platform_checks: Disables checks about cross-platform (Java/Android) # dependencies for this target. This will allow depending on an # android_library target, for example. # enable_desugar: If false, disables desugaring of lambdas, etc. Use this # only when you are sure the library does not require desugaring. E.g. # to hide warnings shown from desugaring. # # additional_jar_files: Use to package additional files (Java resources) # into the output jar. Pass a list of length-2 lists with format: # [ [ path_to_file, path_to_put_in_jar ] ] # # javac_args: Additional arguments to pass to javac. # errorprone_args: Additional arguments to pass to errorprone. # errorprone_expected_warning_regex: When set, throws an exception if the # errorprone compile does not log a warning which matches the regex. # # data_deps, testonly # # Example # java_library("foo_java") { # sources = [ # "org/chromium/foo/Foo.java", # "org/chromium/foo/FooInterface.java", # "org/chromium/foo/FooService.java", # ] # deps = [ # ":bar_java" # ] # srcjar_deps = [ # ":foo_generated_enum" # ] # jar_excluded_patterns = [ # "*/FooService.class", "org/chromium/FooService\$*.class" # ] # } template("java_library") { java_library_impl(target_name) { forward_variables_from(invoker, "*") type = "java_library" } } # Declare a java library target for a prebuilt jar # # Supports all variables of java_library(). # # Example # java_prebuilt("foo_java") { # jar_path = "foo.jar" # deps = [ # ":foo_resources", # ":bar_java" # ] # } template("java_prebuilt") { java_library_impl(target_name) { forward_variables_from(invoker, "*") type = "java_library" } } # Combines all dependent .jar files into a single .jar file. # # Variables: # output: Path to the output jar. # override_build_config: Use a pre-existing .build_config. Must be of type # "apk". # use_interface_jars: Use all dependent interface .jars rather than # implementation .jars. # use_unprocessed_jars: Use unprocessed / undesugared .jars. # direct_deps_only: Do not recurse on deps. # jar_excluded_patterns (optional) # List of globs for paths to exclude. # # Example # dist_jar("lib_fatjar") { # deps = [ ":my_java_lib" ] # output = "$root_build_dir/MyLibrary.jar" # } template("dist_jar") { # TODO(crbug.com/1042017): Remove. not_needed(invoker, [ "no_build_hooks" ]) forward_variables_from(invoker, [ "testonly" ]) _supports_android = !defined(invoker.supports_android) || invoker.supports_android _use_interface_jars = defined(invoker.use_interface_jars) && invoker.use_interface_jars _use_unprocessed_jars = defined(invoker.use_unprocessed_jars) && invoker.use_unprocessed_jars _direct_deps_only = defined(invoker.direct_deps_only) && invoker.direct_deps_only assert(!(_use_unprocessed_jars && _use_interface_jars), "Cannot set both use_interface_jars and use_unprocessed_jars") _jar_target_name = target_name _deps = [] if (defined(invoker.deps)) { _deps = invoker.deps } if (_supports_android) { _deps += [ "//third_party/android_sdk:android_sdk_java" ] } if (defined(invoker.override_build_config)) { _build_config = invoker.override_build_config } else { _build_config = "$target_gen_dir/$target_name.build_config" _build_config_target_name = "$target_name$build_config_target_suffix" write_build_config(_build_config_target_name) { type = "dist_jar" supports_android = _supports_android requires_android = defined(invoker.requires_android) && invoker.requires_android possible_config_deps = _deps build_config = _build_config } _deps += [ ":$_build_config_target_name" ] } _rebased_build_config = rebase_path(_build_config, root_build_dir) action_with_pydeps(_jar_target_name) { forward_variables_from(invoker, [ "data" ]) script = "//build/android/gyp/zip.py" depfile = "$target_gen_dir/$target_name.d" deps = _deps inputs = [ _build_config ] outputs = [ invoker.output ] args = [ "--depfile", rebase_path(depfile, root_build_dir), "--output", rebase_path(invoker.output, root_build_dir), "--no-compress", ] if (_direct_deps_only) { if (_use_interface_jars) { args += [ "--input-zips=@FileArg($_rebased_build_config:javac:interface_classpath)" ] } else if (_use_unprocessed_jars) { args += [ "--input-zips=@FileArg($_rebased_build_config:javac:classpath)", ] } else { assert( false, "direct_deps_only does not work without use_interface_jars or use_unprocessed_jars") } } else { if (_use_interface_jars) { args += [ "--input-zips=@FileArg($_rebased_build_config:dist_jar:all_interface_jars)" ] } else if (_use_unprocessed_jars) { args += [ "--input-zips=@FileArg($_rebased_build_config:deps_info:javac_full_classpath)" ] } else { args += [ "--input-zips=@FileArg($_rebased_build_config:deps_info:device_classpath)" ] } } _excludes = [] if (defined(invoker.jar_excluded_patterns)) { _excludes += invoker.jar_excluded_patterns } if (_use_interface_jars) { # Turbine adds files like: META-INF/TRANSITIVE/.../Foo.class # These confuse proguard: https://crbug.com/1081443 _excludes += [ "META-INF/*" ] } if (_excludes != []) { args += [ "--input-zips-excluded-globs=$_excludes" ] } } } # Combines all dependent .jar files into a single proguarded .dex file. # # Variables: # output: Path to the output dex. # proguard_enabled: Whether to enable R8. # proguard_configs: List of proguard configs. # # Example # dist_dex("lib_fatjar") { # deps = [ ":my_java_lib" ] # output = "$root_build_dir/MyLibrary.jar" # } template("dist_dex") { _deps = [ "//third_party/android_sdk:android_sdk_java" ] if (defined(invoker.deps)) { _deps += invoker.deps } _build_config = "$target_gen_dir/$target_name.build_config" _build_config_target_name = "$target_name$build_config_target_suffix" write_build_config(_build_config_target_name) { type = "dist_jar" forward_variables_from(invoker, [ "proguard_configs", "proguard_enabled", ]) supports_android = true requires_android = true possible_config_deps = _deps build_config = _build_config } _deps += [ ":$_build_config_target_name" ] dex(target_name) { forward_variables_from(invoker, [ "data", "data_deps", "visibility", "testonly", "proguard_configs", "proguard_enabled", "min_sdk_version", ]) deps = _deps build_config = _build_config enable_multidex = false output = invoker.output if (defined(proguard_enabled) && proguard_enabled) { # When trying to build a stand-alone .dex, don't add in jdk_libs_dex. supports_jdk_library_desugaring = false } else { _rebased_build_config = rebase_path(_build_config, root_build_dir) input_dex_filearg = "@FileArg(${_rebased_build_config}:final_dex:all_dex_files)" } } } # Creates an Android .aar library. # # Currently supports: # * AndroidManifest.xml # * classes.jar # * jni/ # * res/ # * R.txt # * proguard.txt # Does not yet support: # * public.txt # * annotations.zip # * assets/ # See: https://developer.android.com/studio/projects/android-library.html#aar-contents # # Variables: # output: Path to the output .aar. # proguard_configs: List of proguard configs (optional). # android_manifest: Path to AndroidManifest.xml (optional). # native_libraries: list of native libraries (optional). # direct_deps_only: Do not recurse on deps. (optional, defaults false). # jar_excluded_patterns (optional): List of globs for paths to exclude. # jar_included_patterns (optional): List of globs for paths to include. # # Example # dist_aar("my_aar") { # deps = [ ":my_java_lib" ] # output = "$root_build_dir/MyLibrary.aar" # } template("dist_aar") { forward_variables_from(invoker, [ "testonly" ]) _deps = [] if (defined(invoker.deps)) { _deps = invoker.deps } _direct_deps_only = defined(invoker.direct_deps_only) && invoker.direct_deps_only _build_config = "$target_gen_dir/$target_name.build_config" _build_config_target_name = "$target_name$build_config_target_suffix" write_build_config(_build_config_target_name) { type = "dist_aar" forward_variables_from(invoker, [ "proguard_configs" ]) possible_config_deps = _deps supports_android = true requires_android = true build_config = _build_config } _deps += [ ":$_build_config_target_name" ] _rebased_build_config = rebase_path(_build_config, root_build_dir) action_with_pydeps(target_name) { forward_variables_from(invoker, [ "data" ]) depfile = "$target_gen_dir/$target_name.d" deps = _deps script = "//build/android/gyp/dist_aar.py" inputs = [ _build_config ] # Although these will be listed as deps in the depfile, they must also # appear here so that "gn analyze" knows about them. # https://crbug.com/827197 if (defined(invoker.proguard_configs)) { inputs += invoker.proguard_configs } outputs = [ invoker.output ] args = [ "--depfile", rebase_path(depfile, root_build_dir), "--output", rebase_path(invoker.output, root_build_dir), "--dependencies-res-zips=@FileArg($_rebased_build_config:deps_info:dependency_zips)", "--r-text-files=@FileArg($_rebased_build_config:deps_info:dependency_r_txt_files)", "--proguard-configs=@FileArg($_rebased_build_config:deps_info:proguard_all_configs)", ] if (_direct_deps_only) { args += [ "--jars=@FileArg($_rebased_build_config:javac:classpath)" ] } else { args += [ "--jars=@FileArg($_rebased_build_config:deps_info:javac_full_classpath)" ] } if (defined(invoker.android_manifest)) { args += [ "--android-manifest", rebase_path(invoker.android_manifest, root_build_dir), ] } if (defined(invoker.native_libraries) && invoker.native_libraries != []) { inputs += invoker.native_libraries _rebased_native_libraries = rebase_path(invoker.native_libraries, root_build_dir) args += [ "--native-libraries=$_rebased_native_libraries", "--abi=$android_app_abi", ] } if (defined(invoker.jar_excluded_patterns)) { args += [ "--jar-excluded-globs=${invoker.jar_excluded_patterns}" ] } if (defined(invoker.jar_included_patterns)) { args += [ "--jar-included-globs=${invoker.jar_included_patterns}" ] } if (defined(invoker.resource_included_patterns)) { args += [ "--resource-included-globs=${invoker.resource_included_patterns}", ] } } } # Declare an Android library target # # This target creates an Android library containing java code and Android # resources. # # Supports all variables of java_library(), plus: # deps: In addition to defining java deps, this can also include # android_assets() and android_resources() targets. # alternative_android_sdk_ijar: if set, the given android_sdk_ijar file # replaces the default android_sdk_ijar. # alternative_android_sdk_ijar_dep: the target that generates # alternative_android_sdk_ijar, must be set if alternative_android_sdk_ijar # is used. # alternative_android_sdk_jar: actual jar corresponding to # alternative_android_sdk_ijar, must be set if alternative_android_sdk_ijar # is used. # # Example # android_library("foo_java") { # sources = [ # "android/org/chromium/foo/Foo.java", # "android/org/chromium/foo/FooInterface.java", # "android/org/chromium/foo/FooService.java", # ] # deps = [ # ":bar_java" # ] # srcjar_deps = [ # ":foo_generated_enum" # ] # jar_excluded_patterns = [ # "*/FooService.class", "org/chromium/FooService\$*.class" # ] # } template("android_library") { java_library(target_name) { forward_variables_from(invoker, "*") supports_android = true requires_android = true if (!defined(jar_excluded_patterns)) { jar_excluded_patterns = [] } jar_excluded_patterns += [ "*/R.class", "*/R\$*.class", "*/Manifest.class", "*/Manifest\$*.class", "*/GEN_JNI.class", ] } } # Declare an Android library target for a prebuilt jar # # This target creates an Android library containing java code and Android # resources. # # Supports all variables of android_library(). # # Example # android_java_prebuilt("foo_java") { # jar_path = "foo.jar" # deps = [ # ":foo_resources", # ":bar_java" # ] # } template("android_java_prebuilt") { android_library(target_name) { forward_variables_from(invoker, "*") } } template("android_system_java_prebuilt") { java_library_impl(target_name) { forward_variables_from(invoker, "*") supports_android = true type = "system_java_library" } } # Creates org/chromium/base/BuildConfig.java # This doesn't really belong in //build since it genates a file for //base. # However, we don't currently have a better way to include this file in all # apks that depend on //base:base_java. # # Variables: # use_final_fields: True to use final fields. When false, all other # variables must not be set. # enable_multidex: Value for ENABLE_MULTIDEX. # min_sdk_version: Value for MIN_SDK_VERSION. # bundles_supported: Whether or not this target can be treated as a bundle. # resources_version_variable: # is_incremental_install: template("generate_build_config_srcjar") { java_cpp_template(target_name) { package_path = "org/chromium/base" sources = [ "//base/android/java/templates/BuildConfig.template" ] defines = [] # Set these even when !use_final_fields so that they have correct default # values within junit_binary(), which ignores jar_excluded_patterns. if (is_java_debug || dcheck_always_on) { defines += [ "_DCHECK_IS_ON" ] } if (use_cfi_diag || is_ubsan || is_ubsan_security || is_ubsan_vptr) { defines += [ "_IS_UBSAN" ] } if (is_chrome_branded) { defines += [ "_IS_CHROME_BRANDED" ] } if (is_chromecast && chromecast_branding == "internal") { defines += [ "_IS_CHROMECAST_BRANDING_INTERNAL" ] } if (defined(invoker.bundles_supported) && invoker.bundles_supported) { defines += [ "_BUNDLES_SUPPORTED" ] } if (defined(invoker.is_incremental_install) && invoker.is_incremental_install) { defines += [ "_IS_INCREMENTAL_INSTALL" ] } if (invoker.use_final_fields) { forward_variables_from(invoker, [ "deps", "testonly", ]) defines += [ "USE_FINAL" ] if (invoker.enable_multidex) { defines += [ "ENABLE_MULTIDEX" ] } if (defined(invoker.min_sdk_version)) { defines += [ "_MIN_SDK_VERSION=${invoker.min_sdk_version}" ] } if (defined(invoker.resources_version_variable)) { defines += [ "_RESOURCES_VERSION_VARIABLE=${invoker.resources_version_variable}", ] } } } } # Creates ProductConfig.java, a file containing product-specific configuration. # # Currently, this includes the list of locales, both in their compressed and # uncompressed format, as well as library loading # # Variables: # build_config: Path to build_config used for locale lists. # is_bundle_module: Whether or not this target is part of a bundle build. # java_package: Java package for the generated class. # use_chromium_linker: # use_modern_linker: template("generate_product_config_srcjar") { java_cpp_template(target_name) { defines = [] _use_final = defined(invoker.build_config) || defined(invoker.use_chromium_linker) || defined(invoker.use_modern_linker) || defined(invoker.is_bundle) if (_use_final) { defines += [ "USE_FINAL" ] } package_path = string_replace(invoker.java_package, ".", "/") sources = [ "//build/android/java/templates/ProductConfig.template" ] defines += [ "PACKAGE=${invoker.java_package}" ] _use_chromium_linker = defined(invoker.use_chromium_linker) && invoker.use_chromium_linker _use_modern_linker = defined(invoker.use_modern_linker) && invoker.use_modern_linker _is_bundle = defined(invoker.is_bundle_module) && invoker.is_bundle_module defines += [ "USE_CHROMIUM_LINKER_VALUE=$_use_chromium_linker", "USE_MODERN_LINKER_VALUE=$_use_modern_linker", "IS_BUNDLE_VALUE=$_is_bundle", ] if (defined(invoker.build_config)) { forward_variables_from(invoker, [ "deps", "testonly", ]) _rebased_build_config = rebase_path(invoker.build_config, root_build_dir) defines += [ "COMPRESSED_LOCALE_LIST=" + "@FileArg($_rebased_build_config:deps_info:compressed_locales_java_list)", "UNCOMPRESSED_LOCALE_LIST=" + "@FileArg($_rebased_build_config:deps_info:uncompressed_locales_java_list)", ] } } } # Declare an Android app module target, which is used as the basis for an # Android APK or an Android app bundle module. # # Supports all variables of android_library(), plus: # android_manifest: Path to AndroidManifest.xml. NOTE: This manifest must # not contain a element. Use [min|target|max]_sdk_version # instead. # android_manifest_dep: Target that generates AndroidManifest (if applicable) # png_to_webp: If true, pngs (with the exception of 9-patch) are # converted to webp during resource packaging. # loadable_modules: List of paths to native libraries to include. Different # from |shared_libraries| in that: # * dependencies of this .so are not automatically included # * ".cr.so" is never added # * they are not side-loaded when incremental_install=true. # * load_library_from_apk, use_chromium_linker, # and enable_relocation_packing do not apply # Use this instead of shared_libraries when you are going to load the library # conditionally, and only when shared_libraries doesn't work for you. # secondary_abi_loadable_modules: This is the loadable_modules analog to # secondary_abi_shared_libraries. # shared_libraries: List shared_library targets to bundle. If these # libraries depend on other shared_library targets, those dependencies will # also be included in the apk (e.g. for is_component_build). # secondary_abi_shared_libraries: secondary abi shared_library targets to # bundle. If these libraries depend on other shared_library targets, those # dependencies will also be included in the apk (e.g. for is_component_build). # native_lib_placeholders: List of placeholder filenames to add to the apk # (optional). # secondary_native_lib_placeholders: List of placeholder filenames to add to # the apk for the secondary ABI (optional). # generate_buildconfig_java: If defined and false, skip generating the # BuildConfig java class describing the build configuration. The default # is true for non-test APKs. # generate_final_jni: If defined and false, skip generating the # GEN_JNI srcjar. # jni_registration_header: If specified, causes the # ${target_name}__final_jni target to additionally output a # header file to this path for use with manual JNI registration. # jni_sources_exclusions: List of source path to exclude from the # final_jni step. # aapt_locale_allowlist: If set, all locales not in this list will be # stripped from resources.arsc. # resource_exclusion_regex: Causes all drawable images matching the regex to # be excluded (mipmaps are still included). # resource_exclusion_exceptions: A list of globs used when # resource_exclusion_regex is set. Files that match this list will # still be included. # resource_values_filter_rules: List of "source_path:name_regex" used to # filter out unwanted values/ resources. # shared_resources: True if this is a runtime shared library APK, like # the system_webview_apk target. Ensures that its resources can be # used by the loading application process. # app_as_shared_lib: True if this is a regular application apk that can # also serve as a runtime shared library, like the monochrome_public_apk # target. Ensures that the resources are usable both by the APK running # as an application, or by another process that loads it at runtime. # shared_resources_allowlist_target: Optional name of a target specifying # an input R.txt file that lists the resources that can be exported # by the APK when shared_resources or app_as_shared_lib is defined. # uncompress_shared_libraries: True if shared libraries should be stored # uncompressed in the APK. Must be unset or true if load_library_from_apk # is set to true. # uncompress_dex: Store final .dex files uncompressed in the apk. # strip_resource_names: True if resource names should be stripped from the # resources.arsc file in the apk or module. # short_resource_paths: True if resource paths should be shortened in the # apk or module. # resources_config_paths: List of paths to the aapt2 optimize config files # that tags resources with acceptable/non-acceptable optimizations. # expected_android_manifest: Enables verification of expected merged # manifest based on a golden file. # resource_ids_provider_dep: If passed, this target will use the resource # IDs generated by {resource_ids_provider_dep}__compile_res during # resource compilation. # static_library_dependent_targets: A list of scopes describing targets that # use this target as a static library. Common Java code from the targets # listed in static_library_dependent_targets will be moved into this # target. Scope members are name and is_resource_ids_provider. # static_library_provider: Specifies a single target that this target will # use as a static library APK. # static_library_synchronized_proguard: When proguard is enabled, the # static_library_provider target will provide the dex file(s) for this # target. # min_sdk_version: The minimum Android SDK version this target supports. # Optional, default $default_min_sdk_version. # target_sdk_version: The target Android SDK version for this target. # Optional, default to android_sdk_version. # max_sdk_version: The maximum Android SDK version this target supports. # Optional, default not set. # require_native_mocks: Enforce that any native calls using # org.chromium.base.annotations.NativeMethods must have a mock set # (optional). # enable_native_mocks: Allow native calls using # org.chromium.base.annotations.NativeMethods to be mocked in tests # (optional). # product_config_java_packages: Optional list of java packages. If given, a # ProductConfig.java file will be generated for each package. # disable_checkdiscard: Turn off -checkdiscard directives in the proguard # step. # disable_r8_outlining: Turn off outlining during the proguard step. # annotation_processor_deps: List of java_annotation_processor targets to # use when compiling the sources given to this target (optional). # processor_args_javac: List of args to pass to annotation processors when # compiling sources given to this target (optional). # bundles_supported: Enable Java code to treat this target as a bundle # whether (by default determined by the target type). # main_component_library: Specifies the name of the base component's library # in a component build. If given, the system will find dependent native # libraries at runtime by inspecting this library (optional). # expected_libs_and_assets: Verify the list of included native libraries # and assets is consistent with the given expectation file. # expected_libs_and_assets_base: Treat expected_libs_and_assets as a diff # with this file as the base. # expected_proguard_config: Checks that the merged set of proguard flags # matches the given config. # expected_proguard_config_base: Treat expected_proguard_config as a diff # with this file as the base. template("android_apk_or_module") { forward_variables_from(invoker, [ "testonly" ]) assert(defined(invoker.android_manifest)) _base_path = "$target_out_dir/$target_name/$target_name" _build_config = "$target_gen_dir/$target_name.build_config" _build_config_target = "$target_name$build_config_target_suffix" _min_sdk_version = default_min_sdk_version _target_sdk_version = android_sdk_version if (defined(invoker.min_sdk_version)) { _min_sdk_version = invoker.min_sdk_version } if (defined(invoker.target_sdk_version)) { _target_sdk_version = invoker.target_sdk_version } _template_name = target_name _is_bundle_module = defined(invoker.is_bundle_module) && invoker.is_bundle_module if (_is_bundle_module) { _is_base_module = defined(invoker.is_base_module) && invoker.is_base_module } _enable_multidex = !defined(invoker.enable_multidex) || invoker.enable_multidex if (!_is_bundle_module) { _final_apk_path = invoker.final_apk_path _final_rtxt_path = "${_final_apk_path}.R.txt" } _short_resource_paths = defined(invoker.short_resource_paths) && invoker.short_resource_paths && enable_arsc_obfuscation _strip_resource_names = defined(invoker.strip_resource_names) && invoker.strip_resource_names && enable_arsc_obfuscation _optimize_resources = _strip_resource_names || _short_resource_paths if (!_is_bundle_module && _short_resource_paths) { _final_pathmap_path = "${_final_apk_path}.pathmap.txt" } _res_size_info_path = "$target_out_dir/$target_name.ap_.info" if (!_is_bundle_module) { _final_apk_path_no_ext_list = process_file_template([ _final_apk_path ], "{{source_dir}}/{{source_name_part}}") _final_apk_path_no_ext = _final_apk_path_no_ext_list[0] not_needed([ "_final_apk_path_no_ext" ]) } # Non-base bundle modules create only proto resources. if (!_is_bundle_module || _is_base_module) { _arsc_resources_path = "$target_out_dir/$target_name.ap_" } if (_is_bundle_module) { # Path to the intermediate proto-format resources zip file. _proto_resources_path = "$target_out_dir/$target_name.proto.ap_" if (_optimize_resources) { _optimized_proto_resources_path = "$target_out_dir/$target_name.optimized.proto.ap_" } } else { # resource_sizes.py needs to be able to find the unpacked resources.arsc # file based on apk name to compute normatlized size. _resource_sizes_arsc_path = "$root_out_dir/arsc/" + rebase_path(_final_apk_path_no_ext, root_build_dir) + ".ap_" if (_optimize_resources) { _optimized_arsc_resources_path = "$target_out_dir/$target_name.optimized.ap_" } } if (defined(invoker.version_code)) { _version_code = invoker.version_code } else { _version_code = android_default_version_code } if (android_override_version_code != "") { _version_code = android_override_version_code } if (defined(invoker.version_name)) { _version_name = invoker.version_name } else { _version_name = android_default_version_name } if (android_override_version_name != "") { _version_name = android_override_version_name } _deps = [] if (defined(invoker.deps)) { _deps = invoker.deps } _srcjar_deps = [] if (defined(invoker.srcjar_deps)) { _srcjar_deps = invoker.srcjar_deps } _android_root_manifest_deps = [] if (defined(invoker.android_manifest_dep)) { _android_root_manifest_deps = [ invoker.android_manifest_dep ] } _android_root_manifest = invoker.android_manifest _use_chromium_linker = defined(invoker.use_chromium_linker) && invoker.use_chromium_linker _use_modern_linker = defined(invoker.use_modern_linker) && invoker.use_modern_linker _load_library_from_apk = defined(invoker.load_library_from_apk) && invoker.load_library_from_apk not_needed([ "_use_chromium_linker", "_use_modern_linker", ]) assert(!_load_library_from_apk || _use_chromium_linker, "load_library_from_apk requires use_chromium_linker") # Make sure that uncompress_shared_libraries is set to true if # load_library_from_apk is true. if (defined(invoker.uncompress_shared_libraries)) { _uncompress_shared_libraries = invoker.uncompress_shared_libraries assert(!_load_library_from_apk || _uncompress_shared_libraries) } else { _uncompress_shared_libraries = _load_library_from_apk } # The dependency that makes the chromium linker, if any is needed. _native_libs_deps = [] _shared_libraries_is_valid = defined(invoker.shared_libraries) && invoker.shared_libraries != [] if (_shared_libraries_is_valid) { _native_libs_deps += invoker.shared_libraries # Write shared library output files of all dependencies to a file. Those # will be the shared libraries packaged into the APK. _shared_library_list_file = "$target_gen_dir/${_template_name}.native_libs" generated_file("${_template_name}__shared_library_list") { deps = _native_libs_deps outputs = [ _shared_library_list_file ] data_keys = [ "shared_libraries" ] walk_keys = [ "shared_libraries_barrier" ] rebase = root_build_dir } } else { # Must exist for instrumentation_test_apk() to depend on. group("${_template_name}__shared_library_list") { } } _secondary_abi_native_libs_deps = [] if (defined(invoker.secondary_abi_shared_libraries) && invoker.secondary_abi_shared_libraries != []) { _secondary_abi_native_libs_deps = invoker.secondary_abi_shared_libraries # Write shared library output files of all dependencies to a file. Those # will be the shared libraries packaged into the APK. _secondary_abi_shared_library_list_file = "$target_gen_dir/${_template_name}.secondary_abi_native_libs" generated_file("${_template_name}__secondary_abi_shared_library_list") { deps = _secondary_abi_native_libs_deps outputs = [ _secondary_abi_shared_library_list_file ] data_keys = [ "shared_libraries" ] walk_keys = [ "shared_libraries_barrier" ] rebase = root_build_dir } } else { # Must exist for instrumentation_test_apk() to depend on. group("${_template_name}__secondary_abi_shared_library_list") { } } _rebased_build_config = rebase_path(_build_config, root_build_dir) assert(_rebased_build_config != "") # Mark as used. _generate_buildconfig_java = !defined(invoker.apk_under_test) if (defined(invoker.generate_buildconfig_java)) { _generate_buildconfig_java = invoker.generate_buildconfig_java } _generate_productconfig_java = defined(invoker.product_config_java_packages) # JNI generation usually goes hand-in-hand with buildconfig generation. _generate_final_jni = _generate_buildconfig_java if (defined(invoker.generate_final_jni)) { _generate_final_jni = invoker.generate_final_jni } _proguard_enabled = defined(invoker.proguard_enabled) && invoker.proguard_enabled if (!_is_bundle_module && _proguard_enabled) { _proguard_mapping_path = "$_final_apk_path.mapping" } # TODO(http://crbug.com/901465): Move shared Java code to static libraries # when !_proguard_enabled too. _is_static_library_provider = defined(invoker.static_library_dependent_targets) && _proguard_enabled if (_is_static_library_provider) { _static_library_sync_dex_path = "$_base_path.synchronized.r8dex.jar" _resource_ids_provider_deps = [] foreach(_target, invoker.static_library_dependent_targets) { if (_target.is_resource_ids_provider) { assert(_resource_ids_provider_deps == [], "Can only have 1 resource_ids_provider_dep") _resource_ids_provider_deps += [ _target.name ] } } _resource_ids_provider_dep = _resource_ids_provider_deps[0] } else if (defined(invoker.resource_ids_provider_dep)) { _resource_ids_provider_dep = invoker.resource_ids_provider_dep } if (_is_static_library_provider) { _shared_resources_allowlist_target = _resource_ids_provider_dep disable_checkdiscard = true } else if (defined(invoker.shared_resources_allowlist_target)) { _shared_resources_allowlist_target = invoker.shared_resources_allowlist_target } _uses_static_library = defined(invoker.static_library_provider) _uses_static_library_synchronized_proguard = defined(invoker.static_library_synchronized_proguard) && invoker.static_library_synchronized_proguard if (_uses_static_library_synchronized_proguard) { assert(_uses_static_library) # These will be provided by the static library APK. _generate_buildconfig_java = false _generate_final_jni = false } # TODO(crbug.com/864142): Allow incremental installs of bundle modules. _incremental_apk = !_is_bundle_module && !(defined(invoker.never_incremental) && invoker.never_incremental) && incremental_install if (_incremental_apk) { _target_dir_name = get_label_info(target_name, "dir") _incremental_install_json_path = "$root_out_dir/gen.runtime/$_target_dir_name/$target_name.incremental.json" _incremental_apk_path = "${_final_apk_path_no_ext}_incremental.apk" } if (!_incremental_apk) { # Bundle modules don't build the dex here, but need to write this path # to their .build_config file. if (_proguard_enabled) { _final_dex_path = "$_base_path.r8dex.jar" } else { _final_dex_path = "$_base_path.mergeddex.jar" } } _android_manifest = "$target_gen_dir/${_template_name}_manifest/AndroidManifest.xml" _merge_manifest_target = "${_template_name}__merge_manifests" merge_manifests(_merge_manifest_target) { forward_variables_from(invoker, [ "manifest_package", "max_sdk_version", ]) input_manifest = _android_root_manifest output_manifest = _android_manifest build_config = _build_config min_sdk_version = _min_sdk_version target_sdk_version = _target_sdk_version deps = _android_root_manifest_deps + [ ":$_build_config_target" ] } _final_deps = [] _enable_main_dex_list = _enable_multidex && _min_sdk_version < 21 if (_enable_main_dex_list) { _generated_proguard_main_dex_config = "$_base_path.resources.main-dex-proguard.txt" } _generated_proguard_config = "$_base_path.resources.proguard.txt" if (_generate_buildconfig_java && defined(invoker.product_version_resources_dep)) { # Needs to be added as a .build_config dep to pick up resources. _deps += [ invoker.product_version_resources_dep ] } if (defined(invoker.alternative_android_sdk_dep)) { _android_sdk_dep = invoker.alternative_android_sdk_dep } else { _android_sdk_dep = "//third_party/android_sdk:android_sdk_java" } if (defined(_shared_resources_allowlist_target)) { _allowlist_gen_dir = get_label_info(_shared_resources_allowlist_target, "target_gen_dir") _allowlist_target_name = get_label_info(_shared_resources_allowlist_target, "name") _allowlist_r_txt_path = "${_allowlist_gen_dir}/${_allowlist_target_name}" + "__compile_resources_R.txt" _allowlist_deps = "${_shared_resources_allowlist_target}__compile_resources" } if (_short_resource_paths) { _resources_path_map_out_path = "${target_gen_dir}/${_template_name}_resources_path_map.txt" } _compile_resources_target = "${_template_name}__compile_resources" _compile_resources_rtxt_out = "${target_gen_dir}/${_compile_resources_target}_R.txt" _compile_resources_emit_ids_out = "${target_gen_dir}/${_compile_resources_target}.resource_ids" compile_resources(_compile_resources_target) { forward_variables_from(invoker, [ "aapt_locale_allowlist", "app_as_shared_lib", "enforce_resource_overlays", "expected_android_manifest", "expected_android_manifest_base", "manifest_package", "max_sdk_version", "no_xml_namespaces", "package_id", "package_name", "png_to_webp", "r_java_root_package_name", "resource_exclusion_exceptions", "resource_exclusion_regex", "resource_values_filter_rules", "resources_config_paths", "shared_resources", "shared_resources_allowlist_locales", "support_zh_hk", ]) short_resource_paths = _short_resource_paths strip_resource_names = _strip_resource_names android_manifest = _android_manifest android_manifest_dep = ":$_merge_manifest_target" version_code = _version_code version_name = _version_name min_sdk_version = _min_sdk_version target_sdk_version = _target_sdk_version if (defined(expected_android_manifest)) { top_target_name = _template_name } if (defined(_resource_ids_provider_dep)) { resource_ids_provider_dep = _resource_ids_provider_dep } if (defined(invoker.post_process_package_resources_script)) { post_process_script = invoker.post_process_package_resources_script } r_text_out_path = _compile_resources_rtxt_out emit_ids_out_path = _compile_resources_emit_ids_out size_info_path = _res_size_info_path proguard_file = _generated_proguard_config if (_enable_main_dex_list) { proguard_file_main_dex = _generated_proguard_main_dex_config } if (_short_resource_paths) { resources_path_map_out_path = _resources_path_map_out_path } build_config = _build_config build_config_dep = ":$_build_config_target" android_sdk_dep = _android_sdk_dep deps = _deps # The static library uses the R.txt files generated by the # static_library_dependent_targets when generating the final R.java file. if (_is_static_library_provider) { foreach(_dep, invoker.static_library_dependent_targets) { deps += [ "${_dep.name}__compile_resources" ] } } if (defined(invoker.apk_under_test)) { # Set the arsc package name to match the apk_under_test package name # So that test resources can references under_test resources via # @type/name syntax. r_java_root_package_name = "test" arsc_package_name = "@FileArg($_rebased_build_config:deps_info:arsc_package_name)" # Passing in the --emit-ids mapping will cause aapt2 to assign resources # IDs that do not conflict with those from apk_under_test. assert(!defined(resource_ids_provider_dep)) resource_ids_provider_dep = invoker.apk_under_test include_resource = get_label_info(invoker.apk_under_test, "target_out_dir") + "/" + get_label_info(invoker.apk_under_test, "name") + ".ap_" _link_against = invoker.apk_under_test } if (_is_bundle_module) { is_bundle_module = true proto_output = _proto_resources_path if (_optimize_resources) { optimized_proto_output = _optimized_proto_resources_path } if (defined(invoker.base_module_target)) { include_resource = get_label_info(invoker.base_module_target, "target_out_dir") + "/" + get_label_info(invoker.base_module_target, "name") + ".ap_" _link_against = invoker.base_module_target } } else if (_optimize_resources) { optimized_arsc_output = _optimized_arsc_resources_path } if (defined(_link_against)) { deps += [ "${_link_against}__compile_resources" ] include_resource = get_label_info(_link_against, "target_out_dir") + "/" + get_label_info(_link_against, "name") + ".ap_" } # Bundle modules have to reference resources from the base module. if (!_is_bundle_module || _is_base_module) { arsc_output = _arsc_resources_path } if (defined(_shared_resources_allowlist_target)) { # Used to ensure that the WebView resources are properly shared # (i.e. are non-final and with package ID 0). shared_resources_allowlist = _allowlist_r_txt_path deps += [ _allowlist_deps ] } } _srcjar_deps += [ ":$_compile_resources_target" ] if (defined(_resource_sizes_arsc_path)) { _copy_arsc_target = "${_template_name}__copy_arsc" copy(_copy_arsc_target) { deps = [ ":$_compile_resources_target" ] # resource_sizes.py doesn't care if it gets the optimized .arsc. sources = [ _arsc_resources_path ] outputs = [ _resource_sizes_arsc_path ] } _final_deps += [ ":$_copy_arsc_target" ] } if (!_is_bundle_module) { # Output the R.txt file to a more easily discoverable location for # archiving. This is necessary when stripping resource names so that we # have an archive of resource names to ids for shipped apks (for # debugging purposes). We copy the file rather than change the location # of the original because other targets rely on the location of the R.txt # file. _copy_rtxt_target = "${_template_name}__copy_rtxt" copy(_copy_rtxt_target) { deps = [ ":$_compile_resources_target" ] sources = [ _compile_resources_rtxt_out ] outputs = [ _final_rtxt_path ] } _final_deps += [ ":$_copy_rtxt_target" ] if (_short_resource_paths) { # Do the same for path map _copy_pathmap_target = "${_template_name}__copy_pathmap" copy(_copy_pathmap_target) { deps = [ ":$_compile_resources_target" ] sources = [ _resources_path_map_out_path ] outputs = [ _final_pathmap_path ] # The monochrome_apk_checker test needs pathmap when run on swarming. data = [ _final_pathmap_path ] } _final_deps += [ ":$_copy_pathmap_target" ] } } _generate_native_libraries_java = (!_is_bundle_module || _is_base_module) && (_native_libs_deps != [] || _secondary_abi_native_libs_deps != []) && !_uses_static_library_synchronized_proguard if (_generate_native_libraries_java) { write_native_libraries_java("${_template_name}__native_libraries") { forward_variables_from(invoker, [ "main_component_library" ]) deps = [] if (defined(invoker.native_lib_version_rule)) { deps += [ invoker.native_lib_version_rule ] } if (defined(invoker.native_lib_version_arg)) { version_number = invoker.native_lib_version_arg } # Do not add a dep on the generated_file target in order to avoid having # to build the native libraries before this target. The dependency is # instead captured via a depfile. if (_native_libs_deps != []) { native_libraries_list_file = _shared_library_list_file } else { native_libraries_list_file = _secondary_abi_shared_library_list_file } enable_chromium_linker = _use_chromium_linker load_library_from_apk = _load_library_from_apk use_modern_linker = _use_modern_linker use_final_fields = true } _srcjar_deps += [ ":${_template_name}__native_libraries" ] } else { if (defined(invoker.native_lib_version_arg)) { not_needed(invoker, [ "native_lib_version_arg" ]) } if (defined(invoker.native_lib_version_rule)) { not_needed(invoker, [ "native_lib_version_rule" ]) } } _loadable_modules = [] if (defined(invoker.loadable_modules)) { _loadable_modules = invoker.loadable_modules } if (_native_libs_deps != []) { _loadable_modules += _sanitizer_runtimes } if (_generate_buildconfig_java) { generate_build_config_srcjar("${_template_name}__build_config_srcjar") { forward_variables_from(invoker, [ "min_sdk_version" ]) _bundles_supported = _is_bundle_module || _is_static_library_provider if (defined(invoker.bundles_supported)) { _bundles_supported = invoker.bundles_supported } bundles_supported = _bundles_supported use_final_fields = true enable_multidex = _enable_multidex is_incremental_install = _incremental_apk if (defined(invoker.product_version_resources_dep)) { resources_version_variable = "org.chromium.base.R.string.product_version" } deps = [ ":$_build_config_target" ] } _srcjar_deps += [ ":${_template_name}__build_config_srcjar" ] } if (_generate_productconfig_java) { foreach(_package, invoker.product_config_java_packages) { _locale_target_name = "${_template_name}_${_package}__product_config_srcjar" generate_product_config_srcjar("$_locale_target_name") { forward_variables_from(invoker, [ "is_bundle_module" ]) build_config = _build_config java_package = _package use_chromium_linker = _use_chromium_linker use_modern_linker = _use_modern_linker deps = [ ":$_build_config_target" ] } _srcjar_deps += [ ":$_locale_target_name" ] } } if (_generate_final_jni) { generate_jni_registration("${_template_name}__final_jni") { forward_variables_from(invoker, [ "enable_native_mocks", "require_native_mocks", ]) if (defined(invoker.bundle_target)) { targets = [ invoker.bundle_target ] } else { targets = [ ":$_template_name" ] } if (_is_static_library_provider) { foreach(_target, invoker.static_library_dependent_targets) { targets += [ _target.name ] } } if (defined(invoker.jni_registration_header)) { header_output = invoker.jni_registration_header } if (defined(invoker.jni_sources_exclusions)) { sources_exclusions = invoker.jni_sources_exclusions } } _srcjar_deps += [ ":${_template_name}__final_jni" ] } _java_target = "${_template_name}__java" java_library_impl(_java_target) { forward_variables_from(invoker, [ "alternative_android_sdk_dep", "android_manifest", "android_manifest_dep", "annotation_processor_deps", "apk_under_test", "base_module_target", "chromium_code", "enable_jetify", "jacoco_never_instrument", "javac_args", "native_lib_placeholders", "processor_args_javac", "secondary_abi_loadable_modules", "secondary_native_lib_placeholders", "sources", "static_library_dependent_targets", "library_always_compress", "library_renames", ]) deps = _deps if (_uses_static_library_synchronized_proguard) { # The static library will provide all R.java files, but we still need to # make the base module R.java files available at compile time since DFM # R.java classes extend base module classes. jar_excluded_patterns = [ "*/R.class", "*/R\$*.class", ] } if (_is_bundle_module) { type = "android_app_bundle_module" res_size_info_path = _res_size_info_path is_base_module = _is_base_module forward_variables_from(invoker, [ "version_code", "version_name", ]) } else { type = "android_apk" } r_text_path = _compile_resources_rtxt_out main_target_name = _template_name supports_android = true requires_android = true srcjar_deps = _srcjar_deps if (defined(_final_dex_path)) { final_dex_path = _final_dex_path } if (_is_bundle_module) { proto_resources_path = _proto_resources_path if (_optimize_resources) { proto_resources_path = _optimized_proto_resources_path if (_short_resource_paths) { module_pathmap_path = _resources_path_map_out_path } } } else { apk_path = _final_apk_path if (_incremental_apk) { incremental_apk_path = _incremental_apk_path incremental_install_json_path = _incremental_install_json_path } } proguard_enabled = _proguard_enabled if (_proguard_enabled) { proguard_configs = [ _generated_proguard_config ] if (defined(invoker.proguard_configs)) { proguard_configs += invoker.proguard_configs } if (_enable_main_dex_list) { proguard_configs += [ "//build/android/multidex.flags" ] } if (!dcheck_always_on && (!defined(testonly) || !testonly) && # Injected JaCoCo code causes -checkdiscards to fail. !use_jacoco_coverage) { proguard_configs += [ "//build/android/dcheck_is_off.flags" ] } if (!_is_bundle_module) { proguard_mapping_path = _proguard_mapping_path } } # Do not add a dep on the generated_file target in order to avoid having # to build the native libraries before this target. The dependency is # instead captured via a depfile. if (_native_libs_deps != []) { shared_libraries_runtime_deps_file = _shared_library_list_file } if (defined(_secondary_abi_shared_library_list_file)) { secondary_abi_shared_libraries_runtime_deps_file = _secondary_abi_shared_library_list_file } loadable_modules = _loadable_modules uncompress_shared_libraries = _uncompress_shared_libraries if (defined(_allowlist_r_txt_path) && _is_bundle_module) { # Used to write the file path to the target's .build_config only. base_allowlist_rtxt_path = _allowlist_r_txt_path } } # TODO(cjhopman): This is only ever needed to calculate the list of tests to # run. See build/android/pylib/instrumentation/test_jar.py. We should be # able to just do that calculation at build time instead. if (defined(invoker.dist_ijar_path)) { _dist_ijar_path = invoker.dist_ijar_path dist_jar("${_template_name}_dist_ijar") { override_build_config = _build_config output = _dist_ijar_path data = [ _dist_ijar_path ] use_interface_jars = true deps = [ ":$_build_config_target", ":$_java_target", ] } } if (_uses_static_library_synchronized_proguard) { _final_dex_target_dep = "${invoker.static_library_provider}__dexsplitter" } else if (_is_bundle_module && _proguard_enabled) { _final_deps += [ ":$_java_target" ] } else if (_incremental_apk) { if (defined(invoker.negative_main_dex_globs)) { not_needed(invoker, [ "negative_main_dex_globs" ]) } if (defined(invoker.disable_checkdiscard)) { not_needed(invoker, [ "disable_checkdiscard" ]) } if (defined(invoker.disable_r8_outlining)) { not_needed(invoker, [ "disable_r8_outlining" ]) } if (defined(invoker.negative_main_dex_globs)) { not_needed(invoker, [ "negative_main_dex_globs" ]) } if (defined(invoker.dexlayout_profile)) { not_needed(invoker, [ "dexlayout_profile" ]) } } else { # Dex generation for app bundle modules with proguarding enabled takes # place later due to synchronized proguarding. For more details, # read build/android/docs/android_app_bundles.md _final_dex_target_name = "${_template_name}__final_dex" dex(_final_dex_target_name) { forward_variables_from(invoker, [ "disable_checkdiscard", "disable_r8_outlining", "dexlayout_profile", ]) min_sdk_version = _min_sdk_version proguard_enabled = _proguard_enabled build_config = _build_config deps = [ ":$_build_config_target", ":$_java_target", ] if (_proguard_enabled) { deps += _deps + [ ":$_compile_resources_target" ] proguard_mapping_path = _proguard_mapping_path proguard_sourcefile_suffix = "$android_channel-$_version_code" has_apk_under_test = defined(invoker.apk_under_test) } else if (_min_sdk_version >= default_min_sdk_version) { # Enable dex merging only when min_sdk_version is >= what the library # .dex files were created with. input_dex_filearg = "@FileArg(${_rebased_build_config}:final_dex:all_dex_files)" if (_enable_main_dex_list) { if (defined(invoker.apk_under_test)) { main_dex_list_input_classes_filearg = "@FileArg(${_rebased_build_config}:deps_info:device_classpath_extended)" } else { main_dex_list_input_classes_filearg = "@FileArg(${_rebased_build_config}:deps_info:device_classpath)" } } } else { input_classes_filearg = "@FileArg($_rebased_build_config:deps_info:device_classpath)" } if (_is_static_library_provider) { # The list of input jars is already recorded in the .build_config, but # we need to explicitly add the java deps here to ensure they're # available to be used as inputs to the dex step. foreach(_dep, invoker.static_library_dependent_targets) { _target_label = get_label_info(_dep.name, "label_no_toolchain") deps += [ "${_target_label}__java" ] } output = _static_library_sync_dex_path is_static_library = true } else { output = _final_dex_path } enable_multidex = _enable_multidex if (_enable_main_dex_list) { forward_variables_from(invoker, [ "negative_main_dex_globs" ]) extra_main_dex_proguard_config = _generated_proguard_main_dex_config deps += [ ":$_compile_resources_target" ] } else if (_enable_multidex && defined(invoker.negative_main_dex_globs)) { not_needed(invoker, [ "negative_main_dex_globs" ]) } } _final_dex_target_dep = ":$_final_dex_target_name" # For static libraries, a single Proguard run is performed that includes # code from the static library APK and the APKs that use the static # library (done via. classpath merging in write_build_config.py). # This dexsplitter target splits the synchronized dex output into dex # files for each APK/Bundle. In the Bundle case, another dexsplitter step # is later performed to split the dex further for each feature module. if (_is_static_library_provider && _proguard_enabled) { _static_library_modules = [] foreach(_target, invoker.static_library_dependent_targets) { _apk_as_module = _target.name _module_config_target = "${_apk_as_module}$build_config_target_suffix" _module_gen_dir = get_label_info(_apk_as_module, "target_gen_dir") _module_name = get_label_info(_apk_as_module, "name") _module_config = "$_module_gen_dir/$_module_name.build_config" _static_library_modules += [ { name = _module_name build_config = _module_config build_config_target = _module_config_target }, ] } _static_library_dexsplitter_target = "${_template_name}__dexsplitter" dexsplitter(_static_library_dexsplitter_target) { input_dex_zip = _static_library_sync_dex_path proguard_mapping = _proguard_mapping_path deps = [ ":$_build_config_target", "$_final_dex_target_dep", ] all_modules = [ { name = "base" build_config = _build_config build_config_target = ":$_build_config_target" }, ] + _static_library_modules feature_jars_args = [ "--feature-jars", "@FileArg($_rebased_build_config:deps_info:" + "static_library_dependent_classpath_configs:" + "$_rebased_build_config)", ] foreach(_module, _static_library_modules) { _rebased_module_config = rebase_path(_module.build_config, root_build_dir) feature_jars_args += [ "--feature-jars", "@FileArg($_rebased_build_config:deps_info:" + "static_library_dependent_classpath_configs:" + "$_rebased_module_config)", ] } } _final_deps += [ ":$_static_library_dexsplitter_target" ] _validate_dex_target = "${_template_name}__validate_dex" action_with_pydeps(_validate_dex_target) { depfile = "$target_gen_dir/$target_name.d" script = "//build/android/gyp/validate_static_library_dex_references.py" inputs = [ _build_config ] _stamp = "$target_gen_dir/$target_name.stamp" outputs = [ _stamp ] deps = [ ":$_build_config_target", ":$_static_library_dexsplitter_target", ] args = [ "--depfile", rebase_path(depfile, root_build_dir), "--stamp", rebase_path(_stamp, root_build_dir), "--static-library-dex", "@FileArg($_rebased_build_config:final_dex:path)", ] foreach(_module, _static_library_modules) { inputs += [ _module.build_config ] _rebased_config = rebase_path(_module.build_config, root_build_dir) deps += [ _module.build_config_target ] args += [ "--static-library-dependent-dex", "@FileArg($_rebased_config:final_dex:path)", ] } } # TODO(crbug.com/1032609): Switch to using R8's support for feature # aware ProGuard and get rid of "_validate_dex_target" or figure out # why some classes aren't properly being kept. # _final_deps += [ ":$_validate_dex_target" ] _final_dex_target_dep = ":$_static_library_dexsplitter_target" } } _all_native_libs_deps = _native_libs_deps + _secondary_abi_native_libs_deps if (_all_native_libs_deps != []) { _native_libs_filearg_dep = ":$_build_config_target" _all_native_libs_deps += [ _native_libs_filearg_dep ] if (!_is_bundle_module) { _native_libs_filearg = "@FileArg($_rebased_build_config:native:libraries)" } } if (_is_bundle_module) { _final_deps += [ ":$_merge_manifest_target", ":$_build_config_target", ":$_compile_resources_target", ] + _all_native_libs_deps if (defined(_final_dex_target_dep)) { not_needed([ "_final_dex_target_dep" ]) } } else { # Generate size-info/*.jar.info files. if (defined(invoker.name)) { # Create size info files for targets that care about size # (have proguard enabled). if (_proguard_enabled) { _size_info_target = "${target_name}__size_info" create_size_info_files(_size_info_target) { name = "${invoker.name}.apk" build_config = _build_config res_size_info_path = _res_size_info_path deps = _deps + [ ":$_build_config_target", ":$_compile_resources_target", ":$_java_target", ] } _final_deps += [ ":$_size_info_target" ] } else { not_needed(invoker, [ "name" ]) } } _keystore_path = android_keystore_path _keystore_name = android_keystore_name _keystore_password = android_keystore_password if (defined(invoker.keystore_path)) { _keystore_path = invoker.keystore_path _keystore_name = invoker.keystore_name _keystore_password = invoker.keystore_password } if (_incremental_apk) { _incremental_compiled_resources_path = "${_base_path}_incremental.ap_" _incremental_compile_resources_target_name = "${target_name}__compile_incremental_resources" action_with_pydeps(_incremental_compile_resources_target_name) { deps = [ ":$_build_config_target", ":$_compile_resources_target", ":$_merge_manifest_target", ] script = "//build/android/incremental_install/generate_android_manifest.py" inputs = [ _android_manifest, _build_config, _arsc_resources_path, ] outputs = [ _incremental_compiled_resources_path ] args = [ "--disable-isolated-processes", "--src-manifest", rebase_path(_android_manifest, root_build_dir), "--in-apk", rebase_path(_arsc_resources_path, root_build_dir), "--out-apk", rebase_path(_incremental_compiled_resources_path, root_build_dir), "--aapt2-path", rebase_path(android_sdk_tools_bundle_aapt2, root_build_dir), "--android-sdk-jars=@FileArg($_rebased_build_config:android:sdk_jars)", ] } } _create_apk_target = "${_template_name}__create" _final_deps += [ ":$_create_apk_target" ] package_apk("$_create_apk_target") { forward_variables_from(invoker, [ "expected_libs_and_assets", "expected_libs_and_assets_base", "native_lib_placeholders", "secondary_abi_loadable_modules", "secondary_native_lib_placeholders", "uncompress_dex", "uncompress_shared_libraries", "library_always_compress", "library_renames", ]) if (defined(expected_libs_and_assets)) { build_config_dep = ":$_build_config_target" top_target_name = _template_name } build_config = _build_config keystore_name = _keystore_name keystore_path = _keystore_path keystore_password = _keystore_password min_sdk_version = _min_sdk_version uncompress_shared_libraries = _uncompress_shared_libraries deps = _deps + [ ":$_build_config_target" ] if (!_proguard_enabled && enable_jdk_library_desugaring) { _all_jdk_libs = "//build/android:all_jdk_libs" deps += [ _all_jdk_libs ] jdk_libs_dex = get_label_info(_all_jdk_libs, "target_out_dir") + "/all_jdk_libs.l8.dex" } if (_incremental_apk) { _dex_target = "//build/android/incremental_install:apk_dex" deps += [ ":${_incremental_compile_resources_target_name}", _dex_target, ] dex_path = get_label_info(_dex_target, "target_out_dir") + "/apk.dex" # All native libraries are side-loaded, so use a placeholder to force # the proper bitness for the app. _has_native_libs = defined(_native_libs_filearg) || _loadable_modules != [] if (_has_native_libs && !defined(native_lib_placeholders)) { native_lib_placeholders = [ "libfix.crbug.384638.so" ] } packaged_resources_path = _incremental_compiled_resources_path output_apk_path = _incremental_apk_path } else { loadable_modules = _loadable_modules deps += _all_native_libs_deps + [ ":$_merge_manifest_target", ":$_compile_resources_target", ] if (defined(_final_dex_path)) { dex_path = _final_dex_path deps += [ _final_dex_target_dep ] } if (_optimize_resources) { packaged_resources_path = _optimized_arsc_resources_path } else { packaged_resources_path = _arsc_resources_path } if (defined(_native_libs_filearg)) { native_libs_filearg = _native_libs_filearg secondary_abi_native_libs_filearg = "@FileArg($_rebased_build_config:native:secondary_abi_libraries)" } output_apk_path = _final_apk_path } } } if (_incremental_apk) { _write_installer_json_rule_name = "${_template_name}__incremental_json" action_with_pydeps(_write_installer_json_rule_name) { script = "//build/android/incremental_install/write_installer_json.py" deps = [ ":$_build_config_target" ] + _all_native_libs_deps data = [ _incremental_install_json_path ] inputs = [ _build_config ] outputs = [ _incremental_install_json_path ] _rebased_incremental_apk_path = rebase_path(_incremental_apk_path, root_build_dir) _rebased_incremental_install_json_path = rebase_path(_incremental_install_json_path, root_build_dir) args = [ "--apk-path=$_rebased_incremental_apk_path", "--output-path=$_rebased_incremental_install_json_path", "--dex-file=@FileArg($_rebased_build_config:final_dex:all_dex_files)", ] if (_proguard_enabled) { args += [ "--show-proguard-warning" ] } if (defined(_native_libs_filearg)) { args += [ "--native-libs=$_native_libs_filearg" ] deps += [ _native_libs_filearg_dep ] } if (_loadable_modules != []) { _rebased_loadable_modules = rebase_path(_loadable_modules, root_build_dir) args += [ "--native-libs=$_rebased_loadable_modules" ] } if (_load_library_from_apk) { args += [ "--dont-even-try=Incremental builds do not work with load_library_from_apk. Try setting is_component_build=true in your GN args." ] } } _final_deps += [ ":$_java_target", ":$_write_installer_json_rule_name", ] } # Generate apk operation related script. if (!_is_bundle_module && (!defined(invoker.create_apk_script) || invoker.create_apk_script)) { if (_uses_static_library) { _install_artifacts_target = "${target_name}__install_artifacts" _install_artifacts_json = "${target_gen_dir}/${target_name}.install_artifacts" generated_file(_install_artifacts_target) { output_conversion = "json" deps = [ invoker.static_library_provider ] outputs = [ _install_artifacts_json ] data_keys = [ "install_artifacts" ] rebase = root_build_dir } } _apk_operations_target_name = "${target_name}__apk_operations" action_with_pydeps(_apk_operations_target_name) { _generated_script = "$root_build_dir/bin/${invoker.target_name}" script = "//build/android/gyp/create_apk_operations_script.py" outputs = [ _generated_script ] data_deps = [ "//tools/android/md5sum" ] args = [ "--script-output-path", rebase_path(_generated_script, root_build_dir), "--target-cpu=$target_cpu", ] if (defined(invoker.command_line_flags_file)) { args += [ "--command-line-flags-file", invoker.command_line_flags_file, ] } if (_incremental_apk) { args += [ "--incremental-install-json-path", rebase_path(_incremental_install_json_path, root_build_dir), ] } else { args += [ "--apk-path", rebase_path(_final_apk_path, root_build_dir), ] } if (_uses_static_library) { deps = [ ":$_install_artifacts_target" ] _rebased_install_artifacts_json = rebase_path(_install_artifacts_json, root_build_dir) _static_library_apk_path = "@FileArg($_rebased_install_artifacts_json[])" args += [ "--additional-apk", _static_library_apk_path, ] } if (!defined(data)) { data = [] } if (_proguard_enabled && !_incremental_apk) { # Required by logcat command. data_deps += [ "//build/android/stacktrace:java_deobfuscate" ] data += [ "$_final_apk_path.mapping" ] args += [ "--proguard-mapping-path", rebase_path("$_final_apk_path.mapping", root_build_dir), ] } } _final_deps += [ ":$_apk_operations_target_name" ] } _enable_lint = defined(invoker.enable_lint) && invoker.enable_lint && !disable_android_lint if (_enable_lint) { android_lint("${target_name}__lint") { forward_variables_from(invoker, [ "lint_baseline_file", "lint_suppressions_file", "min_sdk_version", ]) build_config = _build_config build_config_dep = ":$_build_config_target" deps = [ ":$_java_target" ] if (defined(invoker.lint_suppressions_dep)) { deps += [ invoker.lint_suppressions_dep ] } if (defined(invoker.lint_min_sdk_version)) { min_sdk_version = invoker.lint_min_sdk_version } } } else { not_needed(invoker, [ "lint_baseline_file", "lint_min_sdk_version", "lint_suppressions_dep", "lint_suppressions_file", ]) } group(target_name) { forward_variables_from(invoker, [ "assert_no_deps", "data", "data_deps", "metadata", ]) # Generate apk related operations at runtime. public_deps = _final_deps if (!defined(data_deps)) { data_deps = [] } # Include unstripped native libraries so tests can symbolize stacks. data_deps += _all_native_libs_deps if (_enable_lint) { data_deps += [ ":${target_name}__lint" ] } if (_incremental_apk) { # device/commands is used by the installer script to push files via .zip. data_deps += [ "//build/android/pylib/device/commands" ] } if (_uses_static_library) { data_deps += [ invoker.static_library_provider ] } } } # Declare an Android APK target # # This target creates an Android APK containing java code, resources, assets, # and (possibly) native libraries. # # Supports all variables of android_apk_or_module(), plus: # apk_name: Name for final apk. # final_apk_path: (Optional) path to output APK. # # Example # android_apk("foo_apk") { # android_manifest = "AndroidManifest.xml" # sources = [ # "android/org/chromium/foo/FooApplication.java", # "android/org/chromium/foo/FooActivity.java", # ] # deps = [ # ":foo_support_java" # ":foo_resources" # ] # srcjar_deps = [ # ":foo_generated_enum" # ] # shared_libraries = [ # ":my_shared_lib", # ] # } template("android_apk") { # TODO(crbug.com/1042017): Remove. not_needed(invoker, [ "no_build_hooks" ]) android_apk_or_module(target_name) { forward_variables_from(invoker, [ "aapt_locale_allowlist", "additional_jar_files", "alternative_android_sdk_dep", "android_manifest", "android_manifest_dep", "annotation_processor_deps", "apk_under_test", "app_as_shared_lib", "assert_no_deps", "bundles_supported", "chromium_code", "command_line_flags_file", "create_apk_script", "data", "data_deps", "deps", "dexlayout_profile", "disable_checkdiscard", "disable_r8_outlining", "dist_ijar_path", "enable_lint", "enable_jetify", "enable_multidex", "enable_native_mocks", "enforce_resource_overlays", "expected_android_manifest", "expected_android_manifest_base", "expected_libs_and_assets", "expected_libs_and_assets_base", "generate_buildconfig_java", "generate_final_jni", "input_jars_paths", "use_modern_linker", "jacoco_never_instrument", "javac_args", "jni_registration_header", "jni_sources_exclusions", "keystore_name", "keystore_password", "keystore_path", "lint_baseline_file", "lint_min_sdk_version", "lint_suppressions_dep", "lint_suppressions_file", "load_library_from_apk", "loadable_modules", "manifest_package", "max_sdk_version", "product_config_java_packages", "main_component_library", "min_sdk_version", "native_lib_placeholders", "native_lib_version_arg", "native_lib_version_rule", "negative_main_dex_globs", "never_incremental", "no_xml_namespaces", "png_to_webp", "post_process_package_resources_script", "processor_args_javac", "product_version_resources_dep", "proguard_configs", "proguard_enabled", "r_java_root_package_name", "resource_exclusion_exceptions", "resource_exclusion_regex", "resource_ids_provider_dep", "resource_values_filter_rules", "resources_config_paths", "require_native_mocks", "secondary_abi_loadable_modules", "secondary_abi_shared_libraries", "secondary_native_lib_placeholders", "shared_libraries", "shared_resources", "shared_resources_allowlist_locales", "shared_resources_allowlist_target", "short_resource_paths", "sources", "srcjar_deps", "static_library_dependent_targets", "static_library_provider", "static_library_synchronized_proguard", "strip_resource_names", "support_zh_hk", "target_sdk_version", "testonly", "uncompress_dex", "uncompress_shared_libraries", "library_always_compress", "library_renames", "use_chromium_linker", "version_code", "version_name", ]) is_bundle_module = false name = invoker.apk_name if (defined(invoker.final_apk_path)) { final_apk_path = invoker.final_apk_path } else { final_apk_path = "$root_build_dir/apks/${invoker.apk_name}.apk" } metadata = { install_artifacts = [ final_apk_path ] } if (defined(invoker.static_library_provider)) { metadata.install_artifacts_barrier = [] } } } # Declare an Android app bundle module target. # # The module can be used for an android_apk_or_module(). # # Supports all variables of android_library(), plus: # module_name: Name of the module. # is_base_module: If defined and true, indicates that this is the bundle's # base module (optional). # base_module_target: Base module target of the bundle this module will be # added to (optional). Can only be specified for non-base modules. # bundle_target: Bundle target that this module belongs to (optional). # Can only be specified for base modules. template("android_app_bundle_module") { _is_base_module = defined(invoker.is_base_module) && invoker.is_base_module if (_is_base_module) { assert(!defined(invoker.base_module_target)) } else { assert(!defined(invoker.app_as_shared_lib)) assert(!defined(invoker.shared_resources)) assert(!defined(invoker.shared_resources_allowlist_target)) assert(!defined(invoker.shared_resources_allowlist_locales)) assert(defined(invoker.base_module_target)) assert(!defined(invoker.bundle_target)) } # TODO(tiborg): We have several flags that are necessary for workarounds # that come from the fact that the resources get compiled in the bundle # module target, but bundle modules have to have certain flags in # common or bundle modules have to know information about the base module. # Those flags include version_code, version_name, and base_module_target. # It would be better to move the resource compile target into the bundle # target. Doing so would keep the bundle modules independent from the bundle # and potentially reuse the same bundle modules for multiple bundles. android_apk_or_module(target_name) { forward_variables_from(invoker, [ "aapt_locale_allowlist", "additional_jar_files", "alternative_android_sdk_dep", "android_manifest", "android_manifest_dep", "annotation_processor_deps", "app_as_shared_lib", "assert_no_deps", "base_module_target", "bundle_target", "chromium_code", "data", "data_deps", "deps", "enable_multidex", "enforce_resource_overlays", "expected_android_manifest", "expected_android_manifest_base", "generate_buildconfig_java", "generate_final_jni", "input_jars_paths", "is_base_module", "jacoco_never_instrument", "javac_args", "jni_registration_header", "jni_sources_exclusions", "load_library_from_apk", "loadable_modules", "product_config_java_packages", "manifest_package", "max_sdk_version", "min_sdk_version", "native_lib_placeholders", "native_lib_version_arg", "native_lib_version_rule", "negative_main_dex_globs", "no_xml_namespaces", "package_id", "package_name", "png_to_webp", "processor_args_javac", "product_version_resources_dep", "proguard_configs", "proguard_enabled", "resource_exclusion_exceptions", "resource_exclusion_regex", "resource_ids_provider_dep", "resource_values_filter_rules", "resources_config_paths", "secondary_abi_loadable_modules", "secondary_abi_shared_libraries", "secondary_native_lib_placeholders", "shared_libraries", "shared_resources", "shared_resources_allowlist_locales", "shared_resources_allowlist_target", "short_resource_paths", "srcjar_deps", "static_library_provider", "static_library_synchronized_proguard", "strip_resource_names", "support_zh_hk", "target_sdk_version", "testonly", "uncompress_shared_libraries", "library_always_compress", "library_renames", "use_chromium_linker", "use_modern_linker", "version_code", "version_name", ]) is_bundle_module = true generate_buildconfig_java = _is_base_module } } # Declare an Android instrumentation test runner. # # This target creates a wrapper script to run Android instrumentation tests. # # Arguments: # android_test_apk: The target containing the tests. # android_test_apk_name: The apk_name in android_test_apk # # The following args are optional: # apk_under_test: The target being tested. # additional_apks: Additional targets to install on device. # data: List of runtime data file dependencies. # data_deps: List of non-linked dependencies. # deps: List of private dependencies. # extra_args: Extra arguments set for test runner. # ignore_all_data_deps: Don't build data_deps and additional_apks. # modules: Extra dynamic feature modules to install for test target. Can # only be used if |apk_under_test| is an Android app bundle. # fake_modules: Similar to |modules| but fake installed instead. # never_incremental: Disable incremental builds. # proguard_enabled: Enable proguard # public_deps: List of public dependencies # # Example # instrumentation_test_runner("foo_test_for_bar") { # android_test_apk: ":foo" # android_test_apk_name: "Foo" # apk_under_test: ":bar" # } template("instrumentation_test_runner") { test_runner_script(target_name) { forward_variables_from(invoker, [ "additional_apks", "additional_locales", "apk_under_test", "data", "data_deps", "deps", "extra_args", "fake_modules", "ignore_all_data_deps", "modules", "proguard_enabled", "public_deps", "use_webview_provider", ]) test_name = invoker.target_name test_type = "instrumentation" _apk_target_name = get_label_info(invoker.android_test_apk, "name") apk_target = ":$_apk_target_name" test_jar = "$root_build_dir/test.lib.java/" + invoker.android_test_apk_name + ".jar" incremental_apk = !(defined(invoker.never_incremental) && invoker.never_incremental) && incremental_install public_deps = [ ":$_apk_target_name", # Required by test runner to enumerate test list. ":${_apk_target_name}_dist_ijar", ] if (defined(invoker.apk_under_test)) { public_deps += [ invoker.apk_under_test ] } if (defined(invoker.additional_apks)) { public_deps += invoker.additional_apks } } } # Declare an Android instrumentation test apk # # This target creates an Android instrumentation test apk. # # Supports all variables of android_apk(), plus: # apk_under_test: The apk being tested (optional). # # Example # android_test_apk("foo_test_apk") { # android_manifest = "AndroidManifest.xml" # apk_name = "FooTest" # apk_under_test = "Foo" # sources = [ # "android/org/chromium/foo/FooTestCase.java", # "android/org/chromium/foo/FooExampleTest.java", # ] # deps = [ # ":foo_test_support_java" # ] # } template("android_test_apk") { android_apk(target_name) { testonly = true deps = [ "//testing/android/broker:broker_java" ] if (defined(invoker.deps)) { deps += invoker.deps } data_deps = [ # Ensure unstripped libraries are included in runtime deps so that # symbolization can be done. ":${target_name}__secondary_abi_shared_library_list", ":${target_name}__shared_library_list", "//build/android/pylib/device/commands", "//tools/android/forwarder2", ] if (defined(invoker.data_deps)) { data_deps += invoker.data_deps } if (defined(invoker.apk_under_test)) { data_deps += [ invoker.apk_under_test ] } else { enable_native_mocks = true } if (defined(invoker.apk_under_test)) { _under_test_label = get_label_info(invoker.apk_under_test, "label_no_toolchain") data_deps += [ "${_under_test_label}__secondary_abi_shared_library_list", "${_under_test_label}__shared_library_list", ] } if (defined(invoker.additional_apks)) { data_deps += invoker.additional_apks } if (defined(invoker.use_webview_provider)) { data_deps += [ invoker.use_webview_provider ] } data = [] if (defined(invoker.data)) { data += invoker.data } if (defined(invoker.proguard_enabled) && invoker.proguard_enabled && !incremental_install) { # When ProGuard is on, we use ProGuard to combine the under test java # code and the test java code. This is to allow us to apply all ProGuard # optimizations that we ship with, but not have them break tests. The # apk under test will still have the same resources, assets, and # manifest, all of which are the ones used in the tests. proguard_configs = [ "//testing/android/proguard_for_test.flags" ] if (defined(invoker.proguard_configs)) { proguard_configs += invoker.proguard_configs } disable_checkdiscard = true if (defined(invoker.final_apk_path)) { _final_apk_path = final_apk_path } else { _final_apk_path = "$root_build_dir/apks/${invoker.apk_name}.apk" } data += [ "$_final_apk_path.mapping" ] } dist_ijar_path = "$root_build_dir/test.lib.java/${invoker.apk_name}.jar" create_apk_script = false forward_variables_from(invoker, "*", [ "data", "data_deps", "deps", "proguard_configs", ]) } } # Declare an Android instrumentation test apk with wrapper script. # # This target creates an Android instrumentation test apk with wrapper script # to run the test. # # Supports all variables of android_test_apk. template("instrumentation_test_apk") { assert(defined(invoker.apk_name)) _apk_target_name = "${target_name}__test_apk" android_test_apk(_apk_target_name) { forward_variables_from(invoker, "*") } instrumentation_test_runner(target_name) { forward_variables_from(invoker, [ "additional_apks", "apk_under_test", "data", "data_deps", "deps", "extra_args", "ignore_all_data_deps", "modules", "never_incremental", "proguard_enabled", "public_deps", "use_webview_provider", ]) android_test_apk = ":${_apk_target_name}" android_test_apk_name = invoker.apk_name } } # Declare an Android gtest apk # # This target creates an Android apk for running gtest-based unittests. # # Variables # deps: Specifies the dependencies of this target. These will be passed to # the underlying android_apk invocation and should include the java and # resource dependencies of the apk. # shared_library: shared_library target that contains the unit tests. # apk_name: The name of the produced apk. If unspecified, it uses the name # of the shared_library target suffixed with "_apk" # use_default_launcher: Whether the default activity (NativeUnitTestActivity) # should be used for launching tests. # use_native_activity: Test implements ANativeActivity_onCreate(). # # Example # unittest_apk("foo_unittests_apk") { # deps = [ ":foo_java", ":foo_resources" ] # shared_library = ":foo_unittests" # } template("unittest_apk") { _use_native_activity = defined(invoker.use_native_activity) && invoker.use_native_activity _android_manifest = "$target_gen_dir/$target_name/AndroidManifest.xml" assert(invoker.shared_library != "") # This trivial assert is needed in case android_manifest is defined, # as otherwise _use_native_activity and _android_manifest would not be used. assert(_use_native_activity != "" && _android_manifest != "") if (!defined(invoker.android_manifest)) { jinja_template("${target_name}_manifest") { _native_library_name = get_label_info(invoker.shared_library, "name") input = "//testing/android/native_test/java/AndroidManifest.xml.jinja2" output = _android_manifest variables = [ "is_component_build=${is_component_build}", "native_library_name=${_native_library_name}", "use_native_activity=${_use_native_activity}", ] } } android_apk(target_name) { data_deps = [] forward_variables_from(invoker, "*") testonly = true create_apk_script = false enable_native_mocks = true # TODO(crbug.com/1099849): Figure out why angle tests fail to launch # with newer target_sdk_version. if (!defined(invoker.target_sdk_version) && _use_native_activity) { target_sdk_version = 24 } assert(!defined(invoker.proguard_enabled) || !invoker.proguard_enabled || invoker.proguard_configs != []) if (!defined(apk_name)) { apk_name = get_label_info(invoker.shared_library, "name") } if (!defined(android_manifest)) { android_manifest_dep = ":${target_name}_manifest" android_manifest = _android_manifest } final_apk_path = "$root_build_dir/${apk_name}_apk/${apk_name}-debug.apk" if (!defined(use_default_launcher) || use_default_launcher) { deps += [ "//testing/android/native_test:native_test_java" ] } shared_libraries = [ invoker.shared_library ] deps += [ ":${target_name}__secondary_abi_shared_library_list", ":${target_name}__shared_library_list", "//base:base_java", "//testing/android/reporter:reporter_java", ] data_deps += [ "//build/android/pylib/device/commands" ] if (host_os == "linux") { data_deps += [ "//tools/android/forwarder2" ] } } } # Generate .java files from .aidl files. # # This target will store the .java files in a srcjar and should be included in # an android_library or android_apk's srcjar_deps. # # Variables # sources: Paths to .aidl files to compile. # import_include: Path to directory containing .java files imported by the # .aidl files. # interface_file: Preprocessed aidl file to import. # # Example # android_aidl("foo_aidl") { # import_include = "java/src" # sources = [ # "java/src/com/foo/bar/FooBarService.aidl", # "java/src/com/foo/bar/FooBarServiceCallback.aidl", # ] # } template("android_aidl") { action_with_pydeps(target_name) { set_sources_assignment_filter([]) forward_variables_from(invoker, [ "testonly" ]) script = "//build/android/gyp/aidl.py" sources = invoker.sources _srcjar_path = "${target_gen_dir}/${target_name}.srcjar" _aidl_path = "${android_sdk_build_tools}/aidl" _framework_aidl = "$android_sdk/framework.aidl" _imports = [ _framework_aidl ] if (defined(invoker.interface_file)) { assert(invoker.interface_file != "") _imports += [ invoker.interface_file ] } inputs = [ _aidl_path ] + _imports outputs = [ _srcjar_path ] _rebased_imports = rebase_path(_imports, root_build_dir) args = [ "--aidl-path", rebase_path(_aidl_path, root_build_dir), "--imports=$_rebased_imports", "--srcjar", rebase_path(_srcjar_path, root_build_dir), ] if (defined(invoker.import_include) && invoker.import_include != []) { # TODO(cjhopman): aidl supports creating a depfile. We should be able to # switch to constructing a depfile for the overall action from that # instead of having all the .java files in the include paths as inputs. _rebased_import_paths = [] foreach(_import_path, invoker.import_include) { _rebased_import_path = [] _rebased_import_path = [ rebase_path(_import_path, root_build_dir) ] _rebased_import_paths += _rebased_import_path _java_files_build_rel = [] _java_files_build_rel = exec_script("//build/android/gyp/find.py", [ "--pattern=*.java" ] + _rebased_import_path, "list lines") inputs += rebase_path(_java_files_build_rel, ".", root_build_dir) } args += [ "--includes=$_rebased_import_paths" ] } args += rebase_path(sources, root_build_dir) } } # Compile a protocol buffer to java. # # This generates java files from protocol buffers and creates an Android library # containing the classes. # # Variables # sources (required) # Paths to .proto files to compile. # # proto_path (required) # Root directory of .proto files. # # deps (optional) # Additional dependencies. Passed through to both the action and the # android_library targets. # # import_dirs (optional) # A list of extra import directories to be passed to protoc compiler. # WARNING: This circumvents proto checkdeps, and should only be used # when needed, typically when proto files cannot cleanly import through # absolute paths, such as for third_party or generated .proto files. # http://crbug.com/691451 tracks fixing this. # # Example: # proto_java_library("foo_proto_java") { # proto_path = "src/foo" # sources = [ "$proto_path/foo.proto" ] # } template("proto_java_library") { set_sources_assignment_filter([]) forward_variables_from(invoker, [ "testonly" ]) _template_name = target_name action_with_pydeps("${_template_name}__protoc_java") { # The suffix "__protoc_java.srcjar" is used by SuperSize to identify # protobuf symbols. _srcjar_path = "$target_gen_dir/$target_name.srcjar" script = "//build/protoc_java.py" deps = [] if (defined(invoker.deps)) { deps += invoker.deps } sources = invoker.sources depfile = "$target_gen_dir/$target_name.d" outputs = [ _srcjar_path ] args = [ "--depfile", rebase_path(depfile, root_build_dir), "--protoc", rebase_path(android_protoc_bin, root_build_dir), "--proto-path", rebase_path(invoker.proto_path, root_build_dir), "--srcjar", rebase_path(_srcjar_path, root_build_dir), ] + rebase_path(sources, root_build_dir) if (defined(invoker.import_dirs)) { foreach(_import_dir, invoker.import_dirs) { args += [ "--import-dir", rebase_path(_import_dir, root_build_dir), ] } } } android_library(target_name) { chromium_code = false sources = [] srcjar_deps = [ ":${_template_name}__protoc_java" ] deps = [ "//third_party/android_deps:protobuf_lite_runtime_java" ] if (defined(invoker.deps)) { deps += invoker.deps } } } # Declare an Android library target for a prebuilt AAR. # # This target creates an Android library containing java code and Android # resources. For libraries without resources, it will not generate # corresponding android_resources targets. # # To avoid slowing down "gn gen", an associated .info file must be committed # along with the .aar file. In order to create this file, define the target # and then run once with the gn arg "update_android_aar_prebuilts = true". # # Variables # aar_path: Path to the AAR. # info_path: Path to the .aar.info file (generated via # update_android_aar_prebuilts GN arg). # proguard_configs: List of proguard configs to use in final apk step for # any apk that depends on this library. # ignore_aidl: Whether to ignore .aidl files found with the .aar. # ignore_assets: Whether to ignore assets found in the .aar. # ignore_manifest: Whether to ignore creating manifest. # ignore_native_libraries: Whether to ignore .so files found in the .aar. # See also extract_native_libraries. # ignore_proguard_configs: Whether to ignore proguard configs. # ignore_info_updates: Whether to ignore the info file when # update_android_aar_prebuilts gn arg is true. However, the info file # will still be verified regardless of the value of this flag. # strip_resources: Whether to ignore android resources found in the .aar. # custom_package: Java package for generated R.java files. # extract_native_libraries: Whether to extract .so files found in the .aar. # If the file contains .so, either extract_native_libraries or # ignore_native_libraries must be set. # create_srcjar: If false, does not create an R.java file. # TODO(jbudorick@): remove this arguments after crbug.com/522043 is fixed. # requires_android: Whether this target can only be used for compiling # Android related targets. # # Example # android_aar_prebuilt("foo_java") { # aar_path = "foo.aar" # } template("android_aar_prebuilt") { _info_path = "$target_name.info" if (defined(invoker.info_path)) { _info_path = invoker.info_path } _output_path = "${target_out_dir}/${target_name}" _target_name_without_java_or_junit = string_replace(string_replace(target_name, "_java", ""), "_junit", "") # This unpack target is a python action, not a valid java target. Since the # java targets below depend on it, its name must not match the java patterns # in internal_rules.gni. _unpack_target_name = "${_target_name_without_java_or_junit}__unpack_aar" _ignore_aidl = defined(invoker.ignore_aidl) && invoker.ignore_aidl _ignore_assets = defined(invoker.ignore_assets) && invoker.ignore_assets _ignore_manifest = defined(invoker.ignore_manifest) && invoker.ignore_manifest _ignore_native_libraries = defined(invoker.ignore_native_libraries) && invoker.ignore_native_libraries _ignore_proguard_configs = defined(invoker.ignore_proguard_configs) && invoker.ignore_proguard_configs _extract_native_libraries = defined(invoker.extract_native_libraries) && invoker.extract_native_libraries _strip_resources = defined(invoker.strip_resources) && invoker.strip_resources # Allow 'resource_overlay' parameter even if there are no resources in order # to keep the logic for generated 'android_aar_prebuilt' rules simple. not_needed(invoker, [ "resource_overlay" ]) _ignore_info_updates = defined(invoker.ignore_info_updates) && invoker.ignore_info_updates # Scan the AAR file and determine the resources and jar files. # Some libraries might not have resources; others might have two jars. if (!_ignore_info_updates && update_android_aar_prebuilts) { print("Writing " + rebase_path(_info_path, "//")) exec_script("//build/android/gyp/aar.py", [ "list", rebase_path(invoker.aar_path, root_build_dir), "--output", rebase_path(_info_path, root_build_dir), ]) } # If "gn gen" is failing on the following line, you need to generate an # .info file for your new target by running: # gn gen --args='target_os="android" update_android_aar_prebuilts=true' out/tmp # rm -r out/tmp _scanned_files = read_file(_info_path, "scope") _use_scanned_assets = !_ignore_assets && _scanned_files.assets != [] assert(_ignore_aidl || _scanned_files.aidl == [], "android_aar_prebuilt() aidl not yet supported." + " Implement or use ignore_aidl = true." + " http://crbug.com/644439") assert( !_scanned_files.has_native_libraries || (_ignore_native_libraries || _extract_native_libraries), "android_aar_prebuilt() contains .so files." + " Please set ignore_native_libraries or extract_native_libraries.") assert( !(_ignore_native_libraries && _extract_native_libraries), "ignore_native_libraries and extract_native_libraries cannot both be set.") assert(!_scanned_files.has_native_libraries || _scanned_files.native_libraries != []) assert(_scanned_files.has_classes_jar || _scanned_files.subjars == []) action_with_pydeps(_unpack_target_name) { script = "//build/android/gyp/aar.py" # Unzips the AAR args = [ "extract", rebase_path(invoker.aar_path, root_build_dir), "--output-dir", rebase_path(_output_path, root_build_dir), "--assert-info-file", rebase_path(_info_path, root_build_dir), ] if (_strip_resources) { args += [ "--ignore-resources" ] } inputs = [ invoker.aar_path ] outputs = [] if (!_ignore_manifest) { outputs += [ "${_output_path}/AndroidManifest.xml" ] } if (!_strip_resources && _scanned_files.has_r_text_file) { # Certain packages, in particular Play Services have no R.txt even # though its presence is mandated by AAR spec. Such packages cause # spurious rebuilds if this output is specified unconditionally. outputs += [ "${_output_path}/R.txt" ] } if (!_strip_resources && _scanned_files.resources != []) { outputs += get_path_info( rebase_path(_scanned_files.resources, "", _output_path), "abspath") } if (_scanned_files.has_classes_jar) { outputs += [ "${_output_path}/classes.jar" ] } outputs += get_path_info(rebase_path(_scanned_files.subjars, "", _output_path), "abspath") if (!_ignore_proguard_configs) { if (_scanned_files.has_proguard_flags) { outputs += [ "${_output_path}/proguard.txt" ] } if (defined(_scanned_files.has_proguard_check_flags) && _scanned_files.has_proguard_check_flags) { outputs += [ "${_output_path}/proguard-checks.txt" ] } } if (_extract_native_libraries && _scanned_files.has_native_libraries) { outputs += get_path_info( rebase_path(_scanned_files.native_libraries, "", _output_path), "abspath") } if (_use_scanned_assets) { outputs += get_path_info(rebase_path(_scanned_files.assets, "", _output_path), "abspath") } } _has_unignored_resources = !_strip_resources && (_scanned_files.resources != [] || _scanned_files.has_r_text_file) _should_process_manifest = !_ignore_manifest && !_scanned_files.is_manifest_empty # Create the android_resources target for resources. if (_has_unignored_resources || _should_process_manifest) { _res_target_name = "${target_name}__resources" android_resources(_res_target_name) { forward_variables_from(invoker, [ "custom_package", "create_srcjar", "deps", "resource_overlay", "testonly", "strip_drawables", ]) if (!defined(deps)) { deps = [] } deps += [ ":$_unpack_target_name" ] if (_should_process_manifest) { android_manifest_dep = ":$_unpack_target_name" android_manifest = "${_output_path}/AndroidManifest.xml" } else if (defined(_scanned_files.manifest_package) && !defined(custom_package)) { custom_package = _scanned_files.manifest_package } sources = [] if (!_strip_resources) { sources = rebase_path(_scanned_files.resources, "", _output_path) } if (!_strip_resources && _scanned_files.has_r_text_file) { r_text_file = "${_output_path}/R.txt" } # This is so we do not fail when different prebuilts have resources in # the same package. android_library targets that require resources from # prebuilts must add a resources_package gn flag to their target that # would generate a fake R.java for all their dependencies. All # android_library and android_resources targets will be migrated to # this new way soon (tm) https://crbug.com/1073476 create_srcjar = false } } else if (defined(invoker.strip_drawables)) { not_needed(invoker, [ "strip_drawables" ]) } # Create the android_assets target for assets if (_use_scanned_assets) { _assets_target_name = "${target_name}__assets" android_assets(_assets_target_name) { forward_variables_from(invoker, [ "testonly" ]) renaming_sources = [] renaming_destinations = [] foreach(_asset_file, _scanned_files.assets) { _original_path = get_path_info(rebase_path(_asset_file, "", _output_path), "abspath") _updated_path = string_replace(_asset_file, "assets/", "", 1) renaming_sources += [ _original_path ] renaming_destinations += [ _updated_path ] } } } # Create android_java_prebuilt target for classes.jar. if (_scanned_files.has_classes_jar) { _java_library_vars = [ "enable_bytecode_checks", "enable_jetify", "jar_excluded_patterns", "jar_included_patterns", "missing_classes_allowlist", "requires_android", "testonly", ] # Create android_java_prebuilt target for extra jars within jars/. _subjar_targets = [] foreach(_tuple, _scanned_files.subjar_tuples) { _current_target = "${target_name}__subjar_${_tuple[0]}" _subjar_targets += [ ":$_current_target" ] java_prebuilt(_current_target) { forward_variables_from(invoker, _java_library_vars) deps = [ ":$_unpack_target_name" ] if (!defined(requires_android)) { requires_android = true } supports_android = true jar_path = "$_output_path/${_tuple[1]}" _base_output_name = get_path_info(jar_path, "name") output_name = "${invoker.target_name}-$_base_output_name" public_target_label = invoker.target_name } } _jar_target_name = "${target_name}__classes" java_prebuilt(_jar_target_name) { forward_variables_from(invoker, _java_library_vars) forward_variables_from(invoker, [ "deps", "input_jars_paths", "proguard_configs", ]) if (!defined(deps)) { deps = [] } deps += _subjar_targets + [ ":$_unpack_target_name" ] if (defined(_res_target_name)) { deps += [ ":$_res_target_name" ] } if (!defined(requires_android)) { requires_android = true } supports_android = true jar_path = "$_output_path/classes.jar" output_name = invoker.target_name if (!_ignore_proguard_configs) { if (!defined(proguard_configs)) { proguard_configs = [] } if (_scanned_files.has_proguard_flags) { proguard_configs += [ "$_output_path/proguard.txt" ] } if (defined(_scanned_files.has_proguard_check_flags) && _scanned_files.has_proguard_check_flags) { proguard_configs += [ "$_output_path/proguard-checks.txt" ] } } public_target_label = invoker.target_name } } java_group(target_name) { forward_variables_from(invoker, [ "testonly", "visibility", ]) public_deps = [ ":$_unpack_target_name" ] deps = [] if (defined(_jar_target_name)) { deps += [ ":$_jar_target_name" ] # Although subjars are meant to be private, we add them as deps here # because in practice they seem to contain classes required to be in the # classpath. deps += _subjar_targets } if (defined(_res_target_name)) { deps += [ ":$_res_target_name" ] } if (defined(_assets_target_name)) { deps += [ ":$_assets_target_name" ] } } } # Create an Android application bundle from one base android_apk target, # and zero or more associated android_apk. # # Variables: # base_module_target: Name of the android_app_bundle_module target # corresponding to the base module for this application bundle. The # bundle file will include the same content in its base module, though in # a slightly different format. # # bundle_base_path: Optional. If set, the bundle will be output to this # directory. Defaults to "$root_build_dir/apks". # # bundle_name: Optional. If set, the bundle will be output to the # filename "${bundle_name}.aab". # # extra_modules: Optional list of scopes, one per extra module used by # this bundle. Each scope must have a 'name' field that specifies the # module name (which cannot be 'base', since this is reserved for the # base module), and an 'apk_target' field that specified the # corresponding android_apk target name the module is modeled on. # # enable_language_splits: Optional. If true, enable APK splits based # on languages. # # sign_bundle: Optional. If true, sign the bundle. Default is false # because signing is very slow, and there is no reason to do it # unless one wants to upload the bundle to the Play Store (e.g. # for official builds). # # keystore_path: optional keystore path, used only when generating APKs. # keystore_name: optional keystore name, used only when generating APKs. # keystore_password: optional keystore password, used only when # generating APKs. # # command_line_flags_file: Optional. If provided, named of the on-device # file that will be used to store command-line arguments. The default # is 'command_line_flags_file', but this is typically redefined to # something more specific for certain bundles (e.g. the Chromium based # APKs use 'chrome-command-line', the WebView one uses # 'webview-command-line'). # # proguard_enabled: Optional. True if proguarding is enabled for this # bundle. Default is to enable this only for release builds. Note that # this will always perform synchronized proguarding. # # enable_multidex: Optional. Enable multidexing of optimized modules jars # when using synchronized proguarding. Only applies to base module. # # proguard_android_sdk_dep: Optional. android_system_java_prebuilt() target # used as a library jar for synchronized proguarding. # # compress_shared_libraries: Optional. Whether to compress shared libraries # such that they are extracted upon install. Libraries prefixed with # "crazy." are never compressed. # # system_image_locale_allowlist: List of locales that should be included # on system APKs generated from this bundle. # # static_library_provider: Specifies a single target that this target will # use as a static library APK. # Additionally, when allotting libraries to be packaged into modules, the # libraries packaged into the static library will be accounted for to # avoid library duplication. Effectively, the static library will be # treated as the parent of the base module. # # expected_libs_and_assets: Verify the list of included native libraries # and assets is consistent with the given expectation file. # expected_libs_and_assets_base: Treat expected_libs_and_assets as a diff # with this file as the base. # expected_proguard_config: Checks that the merged set of proguard flags # matches the given config. # expected_proguard_config_base: Treat expected_proguard_config as a diff # with this file as the base. # # version_code: Optional. Version code of the target. # # is_multi_abi: If true will add a library placeholder for the missing ABI # if either the primary or the secondary ABI has no native libraries set. # # default_modules_for_testing: (optional): A list of DFM that the wrapper # script should install. This is for local testing only, and does not # affect the actual DFM in production. # Example: # android_app_bundle("chrome_public_bundle") { # base_module_target = "//chrome/android:chrome_public_apk" # extra_modules = [ # { # NOTE: Scopes require one field per line, and no comma separators. # name = "my_module" # module_target = ":my_module" # }, # ] # } # template("android_app_bundle") { _target_name = target_name _uses_static_library = defined(invoker.static_library_provider) _proguard_enabled = defined(invoker.proguard_enabled) && invoker.proguard_enabled if (defined(invoker.version_code)) { _version_code = invoker.version_code } else { _version_code = android_default_version_code } if (android_override_version_code != "") { _version_code = android_override_version_code } # Prevent "unused variable". not_needed([ "_version_code" ]) _bundle_base_path = "$root_build_dir/apks" if (defined(invoker.bundle_base_path)) { _bundle_base_path = invoker.bundle_base_path } _bundle_name = _target_name if (defined(invoker.bundle_name)) { _bundle_name = invoker.bundle_name } _bundle_path = "$_bundle_base_path/${_bundle_name}.aab" _rebased_bundle_path = rebase_path(_bundle_path, root_build_dir) _base_target_name = get_label_info(invoker.base_module_target, "name") _base_target_gen_dir = get_label_info(invoker.base_module_target, "target_gen_dir") _base_module_build_config = "$_base_target_gen_dir/${_base_target_name}.build_config" _base_module_build_config_target = "${invoker.base_module_target}$build_config_target_suffix" _rebased_base_module_build_config = rebase_path(_base_module_build_config, root_build_dir) _modules = [ { name = "base" module_target = invoker.base_module_target build_config = _base_module_build_config build_config_target = _base_module_build_config_target if (_uses_static_library) { parent = "lib" } }, ] _enable_multidex = !defined(invoker.enable_multidex) || invoker.enable_multidex if (!_proguard_enabled && defined(invoker.min_sdk_version)) { not_needed(invoker, [ "min_sdk_version" ]) } # Prevent "unused variable". not_needed([ "_enable_multidex" ]) if (_proguard_enabled) { _uses_static_library_synchronized_proguard = defined(invoker.static_library_synchronized_proguard) && invoker.static_library_synchronized_proguard # TODO(crbug.com/1032609): Remove dexsplitter from Trichrome Proguard. _dex_target = "${_target_name}__dex" _proguard_mapping_path = "${_bundle_path}.mapping" } assert(_proguard_enabled || !defined(invoker.enable_multidex), "Bundle only adds dexing step if proguarding is enabled.") if (defined(invoker.extra_modules)) { _module_count = 0 not_needed([ "_module_count" ]) foreach(_module, invoker.extra_modules) { _module_count += 1 assert(defined(_module.name), "Missing 'name' field for extra module #${_module_count}.") assert(_module.name != "base", "Module name 'base' is reserved for the main bundle module") assert( defined(_module.module_target), "Missing 'module_target' field for extra module ${_module.name}.") _module_target = _module.module_target _module_target_name = get_label_info(_module_target, "name") _module_target_gen_dir = get_label_info(_module_target, "target_gen_dir") _module.build_config = "$_module_target_gen_dir/${_module_target_name}.build_config" _module.build_config_target = "$_module_target$build_config_target_suffix" _module.parent = "base" _modules += [ _module ] } } # Make build config, which is required for synchronized proguarding. _module_java_targets = [] _module_build_configs = [] _module_targets = [] foreach(_module, _modules) { _module_targets += [ _module.module_target ] _module_java_targets += [ "${_module.module_target}__java" ] _module_build_configs += [ _module.build_config ] } if (_uses_static_library) { _lib_proxy_module = { name = "lib" } _static_library_target_name = get_label_info(invoker.static_library_provider, "name") _static_library_gen_dir = get_label_info(invoker.static_library_provider, "target_gen_dir") _lib_proxy_module.build_config = "$_static_library_gen_dir/$_static_library_target_name.build_config" _lib_proxy_module.build_config_target = "${invoker.static_library_provider}$build_config_target_suffix" } # Allot native libraries to modules they should be packaged into. This is # necessary since all libraries that are depended on by multiple modules # have to go into base or the static shared library if it exists. # TODO(crbug.com/1021565): It would be nice if this lived outside the # android_app_bundle template and the static shared library would pull in # the libs as allotted by this step. _native_libraries_config = "$target_gen_dir/$_target_name.native_libraries_config" _native_libraries_config_target = "${_target_name}__allot_native_libraries" allot_native_libraries(_native_libraries_config_target) { modules = _modules native_libraries_filearg_keys = [ "native:libraries", "native:loadable_modules", ] output = _native_libraries_config if (_uses_static_library) { modules += [ _lib_proxy_module ] } } if (defined(android_app_secondary_abi)) { _secondary_abi_native_libraries_config = "$target_gen_dir/$_target_name.secondary_abi_native_libraries_config" _secondary_abi_native_libraries_config_target = "${_target_name}__allot_secondary_abi_native_libraries" allot_native_libraries(_secondary_abi_native_libraries_config_target) { modules = _modules native_libraries_filearg_keys = [ "native:secondary_abi_libraries", "native:secondary_abi_loadable_modules", ] output = _secondary_abi_native_libraries_config if (_uses_static_library) { modules += [ _lib_proxy_module ] } } } # Used to expose the module Java targets of the bundle. group("${_target_name}__java") { deps = _module_java_targets } group("${_target_name}__compile_resources") { deps = [ "${invoker.base_module_target}__compile_resources" ] } _build_config = "$target_gen_dir/${_target_name}.build_config" _rebased_build_config = rebase_path(_build_config, root_build_dir) _build_config_target = "$_target_name$build_config_target_suffix" if (defined(invoker.proguard_android_sdk_dep)) { proguard_android_sdk_dep_ = invoker.proguard_android_sdk_dep } else { proguard_android_sdk_dep_ = "//third_party/android_sdk:android_sdk_java" } if (_proguard_enabled) { _proguard_mapping_path = "${_bundle_path}.mapping" } write_build_config(_build_config_target) { type = "android_app_bundle" possible_config_deps = _module_targets + [ proguard_android_sdk_dep_ ] build_config = _build_config proguard_enabled = _proguard_enabled module_build_configs = _module_build_configs if (_proguard_enabled) { proguard_mapping_path = _proguard_mapping_path } } if (_proguard_enabled) { # If this Bundle uses a static library, the static library APK will # create the synchronized dex file path. if (_uses_static_library_synchronized_proguard) { if (defined(invoker.min_sdk_version)) { not_needed(invoker, [ "min_sdk_version" ]) } } else { dex(_dex_target) { forward_variables_from(invoker, [ "expected_proguard_config", "expected_proguard_config_base", "min_sdk_version", ]) if (defined(expected_proguard_config)) { top_target_name = _target_name } enable_multidex = _enable_multidex proguard_enabled = true proguard_mapping_path = _proguard_mapping_path proguard_sourcefile_suffix = "$android_channel-$_version_code" build_config = _build_config deps = _module_java_targets + [ ":$_build_config_target" ] modules = _modules } } } _all_create_module_targets = [] _all_module_zip_paths = [] _all_module_build_configs = [] foreach(_module, _modules) { _module_target = _module.module_target _module_build_config = _module.build_config _module_build_config_target = _module.build_config_target if (!_proguard_enabled) { _dex_target_for_module = "${_module_target}__final_dex" } else { _dex_target_for_module = ":$_dex_target" } # Generate one module .zip file per bundle module. # # Important: the bundle tool uses the module's zip filename as # the internal module name inside the final bundle, in other words, # this file *must* be named ${_module.name}.zip _create_module_target = "${_target_name}__${_module.name}__create" _module_zip_path = "$target_gen_dir/$target_name/${_module.name}.zip" create_android_app_bundle_module(_create_module_target) { forward_variables_from(invoker, [ "is_multi_abi", "min_sdk_version", "uncompress_dex", "proguard_enabled", ]) module_name = _module.name build_config = _module_build_config module_zip_path = _module_zip_path native_libraries_config = _native_libraries_config if (module_name == "base" && defined(invoker.expected_libs_and_assets)) { forward_variables_from(invoker, [ "expected_libs_and_assets", "expected_libs_and_assets_base", ]) top_target_name = _target_name build_config_target = _module_build_config_target native_libraries_config_target = ":$_native_libraries_config_target" if (defined(android_app_secondary_abi)) { secondary_abi_native_libraries_config_target = ":$_secondary_abi_native_libraries_config_target" } } deps = [ ":$_native_libraries_config_target", _dex_target_for_module, _module_build_config_target, _module_target, ] if (defined(android_app_secondary_abi)) { secondary_abi_native_libraries_config = _secondary_abi_native_libraries_config deps += [ ":$_secondary_abi_native_libraries_config_target" ] } } _all_create_module_targets += [ ":$_create_module_target", _module_build_config_target, "${_module_target}__compile_resources", ] _all_module_zip_paths += [ _module_zip_path ] _all_module_build_configs += [ _module_build_config ] } _all_rebased_module_zip_paths = rebase_path(_all_module_zip_paths, root_build_dir) _sign_bundle = defined(invoker.sign_bundle) && invoker.sign_bundle _enable_language_splits = defined(invoker.enable_language_splits) && invoker.enable_language_splits _split_dimensions = [] if (_enable_language_splits) { _split_dimensions += [ "language" ] } _keystore_path = android_keystore_path _keystore_password = android_keystore_password _keystore_name = android_keystore_name if (defined(invoker.keystore_path)) { _keystore_path = invoker.keystore_path _keystore_password = invoker.keystore_password _keystore_name = invoker.keystore_name } _rebased_keystore_path = rebase_path(_keystore_path, root_build_dir) if (_sign_bundle) { # For now, the same keys are used to sign the bundle and the set of # generated APKs. In the future, signing the bundle may require a # different set of keys. _bundle_keystore_name = _keystore_name } _bundle_target_name = "${_target_name}__bundle" action_with_pydeps(_bundle_target_name) { script = "//build/android/gyp/create_app_bundle.py" inputs = _all_module_zip_paths + _all_module_build_configs outputs = [ _bundle_path ] deps = _all_create_module_targets + [ ":$_build_config_target" ] args = [ "--out-bundle=$_rebased_bundle_path", "--rtxt-out-path=$_rebased_bundle_path.R.txt", "--pathmap-out-path=$_rebased_bundle_path.pathmap.txt", "--module-zips=$_all_rebased_module_zip_paths", ] if (_sign_bundle) { args += [ "--keystore-path", _rebased_keystore_path, "--keystore-password", _keystore_password, "--key-name", _bundle_keystore_name, ] } if (_split_dimensions != []) { args += [ "--split-dimensions=$_split_dimensions" ] } if (defined(invoker.compress_shared_libraries) && invoker.compress_shared_libraries) { args += [ "--compress-shared-libraries" ] } if (treat_warnings_as_errors) { args += [ "--warnings-as-errors" ] } if (_enable_language_splits) { args += [ "--base-allowlist-rtxt-path=@FileArg(" + "${_rebased_base_module_build_config}:deps_info:base_allowlist_rtxt_path)", "--base-module-rtxt-path=@FileArg(" + "${_rebased_base_module_build_config}:deps_info:r_text_path)", ] } foreach(_module, _modules) { _rebased_build_config = rebase_path(_module.build_config, root_build_dir) args += [ "--uncompressed-assets=@FileArg(" + "$_rebased_build_config:uncompressed_assets)", "--rtxt-in-paths=@FileArg(" + "$_rebased_build_config:deps_info:r_text_path)", "--pathmap-in-paths=@FileArg(" + "$_rebased_build_config:deps_info:module_pathmap_path)", "--module-name=" + _module.name, ] } # http://crbug.com/725224. Fix for bots running out of memory. if (defined(java_cmd_pool_size)) { pool = "//build/config/android:java_cmd_pool($default_toolchain)" } else { pool = "//build/toolchain:link_pool($default_toolchain)" } } # Create size info files for targets that care about size # (have proguard enabled). if (_proguard_enabled) { # Merge all module targets to obtain size info files for all targets. _all_module_targets = _module_targets _size_info_target = "${_target_name}__size_info" create_size_info_files(_size_info_target) { name = "$_bundle_name.aab" deps = _all_module_targets + [ ":$_build_config_target" ] module_build_configs = _all_module_build_configs } } if (_uses_static_library) { _install_artifacts_target = "${target_name}__install_artifacts" _install_artifacts_json = "${target_gen_dir}/${target_name}.install_artifacts" generated_file(_install_artifacts_target) { output_conversion = "json" deps = [ invoker.static_library_provider ] outputs = [ _install_artifacts_json ] data_keys = [ "install_artifacts" ] rebase = root_build_dir } } # Generate a wrapper script for the bundle. _android_aapt2_path = android_sdk_tools_bundle_aapt2 _bundle_apks_path = "$_bundle_base_path/$_bundle_name.apks" _bundle_wrapper_script_dir = "$root_build_dir/bin" _bundle_wrapper_script_path = "$_bundle_wrapper_script_dir/$_target_name" action_with_pydeps("${_target_name}__wrapper_script") { script = "//build/android/gyp/create_bundle_wrapper_script.py" inputs = [ _base_module_build_config ] outputs = [ _bundle_wrapper_script_path ] # Telemetry for bundles uses the wrapper script for installation. data = [ _bundle_wrapper_script_path, _android_aapt2_path, _keystore_path, _bundle_path, ] data_deps = [ "//build/android:bundle_wrapper_script_py", "//tools/android/md5sum", ] deps = [ _base_module_build_config_target ] args = [ "--script-output-path", rebase_path(_bundle_wrapper_script_path, root_build_dir), "--package-name=@FileArg(" + "$_rebased_base_module_build_config:deps_info:package_name)", "--aapt2", rebase_path(_android_aapt2_path, root_build_dir), "--bundle-path", _rebased_bundle_path, "--bundle-apks-path", rebase_path(_bundle_apks_path, root_build_dir), "--target-cpu=$target_cpu", "--keystore-path", _rebased_keystore_path, "--keystore-password", _keystore_password, "--key-name", _keystore_name, ] if (defined(invoker.default_modules_for_testing)) { args += [ "--default-modules" ] + invoker.default_modules_for_testing } if (defined(invoker.system_image_locale_allowlist)) { args += [ "--system-image-locales=${invoker.system_image_locale_allowlist}", ] } if (defined(invoker.command_line_flags_file)) { args += [ "--command-line-flags-file", invoker.command_line_flags_file, ] } if (_uses_static_library) { deps += [ ":$_install_artifacts_target" ] _rebased_install_artifacts_json = rebase_path(_install_artifacts_json, root_build_dir) _static_library_apk_path = "@FileArg($_rebased_install_artifacts_json[])" args += [ "--additional-apk", _static_library_apk_path, ] } if (_proguard_enabled) { args += [ "--proguard-mapping-path", rebase_path(_proguard_mapping_path, root_build_dir), ] # Required by logcat command. data_deps += [ "//build/android/stacktrace:java_deobfuscate" ] data += [ _proguard_mapping_path ] } } _enable_lint = defined(invoker.enable_lint) && invoker.enable_lint && !disable_android_lint if (_enable_lint) { android_lint("${target_name}__lint") { forward_variables_from(invoker, [ "lint_baseline_file", "lint_suppressions_file", "min_sdk_version", ]) build_config = _build_config build_config_dep = ":$_build_config_target" deps = _module_java_targets if (defined(invoker.lint_suppressions_dep)) { deps += [ invoker.lint_suppressions_dep ] } if (defined(invoker.lint_min_sdk_version)) { min_sdk_version = invoker.lint_min_sdk_version } } } else { not_needed(invoker, [ "lint_baseline_file", "lint_min_sdk_version", "lint_suppressions_dep", "lint_suppressions_file", ]) } group(_target_name) { public_deps = [ ":$_bundle_target_name", ":${_target_name}__wrapper_script", ] if (defined(_size_info_target)) { public_deps += [ ":$_size_info_target" ] } if (_enable_lint) { if (!defined(data_deps)) { data_deps = [] } data_deps += [ ":${target_name}__lint" ] } } _apks_path = "$root_build_dir/apks/$_bundle_name.apks" action_with_pydeps("${_target_name}_apks") { script = "//build/android/gyp/create_app_bundle_apks.py" inputs = [ _bundle_path ] outputs = [ _apks_path ] data = [ _apks_path ] args = [ "--bundle", _rebased_bundle_path, "--output", rebase_path(_apks_path, root_build_dir), "--aapt2-path", rebase_path(android_sdk_tools_bundle_aapt2, root_build_dir), "--keystore-path", rebase_path(android_keystore_path, root_build_dir), "--keystore-name", android_keystore_name, "--keystore-password", android_keystore_password, ] deps = [ ":$_bundle_target_name" ] metadata = { install_artifacts = [ _apks_path ] } if (defined(invoker.static_library_provider)) { metadata.install_artifacts_barrier = [] } # http://crbug.com/725224. Fix for bots running out of memory. if (defined(java_cmd_pool_size)) { pool = "//build/config/android:java_cmd_pool($default_toolchain)" } else { pool = "//build/toolchain:link_pool($default_toolchain)" } } } # Create an .apks file from an .aab file. The .apks file will contain the # minimal set of .apk files needed for tracking binary size. # The file will be created at "$bundle_path_without_extension.minimal.apks". # # Variables: # bundle_path: Path to the input .aab file. # # Example: # create_app_bundle_minimal_apks("minimal_apks") { # deps = [ # ":bundle_target", # ] # bundle_path = "$root_build_dir/apks/Bundle.aab" # } template("create_app_bundle_minimal_apks") { action_with_pydeps(target_name) { forward_variables_from(invoker, [ "deps", "testonly", ]) script = "//build/android/gyp/create_app_bundle_apks.py" _dir = get_path_info(invoker.bundle_path, "dir") _name = get_path_info(invoker.bundle_path, "name") _output_path = "$_dir/$_name.minimal.apks" outputs = [ _output_path ] inputs = [ invoker.bundle_path ] args = [ "--bundle", rebase_path(invoker.bundle_path, root_build_dir), "--output", rebase_path(_output_path, root_build_dir), "--aapt2-path", rebase_path(android_sdk_tools_bundle_aapt2, root_build_dir), "--keystore-path", rebase_path(android_keystore_path, root_build_dir), "--keystore-name", android_keystore_name, "--keystore-password", android_keystore_password, "--minimal", ] } } } # Generate an Android resources target that contains localized strings # describing the current locale used by the Android framework to display # UI strings. These are used by # org.chromium.chrome.browser.ChromeLocalizationUtils. # # Variables: # ui_locales: List of Chromium locale names to generate resources for. # template("generate_ui_locale_resources") { _generating_target_name = "${target_name}__generate" _rebased_output_zip_path = rebase_path(target_gen_dir, root_gen_dir) _output_zip = "${root_out_dir}/resource_zips/${_rebased_output_zip_path}/" + "${target_name}.zip" action_with_pydeps(_generating_target_name) { script = "//build/android/gyp/create_ui_locale_resources.py" outputs = [ _output_zip ] args = [ "--locale-list=${invoker.ui_locales}", "--output-zip", rebase_path(_output_zip, root_build_dir), ] } android_generated_resources(target_name) { generating_target_name = ":$_generating_target_name" generated_resources_zip = _output_zip } }