IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 源码分析 (十) 启动广播的发送和接收过程 -> 正文阅读

[移动开发]Android 源码分析 (十) 启动广播的发送和接收过程

广播的发送和接收过程

广播的发送和接收分为 2 个阶段来分析,通过应用进程到 AMS SystemServer 进程的调用,然后 AMS 所在的进程通知应用进程的调用,下面我们先来分析应用程序进程到 AMS

ContextImpl 到 AMS 的调用过程

广播发送多种类型的广播,比如 无序、有序、粘性广播,这里以最简单的广播无序广播来讲解,也就是发送一个普通广播,它的实现也是在 ContextWrapper 中

直接来看 ContextWrapper 的 sendBroadcast 方法,代码如下:

//ContextWrapper.java
    @Override
    public void sendBroadcast(Intent intent) {
      	//调用 Context 的实现类 ContextImpl
        mBase.sendBroadcast(intent);
    }

这里的 mBase 是 Context , 在之前文章中将到了 ContextImpl 是 Context 的实现类,我们直接看它的实现,代码如下:

//ContextImpl.java
    @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

AMS 的代理类 IActivityManager 的?broadcastIntent?函数,我们发现跟咱么之前讲解的 Activity,Service 调用方式一样都会经过 AMS 的代理类 IActivityManager?

//AMS.java

    /**
     * 应用程序进程调用
     * @param caller
     * @param intent
     * @param resolvedType
     * @param resultTo
     * @param resultCode
     * @param resultData
     * @param resultExtras
     * @param requiredPermissions
     * @param appOp
     * @param bOptions
     * @param serialized
     * @param sticky
     * @param userId
     * @return
     */
    public final int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle resultExtras,
            String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean serialized, boolean sticky, int userId) {
        enforceNotIsolatedCaller("broadcastIntent");
        synchronized(this) {
            /**
             * 1. 验证广播是否合法
             */
            intent = verifyBroadcastLocked(intent);
            /**
             * 拿到所在的进程
             */
            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            /**
             * 2. 
             */
            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, appOp, bOptions, serialized, sticky,
                    callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }

我们先看注释 1 内部验证广播代码实现:

//AMS.java

    final Intent verifyBroadcastLocked(Intent intent) {
        // Refuse possible leaked file descriptors
        /**
         * 1. 验证 intent 是否不为null 并且有文件描述符
         */
        if (intent != null && intent.hasFileDescriptors() == true) {
          ...
          }

        /**
         * 2. 获得 intent 的 flags
         */
        int flags = intent.getFlags();

        if (!mProcessesReady) {
            /**
             * 3. 系统正在启动过程中。如果是动态广播者不做处理
             */
            if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
                
                /**
                 * 4. 如果 flag 没有设置为 FLAG_RECEIVER_REGISTERED_ONLY 只接受动态注册的广播接收者则会抛出异常
                 */
            } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
            ...    
            }
        }

				...

        return intent;
    }

根据上面的注释我们知道就是对 Intent 判断是否合法性,下面我们继续回到?broadcastIntent?注释 2 ,代码如下:

//AMS.java
    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 userId) {
      ...
        
            /**
             * 1. 创建 BroadcastRecord 对象将 receivers 传进去。
             */
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                    resultCode, resultData, resultExtras, ordered, sticky, false, userId);
      
                  final boolean replaced = replacePending
                    && (queue.replaceParallelBroadcastLocked(r) != null);
           
            if (!replaced) {
                queue.enqueueParallelBroadcastLocked(r);
                /**
                 * 2.
                 */
                //处理广播分发
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0;
        }
        
      ...
      
    }     

注释 1 上面省略了很多代码,省略的代码如要是把注册 动态/静态的广播接收者按照优先级高低不同储存在不同的列表中,在将这 2 个列表合并到 receivers 列表中,这样 receivers 列表包含了所有的广播接收者。在注释 1 处创建 BroadcastReceiver 对象并将 receivers 传递进去,在注释 2 处调用 BroadcastQuque 的?scheduleBroadcastsLocked?方法。

