Androidのラジオについて(3)

18448 ワード

どのような放送が同時ですか?
Androidのtrickを解読し始めましょう.普通の放送は同時ですか.この問題を抱えてbroadcastInentLockedの実装ロジック.
broadcastInentLockedの詳細は多く、後で説明します.まず、パラレルキューとシリアルキューに関連する部分だけを抽出します.
receiversとregisteredReceivers
重点を描きました.重点を描きましたね.次に、receiverとregisteredReceiverの2つの重要な概念を学びます.この2つの違いは、ブロードキャストを同時に受信できるか、シリアルで受信できるかを本当に決定します.
一般的には、registeredReceiverはJavaコードで実行時に登録されたreceiverであり、receiverはAndroidManifestを接続する.xmlに登録されているものも加算されます.動的に登録されたBroadcastReceiverのみに配布したい場合は、FLAG_を設定できます.RECEIVER_REGISTERED_ONLYプロパティ.
通常放送処理の流れを処理する際には、まずreceiversとregisteredReceiversの2つのListを定義する.
16820        // Figure out who all will receive this broadcast.
16821        List receivers = null;
16822        List registeredReceivers = null;

それぞれ、どこで割り当てられているかを見てみましょう.
先ほど述べたように、FLAGを設けない限りRECEIVER_REGISTERED_ONLYの場合、完全なreceiverリストを調べる必要があります.
16823        // Need to resolve the intent to interested receivers...
16824        if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
16825                 == 0) {
16826            receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
16827        }

もしそうならgetComponent()==nullの場合、registeredReceiversはqueryIntentメソッドでクエリされます.
16828        if (intent.getComponent() == null) {
...
16847                registeredReceivers = mReceiverResolver.queryIntent(intent,
16848                        resolvedType, false, userId);
...
16850        }

はい、2つのreceiver関連のリストが割り当てられています.次の奇跡を明らかにする時が来たが、いったいどれが看板をひっくり返されたのだろうか.
16858        int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
16859        if (!ordered && NR > 0) {
16860            // If we are not serializing this broadcast, then send the
16861            // registered receivers separately so they don't wait for the
16862            // components to be launched.
16863            final BroadcastQueue queue = broadcastQueueForIntent(intent);
16864            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
16865                    callerPackage, callingPid, callingUid, resolvedType, requiredPermissions,
16866                    appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,
16867                    resultExtras, ordered, sticky, false, userId);
16868            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
16869            final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
16870            if (!replaced) {
16871                queue.enqueueParallelBroadcastLocked(r);
16872                queue.scheduleBroadcastsLocked();
16873            }
16874            registeredReceivers = null;
16875            NR = 0;
16876        }

そう、ordered以外のregistered receiversが同時実行されました.
ではreceiversはどのように処理されているのでしょうか.一言でorderedとして扱われた.コードを見てみましょう.
16950        if ((receivers != null && receivers.size() > 0)
16951                || resultTo != null) {
16952            BroadcastQueue queue = broadcastQueueForIntent(intent);
16953            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
16954                    callerPackage, callingPid, callingUid, resolvedType,
16955                    requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
16956                    resultData, resultExtras, ordered, sticky, false, userId);
...
16965                queue.enqueueOrderedBroadcastLocked(r);
16966                queue.scheduleBroadcastsLocked();
...
16968        }

ActivityManagerService.broadcastInentLockedフルフロー分析
次は正式に後の処理ロジックを見始めます.まずタイミングチャートを見てみましょう.全体的にはまず印象があります.
sequenceDiagram;
    Activity ->> ContextWrapper : sendBroadcast()
    ContextWrapper ->> ContextImpl : sendBroadcast()
    ContextImpl ->> ActivityManagerService: broadcastIntent()
    ActivityManagerService ->> ActivityManagerService : broadcastIntentLocked()
    ActivityManagerService ->> ActivityManagerService : collectReceiverComponents()
    ActivityManagerService ->> BroadcastQueue : scheduleBroadcastsLocked()
    BroadcastQueue ->> BroadcastQueue : processNextBroadcast()
    ActivityManagerService ->> ActivityManagerService : deliverToRegisteredReceiverLocked()
    ActivityManagerService ->> ActivityManagerService : performReceiveLocked()
    ActivityManagerService ->> ApplicationThreadProxy : scheduleRegisteredReceiver()
    ApplicationThreadProxy ->> InnerReceiver : performReceive()
    InnerReceiver ->> ReceiverDispatcher : performReceive()
    ReceiverDispatcher ->> BroadcastReceiver : onReceive()

