• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2023 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import("//build/config/android/config.gni")
6import("//build/config/python.gni")
7import("//build/partitioned_shared_library.gni")
8
9declare_args() {
10  # Enables JNI multiplexing to reduce JNI native methods overhead.
11  allow_jni_multiplexing = false
12
13  # Use hashed symbol names to reduce JNI symbol overhead.
14  use_hashed_jni_names = !is_java_debug
15}
16
17# Use a dedicated include dir so that files can #include headers from other
18# toolchains without affecting non-JNI #includes.
19if (target_os == "android") {
20  jni_headers_dir = "$root_build_dir/gen/jni_headers"
21} else {
22  # Chrome OS builds cannot share gen/ directories because is_android=false
23  # within default_toolchain.
24  jni_headers_dir = "$root_gen_dir/jni_headers"
25}
26
27template("jni_sources_list") {
28  generated_file(target_name) {
29    forward_variables_from(invoker,
30                           TESTONLY_AND_VISIBILITY + [
31                                 "deps",
32                                 "walk_keys",
33                               ])
34    outputs = [ invoker.output ]
35    data_keys = [ "jni_source_files" ]
36    rebase = root_build_dir
37    metadata = {
38      # This target is just collecting source files used - this is not a
39      # legitimate dependency.
40      shared_libraries_barrier = []
41    }
42  }
43}
44
45# Declare a jni registration target.
46#
47# This target generates a srcjar containing a copy of GEN_JNI.java, which has
48# the native methods of all dependent java files. It can also create a .h file
49# for use with manual JNI registration.
50#
51# The script does not scan any generated sources (those within .srcjars, or
52# within root_build_dir). This could be fixed by adding deps & logic to scan
53# .srcjars, but isn't currently needed.
54#
55# See base/android/jni_generator/jni_registration_generator.py for more info
56# about the format of the header file.
57#
58# Variables
59#   java_targets: List of android_* targets that comprise your app.
60#   native_deps: List of shared_library targets that comprise your app.
61#   manual_jni_registration: Manually do JNI registration - required for feature
62#     splits which provide their own native library. (optional)
63#   namespace: Registration functions will be wrapped into this. (optional)
64#   require_native_mocks: Enforce that any native calls using
65#     org.chromium.base.annotations.NativeMethods must have a mock set
66#     (optional).
67#   enable_native_mocks: Allow native calls using
68#     org.chromium.base.annotations.NativeMethods to be mocked in tests
69#     (optional).
70#
71# Example
72#   generate_jni_registration("chrome_jni_registration") {
73#     java_targets = [ ":chrome_public_apk" ]
74#     manual_jni_registration = false
75#   }
76template("generate_jni_registration") {
77  forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
78  if (defined(invoker.native_deps)) {
79    _native_sources_list = "$target_gen_dir/$target_name.nativesources.txt"
80    jni_sources_list("${target_name}__native_sources") {
81      deps = invoker.native_deps
82      output = _native_sources_list
83    }
84  }
85
86  _java_sources_list = "$target_gen_dir/$target_name.javasources.txt"
87  jni_sources_list("${target_name}__java_sources") {
88    deps = invoker.java_targets
89    output = _java_sources_list
90
91    # When apk or bundle module targets are uses, do not pull metadata from
92    # their native library deps.
93    walk_keys = [ "java_walk_keys" ]
94  }
95
96  action_with_pydeps(target_name) {
97    script = "//base/android/jni_generator/jni_zero.py"
98    inputs = []
99
100    # Cannot depend on jni_sources_list targets since they likely depend on
101    # this target via srcjar_deps. Depfiles are used to add the dep instead.
102    deps = []
103    _srcjar_output = "$target_gen_dir/$target_name.srcjar"
104    outputs = [ _srcjar_output ]
105    depfile = "$target_gen_dir/$target_name.d"
106
107    args = [
108      "generate-final",
109      "--srcjar-path",
110      rebase_path(_srcjar_output, root_build_dir),
111      "--depfile",
112      rebase_path(depfile, root_build_dir),
113      "--java-sources-file",
114      rebase_path(_java_sources_list, root_build_dir),
115    ]
116
117    if (defined(_native_sources_list)) {
118      args += [
119        "--native-sources-file",
120        rebase_path(_native_sources_list, root_build_dir),
121      ]
122    }
123
124    if (defined(invoker.include_testonly)) {
125      _include_testonly = invoker.include_testonly
126    } else {
127      _include_testonly = defined(testonly) && testonly
128    }
129    if (_include_testonly) {
130      args += [ "--include-test-only" ]
131    }
132
133    if (use_hashed_jni_names) {
134      args += [ "--use-proxy-hash" ]
135    }
136
137    if (defined(invoker.enable_native_mocks) && invoker.enable_native_mocks) {
138      args += [ "--enable-proxy-mocks" ]
139
140      if (defined(invoker.require_native_mocks) &&
141          invoker.require_native_mocks) {
142        args += [ "--require-mocks" ]
143      }
144    }
145
146    if (defined(invoker.remove_uncalled_jni) && invoker.remove_uncalled_jni) {
147      args += [ "--remove-uncalled-methods" ]
148    }
149    if (defined(invoker.add_stubs_for_missing_jni) &&
150        invoker.add_stubs_for_missing_jni) {
151      args += [ "--add-stubs-for-missing-native" ]
152    }
153
154    _manual_jni_registration = defined(invoker.manual_jni_registration) &&
155                               invoker.manual_jni_registration
156    _enable_jni_multiplexing = defined(invoker.enable_jni_multiplexing) &&
157                               invoker.enable_jni_multiplexing
158    if (_manual_jni_registration) {
159      args += [ "--manual-jni-registration" ]
160    }
161    if (_enable_jni_multiplexing) {
162      args += [ "--enable-jni-multiplexing" ]
163    }
164
165    if (_manual_jni_registration || _enable_jni_multiplexing) {
166      _subdir = rebase_path(target_gen_dir, root_gen_dir)
167      _jni_header_output =
168          "$jni_headers_dir/$_subdir/${target_name}_generated.h"
169      outputs += [ _jni_header_output ]
170      args += [
171        "--header-path",
172        rebase_path(_jni_header_output, root_build_dir),
173      ]
174
175      # This gives targets depending on this registration access to our generated header.
176      public_configs = [ "//build/config/android:jni_include_dir" ]
177    }
178
179    if (defined(invoker.namespace)) {
180      args += [ "--namespace=${invoker.namespace}" ]
181    }
182
183    if (defined(invoker.module_name)) {
184      args += [ "--module-name=${invoker.module_name}" ]
185    }
186  }
187}
188
189# This is a wrapper around an underlying native target which inserts JNI
190# registration.
191#
192# The registration is based on the closure of the native target's generate_jni
193# transitive dependencies. Additionally, we use provided java_targets to assert
194# that our native and Java sides line up.
195#
196# In order to depend on the JNI registration, use
197# <native-target-name>__jni_registration.
198template("_native_with_jni") {
199  _needs_native_dep =
200      (defined(invoker.manual_jni_registration) &&
201       invoker.manual_jni_registration) || allow_jni_multiplexing
202  if (_needs_native_dep || current_toolchain == default_toolchain) {
203    _jni_registration_target_name = "${target_name}__jni_registration"
204  }
205
206  if (current_toolchain == default_toolchain) {
207    generate_jni_registration(_jni_registration_target_name) {
208      forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
209      native_deps = invoker.deps
210
211      if (allow_jni_multiplexing) {
212        enable_jni_multiplexing = true
213      }
214      if (defined(invoker.testonly) && invoker.testonly) {
215        enable_native_mocks = true
216        add_stubs_for_missing_jni = true
217        remove_uncalled_jni = true
218      }
219      forward_variables_from(invoker,
220                             [
221                               "add_stubs_for_missing_jni",
222                               "java_targets",
223                               "manual_jni_registration",
224                               "module_name",
225                               "namespace",
226                               "remove_uncalled_jni",
227                             ])
228    }
229  } else {
230    not_needed(invoker,
231               [
232                 "add_stubs_for_missing_jni",
233                 "java_targets",
234                 "manual_jni_registration",
235                 "module_name",
236                 "namespace",
237                 "remove_uncalled_jni",
238               ])
239  }
240
241  if (!defined(invoker.enable_target) || invoker.enable_target) {
242    target(invoker.target_type, target_name) {
243      deps = invoker.deps
244      if (_needs_native_dep) {
245        deps += [ ":$_jni_registration_target_name($default_toolchain)" ]
246      }
247      forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
248      forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY + [ "deps" ])
249    }
250  } else {
251    not_needed(invoker, "*")
252    if (current_toolchain != default_toolchain) {
253      not_needed([ "target_name" ])
254    }
255  }
256}
257
258# native_with_jni for shared libraries - see _native_with_jni for details.
259template("shared_library_with_jni") {
260  _native_with_jni(target_name) {
261    forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
262    forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
263    target_type = "shared_library"
264  }
265}
266set_defaults("shared_library_with_jni") {
267  configs = default_shared_library_configs
268}
269
270# native_with_jni for partitioned shared libraries - see _native_with_jni for
271# details.
272template("partitioned_shared_library_with_jni") {
273  _native_with_jni(target_name) {
274    forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
275    forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
276    target_type = "partitioned_shared_library"
277  }
278}
279set_defaults("partitioned_shared_library_with_jni") {
280  configs = default_shared_library_configs
281}
282
283# native_with_jni for components - see _native_with_jni for details.
284template("component_with_jni") {
285  _native_with_jni(target_name) {
286    forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
287    forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
288    target_type = "component"
289  }
290}
291set_defaults("component_with_jni") {
292  configs = default_component_configs
293}
294