Android broadcast 相同优先级的顺序

From Andriod广播注册接收过程简析

为了利于各个进程应用之间的通信,android提供了一个很方便的处理方式:广播机制。广播机制顾名思义,就是广播发送者无需判断具体某个接收者的存在,把广播发送出去,任务即完成。这样保证了有效通信的同时又最大限度的降低了android系统各个模块的耦合性。

Android广播有两个很重要的要素:

   1 广播 - 用于发送广播

         有序广播  -  被广播接收器接收后,可被终止,无法往下继续传达。         典型代表:短信广播

         普通广播  -  发送至每一个已经注册(订阅)的广播接收器,无法被终止。 典型代表:开机启动广播

   2 广播接收器 - 用于订阅广播后接收广播

         静态注册广播 - 在AndroidManifest.xml中设置,程序不用启动亦可接收。 典型代表:很多开机启动的APP,都是接收开机启动广播带起服务的。

         动态注册广播 - 代码中注册广播,程序未启动时,无法接收广播。             典型代表:Go短信,将Go短信强行停止,Go短信无法接收短信。

 

广播注册过程和接收广播顺序过程

       

                                             图1 注册广播流程简图

    静态广播接收器 由PackageManagerService负责,当手机启动时(或者新安装了应用),PackageManagerService负责扫描手机中所有已安装的APP应用(题外话,确定不再使用的APP需要卸载了),将AndroidManifest.xml中 有关注册广播的信息 解析出来,存储至一个全局静态变量当中mReceivers

  需要注意的是:

 1 PackageManagerService扫描目录的顺序如下:

  system/framework

  system/app

  vendor/app

  data/app

  drm/app-private

  2 当处于同一目录下时:按照file.list()的返回顺序。(题外话:因为在data/app下的应用都是用户安装的,并且都是以com.xxx.xxx-1.apk 的形式出现,所以如果打算做手机管家之类的应用,需要好好的研究下包名,争取在file.list()的独木桥下抢的头筹---优先接收开机启动完成的广播。)

   3 在此处并未对 接收顺序做完整的排序。(注意修饰词完整的,毕竟先扫描的当然会有一定优先级)

 

    动态广播接收器 由ActivityManagerService负责,当APP的服务或者进程起来之后,执行了注册广播接收的代码逻辑,即进行加载,最后会存储在一个全局静态变量

mReceiverResolver中。

    需要注意的是:

    1 这个并非是一成不变的,当程序被杀死之后,  已注册的动态广播接收器也会被移出mReceiverResolver,直到下次程序启动,再进行动态广播的注册,当然这里面的顺序也已经变更了一次。

    2  这里也并没完整的进行广播的排序,只记录的注册的先后顺序,并未有结合优先级的处理。

 

当有广播发出时,接收顺序如下:

 

                                                  图2 广播接收流程简图
 
   在ActivityManagerService处理广播,当广播为有序广播时,将动态广播接收器和动态广播接收器合并起来,形成最终的有序广播接收顺序。
   上述的 规则1排序为:
                                1 优先级高的先接收
                                2 同优先级的动静态广播接收器,动态优先于静态
                                3 同优先级的动态广播接收器  或者同优先级的静态广播接收器,按照图1 的流程注册顺序。
                                   即静态:先扫描的大于后扫描的,动态:先注册的大于后注册的。
  
   当广播为普通广播时, 规则2排序为:
                                1 无视优先级,动态广播接收器优先于静态广播接收器
                                2 同 规则1排序的第3点

 

接下来请看代码以片段:

private final int broadcastIntentLocked(ProcessRecord callerApp,   
        String callerPackage, Intent intent, String resolvedType,   
        IIntentReceiver resultTo, int resultCode, String resultData,   
        Bundle map, String requiredPermission,   
        boolean ordered, boolean sticky, int callingPid, int callingUid) {   

    …………
    …………
    
    // 静态广播接收器list
    List receivers = null; 
    
    // 动态广播接收器List
    List<BroadcastFilter> registeredReceivers = null;   

    // 获取静态广播接收器mReceivers
    try {   
        if (intent.getComponent() != null) {   
            // Broadcast is going to one specific receiver class...   
            ActivityInfo ai = AppGlobals.getPackageManager().   
                getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);   
            if (ai != null) {   
                receivers = new ArrayList();   
                ResolveInfo ri = new ResolveInfo();   
                ri.activityInfo = ai;
                receivers.add(ri);   
            }   
        } else {   
            // Need to resolve the intent to interested receivers...   
            if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)   
                     == 0) {   
                receivers =   
                    AppGlobals.getPackageManager().queryIntentReceivers(   
                            intent, resolvedType, STOCK_PM_FLAGS);   
            } 
            // 获取动态广播接收器mReceiverResolver
            registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);   
        }   
    } catch (RemoteException ex) {   
        // pm is in same process, this will never happen.   
    }   
  
    final boolean replacePending =   
            (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;   
      
    int NR = registeredReceivers != null ? registeredReceivers.size() : 0;  
    ……
    // 如果接收到的广播 是普通广播。
    if (!ordered && NR > 0) {   
        // If we are not serializing this broadcast, then send the   
        // registered receivers separately so they don't wait for the   
        // components to be launched.   
        BroadcastRecord r = new BroadcastRecord(intent, callerApp,   
                callerPackage, callingPid, callingUid, requiredPermission,   
                registeredReceivers, resultTo, resultCode, resultData, map,   
                ordered, sticky, false);   

    // 很明显接收到普通广播之后,在这只处理了动态广播 registeredReceivers,对于普通广播而言,动态广播接收器要优先于静态广播接收器 无关设置的优先级
        boolean replaced = false;   
        if (replacePending) {   
            for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {   
                if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {   
                    if (DEBUG_BROADCAST) Slog.v(TAG,   
                            "***** DROPPING PARALLEL: " + intent);   
                    mParallelBroadcasts.set(i, r);   
                    replaced = true;   
                    break;   
                }   
            }   
        }   
        if (!replaced) {   
            mParallelBroadcasts.add(r);   
            scheduleBroadcastsLocked();   
        }   
        //将registeredReceivers置为null,后面只处理静态广播接收器,所以不会有冲突。
        registeredReceivers = null;   
        NR = 0;   
    }   
    
    //如果是有序广播,将静态广播接收器和动态广播接收器组合成一个最终的顺序
    int ir = 0;   
    if (receivers != null) {   
        ...   
        //合并的过程,注意顺序   
        int NT = receivers != null ? receivers.size() : 0;   
        int it = 0;   
        ResolveInfo curt = null;   
        BroadcastFilter curr = null;   
        while (it < NT && ir < NR) {   
            if (curt == null) {   
                curt = (ResolveInfo)receivers.get(it);   
            }   
            if (curr == null) {   
                curr = registeredReceivers.get(ir);   
            }   
            //如果动态广播接收器优先级高于或者等于静态广播接收器,那么就插到前面      
            //很明显动态的要在静态的前面 
            if (curr.getPriority() >= curt.priority) {   
                // Insert this broadcast record into the final list.   
                receivers.add(it, curr);   
                ir++;   
                curr = null;   
                it++;   
                NT++;   
            } else {   
                // Skip to the next ResolveInfo in the final list.   
                it++;   
                curt = null;   
            }   
        }   
    }


最后举个例子:

(以下的静A 表示静态广播接收器,同理动B。)

1 静A (优先级1)

2 动B(优先级1)

3 静C (优先级2,后扫描)

4 静D (优先级2,先扫描)

5 动E   (优先级2,先注册)

6 动F  (优先级2,后注册)

当来了一个 有序广播,接收顺序如下:动E >  动F  > 静D > 静C > 动B > 静A

当来了一个 普通广播,接收顺序如下:动E >  动F  > 动B > 静D > 静C > 静A

 

参考文章:http://su1216.iteye.com/blog/1776121

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
@SuppressLint("NewApi") public class MainActivity extends Activity { SmsReceiver myReceiver; Button btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn = (Button) findViewById(R.id.btn); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { test(); } }); } public void test(){ Cursor cursor = null; String defaultSmsApp = Telephony.Sms.getDefaultSmsPackage(this); Intent intent = new Intent(Sms.Intents.ACTION_CHANGE_DEFAULT); intent.putExtra(Sms.Intents.EXTRA_PACKAGE_NAME, this.getPackageName()); startActivity(intent); try { cursor = getContentResolver().query(Uri.parse("content://sms/inbox"), new String[] { "_id", "address", "read" }, "read = ? ", new String[] {"0" }, "date desc"); if (cursor != null) { ContentValues values = new ContentValues(); values.put("read", "1"); for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { Log.v("cky", "" + cursor.getInt(cursor.getColumnIndex("_id")) + " , " + cursor.getString(cursor.getColumnIndex("address"))); int res = getContentResolver().update(Uri.parse("content://sms/inbox"), values, "_id=?", new String[] { "" + cursor.getInt(cursor.getColumnIndex("_id")) }); Log.i("cky","geng xin = "+res); } } intent = new Intent(Sms.Intents.ACTION_CHANGE_DEFAULT); intent.putExtra(Sms.Intents.EXTRA_PACKAGE_NAME, defaultSmsApp); startActivity(intent); } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { cursor.close(); cursor = null; } } } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值