上の私达は跳んで见て、みんなは1つの完全な印象に欠けて、私达に我慢して全体の流れを过ごしましょう.
private final int broadcastIntentLocked(ProcessRecord callerApp,
        String callerPackage, Intent intent, String resolvedType,
        IIntentReceiver resultTo, int resultCode, String resultData,
        Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options,
        boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
    intent = new Intent(intent);

    // By default broadcasts do not go to stopped apps.
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

    // If we have not finished booting, don't allow this to launch new processes.
    if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    }

    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
            (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
            + " ordered=" + ordered + " userid=" + userId);
    if ((resultTo != null) && !ordered) {
        Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
    }

    userId = handleIncomingUser(callingPid, callingUid, userId,
            true, ALLOW_NON_FULL, "broadcast", callerPackage);
...

中には判断権限などの操作が山積みになっていて、私たちは省略しました.
...
    final String action = intent.getAction();
    if (action != null) {
        switch (action) {
            case Intent.ACTION_UID_REMOVED:
            case Intent.ACTION_PACKAGE_REMOVED:
            case Intent.ACTION_PACKAGE_CHANGED:
            case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
            case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
...
            case Intent.ACTION_TIMEZONE_CHANGED:
                // If this is the time zone changed action, queue up a message that will reset
                // the timezone of all currently running processes. This message will get
                // queued up before the broadcast happens.
                mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
                break;
            case Intent.ACTION_TIME_CHANGED:
                // If the user set the time, let all running processes know.
                final int is24Hour =
                        intent.getBooleanExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, false) ? 1
                                : 0;
                mHandler.sendMessage(mHandler.obtainMessage(UPDATE_TIME, is24Hour, 0));
                BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
                synchronized (stats) {
                    stats.noteCurrentTimeChangedLocked();
                }
                break;
            case Intent.ACTION_CLEAR_DNS_CACHE:
                mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
                break;
            case Proxy.PROXY_CHANGE_ACTION:
                ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO);
                mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
                break;
        }
    }
...

上はいくつかの特殊な放送の処理です.いよいよコアなロジックを比較して、この放送を受信した受信者が何なのかを調べてみましょう.
    // Figure out who all will receive this broadcast.
    List receivers = null;
    List registeredReceivers = null;
    // Need to resolve the intent to interested receivers...
    if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
             == 0) {
        receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
    }

FLAG_RECEIVER_REGISTERED_ONLYという属性は、コードに動的登録をサポートする受信者であるかどうかを説明するために使用され、そうでない場合はcollectReceiverComponentsメソッドでAndroidManifestに適用するアプリケーションを調べる.xmlにもリスニングが登録されています.
こんな面白い関数、一緒に見に行きましょう.
ActivityManagerService.collectReceiverComponents
入る前に、いくつかのデータクラスの定義を見てみましょう.ResolveInfoクラスはAndroidManifestを格納するために使用されます.xmlのラベルに対応する情報.
public class ResolveInfo implements Parcelable;

