文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android AOSP 6.0.1 registerReceiver广播注册流程分析

2022-06-06 13:23

关注

广播作为 Android 开发的四大组间之一,当我们发送广播以后,发生了什么?广播接收者最终如何收到了广播。

一、复盘广播的使用

在 Android 开发中使用广播分为三个步骤:

1.新建广播接收者 BroadcastReceiver;

2.注册广播接收者,分为静态和动态注册两种方式;

3.其他组间通过 sendBroadcast 向 BroadcastReceiver 发送广播,然后接收者处理。

我在分析流程中使用了动态注册的方式。在 Activity onResume 中注册,onPause 中取消注册。以下是创建 BroadcastReceiver 的代码。

class MainActivity : AppCompatActivity() {
    ......
    inner class MainActivityBroadcastReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (null != intent && intent.action == ACTION) {
                val str = intent.getStringExtra(VALUE_KEY)
                Log.d(TAG, "MainActivityBroadcastReceiver onReceive str=$str")
            }
        }
    }
    ......
}

接着在 Service 中调用 sendBroadcast。

二、广播接收者注册

广播接收者注册调用了 registerReceiver 方法。

class MainActivity : AppCompatActivity() {
    companion object {
        const val TAG = "MainActivity"
        const val ACTION = "com.demo.framework.ACTION"
        const val VALUE_KEY = "value_key"
    }
    private var mMainActivityBroadcastReceiver: MainActivityBroadcastReceiver = MainActivityBroadcastReceiver()
    ......
    override fun onResume() {
        super.onResume()
        val intentFilter = IntentFilter(ACTION)
        registerReceiver(mMainActivityBroadcastReceiver, intentFilter)
    }
    override fun onPause() {
        super.onPause()
        unregisterReceiver(mMainActivityBroadcastReceiver)
    }
    ......
}

registerReceiver 方法来自 ContextWrapper 类,回顾 Android AOSP 6.0.1 startService启动流程分析 一节可知,最终调用了 ContextImpl 类中的 registerReceiver 方法。registerReceiver 方法最后调用了 registerReceiverInternal 方法。

frameworks/base/core/java/android/content/ContextWrapper.java

public class ContextWrapper extends Context {
    ......
    @Override
    public Intent registerReceiver(
        BroadcastReceiver receiver, IntentFilter filter) {
        return mBase.registerReceiver(receiver, filter);
    }
    ......
}

frameworks/base/core/java/android/app/ContextImpl.java

class ContextImpl extends Context {
    ......
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return registerReceiver(receiver, filter, null, null);
    }
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
            String broadcastPermission, Handler scheduler) {
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext());
    }
    ......
    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context) {
        IIntentReceiver rd = null;
        if (receiver != null) {
            if (mPackageInfo != null && context != null) {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                // 进入此处分支
                rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            return ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);
        } catch (RemoteException e) {
            return null;
        }
    }    
}

熟悉的流程,在 registerReceiverInternal 方法中先获取 ActivityManagerProxy,然后调用它的 registerReceiver 方法。在 registerReceiverInternal 函数中主要用来构建 rd 局部变量,它是 IIntentReceiver 类型。rd 对象是经过 mPackageInfo 调用它的 getReceiverDispatcher 方法获取的。mPackageInfo 是一个 LoadedApk 类型。

frameworks/base/core/java/android/app/LoadedApk.java

public final class LoadedApk {
    ......
    public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
            Context context, Handler handler,
            Instrumentation instrumentation, boolean registered) {
        synchronized (mReceivers) {
            LoadedApk.ReceiverDispatcher rd = null;
            ArrayMap map = null;
            if (registered) {
                map = mReceivers.get(context);
                if (map != null) {
                    rd = map.get(r);
                }
            }
            if (rd == null) {
                rd = new ReceiverDispatcher(r, context, handler,
                        instrumentation, registered);
                if (registered) {
                    if (map == null) {
                        map = new ArrayMap();
                        mReceivers.put(context, map);
                    }
                    map.put(r, rd);
                }
            } else {
                rd.validate(context, handler);
            }
            rd.mForgotten = false;
            return rd.getIIntentReceiver();
        }
    }
    ......
}

