1# Copyright 2023 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Bazel Dex Commands.""" 16 17load("//rules:attrs.bzl", _attrs = "attrs") 18load("//rules:common.bzl", _common = "common") 19load("//rules:java.bzl", _java = "java") 20load("@bazel_skylib//lib:collections.bzl", "collections") 21load(":providers.bzl", "StarlarkAndroidDexInfo") 22load(":utils.bzl", "ANDROID_TOOLCHAIN_TYPE", "get_android_toolchain", "utils") 23 24_DEX_MEMORY = 4096 25_DEX_THREADS = 5 26 27_tristate = _attrs.tristate 28 29def _resource_set_for_monolithic_dexing(): 30 return {"cpu": _DEX_THREADS, "memory": _DEX_MEMORY} 31 32def _process_incremental_dexing( 33 ctx, 34 output, 35 deps = [], 36 runtime_jars = [], 37 dexopts = [], 38 main_dex_list = None, 39 min_sdk_version = 0, 40 proguarded_jar = None, 41 java_info = None, 42 desugar_dict = {}, 43 shuffle_jars = None, 44 dexbuilder = None, 45 dexbuilder_after_proguard = None, 46 dexmerger = None, 47 dexsharder = None, 48 toolchain_type = None): 49 info = _merge_infos(utils.collect_providers(StarlarkAndroidDexInfo, deps)) 50 incremental_dexopts = _filter_dexopts(dexopts, ctx.fragments.android.get_dexopts_supported_in_incremental_dexing) 51 inclusion_filter_jar = proguarded_jar 52 if not proguarded_jar: 53 dex_archives = [] 54 for jar in runtime_jars: 55 dex_archive = _get_dx_artifact(ctx, jar.basename + ".dex.zip") 56 _dex( 57 ctx, 58 input = desugar_dict[jar] if jar in desugar_dict else jar, 59 output = dex_archive, 60 incremental_dexopts = incremental_dexopts, 61 min_sdk_version = min_sdk_version, 62 dex_exec = dexbuilder, 63 toolchain_type = toolchain_type, 64 ) 65 dex_archives.append(dex_archive) 66 dex_archives += _to_dexed_classpath( 67 dex_archives_dict = {d.jar: d.dex for d in info.dex_archives_dict.get("".join(incremental_dexopts), depset()).to_list()}, 68 classpath = _filter(java_info.transitive_runtime_jars.to_list(), excludes = _get_library_r_jars(deps)), 69 runtime_jars = runtime_jars, 70 ) 71 else: 72 java_resource_jar = ctx.actions.declare_file(ctx.label.name + "_files/java_resources.jar") 73 if ctx.fragments.android.incremental_dexing_shards_after_proguard > 1: 74 dex_archives = _shard_proguarded_jar_and_dex( 75 ctx, 76 java_resource_jar = java_resource_jar, 77 num_shards = ctx.fragments.android.incremental_dexing_shards_after_proguard, 78 dexopts = incremental_dexopts, 79 proguarded_jar = proguarded_jar, 80 main_dex_list = main_dex_list, 81 min_sdk_version = min_sdk_version, 82 shuffle_jars = shuffle_jars, 83 dexbuilder_after_proguard = dexbuilder_after_proguard, 84 toolchain_type = toolchain_type, 85 ) 86 inclusion_filter_jar = None 87 else: 88 # No need to shuffle if there is only one shard 89 dex_archive = _get_dx_artifact(ctx, "classes.jar") 90 _dex( 91 ctx, 92 input = proguarded_jar, 93 output = dex_archive, 94 incremental_dexopts = incremental_dexopts, 95 min_sdk_version = min_sdk_version, 96 dex_exec = dexbuilder_after_proguard, 97 toolchain_type = toolchain_type, 98 ) 99 dex_archives = [dex_archive] 100 101 if len(dex_archives) == 1: 102 _dex_merge( 103 ctx, 104 output = output, 105 inputs = dex_archives, 106 multidex_strategy = "minimal", 107 main_dex_list = main_dex_list, 108 dexopts = _filter_dexopts(dexopts, ctx.fragments.android.get_dexopts_supported_in_dex_merger), 109 dexmerger = dexmerger, 110 toolchain_type = toolchain_type, 111 ) 112 else: 113 shards = ctx.actions.declare_directory("dexsplits/" + ctx.label.name) 114 dexes = ctx.actions.declare_directory("dexfiles/" + ctx.label.name) 115 _shard_dexes( 116 ctx, 117 output = shards, 118 inputs = dex_archives, 119 dexopts = _filter_dexopts(dexopts, ctx.fragments.android.get_dexopts_supported_in_dex_sharder), 120 main_dex_list = main_dex_list, 121 inclusion_filter_jar = inclusion_filter_jar, 122 dexsharder = dexsharder, 123 toolchain_type = toolchain_type, 124 ) 125 126 # TODO(b/130571505): Implement this after SpawnActionTemplate is supported in Starlark 127 android_common.create_dex_merger_actions( 128 ctx, 129 output = dexes, 130 input = shards, 131 dexopts = dexopts, 132 dexmerger = dexmerger, 133 ) 134 _java.singlejar( 135 ctx, 136 output = output, 137 inputs = [dexes], 138 mnemonic = "MergeDexZips", 139 progress_message = "Merging dex shards for %s." % ctx.label, 140 java_toolchain = _common.get_java_toolchain(ctx), 141 ) 142 143def _process_optimized_dexing( 144 ctx, 145 output, 146 input = None, 147 proguard_output_map = None, 148 postprocessing_output_map = None, 149 dexopts = [], 150 native_multidex = True, 151 min_sdk_version = 0, 152 main_dex_list = None, 153 library_jar = None, 154 startup_profile = None, 155 optimizing_dexer = None, 156 toolchain_type = None): 157 inputs = [input] 158 outputs = [output] 159 160 args = ctx.actions.args() 161 args.add(input) 162 args.add("--release") 163 args.add("--no-desugaring") 164 args.add("--output", output) 165 args.add_all(dexopts) 166 167 if proguard_output_map: 168 args.add("--pg-map", proguard_output_map) 169 args.add("--pg-map-output", postprocessing_output_map) 170 inputs.append(proguard_output_map) 171 outputs.append(postprocessing_output_map) 172 173 if startup_profile and native_multidex: 174 args.add("--startup-profile", startup_profile) 175 inputs.append(startup_profile) 176 177 # TODO(b/261110876): Pass min SDK through here based on the value in the merged manifest. The 178 # current value is statically defined for the entire depot. 179 # We currently set the minimum SDK version to 21 if you are doing native multidex as that is 180 # required for native multidex to work in the first place and as a result is required for 181 # correct behavior from the dexer. 182 sdk = max(min_sdk_version, 21) if native_multidex else min_sdk_version 183 if sdk != 0: 184 args.add("--min-api", sdk) 185 if main_dex_list: 186 args.add("--main-dex-list", main_dex_list) 187 inputs.append(main_dex_list) 188 if library_jar: 189 args.add("--lib", library_jar) 190 inputs.append(library_jar) 191 192 ctx.actions.run( 193 outputs = outputs, 194 executable = optimizing_dexer, 195 inputs = inputs, 196 arguments = [args], 197 mnemonic = "OptimizingDex", 198 progress_message = "Optimized dexing for " + str(ctx.label), 199 use_default_shell_env = True, 200 toolchain = toolchain_type, 201 ) 202 203def _process_monolithic_dexing( 204 ctx, 205 output, 206 input, 207 dexopts = [], 208 min_sdk_version = 0, 209 main_dex_list = None, 210 dexbuilder = None, 211 toolchain_type = None): 212 # Create an artifact for the intermediate zip output generated by AndroidDexer that includes 213 # non-.dex files. A subsequent TrimDexZip action will filter out all non-.dex files. 214 classes_dex_intermediate = _get_dx_artifact(ctx, "intermediate_classes.dex.zip") 215 inputs = [input] 216 217 args = ctx.actions.args() 218 args.add("--dex") 219 args.add_all(dexopts) 220 if min_sdk_version > 0: 221 args.add("--min_sdk_version", min_sdk_version) 222 args.add("--multi-dex") 223 if main_dex_list: 224 args.add(main_dex_list, format = "--main-dex-list=%s") 225 inputs.append(main_dex_list) 226 args.add(classes_dex_intermediate, format = "--output=%s") 227 args.add(input) 228 229 ctx.actions.run( 230 executable = dexbuilder, 231 inputs = inputs, 232 outputs = [classes_dex_intermediate], 233 arguments = [args], 234 progress_message = "Converting %s to dex format" % input.short_path, 235 mnemonic = "AndroidDexer", 236 use_default_shell_env = True, 237 resource_set = _resource_set_for_monolithic_dexing, 238 toolchain = toolchain_type, 239 ) 240 241 # Because the dexer also places resources into this zip, we also need to create a cleanup 242 # action that removes all non-.dex files before staging for apk building. 243 _java.singlejar( 244 ctx, 245 inputs = [classes_dex_intermediate], 246 output = output, 247 include_prefixes = ["classes"], 248 java_toolchain = _common.get_java_toolchain(ctx), 249 mnemonic = "TrimDexZip", 250 progress_message = "Trimming %s." % classes_dex_intermediate.short_path, 251 ) 252 253def _shard_proguarded_jar_and_dex( 254 ctx, 255 java_resource_jar, 256 num_shards = 50, 257 dexopts = [], 258 proguarded_jar = None, 259 main_dex_list = None, 260 min_sdk_version = 0, 261 shuffle_jars = None, 262 dexbuilder_after_proguard = None, 263 toolchain_type = None): 264 if num_shards <= 1: 265 fail("num_shards expects to be larger than 1.") 266 267 shards = _make_shard_artifacts(ctx, num_shards, ".jar.dex.zip") 268 shuffle_outputs = _make_shard_artifacts(ctx, num_shards, ".jar") 269 inputs = [] 270 args = ctx.actions.args() 271 args.add_all(shuffle_outputs, before_each = "--output_jar") 272 args.add("--output_resources", java_resource_jar) 273 274 if main_dex_list: 275 args.add("--main_dex_filter", main_dex_list) 276 inputs.append(main_dex_list) 277 278 # If we need to run Proguard, all the class files will be in the Proguarded jar, which has to 279 # be converted to dex. 280 args.add("--input_jar", proguarded_jar) 281 inputs.append(proguarded_jar) 282 283 ctx.actions.run( 284 executable = shuffle_jars, 285 outputs = shuffle_outputs + [java_resource_jar], 286 inputs = inputs, 287 arguments = [args], 288 mnemonic = "ShardClassesToDex", 289 progress_message = "Sharding classes for dexing for " + str(ctx.label), 290 use_default_shell_env = True, 291 toolchain = toolchain_type, 292 ) 293 294 for i in range(len(shards)): 295 _dex( 296 ctx, 297 input = shuffle_outputs[i], 298 output = shards[i], 299 incremental_dexopts = dexopts, 300 min_sdk_version = min_sdk_version, 301 dex_exec = dexbuilder_after_proguard, 302 toolchain_type = toolchain_type, 303 ) 304 return shards 305 306def _make_shard_artifacts(ctx, n, suffix): 307 return [_get_dx_artifact(ctx, "shard" + str(i) + suffix) for i in range(1, n + 1)] 308 309def _shard_dexes( 310 ctx, 311 output, 312 inputs = [], 313 dexopts = [], 314 main_dex_list = None, 315 inclusion_filter_jar = None, 316 dexsharder = None, 317 toolchain_type = None): 318 args = ctx.actions.args().use_param_file(param_file_arg = "@%s") 319 args.add_all(inputs, before_each = "--input") 320 args.add("--output", output.path) 321 if main_dex_list: 322 inputs.append(main_dex_list) 323 args.add("--main-dex-list", main_dex_list) 324 if inclusion_filter_jar: 325 inputs.append(inclusion_filter_jar) 326 args.add("--inclusion_filter_jar", inclusion_filter_jar) 327 328 args.add_all(dexopts) 329 330 ctx.actions.run( 331 executable = dexsharder, 332 outputs = [output], 333 inputs = inputs, 334 arguments = [args], 335 mnemonic = "ShardForMultidex", 336 progress_message = "Assembling dex files for " + ctx.label.name, 337 use_default_shell_env = True, 338 toolchain = toolchain_type, 339 ) 340 341 return output 342 343def _append_java8_legacy_dex( 344 ctx, 345 output = None, 346 input = None, 347 java8_legacy_dex = None, 348 dex_zips_merger = None): 349 args = ctx.actions.args() 350 351 # Order matters here: we want java8_legacy_dex to be the highest-numbered classesN.dex 352 args.add("--input_zip", input) 353 args.add("--input_zip", java8_legacy_dex) 354 args.add("--output_zip", output) 355 356 ctx.actions.run( 357 executable = dex_zips_merger, 358 inputs = [input, java8_legacy_dex], 359 outputs = [output], 360 arguments = [args], 361 mnemonic = "AppendJava8LegacyDex", 362 use_default_shell_env = True, 363 progress_message = "Adding Java8 legacy library for %s" % ctx.label, 364 toolchain = ANDROID_TOOLCHAIN_TYPE, 365 ) 366 367def _to_dexed_classpath(dex_archives_dict = {}, classpath = [], runtime_jars = []): 368 dexed_classpath = [] 369 for jar in classpath: 370 if jar not in dex_archives_dict: 371 if jar not in runtime_jars: 372 fail("Dependencies on .jar artifacts are not allowed in Android binaries, please use " + 373 "a java_import to depend on " + jar.short_path + 374 ". If this is an implicit dependency then the rule that " + 375 "introduces it will need to be fixed to account for it correctly.") 376 else: 377 dexed_classpath.append(dex_archives_dict[jar]) 378 return dexed_classpath 379 380def _dex( 381 ctx, 382 input, 383 output = None, 384 incremental_dexopts = [], 385 min_sdk_version = 0, 386 dex_exec = None, 387 toolchain_type = None): 388 """Dexes a JAR. 389 390 Args: 391 ctx: The context. 392 input: File. The jar to be dexed. 393 output: File. The archive file containing all of the dexes. 394 incremental_dexopts: List of strings. Additional command-line flags for the dexing tool when building dexes. 395 min_sdk_version: Integer. The minimum targeted sdk version. 396 dex_exec: File. The executable dex builder file. 397 """ 398 args = ctx.actions.args() 399 args.use_param_file("@%s", use_always = True) # Required for workers. 400 args.set_param_file_format("multiline") 401 402 args.add("--input_jar", input) 403 args.add("--output_zip", output) 404 args.add_all(incremental_dexopts) 405 406 if min_sdk_version > 0: 407 args.add("--min_sdk_version", min_sdk_version) 408 409 execution_requirements = {} 410 if ctx.fragments.android.persistent_android_dex_desugar: 411 execution_requirements["supports-workers"] = "1" 412 if ctx.fragments.android.persistent_multiplex_android_dex_desugar: 413 execution_requirements["supports-multiplex-workers"] = "1" 414 415 ctx.actions.run( 416 executable = dex_exec, 417 arguments = [args], 418 inputs = [input], 419 outputs = [output], 420 mnemonic = "DexBuilder", 421 progress_message = "Dexing " + input.path + " with applicable dexopts " + str(incremental_dexopts), 422 execution_requirements = execution_requirements, 423 toolchain = toolchain_type, 424 ) 425 426def _get_dx_artifact(ctx, basename): 427 return ctx.actions.declare_file("_dx_migrated/" + ctx.label.name + "/" + basename) 428 429def _get_effective_incremental_dexing( 430 force_incremental_dexing = _tristate.auto, 431 has_forbidden_dexopts = False, 432 incremental_dexing_after_proguard_by_default = True, 433 incremental_dexing_shards_after_proguard = True, 434 is_binary_optimized = False, 435 use_incremental_dexing = True): 436 if (is_binary_optimized and 437 force_incremental_dexing == _tristate.yes and incremental_dexing_shards_after_proguard <= 0): 438 fail("Target cannot be incrementally dexed because it uses Proguard") 439 440 if force_incremental_dexing == _tristate.yes: 441 return True 442 443 if force_incremental_dexing == _tristate.no: 444 return False 445 446 # If there are incompatible dexopts and the incremental_dexing attr is not set, we silently don't run 447 # incremental dexing. 448 if has_forbidden_dexopts or (is_binary_optimized and not incremental_dexing_after_proguard_by_default): 449 return False 450 451 # use_incremental_dexing config flag will take effect if incremental_dexing attr is not set 452 return use_incremental_dexing 453 454def _get_java8_legacy_dex_and_map(ctx, build_customized_files = False, binary_jar = None, android_jar = None): 455 if not build_customized_files: 456 return utils.only(get_android_toolchain(ctx).java8_legacy_dex.files.to_list()), None 457 else: 458 java8_legacy_dex_rules = _get_dx_artifact(ctx, "_java8_legacy.dex.pgcfg") 459 java8_legacy_dex_map = _get_dx_artifact(ctx, "_java8_legacy.dex.map") 460 java8_legacy_dex = _get_dx_artifact(ctx, "_java8_legacy.dex.zip") 461 462 args = ctx.actions.args() 463 args.add("--rules", java8_legacy_dex_rules) 464 args.add("--binary", binary_jar) 465 args.add("--android_jar", android_jar) 466 args.add("--output", java8_legacy_dex) 467 args.add("--output_map", java8_legacy_dex_map) 468 469 ctx.actions.run( 470 executable = get_android_toolchain(ctx).build_java8_legacy_dex.files_to_run, 471 inputs = [binary_jar, android_jar], 472 outputs = [java8_legacy_dex_rules, java8_legacy_dex_map, java8_legacy_dex], 473 arguments = [args], 474 mnemonic = "BuildLegacyDex", 475 progress_message = "Building Java8 legacy library for %s" % ctx.label, 476 toolchain = ANDROID_TOOLCHAIN_TYPE, 477 ) 478 479 return java8_legacy_dex, java8_legacy_dex_map 480 481def _get_library_r_jars(deps): 482 transitive_resource_jars = [] 483 for dep in utils.collect_providers(AndroidLibraryResourceClassJarProvider, deps): 484 transitive_resource_jars += dep.jars.to_list() 485 return transitive_resource_jars 486 487def _dex_merge( 488 ctx, 489 output = None, 490 inputs = [], 491 multidex_strategy = "minimal", 492 main_dex_list = None, 493 dexopts = [], 494 dexmerger = None, 495 toolchain_type = None): 496 args = ctx.actions.args() 497 args.add("--multidex", multidex_strategy) 498 args.add_all(inputs, before_each = "--input") 499 args.add("--output", output) 500 args.add_all(dexopts) 501 502 if main_dex_list: 503 inputs.append(main_dex_list) 504 args.add("--main-dex-list", main_dex_list) 505 506 ctx.actions.run( 507 executable = dexmerger, 508 arguments = [args], 509 inputs = inputs, 510 outputs = [output], 511 mnemonic = "DexMerger", 512 progress_message = "Assembling dex files into " + output.short_path, 513 toolchain = toolchain_type, 514 ) 515 516def _merge_infos(infos): 517 dex_archives_dict = {} 518 for info in infos: 519 for dexopts in info.dex_archives_dict: 520 if dexopts not in dex_archives_dict: 521 dex_archives_dict[dexopts] = [info.dex_archives_dict[dexopts]] 522 else: 523 dex_archives_dict[dexopts].append(info.dex_archives_dict[dexopts]) 524 return StarlarkAndroidDexInfo( 525 dex_archives_dict = 526 {dexopts: depset(direct = [], transitive = dex_archives) for dexopts, dex_archives in dex_archives_dict.items()}, 527 ) 528 529def _filter_dexopts(tokenized_dexopts, includes): 530 return _normalize_dexopts(_filter(tokenized_dexopts, includes = includes)) 531 532def _filter(candidates, includes = [], excludes = []): 533 if excludes and includes: 534 fail("Only one of excludes list and includes list can be set.") 535 if includes: 536 return [c for c in candidates if c in includes] 537 if excludes: 538 return [c for c in candidates if c not in excludes] 539 return candidates 540 541def _normalize_dexopts(tokenized_dexopts): 542 def _dx_to_dexbuilder(opt): 543 return opt.replace("--no-", "--no") 544 545 return collections.uniq(sorted([_dx_to_dexbuilder(token) for token in tokenized_dexopts])) 546 547def _generate_main_dex_list( 548 ctx, 549 jar, 550 android_jar = None, 551 desugar_java8_libs = True, 552 main_dex_classes = None, 553 main_dex_list_opts = [], 554 main_dex_proguard_spec = None, 555 proguard_specs = [], 556 legacy_apis = [], 557 shrinked_android_jar = None, 558 toolchain_type = None, 559 main_dex_list_creator = None, 560 legacy_main_dex_list_generator = None, 561 proguard_tool = None): 562 main_dex_list = _get_dx_artifact(ctx, "main_dex_list.txt") 563 if not proguard_specs: 564 proguard_specs.append(main_dex_classes) 565 if main_dex_proguard_spec: 566 proguard_specs.append(main_dex_proguard_spec) 567 568 # If legacy_main_dex_list_generator is not set by either the SDK or the flag, use ProGuard and 569 # the main dext list creator specified by the android_sdk rule. If 570 # legacy_main_dex_list_generator is provided, use that tool instead. 571 # TODO(b/147692286): Remove the old main-dex list generation that relied on ProGuard. 572 if not legacy_main_dex_list_generator: 573 if not shrinked_android_jar: 574 fail("In \"legacy\" multidex mode, either legacy_main_dex_list_generator or " + 575 "shrinked_android_jar must be set in the android_sdk.") 576 577 # Process the input jar through Proguard into an intermediate, streamlined jar. 578 stripped_jar = _get_dx_artifact(ctx, "main_dex_intermediate.jar") 579 args = ctx.actions.args() 580 args.add("-forceprocessing") 581 args.add("-injars", jar) 582 args.add("-libraryjars", shrinked_android_jar) 583 args.add("-outjars", stripped_jar) 584 args.add("-dontwarn") 585 args.add("-dontnote") 586 args.add("-dontoptimize") 587 args.add("-dontobfuscate") 588 ctx.actions.run( 589 outputs = [stripped_jar], 590 executable = proguard_tool, 591 args = [args], 592 inputs = [jar, shrinked_android_jar], 593 mnemonic = "MainDexClassesIntermediate", 594 progress_message = "Generating streamlined input jar for main dex classes list", 595 use_default_shell_dev = True, 596 toolchain = toolchain_type, 597 ) 598 599 args = ctx.actions.args() 600 args.add_all([main_dex_list, stripped_jar, jar]) 601 args.add_all(main_dex_list_opts) 602 603 ctx.actions.run( 604 outputs = [main_dex_list], 605 executable = main_dex_list_creator, 606 arguments = [args], 607 inputs = [jar, stripped_jar], 608 mnemonic = "MainDexClasses", 609 progress_message = "Generating main dex classes list", 610 toolchain = toolchain_type, 611 ) 612 else: 613 inputs = [jar, android_jar] + proguard_specs 614 615 args = ctx.actions.args() 616 args.add("--main-dex-list-output", main_dex_list) 617 args.add("--lib", android_jar) 618 if desugar_java8_libs: 619 args.add_all(legacy_apis, before_each = "--lib") 620 inputs += legacy_apis 621 args.add_all(proguard_specs, before_each = "--main-dex-rules") 622 args.add(jar) 623 ctx.actions.run( 624 executable = legacy_main_dex_list_generator, 625 arguments = [args], 626 outputs = [main_dex_list], 627 inputs = inputs, 628 mnemonic = "MainDexClasses", 629 progress_message = "Generating main dex classes list", 630 toolchain = toolchain_type, 631 ) 632 return main_dex_list 633 634def _transform_dex_list_through_proguard_map( 635 ctx, 636 proguard_output_map = None, 637 main_dex_list = None, 638 toolchain_type = None, 639 dex_list_obfuscator = None): 640 if not proguard_output_map: 641 return main_dex_list 642 643 obfuscated_main_dex_list = _get_dx_artifact(ctx, "main_dex_list_obfuscated.txt") 644 645 args = ctx.actions.args() 646 args.add("--input", main_dex_list) 647 args.add("--output", obfuscated_main_dex_list) 648 args.add("--obfuscation_map", proguard_output_map) 649 ctx.actions.run( 650 executable = dex_list_obfuscator, 651 arguments = [args], 652 outputs = [obfuscated_main_dex_list], 653 inputs = [main_dex_list], 654 mnemonic = "MainDexProguardClasses", 655 progress_message = "Obfuscating main dex classes list", 656 toolchain = toolchain_type, 657 ) 658 659 return obfuscated_main_dex_list 660 661dex = struct( 662 append_java8_legacy_dex = _append_java8_legacy_dex, 663 dex = _dex, 664 dex_merge = _dex_merge, 665 generate_main_dex_list = _generate_main_dex_list, 666 get_dx_artifact = _get_dx_artifact, 667 get_effective_incremental_dexing = _get_effective_incremental_dexing, 668 get_java8_legacy_dex_and_map = _get_java8_legacy_dex_and_map, 669 filter_dexopts = _filter_dexopts, 670 merge_infos = _merge_infos, 671 normalize_dexopts = _normalize_dexopts, 672 process_monolithic_dexing = _process_monolithic_dexing, 673 process_incremental_dexing = _process_incremental_dexing, 674 process_optimized_dexing = _process_optimized_dexing, 675 transform_dex_list_through_proguard_map = _transform_dex_list_through_proguard_map, 676) 677