Skip to content

Commit 4f3e23c

Browse files
committed
2 parents 9b6d0be + 253452f commit 4f3e23c

File tree

8 files changed

+306
-77
lines changed

8 files changed

+306
-77
lines changed

PluginCore/src/com/plugin/core/PluginIntentResolver.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,12 @@ public class PluginIntentResolver {
3939

4040
/* package */static void hackReceiverForClassLoader(Object msgObj) {
4141
Intent intent = (Intent) RefInvoker.getFieldObject(msgObj, "android.app.ActivityThread$ReceiverData", "intent");
42+
LogUtil.d("receiver", intent.toUri(0));
4243
if (intent.getComponent().getClassName().equals(PluginStubReceiver.class.getName())) {
4344
Intent realIntent = (Intent) (intent.getParcelableExtra(RECEIVER_ID_IN_PLUGIN));
44-
LogUtil.d("receiver", realIntent.toUri(0));
45+
if (realIntent == null) {
46+
return;
47+
}
4548
intent.putExtras(realIntent.getExtras());
4649
String realClassName = PluginLoader.isMatchPlugin(realIntent);
4750
// PluginReceiverClassLoader检测到这个特殊标记后会进行替换
@@ -98,6 +101,7 @@ public static Intent resolveNotificationIntent(Intent intent) {
98101
return intent;
99102
}
100103

104+
@SuppressWarnings("ResourceType")
101105
public static PendingIntent resolvePendingIntent(PendingIntent origin) {
102106
if (origin != null) {
103107
Intent originIntent = (Intent)RefInvoker.invokeMethod(origin,

PluginCore/src/com/plugin/core/PluginLoader.java

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@
1313
import android.content.Context;
1414
import android.content.ContextWrapper;
1515
import android.content.Intent;
16+
import android.content.pm.ApplicationInfo;
17+
import android.content.pm.PackageInfo;
18+
import android.content.pm.PackageManager;
19+
import android.content.pm.Signature;
1620
import android.content.res.Resources;
1721
import android.os.Handler;
1822
import android.text.TextUtils;
23+
import android.util.Log;
1924

2025
import com.plugin.content.PluginDescriptor;
2126
import com.plugin.content.PluginIntentFilter;
@@ -26,11 +31,14 @@
2631
import com.plugin.util.LogUtil;
2732
import com.plugin.util.ManifestParser;
2833
import com.plugin.util.FileUtil;
34+
import com.plugin.util.PackageVerifyer;
2935
import com.plugin.util.RefInvoker;
3036

3137
import dalvik.system.DexClassLoader;
3238

3339
public class PluginLoader {
40+
41+
private static final boolean needVefifyCert = true;
3442
private static Application sApplication;
3543
private static Object activityThread;
3644
private static PluginManager pluginManager;
@@ -141,48 +149,77 @@ public static boolean isInstalled(String pluginId, String pluginVersion) {
141149
* @return
142150
*/
143151
public static synchronized boolean installPlugin(String srcPluginFile) {
144-
LogUtil.d("Install plugin ", srcPluginFile);
152+
LogUtil.d("开始安装插件", srcPluginFile);
153+
154+
//第0步,先将apk复制到宿主程序私有目录,防止在安装过程中文件被篡改
155+
//TODO XXX
156+
157+
// 第1步,验证插件APK签名,如果被篡改过,将获取不到证书
158+
//sApplication.getPackageManager().getPackageArchiveInfo(srcPluginFile, PackageManager.GET_SIGNATURES);
159+
Signature[] pluginSignatures = PackageVerifyer.collectCertificates(srcPluginFile, false);
160+
boolean isDebugable = (0 != (sApplication.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE));
161+
if (pluginSignatures == null) {
162+
LogUtil.e("插件签名验证失败", srcPluginFile);
163+
return false;
164+
} else if (needVefifyCert && isDebugable) {
165+
//可选步骤,验证插件APK证书是否和宿主程序证书相同。
166+
//证书中存放的是公钥和算法信息,而公钥和私钥是1对1的
167+
//公钥相同意味着是同一个作者发布的程序
168+
Signature[] mainSignatures = null;
169+
try {
170+
PackageInfo pkgInfo = sApplication.getPackageManager().getPackageInfo(sApplication.getPackageName(), PackageManager.GET_SIGNATURES);
171+
mainSignatures = pkgInfo.signatures;
172+
} catch (PackageManager.NameNotFoundException e) {
173+
e.printStackTrace();
174+
}
175+
if (!PackageVerifyer.isSignaturesSame(mainSignatures, pluginSignatures)) {
176+
LogUtil.d("插件证书和宿主证书不一致", srcPluginFile);
177+
return false;
178+
}
179+
}
145180

146-
boolean isInstallSuccess = false;
147-
// 第一步,读取插件描述文件
181+
// 第2步,解析Manifest,获得插件详情
148182
PluginDescriptor pluginDescriptor = ManifestParser.parseManifest(srcPluginFile);
149183
if (pluginDescriptor == null || TextUtils.isEmpty(pluginDescriptor.getPackageName())) {
150-
return isInstallSuccess;
184+
LogUtil.d("解析插件Manifest文件失败", srcPluginFile);
185+
return false;
151186
}
152187

153-
// 第二步,检查插件是否已经存在,若存在删除旧的
188+
// 第2步,检查插件是否已经存在,若存在删除旧的
154189
PluginDescriptor oldPluginDescriptor = getPluginDescriptorByPluginId(pluginDescriptor.getPackageName());
155190
if (oldPluginDescriptor != null) {
156191
remove(pluginDescriptor.getPackageName());
157192
}
158193

159-
// 第三步骤,复制插件到插件目录
160-
if (pluginDescriptor != null) {
161-
162-
String destPluginFile = genInstallPath(pluginDescriptor.getPackageName(), pluginDescriptor.getVersion());
163-
boolean isCopySuccess = FileUtil.copyFile(srcPluginFile, destPluginFile);
164-
if (isCopySuccess) {
165-
166-
//第四步,复制插件so到插件so目录, 在构造插件Dexclassloader的时候,会使用这个so目录作为参数
167-
File tempDir = new File(new File(destPluginFile).getParentFile(), "temp");
168-
Set<String> soList = FileUtil.unZipSo(srcPluginFile, tempDir);
169-
if (soList != null) {
170-
for (String soName : soList) {
171-
FileUtil.copySo(tempDir, soName, new File(destPluginFile).getParent() + File.separator + "lib");
172-
}
194+
// 第4步骤,复制插件到插件目录
195+
String destPluginFile = genInstallPath(pluginDescriptor.getPackageName(), pluginDescriptor.getVersion());
196+
boolean isCopySuccess = FileUtil.copyFile(srcPluginFile, destPluginFile);
197+
if (isCopySuccess) {
198+
199+
//第5步,复制插件so到插件so目录, 在构造插件Dexclassloader的时候,会使用这个so目录作为参数
200+
File tempDir = new File(new File(destPluginFile).getParentFile(), "temp");
201+
Set<String> soList = FileUtil.unZipSo(srcPluginFile, tempDir);
202+
if (soList != null) {
203+
for (String soName : soList) {
204+
FileUtil.copySo(tempDir, soName, new File(destPluginFile).getParent() + File.separator + "lib");
173205
}
206+
}
174207

175-
// 第五步 添加到已安装插件列表
176-
pluginDescriptor.setInstalledPath(destPluginFile);
177-
isInstallSuccess = pluginManager.addOrReplace(pluginDescriptor);
208+
// 第6步 添加到已安装插件列表
209+
pluginDescriptor.setInstalledPath(destPluginFile);
210+
boolean isInstallSuccess = pluginManager.addOrReplace(pluginDescriptor);
178211

179-
if (isInstallSuccess) {
180-
changeListener.onPluginInstalled(pluginDescriptor.getPackageName(), pluginDescriptor.getVersion());
181-
}
212+
if (isInstallSuccess) {
213+
changeListener.onPluginInstalled(pluginDescriptor.getPackageName(), pluginDescriptor.getVersion());
214+
LogUtil.d("安装插件成功", srcPluginFile);
215+
return true;
182216
}
217+
} else {
218+
LogUtil.d("复制插件到安装目录失败", srcPluginFile);
183219
}
184220

185-
return isInstallSuccess;
221+
LogUtil.d("安装插件失败", srcPluginFile);
222+
return false;
186223
}
187224

188225
/**

PluginCore/src/com/plugin/util/FileUtil.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public static Set<String> unZipSo(String apkFile, File tempDir) {
123123
tempDir.mkdirs();
124124
}
125125

126-
LogUtil.d("开始解压到", tempDir.getAbsolutePath());
126+
LogUtil.d("开始so文件", tempDir.getAbsolutePath());
127127

128128
ZipFile zfile = null;
129129
boolean isSuccess = false;
@@ -156,7 +156,7 @@ public static Set<String> unZipSo(String apkFile, File tempDir) {
156156
}
157157

158158
File targetFile = new File(tempDir, relativePath);
159-
LogUtil.d("正在解压文件", targetFile.getAbsolutePath());
159+
LogUtil.d("正在解压so文件", targetFile.getAbsolutePath());
160160
if (!targetFile.getParentFile().exists()) {
161161
targetFile.getParentFile().mkdirs();
162162
}
@@ -205,7 +205,7 @@ public static Set<String> unZipSo(String apkFile, File tempDir) {
205205
}
206206
}
207207

208-
LogUtil.d("解压结束", isSuccess);
208+
LogUtil.d("解压so文件结束", isSuccess);
209209
return result;
210210
}
211211

PluginCore/src/com/plugin/util/LogUtil.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,22 @@
55
public class LogUtil {
66

77
private static final boolean isDebug = true;
8-
8+
9+
private static final int stackLevel = 4;
10+
11+
public static void v(Object... msg) {
12+
printLog(Log.VERBOSE, msg);
13+
}
14+
915
public static void d(Object... msg) {
16+
printLog(Log.DEBUG, msg);
17+
}
18+
19+
public static void e(Object... msg) {
20+
printLog(Log.ERROR, msg);
21+
}
22+
23+
private static void printLog(int level, Object... msg) {
1024
if (isDebug) {
1125
StringBuilder str = new StringBuilder();
1226

@@ -24,8 +38,8 @@ public static void d(Object... msg) {
2438
StackTraceElement[] sts = Thread.currentThread().getStackTrace();
2539
StackTraceElement st = null;
2640
String tag = null;
27-
if (sts != null && sts.length > 3) {
28-
st = sts[3];
41+
if (sts != null && sts.length > stackLevel) {
42+
st = sts[stackLevel];
2943
if (st != null) {
3044
String fileName = st.getFileName();
3145
tag = (fileName == null) ? "Unkown" : fileName.replace(".java", "");
@@ -37,7 +51,13 @@ public static void d(Object... msg) {
3751
tag = (tag==null)?"Plugin":("Plugin_" + tag);
3852
// use logcat log
3953
while (str.length() > 0) {
40-
Log.v(tag, str.substring(0, Math.min(2000, str.length())).toString());
54+
if (level == Log.DEBUG) {
55+
Log.d(tag, str.substring(0, Math.min(2000, str.length())).toString());
56+
} else if (level == Log.ERROR) {
57+
Log.e(tag, str.substring(0, Math.min(2000, str.length())).toString());
58+
} else {
59+
Log.v(tag, str.substring(0, Math.min(2000, str.length())).toString());
60+
}
4161
str.delete(0, 2000);
4262
}
4363
} catch (Exception exception) {

0 commit comments

Comments
 (0)