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的构造函数开始
android安全问题(六) 抢先接收广播 - 内因篇之广播接收器注册流程_第1张图片

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

这里只看几处

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 
  

注意

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 {
    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如何在初始化的时候如何解析manifest并把其中的element存放到内存中的

其中receiver保存到了owner的成员变量receivers中,owner的类型是android.content.pm.PackageParser.Package

也就是说,在上面的#2步中,scanPackageLI返回结果就是已经包含了manifest信息的Package对象

 

4.现在还没有结束,返回的结果最终交给了谁,我们还没有看到,在下面的这个函数中,我们终于发现了端倪

Package com.android.server.pm.PackageManagerService.scanPackageLI(Package pkg, int parseFlags, int scanMode, long currentTime)

N = pkg.receivers.size();
r = null;
for (i=0; i 
  

原来,最终是添加到了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 i,
        HashMap> 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 array = dest.get(name);
        if (array == null) {
            //Slog.v(TAG, "Creating new array for " + name);
            array = new ArrayList();
            dest.put(name, array);
        }
        array.add(filter);
    }
    return num;
}

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

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

 

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

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

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

 

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

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

我们下篇文章再来分析

 

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

我们也是画个简单的流程图,只看关键代码
android安全问题(六) 抢先接收广播 - 内因篇之广播接收器注册流程_第2张图片

最终会调用到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); 

mReceiverResolver的类型为IntentResolver

 

mReceiverResolver.addFilter(bf);

在上面已经简述过了

 

 

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

/**
 * Resolver for broadcast intents to registered receivers.
 * Holds BroadcastFilter (subclass of IntentFilter).
 */
final IntentResolver mReceiverResolver = new IntentResolver() {
    @Override
    protected boolean allowFilterResult(BroadcastFilter filter, List 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 i, HashMap> dest, String prefix)

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

 

 

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

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

 

 

 

转贴请保留以下链接

本人blog地址

http://su1216.iteye.com/

http://blog.csdn.net/su1216/

你可能感兴趣的:(动态广播,静态广播,注册顺序)