以上一段代码并不难理解,mReceivers 是 ArrayMap<Context, ArrayMap> 类型的对象,它是以 Context 作为 key, ArrayMap 作为值的。这个 Context 其实就是对应的 Activity,而值是 BroadcastReceiver-ReceiverDispatcher 组成的键值对。同一个 Activity 里可以创建很多个 BroadcastReceiver,每个 BroadcastReceiver 都会对应一个 ReceiverDispatcher。没有注册过的 BroadcastReceiver,rd == null 分支会为 true,然后 new 一个 ReceiverDispatcher 对象。最后把键值对添加到 mReceivers 中。

frameworks/base/core/java/android/app/LoadedApk.java

public final class LoadedApk {
    ......
    static final class ReceiverDispatcher {
        final static class InnerReceiver extends IIntentReceiver.Stub {
            final WeakReference mDispatcher;
            final LoadedApk.ReceiverDispatcher mStrongRef;
            InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
                mDispatcher = new WeakReference(rd);
                mStrongRef = strong ? rd : null;
            }
            ......
        }
        ......
        final IIntentReceiver.Stub mIIntentReceiver;
        final BroadcastReceiver mReceiver;
        final Context mContext;
        final Handler mActivityThread;
        final Instrumentation mInstrumentation;
        final boolean mRegistered;
        final IntentReceiverLeaked mLocation;
        RuntimeException mUnregisterLocation;
        boolean mForgotten;
        ......
        ReceiverDispatcher(BroadcastReceiver receiver, Context context,
                Handler activityThread, Instrumentation instrumentation,
                boolean registered) {
            if (activityThread == null) {
                throw new NullPointerException("Handler must not be null");
            }
            mIIntentReceiver = new InnerReceiver(this, !registered);
            mReceiver = receiver;
            mContext = context;
            mActivityThread = activityThread;
            mInstrumentation = instrumentation;
            mRegistered = registered;
            mLocation = new IntentReceiverLeaked(null);
            mLocation.fillInStackTrace();
        }
        ......
        IIntentReceiver getIIntentReceiver() {
            return mIIntentReceiver;
        }
        ......
    }
    ......
}

最终要返回的 ReceiverDispatcher 对象,其中 mIIntentReceiver Field 是一个 InnerReceiver 类型,它的构造函数只是简单的为其 Field 赋值, mDispatcher 是一个弱引用对象。这里 mStrongRef 为 null。现在继续前面的思路,拿到 ActivityManagerProxy 对象,调用其 registerReceiver 方法。

frameworks/base/core/java/android/app/ActivityManagerNative.java

class ActivityManagerProxy implements IActivityManager
{
    ......
    public Intent registerReceiver(IApplicationThread caller, String packageName,
            IIntentReceiver receiver,
            IntentFilter filter, String perm, int userId) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(packageName);
        data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
        filter.writeToParcel(data, 0);
        data.writeString(perm);
        data.writeInt(userId);
        mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
        reply.readException();
        Intent intent = null;
        int haveIntent = reply.readInt();
        if (haveIntent != 0) {
            intent = Intent.CREATOR.createFromParcel(reply);
        }
        reply.recycle();
        data.recycle();
        return intent;
    }
    ......
}