AMS 到 BroadcastReceiver 的调用过程

AMS 到 BroadcastReceiver 的调用过程请直接看 BroadcastQueue 的?scheduleBroadcastsLocked?函数实现,代码如下:

//BroadcastQueue.java

    public void scheduleBroadcastsLocked() {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                + mQueueName + "]: current="
                + mBroadcastsScheduled);

        if (mBroadcastsScheduled) {
            return;
        }
        //通过 Handler 分发
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }

上面的代码向 BroadcastHandler 类型的 mHandler 对象发送了 BROADCAST_INTENT_MSG 类型的消息,这个消息在 BroadcastHandler 的 handleMessage 方法中进行处理,如下所示:

    //BroadcastQueue.java
 		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");
                    //处理下一个广播
                    processNextBroadcast(true);
                } break;
                case BROADCAST_TIMEOUT_MSG: {
                    synchronized (mService) {
                        broadcastTimeoutLocked(true);
                    }
                } break;
            }
        }
    }

面的代码向 BroadcastHandler 类型的 mHandler 对象发送了 BROADCAST_INTENT_MSG 类型的消息,这个消息在 BroadcastHandler 的 handleMessage 方法中进行处理,如下所示

    //BroadcastQueue.java
 		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");
                    //处理下一个广播
                    processNextBroadcast(true);
                } break;
                case BROADCAST_TIMEOUT_MSG: {
                    synchronized (mService) {
                        broadcastTimeoutLocked(true);
                    }
                } break;
            }
        }
    }

在 handleMessage 方法中调用了 processnextBroadcast 方法,方法对无序广播和有序广播分别进行处理,在将广播发送给广播接收者,处理代码如下:

//BroadcastQueue.java

    final void processNextBroadcast(boolean fromMsg) {
        synchronized(mService) {
            BroadcastRecord r;

  				...
            mService.updateCpuStats();

            if (fromMsg) {
                /**
                 * 1.  已经处理了  BROADCAST_INTENT_MSG 这条消息
                 */
            
                mBroadcastsScheduled = false;
            }

            /**
             * 2. 遍历存储无序广播的 mParallelBroadcasts 列表
             */
            while (mParallelBroadcasts.size() > 0) {
                /*** 3.获取无序广播 */
                r = mParallelBroadcasts.remove(0);
                ...
                
                for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
                 /**
                 * 4. 将 r 对象描述的广播发送给对应的广播者
                 */
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                }

                addBroadcastToHistoryLocked(r);
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                        + mQueueName + "] " + r);
            }

            ...
        }
    }

从前面 BroadcastHandler 方法中我们得知传入的参数 fromMsg 的值为 true,因此在注释1 处将 mBroadcastsScheduled 设置为 flase, 表示对于此前发来的 BROADCAST_INTENT_MSG 类型的消息已经处理了。在注释 2 处的 mParallelBroadcasts 列表用来存储无序广播,通过 while 循环将 mParallelBroadcasts 列表中的无序广播发送给对应的广播接收者。在注释 3 处获取每一个 mParallelBroadcasts 列表中存储的 BroadcastRecord 类型的 r 对象。在注释 4 处将这些 r 对象描述的广播发送给对应的广播接收者,deliverToRegisteredReceiverLocked 方法,如下所示:

//BroadcastQueue.java


    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) {
     ...
       
                 if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
                 if (ordered) {
                    skipReceiverLocked(r);
                }
            } else {
                /***
                 * 1.
                 */
                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
            }  
       
     ...
       
      
    }


deliverToRegisteredReceiverLocked?内部代码如要是用来检查广播发送者和广播接收者的权限,如果通过了权限的检查,则会调用注释 1 处的?performReceiveLocked?方法。

