Merge "Update Mac dx to a version that supports class file v52"
diff --git a/build.gradle b/build.gradle
index 18b01fc..2d9e9b4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1339,9 +1339,9 @@
}
task buildPreNJdwpTestsDex(type: Exec, dependsOn: "buildPreNJdwpTestsJar") {
- if (OperatingSystem.current().isWindows()) {
+ onlyIf {
// TODO(b/76135355): Update dx.bat on Windows to something that can build this.
- return;
+ !OperatingSystem.current().isWindows()
}
def inFile = buildPreNJdwpTestsJar.archivePath
def outFile = new File(buildPreNJdwpTestsJar.destinationDir, buildPreNJdwpTestsJar.baseName + '-dex.jar')
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 72402b3..5bea64e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -327,7 +327,8 @@
targets.put(INITIAL_BLOCK_OFFSET, new BlockInfo());
// Process reachable code paths starting from instruction 0.
- processedInstructions = new boolean[source.instructionCount()];
+ int instCount = source.instructionCount();
+ processedInstructions = new boolean[instCount];
traceBlocksWorklist.add(0);
while (!traceBlocksWorklist.isEmpty()) {
int startOfBlockOffset = traceBlocksWorklist.remove();
@@ -337,17 +338,17 @@
continue;
}
// Process each instruction until the block is closed.
- for (int index = startOfBlockIndex; index < source.instructionCount(); ++index) {
+ for (int index = startOfBlockIndex; index < instCount; ++index) {
markIndexProcessed(index);
int closedAt = source.traceInstruction(index, this);
if (closedAt != -1) {
- if (closedAt + 1 < source.instructionCount()) {
+ if (closedAt + 1 < instCount) {
ensureBlockWithoutEnqueuing(source.instructionOffset(closedAt + 1));
}
break;
}
// If the next instruction starts a block, fall through to it.
- if (index + 1 < source.instructionCount()) {
+ if (index + 1 < instCount) {
int nextOffset = source.instructionOffset(index + 1);
if (targets.get(nextOffset) != null) {
ensureNormalSuccessorBlock(startOfBlockOffset, nextOffset);
@@ -491,7 +492,8 @@
continue;
}
// Build IR for each dex instruction in the block.
- for (int i = item.firstInstructionIndex; i < source.instructionCount(); ++i) {
+ int instCount = source.instructionCount();
+ for (int i = item.firstInstructionIndex; i < instCount; ++i) {
if (currentBlock == null) {
break;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
index 9d2cd1d..2298bc6 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
@@ -424,11 +424,12 @@
for (JarStateWorklistItem item = worklist.poll(); item != null; item = worklist.poll()) {
state.restoreState(item.instructionIndex);
// Iterate each of the instructions in the block to compute the outgoing JarState.
- for (int i = item.instructionIndex; i <= instructionCount(); ++i) {
+ int instCount = instructionCount();
+ for (int i = item.instructionIndex; i <= instCount; ++i) {
// If we are at the end of the instruction stream or if we have reached the start
// of a new block, propagate the state to all successors and add the ones
// that changed to the worklist.
- if (i == instructionCount() || (i != item.instructionIndex && CFG.containsKey(i))) {
+ if (i == instCount || (i != item.instructionIndex && CFG.containsKey(i))) {
item.blockInfo.normalSuccessors.iterator().forEachRemaining(offset -> {
if (state.recordStateForTarget(offset)) {
if (offset >= 0) {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 9b893d1..dc0cd0f 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -225,7 +225,8 @@
private final Map<Origin, List<InvalidParameterAnnotationInfo>> warningInvalidParameterAnnotations
= new HashMap<>();
- private final Map<Origin, List<DexEncodedMethod>> warningInvalidDebugInfo = new HashMap<>();
+ private final Map<Origin, List<Pair<DexEncodedMethod, String>>> warningInvalidDebugInfo
+ = new HashMap<>();
// Don't read code from dex files. Used to extract non-code information from vdex files where
// the code contains unsupported byte codes.
@@ -268,7 +269,8 @@
public void warningInvalidDebugInfo(
DexEncodedMethod method, Origin origin, InvalidDebugInfoException e) {
synchronized (warningInvalidDebugInfo) {
- warningInvalidDebugInfo.computeIfAbsent(origin, k -> new ArrayList<>()).add(method);
+ warningInvalidDebugInfo.computeIfAbsent(
+ origin, k -> new ArrayList<>()).add(new Pair<>(method, e.getMessage()));
}
}
@@ -299,7 +301,7 @@
}
if (warningInvalidDebugInfo.size() > 0) {
int count = 0;
- for (List<DexEncodedMethod> methods : warningInvalidDebugInfo.values()) {
+ for (List<Pair<DexEncodedMethod, String>> methods : warningInvalidDebugInfo.values()) {
count += methods.size();
}
reporter.warning(
@@ -309,10 +311,11 @@
+ (count == 1 ? " method." : " methods.")));
for (Origin origin : new TreeSet<>(warningInvalidDebugInfo.keySet())) {
StringBuilder builder = new StringBuilder("Methods with invalid locals information:");
- for (DexEncodedMethod method : warningInvalidDebugInfo.get(origin)) {
- builder.append("\n ").append(method.toSourceString());
+ for (Pair<DexEncodedMethod, String> method : warningInvalidDebugInfo.get(origin)) {
+ builder.append("\n ").append(method.getFirst().toSourceString());
+ builder.append("\n ").append(method.getSecond());
}
- reporter.info(new StringDiagnostic(builder.toString(), origin));
+ reporter.warning(new StringDiagnostic(builder.toString(), origin));
}
printed = true;
printOutdatedToolchain = true;
diff --git a/src/test/java/com/android/tools/r8/R8ApiBinaryCompatibilityTests.java b/src/test/java/com/android/tools/r8/R8ApiBinaryCompatibilityTests.java
index 28fe5dc..79017bc 100644
--- a/src/test/java/com/android/tools/r8/R8ApiBinaryCompatibilityTests.java
+++ b/src/test/java/com/android/tools/r8/R8ApiBinaryCompatibilityTests.java
@@ -3,6 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.FileUtils;
@@ -13,7 +16,6 @@
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
-import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -31,13 +33,15 @@
List<Path> inputs =
ImmutableList.of(Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, "arithmetic.jar"));
+ String keepMain = "-keep public class arithmetic.Arithmetic {\n"
+ + " public static void main(java.lang.String[]);\n"
+ + "}";
+
Path pgConf = temp.getRoot().toPath().resolve("pg.conf");
- FileUtils.writeTextFile(
- pgConf, TestBase.keepMainProguardConfiguration("arithmetic.Arithmetic"));
+ FileUtils.writeTextFile(pgConf, keepMain);
Path mainDexRules = temp.getRoot().toPath().resolve("maindex.rules");
- FileUtils.writeTextFile(
- mainDexRules, TestBase.keepMainProguardConfiguration("arithmetic.Arithmetic"));
+ FileUtils.writeTextFile(mainDexRules, keepMain);
Path mainDexList = temp.getRoot().toPath().resolve("maindexlist.txt");
FileUtils.writeTextFile(mainDexList, "arithmetic/Arithmetic.class");
@@ -68,8 +72,8 @@
ProcessBuilder builder = new ProcessBuilder(command);
ProcessResult result = ToolHelper.runProcess(builder);
- Assert.assertEquals(result.stderr + "\n" + result.stdout, 0, result.exitCode);
- Assert.assertTrue(result.stdout, result.stdout.isEmpty());
- Assert.assertTrue(result.stderr, result.stderr.isEmpty());
+ assertEquals(result.stderr + "\n" + result.stdout, 0, result.exitCode);
+ assertTrue(result.stdout, result.stdout.isEmpty());
+ assertTrue(result.stderr, result.stderr.isEmpty());
}
}
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java
index 2a613b4..5d7bec0 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -377,7 +377,7 @@
Path proguardPrintSeedsConfiguration = temp.newFile("printseeds.txt").toPath().toAbsolutePath();
FileUtils.writeTextFile(proguardPrintSeedsConfiguration, ImmutableList.of("-printseeds"));
ProcessResult result = runR8OnShaking1(proguardPrintSeedsConfiguration);
- assertTrue(result.exitCode == 0);
+ assertEquals("R8 run failed: " + result.stderr, 0, result.exitCode);
assertTrue(result.stdout.contains("void main(java.lang.String[])"));
}
@@ -386,7 +386,7 @@
Path proguardPrintUsageConfiguration = temp.newFile("printusage.txt").toPath().toAbsolutePath();
FileUtils.writeTextFile(proguardPrintUsageConfiguration, ImmutableList.of("-printusage"));
ProcessResult result = runR8OnShaking1(proguardPrintUsageConfiguration);
- assertTrue(result.exitCode == 0);
+ assertEquals("R8 run failed: " + result.stderr, 0, result.exitCode);
assertTrue(result.stdout.contains("shaking1.Unused"));
}
@@ -397,7 +397,7 @@
FileUtils.writeTextFile(
proguardPrintSeedsConfiguration, ImmutableList.of("-printseeds", "-printusage"));
ProcessResult result = runR8OnShaking1(proguardPrintSeedsConfiguration);
- assertTrue(result.exitCode == 0);
+ assertEquals("R8 run failed: " + result.stderr, 0, result.exitCode);
assertTrue(result.stdout.contains("void main(java.lang.String[])"));
assertTrue(result.stdout.contains("shaking1.Unused"));
}
diff --git a/src/test/sampleApks/simple/AndroidManifest.xml b/src/test/sampleApks/simple/AndroidManifest.xml
new file mode 100644
index 0000000..f959dbd
--- /dev/null
+++ b/src/test/sampleApks/simple/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+for details. All rights reserved. Use of this source code is governed by a
+BSD-style license that can be found in the LICENSE file.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tools.r8.sample.simple"
+ android:versionCode="1"
+ android:versionName="0.1" >
+
+ <uses-sdk android:minSdkVersion="21" />
+
+ <application
+ android:icon="@drawable/icon"
+ android:label="@string/app_name" >
+ <activity
+ android:name=".R8Activity"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/src/test/sampleApks/simple/assets/README.txt b/src/test/sampleApks/simple/assets/README.txt
new file mode 100644
index 0000000..fdf73af
--- /dev/null
+++ b/src/test/sampleApks/simple/assets/README.txt
@@ -0,0 +1 @@
+Sample app from R8 project
diff --git a/src/test/sampleApks/simple/res/drawable-mdpi/icon.png b/src/test/sampleApks/simple/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..0799d58
--- /dev/null
+++ b/src/test/sampleApks/simple/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/src/test/sampleApks/simple/res/layout/main.xml b/src/test/sampleApks/simple/res/layout/main.xml
new file mode 100644
index 0000000..7859435
--- /dev/null
+++ b/src/test/sampleApks/simple/res/layout/main.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+for details. All rights reserved. Use of this source code is governed by a
+BSD-style license that can be found in the LICENSE file.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical" android:layout_width="fill_parent"
+ android:layout_height="fill_parent" android:id="@+id/MainLayout"
+ android:background="@android:color/background_light">
+
+ <Button
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" android:id="@+id/PressButton"
+ android:layout_margin="2dip"
+ android:text="Do something"/>
+</LinearLayout>
diff --git a/src/test/sampleApks/simple/res/values/strings.xml b/src/test/sampleApks/simple/res/values/strings.xml
new file mode 100644
index 0000000..8bae26c
--- /dev/null
+++ b/src/test/sampleApks/simple/res/values/strings.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+for details. All rights reserved. Use of this source code is governed by a
+BSD-style license that can be found in the LICENSE file.
+-->
+<resources>
+ <string name="app_name">R8 simple app</string>
+</resources>
diff --git a/src/test/sampleApks/simple/src/com/android/tools/r8/sample/simple/R8Activity.java b/src/test/sampleApks/simple/src/com/android/tools/r8/sample/simple/R8Activity.java
new file mode 100644
index 0000000..4a09fd4
--- /dev/null
+++ b/src/test/sampleApks/simple/src/com/android/tools/r8/sample/simple/R8Activity.java
@@ -0,0 +1,17 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.sample.simple;
+
+import android.app.Activity;
+import android.os.Bundle;
+import com.android.tools.r8.sample.simple.R;
+
+public class R8Activity extends Activity {
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setTheme(android.R.style.Theme_Light);
+ setContentView(R.layout.main);
+ }
+}
diff --git a/tools/apk-masseur.py b/tools/apk-masseur.py
index 8e98e47..4f24f0f 100755
--- a/tools/apk-masseur.py
+++ b/tools/apk-masseur.py
@@ -3,6 +3,7 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
+import apk_utils
import glob
import optparse
import os
@@ -68,23 +69,8 @@
return processed_apk
def sign(unsigned_apk, keystore, temp):
- print 'Signing (ignore the warnings)'
- cmd = ['zip', '-d', unsigned_apk, 'META-INF/*']
- utils.PrintCmd(cmd)
- subprocess.call(cmd)
signed_apk = os.path.join(temp, 'unaligned.apk')
- cmd = [
- 'jarsigner',
- '-sigalg', 'SHA1withRSA',
- '-digestalg', 'SHA1',
- '-keystore', keystore,
- '-storepass', 'android',
- '-signedjar', signed_apk,
- unsigned_apk,
- 'androiddebugkey'
- ]
- utils.PrintCmd(cmd)
- subprocess.check_call(cmd)
+ apk_utils.sign(unsigned_apk, signed_apk, keystore)
return signed_apk
def align(signed_apk, temp):
diff --git a/tools/apk_utils.py b/tools/apk_utils.py
new file mode 100644
index 0000000..a4c0471
--- /dev/null
+++ b/tools/apk_utils.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+# Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import subprocess
+import utils
+
+def sign(unsigned_apk, signed_apk, keystore):
+ print 'Signing (ignore the warnings)'
+ cmd = ['zip', '-d', unsigned_apk, 'META-INF/*']
+ utils.PrintCmd(cmd)
+ subprocess.call(cmd)
+ cmd = [
+ 'jarsigner',
+ '-sigalg', 'SHA1withRSA',
+ '-digestalg', 'SHA1',
+ '-keystore', keystore,
+ '-storepass', 'android',
+ '-signedjar', signed_apk,
+ unsigned_apk,
+ 'androiddebugkey'
+ ]
+ utils.PrintCmd(cmd)
+ subprocess.check_call(cmd)
diff --git a/tools/build_sample_apk.py b/tools/build_sample_apk.py
new file mode 100755
index 0000000..5d691d9
--- /dev/null
+++ b/tools/build_sample_apk.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+# Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Script for building sample apks using the sdk tools directly.
+
+import apk_utils
+import fnmatch
+import glob
+import optparse
+import os
+import shutil
+import subprocess
+import sys
+import utils
+
+ANDROID_JAR = 'third_party/android_jar/lib-v{api}/android.jar'
+DEFAULT_AAPT = 'aapt' # Assume in path.
+DEFAULT_D8 = os.path.join(utils.REPO_ROOT, 'tools', 'd8.py')
+DEFAULT_JAVAC = 'javac'
+SRC_LOCATION = 'src/com/android/tools/r8/sample/{app}/*.java'
+DEFAULT_KEYSTORE = os.path.join(os.getenv('HOME'), '.android', 'debug.keystore')
+
+SAMPLE_APKS = [
+ 'simple'
+]
+
+def parse_options():
+ result = optparse.OptionParser()
+ result.add_option('--aapt',
+ help='aapt executable to use',
+ default=DEFAULT_AAPT)
+ result.add_option('--api',
+ help='Android api level',
+ default=21,
+ choices=[14, 15, 19, 21, 22, 23, 24, 25, 26])
+ result.add_option('--keystore',
+ help='Keystore used for signing',
+ default=DEFAULT_KEYSTORE)
+ result.add_option('--app',
+ help='Which app to build',
+ default='simple',
+ choices=SAMPLE_APKS)
+ return result.parse_args()
+
+def run_aapt(aapt, args):
+ command = [aapt]
+ command.extend(args)
+ utils.PrintCmd(command)
+ subprocess.check_call(command)
+
+def get_build_dir(app):
+ return os.path.join(utils.BUILD, 'sampleApks', app)
+
+def get_gen_path(app):
+ gen_path = os.path.join(get_build_dir(app), 'gen')
+ utils.makedirs_if_needed(gen_path)
+ return gen_path
+
+def get_bin_path(app):
+ bin_path = os.path.join(get_build_dir(app), 'bin')
+ utils.makedirs_if_needed(bin_path)
+ return bin_path
+
+def get_android_jar(api):
+ return os.path.join(utils.REPO_ROOT, ANDROID_JAR.format(api=api))
+
+def get_sample_dir(app):
+ return os.path.join(utils.REPO_ROOT, 'src', 'test', 'sampleApks', app)
+
+def get_src_path(app):
+ return os.path.join(get_sample_dir(app), 'src')
+
+def run_aapt_pack(aapt, api, app):
+ with utils.ChangedWorkingDirectory(get_sample_dir(app)):
+ args = ['package',
+ '-v', '-f',
+ '-I', get_android_jar(api),
+ '-M', 'AndroidManifest.xml',
+ '-A', 'assets',
+ '-S', 'res',
+ '-m',
+ '-J', get_gen_path(app),
+ '-F', os.path.join(get_bin_path(app), 'resources.ap_')]
+ run_aapt(aapt, args)
+
+def compile_with_javac(api, app):
+ with utils.ChangedWorkingDirectory(get_sample_dir(app)):
+ files = glob.glob(SRC_LOCATION.format(app=app))
+ command = [DEFAULT_JAVAC,
+ '-classpath', get_android_jar(api),
+ '-sourcepath', '%s:%s' % (get_src_path(app), get_gen_path(app)),
+ '-d', get_bin_path(app)]
+ command.extend(files)
+ utils.PrintCmd(command)
+ subprocess.check_call(command)
+
+def dex(app, api):
+ files = []
+ for root, dirnames, filenames in os.walk(get_bin_path(app)):
+ for filename in fnmatch.filter(filenames, '*.class'):
+ files.append(os.path.join(root, filename))
+ command = [DEFAULT_D8,
+ '--output', get_bin_path(app),
+ '--classpath', get_android_jar(api),
+ '--min-api', str(api)]
+ command.extend(files)
+ utils.PrintCmd(command)
+ subprocess.check_call(command)
+
+def create_temp_apk(app):
+ temp_apk_path = os.path.join(get_bin_path(app), '%s.ap_' % app)
+ shutil.move(os.path.join(get_bin_path(app), 'resources.ap_'),
+ temp_apk_path)
+ return temp_apk_path
+
+def aapt_add_dex(aapt, app, temp_apk_path):
+ args = ['add',
+ '-k', temp_apk_path,
+ os.path.join(get_bin_path(app), 'classes.dex')]
+ run_aapt(aapt, args)
+
+def Main():
+ (options, args) = parse_options()
+ run_aapt_pack(options.aapt, options.api, options.app)
+ compile_with_javac(options.api, options.app)
+ dex(options.app, options.api)
+ temp_apk_path = create_temp_apk(options.app)
+ aapt_add_dex(options.aapt, options.app, temp_apk_path)
+ apk_path = os.path.join(get_bin_path(options.app), '%s.apk' % options.app)
+ apk_utils.sign(temp_apk_path, apk_path, options.keystore)
+ print('Apk available at: %s' % apk_path)
+
+if __name__ == '__main__':
+ sys.exit(Main())
diff --git a/tools/windows/README.dx b/tools/windows/README.dx
index 348dc4a..4d93487 100644
--- a/tools/windows/README.dx
+++ b/tools/windows/README.dx
@@ -1,25 +1,25 @@
-Dx version: 1.12
-dx.bat and dx.jar are fetched from SDK build tools 24.0.0.
-dx.bat has been modified so that the code that checks if 'java' if on current path
-is removed and replaced by a direct reference to it.
-This is done because this relies on a tool found in the SDK and not present in the
-current package.
-Diff:
-
-26,29c26,29
-< set java_exe=
-< if exist "%~dp0..\tools\lib\find_java.bat" call "%~dp0..\tools\lib\find_java.bat"
-< if exist "%~dp0..\..\tools\lib\find_java.bat" call "%~dp0..\..\tools\lib\find_java.bat"
-< if not defined java_exe goto :EOF
----
-> REM set java_exe=
-> REM if exist "%~dp0..\tools\lib\find_java.bat" call "%~dp0..\tools\lib\find_java.bat"
-> REM if exist "%~dp0..\..\tools\lib\find_java.bat" call "%~dp0..\..\tools\lib\find_java.bat"
-> REM if not defined java_exe goto :EOF
-87c87
-< call "%java_exe%" %javaOpts% -Djava.ext.dirs="%frameworkdir%" -jar "%jarpath%" %params%
----
-> call java %javaOpts% -Djava.ext.dirs="%frameworkdir%" -jar "%jarpath%" %params%
-
-dexmerger.bat has been copied from dx.bat, and the command line has been updated
+Dx version: 1.13
+dx.bat and dx.jar are fetched from SDK build tools 26.0.0.
+dx.bat has been modified so that the code that checks if 'java' if on current path
+is removed and replaced by a direct reference to it.
+This is done because this relies on a tool found in the SDK and not present in the
+current package.
+Diff:
+
+26,29c26,29
+< set java_exe=
+< if exist "%~dp0..\tools\lib\find_java.bat" call "%~dp0..\tools\lib\find_java.bat"
+< if exist "%~dp0..\..\tools\lib\find_java.bat" call "%~dp0..\..\tools\lib\find_java.bat"
+< if not defined java_exe goto :EOF
+---
+> REM set java_exe=
+> REM if exist "%~dp0..\tools\lib\find_java.bat" call "%~dp0..\tools\lib\find_java.bat"
+> REM if exist "%~dp0..\..\tools\lib\find_java.bat" call "%~dp0..\..\tools\lib\find_java.bat"
+> REM if not defined java_exe goto :EOF
+87c87
+< call "%java_exe%" %javaOpts% -Djava.ext.dirs="%frameworkdir%" -jar "%jarpath%" %params%
+---
+> call java %javaOpts% -Djava.ext.dirs="%frameworkdir%" -jar "%jarpath%" %params%
+
+dexmerger.bat has been copied from dx.bat, and the command line has been updated
according to the SDK dexmerger bash script to call the right class.
\ No newline at end of file
diff --git a/tools/windows/dx.tar.gz.sha1 b/tools/windows/dx.tar.gz.sha1
index 0f3e345..867adab 100644
--- a/tools/windows/dx.tar.gz.sha1
+++ b/tools/windows/dx.tar.gz.sha1
@@ -1 +1 @@
-9adeae753e17fa0a663e4d458b406a39ded27621
\ No newline at end of file
+47414f7ebc8a8cc14b29fc6732510a20947870aa
\ No newline at end of file