1.开始安装APK使用之前需要判断一下插件服务是否连接(待研究)
if (!PluginManager.getInstance().isConnected()) {
//return "连接失败"; // 连接失败
Toast.makeText(MainActivity.this, "连接失败", Toast.LENGTH_SHORT).show();
}
2.插件安装
真正的实现在IPluginManagerImpl
中,(具体的从PliginManager调用链过程之后分析)。
@Override
public int installPackage(String filepath, int flags) throws RemoteException {
//install plugin
String apkfile = null;
try {
//拿到pcakageInfo信息
PackageManager pm = mContext.getPackageManager();
PackageInfo info = pm.getPackageArchiveInfo(filepath, 0);
if (info == null) {
return PackageManagerCompat.INSTALL_FAILED_INVALID_APK;
}
apkfile = PluginDirHelper.getPluginApkFile(mContext, info.packageName);
//打印下:apkfile: /data/data/com.example.TestPlugin/Plugin/com.iflytek.flownotification/apk/base-1.apk
//这里暂时理解为安装后的路径
if ((flags & PackageManagerCompat.INSTALL_REPLACE_EXISTING) != 0) {
//新安装的插件
// 停止,???
forceStopPackage(info.packageName);
//删除插件的缓存 ??
if (mPluginCache.containsKey(info.packageName)) {
deleteApplicationCacheFiles(info.packageName, null);
}
//删除文件???
new File(apkfile).delete();
//将安装包拷贝到apkfile
Utils.copyFile(filepath, apkfile);
//初始化解析器并完成Mainfest的解析,返回解析器,保存了解析内容
PluginPackageParser parser = new PluginPackageParser(mContext, new File(apkfile));
//获取应用签名
parser.collectCertificates(0);
//获取权限和签名
PackageInfo pkgInfo = parser.getPackageInfo(PackageManager.GET_PERMISSIONS | PackageManager.GET_SIGNATURES);
//校验权限是否在宿主中有声明过
if (pkgInfo != null && pkgInfo.requestedPermissions != null && pkgInfo.requestedPer
//保存签名信息
saveSignatures(pkgInfo);
// if (pkgInfo.reqFeatures != null && pkgInfo.reqFeatures.length > 0) {
// for (FeatureInfo reqFeature : pkgInfo.reqFeatures) {
// Log.e(TAG, "reqFeature name=%s,flags=%s,glesVersion=%s", reqFeature.name, reqFeature.flags, reqFeature.getGlEsVersion());
// }
// }
// 拷贝插件中的native库文件。
copyNativeLibs(mContext, apkfile, parser.getApplicationInfo(0));
//opt,暂时没用到,忽略
dexOpt(mContext, apkfile, parser);
//缓存下
mPluginCache.put(parser.getPackageName(), parser);
//回调函数???,通知插件安装
mActivityManagerService.onPkgInstalled(mPluginCache, parser, parser.getPackageName());
sendInstalledBroadcast(info.packageName);
return PackageManagerCompat.INSTALL_SUCCEEDED;
} else {
//已经安装过了,做升级处理
if (mPluginCache.containsKey(info.packageName)) {
return PackageManagerCompat.INSTALL_FAILED_ALREADY_EXISTS;
} else {
forceStopPackage(info.packageName);
new File(apkfile).delete();
Utils.copyFile(filepath, apkfile);
PluginPackageParser parser = new PluginPackageParser(mContext, new File(apkfile));
parser.collectCertificates(0);
PackageInfo pkgInfo = parser.getPackageInfo(PackageManager.GET_PERMISSIONS | PackageManager.GET_SIGNATURES);
if (pkgInfo != null && pkgInfo.requestedPermissions != null && pkgInfo.requestedPermissions.length > 0) {
for (String requestedPermission : pkgInfo.requestedPermissions) {
boolean b = false;
try {
b = pm.getPermissionInfo(requestedPermission, 0) != null;
} catch (NameNotFoundException e) {
}
if (!mHostRequestedPermission.contains(requestedPermission) && b) {
Log.e(TAG, "No Permission %s", requestedPermission);
new File(apkfile).delete();
return PluginManager.INSTALL_FAILED_NO_REQUESTEDPERMISSION;
}
}
}
saveSignatures(pkgInfo);
// if (pkgInfo.reqFeatures != null && pkgInfo.reqFeatures.length > 0) {
// for (FeatureInfo reqFeature : pkgInfo.reqFeatures) {
// Log.e(TAG, "reqFeature name=%s,flags=%s,glesVersion=%s", reqFeature.name, reqFeature.flags, reqFeature.getGlEsVersion());
// }
// }
copyNativeLibs(mContext, apkfile, parser.getApplicationInfo(0));
dexOpt(mContext, apkfile, parser);
mPluginCache.put(parser.getPackageName(), parser);
mActivityManagerService.onPkgInstalled(mPluginCache, parser, parser.getPackageName());
sendInstalledBroadcast(info.packageName);
return PackageManagerCompat.INSTALL_SUCCEEDED;
}
}
} catch (Exception e) {
if (apkfile != null) {
new File(apkfile).delete();
}
handleException(e);
return PackageManagerCompat.INSTALL_FAILED_INTERNAL_ERROR;
}
}
其中
PluginPackageParser构造函数部分代码如下:
public PluginPackageParser(Context hostContext, File pluginFile) throws Exception {
mHostContext = hostContext; //保存宿主进程Context
mPluginFile = pluginFile;//插件Apk文件路径。
mParser = PackageParser.newPluginParser(hostContext);//PackageParser(插件自定义)类实例,他是一个兼容系统各个版本的PackageParser,解析Mainfest
mParser.parsePackage(pluginFile, 0);
mPackageName = mParser.getPackageName();//解析后获得插件Apk的包名。
mHostPackageInfo = mHostContext.getPackageManager().getPackageInfo(mHostContext.getPackageName(), 0);// 宿主进程的PackageInfo实例。
//mActivityIntentFilterCache,mServiceIntentFilterCache,mProviderIntentFilterCache,mReceiverIntentFilterCache: 这几个变量主要保存四大组件ComponentName对应的IntentFilter。
//获取保存Activity
List datas = mParser.getActivities();
for (Object data : datas) {
ComponentName componentName = new ComponentName(mPackageName, mParser.readNameFromComponent(data));
synchronized (mActivityObjCache) {
mActivityObjCache.put(componentName, data);
}
synchronized (mActivityInfoCache) {
ActivityInfo value = mParser.generateActivityInfo(data, 0);
fixApplicationInfo(value.applicationInfo);
if (TextUtils.isEmpty(value.processName)) {
value.processName = value.packageName;
}
mActivityInfoCache.put(componentName, value);
}
List<IntentFilter> filters = mParser.readIntentFilterFromComponent(data);
synchronized (mActivityIntentFilterCache) {
mActivityIntentFilterCache.remove(componentName);
mActivityIntentFilterCache.put(componentName, new ArrayList<IntentFilter>(filters));
}
}
//获取保存Service
//获取保存ContentProvide
//获取保存 Receiver
//获取保存Instrumentation
//获取保存Permissions
//获取保存PermissionGroups
//获取保存PermissionGroups
}
总结:插件的安装过程其实就是,
1 把插件Apk文件保存在宿主进程:/data/data/宿主进程报名/plugin/plugin包名/apk/base-1.apk下面。
2 通过PluginPackageParser解析插件Apk AndroidManifest文件,保存插件Apk 四大组件以及权限等信息,来方便查询。
3 PluginClassLoader保存优化后的Dex文件,加载插件Apk的类。
3.卸载
@Override
public int deletePackage(String packageName, int flags) throws RemoteException {
try {
if (mPluginCache.containsKey(packageName)) {
forceStopPackage(packageName);
PluginPackageParser parser;
synchronized (mPluginCache) {
parser = mPluginCache.remove(packageName);
}
Utils.deleteDir(PluginDirHelper.makePluginBaseDir(mContext, packageName));
mActivityManagerService.onPkgDeleted(mPluginCache, parser, packageName);
mSignatureCache.remove(packageName);
sendUninstalledBroadcast(packageName);
return PackageManagerCompat.DELETE_SUCCEEDED;
}
} catch (Exception e) {
handleException(e);
}
return PackageManagerCompat.DELETE_FAILED_INTERNAL_ERROR;
}
这个函数主要工作如下:
从mPluginCache中通过要卸载的插件Apk包名查看是否已经安装并缓存相关信息。如果在mPluginCache存在对应包的PluginPackageParser类实例,就对一些缓存进行处理:
- 停止包运行的所在进程,
- 把包对应的PluginPackageParser从缓存中删除
- 删除宿主进程安装包对应的目录(/data/data/宿主进程报名/plugin/plugin包名)中的文件
- 移除插件包对应的签名
- 发送卸载成功广播