私たちは正式にcollectReceiverComponentsに入りました.
private List collectReceiverComponents(Intent intent, String resolvedType,int callingUid, int[] users) {
    List receivers = null;
    try {
        HashSet singleUserReceivers = null;
        boolean scannedFirstReceivers = false;
        for (int user : users) {
            // Skip users that have Shell restrictions
            if (callingUid == Process.SHELL_UID
                    && getUserManagerLocked().hasUserRestriction(
                            UserManager.DISALLOW_DEBUGGING_FEATURES, user)) {
                continue;
            }

次にPMSを呼び出してクエリーします.
            List newReceivers = AppGlobals.getPackageManager()
                    .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);

PMSのこのコードはこのようなもので、私たちは先に詳しく分析しないで、後で登録の時に言及します.
public List queryIntentReceivers(Intent intent, String resolvedType, int flags,
        int userId) {
    if (!sUserManager.exists(userId)) return Collections.emptyList();
    ComponentName comp = intent.getComponent();
    if (comp == null) {
        if (intent.getSelector() != null) {
            intent = intent.getSelector();
            comp = intent.getComponent();
        }
    }
    if (comp != null) {
        List list = new ArrayList(1);
        ActivityInfo ai = getReceiverInfo(comp, flags, userId);
        if (ai != null) {
            ResolveInfo ri = new ResolveInfo();
            ri.activityInfo = ai;
            list.add(ri);
        }
        return list;
    }

    // reader
    synchronized (mPackages) {
        String pkgName = intent.getPackage();
        if (pkgName == null) {
            return mReceivers.queryIntent(intent, resolvedType, flags, userId);
        }
        final PackageParser.Package pkg = mPackages.get(pkgName);
        if (pkg != null) {
            return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers,
                    userId);
        }
        return null;
    }
}

collectReceiverComponentsに戻って下を見続けます.
            if (user != UserHandle.USER_OWNER && newReceivers != null) {
                // If this is not the primary user, we need to check for
                // any receivers that should be filtered out.
                for (int i=0; i();
                            }
                            singleUserReceivers.add(cn);
                        }
                    }
                }
                // Add the new results to the existing results, tracking
                // and de-dupping single user receivers.
                for (int i=0; i();
                        }
                        if (!singleUserReceivers.contains(cn)) {
                            singleUserReceivers.add(cn);
                            receivers.add(ri);
                        }
                    } else {
                        receivers.add(ri);
                    }
                }
            }
        }
    } catch (RemoteException ex) {
        // pm is in same process, this will never happen.
    }
    return receivers;
}

次にbroadcastInentLockedに戻って下を見続けます.
    if (intent.getComponent() == null) {
        if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
            // Query one target user at a time, excluding shell-restricted users
            UserManagerService ums = getUserManagerLocked();
            for (int i = 0; i < users.length; i++) {
                if (ums.hasUserRestriction(
                        UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                    continue;
                }
                List registeredReceiversForUser =
                        mReceiverResolver.queryIntent(intent,
                                resolvedType, false, users[i]);
                if (registeredReceivers == null) {
                    registeredReceivers = registeredReceiversForUser;
                } else if (registeredReceiversForUser != null) {
                    registeredReceivers.addAll(registeredReceiversForUser);
                }
            }
        } else {
            registeredReceivers = mReceiverResolver.queryIntent(intent,
                    resolvedType, false, userId);
        }
    }

    final boolean replacePending =
            (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

いよいよ私たちが最も関心を持っている論理部分に着きます.みんなよく見てください.
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueing broadcast: " + intent.getAction()
            + " replacePending=" + replacePending);

    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.


orderedでなく、このイベントを登録したreceiverキューが空でない場合は、通常のメッセージの処理を開始します.
        final BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                callerPackage, callingPid, callingUid, resolvedType, requiredPermissions,
                appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,
                resultExtras, ordered, sticky, false, userId);
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
        final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);

次に、通常のメッセージをパラレル・メッセージ・キューに追加します.e n q ueParallelBroadcastLockedとscheduleBroadcastsLockedは、前の準備知識を話しました.ここでは繰り返しません.
        if (!replaced) {
            queue.enqueueParallelBroadcastLocked(r);
            queue.scheduleBroadcastsLocked();
        }
        registeredReceivers = null;
        NR = 0;
    }

以上、同時メッセージ処理は正式に終了した.次にシリアルメッセージの処理を開始し、PACKAGE_について省略します.ADDEDメッセージは、新しくインストールされたアプリケーションにこの分岐タスクを送信します.
また、整列キューには追加のことがあります.整列しますか.ソートします.
    // Merge into one list.
    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;
            }
        }
    }
    while (ir < NR) {
        if (receivers == null) {
            receivers = new ArrayList();
        }
        receivers.add(registeredReceivers.get(ir));
        ir++;
    }

最後に、シリアルキューに参加してメッセージを送信するプロセスです.コンカレントキューはキューを除いて同じです.
    if ((receivers != null && receivers.size() > 0)
            || resultTo != null) {
        BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                callerPackage, callingPid, callingUid, resolvedType,
                requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                resultData, resultExtras, ordered, sticky, false, userId);

        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
                + ": prev had " + queue.mOrderedBroadcasts.size());
        if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
                "Enqueueing broadcast " + r.intent.getAction());

        boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
        if (!replaced) {
            queue.enqueueOrderedBroadcastLocked(r);
            queue.scheduleBroadcastsLocked();
        }
    }

    return ActivityManager.BROADCAST_SUCCESS;
}