提交 1b7cfbf7 编写于 作者: S superq_sky

Optimized process of copying native libs.

上级 ad024b1b
...@@ -47,7 +47,6 @@ import android.content.res.XmlResourceParser; ...@@ -47,7 +47,6 @@ import android.content.res.XmlResourceParser;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Bundle;
import android.os.Process; import android.os.Process;
import android.os.UserHandle; import android.os.UserHandle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
...@@ -147,22 +146,7 @@ public final class LoadedPlugin { ...@@ -147,22 +146,7 @@ public final class LoadedPlugin {
private Application mApplication; private Application mApplication;
// void dumpClass(Class cls) { LoadedPlugin(PluginManager pluginManager, Context context, File apk) throws Exception {
// Log.w(TAG, "########################################");
// Log.w(TAG, "cls: " + cls.getName());
// Log.w(TAG, "cls.super: " + cls.getSuperclass());
// Log.w(TAG, "field size: " + cls.getDeclaredFields().length);
// Log.w(TAG, "method size: " + cls.getDeclaredMethods().length);
//
// for (Field f : cls.getDeclaredFields()) {
// Log.w(TAG, "field: " + f.getType().getName() + " " + f.getName());
// }
// for (Method m : cls.getDeclaredMethods()) {
// Log.w(TAG, "method: " + m.getReturnType() + " " + m.getName() + " " + Arrays.toString(m.getParameterTypes()));
// }
// }
LoadedPlugin(PluginManager pluginManager, Context context, File apk) throws PackageParser.PackageParserException {
this.mPluginManager = pluginManager; this.mPluginManager = pluginManager;
this.mHostContext = context; this.mHostContext = context;
this.mLocation = apk.getAbsolutePath(); this.mLocation = apk.getAbsolutePath();
...@@ -172,14 +156,6 @@ public final class LoadedPlugin { ...@@ -172,14 +156,6 @@ public final class LoadedPlugin {
this.mPackageInfo.applicationInfo = this.mPackage.applicationInfo; this.mPackageInfo.applicationInfo = this.mPackage.applicationInfo;
this.mPackageInfo.applicationInfo.sourceDir = apk.getAbsolutePath(); this.mPackageInfo.applicationInfo.sourceDir = apk.getAbsolutePath();
// dumpClass(PackageParser.class);
// dumpClass(this.mPackage.getClass());
// try {
// dumpClass(Class.forName("android.content.pm.PackageParser$SigningDetails"));
// } catch (ClassNotFoundException e) {
// Log.w(TAG, e);
// }
if (Build.VERSION.SDK_INT == 27 && Build.VERSION.PREVIEW_SDK_INT != 0) { // Android P Preview if (Build.VERSION.SDK_INT == 27 && Build.VERSION.PREVIEW_SDK_INT != 0) { // Android P Preview
this.mPackageInfo.signatures = this.mPackage.mSigningDetails.signatures; this.mPackageInfo.signatures = this.mPackage.mSigningDetails.signatures;
} else { } else {
...@@ -239,25 +215,18 @@ public final class LoadedPlugin { ...@@ -239,25 +215,18 @@ public final class LoadedPlugin {
Map<ComponentName, ActivityInfo> receivers = new HashMap<ComponentName, ActivityInfo>(); Map<ComponentName, ActivityInfo> receivers = new HashMap<ComponentName, ActivityInfo>();
for (PackageParser.Activity receiver : this.mPackage.receivers) { for (PackageParser.Activity receiver : this.mPackage.receivers) {
receivers.put(receiver.getComponentName(), receiver.info); receivers.put(receiver.getComponentName(), receiver.info);
try { BroadcastReceiver br = BroadcastReceiver.class.cast(getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance());
BroadcastReceiver br = BroadcastReceiver.class.cast(getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance()); for (PackageParser.ActivityIntentInfo aii : receiver.intents) {
for (PackageParser.ActivityIntentInfo aii : receiver.intents) { this.mHostContext.registerReceiver(br, aii);
this.mHostContext.registerReceiver(br, aii);
}
} catch (Exception e) {
e.printStackTrace();
} }
} }
this.mReceiverInfos = Collections.unmodifiableMap(receivers); this.mReceiverInfos = Collections.unmodifiableMap(receivers);
this.mPackageInfo.receivers = receivers.values().toArray(new ActivityInfo[receivers.size()]); this.mPackageInfo.receivers = receivers.values().toArray(new ActivityInfo[receivers.size()]);
} }
private void tryToCopyNativeLib(File apk) { private void tryToCopyNativeLib(File apk) throws Exception {
Bundle metaData = this.mPackageInfo.applicationInfo.metaData; PluginUtil.copyNativeLib(apk, mHostContext, mPackageInfo, mNativeLibDir);
if (metaData != null && metaData.getBoolean("VA_IS_HAVE_LIB")) {
PluginUtil.copyNativeLib(apk, mHostContext, mPackageInfo, mNativeLibDir);
}
} }
public String getLocation() { public String getLocation() {
......
...@@ -23,15 +23,13 @@ import android.content.Intent; ...@@ -23,15 +23,13 @@ import android.content.Intent;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.support.annotation.Keep;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import android.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import com.didi.virtualapk.PluginManager; import com.didi.virtualapk.PluginManager;
...@@ -46,10 +44,6 @@ import java.io.IOException; ...@@ -46,10 +44,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
...@@ -186,68 +180,98 @@ public class PluginUtil { ...@@ -186,68 +180,98 @@ public class PluginUtil {
return null; return null;
} }
} }
public static void copyNativeLib(File apk, Context context, PackageInfo packageInfo, File nativeLibDir) { public static void copyNativeLib(File apk, Context context, PackageInfo packageInfo, File nativeLibDir) throws Exception {
long startTime = System.currentTimeMillis();
ZipFile zipfile = new ZipFile(apk.getAbsolutePath());
try { try {
String cpuArch;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cpuArch = Build.SUPPORTED_ABIS[0]; for (String cpuArch : Build.SUPPORTED_ABIS) {
if (findAndCopyNativeLib(zipfile, context, cpuArch, packageInfo, nativeLibDir)) {
return;
}
}
} else { } else {
cpuArch = Build.CPU_ABI; if (findAndCopyNativeLib(zipfile, context, Build.CPU_ABI, packageInfo, nativeLibDir)) {
} return;
boolean findSo = false;
ZipFile zipfile = new ZipFile(apk.getAbsolutePath());
ZipEntry entry;
Enumeration e = zipfile.entries();
while (e.hasMoreElements()) {
entry = (ZipEntry) e.nextElement();
if (entry.isDirectory())
continue;
if(entry.getName().endsWith(".so") && entry.getName().contains("lib/" + cpuArch)){
findSo = true;
break;
} }
} }
e = zipfile.entries();
while (e.hasMoreElements()) { findAndCopyNativeLib(zipfile, context, "armeabi", packageInfo, nativeLibDir);
entry = (ZipEntry) e.nextElement();
if (entry.isDirectory() || !entry.getName().endsWith(".so")) } finally {
zipfile.close();
Log.d("NativeLib", "Done! +" + (System.currentTimeMillis() - startTime) + "ms");
}
}
private static boolean findAndCopyNativeLib(ZipFile zipfile, Context context, String cpuArch, PackageInfo packageInfo, File nativeLibDir) throws Exception {
Log.d("NativeLib", "Try to copy plugin's cup arch: " + cpuArch);
boolean findLib = false;
boolean findSo = false;
byte buffer[] = null;
String libPrefix = "lib/" + cpuArch + "/";
ZipEntry entry;
Enumeration e = zipfile.entries();
while (e.hasMoreElements()) {
entry = (ZipEntry) e.nextElement();
String entryName = entry.getName();
if (entryName.charAt(0) < 'l') {
continue;
}
if (entryName.charAt(0) > 'l') {
break;
}
if (!findLib && !entryName.startsWith("lib/")) {
continue;
}
findLib = true;
if (!entryName.endsWith(".so") || !entryName.startsWith(libPrefix)) {
continue;
}
if (buffer == null) {
findSo = true;
Log.d("NativeLib", "Found plugin's cup arch dir: " + cpuArch);
buffer = new byte[8192];
}
String libName = entryName.substring(entryName.lastIndexOf('/') + 1);
Log.d("NativeLib", "verify so " + libName);
File libFile = new File(nativeLibDir, libName);
String key = packageInfo.packageName + "_" + libName;
if (libFile.exists()) {
int VersionCode = Settings.getSoVersion(context, key);
if (VersionCode == packageInfo.versionCode) {
Log.d("NativeLib", "skip existing so : " + entry.getName());
continue; continue;
if((findSo && entry.getName().contains("lib/" + cpuArch)) || (!findSo && entry.getName().contains("lib/armeabi/"))){
String[] temp = entry.getName().split("/");
String libName = temp[temp.length - 1];
System.out.println("verify so " + libName);
File libFile = new File(nativeLibDir.getAbsolutePath() + File.separator + libName);
String key = packageInfo.packageName + "_" + libName;
if (libFile.exists()) {
int VersionCode = Settings.getSoVersion(context, key);
if (VersionCode == packageInfo.versionCode) {
System.out.println("skip existing so : " + entry.getName());
continue;
}
}
FileOutputStream fos = new FileOutputStream(libFile);
System.out.println("copy so " + entry.getName() + " of " + cpuArch);
copySo(zipfile.getInputStream(entry), fos);
Settings.setSoVersion(context, key, packageInfo.versionCode);
} }
} }
FileOutputStream fos = new FileOutputStream(libFile);
zipfile.close(); Log.d("NativeLib", "copy so " + entry.getName() + " of " + cpuArch);
} catch (IOException e) { copySo(buffer, zipfile.getInputStream(entry), fos);
e.printStackTrace(); Settings.setSoVersion(context, key, packageInfo.versionCode);
} }
if (!findLib) {
Log.d("NativeLib", "Fast skip all!");
return true;
}
return findSo;
} }
private static void copySo(InputStream input, OutputStream output) throws IOException { private static void copySo(byte[] buffer, InputStream input, OutputStream output) throws IOException {
BufferedInputStream bufferedInput = new BufferedInputStream(input); BufferedInputStream bufferedInput = new BufferedInputStream(input);
BufferedOutputStream bufferedOutput = new BufferedOutputStream(output); BufferedOutputStream bufferedOutput = new BufferedOutputStream(output);
int count; int count;
byte data[] = new byte[8192];
while ((count = bufferedInput.read(data, 0, 8192)) != -1) { while ((count = bufferedInput.read(buffer)) > 0) {
bufferedOutput.write(data, 0, count); bufferedOutput.write(buffer, 0, count);
} }
bufferedOutput.flush(); bufferedOutput.flush();
bufferedOutput.close(); bufferedOutput.close();
......
...@@ -11,7 +11,7 @@ def gitUrl = 'https://github.com/didi/VirtualAPK' // Git仓库的url ...@@ -11,7 +11,7 @@ def gitUrl = 'https://github.com/didi/VirtualAPK' // Git仓库的url
group = GROUP_ID group = GROUP_ID
archivesBaseName = 'core' archivesBaseName = 'core'
version = "0.9.4-dev" version = "0.9.5-dev"
install { install {
......
...@@ -51,7 +51,7 @@ dependencies { ...@@ -51,7 +51,7 @@ dependencies {
// the following aars are also compiled in host project, so they will be filterd when build plugin apk. // the following aars are also compiled in host project, so they will be filterd when build plugin apk.
// but, wo can still visit their Class and Resources. // but, wo can still visit their Class and Resources.
compile 'com.android.support:appcompat-v7:23.4.0' compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.didi.virtualapk:core:0.9.4-dev' compile 'com.didi.virtualapk:core:0.9.5-dev'
} }
apply plugin: 'com.didi.virtualapk.plugin' apply plugin: 'com.didi.virtualapk.plugin'
......
...@@ -41,7 +41,7 @@ apply plugin: 'com.didi.virtualapk.host' ...@@ -41,7 +41,7 @@ apply plugin: 'com.didi.virtualapk.host'
Compile VirtualAPK in application module of `build.gradle`. Compile VirtualAPK in application module of `build.gradle`.
``` java ``` java
compile 'com.didi.virtualapk:core:0.9.4-dev' compile 'com.didi.virtualapk:core:0.9.5-dev'
``` ```
Initialize `PluginManager` in `YourApplication::attachBaseContext()`. Initialize `PluginManager` in `YourApplication::attachBaseContext()`.
......
...@@ -49,7 +49,7 @@ dependencies { ...@@ -49,7 +49,7 @@ dependencies {
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0' compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.didi.virtualapk:core:0.9.4-dev' compile 'com.didi.virtualapk:core:0.9.5-dev'
// compile project (':CoreLibrary') // compile project (':CoreLibrary')
} }
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册