Work-around non-deterministic smali

Test: Local and remote RBE output is identical
Change-Id: Id89137a0cf1f1a60cf86856e042e306a297ab3c2
diff --git a/test/run_test_build.py b/test/run_test_build.py
index 36eddae..fa2e9d4 100755
--- a/test/run_test_build.py
+++ b/test/run_test_build.py
@@ -75,9 +75,11 @@
     self.javac_args = "-g -Xlint:-options"
 
     # Helper functions to execute tools.
+    self.d8_path = args.d8.absolute()
     self.d8 = functools.partial(self.run, args.d8.absolute())
     self.jasmin = functools.partial(self.run, args.jasmin.absolute())
     self.javac = functools.partial(self.run, self.javac_path)
+    self.smali_path = args.smali.absolute()
     self.smali = functools.partial(self.run, args.smali.absolute())
     self.soong_zip = functools.partial(self.run, args.soong_zip.absolute())
     self.zipalign = functools.partial(self.run, args.zipalign.absolute())
@@ -189,12 +191,38 @@
       d8_path] + args, inputs)
 
   def rbe_smali(self, smali_path:Path, args):
-    inputs = set([smali_path.parent.parent / "framework/smali.jar"])
-    output = relpath(Path(args[args.index("--output") + 1]), self.rbe_exec_root)
-    return self.rbe_wrap([
-      "--output_files", output,
+    # The output of smali is non-deterministic, so create wrapper script,
+    # which runs D8 on the output to normalize it.
+    api = args[args.index("--api") + 1]
+    output = Path(args[args.index("--output") + 1])
+    wrapper = output.with_suffix(".sh")
+    wrapper.write_text('''
+      set -e
+      {smali} $@
+      mkdir dex_normalize
+      {d8} --min-api {api} --output dex_normalize {output}
+      cp dex_normalize/classes.dex {output}
+      rm -rf dex_normalize
+    '''.strip().format(
+      smali=relpath(self.smali_path, self.test_dir),
+      d8=relpath(self.d8_path, self.test_dir),
+      api=api,
+      output=relpath(output, self.test_dir),
+    ))
+
+    inputs = set([
+      wrapper,
+      self.smali_path,
+      self.smali_path.parent.parent / "framework/smali.jar",
+      self.d8_path,
+      self.d8_path.parent.parent / "framework/d8.jar",
+    ])
+    res = self.rbe_wrap([
+      "--output_files", relpath(output, self.rbe_exec_root),
       "--toolchain_inputs=prebuilts/jdk/jdk17/linux-x86/bin/java",
-      smali_path] + args, inputs)
+      "/bin/bash", wrapper] + args, inputs)
+    wrapper.unlink()
+    return res
 
   def build(self) -> None:
     script = self.test_dir / "build.py"