架构之占位式插件化框架-APK解析原理系统源码分析

实现在插件中静态广播的加载,而静态广播是在manifest文件中注册的。那么宿主如何获取插件中manifest中配置的静态接受者?所以需要了解apk解析的原理。

问题:

  1. 静态注册的广播,是什么时候注册的?
    手机开机的时候,系统会将所有的app再次重新安装一遍,系统会去解析AndroidManifest,解析静态广播后,就会自动注册。

  2. 分析系统如何安装。
    apk安装时候会同步三个目录,分别是:

    • data/app/包名,会把apk安装文件拷贝到该目录下。
    • 创建app 应用所属目录,也就是data/data/包名
    • data/dalvik-cache 虚拟机去加载执行指令
  3. 分析 目录 data/app/包名
    手机开机后,会将所有的app在安装一遍,安装过后会全盘扫描data/app/包名 目录,解析出各个包名下apk文件里面所有的组件,包括权限,也就是解析AndroidManifest文件。如发现有静态广播就回去注册该广播。

  4. 分析源码,系统如何解析apk文件里的组件信息
    需要关注一个一个类PackageManagerService,android系统中所有的apk文件,都是由该类来管理。

  5. 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: 我是静态广播接受者,收到了来自宿主发送到广播

源码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值