通过 Binder 机制实际远程调用了 ActivityManagerService 中的同名 registerReceiver 方法。

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNative
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    ......
    // 跟踪已注册用于广播的所有 IIntentReceiver。 哈希键是接收者 IBinder,哈希值是 ReceiverList。
    final HashMap mRegisteredReceivers = new HashMap();    
    ......
    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
        enforceNotIsolatedCaller("registerReceiver");
        ArrayList stickyIntents = null;
        ProcessRecord callerApp = null;
        int callingUid;
        int callingPid;
        synchronized(this) {
            if (caller != null) {
                callerApp = getRecordForAppLocked(caller);
                ......
                // 给调用者 uid 和 pid 赋值
                callingUid = callerApp.info.uid;
                callingPid = callerApp.pid;
            } else {
                ......
            }
            userId = handleIncomingUser(callingPid, callingUid, userId,
                    true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
            // 获取 IntentFilter 中 action 迭代器
            Iterator actions = filter.actionsIterator();
            if (actions == null) {
                ArrayList noAction = new ArrayList(1);
                noAction.add(null);
                actions = noAction.iterator();
            }
            ......
        }
       ......
        synchronized (this) {
            if (callerApp != null && (callerApp.thread == null
                    || callerApp.thread.asBinder() != caller.asBinder())) {
                // Original caller already died
                return null;
            }
            // 1.获取 ReceiverList 对象
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                    // 2.添加 ReceiverList 对象到 ProcessRecord 对象的 receivers field
                    rl.app.receivers.add(rl);
                } else {
                    try {
                        receiver.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                // 3.添加 ReceiverList 对象到 mRegisteredReceivers
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            } else if (rl.uid != callingUid) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for uid " + callingUid
                        + " was previously registered for uid " + rl.uid);
            } else if (rl.pid != callingPid) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for pid " + callingPid
                        + " was previously registered for pid " + rl.pid);
            } else if (rl.userId != userId) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for user " + userId
                        + " was previously registered for user " + rl.userId);
            }
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId);
            // 4.ReceiverList 添加对应的 BroadcastFilter 
            rl.add(bf);
            if (!bf.debugCheck()) {
                Slog.w(TAG, "==> For Dynamic broadcast");
            }
            // 5.添加 BroadcastFilter 对象到 mReceiverResolver
            mReceiverResolver.addFilter(bf);
            ......
        }
    }
    ......
}

1.获取 ReceiverList 对象

mRegisteredReceivers 是一个 HashMap,现从这个 HashMap 中查找对应的 ReceiverList 是否存在,如果不存在就 new 一个 ReceiverList 对象。

frameworks/base/services/core/java/com/android/server/am/ReceiverList.java


final class ReceiverList extends ArrayList
        implements IBinder.DeathRecipient {
    final ActivityManagerService owner;
    public final IIntentReceiver receiver;
    public final ProcessRecord app;
    public final int pid;
    public final int uid;
    public final int userId;
    BroadcastRecord curBroadcast = null;
    boolean linkedToDeath = false;
    String stringName;
    ReceiverList(ActivityManagerService _owner, ProcessRecord _app,
            int _pid, int _uid, int _userId, IIntentReceiver _receiver) {
        owner = _owner;
        receiver = _receiver;
        app = _app;
        pid = _pid;
        uid = _uid;
        userId = _userId;
    }
    ......
}

2.添加 ReceiverList 对象到 ProcessRecord 对象的 receivers,实际上是一个 ArraySet 对象。

frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java

final class ProcessRecord {
    ......
    // 该进程注册的所有 IIntentReceivers。
    final ArraySet receivers = new ArraySet();
    ......
}

3.添加新创建的 ReceiverList 对象到 mRegisteredReceivers。

4.ReceiverList 添加对应的 BroadcastFilter。

frameworks/base/services/core/java/com/android/server/am/BroadcastFilter.java

final class BroadcastFilter extends IntentFilter {
    // 该过滤器所在列表的后向指针。
    final ReceiverList receiverList;
    final String packageName;
    final String requiredPermission;
    final int owningUid;
    final int owningUserId;
    BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
            String _packageName, String _requiredPermission, int _owningUid, int _userId) {
        super(_filter);
        receiverList = _receiverList;
        packageName = _packageName;
        requiredPermission = _requiredPermission;
        owningUid = _owningUid;
        owningUserId = _userId;
    }
    ......
}

