说说Android的广播(6) - 广播消息的接收和派发

说说Android的广播(6) - 广播消息的接收和派发

广播消息的接收过程

并发队列的处理

我们还是继续上一讲的讲法,先把干货提炼出来,然后再看完整的流程.

654            // First, deliver any non-serialized broadcasts right away.
655            while (mParallelBroadcasts.size() > 0) {
656                r = mParallelBroadcasts.remove(0);
657                r.dispatchTime = SystemClock.uptimeMillis();
658                r.dispatchClockTime = System.currentTimeMillis();
659                final int N = r.receivers.size();
...
662                for (int i=0; i<N; i++) {
663                    Object target = r.receivers.get(i);
...
667                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
668                }
669                addBroadcastToHistoryLocked(r);
...
672            }

针对每个receiver,都调用deliverToRegisteredReceiverLocked方法去处理,没有返回值,没有等待。
最后加入到广播历史中,结束,就这么简单.

有序广播处理结束,返回结果的处理

754
755                if (r.receivers == null || r.nextReceiver >= numReceivers
756                        || r.resultAbort || forceReceive) {
757                    // No more receivers for this broadcast!  Send the final
758                    // result if requested...
759                    if (r.resultTo != null) {
760                        try {
...

既然结束了,就可以调用performReceiveLocked返回最终的结果给调用者了。

764                            performReceiveLocked(r.callerApp, r.resultTo,
765                                new Intent(r.intent), r.resultCode,
766                                r.resultData, r.resultExtras, false, false, r.userId);
767                            // Set this to null so that the reference
768                            // (local and remote) isn't kept in the mBroadcastHistory.
769                            r.resultTo = null;
770                        } catch (RemoteException e) {
771                            r.resultTo = null;
772                            Slog.w(TAG, "Failure ["
773                                    + mQueueName + "] sending broadcast result of "
774                                    + r.intent, e);
775                        }
776                    }
...

结束了,清理timer吧:

779                    cancelBroadcastTimeoutLocked();
...

下面记录一下历史,把当前组件从队列中去掉,进行下一次循环。

784                    // ... and on to the next...
785                    addBroadcastToHistoryLocked(r);
786                    mOrderedBroadcasts.remove(0);
787                    r = null;
788                    looped = true;
789                    continue;
790                }
791            } while (r == null);

BroadcastHandler

前面我们分析过了,发送广播时,不管是有序的还是无序的,都会是发送一个BROADCAST_INTENT_MSG的消息出来。
下面我们看看Handler中是如何处理的:

157    private final class BroadcastHandler extends Handler {
158        public BroadcastHandler(Looper looper) {
159            super(looper, null, true);
160        }
161
162        @Override
163        public void handleMessage(Message msg) {
164            switch (msg.what) {
165                case BROADCAST_INTENT_MSG: {
166                    if (DEBUG_BROADCAST) Slog.v(
167                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
168                    processNextBroadcast(true);
169                } break;
170                case BROADCAST_TIMEOUT_MSG: {
171                    synchronized (mService) {
172                        broadcastTimeoutLocked(true);
173                    }
174                } break;
175                case SCHEDULE_TEMP_WHITELIST_MSG: {
176                    DeviceIdleController.LocalService dic = mService.mLocalDeviceIdleController;
177                    if (dic != null) {
178                        dic.addPowerSaveTempWhitelistAppDirect(UserHandle.getAppId(msg.arg1),
179                                msg.arg2, true, (String)msg.obj);
180                    }
181                } break;
182            }
183        }
184    };

如上面所看到的,BROADCAST_INTENT_MSG会去调用processNextBroadcast方法。

processNextBroadcast

processNextBroadcast是整个逻辑的核心。

639    final void processNextBroadcast(boolean fromMsg) {
640        synchronized(mService) {
641            BroadcastRecord r;
642
...
647
648            mService.updateCpuStats();
649
650            if (fromMsg) {
651                mBroadcastsScheduled = false;
652            }

第一步是处理动态注册的广播,这个前面我们已经分析过了。

653
654            // First, deliver any non-serialized broadcasts right away.
655            while (mParallelBroadcasts.size() > 0) {
656                r = mParallelBroadcasts.remove(0);
657                r.dispatchTime = SystemClock.uptimeMillis();
658                r.dispatchClockTime = System.currentTimeMillis();
659                final int N = r.receivers.size();
660                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
661                        + mQueueName + "] " + r);
662                for (int i=0; i<N; i++) {
663                    Object target = r.receivers.get(i);
664                    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
665                            "Delivering non-ordered on [" + mQueueName + "] to registered "
666                            + target + ": " + r);
667                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
668                }
669                addBroadcastToHistoryLocked(r);
670                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
671                        + mQueueName + "] " + r);
672            }

