diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/004-UnsafeTest/src/Main.java | 2 | ||||
| -rw-r--r-- | test/004-checker-UnsafeTest18/expected.txt | 2 | ||||
| -rw-r--r-- | test/004-checker-UnsafeTest18/info.txt | 1 | ||||
| -rw-r--r-- | test/004-checker-UnsafeTest18/src/Main.java | 270 | ||||
| -rw-r--r-- | test/145-alloc-tracking-stress/src/Main.java | 1 | ||||
| -rw-r--r-- | test/462-checker-inlining-across-dex-files/multidex.jpp | 8 | ||||
| -rw-r--r-- | test/556-invoke-super/multidex.jpp | 4 | ||||
| -rw-r--r-- | test/569-checker-pattern-replacement/multidex.jpp | 8 | ||||
| -rw-r--r-- | test/577-profile-foreign-dex/expected.txt | 0 | ||||
| -rw-r--r-- | test/577-profile-foreign-dex/info.txt | 1 | ||||
| -rw-r--r-- | test/577-profile-foreign-dex/run | 20 | ||||
| -rw-r--r-- | test/577-profile-foreign-dex/src-ex/OtherDex.java | 17 | ||||
| -rw-r--r-- | test/577-profile-foreign-dex/src/Main.java | 175 | ||||
| -rw-r--r-- | test/Android.run-test.mk | 4 | ||||
| -rwxr-xr-x | test/etc/default-build | 29 |
15 files changed, 527 insertions, 15 deletions
diff --git a/test/004-UnsafeTest/src/Main.java b/test/004-UnsafeTest/src/Main.java index a9a7a058e0..b2f905e0ee 100644 --- a/test/004-UnsafeTest/src/Main.java +++ b/test/004-UnsafeTest/src/Main.java @@ -40,7 +40,7 @@ public class Main { } private static Unsafe getUnsafe() throws Exception { - Class<?> unsafeClass = Class.forName("sun.misc.Unsafe"); + Class<?> unsafeClass = Unsafe.class; Field f = unsafeClass.getDeclaredField("theUnsafe"); f.setAccessible(true); return (Unsafe) f.get(null); diff --git a/test/004-checker-UnsafeTest18/expected.txt b/test/004-checker-UnsafeTest18/expected.txt new file mode 100644 index 0000000000..651da727af --- /dev/null +++ b/test/004-checker-UnsafeTest18/expected.txt @@ -0,0 +1,2 @@ +starting +passed diff --git a/test/004-checker-UnsafeTest18/info.txt b/test/004-checker-UnsafeTest18/info.txt new file mode 100644 index 0000000000..0fca5ebf03 --- /dev/null +++ b/test/004-checker-UnsafeTest18/info.txt @@ -0,0 +1 @@ +Test support for 1.8 sun.misc.Unsafe. diff --git a/test/004-checker-UnsafeTest18/src/Main.java b/test/004-checker-UnsafeTest18/src/Main.java new file mode 100644 index 0000000000..bb020b9b9f --- /dev/null +++ b/test/004-checker-UnsafeTest18/src/Main.java @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.lang.reflect.Field; + +import sun.misc.Unsafe; + +/** + * Checker test on the 1.8 unsafe operations. Note, this is by no means an + * exhaustive unit test for these CAS (compare-and-swap) and fence operations. + * Instead, this test ensures the methods are recognized as intrinsic and behave + * as expected. + */ +public class Main { + + private static final Unsafe unsafe = getUnsafe(); + + private static Thread[] sThreads = new Thread[10]; + + // + // Fields accessed by setters and adders. + // + + public int i = 0; + public long l = 0; + public Object o = null; + + // + // Setters. + // + + /// CHECK-START: int Main.set32(java.lang.Object, long, int) intrinsics_recognition (after) + /// CHECK-DAG: <<Result:i\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetInt + /// CHECK-DAG: Return [<<Result>>] + private static int set32(Object o, long offset, int newValue) { + return unsafe.getAndSetInt(o, offset, newValue); + } + + /// CHECK-START: long Main.set64(java.lang.Object, long, long) intrinsics_recognition (after) + /// CHECK-DAG: <<Result:j\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetLong + /// CHECK-DAG: Return [<<Result>>] + private static long set64(Object o, long offset, long newValue) { + return unsafe.getAndSetLong(o, offset, newValue); + } + + /// CHECK-START: java.lang.Object Main.setObj(java.lang.Object, long, java.lang.Object) intrinsics_recognition (after) + /// CHECK-DAG: <<Result:l\d+>> InvokeVirtual intrinsic:UnsafeGetAndSetObject + /// CHECK-DAG: Return [<<Result>>] + private static Object setObj(Object o, long offset, Object newValue) { + return unsafe.getAndSetObject(o, offset, newValue); + } + + // + // Adders. + // + + /// CHECK-START: int Main.add32(java.lang.Object, long, int) intrinsics_recognition (after) + /// CHECK-DAG: <<Result:i\d+>> InvokeVirtual intrinsic:UnsafeGetAndAddInt + /// CHECK-DAG: Return [<<Result>>] + private static int add32(Object o, long offset, int delta) { + return unsafe.getAndAddInt(o, offset, delta); + } + + /// CHECK-START: long Main.add64(java.lang.Object, long, long) intrinsics_recognition (after) + /// CHECK-DAG: <<Result:j\d+>> InvokeVirtual intrinsic:UnsafeGetAndAddLong + /// CHECK-DAG: Return [<<Result>>] + private static long add64(Object o, long offset, long delta) { + return unsafe.getAndAddLong(o, offset, delta); + } + + // + // Fences (native). + // + + /// CHECK-START: void Main.load() intrinsics_recognition (after) + /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeLoadFence + // + /// CHECK-START: void Main.load() instruction_simplifier (after) + /// CHECK-NOT: InvokeVirtual intrinsic:UnsafeLoadFence + // + /// CHECK-START: void Main.load() instruction_simplifier (after) + /// CHECK-DAG: MemoryBarrier kind:LoadAny + private static void load() { + unsafe.loadFence(); + } + + /// CHECK-START: void Main.store() intrinsics_recognition (after) + /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeStoreFence + // + /// CHECK-START: void Main.store() instruction_simplifier (after) + /// CHECK-NOT: InvokeVirtual intrinsic:UnsafeStoreFence + // + /// CHECK-START: void Main.store() instruction_simplifier (after) + /// CHECK-DAG: MemoryBarrier kind:AnyStore + private static void store() { + unsafe.storeFence(); + } + + /// CHECK-START: void Main.full() intrinsics_recognition (after) + /// CHECK-DAG: InvokeVirtual intrinsic:UnsafeFullFence + // + /// CHECK-START: void Main.full() instruction_simplifier (after) + /// CHECK-NOT: InvokeVirtual intrinsic:UnsafeFullFence + // + /// CHECK-START: void Main.full() instruction_simplifier (after) + /// CHECK-DAG: MemoryBarrier kind:AnyAny + private static void full() { + unsafe.fullFence(); + } + + // + // Thread fork/join. + // + + private static void fork(Runnable r) { + for (int i = 0; i < 10; i++) { + sThreads[i] = new Thread(r); + sThreads[i].start(); + } + } + + private static void join() { + try { + for (int i = 0; i < 10; i++) { + sThreads[i].join(); + } + } catch (InterruptedException e) { + throw new Error("Failed join: " + e); + } + } + + // + // Driver. + // + + public static void main(String[] args) { + System.out.println("starting"); + + final Main m = new Main(); + + // Get the offsets. + + final long intOffset, longOffset, objOffset; + try { + Field intField = Main.class.getDeclaredField("i"); + Field longField = Main.class.getDeclaredField("l"); + Field objField = Main.class.getDeclaredField("o"); + + intOffset = unsafe.objectFieldOffset(intField); + longOffset = unsafe.objectFieldOffset(longField); + objOffset = unsafe.objectFieldOffset(objField); + + } catch (NoSuchFieldException e) { + throw new Error("No offset: " + e); + } + + // Some sanity within same thread. + + set32(m, intOffset, 3); + expectEquals32(3, m.i); + + set64(m, longOffset, 7L); + expectEquals64(7L, m.l); + + setObj(m, objOffset, m); + expectEqualsObj(m, m.o); + + add32(m, intOffset, 11); + expectEquals32(14, m.i); + + add64(m, longOffset, 13L); + expectEquals64(20L, m.l); + + // Some sanity on setters within different threads. + + fork(new Runnable() { + public void run() { + for (int i = 0; i < 10; i++) + set32(m, intOffset, i); + } + }); + join(); + expectEquals32(9, m.i); // one thread's last value wins + + fork(new Runnable() { + public void run() { + for (int i = 0; i < 10; i++) + set64(m, longOffset, (long) (100 + i)); + } + }); + join(); + expectEquals64(109L, m.l); // one thread's last value wins + + fork(new Runnable() { + public void run() { + for (int i = 0; i < 10; i++) + setObj(m, objOffset, sThreads[i]); + } + }); + join(); + expectEqualsObj(sThreads[9], m.o); // one thread's last value wins + + // Some sanity on adders within different threads. + + fork(new Runnable() { + public void run() { + for (int i = 0; i < 10; i++) + add32(m, intOffset, i + 1); + } + }); + join(); + expectEquals32(559, m.i); // all values accounted for + + fork(new Runnable() { + public void run() { + for (int i = 0; i < 10; i++) + add64(m, longOffset, (long) (i + 1)); + } + }); + join(); + expectEquals64(659L, m.l); // all values accounted for + + // TODO: the fences + + System.out.println("passed"); + } + + // Use reflection to implement "Unsafe.getUnsafe()"; + private static Unsafe getUnsafe() { + try { + Class<?> unsafeClass = Unsafe.class; + Field f = unsafeClass.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (Unsafe) f.get(null); + } catch (Exception e) { + throw new Error("Cannot get Unsafe instance"); + } + } + + private static void expectEquals32(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals64(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEqualsObj(Object expected, Object result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/145-alloc-tracking-stress/src/Main.java b/test/145-alloc-tracking-stress/src/Main.java index 752fdd9135..418690a2a6 100644 --- a/test/145-alloc-tracking-stress/src/Main.java +++ b/test/145-alloc-tracking-stress/src/Main.java @@ -1,5 +1,4 @@ /* - * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test/462-checker-inlining-across-dex-files/multidex.jpp b/test/462-checker-inlining-across-dex-files/multidex.jpp new file mode 100644 index 0000000000..ae554566cb --- /dev/null +++ b/test/462-checker-inlining-across-dex-files/multidex.jpp @@ -0,0 +1,8 @@ +Main: + @@com.android.jack.annotations.ForceInMainDex + class Main + +AAA: + @@com.android.jack.annotations.ForceInMainDex + class AAA + diff --git a/test/556-invoke-super/multidex.jpp b/test/556-invoke-super/multidex.jpp new file mode 100644 index 0000000000..fe018019e3 --- /dev/null +++ b/test/556-invoke-super/multidex.jpp @@ -0,0 +1,4 @@ +Main: + @@com.android.jack.annotations.ForceInMainDex + class Main* + diff --git a/test/569-checker-pattern-replacement/multidex.jpp b/test/569-checker-pattern-replacement/multidex.jpp new file mode 100644 index 0000000000..cfc8ad1fc9 --- /dev/null +++ b/test/569-checker-pattern-replacement/multidex.jpp @@ -0,0 +1,8 @@ +Main: + @@com.android.jack.annotations.ForceInMainDex + class Main + +BaseInMainDex: + @@com.android.jack.annotations.ForceInMainDex + class BaseInMainDex + diff --git a/test/577-profile-foreign-dex/expected.txt b/test/577-profile-foreign-dex/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/577-profile-foreign-dex/expected.txt diff --git a/test/577-profile-foreign-dex/info.txt b/test/577-profile-foreign-dex/info.txt new file mode 100644 index 0000000000..090db3fdc6 --- /dev/null +++ b/test/577-profile-foreign-dex/info.txt @@ -0,0 +1 @@ +Check that we record the use of foreign dex files when profiles are enabled. diff --git a/test/577-profile-foreign-dex/run b/test/577-profile-foreign-dex/run new file mode 100644 index 0000000000..ad57d14c60 --- /dev/null +++ b/test/577-profile-foreign-dex/run @@ -0,0 +1,20 @@ +#!/bin/bash +# +# Copyright 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +exec ${RUN} \ + --runtime-option -Xjitsaveprofilinginfo \ + --runtime-option -Xusejit:true \ + "${@}" diff --git a/test/577-profile-foreign-dex/src-ex/OtherDex.java b/test/577-profile-foreign-dex/src-ex/OtherDex.java new file mode 100644 index 0000000000..cba73b3094 --- /dev/null +++ b/test/577-profile-foreign-dex/src-ex/OtherDex.java @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +public class OtherDex { +} diff --git a/test/577-profile-foreign-dex/src/Main.java b/test/577-profile-foreign-dex/src/Main.java new file mode 100644 index 0000000000..0cd85b58e8 --- /dev/null +++ b/test/577-profile-foreign-dex/src/Main.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; +import java.util.HashMap; + +public class Main { + + private static final String PROFILE_NAME = "primary.prof"; + private static final String APP_DIR_PREFIX = "app_dir_"; + private static final String FOREIGN_DEX_PROFILE_DIR = "foreign-dex"; + private static final String TEMP_FILE_NAME_PREFIX = "dummy"; + private static final String TEMP_FILE_NAME_SUFFIX = "-file"; + + public static void main(String[] args) throws Exception { + File tmpFile = null; + File appDir = null; + File profileFile = null; + File foreignDexProfileDir = null; + + try { + // Create the necessary files layout. + tmpFile = createTempFile(); + appDir = new File(tmpFile.getParent(), APP_DIR_PREFIX + tmpFile.getName()); + appDir.mkdir(); + foreignDexProfileDir = new File(tmpFile.getParent(), FOREIGN_DEX_PROFILE_DIR); + foreignDexProfileDir.mkdir(); + profileFile = createTempFile(); + + String codePath = System.getenv("DEX_LOCATION") + "/577-profile-foreign-dex.jar"; + + // Register the app with the runtime + VMRuntime.registerAppInfo(profileFile.getPath(), appDir.getPath(), + new String[] { codePath }, foreignDexProfileDir.getPath()); + + testMarkerForForeignDex(foreignDexProfileDir); + testMarkerForCodePath(foreignDexProfileDir); + testMarkerForApplicationDexFile(foreignDexProfileDir, appDir); + } finally { + if (tmpFile != null) { + tmpFile.delete(); + } + if (profileFile != null) { + profileFile.delete(); + } + if (foreignDexProfileDir != null) { + foreignDexProfileDir.delete(); + } + if (appDir != null) { + appDir.delete(); + } + } + } + + // Verify we actually create a marker on disk for foreign dex files. + private static void testMarkerForForeignDex(File foreignDexProfileDir) throws Exception { + String foreignDex = System.getenv("DEX_LOCATION") + "/577-profile-foreign-dex-ex.jar"; + loadDexFile(foreignDex); + checkMarker(foreignDexProfileDir, foreignDex, /* exists */ true); + } + + // Verify we do not create a marker on disk for dex files path of the code path. + private static void testMarkerForCodePath(File foreignDexProfileDir) throws Exception { + String codePath = System.getenv("DEX_LOCATION") + "/577-profile-foreign-dex.jar"; + loadDexFile(codePath); + checkMarker(foreignDexProfileDir, codePath, /* exists */ false); + } + + private static void testMarkerForApplicationDexFile(File foreignDexProfileDir, File appDir) + throws Exception { + // Copy the -ex jar to the application directory and load it from there. + // This will record duplicate class conflicts but we don't care for this use case. + File foreignDex = new File(System.getenv("DEX_LOCATION") + "/577-profile-foreign-dex-ex.jar"); + File appDex = new File(appDir, "appDex.jar"); + try { + copyFile(foreignDex, appDex); + + loadDexFile(appDex.getAbsolutePath()); + checkMarker(foreignDexProfileDir, appDex.getAbsolutePath(), /* exists */ false); + } finally { + if (appDex != null) { + appDex.delete(); + } + } + } + + private static void checkMarker(File foreignDexProfileDir, String dexFile, boolean exists) { + File marker = new File(foreignDexProfileDir, dexFile.replace('/', '@')); + boolean result_ok = exists ? marker.exists() : !marker.exists(); + if (!result_ok) { + throw new RuntimeException("Marker test failed for:" + marker.getPath()); + } + } + + private static void loadDexFile(String dexFile) throws Exception { + Class pathClassLoader = Class.forName("dalvik.system.PathClassLoader"); + if (pathClassLoader == null) { + throw new RuntimeException("Couldn't find path class loader class"); + } + Constructor constructor = + pathClassLoader.getDeclaredConstructor(String.class, ClassLoader.class); + constructor.newInstance( + dexFile, ClassLoader.getSystemClassLoader()); + } + + private static class VMRuntime { + private static final Method registerAppInfoMethod; + static { + try { + Class c = Class.forName("dalvik.system.VMRuntime"); + registerAppInfoMethod = c.getDeclaredMethod("registerAppInfo", + String.class, String.class, String[].class, String.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void registerAppInfo(String pkgName, String appDir, + String[] codePath, String foreignDexProfileDir) throws Exception { + registerAppInfoMethod.invoke(null, pkgName, appDir, codePath, foreignDexProfileDir); + } + } + + private static void copyFile(File fromFile, File toFile) throws Exception { + FileInputStream in = new FileInputStream(fromFile); + FileOutputStream out = new FileOutputStream(toFile); + try { + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = in.read(buffer)) >= 0) { + out.write(buffer, 0, bytesRead); + } + } finally { + out.flush(); + try { + out.getFD().sync(); + } catch (IOException e) { + } + out.close(); + in.close(); + } + } + + private static File createTempFile() throws Exception { + try { + return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); + } catch (IOException e) { + System.setProperty("java.io.tmpdir", "/data/local/tmp"); + try { + return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); + } catch (IOException e2) { + System.setProperty("java.io.tmpdir", "/sdcard"); + return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); + } + } + } +} diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index c4f0171f0d..7036bdcaf5 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -567,7 +567,9 @@ TEST_ART_BROKEN_OPTIMIZING_READ_BARRIER_RUN_TESTS := \ 537-checker-arraycopy # Tests that should fail in the read barrier configuration with JIT (Optimizing compiler). -TEST_ART_BROKEN_JIT_READ_BARRIER_RUN_TESTS := +# 145: Test sometimes times out in read barrier configuration (b/27467554). +TEST_ART_BROKEN_JIT_READ_BARRIER_RUN_TESTS := \ + 145-alloc-tracking-stress ifeq ($(ART_USE_READ_BARRIER),true) ifneq (,$(filter interpreter,$(COMPILER_TYPES))) diff --git a/test/etc/default-build b/test/etc/default-build index 6e855ec30a..5f78496c3f 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -116,28 +116,33 @@ if ! [ "${HAS_SRC}" = "true" ] && ! [ "${HAS_SRC2}" = "true" ]; then SKIP_DX_MERGER="true" fi -if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then - # Jack does not support this configuration unless we specify how to partition the DEX file - # with a .jpp file. - USE_JACK="false" -fi - if [ ${USE_JACK} = "true" ]; then # Jack toolchain if [ "${HAS_SRC}" = "true" ]; then - ${JACK} ${JACK_ARGS} --output-jack src.jack src - imported_jack_files="--import src.jack" + if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then + # Compile src and src-multidex in the same .jack file. We will apply multidex partitioning + # when creating the output .dex file. + ${JACK} ${JACK_ARGS} --output-jack src.jack src src src-multidex + jack_extra_args="${jack_extra_args} -D jack.dex.output.policy=minimal-multidex" + jack_extra_args="${jack_extra_args} -D jack.preprocessor=true" + jack_extra_args="${jack_extra_args} -D jack.preprocessor.file=multidex.jpp" + else + ${JACK} ${JACK_ARGS} --output-jack src.jack src + fi + jack_extra_args="${jack_extra_args} --import src.jack" fi if [ "${HAS_SRC2}" = "true" ]; then ${JACK} ${JACK_ARGS} --output-jack src2.jack src2 - imported_jack_files="--import src2.jack ${imported_jack_files}" + # In case of duplicate classes, we want to take into account the classes from src2. Therefore + # we apply the 'keep-first' policy and import src2.jack file *before* the src.jack file. + jack_extra_args="${jack_extra_args} -D jack.import.type.policy=keep-first" + jack_extra_args="--import src2.jack ${jack_extra_args}" fi - # Compile jack files into a DEX file. We set jack.import.type.policy=keep-first to consider - # class definitions from src2 first. + # Compile jack files into a DEX file. if [ "${HAS_SRC}" = "true" ] || [ "${HAS_SRC2}" = "true" ]; then - ${JACK} ${JACK_ARGS} ${imported_jack_files} -D jack.import.type.policy=keep-first --output-dex . + ${JACK} ${JACK_ARGS} ${jack_extra_args} --output-dex . fi else # Legacy toolchain with javac+dx |