5.添加 BroadcastFilter 对象到 mReceiverResolver,mReceiverResolver 是 IntentResolver 类型,它实现了 IntentResolver 抽象类。 其 addFilter 方法调用 mFilters 的 add 方法将 BroadcastFilter 添加到 ArraySet,这个 Set 代表所有已注册的过滤器。然后调用 register_intent_filter 和 register_mime_types 方法将 BroadcastFilter “分解”添加到各个容器中。

frameworks/base/services/core/java/com/android/server/IntentResolver.java

public abstract class IntentResolver {
    final private static String TAG = "IntentResolver";
    final private static boolean DEBUG = false;
    final private static boolean localLOGV = DEBUG || false;
    final private static boolean localVerificationLOGV = DEBUG || false;
    public void addFilter(F f) {
        if (localLOGV) {
            Slog.v(TAG, "Adding filter: " + f);
            f.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "      ");
            Slog.v(TAG, "    Building Lookup Maps:");
        }
        mFilters.add(f);
        int numS = register_intent_filter(f, f.schemesIterator(),
                mSchemeToFilter, "      Scheme: ");
        int numT = register_mime_types(f, "      Type: ");
        if (numS == 0 && numT == 0) {
            register_intent_filter(f, f.actionsIterator(),
                    mActionToFilter, "      Action: ");
        }
        if (numT != 0) {
            register_intent_filter(f, f.actionsIterator(),
                    mTypedActionToFilter, "      TypedAction: ");
        }
    }
    ......
    
    private final ArraySet mFilters = new ArraySet();
    
    private final ArrayMap mTypeToFilter = new ArrayMap();
    
    private final ArrayMap mBaseTypeToFilter = new ArrayMap();
    
    private final ArrayMap mWildTypeToFilter = new ArrayMap();
    
    private final ArrayMap mSchemeToFilter = new ArrayMap();
    
    private final ArrayMap mActionToFilter = new ArrayMap();
    
    private final ArrayMap mTypedActionToFilter = new ArrayMap();
}

打印一下 Log 查看调用过程。

07-10 01:58:24.078 2481-2481/com.demo.framework V/lhw: ContextImpl registerReceiver receiver=com.demo.framework.MainActivity$MainActivityBroadcastReceiver@8b54cc8,filter=android.content.IntentFilter@d46d161
07-10 01:58:24.078 2481-2481/com.demo.framework V/lhw: ContextImpl registerReceiverInternal receiver=com.demo.framework.MainActivity$MainActivityBroadcastReceiver@8b54cc8,userId=0,filter=android.content.IntentFilter@d46d161,broadcastPermission=null,context=com.demo.framework.MainActivity@5ad9602
07-10 01:58:24.078 2481-2481/com.demo.framework V/lhw: ContextImpl registerReceiverInternal mPackageInfo=android.app.LoadedApk@6f21ea2,scheduler=Handler (android.app.ActivityThread$H) {db89733}
07-10 01:58:24.078 2481-2481/com.demo.framework V/lhw: ActivityManagerProxy registerReceiver caller=android.app.ActivityThread$ApplicationThread@a1c1af0,packageName=com.demo.framework,receiver=android.app.LoadedApk$ReceiverDispatcher$InnerReceiver@cf8e486,filter=android.content.IntentFilter@d46d161,perm=null,userId=0
07-10 01:58:24.079 774-1388/system_process V/lhw: ActivityManagerService registerReceiver caller=android.app.ApplicationThreadProxy@6775003,callerPackage=com.demo.framework,receiver=android.content.IIntentReceiver$Stub$Proxy@802b80,filter=android.content.IntentFilter@8d3b5b9,permission=null,userId=0

最后画时序图作为总结。
registReceiver


作者:tyyj90


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