android framework开发之广播broadcast源码分析-千里马

Posted Android高级知识分享官

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android framework开发之广播broadcast源码分析-千里马相关的知识,希望对你有一定的参考价值。

hi,粉丝朋友大家好!
今天是2-8号,也是我春节第一天正式开工的日子,在这里首先祝大家新的一年技术进步,与千里马共同学习共同进步,共同升职加薪。今天要给大家分享的一个课题是大家都很熟悉的广播。
这里将要分为2个部分来对广播进行分析:

入门课,实战课,跨进程专题
ps需要学习深入framework课程和课程优惠
(可以加我qq:2102309716 优惠购买)
1、广播发送部分
一般我们正常使用发送广播都会有调用一个context的sendBroadcas,方法原型如下:

 public void sendBroadcast(Intent intent)

这里我们一般就是只想要传递一个intent参数既可以,这里调用context方法,其实和上一节讲解service一样,最后都会调用到ContextImpl方法中的sendBroadcast:

    @Override
    public void sendBroadcast(Intent intent) 
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try 
            intent.prepareToLeaveProcess(this);//只是对intent进行一下预处理
            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());//最后调用到了AMS里面的broadcastIntent
         catch (RemoteException e) 
            throw e.rethrowFromSystemServer();
        
    

下面来看AMS的broadcastIntent方法,这里我们暂时只分析最常见的一类平行广播,不看有序部分,感兴趣可以自己分析:

final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, Intent intent, String resolvedType,
            IIntentReceiver resultTo, int resultCode, String resultData,
            Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
            int realCallingPid, int userId, boolean allowBackgroundActivityStarts) 
     //省略部分
 // Figure out who all will receive this broadcast.
        List receivers = null;
        List<BroadcastFilter> registeredReceivers = null;//获取接受者的List
        // Need to resolve the intent to interested receivers...
        if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                 == 0) 
            receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
        
        if (intent.getComponent() == null) 
        //具体根据intent进行filter获取接受者的List
            if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) 
                // Query one target user at a time, excluding shell-restricted users
                for (int i = 0; i < users.length; i++) 
                    if (mUserController.hasUserRestriction(
                            UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) 
                        continue;
                    
                    List<BroadcastFilter> registeredReceiversForUser =
                            mReceiverResolver.queryIntent(intent,
                                    resolvedType, false /*defaultOnly*/, users[i]);
                    if (registeredReceivers == null) 
                        registeredReceivers = registeredReceiversForUser;
                     else if (registeredReceiversForUser != null) 
                        registeredReceivers.addAll(registeredReceiversForUser);
                    
                
             else 
                registeredReceivers = mReceiverResolver.queryIntent(intent,
                        resolvedType, false /*defaultOnly*/, userId);
            
        
        
               if (!ordered && NR > 0) 
          
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                    resultCode, resultData, resultExtras, ordered, sticky, false, userId,
                    allowBackgroundActivityStarts, timeoutExempt);//构造出一个BroadcastRecord
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
            final boolean replaced = replacePending
                    && (queue.replaceParallelBroadcastLocked(r) != null);
            // Note: We assume resultTo is null for non-ordered broadcasts.
            if (!replaced) 
                queue.enqueueParallelBroadcastLocked(r);//插入平行广播队列
                queue.scheduleBroadcastsLocked();
            
            registeredReceivers = null;
            NR = 0;
        
//省略部分
        return ActivityManager.BROADCAST_SUCCESS;
    

接下来看看最重要的enqueueParallelBroadcastLocked和scheduleBroadcastsLocked部分:

     public void enqueueParallelBroadcastLocked(BroadcastRecord r) 
        mParallelBroadcasts.add(r);//这里动作很简单就是把BroadcastRecord插入到mParallelBroadcasts这个list
        enqueueBroadcastHelper(r);
    

接下来看scheduleBroadcastsLocked:

    public void scheduleBroadcastsLocked() 
        //省略部分
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    

这里其实就只是发送了一个BROADCAST_INTENT_MSG消息:
来看看对这个消息的处理

    private final class BroadcastHandler extends Handler 
        public BroadcastHandler(Looper looper) 
            super(looper, null, true);
        

        @Override
        public void handleMessage(Message msg) 
            switch (msg.what) 
                case BROADCAST_INTENT_MSG: 
                    if (DEBUG_BROADCAST) Slog.v(
                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
                            + mQueueName + "]");
                    processNextBroadcast(true);//调用了processNextBroadcast方法
                 break;
                case BROADCAST_TIMEOUT_MSG: 
                    synchronized (mService) 
                        broadcastTimeoutLocked(true);
                    
                 break;
            
        
    

