这篇文章主要从调用流程上分析一下Android 6.0 权限检查和申请

权限管理涉及到四个基本API:

  1. 检查是否有权限
    checkSelfPermission(String)

  2. 是否需要提示用户为什么需要这个权限
    shouldShowRequestPermissionRationale (String permission)

  3. 请求权限:
    requestPermissions (String[] permissions, int requestCode)

  4. 处理回调
    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不能为空,否则就会抛出异常, 接着调用ContextImplcheckPermission方法,

`/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;}

更多相关文章

  1. 移动接口开发:JAVA判断是android还是ios 端请求
  2. Android工具类ImgUtil选择相机和系统相册
  3. Android(安卓)访问HTTP资源
  4. android studio 6.0以上动态申请权限的代码
  5. framework中自定义系统级权限
  6. 初探 Retrofit (入门)
  7. Android(安卓)使用HTTPClient调用Web请求(查询手机号码区域)
  8. xxx is not translated in yyy, zzz 的解决方法
  9. Android(安卓)权限表

随机推荐

  1. Android(安卓)主界面 九宫格 超灵活的配
  2. Android关闭输入法
  3. 【android】通话录音 -- service
  4. android隐藏底部虚拟键Navigation Bar实
  5. android里的service和content provider简
  6. android 读写文件
  7. android联系人多选
  8. mac安装adb
  9. Android上运行QT项目Necessitas的基本原
  10. 自定义View ----QQ5.0左边侧滑 + 动画