Android 6.0 权限申请源码解析

这篇文章主要从调用流程上分析一下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<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;
}

猜你喜欢

转载自blog.csdn.net/u010784887/article/details/79353189