Skip to content

Commit

Permalink
feat(core.manager): 支持extractNativeLibs="false"时不解压so
Browse files Browse the repository at this point in the history
API大于等于23时有效。插件Manifest中设置extractNativeLibs="false",
正常的编译流程就会不压缩apk中的so文件。此时将apk路径拼接上so目录直接设置
为ClassLoader的librarySearchPath即可加载so。

参考引用见issue记录。

#739
  • Loading branch information
shifujun committed Jan 5, 2022
1 parent 307800c commit b4dc172
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import android.content.Context;
import android.os.RemoteException;
import android.util.Pair;

import com.tencent.shadow.core.common.Logger;
import com.tencent.shadow.core.common.LoggerFactory;
Expand All @@ -33,6 +34,7 @@

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
Expand All @@ -59,6 +61,7 @@ public InstalledPlugin installPlugin(String zip, String hash , boolean odex) thr
final PluginConfig pluginConfig = installPluginFromZip(new File(zip), hash);
final String uuid = pluginConfig.UUID;
List<Future> futures = new LinkedList<>();
List<Future<Pair<String, String>>> extractSoFutures = new LinkedList<>();
if (pluginConfig.runTime != null && pluginConfig.pluginLoader != null) {
Future odexRuntime = mFixedPool.submit(new Callable() {
@Override
Expand All @@ -82,14 +85,9 @@ public Object call() throws Exception {
for (Map.Entry<String, PluginConfig.PluginFileInfo> plugin : pluginConfig.plugins.entrySet()) {
final String partKey = plugin.getKey();
final File apkFile = plugin.getValue().file;
Future extractSo = mFixedPool.submit(new Callable() {
@Override
public Object call() throws Exception {
extractSo(uuid, partKey, apkFile);
return null;
}
});
Future<Pair<String, String>> extractSo = mFixedPool.submit(() -> extractSo(uuid, partKey, apkFile));
futures.add(extractSo);
extractSoFutures.add(extractSo);
if (odex) {
Future odexPlugin = mFixedPool.submit(new Callable() {
@Override
Expand All @@ -105,7 +103,12 @@ public Object call() throws Exception {
for (Future future : futures) {
future.get();
}
onInstallCompleted(pluginConfig);
Map<String, String> soDirMap = new HashMap<>();
for (Future<Pair<String, String>> future : extractSoFutures) {
Pair<String, String> pair = future.get();
soDirMap.put(pair.first, pair.second);
}
onInstallCompleted(pluginConfig, soDirMap);

return getInstalledPlugins(1).get(0);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Pair;

import com.tencent.shadow.core.common.Logger;
import com.tencent.shadow.core.common.LoggerFactory;
Expand Down Expand Up @@ -112,13 +113,14 @@ public final PluginConfig installPluginFromZip(File zip, String hash) throws IOE
* 将插件信息持久化到数据库
*
* @param pluginConfig 插件配置信息
* @param soDirMap key:type+partKey
*/
public final void onInstallCompleted(PluginConfig pluginConfig) {
public final void onInstallCompleted(PluginConfig pluginConfig,
Map<String, String> soDirMap) {
File root = mUnpackManager.getAppDir();
String soDir = AppCacheFolderManager.getLibDir(root, pluginConfig.UUID).getAbsolutePath();
String oDexDir = AppCacheFolderManager.getODexDir(root, pluginConfig.UUID).getAbsolutePath();

mInstalledDao.insert(pluginConfig, soDir, oDexDir);
mInstalledDao.insert(pluginConfig, soDirMap, oDexDir);
}

protected InstalledPlugin.Part getPluginPartByPartKey(String uuid, String partKey) {
Expand Down Expand Up @@ -176,8 +178,9 @@ public final void oDexPlugin(String uuid, String partKey, File apkFile) throws I

/**
* odex优化
* @param uuid 插件包的uuid
* @param type 要oDex的插件类型 @class IntalledType loader or runtime
*
* @param uuid 插件包的uuid
* @param type 要oDex的插件类型 @class IntalledType loader or runtime
* @param apkFile 插件apk文件
*/
public final void oDexPluginLoaderOrRunTime(String uuid, int type, File apkFile) throws InstallPluginException {
Expand Down Expand Up @@ -205,25 +208,39 @@ public final void oDexPluginLoaderOrRunTime(String uuid, int type, File apkFile)
* @param uuid 插件包的uuid
* @param partKey 要解压so的插件partkey
* @param apkFile 插件apk文件
* @return soDirMap条目
*/
public final void extractSo(String uuid, String partKey, File apkFile) throws InstallPluginException {
public final Pair<String, String> extractSo(String uuid, String partKey, File apkFile) throws InstallPluginException {
try {
File root = mUnpackManager.getAppDir();
File soDir = AppCacheFolderManager.getLibDir(root, uuid);
String soDirMapKey = InstalledType.TYPE_PLUGIN + partKey;
String soDirPath = soDir.getAbsolutePath();

String pluginPreferredAbi = getPluginPreferredAbi(getPluginSupportedAbis(), apkFile);
if (pluginPreferredAbi.isEmpty()) {
if (mLogger.isInfoEnabled()) {
mLogger.info("插件没有so");
}
return;
}
String filter = "lib/" + pluginPreferredAbi + "/";
File soDir = AppCacheFolderManager.getLibDir(root, uuid);
if (mLogger.isInfoEnabled()) {
mLogger.info("extractSo uuid=={} partKey=={} apkFile=={} soDir=={} filter=={}",
uuid, partKey, apkFile.getAbsolutePath(), soDir.getAbsolutePath(), filter);
} else {
String filter = "lib/" + pluginPreferredAbi + "/";

// 插件如果设置了android:extractNativeLibs="false",则不需要解压出so
boolean needExtractNativeLibs = needExtractNativeLibs(apkFile, filter);

if (mLogger.isInfoEnabled()) {
mLogger.info("extractSo uuid=={} partKey=={} apkFile=={} soDir=={} filter=={} needExtractNativeLibs=={}",
uuid, partKey, apkFile.getAbsolutePath(), soDir.getAbsolutePath(), filter, needExtractNativeLibs);
}

if (needExtractNativeLibs) {
CopySoBloc.copySo(apkFile, soDir
, AppCacheFolderManager.getLibCopiedFile(soDir, partKey), filter);
} else {
soDirPath = apkFile.getAbsolutePath() + "!/" + filter;
}
}
CopySoBloc.copySo(apkFile, soDir
, AppCacheFolderManager.getLibCopiedFile(soDir, partKey), filter);
return new Pair<>(soDirMapKey, soDirPath);
} catch (InstallPluginException e) {
if (mLogger.isErrorEnabled()) {
mLogger.error("extractSo exception:", e);
Expand All @@ -235,25 +252,34 @@ public final void extractSo(String uuid, String partKey, File apkFile) throws In
/**
* 插件apk的so解压
*
* @param uuid 插件包的uuid
* @param type 要oDex的插件类型 @class IntalledType loader or runtime
* @param uuid 插件包的uuid
* @param type 要oDex的插件类型 @class IntalledType loader or runtime
* @param apkFile 插件apk文件
* @return soDirMap条目
*/
public final void extractLoaderOrRunTimeSo(String uuid, int type, File apkFile) throws InstallPluginException {
public final Pair<String, String> extractLoaderOrRunTimeSo(String uuid,
int type,
File apkFile)
throws InstallPluginException {
try {
File root = mUnpackManager.getAppDir();
String key = type == InstalledType.TYPE_PLUGIN_LOADER ? "loader" : "runtime";
String pluginPreferredAbi = getPluginPreferredAbi(getPluginSupportedAbis(), apkFile);
String filter = "lib/" + pluginPreferredAbi + "/";
File soDir = AppCacheFolderManager.getLibDir(root, uuid);

if (pluginPreferredAbi.isEmpty()) {
if (mLogger.isInfoEnabled()) {
mLogger.info(key + "没有so");
}
return;
} else {
CopySoBloc.copySo(apkFile, soDir
, AppCacheFolderManager.getLibCopiedFile(soDir, key), filter);
}
String filter = "lib/" + pluginPreferredAbi + "/";
File soDir = AppCacheFolderManager.getLibDir(root, uuid);
CopySoBloc.copySo(apkFile, soDir
, AppCacheFolderManager.getLibCopiedFile(soDir, key), filter);

String soDirMapKey = Integer.toString(type) + null;// 同InstalledDao.parseConfig
String soDirPath = soDir.getAbsolutePath();
return new Pair<>(soDirMapKey, soDirPath);
} catch (InstallPluginException e) {
if (mLogger.isErrorEnabled()) {
mLogger.error("extractLoaderOrRunTimeSo exception:", e);
Expand Down Expand Up @@ -417,6 +443,28 @@ private static boolean is64BitInstructionSet(String instructionSet) {
"mips64".equals(instructionSet);
}

private static boolean needExtractNativeLibs(File apkFile, String filter) throws InstallPluginException {
//android:extractNativeLibs是API 23引入的
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
ZipFile zipFile;
try {
zipFile = new SafeZipFile(apkFile);
} catch (IOException e) {
throw new InstallPluginException("读取apk失败,apkFile==" + apkFile, e);
}
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
String name = entry.getName();
if (name.startsWith(filter)) {
return entry.getMethod() != ZipEntry.STORED;
}
}
return false;
}

/**
* 释放资源
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand All @@ -44,12 +45,15 @@ public InstalledDao(InstalledPluginDBHelper dbHelper) {
* 根据插件配置信息插入一组数据
*
* @param pluginConfig 插件配置信息
* @param soDir
* @param soDirMap key:type+partKey
* @param oDexDir
*/
public void insert(PluginConfig pluginConfig, String soDir, String oDexDir) {
public void insert(PluginConfig pluginConfig, Map<String, String> soDirMap, String oDexDir) {
SQLiteDatabase db = mDBHelper.getWritableDatabase();
List<ContentValues> contentValuesList = parseConfig(pluginConfig, soDir, oDexDir);
if (soDirMap == null) {
soDirMap = Collections.emptyMap();
}
List<ContentValues> contentValuesList = parseConfig(pluginConfig, soDirMap, oDexDir);
db.beginTransaction();
try {
for (ContentValues contentValues : contentValuesList) {
Expand Down Expand Up @@ -174,25 +178,32 @@ public List<InstalledPlugin> getLastPlugins(int limit) {
return installedPlugins;
}

private List<ContentValues> parseConfig(PluginConfig pluginConfig, String soDir, String oDexDir) {
private List<ContentValues> parseConfig(PluginConfig pluginConfig,
Map<String, String> soDirMap,// key:type+partKey
String oDexDir
) {
List<InstalledRow> installedRows = new ArrayList<>();
if (pluginConfig.pluginLoader != null) {
String soDir = soDirMap.get(Integer.toString(InstalledType.TYPE_PLUGIN_LOADER) + null);
installedRows.add(new InstalledRow(pluginConfig.pluginLoader.hash, null, pluginConfig.pluginLoader.file.getAbsolutePath(), InstalledType.TYPE_PLUGIN_LOADER,
soDir, oDexDir));
}
if (pluginConfig.runTime != null) {
String soDir = soDirMap.get(Integer.toString(InstalledType.TYPE_PLUGIN_RUNTIME) + null);
installedRows.add(new InstalledRow(pluginConfig.runTime.hash, null, pluginConfig.runTime.file.getAbsolutePath(), InstalledType.TYPE_PLUGIN_RUNTIME,
soDir, oDexDir));
}
if (pluginConfig.plugins != null) {
Set<Map.Entry<String, PluginConfig.PluginFileInfo>> plugins = pluginConfig.plugins.entrySet();
for (Map.Entry<String, PluginConfig.PluginFileInfo> plugin : plugins) {
PluginConfig.PluginFileInfo fileInfo = plugin.getValue();
String partKey = plugin.getKey();
String soDir = soDirMap.get(InstalledType.TYPE_PLUGIN + partKey);
installedRows.add(
new InstalledRow(
fileInfo.hash,
fileInfo.businessName,
plugin.getKey(),
partKey,
fileInfo.dependsOn,
fileInfo.file.getAbsolutePath(),
InstalledType.TYPE_PLUGIN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.util.Pair;

import com.tencent.shadow.core.common.Logger;
import com.tencent.shadow.core.common.LoggerFactory;
Expand All @@ -35,6 +36,7 @@

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
Expand All @@ -61,6 +63,7 @@ public InstalledPlugin installPlugin(String zip, String hash , boolean odex) thr
final PluginConfig pluginConfig = installPluginFromZip(new File(zip), hash);
final String uuid = pluginConfig.UUID;
List<Future> futures = new LinkedList<>();
List<Future<Pair<String, String>>> extractSoFutures = new LinkedList<>();
if (pluginConfig.runTime != null && pluginConfig.pluginLoader != null) {
Future odexRuntime = mFixedPool.submit(new Callable() {
@Override
Expand All @@ -84,14 +87,9 @@ public Object call() throws Exception {
for (Map.Entry<String, PluginConfig.PluginFileInfo> plugin : pluginConfig.plugins.entrySet()) {
final String partKey = plugin.getKey();
final File apkFile = plugin.getValue().file;
Future extractSo = mFixedPool.submit(new Callable() {
@Override
public Object call() throws Exception {
extractSo(uuid, partKey, apkFile);
return null;
}
});
Future<Pair<String, String>> extractSo = mFixedPool.submit(() -> extractSo(uuid, partKey, apkFile));
futures.add(extractSo);
extractSoFutures.add(extractSo);
if (odex) {
Future odexPlugin = mFixedPool.submit(new Callable() {
@Override
Expand All @@ -107,7 +105,12 @@ public Object call() throws Exception {
for (Future future : futures) {
future.get();
}
onInstallCompleted(pluginConfig);
Map<String, String> soDirMap = new HashMap<>();
for (Future<Pair<String, String>> future : extractSoFutures) {
Pair<String, String> pair = future.get();
soDirMap.put(pair.first, pair.second);
}
onInstallCompleted(pluginConfig, soDirMap);

return getInstalledPlugins(1).get(0);
}
Expand Down

0 comments on commit b4dc172

Please sign in to comment.