Android14 平凡应用registerReceiver注册广播报错One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified …
一、前言
Android14 平凡应用注册广播registerReceiver会报错,提示须要添加一个参数RECEIVER_EXPORTED 大概 RECEIVER_NOT_EXPORTED;体系framework大概体系应用是不会报这个错误的!
这个题目比力好办理,加一个参数就行,但是网上现在没有人对这个题目本日深入分析。
本文对registerReceiver报错举行分析,具体到哪个类哪行代码报错,
分析相识后对于体系其他相干报错能有个认识,大概有分析思绪。
RECEIVER_EXPORTED 体现外部应用范围,RECEIVER_NOT_EXPORTED 体现非外部应用范围,是否有作用?
二、Google 对Android14 广播阐明
阐明图片所示:
对于Android14 紧张阐明内容:
- For apps targeting Build.VERSION_CODES.UPSIDE_DOWN_CAKE, either RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED must be specified if the receiver is not being registered for system broadcasts or a SecurityException will be thrown. See registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int) to register a receiver with flags.
复制代码 Build.VERSION_CODES.UPSIDE_DOWN_CAKE 是Android14的名称,旋转蛋糕。
上面的英文大概意思:
- 对于以Build为 Android14的应用程序版本代码。
- 如果接收器没有为系统广播注册,或者将引发SecurityException,
- 则必须指定RECEIVER_EXPORTED或RECEIVE_NOT_EXPORTED。
- 请参阅registerReceiver(android.content.BroadcastReceiver,android.contant.IntentFilter,int)注册带有标志的接收器。
复制代码 相干网址:https://developer.android.google.cn/reference/android/content/Context
搜索 registerReceiver 就大概找到相干代码。
三、Android14 注册广播报错办理和分析
1、报错示例息争决方法
Android平凡应用的注册广播的代码:
- public class MainActivity extends AppCompatActivity {
- public void testBroadcast(View view) { //点击按钮,监听广播
- LogUtil.debug("");
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction("aa");
- //registerReceiver(mReceiver1, intentFilter);//在这里报错,如果没有try catch,会崩溃
-
- //解决方法:添加一个参数Context.RECEIVER_EXPORTED 或者ContextRECEIVER_NOT_EXPORTED
- //RECEIVER_EXPORTED 表示可以接收应用外部广播,ContextRECEIVER_NOT_EXPORTED 应用内部广播
- registerReceiver(mReceiver2, intentFilter, Context.RECEIVER_EXPORTED);
- }
- private BroadcastReceiver mReceiver1 = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- LogUtil.debug("action = " + action);
- }
- }
复制代码 上面代码就包罗了报错的代码示例和准确的写法。
在Android13大概更早的版本,上面的代码都是没有题目标;只有Android14 会报错。
2、报错分析
报错的堆栈信息:
报错最紧张相干日志 :
- Caused by: java.lang.SecurityException: com.demo.android14demo: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts
- at android.app.IActivityManager.registerReceiverWithFeature
- at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1852)
- at android.app.ContextImpl.registerReceiver(ContextImpl.java:1792)
- at android.app.ContextImpl.registerReceiver(ContextImpl.java:1780)
- at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:755)
- at com.demo.android14demo.MainActivity.testBroadcast(MainActivity.java:25)
- Caused by: android.os.RemoteException: Remote stack trace:
- at com.android.server.am.ActivityManagerService.registerReceiverWithFeature(ActivityManagerService.java:13927)
复制代码 从报错日志 看,MainActivity 注册广播后,ContextImpl.registerReceiverInternal 之后就报错了;
岂非报错信息在 ContextImpl.java 代码内里?
查察 ContextImpl.java 源码,并没有发现报错判定和相干关键字,以是是在往下的逻辑举行的报错。
着实就是 IActivityManager的实现类 ActivityManagerService 内里报错的:
release\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
- public Intent registerReceiverWithFeature(... IIntentReceiver receiver,
- IntentFilter filter, String permission, int userId, int flags) {
- //(1)判断是否设置了RECEIVER_EXPORTED 或者 RECEIVER_NOT_EXPORTED 的flag
- final boolean explicitExportStateDefined =
- (flags & (Context.RECEIVER_EXPORTED | Context.RECEIVER_NOT_EXPORTED)) != 0;
- //(2)动态接收广播,这里有判断 callingUid 应用等级,可能是系统应用没有报错的原因
- boolean requireExplicitFlagForDynamicReceivers = CompatChanges.isChangeEnabled(
- DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED, callingUid);
- if (!onlyProtectedBroadcasts) { //(3)非保护广播
- if (receiver == null && !explicitExportStateDefined) {
- // sticky broadcast, no flag specified (flag isn't required)
- flags |= Context.RECEIVER_EXPORTED;
- } else if (requireExplicitFlagForDynamicReceivers && !explicitExportStateDefined) {//(4)未设置flag和动态注册的广播---抛出异常
- throw new SecurityException(
- callerPackage + ": One of RECEIVER_EXPORTED or "
- + "RECEIVER_NOT_EXPORTED should be specified when a receiver "
- + "isn't being registered exclusively for system broadcasts");
- // Assume default behavior-- flag check is not enforced
- } else if (!requireExplicitFlagForDynamicReceivers && (
- (flags & Context.RECEIVER_NOT_EXPORTED) == 0)) {
- // Change is not enabled, assume exported unless otherwise specified.
- flags |= Context.RECEIVER_EXPORTED;
- }
- } else if ((flags & Context.RECEIVER_NOT_EXPORTED) == 0) {
- flags |= Context.RECEIVER_EXPORTED;
- }
- }
- }
复制代码 Android14注册广播报错是在 ActivityManagerService.java 内里一些列判定之后抛出非常报错的。
四、其他
1、Android14 registerReceiver注册广播报错总结
平凡应用须要再末了添加参数Context.RECEIVER_EXPORTED 大概 Context.RECEIVER_NOT_EXPORTED;
Android13 大概更低版本测试了并没有这个题目。
着实 Android13 的ActivityManagerService.java也是有大抵的流程,也会抛出谁人非常过程,
至于为啥没有报错,应该是具体判定内里的流程中,某个属性值的返回有差异以是没进入到抛出非常的过程。
2、Android13 开始AndroidManifest.xml内里的四大组件都是要界说exported属性的,否则会编译报错
activity、service、receiver、provider 这个四大组件都是必须设置 exported 属性,否则会报错
- <activity android:name=".MainActivity" android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
复制代码 纵然是Android Studio新建的项目,activity也要添加exported属性,否则编译错误。
3、Context.RECEIVER_EXPORTED 和Context.RECEIVER_NOT_EXPORTED作用?
从字面意思看:EXPORTED体现外部应用,NOT_EXPORTED体现非外部应用,即本应用内。
以是Context.RECEIVER_EXPORTED体现可以汲取外部的广播,
Context.RECEIVER_NOT_EXPORTED体现只能汲取应用内的广播?
从现在现实测试结果看,并非云云。
测试体系自动广播和app自界说广播,demo示例汲取广播,Action代码:
- IntentFilter mFilter = new IntentFilter();
- mFilter.addAction("action.mytest"); //自定义action
- mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);//网络变化广播
- mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); //wifi开关广播
- mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
- mFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
- mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
- registerReceiver(mReceiver1, mFilter, Context.RECEIVER_EXPORTED);
复制代码 监听广播不管设置Context.RECEIVER_EXPORTED还是Context.RECEIVER_NOT_EXPORTED,
都是可以汲取到网络厘革的广播和其他应用自界说发出的广播。
以是从现实来看:
- Context.RECEIVER_EXPORTED和Context.RECEIVER_NOT_EXPORTED其实没啥区别,效果是一样的。
复制代码 也就是说 Context.RECEIVER_NOT_EXPORTED 限定只继承应用内广播,并不会起作用。
但是最好还是都设置成 Context.RECEIVER_EXPORTED ,由于我看了 ActivityManagerService.java 的源码,
发现 Context.RECEIVER_NOT_EXPORTED 的情况有更多判定,以致有抛出非常的大概!
Android 14 ActivityManagerService.java:
- public class ActivityManagerService extends IActivityManager.Stub {
- ...
- public Intent registerReceiverWithFeature(...IntentFilter filter) {
- enforceNotIsolatedCaller("registerReceiver");
- ...
- }
- /* package */ void enforceNotIsolatedCaller(String caller) {
- if (UserHandle.isIsolated(Binder.getCallingUid())) { //Isolated 表示远程的,外部的
- throw new SecurityException("Isolated process not allowed to call " + caller);
- }
- }
- }
复制代码 从现在情况看,并不会抛出这个非常(外部应用不答应监听)。
Android13 ActivityManagerService.java代码中,
设置了Context.RECEIVER_NOT_EXPORTED 才会进入判定 enforceNotIsolatedCaller :
- if ((flags & Context.RECEIVER_NOT_EXPORTED) != 0) {
- enforceNotIsolatedCaller("registerReceiver");
- }
复制代码 着实上面代码只是分析了Android14报错,但是并没有分析Android13 的代码为啥不会报错,
具体是那边的差异,在源码中并未看到,有爱好的同砚本身可以举行研究看看。
4、ActivityManagerService.java 的源码
Android13 ActivityManagerService.java:
http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
Android14 ActivityManagerService.java:
http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
Android 体系其他代码也可以使用网址查察:http://aospxref.com 。
寄语:来日诰日五一,劳动节快乐。
|