实现在插件中静态广播的加载,而静态广播是在
manifest
文件中注册的。那么宿主如何获取插件中manifest
中配置的静态接受者?所以需要了解apk解析的原理。
问题:
-
静态注册的广播,是什么时候注册的?
手机开机的时候,系统会将所有的app再次重新安装一遍,系统会去解析AndroidManifest
,解析静态广播后,就会自动注册。 -
分析系统如何安装。
apk安装时候会同步三个目录,分别是:data/app/包名
,会把apk安装文件拷贝到该目录下。- 创建
app 应用所属目录
,也就是data/data/包名
data/dalvik-cache
虚拟机去加载执行指令
-
分析 目录
data/app/包名
手机开机后,会将所有的app在安装一遍,安装过后会全盘扫描data/app/包名
目录,解析出各个包名下apk文件里面所有的组件,包括权限,也就是解析AndroidManifest
文件。如发现有静态广播就回去注册该广播。 -
分析源码,系统如何解析apk文件里的组件信息
需要关注一个一个类PackageManagerService
,android系统中所有的apk文件,都是由该类来管理。 -
PackageManagerService
服务启动的大致流程
Linux内核 --> init进程 --> zygote进程 孵化 SystemService–>PackageManagerService
init进程启动之后,启动了ServiceManager
,该服务用来管理系统中的service
SystemService该服务,启动android所有的服务。包括PackageManagerService
,后面简称pms
pms 如何处理data/app/包名
目录
查阅PackageManagerService
源码,具体流程分析:
PackageParser.Package
内部类,其中有四个属性activities receivers providers services
用来分别存储四大组件。
注意:泛型类型Activity Provider Service
并非真正的四大组件,而是 PackageParser
的内部类,如下:
public final static class Service extends Component<ServiceIntentInfo> implements Parcelable {}
public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable {}
public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {}
所以拿到Package
就可以拿到所有的静态广播信息,如下:
<!--注册静态广播-->
<receiver android:name=".receiver.PluginStaticReceiver">
<intent-filter>
<action android:name="pulgin.static_receiver" />
</intent-filter>
</receiver>
最终目的,是拿到Manifest
文件中的静态广播信息。
通过反射系统源码,来解析apk文件里的所有信息。
具体流程:
/**
* =============================================================================
* <p>
* 注册 插件中的 静态广播
* 具体做法:反射系统源码,来解析apk文件里的所有信息。
* <p>
* 反射获取对象:
* 1. Object.class.getConstruct().newInstance()
* 2. 调用类提供的方法,返回对象。
* <p>
* =============================================================================
*/
public void parseApkAction() {
// android.content.pm.PackageParser#parsePackage(java.io.File, int)
Class[] classes = new Class[]{File.class, int.class};
try {
// 返回 PackageParser类型
Class<?> packageParseClass = Class.forName("android.content.pm.PackageParser");
Method parsePackageMethod = packageParseClass.getMethod("parsePackage", classes);
// 返回Package对象
Object packageObj = parsePackageMethod.invoke(
packageParseClass.newInstance(),
getPluginPath(), PackageManager.GET_ACTIVITIES);
Log.e(TAG, "package_: " + packageObj.toString());
// todo 疑问,为什么无法反射 三个参数的 parsePackage(java.io.File, int, boolean)
// 继续分析 packageObj
// 静态内部类 通过 $ 符号拼接
// Class<?> packageClass = Class.forName("android.content.pm.PackageParser$Package");
// packageObj.getClass() 通过这种方式 拿到类 , 替代 Class.forName("android.content.pm.PackageParser$Package");
Field receiversField = packageObj.getClass().getField("receivers");
Log.e(TAG, "receiversField: " + receiversField);
// receivers 字段对应的 值 也就是 ArrayList<Activity>
Object receivers = receiversField.get(packageObj);
ArrayList receiversList = (ArrayList) receivers;
Log.e(TAG, "receiversList size:" + receiversList.size());
/**
* public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable
*
* 1. Activity 的属性 ActivityInfo 的父类 有一个属性 name ,注释:Public name of this item. From the "android:name" attribute.
* 可以得到 广播的 全限定名 包名+类名
* ActivityInfo generateActivityInfo(Activity a, int flags,PackageUserState state, int userId) 该方法返回 ActivityInfo
* userId 可以在 android.os.UserHandle#getCallingUserId 获得
* 2. Activity的父类 Component 泛型为IntentFilter,属性 intents 为ArrayList<II>,也就是 ArrayList<IntentFilter>
* 获取 Component 对应的子类,就可以得到 intents,进而得到 IntentFilter
*
*/
// 此处的 receiversPackage 为 android.content.pm.PackageParser.Activity 类对象 ,并非四大组件的Activity
for (Object receiversPackage : receiversList) {
// 1. 拿到 IntentFilter
ArrayList<IntentFilter> intents = (ArrayList<IntentFilter>) receiversPackage.
getClass().getField("intents").get(receiversPackage); // intents 为 <intent-filter>
// 2. 拿到静态广播 的 全限定名 包名+类名 android:name=".receiver.PluginStaticReceiver"
Class packageUserState = Class.forName("android.content.pm.PackageUserState");
Method generateActivityInfoMethod = packageParseClass.getMethod("generateActivityInfo",
receiversPackage.getClass(), int.class, packageUserState, int.class);
// userId
Class userHandlerClass = Class.forName("android.os.UserHandle");
int userId = (int) userHandlerClass.getMethod("getCallingUserId").invoke(null);
// 静态方法调用, 第一个参数 可以传null
ActivityInfo activityInfo = (ActivityInfo) generateActivityInfoMethod.invoke(null,
receiversPackage, 0, packageUserState.newInstance(), userId);
String receiverClassName = activityInfo.name; // com.purang.plugin_package.receiver.PluginStaticReceiver
Log.e(TAG, "receiverClassName: " + receiverClassName);
// 通过类加载 来加载该类
Class<?> pluginStaticReceiverClass = getClassLoader().loadClass(receiverClassName);
// 实例化该来
BroadcastReceiver broadcastReceiver = (BroadcastReceiver) pluginStaticReceiverClass.newInstance();
for (IntentFilter intentFilter : intents) {
mContext.registerReceiver(broadcastReceiver, intentFilter);
Log.e(TAG, String.format("静态广播%s 注册成功", receiverClassName));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
测试:注册成功之后,在宿主发送广播:
Intent intent = new Intent();
intent.setAction("pulgin.static_receiver");
sendBroadcast(intent);
输出结果:
2020-02-26 21:41:43.864 19679-19679/com.purang.plugin E/PluginManager: 静态广播com.purang.plugin_package.receiver.PluginStaticReceiver 注册成功
2020-02-26 21:41:46.273 19679-19679/com.purang.plugin E/PluginStaticReceiver: 我是静态广播接受者,收到了来自宿主发送到广播