Launcher中动态加载APK出现java.lang.SecurityException异常的解决方法(二)
来源:互联网 发布:greenplum数据集市 编辑:程序博客网 时间:2024/06/05 05:04
在Launcher中动态加载APK,之前有出现过java.lang.SecurityException的异常,
具体的异常信息如下:
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,Launcher中动态加载此APK出现java.lang.SecurityException异常的解决方法》。
这两天我们基于Baidu的APK实现了一个简单的地图应用,在将其动态加载到Launcher中时,发现也遇到了同样的问题,之前的解决虽然可以解决此异常,
但是Baidu地图无法正常显示,看来只能尝试如何解决此异常了。
再重新根据“Given caller package” 关键字,搜索Android的源码,在 frameworks\base\services\java\com\android\server\am 下的 ActivityManagerService.java 中找到了这个异常出现的位置:
public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { enforceNotIsolatedCaller("registerReceiver"); int callingUid; int callingPid; synchronized(this) { ProcessRecord callerApp = null; if (caller != null) { callerApp = getRecordForAppLocked(caller); if (callerApp == null) { throw new SecurityException( "Unable to find app for caller " + caller + " (pid=" + Binder.getCallingPid() + ") when registering receiver " + receiver); } if (callerApp.info.uid != Process.SYSTEM_UID && !callerApp.pkgList.contains(callerPackage)) {------------ throw new SecurityException("Given caller package " + callerPackage------------ + " is not running in process " + callerApp); } callingUid = callerApp.info.uid; callingPid = callerApp.pid; } else { callerPackage = null; callingUid = Binder.getCallingUid(); callingPid = Binder.getCallingPid(); }
根据代码分析,是因为发起此请求的应用所在的进程不是系统进程,并且此进程的包名列表中,并不包含要注册的receiver对应的package名称。
根据此条件“callerApp.info.uid != Process.SYSTEM_UID && !callerApp.pkgList.contains(callerPackage)” ,要解决此问题,可以有两个方法:
1、发起调用方的进程是系统进程;
2、将动态加载的APK的包名发起此请求的进程的pkgList中;
第一个解决方法,对于普通应用来说,基本上实现不了;第二个解决方法,可以进一步研究Android源码找一下解决方法。
callerApp这个对象的类型是ProcessRecord类型的,此类中有如下方法:
/* * Return true if package has been added false if not */ public boolean addPackage(String pkg) { if (!pkgList.contains(pkg)) { pkgList.add(pkg); return true; } return false; }
只要我们在应用代码中,能获取到ProcessRecord对象即可,ActivityManagerService类有如下方法可以获取到ProcessRecord,但是package的方法,
final ProcessRecord getRecordForAppLocked( IApplicationThread thread) { if (thread == null) { return null; } int appIndex = getLRURecordIndexForAppLocked(thread); return appIndex >= 0 ? mLruProcesses.get(appIndex) : null; }
ActivityManagerService类的继承关系如下:
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallbackpublic abstract class ActivityManagerNative extends Binder implements IActivityManager
应用层要访问ActivityManagerService,必须要通过 ActivityManagerNative.getDefault() 来进行,得到的是一个IActivityManager的对象。
这个对象本身并不对外暴露getRecordForAppLocked()方法,即使暴露,而ProcessRecord类也是Package级别的类,只有同一个包下的类才能访问得到。
看来要走这条路,要对原生代码要做很大的改动才行。
比如Activity.java中要启动一个Activity,可以使用startActivityForResult方法,
public void startActivityForResult(Intent intent, int requestCode, Bundle options) { if (mParent == null) { Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);
然后又调用了Instrumentation的execStartActivity()方法,
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Fragment target, ...... try { intent.setAllowFds(false); intent.migrateExtraStreamToClipData(); int result = ActivityManagerNative.getDefault() .startActivity(whoThread, intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mWho : null, requestCode, 0, null, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { } return null;
既然如下,要让此异常不出现,必须要修改framework的代码了,那直接直接注释掉如下代码看看效果:
/* if (callerApp.info.uid != Process.SYSTEM_UID && !callerApp.pkgList.contains(callerPackage)) { throw new SecurityException("Given caller package " + callerPackage + " is not running in process " + callerApp); } */
注释此段代码后,在Android代码的源码目录下,执行如下命令,编译出services.jar
mmm frameworks/base/services/java/
使用此jar替换 /system/framework 下的同名文件,重启Android,再测试,问题解决。
注意:services.jar是系统级的文件,要正常替换,请参考:《做自己的Android ROM,屏蔽对framework中的系统APK的签名检查》
- Launcher中动态加载APK出现java.lang.SecurityException异常的解决方法(二)
- 某APK中使用了动态注册BroadcastReceiver,Launcher中动态加载此APK出现java.lang.SecurityException异常的解决方法
- java.lang.SecurityException异常
- IDEA使用sbt打包运行出现java.lang.securityException的解决方法
- java.lang.SecurityException: Permission Denial: opening provider的解决方法
- SecurityException: java.lang.SecurityException
- 代码实现拨打电话的功能后,用真机调试时,出现异常:java.lang.SecurityException: Permission Denial...
- Launcher中动态加载其它APK中Activity的问题解决思路
- Java 出现java.lang.SecurityException: Prohibited package name:java.my 错误解决方法
- android 出现java.lang.SecurityException:requires READ_PHONE_STATE
- 出现异常java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.
- ActivityGroup中错误 java.lang.SecurityException的处理
- android中java.lang.NoClassDefFoundError异常的解决方法之一
- Android apk动态加载机制的研究(二)
- Android apk动态加载机制的研究(二)
- Android问题分享:DownloadManager基本用法及发生java.lang.SecurityException异常的解决办法
- 【我的Android进阶之旅】Android 7.0报异常:java.lang.SecurityException: COLUMN_LOCAL_FILENAME is deprecated;
- <Gradle> java.lang.SecurityException的解决办法
- 代理模式【Proxy Pattern】
- Ruby使用HTTP协议发送请求
- Java二分查找实现
- jpeg压缩解压缩简介
- iOS 6常用控件之UITextField
- Launcher中动态加载APK出现java.lang.SecurityException异常的解决方法(二)
- MyEclipse 10 中增加svn插件
- UITableView的用法
- .NET发烧者的呐喊
- google map api key申请
- 函数传递的参数是原参数的副本
- vim相关命令
- c++对象和内存
- 记录学习旅途中的问题 ——AUTOCAD