說說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    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容