美文网首页Android知识
Broadcast(三)sendBroadcast

Broadcast(三)sendBroadcast

作者: 风风风筝 | 来源:发表于2016-09-13 21:22 被阅读2203次

sendBroadcast、sendStickyBroadcast、sendOrderedBroadcast基本一样,只差一个参数broadcastIntent方法倒数第二个参数代表sticky,倒数第三个参数代表serialized

@Override
@Deprecated
public void sendStickyBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        // 这个true就代表是sticky
        ActivityManagerNative.getDefault().broadcastIntent(
            mMainThread.getApplicationThread(), intent, resolvedType, null,
            Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
            getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

ActivityManagerService.java
broadcastIntent→broadcastIntentLocked

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) {
    // step1:设置flag
    // step2:广播权限校验
    // step3:处理系统广播
    // step4:增加sticky广播
    // step5:查询receivers(静态注册的接收者)和registeredReceivers(动态注册的接收者)
    // step6:处理无序广播
    // step7:合并registeredReceivers到receivers
    // step8:处理有序广播
    return ActivityManager.BROADCAST_SUCCESS;
}

sendBroadcast→→→→→1 2 3 x 5 6 7 8
sendStickyBroadcast→→1 2 3 4 5 6 7 8
sendOrderedBroadcast→1 2 3 x 5 x 7 8
注意这3个方法执行的step,下面会详细说明

step1:设置广播flag

intent = new Intent(intent);
//广播不会发送给已停止的package
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

//当没有启动完成时,不允许启动新进程
if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
userId = handleIncomingUser(callingPid, callingUid, userId,
        true, ALLOW_NON_FULL, "broadcast", callerPackage);

//当非USER_ALL广播且当前用户并没有处于Running的情况下,除非是系统升级广播或者关机广播,否则直接返回
if (userId != UserHandle.USER_ALL && !isUserRunningLocked(userId, false)) {
    if ((callingUid != Process.SYSTEM_UID
            || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
            && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
        return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
    }
}

BroadcastReceiver还有其他flag,位于Intent.java常量

FLAG_RECEIVER_REGISTERED_ONLY //只允许已注册receiver接收广播
FLAG_RECEIVER_REPLACE_PENDING //新广播会替代相同广播
FLAG_RECEIVER_FOREGROUND //只允许前台receiver接收广播
FLAG_RECEIVER_NO_ABORT //对于有序广播,先接收到的receiver无权抛弃广播
FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT //Boot完成之前,只允许已注册receiver接收广播
FLAG_RECEIVER_BOOT_UPGRADE //升级模式下,允许系统准备就绪前可以发送广播

step2:广播权限验证

//对于callingAppId为SYSTEM_UID,PHONE_UID,SHELL_UID,BLUETOOTH_UID,NFC_UID或者callingUid == 0时直接通过
int callingAppId = UserHandle.getAppId(callingUid);
if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
    || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
    || callingAppId == Process.NFC_UID || callingUid == 0) {
    //直接通过
} else if (callerApp == null || !callerApp.persistent) {
    try {
        if (AppGlobals.getPackageManager().isProtectedBroadcast(
                intent.getAction())) {
            //不允许发送给受保护的广播
            throw new SecurityException(msg);
        } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) {
            ...
        }
    } catch (RemoteException e) {
        return ActivityManager.BROADCAST_SUCCESS;
    }
}