第二步,开始处理有序广播,当然,如前面我们反复所讲的,非动态注册的也是按有序广播处理的。

674            // Now take care of the next serialized one...
675
676            // If we are waiting for a process to come up to handle the next
677            // broadcast, then do nothing at this point.  Just in case, we
678            // check that the process we're waiting for still exists.
679            if (mPendingBroadcast != null) {
680                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
681                        "processNextBroadcast [" + mQueueName + "]: waiting for "
682                        + mPendingBroadcast.curApp);
683
684                boolean isDead;
685                synchronized (mService.mPidsSelfLocked) {
686                    ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
687                    isDead = proc == null || proc.crashing;
688                }
689                if (!isDead) {
690                    // It's still alive, so keep waiting
691                    return;
692                } else {
693                    Slog.w(TAG, "pending app  ["
694                            + mQueueName + "]" + mPendingBroadcast.curApp
695                            + " died before responding to broadcast");
696                    mPendingBroadcast.state = BroadcastRecord.IDLE;
697                    mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
698                    mPendingBroadcast = null;
699                }
700            }
701

前面处理一些异常情况,下面开始第三步,先处理下有序队列为空的性况。
如果是最后一条,就调整一下OOM Adj之类的,为系统做点贡献。

702            boolean looped = false;
703
704            do {
705                if (mOrderedBroadcasts.size() == 0) {
706                    // No more broadcasts pending, so all done!
707                    mService.scheduleAppGcsLocked();
708                    if (looped) {
709                        // If we had finished the last ordered broadcast, then
710                        // make sure all processes have correct oom and sched
711                        // adjustments.
712                        mService.updateOomAdjLocked();
713                    }
714                    return;
715                }

如果不为空,我们就take一个记录,开始干活。先处理超时的情况,如果超时的话,就调用broadcastTimeoutLocked来结束广播。

716                r = mOrderedBroadcasts.get(0);
717                boolean forceReceive = false;
718
719                // Ensure that even if something goes awry with the timeout
720                // detection, we catch "hung" broadcasts here, discard them,
721                // and continue to make progress.
722                //
723                // This is only done if the system is ready so that PRE_BOOT_COMPLETED
724                // receivers don't get executed with timeouts. They're intended for
725                // one time heavy lifting after system upgrades and can take
726                // significant amounts of time.
727                int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
728                if (mService.mProcessesReady && r.dispatchTime > 0) {
729                    long now = SystemClock.uptimeMillis();
730                    if ((numReceivers > 0) &&
731                            (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
732                        Slog.w(TAG, "Hung broadcast ["
733                                + mQueueName + "] discarded after timeout failure:"
734                                + " now=" + now
735                                + " dispatchTime=" + r.dispatchTime
736                                + " startTime=" + r.receiverTime
737                                + " intent=" + r.intent
738                                + " numReceivers=" + numReceivers
739                                + " nextReceiver=" + r.nextReceiver
740                                + " state=" + r.state);
741                        broadcastTimeoutLocked(false); // forcibly finish this broadcast
742                        forceReceive = true;
743                        r.state = BroadcastRecord.IDLE;
744                    }
745                }

如果拿到的这个广播记录已经是在非空闲状态了,那就let it be.

746
747                if (r.state != BroadcastRecord.IDLE) {
748                    if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
749                            "processNextBroadcast("
750                            + mQueueName + ") called when not idle (state="
751                            + r.state + ")");
752                    return;
753                }

如果已经是最后一个接收者了,说明一切该结束了,那么就调用performReceiveLocked返回值吧。有序广播是要求返回结果的。

755                if (r.receivers == null || r.nextReceiver >= numReceivers
756                        || r.resultAbort || forceReceive) {
757                    // No more receivers for this broadcast!  Send the final
758                    // result if requested...
759                    if (r.resultTo != null) {
760                        try {
...
764                            performReceiveLocked(r.callerApp, r.resultTo,
765                                new Intent(r.intent), r.resultCode,
766                                r.resultData, r.resultExtras, false, false, r.userId);
767                            // Set this to null so that the reference
768                            // (local and remote) isn't kept in the mBroadcastHistory.
769                            r.resultTo = null;
770                        } catch (RemoteException e) {
771                            r.resultTo = null;
772                            Slog.w(TAG, "Failure ["
773                                    + mQueueName + "] sending broadcast result of "
774                                    + r.intent, e);
775                        }
776                    }
777

既然处理完了,超时就可以停掉了。

779                    cancelBroadcastTimeoutLocked();

记录历史,进行下一个。

784                    // ... and on to the next...
785                    addBroadcastToHistoryLocked(r);
786                    mOrderedBroadcasts.remove(0);
787                    r = null;
788                    looped = true;
789                    continue;
790                }
791            } while (r == null);

