> 技术文档 > Android14 普通应用registerReceiver注册广播报错One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be_android 14 registerreceiver

Android14 普通应用registerReceiver注册广播报错One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be_android 14 registerreceiver


Android14 普通应用registerReceiver注册广播报错One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified …

文章目录

  • Android14 普通应用registerReceiver注册广播报错One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified ...
    • 一、前言
    • 二、Google 对Android14 广播说明
    • 三、Android14 注册广播报错解决和分析
      • 1、报错示例和解决方法
      • 2、报错分析
    • 四、其他
      • 1、Android14 registerReceiver注册广播报错总结
      • 2、Android13 开始AndroidManifest.xml里面的四大组件都是要定义exported属性的,否则会编译报错
      • 3、Context.RECEIVER_EXPORTED 和Context.RECEIVER_NOT_EXPORTED作用?
      • 4、ActivityManagerService.java 的源码
  • 寄语:明天五一,劳动节快乐。

一、前言

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 broadcastsat 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 属性,否则会报错

      

即使是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\"); //自定义actionmFilter.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 。

寄语:明天五一,劳动节快乐。