feat: runtime.loadJar() cache dex
This commit is contained in:
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
@@ -16,8 +16,8 @@ android {
|
|||||||
applicationId "org.autojs.autojs"
|
applicationId "org.autojs.autojs"
|
||||||
minSdkVersion versions.mini
|
minSdkVersion versions.mini
|
||||||
targetSdkVersion versions.target
|
targetSdkVersion versions.target
|
||||||
versionCode 423
|
versionCode versions.appVersionCode
|
||||||
versionName "4.0.3 Alpha4"
|
versionName versions.appVersionName
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
ndk {
|
ndk {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package com.stardust.autojs.rhino;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.dx.command.dexer.Main;
|
import com.android.dx.command.dexer.Main;
|
||||||
import com.android.dx.dex.file.DexFile;
|
import com.stardust.pio.PFiles;
|
||||||
|
import com.stardust.util.MD5;
|
||||||
|
|
||||||
import net.lingala.zip4j.core.ZipFile;
|
import net.lingala.zip4j.core.ZipFile;
|
||||||
import net.lingala.zip4j.exception.ZipException;
|
import net.lingala.zip4j.exception.ZipException;
|
||||||
@@ -16,6 +17,7 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -42,7 +44,11 @@ public class AndroidClassLoader extends ClassLoader implements GeneratedClassLoa
|
|||||||
public AndroidClassLoader(ClassLoader parent, File dir) {
|
public AndroidClassLoader(ClassLoader parent, File dir) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
mCacheDir = dir;
|
mCacheDir = dir;
|
||||||
dir.mkdirs();
|
if (dir.exists()) {
|
||||||
|
PFiles.deleteFilesOfDir(dir);
|
||||||
|
} else {
|
||||||
|
dir.mkdirs();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,13 +59,13 @@ public class AndroidClassLoader extends ClassLoader implements GeneratedClassLoa
|
|||||||
Log.d(LOG_TAG, "defineClass: name = " + name + " data.length = " + data.length);
|
Log.d(LOG_TAG, "defineClass: name = " + name + " data.length = " + data.length);
|
||||||
File classFile = null;
|
File classFile = null;
|
||||||
try {
|
try {
|
||||||
classFile = generateTempClassFile(name, false);
|
classFile = generateTempFile(name, false);
|
||||||
final ZipFile zipFile = new ZipFile(classFile);
|
final ZipFile zipFile = new ZipFile(classFile);
|
||||||
final ZipParameters parameters = new ZipParameters();
|
final ZipParameters parameters = new ZipParameters();
|
||||||
parameters.setFileNameInZip(name.replace('.', '/') + ".class");
|
parameters.setFileNameInZip(name.replace('.', '/') + ".class");
|
||||||
parameters.setSourceExternalStream(true);
|
parameters.setSourceExternalStream(true);
|
||||||
zipFile.addStream(new ByteArrayInputStream(data), parameters);
|
zipFile.addStream(new ByteArrayInputStream(data), parameters);
|
||||||
return dexJar(classFile).loadClass(name);
|
return dexJar(classFile, null).loadClass(name);
|
||||||
} catch (IOException | ZipException | ClassNotFoundException e) {
|
} catch (IOException | ZipException | ClassNotFoundException e) {
|
||||||
throw new FatalLoadingException(e);
|
throw new FatalLoadingException(e);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -69,7 +75,7 @@ public class AndroidClassLoader extends ClassLoader implements GeneratedClassLoa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private File generateTempClassFile(String name, boolean create) throws IOException {
|
private File generateTempFile(String name, boolean create) throws IOException {
|
||||||
File file = new File(mCacheDir, name.hashCode() + System.currentTimeMillis() + ".jar");
|
File file = new File(mCacheDir, name.hashCode() + System.currentTimeMillis() + ".jar");
|
||||||
if (create) {
|
if (create) {
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
@@ -83,8 +89,16 @@ public class AndroidClassLoader extends ClassLoader implements GeneratedClassLoa
|
|||||||
|
|
||||||
public void loadJar(File jar) throws IOException {
|
public void loadJar(File jar) throws IOException {
|
||||||
Log.d(LOG_TAG, "loadJar: jar = " + jar);
|
Log.d(LOG_TAG, "loadJar: jar = " + jar);
|
||||||
|
if (!jar.exists() || !jar.canRead()) {
|
||||||
|
throw new FileNotFoundException("File does not exist or readable: " + jar.getPath());
|
||||||
|
}
|
||||||
|
File dexFile = new File(mCacheDir, generateDexFileName(jar));
|
||||||
|
if (dexFile.exists()) {
|
||||||
|
loadDex(dexFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
final File classFile = generateTempClassFile(jar.getPath(), false);
|
final File classFile = generateTempFile(jar.getPath(), false);
|
||||||
final ZipFile zipFile = new ZipFile(classFile);
|
final ZipFile zipFile = new ZipFile(classFile);
|
||||||
final ZipFile jarFile = new ZipFile(jar);
|
final ZipFile jarFile = new ZipFile(jar);
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
@@ -96,12 +110,22 @@ public class AndroidClassLoader extends ClassLoader implements GeneratedClassLoa
|
|||||||
zipFile.addStream(jarFile.getInputStream(header), parameters);
|
zipFile.addStream(jarFile.getInputStream(header), parameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dexJar(classFile);
|
dexJar(classFile, dexFile);
|
||||||
|
classFile.delete();
|
||||||
} catch (ZipException e) {
|
} catch (ZipException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String generateDexFileName(File jar) {
|
||||||
|
String message = jar.getPath() + "_" + jar.lastModified();
|
||||||
|
try {
|
||||||
|
return MD5.md5(message);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public DexClassLoader loadDex(File file) throws FileNotFoundException {
|
public DexClassLoader loadDex(File file) throws FileNotFoundException {
|
||||||
Log.d(LOG_TAG, "loadDex: file = " + file);
|
Log.d(LOG_TAG, "loadDex: file = " + file);
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
@@ -112,15 +136,20 @@ public class AndroidClassLoader extends ClassLoader implements GeneratedClassLoa
|
|||||||
return loader;
|
return loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DexClassLoader dexJar(File classFile) throws IOException {
|
private DexClassLoader dexJar(File classFile, File dexFile) throws IOException {
|
||||||
final Main.Arguments arguments = new Main.Arguments();
|
final Main.Arguments arguments = new Main.Arguments();
|
||||||
arguments.fileNames = new String[]{classFile.getPath()};
|
arguments.fileNames = new String[]{classFile.getPath()};
|
||||||
File dexFile = generateTempClassFile("dex-" + classFile.getPath(), true);
|
boolean isTmpDex = dexFile == null;
|
||||||
|
if (isTmpDex) {
|
||||||
|
dexFile = generateTempFile("dex-" + classFile.getPath(), true);
|
||||||
|
}
|
||||||
arguments.outName = dexFile.getPath();
|
arguments.outName = dexFile.getPath();
|
||||||
arguments.jarOutput = true;
|
arguments.jarOutput = true;
|
||||||
Main.run(arguments);
|
Main.run(arguments);
|
||||||
DexClassLoader loader = loadDex(dexFile);
|
DexClassLoader loader = loadDex(dexFile);
|
||||||
dexFile.delete();
|
if (isTmpDex) {
|
||||||
|
dexFile.delete();
|
||||||
|
}
|
||||||
return loader;
|
return loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
10
build.gradle
10
build.gradle
@@ -28,9 +28,11 @@ task clean(type: Delete) {
|
|||||||
|
|
||||||
ext {
|
ext {
|
||||||
versions = [
|
versions = [
|
||||||
target: 28,
|
appVersionCode: 423,
|
||||||
mini: 17,
|
appVersionName: '4.0.3 Alpha4',
|
||||||
compile: 28,
|
target : 28,
|
||||||
buildTool: '28.0.3'
|
mini : 17,
|
||||||
|
compile : 28,
|
||||||
|
buildTool : '28.0.3'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -395,6 +395,19 @@ public class PFiles {
|
|||||||
return file.delete();
|
return file.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean deleteFilesOfDir(File dir) {
|
||||||
|
if (!dir.isDirectory())
|
||||||
|
throw new IllegalArgumentException("not a directory: " + dir);
|
||||||
|
File[] children = dir.listFiles();
|
||||||
|
if (children != null) {
|
||||||
|
for (File child : children) {
|
||||||
|
if (!deleteRecursively(child))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean remove(String path) {
|
public static boolean remove(String path) {
|
||||||
return new File(path).delete();
|
return new File(path).delete();
|
||||||
}
|
}
|
||||||
|
|||||||
26
common/src/main/java/com/stardust/util/MD5.java
Normal file
26
common/src/main/java/com/stardust/util/MD5.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package com.stardust.util;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
public class MD5 {
|
||||||
|
|
||||||
|
public static byte[] md5Bytes(String message) throws NoSuchAlgorithmException {
|
||||||
|
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||||
|
md5.update(message.getBytes());
|
||||||
|
return md5.digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String md5(String message) throws NoSuchAlgorithmException {
|
||||||
|
byte[] bytes = md5Bytes(message);
|
||||||
|
StringBuilder hexString = new StringBuilder(32);
|
||||||
|
for (byte b : bytes) {
|
||||||
|
String hex = Integer.toHexString(0xFF & b);
|
||||||
|
if (hex.length() == 1) {
|
||||||
|
hexString.append('0');
|
||||||
|
}
|
||||||
|
hexString.append(hex);
|
||||||
|
}
|
||||||
|
return hexString.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,8 +8,8 @@ android {
|
|||||||
applicationId "com.stardust.auojs.inrt"
|
applicationId "com.stardust.auojs.inrt"
|
||||||
minSdkVersion versions.mini
|
minSdkVersion versions.mini
|
||||||
targetSdkVersion versions.target
|
targetSdkVersion versions.target
|
||||||
versionCode 210
|
versionCode versions.appVersionCode - 200
|
||||||
versionName "4.0.2 Alpha5"
|
versionName versions.appVersionName
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters 'armeabi-v7a'
|
abiFilters 'armeabi-v7a'
|
||||||
|
|||||||
@@ -26,7 +26,8 @@
|
|||||||
android:label="inrt"
|
android:label="inrt"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
tools:replace="android:label, android:allowBackup">
|
tools:replace="android:label, android:allowBackup"
|
||||||
|
tools:ignore="GoogleAppIndexingWarning">
|
||||||
<activity android:name=".LogActivity">
|
<activity android:name=".LogActivity">
|
||||||
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|||||||
Reference in New Issue
Block a user