zoukankan      html  css  js  c++  java
  • Android安全问题 抢先接收广播

    导读:本文说明系统是如何注册动态广播以及静态广播,这里主要注意其注册的顺序

     

    这篇文章主要是针对我前两篇文章

    android安全问题  抢先开机启动 - 结果篇

    android安全问题  抢先拦截短信 - 结果篇

    之前只给出了结果,并没有给出代码分析,现在给出第一步分的分析

     

    大家都知道,广播接收器分为动态注册和静态注册两种

    静态接收,就是配置到manifest.xml文件中,PackageManagerService扫描后记录其信息……

    动态接收,就是从代码中注册,通过调用下面的方法实现

    Intent android.content.Context.registerReceiver(BroadcastReceiver receiver, IntentFilter filter)

     

     (下面的流程图估计画的比较水,将就看一下吧,得补习一下UML了)

    首先分析静态注册Receiver的流程

    静态receiver的注册是由PackageManagerService开机的时候负责初始化

    (PackageManagerService之后简称为PMS)

    PMS在开机的时候会对系统一些目录逐个扫描,解析apk文件。静态广播接收器就是在PMS做这件事情的时候顺便处理的。

    PMS会解析apk的manifest文件,查找这里注册的receiver,然后加载到内存中

    下面看一下PMS是如何工作的

    这部分内容没有什么难度,只要有耐心就行,我画了一个很简单流程图,从调用PMS的构造函数开始

    注意,这里有几个同名函数,大家需要分清。并不是同一个函数调用了两次

    这里只看几处

    1.PMS初始化的时候干了些什么

    当然,PMS会做很多很多事情,这里我们只看我们关注的,和这篇文章相关的部分

    // Collect all system packages.
    mSystemAppDir = new File(Environment.getRootDirectory(), "app");
    mSystemInstallObserver = new AppDirObserver(
        mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
    mSystemInstallObserver.startWatching();
    scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

    扫描目录的顺序

    system/framework

    system/app

    vendor/app

    data/app

    drm/app-private

    这里以system/app目录为例

     

    2.下一个要关注的地方是

    void com.android.server.pm.PackageManagerService.scanDirLI(File dir, int flags, int scanMode, long currentTime)

    private void scanDirLI(File dir, int flags, int scanMode, long currentTime {
        String[] files = dir.list();
        ……
        int i;
        for (i=0; i<files.length; i++) {
            File file = new File(dir, files[i]);
        ……
            PackageParser.Package pkg = scanPackageLI(file, flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);
        ……
        }
    }

    注意

    String[] files = dir.list();

    以及之后的for循环

     

    3.之后的部分比较无聊,我们直接跳到parseApplication函数部分

    else if (tagName.equals("receiver")) {
        Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false);
        if (a == null) {
            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
            return false;
        }
    
        owner.receivers.add(a);
    }

    这部分就是解析manifest中的receiver部分,大家会很奇怪,receiver为什么会变成一个Activity

    此Activity非彼Activity,这个Activity是PackageParser的一个内部类,结构也非常简单

     

    public final static class Activity extends Component<ActivityIntentInfo> {
        public final ActivityInfo info;
    
        public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
            super(args, _info);
            info = _info;
            info.applicationInfo = args.owner.applicationInfo;
        }
        
        public void setPackageName(String packageName) {
            super.setPackageName(packageName);
            info.packageName = packageName;
        }
        ……
    }

     

    原来,最终是添加到了PMS中的成员变量mReceivers中

    // All available receivers, for your resolving pleasure.
    final ActivityIntentResolver mReceivers = new ActivityIntentResolver();、

    下面我们看看它是如何add的

    void com.android.server.pm.PackageManagerService.ActivityIntentResolver.addActivity(Activity a, String type)

    void com.android.server.IntentResolver.addFilter(ActivityIntentInfo f)

        public void addFilter(F f) {
            ......
            mFilters.add(f);
            int numS = register_intent_filter(f, f.schemesIterator(),
                    mSchemeToFilter, "      Scheme: ");
            int numT = register_mime_types(f, "      Type: ");
            //根据我下面红色文字的假设,这里numS和numT应该都为0
            if (numS == 0 && numT == 0) {
                register_intent_filter(f, f.actionsIterator(),
                        mActionToFilter, "      Action: ");
            }
            if (numT != 0) {
                register_intent_filter(f, f.actionsIterator(),
                        mTypedActionToFilter, "      TypedAction: ");
            }
        }

    由于开机启动和接收短信并不涉及MIME Type、Scheme等因素。所有我们只考虑Intent中的Action,MIME Type、Scheme等均不考虑

    最后看一下register_intent_filter函数,里面没有任何关于排序的代码,只是按顺序add到list中

    private final int register_intent_filter(F filter, Iterator<String> i,
            HashMap<String, ArrayList<F>> dest, String prefix) {
        if (i == null) {
            return 0;
        }
    
        int num = 0;
        while (i.hasNext()) {
            String name = i.next();
            num++;
            if (localLOGV) Slog.v(TAG, prefix + name);
            ArrayList<F> array = dest.get(name);
            if (array == null) {
                //Slog.v(TAG, "Creating new array for " + name);
                array = new ArrayList<F>();
                dest.put(name, array);
            }
            array.add(filter);
        }
        return num;
    }

    Action保存在mActionToFilter中记录,之后发送广播的时候,查找接收器还要靠mActionToFilter这个成员变量

    每个action对应一个List,含有此action的filter将被保存到同一个List中

     

    我们要注意一个事情,那就是mReceivers保存这些receiver的顺序

    那就是一直与#2步的顺序保持一致,没有遭到破坏

    甚至并没有根据优先级排序,只是一味的add

     

    ---------------------------------------------------------------

    静态广播接收器的注册分析完了,之后就是系统发出广播,然后如何去分发给他们了

    我们下篇文章再来分析

     

    下面看看动态接收器的注册流程

    我们也是画个简单的流程图,只看关键代码

    最终会调用到AMS中的registerReceiver函数

    其中关键部分如下

    ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
    if (rl == null) {
        rl = new ReceiverList(this, callerApp,
                Binder.getCallingPid(),
                Binder.getCallingUid(), receiver);
        if (rl.app != null) {
            rl.app.receivers.add(rl);
        } else {
            try {
                receiver.asBinder().linkToDeath(rl, 0);
            } catch (RemoteException e) {
                return sticky;
            }
            rl.linkedToDeath = true;
        }
        mRegisteredReceivers.put(receiver.asBinder(), rl);
    }
    BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission);
    rl.add(bf);
    if (!bf.debugCheck()) {
        Slog.w(TAG, "==> For Dynamic broadast");
    }
    mReceiverResolver.addFilter(bf);&nbsp;

    mReceiverResolver的类型为IntentResolver<BroadcastFilter, BroadcastFilter>

    mReceiverResolver.addFilter(bf);

    在上面已经简述过了

    最终所有动态注册的receiver都保存到AMS的成员变量mReceiverResolver中

     

    /**
     * Resolver for broadcast intents to registered receivers.
     * Holds BroadcastFilter (subclass of IntentFilter).
     */
    final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
        @Override
        protected boolean allowFilterResult(BroadcastFilter filter, List<BroadcastFilter> dest) {
            IBinder target = filter.receiverList.receiver.asBinder();
            for (int i=dest.size()-1; i>=0; i--) {
                if (dest.get(i).receiverList.receiver.asBinder() == target) {
                    return false;
                }
            }
            return true;
        }
    
        @Override
        protected String packageForFilter(BroadcastFilter filter) {
            return filter.packageName;
        }
    };

     

     

    总结:

    静态广播和动态广播如何注册的,我们已经全部分析完了

    静态广播是PackageManagerService负责,保存到其成员变量mReceivers

    动态广播是ActivityManagerService负责,保存到其成员变量mReceiverResolver

     

    注册的顺序:

    动态广播与应用中调用的顺序一致

    静态广播参考函数

    void com.android.server.pm.PackageManagerService.scanDirLI(File dir, int flags, int scanMode, long currentTime)

     

    注意

     

    String[] files = dir.list();

     

    以及之后的for循环


    由于开机启动和接收短信并不涉及MIME Type、Scheme等因素。所有我们这里只考虑Intent中的Action,MIME Type、Scheme等均不考虑

    保存的顺序参考函数

    void com.android.server.IntentResolver.addFilter(ActivityIntentInfo f)

    int com.android.server.IntentResolver.register_intent_filter(F filter, Iterator<String> i, HashMap<String, ArrayList<F>> dest, String prefix)

    注意:其中没有任何关于排序的代码

     

     

    下篇文章将讲述发送广播之后,系统如何查找对应的receiver。在这个过程中,系统才开始考虑优先级。

    下篇文章顺便看看隐式Intent是如何查找到目标组件的

     

     

     

  • 相关阅读:
    ubuntu12.04 安装CAJViewer-ubuntu(待解决)
    ROS中遇到的一些问题和解决(更新)
    Virtualbox主机和虚拟机之间文件夹共享及双向拷贝
    Ubuntu自带截图工具screenshoot
    Ubuntu vim终端常用的快捷键
    Ubuntu终端多窗口分屏Terminator
    Apollo快速安装视频教程
    ML--XOR问题
    DL之Example1--MNIST
    Python之ML--人工神经网络识别图像
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/4262952.html
Copyright © 2011-2022 走看看