这篇文章主要从调用流程上分析一下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();
}
}123456789101112
/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);
}12345678
/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<String> 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;
}
---------------------
作者:青雨xh
来源:CSDN
原文:https://blog.csdn.net/u010784887/article/details/79353189
版权声明:本文为博主原创文章,转载请附上博文链接!