step3:处理系统相关广播

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:
            // Handle special intents: if this broadcast is from the package
            // manager about a package being removed, we need to remove all of
            // its activities from the history stack.
            if (checkComponentPermission(
                    android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
                    callingPid, callingUid, -1, true)
                    != PackageManager.PERMISSION_GRANTED) {
                String msg = "Permission Denial: " + intent.getAction()
                        + " broadcast from " + callerPackage + " (pid=" + callingPid
                        + ", uid=" + callingUid + ")"
                        + " requires "
                        + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
                Slog.w(TAG, msg);
                throw new SecurityException(msg);
            }
            switch (action) {
                case Intent.ACTION_UID_REMOVED:
                    final Bundle intentExtras = intent.getExtras();
                    final int uid = intentExtras != null
                            ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
                    if (uid >= 0) {
                        mBatteryStatsService.removeUid(uid);
                        mAppOpsService.uidRemoved(uid);
                    }
                    break;
                case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
                    // If resources are unavailable just force stop all those packages
                    // and flush the attribute cache as well.
                    String list[] =
                            intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                    if (list != null && list.length > 0) {
                        for (int i = 0; i < list.length; i++) {
                            forceStopPackageLocked(list[i], -1, false, true, true,
                                    false, false, userId, "storage unmount");
                        }
                        mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
                        sendPackageBroadcastLocked(
                                IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list,
                                userId);
                    }
                    break;
                case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
                    mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
                    break;
                case Intent.ACTION_PACKAGE_REMOVED:
                case Intent.ACTION_PACKAGE_CHANGED:
                    Uri data = intent.getData();
                    String ssp;
                    if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
                        boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);
                        boolean fullUninstall = removed &&
                                !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                        if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
                            forceStopPackageLocked(ssp, UserHandle.getAppId(
                                    intent.getIntExtra(Intent.EXTRA_UID, -1)),
                                    false, true, true, false, fullUninstall, userId,
                                    removed ? "pkg removed" : "pkg changed");
                        }
                        if (removed) {
                            sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
                                    new String[] {ssp}, userId);
                            if (fullUninstall) {
                                mAppOpsService.packageRemoved(
                                        intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);

                                // Remove all permissions granted from/to this package
                                removeUriPermissionsForPackageLocked(ssp, userId, true);

                                removeTasksByPackageNameLocked(ssp, userId);
                                mBatteryStatsService.notePackageUninstalled(ssp);
                            }
                        } else {
                            cleanupDisabledPackageComponentsLocked(ssp, userId,
                                    intent.getStringArrayExtra(
                                            Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
                        }
                    }
                    break;
            }
            break;
        case Intent.ACTION_PACKAGE_ADDED:
            // Special case for adding a package: by default turn on compatibility mode.
            Uri data = intent.getData();
            String ssp;
            if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
                final boolean replacing =
                        intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                mCompatModePackages.handlePackageAddedLocked(ssp, replacing);

                try {
                    ApplicationInfo ai = AppGlobals.getPackageManager().
                            getApplicationInfo(ssp, 0, 0);
                    mBatteryStatsService.notePackageInstalled(ssp,
                            ai != null ? ai.versionCode : 0);
                } catch (RemoteException e) {
                }
            }
            break;
        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;
    }
}

主要处理系统相关的广播,10个case

case Intent.ACTION_UID_REMOVED: //uid移除
case Intent.ACTION_PACKAGE_REMOVED: //package移除,
case Intent.ACTION_PACKAGE_CHANGED: //package改变
case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: //外部设备不可用时,强制停止所有波及的应用并清空cache数据
case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: //外部设备可用
case Intent.ACTION_PACKAGE_ADDED: //增加package,处于兼容考虑

case Intent.ACTION_TIMEZONE_CHANGED: //时区改变,通知所有运行中的进程
case Intent.ACTION_TIME_CHANGED: //时间改变,通知所有运行中的进程
case Intent.ACTION_CLEAR_DNS_CACHE: //dns缓存清空
case Proxy.PROXY_CHANGE_ACTION: //网络代理改变

step4:增加sticky广播

// Add to the sticky list if requested.
if (sticky) {
    if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
                callingPid, callingUid)
                != PackageManager.PERMISSION_GRANTED) {
          throw new SecurityException(msg);
    }
    if (requiredPermissions != null && requiredPermissions.length > 0) {
        return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
    }
    if (intent.getComponent() != null) {
        throw new SecurityException(
                    "Sticky broadcasts can't target a specific component");
    }
    // We use userId directly here, since the "all" target is maintained
    // as a separate set of sticky broadcasts.
    if (userId != UserHandle.USER_ALL) {
        // But first, if this is not a broadcast to all users, then
        // make sure it doesn't conflict with an existing broadcast to
        // all users.
        ...
    }
    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
    if (stickies == null) {
        stickies = new ArrayMap<>();
        mStickyBroadcasts.put(userId, stickies);
    }
    ArrayList<Intent> list = stickies.get(intent.getAction());
    if (list == null) {
        list = new ArrayList<>();
        stickies.put(intent.getAction(), list);
    }
    final int stickiesCount = list.size();
    int i;
    for (i = 0; i < stickiesCount; i++) {
        if (intent.filterEquals(list.get(i))) {
            // This sticky already exists, replace it.
            list.set(i, new Intent(intent));
            break;
        }
    }
    // 新的intent追加到list
    if (i >= stickiesCount) {
        list.add(new Intent(intent));
    }
}

简单说,就是如果sticky==true,则mStickyBroadcasts增加一条广播
step5:查询receivers和registeredReceivers

int[] users;
if (userId == UserHandle.USER_ALL) {
    // 广播给所有已启动用户
    // Caller wants broadcast to go to all started users.
    users = mStartedUserArray;
} else {
    // Caller wants broadcast to go to one specific user.
    users = new int[] {userId};
}

// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
         == 0) {
    // 根据intent查找静态注册的广播,已经按priority(默认值是0)从高到低排好顺序
    receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
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;
            }
            // 查询动态注册的广播,已经按priority从高到低排好顺序
            List<BroadcastFilter> registeredReceiversForUser =
                    mReceiverResolver.queryIntent(intent,
                            resolvedType, false, users[i]);
            if (registeredReceivers == null) {
                registeredReceivers = registeredReceiversForUser;
            } else if (registeredReceiversForUser != null) {
                registeredReceivers.addAll(registeredReceiversForUser);
            }
        }
    } else {
        // 查询动态注册的广播,已经按priority从高到低排好顺序
        registeredReceivers = mReceiverResolver.queryIntent(intent,
                resolvedType, false, userId);
    }
}

查询静态注册的广播

private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
        int callingUid, int[] users) {
    List<ResolveInfo> receivers = null;
    try {
        HashSet<ComponentName> 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;
            }
            // 调用PackageManagerService.queryIntentReceivers,获取AndroidManifest.xml声明的接收者信息
            List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
                    .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);
            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<newReceivers.size(); i++) {
                    ResolveInfo ri = newReceivers.get(i);
                    if ((ri.activityInfo.flags&ActivityInfo.FLAG_PRIMARY_USER_ONLY) != 0) {
                        // 移除FLAG_PRIMARY_USER_ONLY的receiver
                        newReceivers.remove(i);
                        i--;
                    }
                }
            }
            if (newReceivers != null && newReceivers.size() == 0) {
                newReceivers = null;
            }
            if (receivers == null) {
                receivers = newReceivers;
            } else if (newReceivers != null) {
                // We need to concatenate the additional receivers
                // found with what we have do far.  This would be easy,
                // but we also need to de-dup any receivers that are
                // singleUser.
                // 将所有用户的receiver整合到receivers
                ...
            }
        }
    } catch (RemoteException ex) {
        // pm is in same process, this will never happen.
    }
    return receivers;
}

step6:处理无序广播
如果ordered ==false,并且有动态注册的接收者,那么就会进入这个步骤。
在无序广播队列增加一条广播,然后遍历动态注册的接收者并通知。

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

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.
    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);
    if (!replaced) {
        // 详情参考[Broadcast(二)registerReceiver时sticky广播]
        queue.enqueueParallelBroadcastLocked(r);
        queue.scheduleBroadcastsLocked();
    }
    // 注意这2变量重置
    registeredReceivers = null;
    NR = 0;
}

step7:合并registeredReceivers到receivers
按priority从高到低,把动态注册的接收者和静态注册的接收者合并。相同的priority,动态注册的接收者优先

// Merge into one list.
int ir = 0;
if (receivers != null) {
    // A special case for PACKAGE_ADDED: do not allow the package
    // being added to see this broadcast.  This prevents them from
    // using this as a back door to get run as soon as they are
    // installed.  Maybe in the future we want to have a special install
    // broadcast or such for apps, but we'd like to deliberately make
    // this decision.
    // 防止应用监听该广播,在安装时直接运行
    String skipPackages[] = null;
    if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
            || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
            || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
        Uri data = intent.getData();
        if (data != null) {
            String pkgName = data.getSchemeSpecificPart();
            if (pkgName != null) {
                skipPackages = new String[] { pkgName };
            }
        }
    } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
        skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
    }
    // 将skipPackages相关的广播接收者从receivers中移除
    if (skipPackages != null && (skipPackages.length > 0)) {
        for (String skipPackage : skipPackages) {
            if (skipPackage != null) {
                int NT = receivers.size();
                for (int it=0; it<NT; it++) {
                    ResolveInfo curt = (ResolveInfo)receivers.get(it);
                    if (curt.activityInfo.packageName.equals(skipPackage)) {
                        receivers.remove(it);
                        it--;
                        NT--;
                    }
                }
            }
        }
    }

    int NT = receivers != null ? receivers.size() : 0;
    int it = 0;
    ResolveInfo curt = null;
    BroadcastFilter curr = null;
    // 如果处理了无序广播,那么NR=0
    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++;
}

step8:处理有序广播
如果你明白上面7步做了什么,那你应该知道当ordered==true或者有静态注册的接收者的时候(显然只有这2个条件至少满足一个,receivers.size()才会大于0)就会进入这个步骤。

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);
    boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
    if (!replaced) {
        // 见[Broadcast (四)有序广播和ANR]
        queue.enqueueOrderedBroadcastLocked(r);
        queue.scheduleBroadcastsLocked();
    }
}

参考引用

Gityuan Android Broadcast广播机制分析

相关文章

网友评论

    本文标题:Broadcast(三)sendBroadcast

    本文链接:https://www.haomeiwen.com/subject/wawyettx.html