//BroadcastQueue.java

    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
        /**
         * 1. 
         */
        if (app != null) {
            /**
             * 2. 
             */
            if (app.thread != null) {
                
                try {
                    /**
                     * 3. 
                     */
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);
                ...
    }

在注释 1 处和注释 2 处的代码表示如果广播的接收者所在的应用程序进程存在并且正在运行,则执行注释 3 处的代码,表示用广播接收者所在的应用程序进程来接收广播,这里 app.thread 指的是 ApplicationThread,它其实在 ActivityThread 内部类中,继承于 IApplicationThread.Stub 下面我们看它的实现,代码如下:


?

//ActivityThread.java

    private class ApplicationThread extends IApplicationThread.Stub {
    ...
      
            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);
      			/***1. 调用 IIntentReceiver 中的 performReceive 函数*/
            receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                    sticky, sendingUser);
        }
    ...
      
    }

在注释 1 中调用了 IIntentReceiver 的 performReceive 函数,IItentReceiver 在前面提到过,用于广播的跨进程的通信,它的具体实现在 LoadedApk.ReceiverDispatcher.InnerReceiver,代码如下:


?

//LoadedApk.java
    static final class ReceiverDispatcher {

        final static class InnerReceiver extends IIntentReceiver.Stub {
            final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
            final LoadedApk.ReceiverDispatcher mStrongRef;

            InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
                mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
                mStrongRef = strong ? rd : null;
            }

            @Override
            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                final LoadedApk.ReceiverDispatcher rd;
                if (intent == null) {
                    Log.wtf(TAG, "Null intent received");
                    rd = null;
                } else {
                    rd = mDispatcher.get();
                }
              ...
                if (rd != null) {
                  //1. 
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                } else {
                   ...
                }
            }
        }
      ....
        
    }

其实 IIntentReceiver 和 IActivityManager 一样,都使用了 aidl 来实现进程间通信。InnerReceiver 继承自 IIntentReceiver.Stub,是 Binder 通信的服务器端, IIntentReceiver 则是 Binder 通信的客服端、InnerReceiver 在本地的代理,它的具体的实现就是 InnerReceiver. 在 InnerReceiver 的 performReceiver 方法的注释 1 调用了 ReceiverDispatch 类型的 rd 对象的 performReceive 方法,代码如下:

//LoadedApk.java
        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            /**
             * 1. 
             */
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
           ...
            /**
             * 2. 
             */
            if (intent == null || !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);
                }
            }
        }

    }

在注释 1 处将广播的 intent 等信息封装到了为 Args 对象中,在注释 2 处调用 mActivityThread 的 post 方法并传入了 Args 对象。在这个 mActivityThread 是一个 Handler 对象,具体指向的就是 H 类,在注释 2 处的代码就是将 Args 对象的 getRunnable 方法通过 H 发送到线程的消息队列中, Args 中的实现,代码如下:


?

//LoadedApk.java

        final class Args extends BroadcastReceiver.PendingResult {
            private Intent mCurIntent;
            private final boolean mOrdered;
            private boolean mDispatched;
            private Throwable mPreviousRunStacktrace; // To investigate b/37809561. STOPSHIP remove.

            public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                    boolean ordered, boolean sticky, int sendingUser) {
                super(resultCode, resultData, resultExtras,
                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                        sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
                mCurIntent = intent;
                mOrdered = ordered;
            }

            public final Runnable getRunnable() {
                return () -> {
                    final BroadcastReceiver receiver = mReceiver;
                    ...
                    try {
                        ClassLoader cl = mReceiver.getClass().getClassLoader();
                        intent.setExtrasClassLoader(cl);
                        intent.prepareToEnterProcess();
                        setExtrasClassLoader(cl);
                        receiver.setPendingResult(this);
                        //1. 回调到接收广播的 onReceiver
                        receiver.onReceive(mContext, intent);
                    } catch (Exception e) {
                        ...
                  
                };
            }
        }

在注释 1 处执行了 BroadcastReceiver 回调 **onReceive(mContext, intent);**方法,这样注册广播接收者就收到了广播并得到了 intent ,整个流程到这里就讲解完了

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-01-03 16:13:34  更:2022-01-03 16:14:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:43:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码