处理下一个receiver:

793            // Get the next receiver...
794            int recIdx = r.nextReceiver++;
795
796            // Keep track of when this receiver started, and make sure there
797            // is a timeout message pending to kill it if need be.
798            r.receiverTime = SystemClock.uptimeMillis();
799            if (recIdx == 0) {
800                r.dispatchTime = r.receiverTime;
801                r.dispatchClockTime = System.currentTimeMillis();
...

如果有mPendingBroadcastTimeoutMessage的欠债,就赶快还了吧。

805            if (! mPendingBroadcastTimeoutMessage) {
806                long timeoutTime = r.receiverTime + mTimeoutPeriod;
807                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
808                        "Submitting BROADCAST_TIMEOUT_MSG ["
809                        + mQueueName + "] for " + r + " at " + timeoutTime);
810                setBroadcastTimeoutLocked(timeoutTime);
811            }
812
813            final BroadcastOptions brOptions = r.options;
814            final Object nextReceiver = r.receivers.get(recIdx);
815
816            if (nextReceiver instanceof BroadcastFilter) {
817                // Simple case: this is a registered receiver who gets
818                // a direct call.
819                BroadcastFilter filter = (BroadcastFilter)nextReceiver;

核心逻辑是下面调用的deliverToRegisteredReceiverLocked。

824                deliverToRegisteredReceiverLocked(r, filter, r.ordered);
825                if (r.receiver == null || !r.ordered) {
826                    // The receiver has already finished, so schedule to
827                    // process the next one.
...
831                    r.state = BroadcastRecord.IDLE;
832                    scheduleBroadcastsLocked();
833                } else {
834                    if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
835                        scheduleTempWhitelistLocked(filter.owningUid,
836                                brOptions.getTemporaryAppWhitelistDuration(), r);
837                    }
838                }
839                return;
840            }

下面开始进入Hard case,就是该启动新的进程了去接收消息了。

842            // Hard case: need to instantiate the receiver, possibly
843            // starting its application process to host it.
844
845            ResolveInfo info =
846                (ResolveInfo)nextReceiver;
847            ComponentName component = new ComponentName(
848                    info.activityInfo.applicationInfo.packageName,
849                    info.activityInfo.name);
850
851            boolean skip = false;
...

中间有大段的权限相关的处理,我们暂时不关注。

