Skip to content

Commit

Permalink
use system NativeLibraryHelper for copying native binaries
Browse files Browse the repository at this point in the history
  • Loading branch information
JackCho committed Apr 22, 2016
1 parent 3179d92 commit f8491e0
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,26 +54,19 @@
import com.morgoo.droidplugin.pm.parser.PluginPackageParser;
import com.morgoo.helper.Log;
import com.morgoo.helper.Utils;
import com.morgoo.helper.compat.BuildCompat;
import com.morgoo.helper.compat.NativeLibraryHelperCompat;
import com.morgoo.helper.compat.PackageManagerCompat;
import com.morgoo.helper.compat.VMRuntimeCompat;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
* 此服务模仿系统的PackageManagerService,提供对插件简单的管理服务。
Expand Down Expand Up @@ -987,115 +980,10 @@ private void sendUninstalledBroadcast(String packageName) {

private void copyNativeLibs(Context context, String apkfile, ApplicationInfo applicationInfo) throws Exception {
String nativeLibraryDir = PluginDirHelper.getPluginNativeLibraryDir(context, applicationInfo.packageName);
ZipFile zipFile = null;
try {
zipFile = new ZipFile(apkfile);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
Map<String, ZipEntry> libZipEntries = new HashMap<String, ZipEntry>();
Map<String, Set<String>> soList = new HashMap<String, Set<String>>(1);
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
String name = entry.getName();
if (name.contains("../")) {
Log.d(TAG, "Path traversal attack prevented");
continue;
}
if (name.startsWith("lib/") && !entry.isDirectory()) {
libZipEntries.put(name, entry);
String soName = new File(name).getName();
Set<String> fs = soList.get(soName);
if (fs == null) {
fs = new TreeSet<String>();
soList.put(soName, fs);
}
fs.add(name);
}
}

for (String soName : soList.keySet()) {
Log.e(TAG, "try so =" + soName);
Set<String> soPaths = soList.get(soName);
String soPath = findSoPath(soPaths, soName);
if (soPath != null) {
File file = new File(nativeLibraryDir, soName);
if (file.exists()) {
file.delete();
}
InputStream in = null;
FileOutputStream ou = null;
try {
in = zipFile.getInputStream(libZipEntries.get(soPath));
ou = new FileOutputStream(file);
byte[] buf = new byte[8192];
int read = 0;
while ((read = in.read(buf)) != -1) {
ou.write(buf, 0, read);
}
ou.flush();
ou.getFD().sync();
Log.i(TAG, "copy so(%s) for %s to %s ok!", soName, soPath, file.getPath());
} catch (Exception e) {
if (file.exists()) {
file.delete();
}
throw e;
} finally {
if (in != null) {
try {
in.close();
} catch (Exception e) {
}
}
if (ou != null) {
try {
ou.close();
} catch (Exception e) {
}
}
}
}
}
} finally {
if (zipFile != null) {
try {
zipFile.close();
} catch (Exception e) {
}
}
}
NativeLibraryHelperCompat.copyNativeBinaries(new File(apkfile), new File(nativeLibraryDir));
}


private String findSoPath(Set<String> soPaths, String soName) {
if (soPaths != null && soPaths.size() > 0) {
if (VMRuntimeCompat.is64Bit()) {
//在宿主程序运行在64位进程中的时候,插件的so也只拷贝64位,否则会出现不支持的情况。
String[] supported64BitAbis = BuildCompat.SUPPORTED_64_BIT_ABIS;
Arrays.sort(supported64BitAbis);
for (String soPath : soPaths) {
String abi = soPath.replaceFirst("lib/", "");
abi = abi.replace("/" + soName, "");

if (!TextUtils.isEmpty(abi) && Arrays.binarySearch(supported64BitAbis, abi) >= 0) {
return soPath;
}
}
} else {
//在宿主程序运行在32位进程中的时候,插件的so也只拷贝64位,否则会出现不支持的情况。
String[] supported32BitAbis = BuildCompat.SUPPORTED_32_BIT_ABIS;
Arrays.sort(supported32BitAbis);
for (String soPath : soPaths) {
String abi = soPath.replaceFirst("lib/", "");
abi = abi.replace("/" + soName, "");
if (!TextUtils.isEmpty(abi) && Arrays.binarySearch(supported32BitAbis, abi) >= 0) {
return soPath;
}
}
}
}
return null;
}

@Override
public int deletePackage(String packageName, int flags) throws RemoteException {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.morgoo.helper.compat;

import android.annotation.TargetApi;
import android.os.Build;
import com.morgoo.droidplugin.reflect.MethodUtils;
import java.io.File;
import java.lang.reflect.InvocationTargetException;

public class NativeLibraryHelperCompat {


private static final Class nativeLibraryHelperClass() throws ClassNotFoundException {
return Class.forName("com.android.internal.content.NativeLibraryHelper");
}

private static final Class handleClass() throws ClassNotFoundException {
return Class.forName("com.android.internal.content.NativeLibraryHelper$Handle");
}

public static final int copyNativeBinaries(File apkFile, File sharedLibraryDir) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return copyNativeBinariesAfterM(apkFile, sharedLibraryDir);
} else {
return copyNativeBinariesBeforeM(apkFile, sharedLibraryDir);
}

}

private static int copyNativeBinariesBeforeM(File apkFile, File sharedLibraryDir) {
try {
Object[] args = new Object[2];
args[0] = apkFile;
args[1] = sharedLibraryDir;

return (int) MethodUtils.invokeStaticMethod(nativeLibraryHelperClass(), "copyNativeBinariesIfNeededLI", args);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

return -1;
}

@TargetApi(Build.VERSION_CODES.M)
private static int copyNativeBinariesAfterM(File apkFile, File sharedLibraryDir) {

try {
Object handleInstance = MethodUtils.invokeStaticMethod(handleClass(), "create", apkFile);
if (handleInstance == null) {
return -1;
}
String abi = null;
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
int abiIndex = (int) MethodUtils.invokeStaticMethod(nativeLibraryHelperClass(), "findSupportedAbi", handleInstance, Build.SUPPORTED_32_BIT_ABIS);
abi = Build.SUPPORTED_32_BIT_ABIS[abiIndex];
}

if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
int abiIndex = (int) MethodUtils.invokeStaticMethod(nativeLibraryHelperClass(), "findSupportedAbi", handleInstance, Build.SUPPORTED_64_BIT_ABIS);
if (abiIndex >= 0) {
abi = Build.SUPPORTED_64_BIT_ABIS[abiIndex];
}
}

Object[] args = new Object[3];
args[0] = handleInstance;
args[1] = sharedLibraryDir;
args[2] = abi;
return (int) MethodUtils.invokeStaticMethod(nativeLibraryHelperClass(), "copyNativeBinaries", args);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

return -1;
}
}

0 comments on commit f8491e0

Please sign in to comment.