Android(安卓)6.0 权限申请源码解析
这篇文章主要从调用流程上分析一下Android 6.0 权限检查和申请
权限管理涉及到四个基本API:
检查是否有权限
checkSelfPermission(String)
是否需要提示用户为什么需要这个权限
shouldShowRequestPermissionRationale (String permission)
请求权限:
requestPermissions (String[] permissions, int requestCode)
处理回调
onRequestPermissionsResult(int, String[], int[])
请求permission后系统调用该函数,通知app permission是被允许还是拒绝。
权限检查
权限检查使用的核心API就是checkSelfPermission
, 接下来我们从这个API开始分析权限检查
/frameworks/support/compat/java/android/support/v4/content/ContextCompat.java
public static int checkSelfPermission(@NonNull Context context, @NonNull String permission) { if (permission == null) { throw new IllegalArgumentException("permission is null"); } return context.checkPermission(permission, android.os.Process.myPid(), Process.myUid());}
从上面代码看出在检查权限的时候必须保证permission
不能为空,否则就会抛出异常, 接着调用ContextImpl
的checkPermission
方法,
`/frameworks/base/core/java/android/app/ContextImpl.java
public int checkPermission(String permission, int pid, int uid, IBinder callerToken) { if (permission == null) { throw new IllegalArgumentException("permission is null"); } try { return ActivityManager.getService().checkPermissionWithToken( permission, pid, uid, callerToken); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); }}
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public int checkPermissionWithToken(String permission, int pid, int uid, IBinder callerToken) { if (permission == null) { return PackageManager.PERMISSION_DENIED; } // We might be performing an operation on behalf of an indirect binder // invocation, e.g. via {@link #openContentUri}. Check and adjust the // client identity accordingly before proceeding. Identity tlsIdentity = sCallerIdentity.get(); if (tlsIdentity != null && tlsIdentity.token == callerToken) { Slog.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"+ tlsIdentity.pid + "," + tlsIdentity.uid + "}"); uid = tlsIdentity.uid; pid = tlsIdentity.pid; } return checkComponentPermission(permission, pid, uid, -1, true);}
int checkComponentPermission(String permission, int pid, int uid, int owningUid, boolean exported) { if (pid == MY_PID) { return PackageManager.PERMISSION_GRANTED; } return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported);}
/frameworks/base/core/java/android/app/ActivityManager.java
public static int checkComponentPermission(String permission, int uid, int owningUid, boolean exported) { // Root, system server get to do everything. final int appId = UserHandle.getAppId(uid); if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) { return PackageManager.PERMISSION_GRANTED; } // Isolated processes don't get any permissions. if (UserHandle.isIsolated(uid)) { return PackageManager.PERMISSION_DENIED; } // If there is a uid that owns whatever is being accessed, it has // blanket access to it regardless of the permissions it requires. if (owningUid >= 0 && UserHandle.isSameApp(uid, owningUid)) { return PackageManager.PERMISSION_GRANTED; } // If the target is not exported, then nobody else can get to it. if (!exported) { /* RuntimeException here = new RuntimeException("here"); here.fillInStackTrace(); Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid, here); */ return PackageManager.PERMISSION_DENIED; } if (permission == null) { return PackageManager.PERMISSION_GRANTED; } try { return AppGlobals.getPackageManager() .checkUidPermission(permission, uid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); }}
/frameworks/base/core/java/android/app/AppGlobals.java
public static IPackageManager getPackageManager() { return ActivityThread.getPackageManager();}
/frameworks/base/core/java/android/app/ActivityThread.java
public static IPackageManager getPackageManager() { if (sPackageManager != null) { //Slog.v("PackageManager", "returning cur default = " + sPackageManager); return sPackageManager; } IBinder b = ServiceManager.getService("package"); //Slog.v("PackageManager", "default service binder = " + b); sPackageManager = IPackageManager.Stub.asInterface(b); //Slog.v("PackageManager", "default service = " + sPackageManager); return sPackageManager;}
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public int checkUidPermission(String permName, int uid) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null; final boolean isUidInstantApp = getInstantAppPackageName(uid) != null; final int userId = UserHandle.getUserId(uid); if (!sUserManager.exists(userId)) { return PackageManager.PERMISSION_DENIED; } synchronized (mPackages) { Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); if (obj != null) { if (obj instanceof SharedUserSetting) { if (isCallerInstantApp) { return PackageManager.PERMISSION_DENIED; } } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (filterAppAccessLPr(ps, callingUid, callingUserId)) { return PackageManager.PERMISSION_DENIED; } } final SettingBase settingBase = (SettingBase) obj; final PermissionsState permissionsState = settingBase.getPermissionsState(); if (permissionsState.hasPermission(permName, userId)) { if (isUidInstantApp) { BasePermission bp = mSettings.mPermissions.get(permName); if (bp != null && bp.isInstant()) { return PackageManager.PERMISSION_GRANTED; } } else { return PackageManager.PERMISSION_GRANTED; } } // Special case: ACCESS_FINE_LOCATION permission includes ACCESS_COARSE_LOCATION if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) { return PackageManager.PERMISSION_GRANTED; } } else { ArraySet perms = mSystemPermissions.get(uid); if (perms != null) { if (perms.contains(permName)) { return PackageManager.PERMISSION_GRANTED; } if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && perms .contains(Manifest.permission.ACCESS_FINE_LOCATION)) { return PackageManager.PERMISSION_GRANTED; } } } } return PackageManager.PERMISSION_DENIED;}
/frameworks/base/core/java/android/content/pm/PackageManager.java
public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) { if (ArrayUtils.isEmpty(permissions)) { throw new IllegalArgumentException("permission cannot be null or empty"); } Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS); intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions); intent.setPackage(getPermissionControllerPackageName()); return intent;}
请求权限
GrantPermissionsActivity
<activity android:name=".permission.ui.GrantPermissionsActivity" android:configChanges="orientation|keyboardHidden|screenSize" android:excludeFromRecents="true" android:theme="@style/GrantPermissions" android:visibleToInstantApps="true"> <intent-filter android:priority="1"> <action android:name="android.content.pm.action.REQUEST_PERMISSIONS" /> <category android:name="android.intent.category.DEFAULT" /> intent-filter>activity>
/frameworks/base/core/java/android/app/Activity.java
public final void requestPermissions(@NonNull String[] permissions, int requestCode) { if (requestCode < 0) { throw new IllegalArgumentException("requestCode should be >= 0"); } if (mHasCurrentPermissionsRequest) { Log.w(TAG, "Can reqeust only one set of permissions at a time"); // Dispatch the callback with empty arrays which means a cancellation. onRequestPermissionsResult(requestCode, new String[0], new int[0]); return; } Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions); startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null); mHasCurrentPermissionsRequest = true;}
/frameworks/base/core/java/android/content/pm/PackageManager.java
public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) { if (ArrayUtils.isEmpty(permissions)) { throw new IllegalArgumentException("permission cannot be null or empty"); } Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS); intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions); intent.setPackage(getPermissionControllerPackageName()); return intent;}
更多相关文章
- 移动接口开发:JAVA判断是android还是ios 端请求
- Android工具类ImgUtil选择相机和系统相册
- Android(安卓)访问HTTP资源
- android studio 6.0以上动态申请权限的代码
- framework中自定义系统级权限
- 初探 Retrofit (入门)
- Android(安卓)使用HTTPClient调用Web请求(查询手机号码区域)
- xxx is not translated in yyy, zzz 的解决方法
- Android(安卓)权限表