944            boolean isSingleton = false;
945            try {
946                isSingleton = mService.isSingleton(info.activityInfo.processName,
947                        info.activityInfo.applicationInfo,
948                        info.activityInfo.name, info.activityInfo.flags);
949            } catch (SecurityException e) {
950                Slog.w(TAG, e.getMessage());
951                skip = true;
952            }
953            if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {
954                if (ActivityManager.checkUidPermission(
955                        android.Manifest.permission.INTERACT_ACROSS_USERS,
956                        info.activityInfo.applicationInfo.uid)
957                                != PackageManager.PERMISSION_GRANTED) {
958                    Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString()
959                            + " requests FLAG_SINGLE_USER, but app does not hold "
960                            + android.Manifest.permission.INTERACT_ACROSS_USERS);
961                    skip = true;
962                }
963            }
964            if (r.curApp != null && r.curApp.crashing) {
965                // If the target process is crashing, just skip it.
966                Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r
967                        + " to " + r.curApp + ": process crashing");
968                skip = true;
969            }
970            if (!skip) {
971                boolean isAvailable = false;
972                try {
973                    isAvailable = AppGlobals.getPackageManager().isPackageAvailable(
974                            info.activityInfo.packageName,
975                            UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
976                } catch (Exception e) {
977                    // all such failures mean we skip this receiver
978                    Slog.w(TAG, "Exception getting recipient info for "
979                            + info.activityInfo.packageName, e);
980                }
981                if (!isAvailable) {
982                    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
983                            "Skipping delivery to " + info.activityInfo.packageName + " / "
984                            + info.activityInfo.applicationInfo.uid
985                            + " : package no longer available");
986                    skip = true;
987                }
988            }
989
990            if (skip) {
991                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
992                        "Skipping delivery of ordered [" + mQueueName + "] "
993                        + r + " for whatever reason");
994                r.receiver = null;
995                r.curFilter = null;
996                r.state = BroadcastRecord.IDLE;
997                scheduleBroadcastsLocked();
998                return;
999            }
1000
1001            r.state = BroadcastRecord.APP_RECEIVE;
1002            String targetProcess = info.activityInfo.processName;
1003            r.curComponent = component;
1004            final int receiverUid = info.activityInfo.applicationInfo.uid;
1005            // If it's a singleton, it needs to be the same app or a special app
1006            if (r.callingUid != Process.SYSTEM_UID && isSingleton
1007                    && mService.isValidSingletonCall(r.callingUid, receiverUid)) {
1008                info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
1009            }
1010            r.curReceiver = info.activityInfo;
1011            if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {
1012                Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
1013                        + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
1014                        + info.activityInfo.applicationInfo.uid);
1015            }
1016
1017            if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
1018                scheduleTempWhitelistLocked(receiverUid,
1019                        brOptions.getTemporaryAppWhitelistDuration(), r);
1020            }
1021
1022            // Broadcast is being executed, its package can't be stopped.
1023            try {
1024                AppGlobals.getPackageManager().setPackageStoppedState(
1025                        r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
1026            } catch (RemoteException e) {
1027            } catch (IllegalArgumentException e) {
1028                Slog.w(TAG, "Failed trying to unstop package "
1029                        + r.curComponent.getPackageName() + ": " + e);
1030            }

这里后面调用核心逻辑processCurBroadcastLocked。

1032            // Is this receiver's application already running?
1033            ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
1034                    info.activityInfo.applicationInfo.uid, false);
1035            if (app != null && app.thread != null) {
1036                try {
1037                    app.addPackage(info.activityInfo.packageName,
1038                            info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
1039                    processCurBroadcastLocked(r, app);
1040                    return;
1041                } catch (RemoteException e) {
1042                    Slog.w(TAG, "Exception when sending broadcast to "
1043                          + r.curComponent, e);
1044                } catch (RuntimeException e) {
1045                    Slog.wtf(TAG, "Failed sending broadcast to "
1046                            + r.curComponent + " with " + r.intent, e);
1047                    // If some unexpected exception happened, just skip
1048                    // this broadcast.  At this point we are not in the call
1049                    // from a client, so throwing an exception out from here
1050                    // will crash the entire system instead of just whoever
1051                    // sent the broadcast.
1052                    logBroadcastReceiverDiscardLocked(r);
1053                    finishReceiverLocked(r, r.resultCode, r.resultData,
1054                            r.resultExtras, r.resultAbort, false);
1055                    scheduleBroadcastsLocked();
1056                    // We need to reset the state if we failed to start the receiver.
1057                    r.state = BroadcastRecord.IDLE;
1058                    return;
1059                }
1060
1061                // If a dead object exception was thrown -- fall through to
1062                // restart the application.
1063            }

下面开始重头戏,如果进程没启动,调用startProcessLocked去启动进程。

1065            // Not running -- get it started, to be executed when the app comes up.
1066            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
1067                    "Need to start app ["
1068                    + mQueueName + "] " + targetProcess + " for broadcast " + r);
1069            if ((r.curApp=mService.startProcessLocked(targetProcess,
1070                    info.activityInfo.applicationInfo, true,
1071                    r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
1072                    "broadcast", r.curComponent,
1073                    (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
1074                            == null) {
1075                // Ah, this recipient is unavailable.  Finish it if necessary,
1076                // and mark the broadcast record as ready for the next.
1077                Slog.w(TAG, "Unable to launch app "
1078                        + info.activityInfo.applicationInfo.packageName + "/"
1079                        + info.activityInfo.applicationInfo.uid + " for broadcast "
1080                        + r.intent + ": process is bad");
1081                logBroadcastReceiverDiscardLocked(r);
1082                finishReceiverLocked(r, r.resultCode, r.resultData,
1083                        r.resultExtras, r.resultAbort, false);
1084                scheduleBroadcastsLocked();
1085                r.state = BroadcastRecord.IDLE;
1086                return;
1087            }
1088
1089            mPendingBroadcast = r;
1090            mPendingBroadcastRecvIndex = recIdx;
1091        }
1092    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容