• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# -*- bazel-starlark -*-
2# Copyright 2023 The Chromium Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5"""Siso configuration for Android builds."""
6
7load("@builtin//encoding.star", "json")
8load("@builtin//lib/gn.star", "gn")
9load("@builtin//struct.star", "module")
10load("./config.star", "config")
11load("./gn_logs.star", "gn_logs")
12
13# TODO: crbug.com/323091468 - Propagate target android ABI and
14# android SDK version from GN, and remove the hardcoded filegroups.
15__archs = [
16    "aarch64-linux-android",
17    "arm-linux-androideabi",
18    "i686-linux-android",
19    "riscv64-linux-android",
20    "x86_64-linux-android",
21]
22
23def __enabled(ctx):
24    if "args.gn" in ctx.metadata:
25        gn_args = gn.args(ctx)
26        if gn_args.get("target_os") == '"android"':
27            return True
28    return False
29
30def __filegroups(ctx):
31    fg = {}
32    for arch in __archs:
33        api_level = gn_logs.read(ctx).get("android64_ndk_api_level")
34        if api_level:
35            group = "third_party/android_toolchain/ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/%s/%s:link" % (arch, api_level)
36            fg[group] = {
37                "type": "glob",
38                "includes": ["*"],
39            }
40    return fg
41
42def __step_config(ctx, step_config):
43    remote_run = True  # Turn this to False when you do file access trace.
44
45    # Run static analysis steps locally when build server is enabled.
46    # https://chromium.googlesource.com/chromium/src/+/main/docs/android_build_instructions.md#asynchronous-static-analysis
47    remote_run_static_analysis = True
48    if "args.gn" in ctx.metadata:
49        gn_args = gn.args(ctx)
50        if gn_args.get("android_static_analysis") == '"build_server"':
51            remote_run_static_analysis = False
52
53    step_config["rules"].extend([
54        # See also https://chromium.googlesource.com/chromium/src/build/+/HEAD/android/docs/java_toolchain.md
55        {
56            "name": "android/write_build_config",
57            "command_prefix": "python3 ../../build/android/gyp/write_build_config.py",
58            "handler": "android_write_build_config",
59            "remote": remote_run,
60            "canonicalize_dir": True,
61            "timeout": "2m",
62        },
63        {
64            "name": "android/ijar",
65            "command_prefix": "python3 ../../build/android/gyp/ijar.py",
66            "remote": remote_run,
67            "canonicalize_dir": True,
68            "timeout": "2m",
69        },
70        {
71            "name": "android/turbine",
72            "command_prefix": "python3 ../../build/android/gyp/turbine.py",
73            "handler": "android_turbine",
74            # TODO: crbug.com/396220357 - fix gn to remove unnecessary deps
75            "exclude_input_patterns": [
76                "*.a",
77                "*.cc",
78                "*.cpp",
79                "*.h",
80                "*.html",
81                "*.inc",
82                "*.info",
83                "*.js",
84                "*.map",
85                "*.o",
86                "*.pak",
87                "*.proto",
88                "*.sql",
89                "*.stamp",
90                "*.svg",
91                "*.xml",
92            ],
93            "remote": remote_run,
94            "platform_ref": "large",
95            "canonicalize_dir": True,
96            "timeout": "2m",
97        },
98        {
99            "name": "android/compile_resources",
100            "command_prefix": "python3 ../../build/android/gyp/compile_resources.py",
101            "handler": "android_compile_resources",
102            "exclude_input_patterns": [
103                "*.a",
104                "*.cc",
105                "*.h",
106                "*.inc",
107                "*.info",
108                "*.o",
109                "*.pak",
110                "*.sql",
111            ],
112            "remote": remote_run,
113            "canonicalize_dir": True,
114            "timeout": "5m",
115        },
116        {
117            "name": "android/compile_java",
118            "command_prefix": "python3 ../../build/android/gyp/compile_java.py",
119            "handler": "android_compile_java",
120            "exclude_input_patterns": [
121                "*.a",
122                "*.cc",
123                "*.h",
124                "*.inc",
125                "*.info",
126                "*.o",
127                "*.pak",
128                "*.sql",
129            ],
130            # Don't include files under --generated-dir.
131            # This is probably optimization for local incrmental builds.
132            # However, this is harmful for remote build cache hits.
133            "ignore_extra_input_pattern": ".*srcjars.*\\.java",
134            "ignore_extra_output_pattern": ".*srcjars.*\\.java",
135            "remote": remote_run,
136            "platform_ref": "large",
137            "canonicalize_dir": True,
138            "timeout": "2m",
139        },
140        {
141            "name": "android/errorprone",
142            "command_prefix": "python3 ../../build/android/gyp/errorprone.py",
143            "handler": "android_compile_java",
144            "exclude_input_patterns": [
145                "*.a",
146                "*.cc",
147                "*.h",
148                "*.inc",
149                "*.info",
150                "*.o",
151                "*.pak",
152                "*.sql",
153            ],
154            "remote": remote_run_static_analysis,
155            "platform_ref": "large",
156            "canonicalize_dir": True,
157            "timeout": "2m",
158        },
159        {
160            "name": "android/compile_kt",
161            "command_prefix": "python3 ../../build/android/gyp/compile_kt.py",
162            "handler": "android_compile_java",
163            "exclude_input_patterns": [
164                "*.a",
165                "*.cc",
166                "*.h",
167                "*.inc",
168                "*.info",
169                "*.o",
170                "*.pak",
171                "*.sql",
172            ],
173            # Don't include files under --generated-dir.
174            # This is probably optimization for local incrmental builds.
175            # However, this is harmful for remote build cache hits.
176            "ignore_extra_input_pattern": ".*srcjars.*\\.java",
177            "ignore_extra_output_pattern": ".*srcjars.*\\.java",
178            "remote": remote_run,
179            "platform_ref": "large",
180            "canonicalize_dir": True,
181            "timeout": "2m",
182        },
183        {
184            "name": "android/dex",
185            "command_prefix": "python3 ../../build/android/gyp/dex.py",
186            "handler": "android_dex",
187            # TODO(crbug.com/40270798): include only required jar, dex files in GN config.
188            "indirect_inputs": {
189                "includes": ["*.dex", "*.ijar.jar", "*.turbine.jar"],
190            },
191            "exclude_input_patterns": [
192                "*.a",
193                "*.cc",
194                "*.h",
195                "*.inc",
196                "*.info",
197                "*.o",
198                "*.pak",
199                "*.sql",
200            ],
201            # *.dex files are intermediate files used in incremental builds.
202            # Fo remote actions, let's ignore them, assuming remote cache hits compensate.
203            "ignore_extra_input_pattern": ".*\\.dex",
204            "ignore_extra_output_pattern": ".*\\.dex",
205            "remote": remote_run,
206            "platform_ref": "large",
207            "canonicalize_dir": True,
208            "timeout": "2m",
209        },
210        {
211            "name": "android/filter_zip",
212            "command_prefix": "python3 ../../build/android/gyp/filter_zip.py",
213            "remote": remote_run,
214            "canonicalize_dir": True,
215            "timeout": "2m",
216        },
217        {
218            "name": "android/generate_resource_allowlist",
219            "command_prefix": "python3 ../../tools/resources/generate_resource_allowlist.py",
220            "indirect_inputs": {
221                "includes": ["*.o", "*.a"],
222            },
223            # When remote linking without bytes enabled, .o, .a files don't
224            # exist on the local file system.
225            # This step also should run remortely to avoid downloading them.
226            "remote": config.get(ctx, "remote-link"),
227            "platform_ref": "large",
228            "canonicalize_dir": True,
229            "timeout": "2m",
230        },
231        {
232            "name": "android/proguard",
233            "command_prefix": "python3 ../../build/android/gyp/proguard.py",
234            "handler": "android_proguard",
235            "exclude_input_patterns": [
236                "*.a",
237                "*.cc",
238                "*.h",
239                "*.inc",
240                "*.info",
241                "*.o",
242                "*.pak",
243                "*.sql",
244            ],
245            "canonicalize_dir": True,
246            # Speculatively disabling for https://crbug.com/398058215
247            "remote": False,
248            "platform_ref": "large",
249            "timeout": "10m",
250        },
251    ])
252    return step_config
253
254def __filearg(ctx, arg):
255    fn = ""
256    if arg.startswith("@FileArg("):
257        f = arg.removeprefix("@FileArg(").removesuffix(")").split(":")
258        fn = f[0].removesuffix("[]")  # [] suffix controls expand list?
259        v = json.decode(str(ctx.fs.read(ctx.fs.canonpath(fn))))
260        for k in f[1:]:
261            v = v[k]
262        arg = v
263    if type(arg) == "string":
264        if arg.startswith("["):
265            return fn, json.decode(arg)
266        return fn, [arg]
267    return fn, arg
268
269def __android_compile_resources_handler(ctx, cmd):
270    # Script:
271    #   https://crsrc.org/c/build/android/gyp/compile_resources.py
272    # GN Config:
273    #   https://crsrc.org/c/build/config/android/internal_rules.gni;l=2163;drc=1b15af251f8a255e44f2e3e3e7990e67e87dcc3b
274    #   https://crsrc.org/c/build/config/android/system_image.gni;l=58;drc=39debde76e509774287a655285d8556a9b8dc634
275    # Sample args:
276    #   --aapt2-path ../../third_party/android_build_tools/aapt2/cipd/aapt2
277    #   --android-manifest gen/chrome/android/trichrome_library_system_stub_apk__manifest.xml
278    #   --arsc-package-name=org.chromium.trichromelibrary
279    #   --arsc-path obj/chrome/android/trichrome_library_system_stub_apk.ap_
280    #   --debuggable
281    #   --dependencies-res-zip-overlays=@FileArg\(gen/chrome/android/webapk/shell_apk/maps_go_webapk.build_config.json:deps_info:dependency_zip_overlays\)
282    #   --dependencies-res-zips=@FileArg\(gen/chrome/android/webapk/shell_apk/maps_go_webapk.build_config.json:deps_info:dependency_zips\)
283    #   --depfile gen/chrome/android/webapk/shell_apk/maps_go_webapk__compile_resources.d
284    #   --emit-ids-out=gen/chrome/android/webapk/shell_apk/maps_go_webapk__compile_resources.resource_ids
285    #   --extra-res-packages=@FileArg\(gen/chrome/android/webapk/shell_apk/maps_go_webapk.build_config.json:deps_info:extra_package_names\)
286    #   --include-resources(=)../../third_party/android_sdk/public/platforms/android-34/android.jar
287    #   --info-path obj/chrome/android/webapk/shell_apk/maps_go_webapk.ap_.info
288    #   --min-sdk-version=24
289    #   --proguard-file obj/chrome/android/webapk/shell_apk/maps_go_webapk/maps_go_webapk.resources.proguard.txt
290    #   --r-text-out gen/chrome/android/webapk/shell_apk/maps_go_webapk__compile_resources_R.txt
291    #   --rename-manifest-package=org.chromium.trichromelibrary
292    #   --srcjar-out gen/chrome/android/webapk/shell_apk/maps_go_webapk__compile_resources.srcjar
293    #   --target-sdk-version=33
294    #   --version-code 1
295    #   --version-name Developer\ Build
296    #   --webp-cache-dir=obj/android-webp-cache
297    inputs = []
298    for i, arg in enumerate(cmd.args):
299        for k in ["--dependencies-res-zips=", "--dependencies-res-zip-overlays=", "--extra-res-packages="]:
300            if arg.startswith(k):
301                arg = arg.removeprefix(k)
302                _, v = __filearg(ctx, arg)
303                for f in v:
304                    f = ctx.fs.canonpath(f)
305                    inputs.append(f)
306                    if k == "--dependencies-res-zips=" and ctx.fs.exists(f + ".info"):
307                        inputs.append(f + ".info")
308
309    ctx.actions.fix(
310        inputs = cmd.inputs + inputs,
311    )
312
313def __android_compile_java_handler(ctx, cmd):
314    # Script:
315    #   https://crsrc.org/c/build/android/gyp/compile_java.py
316    # GN Config:
317    #   https://crsrc.org/c/build/config/android/internal_rules.gni;l=2995;drc=775b3a9ebccd468c79592dad43ef46632d3a411f
318    # Sample args:
319    #   --depfile=gen/chrome/android/chrome_test_java__compile_java.d
320    #   --generated-dir=gen/chrome/android/chrome_test_java/generated_java
321    #   --jar-path=obj/chrome/android/chrome_test_java.javac.jar
322    #   --java-srcjars=\[\"gen/chrome/browser/tos_dialog_behavior_generated_enum.srcjar\",\ \"gen/chrome/android/chrome_test_java__assetres.srcjar\",\ \"gen/chrome/android/chrome_test_java.generated.srcjar\"\]
323    #   --target-name //chrome/android:chrome_test_java__compile_java
324    #   --classpath=@FileArg\(gen/chrome/android/chrome_test_java.build_config.json:android:sdk_interface_jars\)
325    #   --header-jar obj/chrome/android/chrome_test_java.turbine.jar
326    #   --classpath=\[\"obj/chrome/android/chrome_test_java.turbine.jar\"\]
327    #   --classpath=@FileArg\(gen/chrome/android/chrome_test_java.build_config.json:deps_info:javac_full_interface_classpath\)
328    #   --kotlin-jar-path=obj/chrome/browser/tabmodel/internal/java.kotlinc.jar
329    #   --chromium-code=1
330    #   --warnings-as-errors
331    #   --jar-info-exclude-globs=\[\"\*/R.class\",\ \"\*/R\\\$\*.class\",\ \"\*/Manifest.class\",\ \"\*/Manifest\\\$\*.class\",\ \"\*/\*GEN_JNI.class\"\]
332    #   --enable-errorprone
333    #   @gen/chrome/android/chrome_test_java.sources
334
335    out = cmd.outputs[0]
336    outputs = [
337        out + ".md5.stamp",
338    ]
339
340    inputs = []
341    for i, arg in enumerate(cmd.args):
342        for k in ["--classpath=", "--bootclasspath=", "--processorpath="]:
343            if arg.startswith(k):
344                arg = arg.removeprefix(k)
345                fn, v = __filearg(ctx, arg)
346                if fn:
347                    inputs.append(ctx.fs.canonpath(fn))
348                for f in v:
349                    f, _, _ = f.partition(":")
350                    inputs.append(ctx.fs.canonpath(f))
351
352    ctx.actions.fix(
353        inputs = cmd.inputs + inputs,
354        outputs = cmd.outputs + outputs,
355    )
356
357def __android_dex_handler(ctx, cmd):
358    out = cmd.outputs[0]
359    inputs = []
360
361    # Add __dex.desugardeps to the outputs.
362    outputs = [
363        out + ".md5.stamp",
364    ]
365    for i, arg in enumerate(cmd.args):
366        if arg == "--desugar-dependencies":
367            outputs.append(ctx.fs.canonpath(cmd.args[i + 1]))
368        for k in ["--class-inputs=", "--bootclasspath=", "--classpath=", "--class-inputs-filearg=", "--dex-inputs-filearg="]:
369            if arg.startswith(k):
370                arg = arg.removeprefix(k)
371                _, v = __filearg(ctx, arg)
372                for f in v:
373                    f, _, _ = f.partition(":")
374                    f = ctx.fs.canonpath(f)
375                    inputs.append(f)
376
377    # TODO: dex.py takes --incremental-dir to reuse the .dex produced in a previous build.
378    # Should remote dex action also take this?
379    ctx.actions.fix(
380        inputs = cmd.inputs + inputs,
381        outputs = cmd.outputs + outputs,
382    )
383
384def __android_proguard_handler(ctx, cmd):
385    inputs = []
386    outputs = []
387    for i, arg in enumerate(cmd.args):
388        for k in ["--proguard-configs=", "--input-paths=", "--feature-jars="]:
389            if arg.startswith(k):
390                arg = arg.removeprefix(k)
391                fn, v = __filearg(ctx, arg)
392                if fn:
393                    inputs.append(ctx.fs.canonpath(fn))
394                for f in v:
395                    f, _, _ = f.partition(":")
396                    inputs.append(ctx.fs.canonpath(f))
397                break
398        if arg in ["--sdk-jars", "--sdk-extension-jars"]:
399            fn, v = __filearg(ctx, cmd.args[i + 1])
400            if fn:
401                inputs.append(ctx.fs.canonpath(fn))
402            for f in v:
403                f, _, _ = f.partition(":")
404                inputs.append(ctx.fs.canonpath(f))
405            continue
406        if arg.startswith("--dex-dest="):
407            arg = arg.removeprefix("--dex-dest=")
408            fn, v = __filearg(ctx, arg)
409            if fn:
410                inputs.append(ctx.fs.canonpath(fn))
411            for f in v:
412                f, _, _ = f.partition(":")
413                outputs.append(ctx.fs.canonpath(f))
414            continue
415
416    ctx.actions.fix(
417        inputs = cmd.inputs + inputs,
418        outputs = cmd.outputs + outputs,
419    )
420
421def __android_turbine_handler(ctx, cmd):
422    inputs = []
423    for i, arg in enumerate(cmd.args):
424        for k in ["--classpath=", "--processorpath="]:
425            if arg.startswith(k):
426                arg = arg.removeprefix(k)
427                _, v = __filearg(ctx, arg)
428                for f in v:
429                    f, _, _ = f.partition(":")
430                    inputs.append(ctx.fs.canonpath(f))
431
432    ctx.actions.fix(
433        inputs = cmd.inputs + inputs,
434    )
435
436def __deps_configs(ctx, f, seen, inputs):
437    if f in seen:
438        return
439    seen[f] = True
440    inputs.append(f)
441    v = json.decode(str(ctx.fs.read(f)))
442    for f in v["deps_info"]["deps_configs"]:
443        f = ctx.fs.canonpath(f)
444        __deps_configs(ctx, f, seen, inputs)
445    if "public_deps_configs" in v["deps_info"]:
446        for f in v["deps_info"]["public_deps_configs"]:
447            f = ctx.fs.canonpath(f)
448            __deps_configs(ctx, f, seen, inputs)
449
450def __android_write_build_config_handler(ctx, cmd):
451    # Script:
452    #   https://crsrc.org/c/build/android/gyp/write_build_config.py
453    # GN Config:
454    #   https://crsrc.org/c/build/config/android/internal_rules.gni;l=122;drc=99e4f79301e108ea3d27ec84320f430490382587
455    # Sample args:
456    #   --type=java_library
457    #   --depfile gen/third_party/android_deps/org_jetbrains_kotlinx_kotlinx_metadata_jvm_java__build_config_crbug_908819.d
458    #   --deps-configs=\[\"gen/third_party/kotlin_stdlib/kotlin_stdlib_java.build_config.json\"\]
459    #   --public-deps-configs=\[\]
460    #   --build-config gen/third_party/android_deps/org_jetbrains_kotlinx_kotlinx_metadata_jvm_java.build_config.json
461    #   --gn-target //third_party/android_deps:org_jetbrains_kotlinx_kotlinx_metadata_jvm_java
462    #   --non-chromium-code
463    #   --host-jar-path lib.java/third_party/android_deps/org_jetbrains_kotlinx_kotlinx_metadata_jvm.jar
464    #   --unprocessed-jar-path ../../third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_metadata_jvm/kotlinx-metadata-jvm-0.1.0.jar
465    #   --interface-jar-path obj/third_party/android_deps/org_jetbrains_kotlinx_kotlinx_metadata_jvm.ijar.jar
466    #   --is-prebuilt
467    #   --bundled-srcjars=\[\]
468    inputs = []
469    seen = {}
470    for i, arg in enumerate(cmd.args):
471        if arg in ["--shared-libraries-runtime-deps", "--secondary-abi-shared-libraries-runtime-deps"]:
472            inputs.append(ctx.fs.canonpath(cmd.args[i + 1]))
473            continue
474        if arg == "--tested-apk-config":
475            f = ctx.fs.canonpath(cmd.args[i + 1])
476            __deps_configs(ctx, f, seen, inputs)
477            continue
478        for k in ["--deps-configs=", "--public-deps-configs=", "--annotation-processor-configs="]:
479            if arg.startswith(k):
480                arg = arg.removeprefix(k)
481                v = json.decode(arg)
482                for f in v:
483                    f = ctx.fs.canonpath(f)
484                    __deps_configs(ctx, f, seen, inputs)
485
486    ctx.actions.fix(inputs = cmd.inputs + inputs)
487
488__handlers = {
489    "android_compile_java": __android_compile_java_handler,
490    "android_compile_resources": __android_compile_resources_handler,
491    "android_dex": __android_dex_handler,
492    "android_proguard": __android_proguard_handler,
493    "android_turbine": __android_turbine_handler,
494    "android_write_build_config": __android_write_build_config_handler,
495}
496
497android = module(
498    "android",
499    enabled = __enabled,
500    archs = __archs,
501    step_config = __step_config,
502    filegroups = __filegroups,
503    handlers = __handlers,
504)
505