Android P添加自定义系统广播

前言

最近有一个需求,要求实现20秒无操作就跳转到一个界面,因为开发初期没有添加BaseActivity,所以再想在APP中实现事件监听就比较难修改。

正文

查阅资料发现可以在framework的ViewRootImpl类的内部类WindowInputEventReceiveronInputEvent方法中添加广播实现,但是添加后发现会有Sending non-protected broadcast的报错,于是又查阅资料,将添加的广播在AndroidManifest.xml中注册为protected-broadcast:

<protected-broadcast android:name="android.intent.action.xxx" />

添加了之后,又发现非系统应用再点击任何按键时都会闪退,查看报错以及查阅资料发现,protected-broadcast是为了防止三方垃圾应用也发送这些广播,会进行权限检查,不通过时,会抛出一个异常,具体代码在ActivityManagerService中的checkBroadcastFromSystem方法中:

private void checkBroadcastFromSystem(Intent intent, ProcessRecord callerApp,
            String callerPackage, int callingUid, boolean isProtectedBroadcast, List receivers) {
        if ((intent.getFlags() & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
            // Don't yell about broadcasts sent via shell
            return;
        }

        final String action = intent.getAction();
        if (isProtectedBroadcast
                || Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
                ******
                || AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION.equals(action)) {
            // Broadcast is either protected, or it's a public action that
            // we've relaxed, so it's fine for system internals to send.
            return;
        }

        ******
        
        if (callerApp != null) {
            Log.wtf(TAG, "Sending non-protected broadcast " + action
                            + " from system " + callerApp.toShortString() + " pkg " + callerPackage,
                    new Throwable());
        } else {
            Log.wtf(TAG, "Sending non-protected broadcast " + action
                            + " from system uid " + UserHandle.formatUid(callingUid)
                            + " pkg " + callerPackage,
                    new Throwable());
        }
    }

于是在上面的判断中加入自定义的系统广播,但是验证发现还是会报错:

java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.xxx from pid=11072, uid=10013

根据报错信息,找到了对应的代码(ActivityManagerService):

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) {
            ******
            if (!isCallerSystem) {
	            if (isProtectedBroadcast) {
	                String msg = "Permission Denial: not allowed to send broadcast "
	                        + action + " from pid="
	                        + callingPid + ", uid=" + callingUid;
	                Slog.w(TAG, msg);
	                throw new SecurityException(msg);
	            }
	            ******
	       }
	       ******
}

于是又在isProtectedBroadcast的判断中添加了新增的自定义广播的判断,再验证就没问题了。

综上,要添加一个自定义的系统广播,首先要在frameworks\base\core\res\AndroidManifest.xml中注册成protected-broadcast,然后需要在ActivityManagerService中添加判断;这样才能在framework中使用这个广播。

最后,可以根据具体需求,看是否要添加到Intent类中作为常量,比如需求提供给第三方SDK时,可以添加一下。

注意:这种方式添加的自定义系统广播,任何应用都可以发送相同的广播(与protected-broadcast设计初衷背道而驰),所以不适用于非常精准和严谨的情况。

后记

单纯是20秒无操作,也许还有其它的实现思路,这里结合自己查到的资料提一下,因为InputEvent的直接子类只有MotionEvent以及KeyEvent,对应了按键输入和“点触”设备输入,所以也可以利用这两点来解决,可能会稍微复杂一点,工作要注意效率,故未深入研究,这里说出思路供有相似需求的小伙伴参考:

  • PointerEventDispatcher类及PointerEventListener接口可以实现触摸以及鼠标点击等touch事件的监听,但是也需要在framework做修改
  • KeyEvent老生常谈,可以在PhoneWindowManager做处理
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值