Android7.0的静默安装失败问题研究
来源:互联网 发布:怎样申请新的淘宝账号 编辑:程序博客网 时间:2024/05/27 06:17
Android7.0的静默安装失败问题研究
最近遇到了在Android7.0上静默安装失败的问题。应用程序放到系统分区(/system/priv-app/)执行pm命令实现静默安装的方式在其他版本上都可以实现静默安装,在7.0上就安装失败,报这个异常:
java.lang.SecurityException: Permission Denial: runInstallCreate from pm command asks to run as user -1 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL
至于安装失败肯定是pm instll的执行逻辑做了修改,我们直接从Pm的源码开始研究。
网上关于7.0静默安装的资料确实很少,没办法了只能先去查看源码看为啥报这个异常了。手头上也没有7.0的源码,只能去下载了,20个G的源码下载了三个小时左右。7.0源码下载,清华大学Android源码镜像站,在解压的aosp目录下面执行repo sync即可得到完整目录。
看frameworks的,源码查看工具我用的是understand,全局搜索runInstallCreate from pm command asks to run as user没搜到,说明这句话是组装成的,所以拆开搜索,全局搜索asks to run as user,这次搜到了。该方法在UserController类中
int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll, int allowMode, String name, String callerPackage) { //测试发现这个getUserId的返回值应该为0 final int callingUserId = UserHandle.getUserId(callingUid); if (callingUserId == userId) { return userId; } // Note that we may be accessing mCurrentUserId outside of a lock... // shouldn't be a big deal, if this is being called outside // of a locked context there is intrinsically a race with // the value the caller will receive and someone else changing it. // We assume that USER_CURRENT_OR_SELF will use the current user; later // we will switch to the calling user if access to the current user fails. int targetUserId = unsafeConvertIncomingUserLocked(userId); if (callingUid != 0 && callingUid != SYSTEM_UID) { final boolean allow; if (mService.checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid, callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) { // If the caller has this permission, they always pass go. And collect $200. allow = true; } else if (allowMode == ALLOW_FULL_ONLY) { // We require full access, sucks to be you. allow = false; } else if (mService.checkComponentPermission(INTERACT_ACROSS_USERS, callingPid, callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) { // If the caller does not have either permission, they are always doomed. allow = false; } else if (allowMode == ALLOW_NON_FULL) { // We are blanket allowing non-full access, you lucky caller! allow = true; } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE) { // We may or may not allow this depending on whether the two users are // in the same profile. allow = isSameProfileGroup(callingUserId, targetUserId); } else { throw new IllegalArgumentException("Unknown mode: " + allowMode); } if (!allow) { if (userId == UserHandle.USER_CURRENT_OR_SELF) { // In this case, they would like to just execute as their // owner user instead of failing. targetUserId = callingUserId; } else { StringBuilder builder = new StringBuilder(128); builder.append("Permission Denial: "); builder.append(name); if (callerPackage != null) { builder.append(" from "); builder.append(callerPackage); } builder.append(" asks to run as user "); builder.append(userId); builder.append(" but is calling from user "); builder.append(UserHandle.getUserId(callingUid)); builder.append("; this requires "); builder.append(INTERACT_ACROSS_USERS_FULL); if (allowMode != ALLOW_FULL_ONLY) { builder.append(" or "); builder.append(INTERACT_ACROSS_USERS); } String msg = builder.toString(); Slog.w(TAG, msg); throw new SecurityException(msg); } } } if (!allowAll && targetUserId < 0) { throw new IllegalArgumentException( "Call does not support special user #" + targetUserId); } // Check shell permission if (callingUid == Process.SHELL_UID && targetUserId >= UserHandle.USER_SYSTEM) { if (hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId)) { throw new SecurityException("Shell does not have permission to access user " + targetUserId + "\n " + Debug.getCallers(3)); } } return targetUserId; }
研究发现callingUserId = UserHandle.getUserId(callingUid)的返回值为0,如果userId的值和callingUserId的值相同就不会执行下面的方法,也就不会抛出异常了。那我们就继续追踪看看userId是什么。这次我们Pm的源码开始,pm install就是在Pm这个类中执行的,调用的是runInstall方法,runInstall的源码就不贴出来了,我们这里只关心两个方法
final InstallParams params = makeInstallParams();和final int sessionId = doCreateSession(params.sessionParams,params.installerPackageName, params.userId);
makeInstallParams的源码:该方法是解析命令中的参数的,这里只看主要的
private InstallParams makeInstallParams() { final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL); final InstallParams params = new InstallParams(); params.sessionParams = sessionParams; String opt; while ((opt = nextOption()) != null) { switch (opt) { .... case "-i": params.installerPackageName = nextArg(); if (params.installerPackageName == null) { throw new IllegalArgumentException("Missing installer package"); } break; ... ... case "--user": params.userId = UserHandle.parseUserArg(nextOptionData()); break; .... default: throw new IllegalArgumentException("Unknown option " + opt); } } return params; }
doCreateSession方法中回去调用userId = translateUserId(userId, “runInstallCreate”);
translateUserId中回去调用ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, logContext, “pm command”);看ActivityManagerService中的handleIncomingUser方法
@Override public int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll, boolean requireFull, String name, String callerPackage) { return mUserController.handleIncomingUser(callingPid, callingUid, userId, allowAll, requireFull ? ALLOW_FULL_ONLY : ALLOW_NON_FULL, name, callerPackage); }
找到了,就是在这里调用的mUserController.handleIncomingUser方法,抛出的异常。这个userId就是我们调用doCreateSession方法传入的params.userId,我们继续看makeInstallParams的源码,params.userId是–user指定的。
我们在代码中执行Runtime.getRuntime().exec(“pm install –user 0 apkpath”),log又抛出一个空指针异常。
调用链:doCreateSession—>mInstaller.createSession(params, installerPackageName, userId)–>createSessionInternal–>mAppOps.checkPackage(callingUid, installerPackageName);
checkPackageName会判断installerPackageName是不是为空,为空就抛出异常。installerPackageNameye也是调用doCreateSession时传入params.installerPackageName 该值也是pm命令指定的,为当前调用执行pm命令的包名
所以修改pm命令为:Runtime.getRuntime().exec(“pm install -i 包名 –user 0 apkpath”),静默安装成功!!!
到这里就结束了,后面的源码没有贴出来,但是写出了调用过程,大家可以自己去追踪一下源码!
- Android7.0的静默安装失败问题研究
- android7.0应用安装失败的问题
- Android真正的静默安装(android7.0静默安装)
- Android7.0 MTK方案 静默安装和卸载
- Android7.0打包安装问题
- swap size为0引起的ORACLE静默安装检测失败
- 安卓中静默安装出现的权限问题
- 静默安装时,权限问题的处理
- Android7.0升级安装APK,FileUriExposedException问题
- Android7.0拍照失败FileUriExposedException
- Android7.0拍照失败FileUriExposedException异常的解决
- PopupWindow的showAsDropDown位置问题 Android7.0
- Android7.0反射类找不到的问题
- Android7.0的相机相册遇到问题
- Android7.0 popupWindow显示位置的问题
- Android7.0反射类找不到的问题
- rhel7.0下oracle11gr2的静默安装
- InstallShield12的静默安装
- Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1
- 今天入门啦
- Asp.net mvc 知多少(六)
- Socket通信 客户端和服务器端的通信 客户端
- myeclipse xml自动提示怎么配置
- Android7.0的静默安装失败问题研究
- 如何导入项目到MyEclipse?(版本10.7.1)
- 1: Remove Duplicates from Sorted Array
- 冈萨雷斯《数字图像处理》学习笔记一:绪论
- Nginx的异步非阻塞
- android wifi开发
- IAP支付
- 理解HTTP协议
- 机器学习和深度学习计划