这里我们来看processNextBroadcast:

   final void processNextBroadcast(boolean fromMsg) 
        synchronized (mService) 
            processNextBroadcastLocked(fromMsg, false);
        
    


重点看看processNextBroadcastLocked:

   final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) 
        BroadcastRecord r;
        while (mParallelBroadcasts.size() > 0) 
            r = mParallelBroadcasts.remove(0);//获取平行广播的BroadcastRecord对象

            final int N = r.receivers.size();
            for (int i=0; i<N; i++) 
                Object target = r.receivers.get(i);
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);//这里是核心调用了deliverToRegisteredReceiverLocked方法
            
            addBroadcastToHistoryLocked(r);
            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                    + mQueueName + "] " + r);
        
//省略部分

下面来看deliverToRegisteredReceiverLocked方法:

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) 
       //省略部分
        try 
            if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) 
                //省略部分
             else 
                r.receiverTime = SystemClock.uptimeMillis();
                maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
                        //最重要调用了performReceiveLocked
                //省略部分
            
           //省略部分
         catch (RemoteException e) 
            //省略部分
        
    


接下来重点看performReceiveLocked:

 void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser)
            throws RemoteException 
        //省略
        if (app != null) 
            if (app.thread != null) 
                
                try 
                //调用到了具体应用进程的scheduleRegisteredReceiver方法
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
             
                 catch (RemoteException ex) 
                   //省略
                
             else 
                throw new RemoteException("app.thread must not be null");
            
         else 
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
        
    

这里的scheduleRegisteredReceiver方法是在应用进程的ActivityThread类中实现的:

        // This function exists to make sure all receiver dispatching is
        // correctly ordered, since these are one-way calls and the binder driver
        // applies transaction ordering per object for such calls.
        public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
                int resultCode, String dataStr, Bundle extras, boolean ordered,
                boolean sticky, int sendingUser, int processState) throws RemoteException 
            updateProcessState(processState, false);
            receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                    sticky, sendingUser);
        

这里会调用到receiver的performReceive方法,其中IIntentReceiver实际实在LoadedApk.java中:

 final static class InnerReceiver extends IIntentReceiver.Stub 
            //省略

            @Override
            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) 
                final LoadedApk.ReceiverDispatcher rd;
               //省略
                if (rd != null) 
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                 else 
                 //省略
                
            
        

这里就调用了 LoadedApk.ReceiverDispatcher的performReceive方法,其中ReceiverDispatcher也在LoadedApk.java:

     public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) 
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
           //省略
            if (intent == null || !mActivityThread.post(args.getRunnable()))  
            //这句mActivityThread.post(args.getRunnable())是核心
                if (mRegistered && ordered) 
                    IActivityManager mgr = ActivityManager.getService();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                    args.sendFinished(mgr);
                
            
        

这里mActivityThread.post(args.getRunnable())是核心,就是往主线程post了一个runnable,我们来看getRunnable这个方法:

public final Runnable getRunnable() 
                return () -> 
                    //省略部分
                    try 
                        ClassLoader cl = mReceiver.getClass().getClassLoader();
                        intent.setExtrasClassLoader(cl);
                        intent.prepareToEnterProcess();
                        setExtrasClassLoader(cl);
                        receiver.setPendingResult(this);
                        receiver.onReceive(mContext, intent);//调用到具体应用广播接收器的onReceive
                     catch (Exception e) 
                     //省略部分
                ;
            
        

主要就 receiver.onReceive(mContext, intent)这里就调用到具体应用广播接收器的onReceive,也就是我们经常onReceive写处理业务地方
总结图如下:

2、广播注册接受部分
下一节讲解

以上是关于android framework开发之广播broadcast源码分析-千里马的主要内容,如果未能解决你的问题,请参考以下文章

android framework开发之广播broadcast源码分析2-千里马

android framework开发之广播broadcast源码分析-千里马

BroadcastReceiver机制-Android12

BroadcastReceiver机制-Android12

Android开发之广播

Android获取当前电量信息(BroadcastReceiver的使用)