PKMS(二)

作者: 涛涛123759 | 来源:发表于2021-10-26 17:05 被阅读0次

    Android知识总结

    一、权限的分类

    系统权限分为两类:正常权限危险权限

    • 正常权限不会直接给用户隐私权带来风险。如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。
    • 危险权限会授予应用访问用户机密数据的权限。如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。如果您列出了危险权限,则用户必须明确批准您的应用使用这些权限。

    那么,那些是危险权限呢,为什么是危险权限呢?

      <!-- 权限组:CALENDAR == 日历读取的权限申请 -->
      <uses-permission android:name="android.permission.READ_CALENDAR" />
      <uses-permission android:name="android.permission.WRITE_CALENDAR" />
      <!-- 权限组:CAMERA == 相机打开的权限申请 -->
      <uses-permission android:name="android.permission.CAMERA" />
      <!-- 权限组:CONTACTS == 联系人通讯录信息获取/写入的权限申请 -->
      <uses-permission android:name="android.permission.READ_CONTACTS" />
      <uses-permission android:name="android.permission.WRITE_CONTACTS" />
      <!-- 权限组:LOCATION == 位置相关的权限申请 -->
      <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
      <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
      <!-- 权限组:PHONE == 拨号相关的权限申请 -->
      <uses-permission android:name="android.permission.CALL_PHONE" />
      <uses-permission android:name="android.permission.READ_PHONE_STATE" />
      <!-- 权限组:SMS == 短信相关的权限申请 -->
      <uses-permission android:name="android.permission.SEND_SMS" />
      <uses-permission android:name="android.permission.READ_SMS" />
      <!-- 权限组:STORAGE == 读取存储相关的权限申请 -->
      <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    

    二、权限申请代码

    <!-- 第一步:在AndroidManifest.xml中添加所需权限。 -->
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    
    public class MainActivity extends AppCompatActivity {
    
        private static final String TAG = MainActivity.class.getSimpleName();
        private static final int MY_PERMISSIONS_REQUEST_READ_CONTACTS = 999;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // 申请 危险权限
            requestPermission();
        }
    
        // 第二步:封装了一个requestPermission方法来动态检查和申请权限
        private void requestPermission() {
    
            Log.i(TAG, "requestPermission");
    
            //先检查之前有没有申请过这个READ_CONTACTS权限,如果么有申请过,才申请
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
                Log.i(TAG, "checkSelfPermission");
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS)) {
                    Log.i(TAG, "shouldShowRequestPermissionRationale 原来你个货,之前拒绝过申请权限");
                    // 申请 联系人读取权限
                    ActivityCompat.requestPermissions(this,
                            new String[]{Manifest.permission.READ_CONTACTS},
                            MY_PERMISSIONS_REQUEST_READ_CONTACTS);
    
                } else {
                    Log.i(TAG, "requestPermissions 之前没有拒绝过,正常的申请权限");
                    // No explanation needed, we can request the permission.
                    // 申请 联系人读取权限
                    ActivityCompat.requestPermissions(this,
                            new String[]{Manifest.permission.READ_CONTACTS},
                            MY_PERMISSIONS_REQUEST_READ_CONTACTS);
                }
            }
        }
    
        // 第三步:重写onRequestPermissionsResult方法根据用户的不同选择做出响应。
        @Override
        public void onRequestPermissionsResult(int requestCode,
                                               String permissions[], int[] grantResults) {
            switch (requestCode) {
                case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
                    // If request is cancelled, the result arrays are empty.
                    if (grantResults.length > 0
                            && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        Log.i(TAG, "onRequestPermissionsResult granted");.
                    } else {
                        Log.i(TAG, "onRequestPermissionsResult denied");
                        showWaringDialog();
                    }
                    return;
                }
            }
        }
    
        // 如果点击 拒绝,就会弹出这个 提示框
        private void showWaringDialog() {
            new AlertDialog.Builder(this)
                    .setTitle("警告!")
                    .setMessage("请前往设置->应用->PermissionDemo->权限中打开相关权限,否则功能无法正常运行!")
                    .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            // 一般情况下如果用户不授权的话,功能是无法运行的,做退出处理
                            finish();
                        }
                    }).show();
        }
        
    }
    
    运行结果

    2.1、requestPermissions源码整体

    总结上面的几个 核心函数

    //检查应用是否具有某个危险权限。
    //如果应用具有此权限,方法将返回 PackageManager.PERMISSION_GRANTED,并且应用可以继续操作。
    //如果应用不具有此权限,方法将返回 PackageManager.PERMISSION_DENIED,且应用必须明确向用户要求权限
    checkSelfPermission(@NonNull String permission)
    
    //应用可以通过这个方法动态申请权限,调用后会弹出一个对话框提示用户授权所申请的权限。
    requestPermissions(@NonNull String[] permissions, int requestCode)
    
    //处理结果回调
    onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
    
    //是否需要显示UI界面提示用户为什么需要这个权限
    //如果应用之前请求过此权限但用户拒绝了请求,此方法将返回 true。如果用户在过去拒绝了权限请求,并在
    //权限请求系统对话框中选择了 Don't ask again 选项,此方法将返回 false。如果设备规范禁止应用具有该权限,此方法也会返回 false
    ActivityCompat.shouldShowRequestPermissionRationale(@NonNull String permission)
    

    三、权限申请源码流程

    权限申请整体流程图

    重申请权限开始

     ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS);
    

    调用ActivityCompat中的requestPermissions方法

        public static void requestPermissions(final @NonNull Activity activity,
                final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode) {
            if (sDelegate != null
                    && sDelegate.requestPermissions(activity, permissions, requestCode)) {
                // Delegate has handled the permission request.
                return;
            }
            //API 23以上执行
            if (Build.VERSION.SDK_INT >= 23) {
                if (activity instanceof RequestPermissionsRequestCodeValidator) {
                    ((RequestPermissionsRequestCodeValidator) activity)
                            .validateRequestPermissionsRequestCode(requestCode);
                }
                //权限申请
                activity.requestPermissions(permissions, requestCode);
            } else if (activity instanceof OnRequestPermissionsResultCallback) {
                Handler handler = new Handler(Looper.getMainLooper());
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        final int[] grantResults = new int[permissions.length];
    
                        PackageManager packageManager = activity.getPackageManager();
                        String packageName = activity.getPackageName();
    
                        final int permissionCount = permissions.length;
                        for (int i = 0; i < permissionCount; i++) {
                            grantResults[i] = packageManager.checkPermission(
                                    permissions[i], packageName);
                        }
    
                        ((OnRequestPermissionsResultCallback) activity).onRequestPermissionsResult(
                                requestCode, permissions, grantResults);
                    }
                });
            }
        }
    

    执行ActivityrequestPermissions

        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 request only one set of permissions at a time");
                // 返回结果
                onRequestPermissionsResult(requestCode, new String[0], new int[0]);
                return;
            }
            //从 PackageManager 获取 Intent
            Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
            startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
            mHasCurrentPermissionsRequest = true;
        }
    

    执行PackageManager获取Intent

        public static final String ACTION_REQUEST_PERMISSIONS =
                "android.content.pm.action.REQUEST_PERMISSIONS";
    
        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;
        }
    

    接下来我们可以在AndroidManifest.xml中找的系统的Activity


    <activity android:name=".permission.ui.GrantPermissionsActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:excludeFromRecents="true"
            android:theme="@style/GrantPermissions"
            android:visibleToInstantApps="true">
         
         <!-- 那么我们就根据”android.content.pm.action.REQUEST_PERMISSIONS“ 
    表示动作来找到需要激活的某个Activity不就行了 -->
            <intent-filter android:priority="1">
              <action
    android:name="android.content.pm.action.REQUEST_PERMISSIONS" />
              <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    

    接下来我们就对GrantPermissionsActivity进行分析。
    原来GrantPermissionsActivity也就是我们常见的权限申请界面,用户可以根据提示选择是否授权给应用相应的权限。用户操作后的结果会通过回调GrantPermissionsActivity的onPermissionGrantResult方法返回。在onPermissionGrantResult方法中会根据返回结果去决定是走授予权限还是撤销权限流程,然后会更新授权结果,最后返回结果并结束自己:

      @Override
      public void onPermissionGrantResult(String name, boolean granted, boolean doNotAskAgain) {
        GroupState groupState = mRequestGrantPermissionGroups.get(name);
        if (groupState.mGroup != null) {
          if (granted) {
            // 授予权限
            groupState.mGroup.grantRuntimePermissions(doNotAskAgain,
                groupState.affectedPermissions);
            groupState.mState = GroupState.STATE_ALLOWED;
         } else {
            // 撤销权限
            groupState.mGroup.revokeRuntimePermissions(doNotAskAgain,
                groupState.affectedPermissions);
            groupState.mState = GroupState.STATE_DENIED;
            int numRequestedPermissions = mRequestedPermissions.length;
            for (int i = 0; i < numRequestedPermissions; i++) {
              String permission = mRequestedPermissions[i];
              if (groupState.mGroup.hasPermission(permission)) {
                EventLogger.logPermissionDenied(this, permission,
                    mAppPermissions.getPackageInfo().packageName);
             }
           }
         }
          // 更新授权结果
          updateGrantResults(groupState.mGroup);
       }
        if (!showNextPermissionGroupGrantRequest()) {
          // 返回授权结果并结束自己
          setResultAndFinish();
       }
     }
    

    接下来继续跟踪AppPermissionGroup.grantRuntimePermissions方法分析授权流程。AppPermissionGroup.grantRuntimePermissions方法中会判断targetSdkVersion是否大于LOLLIPOP_MR1(22),如果大于则做动态权限申请处理。

    
        public boolean grantRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) {
            final int uid = mPackageInfo.applicationInfo.uid;
    
            for (Permission permission : mPermissions.values()) {
                if (mAppSupportsRuntimePermissions) {
                    //  在Android 5.1后,就需要支持动态申请权限啦
                    // LOLLIPOP_MR1之后版本,支持动态权限申请
                    // Do not touch permissions fixed by the system.
                    if (permission.isSystemFixed()) {
                        return false;
                    }
                    if (permission.hasAppOp() && !permission.isAppOpAllowed()) {
                        permission.setAppOpAllowed(true);
                        mAppOps.setUidMode(permission.getAppOp(), uid,
                                AppOpsManager.MODE_ALLOWED);
                    }
                    if (!permission.isGranted()) {
                        permission.setGranted(true);
                        // 这里很关键, 通过mPackageManager.grantRuntimePermission 跨进程到 PKMS
                        // 下面我们就分析这个操作了哦,注意哦
                        // 熟悉Android源码的同学都知道XXXManager只是一个辅助类,其真正提供服
                        //务的都是XXXManagerService,所以 直接跳转PackageManagerService中的grantRuntimePermission方法。
                        mPackageManager.grantRuntimePermission(mPackageInfo.packageName, permission.getName(), mUserHandle);
                    }
    
                    if (!fixedByTheUser) {
                        if (permission.isUserFixed() || permission.isUserSet()) {
                            permission.setUserFixed(false);
                            permission.setUserSet(false);
                            mPackageManager.updatePermissionFlags(permission.getName(),
                                    mPackageInfo.packageName,
                                    PackageManager.FLAG_PERMISSION_USER_FIXED
                                    PackageManager.FLAG_PERMISSION_USER_SET, 0, mUserHandle);
                        }
                    }
                } else {
                    // LOLLIPOP_MR1之前版本,不支持动态权限申请
                    ...
                }
            }
            return true;
        }
    

    接下来看PackageManagerServicegrantRuntimePermission方法,涉及跨进程通信

        private final PermissionManagerInternal mPermissionManager;
    
        public void grantRuntimePermission(String packageName, String permName, final int userId) {
            mPermissionManager.grantRuntimePermission(permName, packageName, false /*overridePolicy*/,
                    getCallingUid(), userId, mPermissionCallback);
        }
    

    PermissionManagerService中实现PermissionManagerInternalgrantRuntimePermission方法

       private class PermissionManagerInternalImpl extends PermissionManagerInternal {
            public void grantRuntimePermission(String permName, String packageName,
                    boolean overridePolicy, int callingUid, int userId,
                    PermissionCallback callback) {
                PermissionManagerService.this.grantRuntimePermission(
                        permName, packageName, overridePolicy, callingUid, userId, callback);
            }
    }
    
        private void grantRuntimePermission(String permName, String packageName, boolean overridePolicy,
                int callingUid, final int userId, PermissionCallback callback) {
            // 检查用户是否存在
            if (!mUserManagerInt.exists(userId)) {
                Log.e(TAG, "No such user:" + userId);
                return;
            }
            //检查PackageInstaller是否有动态权限授权权限
            mContext.enforceCallingOrSelfPermission(
                    android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
                    "grantRuntimePermission");
    
            enforceCrossUserPermission(callingUid, userId,
                    true,  // requireFullPermission
                    true,  // checkShell
                    false, // requirePermissionWhenSameUser
                    "grantRuntimePermission");
    
            final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
            if (pkg == null || pkg.mExtras == null) {
                throw new IllegalArgumentException("Unknown package: " + packageName);
            }
            final BasePermission bp;
            synchronized(mLock) {
                bp = mSettings.getPermissionLocked(permName);
            }
            if (bp == null) {
                throw new IllegalArgumentException("Unknown permission: " + permName);
            }
            if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
                throw new IllegalArgumentException("Unknown package: " + packageName);
            }
    
            bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
            if (mSettings.mPermissionReviewRequired
                    && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
                    && bp.isRuntime()) {
                return;
            }
    
            final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
    
            final PackageSetting ps = (PackageSetting) pkg.mExtras;
            final PermissionsState permissionsState = ps.getPermissionsState();
    
            final int flags = permissionsState.getPermissionFlags(permName, userId);
            if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
                throw new SecurityException("Cannot grant system fixed permission "
                        + permName + " for package " + packageName);
            }
            if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
                throw new SecurityException("Cannot grant policy fixed permission "
                        + permName + " for package " + packageName);
            }
    
            if (bp.isDevelopment()) {
                if (permissionsState.grantInstallPermission(bp) !=
                        PermissionsState.PERMISSION_OPERATION_FAILURE) {
                    if (callback != null) {
                        callback.onInstallPermissionGranted();
                    }
                }
                return;
            }
    
            if (ps.getInstantApp(userId) && !bp.isInstant()) {
                throw new SecurityException("Cannot grant non-ephemeral permission"
                        + permName + " for package " + packageName);
            }
    
            if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
                Slog.w(TAG, "Cannot grant runtime permission to a legacy app");
                return;
            }
    
            final int result = permissionsState.grantRuntimePermission(bp, userId);
            switch (result) {
                case PermissionsState.PERMISSION_OPERATION_FAILURE: {
                    return;
                }
    
                case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
                    if (callback != null) {
                          //权限改变
                        callback.onGidsChanged(UserHandle.getAppId(pkg.applicationInfo.uid), userId);
                    }
                }
                break;
            }
    
            if (bp.isRuntime()) {
                logPermission(MetricsEvent.ACTION_PERMISSION_GRANTED, permName, packageName);
            }
    
            if (callback != null) {
                //回调PermissionCallback的onPermissionGranted方法通知授予权限
                callback.onPermissionGranted(uid, userId);
            }
    
            // to make an expensive call to remount processes for the changed permissions.
            if (READ_EXTERNAL_STORAGE.equals(permName)
                    || WRITE_EXTERNAL_STORAGE.equals(permName)) {
                final long token = Binder.clearCallingIdentity();
                try {
                    if (mUserManagerInt.isUserInitialized(userId)) {
                        StorageManagerInternal storageManagerInternal = LocalServices.getService(
                                StorageManagerInternal.class);
                        storageManagerInternal.onExternalStoragePolicyChanged(uid, packageName);
                    }
                } finally {
                    Binder.restoreCallingIdentity(token);
                }
            }
        }
    

    然后又回到PackageManagerService

        private PermissionCallback mPermissionCallback = new PermissionCallback() {
            public void onPermissionGranted(int uid, int userId) {
                mOnPermissionChangeListeners.onPermissionsChanged(uid);
                // Not critical; if this is lost, the application has to request again.
                synchronized (mPackages) {
                    //下面会分钟分析这个函数
                    mSettings.writeRuntimePermissionsForUserLPr(userId, false);
                }
            }
    }
    

    回调的是PackageManagerService中的PermissionCallback,在其实现的onPermissionGranted方法中会去通知观察者权 限发生变化,并调用PackageManager的Settings记录动态权限授权状态。

    看在Settings的执行流程

    public final class Settings {
        public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) {
            if (sync) {
                mRuntimePermissionsPersistence.writePermissionsForUserSyncLPr(userId);
            } else {
                mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
            }
        }
    
        private final class RuntimePermissionPersistence {
            public void writePermissionsForUserSyncLPr(int userId) {
                mHandler.removeMessages(userId);
                writePermissionsSync(userId);
            }
    
            // writePermissionsSync方法来完成最后的记录工作。
            // writePermissionsSync方法的代码很长,但是逻辑很清晰,就是先查询与应用相关的所有权限状态,
            // 然后创建 runtime-permissions.xml 文件把这些信息记录进去。
            private void writePermissionsSync(int userId) {
                // 动态权限文件(runtime-permissions.xml
                AtomicFile destination = new AtomicFile(getUserRuntimePermissionsFile(userId),
                        "package-perms-" + userId);
    
                ArrayMap<String, List<PermissionState>> permissionsForPackage = new ArrayMap<>();
                ArrayMap<String, List<PermissionState>> permissionsForSharedUser = new ArrayMap<>();
    
                synchronized (mPersistenceLock) {
                    mWriteScheduled.delete(userId);
                    //获得Package权限状态
                    final int packageCount = mPackages.size();
                    for (int i = 0; i < packageCount; i++) {
                        String packageName = mPackages.keyAt(i);
                        PackageSetting packageSetting = mPackages.valueAt(i);
                        if (packageSetting.sharedUser == null) {
                            PermissionsState permissionsState = packageSetting.getPermissionsState();
                            List<PermissionState> permissionsStates = permissionsState
                                    .getRuntimePermissionStates(userId);
                            if (!permissionsStates.isEmpty()) {
                                permissionsForPackage.put(packageName, permissionsStates);
                            }
                        }
                    }
                    //获得SharedUser权限状态
                    final int sharedUserCount = mSharedUsers.size();
                    for (int i = 0; i < sharedUserCount; i++) {
                        String sharedUserName = mSharedUsers.keyAt(i);
                        SharedUserSetting sharedUser = mSharedUsers.valueAt(i);
                        PermissionsState permissionsState = sharedUser.getPermissionsState();
                        List<PermissionState> permissionsStates = permissionsState
                                .getRuntimePermissionStates(userId);
                        if (!permissionsStates.isEmpty()) {
                            permissionsForSharedUser.put(sharedUserName, permissionsStates);
                        }
                    }
                }
    
                FileOutputStream out = null;
                try {
                    out = destination.startWrite();
                    // 创建xml文件用于记录权限状态
                    XmlSerializer serializer = Xml.newSerializer();
                    serializer.setOutput(out, StandardCharsets.UTF_8.name());
                    serializer.setFeature(
                            "http://xmlpull.org/v1/doc/features.html#indent-output", true);
                    serializer.startDocument(null, true);
    
                    serializer.startTag(null, TAG_RUNTIME_PERMISSIONS);
    
                    String fingerprint = mFingerprints.get(userId);
                    if (fingerprint != null) {
                        serializer.attribute(null, ATTR_FINGERPRINT, fingerprint);
                    }
                    // 写入Package权限状态
                    final int packageCount = permissionsForPackage.size();
                    for (int i = 0; i < packageCount; i++) {
                        String packageName = permissionsForPackage.keyAt(i);
                        List<PermissionState> permissionStates = permissionsForPackage.valueAt(i);
                        serializer.startTag(null, TAG_PACKAGE);
                        serializer.attribute(null, ATTR_NAME, packageName);
                        writePermissions(serializer, permissionStates);
                        serializer.endTag(null, TAG_PACKAGE);
                    }
                    // 写入SharedUser权限状态
                    final int sharedUserCount = permissionsForSharedUser.size();
                    for (int i = 0; i < sharedUserCount; i++) {
                        String packageName = permissionsForSharedUser.keyAt(i);
                        List<PermissionState> permissionStates = permissionsForSharedUser.valueAt(i);
                        serializer.startTag(null, TAG_SHARED_USER);
                        serializer.attribute(null, ATTR_NAME, packageName);
                        writePermissions(serializer, permissionStates);
                        serializer.endTag(null, TAG_SHARED_USER);
                    }
    
                    serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);
    
                    // Now any restored permission grants that are waiting for the apps
                    // in question to be installed.  These are stored as per-package
                    // TAG_RESTORED_RUNTIME_PERMISSIONS blocks, each containing some
                    // number of individual permission grant entities.
                    if (mRestoredUserGrants.get(userId) != null) {
                        ArrayMap<String, ArraySet<RestoredPermissionGrant>> restoredGrants =
                                mRestoredUserGrants.get(userId);
                        if (restoredGrants != null) {
                            final int pkgCount = restoredGrants.size();
                            for (int i = 0; i < pkgCount; i++) {
                                final ArraySet<RestoredPermissionGrant> pkgGrants =
                                        restoredGrants.valueAt(i);
                                if (pkgGrants != null && pkgGrants.size() > 0) {
                                    final String pkgName = restoredGrants.keyAt(i);
                                    serializer.startTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
                                    serializer.attribute(null, ATTR_PACKAGE_NAME, pkgName);
    
                                    final int N = pkgGrants.size();
                                    for (int z = 0; z < N; z++) {
                                        RestoredPermissionGrant g = pkgGrants.valueAt(z);
                                        serializer.startTag(null, TAG_PERMISSION_ENTRY);
                                        serializer.attribute(null, ATTR_NAME, g.permissionName);
    
                                        if (g.granted) {
                                            serializer.attribute(null, ATTR_GRANTED, "true");
                                        }
    
                                        if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) {
                                            serializer.attribute(null, ATTR_USER_SET, "true");
                                        }
                                        if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) {
                                            serializer.attribute(null, ATTR_USER_FIXED, "true");
                                        }
                                        if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
                                            serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
                                        }
                                        serializer.endTag(null, TAG_PERMISSION_ENTRY);
                                    }
                                    serializer.endTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
                                }
                            }
                        }
                    }
                    // 写入结束
                    serializer.endDocument();
                    destination.finishWrite(out);
    
                    if (Build.FINGERPRINT.equals(fingerprint)) {
                        mDefaultPermissionsGranted.put(userId, true);
                    }
                    // Any error while writing is fatal.
                } catch (Throwable t) {
                    Slog.wtf(PackageManagerService.TAG,
                            "Failed to write settings, restoring backup", t);
                    destination.failWrite(out);
                } finally {
                    IoUtils.closeQuietly(out);
                }
            }
        }    
    }
    

    权限申请源码流程总结:

    • 第一步:MainActivity 调用 requestPermissions 进行动态权限申请;
    • 第二步:requestPermissions函数通过隐士意图,激活PackageInstaller的GrantPermissionsActivity界面,让用户选择是否授权;
    • 第三步:经过PKMS把相关信息传递给PermissionManagerService处理;
    • 第四步:PermissionManagerService处理结束后回调给---->PKMS中的onPermissionGranted方法把处理结果返回;
    • 第五步:PKMS通知过程中权限变化,并调用writeRuntimePermissionsForUserLPr函数让PackageManager的settings记录下相关授权信息,保存到 XML(data/system/users/0/runtime-permissions.xml) 文件中;
    • 注意:最终会通过这个类将相应的权限写入data/system/users/0/runtime-permissions.xml这个文件中,供其他接口调用
    权限保存位置

    四、校验权限流程

    check权限流程

    从权限的鉴定开始

         if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED) {
             
        }
    

    调用ContextCompat.checkSelfPermission方法

        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());
        }
    

    因为Context运用装饰模式,最终会调用ContextImpl中的checkPermission

        public int checkPermission(String permission, int pid, int uid) {
            if (permission == null) {
                throw new IllegalArgumentException("permission is null");
            }
    
            final IActivityManager am = ActivityManager.getService();
            if (am == null) {
                // Well this is super awkward; we somehow don't have an active
                // ActivityManager instance. If we're testing a root or system
                // UID, then they totally have whatever permission this is.
                final int appId = UserHandle.getAppId(uid);
                if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
                    Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission);
                    return PackageManager.PERMISSION_GRANTED;
                }
                Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold "
                        + permission);
                return PackageManager.PERMISSION_DENIED;
            }
    
            try {
                //进入AMS 进行跨进程通信
                return am.checkPermission(permission, pid, uid);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    调用ActivityManagerService中的checkComponentPermission

        public int checkPermission(String permission, int pid, int uid) {
            if (permission == null) {
                return PackageManager.PERMISSION_DENIED;
            }
            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);
        }
    

    进入大管家ActivityManagercheckComponentPermission

        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 {
                //会进入PKMS中,进行跨进程通信
                return AppGlobals.getPackageManager()
                        .checkUidPermission(permission, uid);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    进入PackageManagerService中的checkUidPermission

        public int checkUidPermission(String permName, int uid) {
            synchronized (mPackages) {
                final String[] packageNames = getPackagesForUid(uid);
                final PackageParser.Package pkg = (packageNames != null && packageNames.length > 0)
                        ? mPackages.get(packageNames[0])
                        : null;
                //进入 PermissionManagerService
                return mPermissionManager.checkUidPermission(permName, pkg, uid, getCallingUid());
            }
        }
    

    进入PermissionManagerService权限管理中

    public class PermissionManagerService {
        private int checkUidPermission(String permName, PackageParser.Package pkg, int uid,
                int callingUid) {
            final int callingUserId = UserHandle.getUserId(callingUid);
            final boolean isCallerInstantApp =
                    mPackageManagerInt.getInstantAppPackageName(callingUid) != null;
            final boolean isUidInstantApp =
                    mPackageManagerInt.getInstantAppPackageName(uid) != null;
            final int userId = UserHandle.getUserId(uid);
            if (!mUserManagerInt.exists(userId)) {
                return PackageManager.PERMISSION_DENIED;
            }
    
            if (pkg != null) {
                if (pkg.mSharedUserId != null) {
                    if (isCallerInstantApp) {
                        return PackageManager.PERMISSION_DENIED;
                    }
                } else if (mPackageManagerInt.filterAppAccess(pkg, callingUid, callingUserId)) {
                    return PackageManager.PERMISSION_DENIED;
                }
                final PermissionsState permissionsState =
                        ((PackageSetting) pkg.mExtras).getPermissionsState();
                if (permissionsState.hasPermission(permName, userId)) {
                    if (isUidInstantApp) {
                        if (mSettings.isPermissionInstant(permName)) {
                            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;
        }
    
    
        private class PermissionManagerInternalImpl extends PermissionManagerInternal {
            @Override
            public int checkUidPermission(String permName, PackageParser.Package pkg, int uid,
                    int callingUid) {
                return PermissionManagerService.this.checkUidPermission(permName, pkg, uid, callingUid);
            }
        }
    }
    

    五、总结

    权限整体流程.jpg

    相关文章

      网友评论

          本文标题:PKMS(二)

          本文链接:https://www.haomeiwen.com/subject/brlyaltx.html