• 某APK中使用了动态注册BroadcastReceiver,Launcher中动态加载此APK出现java.lang.SecurityException异常的解决方法


    在某APK中,通过如下方法动态注册了一个BroadcastReceiver,代码参考如下:

        @Override
        protected void onAttachedToWindow()
        {
            super.onAttachedToWindow();
            
            /* monitor time ticks, time changed, timezone */
            
            if (mIntentReceiver == null)
            {
                mIntentReceiver = new TimeChangedReceiver(this);
                IntentFilter filter = new IntentFilter();
                filter.addAction(Intent.ACTION_TIME_TICK);
                filter.addAction(Intent.ACTION_TIME_CHANGED);
                filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
                getContext().registerReceiver(mIntentReceiver, filter);

    Launcher要动态加载此APK(动态加载APK的目的和实现思路,参见我的这个文章: Launcher中动态加载其它APK中Activity的问题解决思路 ),

    出现了如下异常:

    09-05 19:05:55.033: E/AndroidRuntime(28637): java.lang.SecurityException: Given caller package com.zhao3546.time is not running in process ProcessRecord{41e74e50 28637:com.zhao3546.launcher/u0a10142}
    

    搜索了一下,很多人遇到过此类问题,但都没有提出解决方法,看来只能自己动手解决了。

    动态加载不行,那在AndroidManifest.xml试试静态加载BroadcastReceiver是否可以?

    如果是其它的BroadcastRecevier,验证了是ok的,但android.content.Intent.ACTION_TIME_TICK这个不行,Android的注释中已经明确说明了。

    String android.content.Intent.ACTION_TIME_TICK = "android.intent.action.TIME_TICK"
    
    Broadcast Action: The current time has changed. Sent every minute. You can not receive this through components declared in manifests, only by exlicitly registering for it with Context.registerReceiver(). 
    
    This is a protected intent that can only be sent by the system.
    

    难道就真的没有解决方法了?

    手头有一份Android源码,我根据“Given caller package”和“is not running in process ProcessRecord”这两个关键字全文搜索,

    想看看抛出这个异常的代码是在哪里搞出来的,在*.cpp,*.c*,*.java中搜索都没有找到,先放弃此方法吧。

    回头再来分析此异常,

    09-05 19:05:55.033: E/AndroidRuntime(28637): java.lang.SecurityException: Given caller package com.zhao3546.time is not running in process ProcessRecord{41e74e50 28637:com.zhao3546.launcher/u0a10142}
    

    我是在第三方APK中注册的BroadcastReceiver,这个APK在AndroidManifest.xml中声明的包名正好是“com.zhao3546.time”,而最终是和Launcher运行在同一个进程中的,这个进程对应的包名是“com.zhao3546.launcher”,因为Launcher先运行,而APK是被动态加载进来的。

    那是不是只要我注册BroadcastReceiver对应的包名只要是“com.zhao3546.launcher”,就可以解决问题了?

    Launcher中动态加载其它APK中Activity的问题解决思路,此文中已经通过将Launcher和第三方APK的AndroidManifest.xml中android:sharedUserId属性声明成为一致了,

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.zhao3546.time"
        android:sharedUserId="zhao3546.launcher"

    所以Launcher和第三方APK实际上是运行在同一个进程中的,那只要将Launcher的context对象传给这个APK,这个APK使用Launcher的context去注册BroadcastReceiver,是不是就可以解决问题了?

    第三方APK的com.zhao3546.time包下新增如下类,并实现有public static void setContext(Context context)这个静态方法:

    package com.zhao3546.time;
    
    import android.content.Context;
    
    public class ContextHolder
    {
        private static Context context = null;
        
        public static void setContext(Context context)
        {
            System.out.println("com.zhao3546.time.ContextHolder setContext");
            
            ContextHolder.context = context;
        }
        
        public static Context getContext()
        {
            System.out.println("com.zhao3546.time.ContextHolder getContext() context="
                    + context);
            
            return context;
        }
    }

    在Launcher代码中,通过反射机制动态地将launcher的context对象传到 com.zhao3546.time.ContextHolder 中,

        private void setContext2Plugin(ClassLoader pluginClassLoader,
                String pluginPackageName, Context launcherContext)
        {
            String className = pluginPackageName + ".ContextHolder";
            try
            {
                Method m = pluginClassLoader.loadClass(className)
                        .getMethod("setContext", Context.class);
                m.invoke(null, launcherContext);
            }
            catch (Exception e)
            {
                Log.w(TAG, "Fail to loadClass " + className + ", skip it", e);
            }
        }

    修改之前注册BroadcastReceiver的地方,通过ContextHolder()来注册BroadcastReceiver,把APK重新部署验证,问题解决。

    看似解决不了的问题,其实有时需要换个思路去尝试不同的方法,可能就会取得意想不到的效果。


  • 相关阅读:
    创造别人想要的东西(2)----创业15问
    创造别人想要的东西(1)----创业的本质
    有点迷茫
    普林斯顿大学算法公开课(1)----介绍
    工业控制系统信息安全与信息安全、功能安全的区别【转自工控工程网】
    十条概念区分信息安全与隐私保护【转自安全牛】
    NBT(NetBIOS Over TCP)名称解析概述
    SMB协议概述
    PCI DSS合规建设ASV扫描介绍
    信息安全等级测评师(初级 技术)
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3306220.html
Copyright © 2020-2023  润新知