Android O系统之后,Android系统对于广播的使用进行了限制,目的是避免广播滥用造成系统资源短缺,内存抖动和耗电等问题。
总之,大量的广播使用不仅耗电,还会影响系统性能。
关于大量发送广播为啥会耗电,大量app注册了静态广播(Manifest注册),当系统发送一个广播时,会唤醒多个app,需要启动app去接收广播,但是没有足够的内存让所有的app进行在缓存中处理,即内存有限,启动一个app后又kill掉另一个app进程。系统会在各个app进程之间跳动。
03-26 23:29:47.424 2663 2807 E ActivityManager: Sending non-protected broadcast android.media.extra.DSP_PCHIME from system 2663:system/1000 pkg android
03-26 23:29:47.424 2663 2807 E ActivityManager: java.lang.Throwable
03-26 23:29:47.424 2663 2807 E ActivityManager: at com.android.server.am.ActivityManagerService.checkBroadcastFromSystem(ActivityManagerService.java:21398)
系统对发送普通广播进行了检查,如果在系统中发送了未被保护的广播,就会出现上述警告。
1.如果是在系统里发送广播,即系统应用给系统发送广播,或者系统应用给系统应用发送广播,或者是系统给系统应用发,必须给广播加上保护,frameworks\base\core\res\AndroidManifest.xml中,添加:
<protected-broadcast android:name="android.media.extra.DSP_PCHIME" />
2.如果是普通app间的广播,对于广播发送者,必须在intent中指明包名;对于广播注册者,静态广播,exported为true的时候,必须加上permission限制,对于发送者的限制,如果发送者没有添加该permission权限(),则发送的广播,接收端是不会接收的。
//自定义权限
<permission android:name="io.github.mindjet.SEND_PERMISSION" />
<receiver android:name="MyBroadcastReceiver"
android:permission="io.github.mindjet.SEND_PERMISSION">
<intent-filter>
<action android:name="io.github.mindjet.JUST_BROADCAST" />
</intent-filter>
</receiver>
如果是动态广播,在filter中指定permission限制。当然要先在Manifest.xml中自定义。
//自定义权限
<permission android:name="io.github.mindjet.SEND_PERMISSION" />
ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.sendBroadcast
系统或者使用了android:sharedUserId="android.uid.system"的系统应用在调用Context接口的时候,必须指定发送广播的user。
Intent intent = new Intent();
intent.setAction(ACTION_TTS);
intent.putExtra(EXTRA_TTS, isGain ? 1 : 0); // 1: gain audio focus, 0: release audio focus
intent.addFlags(FLAG_RECEIVER_INCLUDE_BACKGROUND);
context.sendBroadcast(intent);
修改为:
context.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
如何判断应用是否为系统应用:
命令:ps -A
可以查看USER,root,system,media,bluetooth,u0_a13,u0_a46,u0_a28等等。
user为system的,即为系统应用。
当一个app为非系统应用时,缺使用了被保护的广播,就会报错:
java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.com.hsae.speech.service.action.ACTION_VR_TTS_SET_CHAN from pid=4315, uid=10068
at android.os.Parcel.createException(Parcel.java:1950)
at android.os.Parcel.readException(Parcel.java:1918)
at android.os.Parcel.readException(Parcel.java:1868)
at android.app.IActivityManager$Stub$Proxy.broadcastIntent(IActivityManager.java:3894)
总结,被保护的广播只能被系统使用。系统中的广播不需要指定包名,但是一定要加保护。