David Srbecky | 8106b38 | 2022-04-20 13:37:15 +0100 | [diff] [blame] | 1 | # |
| 2 | # Copyright (C) 2021 The Android Open Source Project |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
| 15 | |
| 16 | """This is the default build script for run-tests. |
| 17 | |
| 18 | It can be overwrite by specific run-tests if needed. |
| 19 | It is used from soong build and not intended to be called directly. |
| 20 | """ |
| 21 | |
| 22 | import argparse |
| 23 | import functools |
| 24 | import glob |
| 25 | import os |
| 26 | from os import path |
| 27 | import shlex |
| 28 | import shutil |
| 29 | import subprocess |
| 30 | import tempfile |
| 31 | import zipfile |
| 32 | from shutil import rmtree |
| 33 | from os import remove |
| 34 | |
David Srbecky | e9142f2 | 2022-08-03 11:05:19 +0100 | [diff] [blame] | 35 | USE_RBE_FOR_JAVAC = 100 # Percentage of tests that can use RBE (between 0 and 100) |
| 36 | USE_RBE_FOR_D8 = 100 # Percentage of tests that can use RBE (between 0 and 100) |
David Srbecky | 89010a3 | 2022-07-14 16:47:30 +0000 | [diff] [blame] | 37 | |
David Srbecky | 8106b38 | 2022-04-20 13:37:15 +0100 | [diff] [blame] | 38 | def rm(*patterns): |
| 39 | for pattern in patterns: |
| 40 | for path in glob.glob(pattern): |
| 41 | if os.path.isdir(path): |
| 42 | shutil.rmtree(path) |
| 43 | else: |
| 44 | os.remove(path) |
| 45 | |
| 46 | def build_run_test( |
| 47 | use_desugar=True, |
| 48 | use_hiddenapi=True, |
| 49 | need_dex=None, |
| 50 | experimental="no-experiment", |
| 51 | zip_compression_method="deflate", |
| 52 | zip_align_bytes=None, |
| 53 | api_level=None, |
| 54 | javac_args=[], |
| 55 | d8_flags=[], |
| 56 | smali_args=[], |
| 57 | has_smali=None, |
| 58 | has_jasmin=None, |
| 59 | ): |
| 60 | |
| 61 | def parse_bool(text): |
| 62 | return {"true": True, "false": False}[text.lower()] |
| 63 | |
David Srbecky | 89010a3 | 2022-07-14 16:47:30 +0000 | [diff] [blame] | 64 | ANDROID_BUILD_TOP = os.environ["ANDROID_BUILD_TOP"] |
| 65 | SBOX_PATH = os.environ["SBOX_PATH"] |
| 66 | CWD = os.getcwd() |
David Srbecky | 8106b38 | 2022-04-20 13:37:15 +0100 | [diff] [blame] | 67 | TEST_NAME = os.environ["TEST_NAME"] |
David Srbecky | 89010a3 | 2022-07-14 16:47:30 +0000 | [diff] [blame] | 68 | ART_TEST_RUN_TEST_BOOTCLASSPATH = path.relpath(os.environ["ART_TEST_RUN_TEST_BOOTCLASSPATH"], CWD) |
David Srbecky | 8106b38 | 2022-04-20 13:37:15 +0100 | [diff] [blame] | 69 | NEED_DEX = parse_bool(os.environ["NEED_DEX"]) if need_dex is None else need_dex |
| 70 | |
David Srbecky | 89010a3 | 2022-07-14 16:47:30 +0000 | [diff] [blame] | 71 | RBE_exec_root = os.environ.get("RBE_exec_root") |
| 72 | RBE_rewrapper = path.join(ANDROID_BUILD_TOP, "prebuilts/remoteexecution-client/live/rewrapper") |
| 73 | |
David Srbecky | 8106b38 | 2022-04-20 13:37:15 +0100 | [diff] [blame] | 74 | # Set default values for directories. |
| 75 | HAS_SMALI = path.exists("smali") if has_smali is None else has_smali |
| 76 | HAS_JASMIN = path.exists("jasmin") if has_jasmin is None else has_jasmin |
| 77 | HAS_SRC = path.exists("src") |
| 78 | HAS_SRC_ART = path.exists("src-art") |
| 79 | HAS_SRC2 = path.exists("src2") |
| 80 | HAS_SRC_MULTIDEX = path.exists("src-multidex") |
| 81 | HAS_SMALI_MULTIDEX = path.exists("smali-multidex") |
| 82 | HAS_JASMIN_MULTIDEX = path.exists("jasmin-multidex") |
| 83 | HAS_SMALI_EX = path.exists("smali-ex") |
| 84 | HAS_SRC_EX = path.exists("src-ex") |
| 85 | HAS_SRC_EX2 = path.exists("src-ex2") |
| 86 | HAS_SRC_AOTEX = path.exists("src-aotex") |
| 87 | HAS_SRC_BCPEX = path.exists("src-bcpex") |
| 88 | HAS_HIDDENAPI_SPEC = path.exists("hiddenapi-flags.csv") |
| 89 | |
| 90 | JAVAC_ARGS = shlex.split(os.environ.get("JAVAC_ARGS", "")) + javac_args |
| 91 | SMALI_ARGS = shlex.split(os.environ.get("SMALI_ARGS", "")) + smali_args |
| 92 | D8_FLAGS = shlex.split(os.environ.get("D8_FLAGS", "")) + d8_flags |
| 93 | |
| 94 | BUILD_MODE = os.environ["BUILD_MODE"] |
| 95 | |
| 96 | # Setup experimental API level mappings in a bash associative array. |
| 97 | EXPERIMENTAL_API_LEVEL = {} |
| 98 | EXPERIMENTAL_API_LEVEL["no-experiment"] = "26" |
| 99 | EXPERIMENTAL_API_LEVEL["default-methods"] = "24" |
| 100 | EXPERIMENTAL_API_LEVEL["parameter-annotations"] = "25" |
| 101 | EXPERIMENTAL_API_LEVEL["agents"] = "26" |
| 102 | EXPERIMENTAL_API_LEVEL["method-handles"] = "26" |
| 103 | EXPERIMENTAL_API_LEVEL["var-handles"] = "28" |
| 104 | |
| 105 | if BUILD_MODE == "jvm": |
| 106 | # No desugaring on jvm because it supports the latest functionality. |
| 107 | use_desugar = False |
| 108 | # Do not attempt to build src-art directories on jvm, |
| 109 | # since it would fail without libcore. |
| 110 | HAS_SRC_ART = False |
| 111 | |
| 112 | # Set API level for smali and d8. |
| 113 | if not api_level: |
| 114 | api_level = EXPERIMENTAL_API_LEVEL[experimental] |
| 115 | |
| 116 | # Add API level arguments to smali and dx |
| 117 | SMALI_ARGS.extend(["--api", str(api_level)]) |
| 118 | D8_FLAGS.extend(["--min-api", str(api_level)]) |
| 119 | |
| 120 | |
| 121 | def run(executable, args): |
| 122 | cmd = shlex.split(executable) + args |
| 123 | if executable.endswith(".sh"): |
| 124 | cmd = ["/bin/bash"] + cmd |
| 125 | p = subprocess.run(cmd, |
| 126 | encoding=os.sys.stdout.encoding, |
| 127 | stderr=subprocess.STDOUT, |
| 128 | stdout=subprocess.PIPE) |
| 129 | if p.returncode != 0: |
| 130 | raise Exception("Command failed with exit code {}\n$ {}\n{}".format( |
| 131 | p.returncode, " ".join(cmd), p.stdout)) |
| 132 | |
| 133 | |
| 134 | # Helper functions to execute tools. |
| 135 | soong_zip = functools.partial(run, os.environ["SOONG_ZIP"]) |
| 136 | zipalign = functools.partial(run, os.environ["ZIPALIGN"]) |
| 137 | javac = functools.partial(run, os.environ["JAVAC"]) |
| 138 | jasmin = functools.partial(run, os.environ["JASMIN"]) |
| 139 | smali = functools.partial(run, os.environ["SMALI"]) |
| 140 | d8 = functools.partial(run, os.environ["D8"]) |
| 141 | hiddenapi = functools.partial(run, os.environ["HIDDENAPI"]) |
| 142 | |
David Srbecky | 89010a3 | 2022-07-14 16:47:30 +0000 | [diff] [blame] | 143 | if "RBE_server_address" in os.environ: |
| 144 | def rbe_wrap(args, inputs=set()): |
| 145 | with tempfile.NamedTemporaryFile(mode="w+t", dir=RBE_exec_root) as input_list: |
| 146 | for arg in args: |
| 147 | inputs.update(filter(path.exists, arg.split(":"))) |
| 148 | input_list.writelines([path.relpath(i, RBE_exec_root)+"\n" for i in inputs]) |
| 149 | input_list.flush() |
| 150 | return run(RBE_rewrapper, [ |
| 151 | "--platform=" + os.environ["RBE_platform"], |
| 152 | "--input_list_paths=" + input_list.name, |
| 153 | ] + args) |
| 154 | |
| 155 | if USE_RBE_FOR_JAVAC > (hash(TEST_NAME) % 100): # Use for given percentage of tests. |
| 156 | def javac(args): |
| 157 | output = path.relpath(path.join(CWD, args[args.index("-d") + 1]), RBE_exec_root) |
| 158 | return rbe_wrap([ |
| 159 | "--output_directories", output, |
| 160 | os.path.relpath(os.environ["JAVAC"], CWD), |
| 161 | ] + args) |
| 162 | |
| 163 | if USE_RBE_FOR_D8 > (hash(TEST_NAME) % 100): # Use for given percentage of tests. |
| 164 | def d8(args): |
| 165 | inputs = set([path.join(SBOX_PATH, "tools/out/framework/d8.jar")]) |
| 166 | output = path.relpath(path.join(CWD, args[args.index("--output") + 1]), RBE_exec_root) |
| 167 | return rbe_wrap([ |
| 168 | "--output_files" if output.endswith(".jar") else "--output_directories", output, |
| 169 | "--toolchain_inputs=prebuilts/jdk/jdk11/linux-x86/bin/java" |
| 170 | # TODO(dsrbecky): Work around bug b/227376947 ; Remove this when it is fixed. |
| 171 | + ",../../../../../../../../prebuilts/jdk/jdk11/linux-x86/bin/java", |
| 172 | os.path.relpath(os.environ["D8"], CWD)] + args, inputs) |
| 173 | |
David Srbecky | 8106b38 | 2022-04-20 13:37:15 +0100 | [diff] [blame] | 174 | # If wrapper script exists, use it instead of the default javac. |
| 175 | if os.path.exists("javac_wrapper.sh"): |
| 176 | javac = functools.partial(run, "javac_wrapper.sh") |
| 177 | |
| 178 | def find(root, name): |
| 179 | return sorted(glob.glob(path.join(root, "**", name), recursive=True)) |
| 180 | |
| 181 | |
| 182 | def zip(zip_target, *files): |
| 183 | zip_args = ["-o", zip_target] |
| 184 | if zip_compression_method == "store": |
| 185 | zip_args.extend(["-L", "0"]) |
| 186 | for f in files: |
| 187 | zip_args.extend(["-f", f]) |
| 188 | soong_zip(zip_args) |
| 189 | |
| 190 | if zip_align_bytes: |
| 191 | # zipalign does not operate in-place, so write results to a temp file. |
| 192 | with tempfile.TemporaryDirectory(dir=".") as tmp_dir: |
| 193 | tmp_file = path.join(tmp_dir, "aligned.zip") |
| 194 | zipalign(["-f", str(zip_align_bytes), zip_target, tmp_file]) |
| 195 | # replace original zip target with our temp file. |
| 196 | os.rename(tmp_file, zip_target) |
| 197 | |
| 198 | |
| 199 | def make_jasmin(out_directory, jasmin_sources): |
| 200 | os.makedirs(out_directory, exist_ok=True) |
| 201 | jasmin(["-d", out_directory] + sorted(jasmin_sources)) |
| 202 | |
| 203 | |
| 204 | # Like regular javac but may include libcore on the bootclasspath. |
| 205 | def javac_with_bootclasspath(args): |
| 206 | flags = JAVAC_ARGS + ["-encoding", "utf8"] |
| 207 | if BUILD_MODE != "jvm": |
| 208 | flags.extend(["-bootclasspath", ART_TEST_RUN_TEST_BOOTCLASSPATH]) |
| 209 | javac(flags + args) |
| 210 | |
| 211 | |
| 212 | # Make a "dex" file given a directory of classes. This will be |
| 213 | # packaged in a jar file. |
| 214 | def make_dex(name): |
| 215 | d8_inputs = find(name, "*.class") |
| 216 | d8_output = name + ".jar" |
| 217 | dex_output = name + ".dex" |
| 218 | if use_desugar: |
| 219 | flags = ["--lib", ART_TEST_RUN_TEST_BOOTCLASSPATH] |
| 220 | else: |
| 221 | flags = ["--no-desugaring"] |
| 222 | assert d8_inputs |
| 223 | d8(D8_FLAGS + flags + ["--output", d8_output] + d8_inputs) |
| 224 | |
| 225 | # D8 outputs to JAR files today rather than DEX files as DX used |
| 226 | # to. To compensate, we extract the DEX from d8's output to meet the |
| 227 | # expectations of make_dex callers. |
| 228 | with tempfile.TemporaryDirectory(dir=".") as tmp_dir: |
| 229 | zipfile.ZipFile(d8_output, "r").extractall(tmp_dir) |
| 230 | os.rename(path.join(tmp_dir, "classes.dex"), dex_output) |
| 231 | |
| 232 | |
| 233 | # Merge all the dex files. |
| 234 | # Skip non-existing files, but at least 1 file must exist. |
| 235 | def make_dexmerge(*dex_files_to_merge): |
| 236 | # Dex file that acts as the destination. |
| 237 | dst_file = dex_files_to_merge[0] |
| 238 | |
| 239 | # Skip any non-existing files. |
| 240 | dex_files_to_merge = list(filter(path.exists, dex_files_to_merge)) |
| 241 | |
| 242 | # NB: We merge even if there is just single input. |
| 243 | # It is useful to normalize non-deterministic smali output. |
| 244 | |
David Srbecky | 89010a3 | 2022-07-14 16:47:30 +0000 | [diff] [blame] | 245 | tmp_dir = "dexmerge" |
| 246 | os.makedirs(tmp_dir) |
| 247 | d8(["--min-api", api_level, "--output", tmp_dir] + dex_files_to_merge) |
| 248 | assert not path.exists(path.join(tmp_dir, "classes2.dex")) |
| 249 | for input_dex in dex_files_to_merge: |
| 250 | os.remove(input_dex) |
| 251 | os.rename(path.join(tmp_dir, "classes.dex"), dst_file) |
| 252 | os.rmdir(tmp_dir) |
David Srbecky | 8106b38 | 2022-04-20 13:37:15 +0100 | [diff] [blame] | 253 | |
| 254 | |
| 255 | def make_hiddenapi(*dex_files): |
| 256 | args = ["encode"] |
| 257 | for dex_file in dex_files: |
| 258 | args.extend(["--input-dex=" + dex_file, "--output-dex=" + dex_file]) |
| 259 | args.append("--api-flags=hiddenapi-flags.csv") |
| 260 | args.append("--no-force-assign-all") |
| 261 | hiddenapi(args) |
| 262 | |
| 263 | |
| 264 | if path.exists("classes.dex"): |
| 265 | zip(TEST_NAME + ".jar", "classes.dex") |
| 266 | return |
| 267 | |
| 268 | |
| 269 | def has_multidex(): |
| 270 | return HAS_SRC_MULTIDEX or HAS_JASMIN_MULTIDEX or HAS_SMALI_MULTIDEX |
| 271 | |
| 272 | |
| 273 | def add_to_cp_args(old_cp_args, path): |
| 274 | if len(old_cp_args) == 0: |
| 275 | return ["-cp", path] |
| 276 | else: |
| 277 | return ["-cp", old_cp_args[1] + ":" + path] |
| 278 | |
| 279 | |
| 280 | src_tmp_all = [] |
| 281 | |
| 282 | if HAS_JASMIN: |
| 283 | make_jasmin("jasmin_classes", find("jasmin", "*.j")) |
| 284 | src_tmp_all = add_to_cp_args(src_tmp_all, "jasmin_classes") |
| 285 | |
| 286 | if HAS_JASMIN_MULTIDEX: |
| 287 | make_jasmin("jasmin_classes2", find("jasmin-multidex", "*.j")) |
| 288 | src_tmp_all = add_to_cp_args(src_tmp_all, "jasmin_classes2") |
| 289 | |
| 290 | if HAS_SRC and (HAS_SRC_MULTIDEX or HAS_SRC_AOTEX or HAS_SRC_BCPEX or |
| 291 | HAS_SRC_EX or HAS_SRC_ART or HAS_SRC2 or HAS_SRC_EX2): |
| 292 | # To allow circular references, compile src/, src-multidex/, src-aotex/, |
| 293 | # src-bcpex/, src-ex/ together and pass the output as class path argument. |
| 294 | # Replacement sources in src-art/, src2/ and src-ex2/ can replace symbols |
| 295 | # used by the other src-* sources we compile here but everything needed to |
| 296 | # compile the other src-* sources should be present in src/ (and jasmin*/). |
| 297 | os.makedirs("classes-tmp-all") |
| 298 | javac_with_bootclasspath(["-implicit:none"] + src_tmp_all + |
| 299 | ["-d", "classes-tmp-all"] + |
| 300 | find("src", "*.java") + |
| 301 | find("src-multidex", "*.java") + |
| 302 | find("src-aotex", "*.java") + |
| 303 | find("src-bcpex", "*.java") + |
| 304 | find("src-ex", "*.java")) |
| 305 | src_tmp_all = add_to_cp_args(src_tmp_all, "classes-tmp-all") |
| 306 | |
| 307 | if HAS_SRC_AOTEX: |
| 308 | os.makedirs("classes-aotex") |
| 309 | javac_with_bootclasspath(["-implicit:none"] + src_tmp_all + |
| 310 | ["-d", "classes-aotex"] + |
| 311 | find("src-aotex", "*.java")) |
| 312 | if NEED_DEX: |
| 313 | make_dex("classes-aotex") |
| 314 | # rename it so it shows up as "classes.dex" in the zip file. |
| 315 | os.rename("classes-aotex.dex", "classes.dex") |
| 316 | zip(TEST_NAME + "-aotex.jar", "classes.dex") |
| 317 | |
| 318 | if HAS_SRC_BCPEX: |
| 319 | os.makedirs("classes-bcpex") |
| 320 | javac_with_bootclasspath(["-implicit:none"] + src_tmp_all + |
| 321 | ["-d", "classes-bcpex"] + |
| 322 | find("src-bcpex", "*.java")) |
| 323 | if NEED_DEX: |
| 324 | make_dex("classes-bcpex") |
| 325 | # rename it so it shows up as "classes.dex" in the zip file. |
| 326 | os.rename("classes-bcpex.dex", "classes.dex") |
| 327 | zip(TEST_NAME + "-bcpex.jar", "classes.dex") |
| 328 | |
| 329 | if HAS_SRC: |
| 330 | os.makedirs("classes", exist_ok=True) |
| 331 | javac_with_bootclasspath(["-implicit:none"] + src_tmp_all + |
| 332 | ["-d", "classes"] + find("src", "*.java")) |
| 333 | |
| 334 | if HAS_SRC_ART: |
| 335 | os.makedirs("classes", exist_ok=True) |
| 336 | javac_with_bootclasspath(["-implicit:none"] + src_tmp_all + |
| 337 | ["-d", "classes"] + find("src-art", "*.java")) |
| 338 | |
| 339 | if HAS_SRC_MULTIDEX: |
| 340 | os.makedirs("classes2") |
| 341 | javac_with_bootclasspath(["-implicit:none"] + src_tmp_all + |
| 342 | ["-d", "classes2"] + |
| 343 | find("src-multidex", "*.java")) |
| 344 | if NEED_DEX: |
| 345 | make_dex("classes2") |
| 346 | |
| 347 | if HAS_SRC2: |
| 348 | os.makedirs("classes", exist_ok=True) |
| 349 | javac_with_bootclasspath(["-implicit:none"] + src_tmp_all + |
| 350 | ["-d", "classes"] + |
| 351 | find("src2", "*.java")) |
| 352 | |
| 353 | # If the classes directory is not-empty, package classes in a DEX file. |
| 354 | # NB: some tests provide classes rather than java files. |
| 355 | if find("classes", "*"): |
| 356 | if NEED_DEX: |
| 357 | make_dex("classes") |
| 358 | |
| 359 | if HAS_JASMIN: |
| 360 | # Compile Jasmin classes as if they were part of the classes.dex file. |
| 361 | if NEED_DEX: |
| 362 | make_dex("jasmin_classes") |
| 363 | make_dexmerge("classes.dex", "jasmin_classes.dex") |
| 364 | else: |
| 365 | # Move jasmin classes into classes directory so that they are picked up |
| 366 | # with -cp classes. |
| 367 | os.makedirs("classes", exist_ok=True) |
| 368 | shutil.copytree("jasmin_classes", "classes", dirs_exist_ok=True) |
| 369 | |
| 370 | if HAS_SMALI and NEED_DEX: |
| 371 | # Compile Smali classes |
| 372 | smali(["-JXmx512m", "assemble"] + SMALI_ARGS + |
| 373 | ["--output", "smali_classes.dex"] + find("smali", "*.smali")) |
| 374 | assert path.exists("smali_classes.dex") |
| 375 | # Merge smali files into classes.dex, |
| 376 | # this takes priority over any jasmin files. |
| 377 | make_dexmerge("classes.dex", "smali_classes.dex") |
| 378 | |
| 379 | # Compile Jasmin classes in jasmin-multidex as if they were part of |
| 380 | # the classes2.jar |
| 381 | if HAS_JASMIN_MULTIDEX: |
| 382 | if NEED_DEX: |
| 383 | make_dex("jasmin_classes2") |
| 384 | make_dexmerge("classes2.dex", "jasmin_classes2.dex") |
| 385 | else: |
| 386 | # Move jasmin classes into classes2 directory so that |
| 387 | # they are picked up with -cp classes2. |
| 388 | os.makedirs("classes2", exist_ok=True) |
| 389 | shutil.copytree("jasmin_classes2", "classes2", dirs_exist_ok=True) |
| 390 | shutil.rmtree("jasmin_classes2") |
| 391 | |
| 392 | if HAS_SMALI_MULTIDEX and NEED_DEX: |
| 393 | # Compile Smali classes |
| 394 | smali(["-JXmx512m", "assemble"] + SMALI_ARGS + |
| 395 | ["--output", "smali_classes2.dex"] + find("smali-multidex", "*.smali")) |
| 396 | |
| 397 | # Merge smali_classes2.dex into classes2.dex |
| 398 | make_dexmerge("classes2.dex", "smali_classes2.dex") |
| 399 | |
| 400 | if HAS_SRC_EX: |
| 401 | os.makedirs("classes-ex", exist_ok=True) |
| 402 | javac_with_bootclasspath(["-implicit:none"] + src_tmp_all + |
| 403 | ["-d", "classes-ex"] + find("src-ex", "*.java")) |
| 404 | |
| 405 | if HAS_SRC_EX2: |
| 406 | os.makedirs("classes-ex", exist_ok=True) |
| 407 | javac_with_bootclasspath(["-implicit:none"] + src_tmp_all + |
| 408 | ["-d", "classes-ex"] + find("src-ex2", "*.java")) |
| 409 | |
| 410 | if path.exists("classes-ex") and NEED_DEX: |
| 411 | make_dex("classes-ex") |
| 412 | |
| 413 | if HAS_SMALI_EX and NEED_DEX: |
| 414 | # Compile Smali classes |
| 415 | smali(["-JXmx512m", "assemble"] + SMALI_ARGS + |
| 416 | ["--output", "smali_classes-ex.dex"] + find("smali-ex", "*.smali")) |
| 417 | assert path.exists("smali_classes-ex.dex") |
| 418 | # Merge smali files into classes-ex.dex. |
| 419 | make_dexmerge("classes-ex.dex", "smali_classes-ex.dex") |
| 420 | |
| 421 | if path.exists("classes-ex.dex"): |
| 422 | # Apply hiddenapi on the dex files if the test has API list file(s). |
| 423 | if use_hiddenapi and HAS_HIDDENAPI_SPEC: |
| 424 | make_hiddenapi("classes-ex.dex") |
| 425 | |
| 426 | # quick shuffle so that the stored name is "classes.dex" |
| 427 | os.rename("classes.dex", "classes-1.dex") |
| 428 | os.rename("classes-ex.dex", "classes.dex") |
| 429 | zip(TEST_NAME + "-ex.jar", "classes.dex") |
| 430 | os.rename("classes.dex", "classes-ex.dex") |
| 431 | os.rename("classes-1.dex", "classes.dex") |
| 432 | |
| 433 | # Apply hiddenapi on the dex files if the test has API list file(s). |
| 434 | if NEED_DEX and use_hiddenapi and HAS_HIDDENAPI_SPEC: |
| 435 | if has_multidex(): |
| 436 | make_hiddenapi("classes.dex", "classes2.dex") |
| 437 | else: |
| 438 | make_hiddenapi("classes.dex") |
| 439 | |
| 440 | # Create a single dex jar with two dex files for multidex. |
| 441 | if NEED_DEX: |
| 442 | if path.exists("classes2.dex"): |
| 443 | zip(TEST_NAME + ".jar", "classes.dex", "classes2.dex") |
| 444 | else: |
| 445 | zip(TEST_NAME + ".jar", "classes.dex") |