Android權限系統(二):開機授予運行時權限

DefaultPermissionGrantPolicy簡介

.  Android開機後,除了根據上次開機的記錄(runtime-permissions.xml)授予運行時權限外,一些系統重要的組件也需要提前授予運行時權限。例如,系統會爲默認的瀏覽器提前授予位置相關的運行時權限。而這些授權操作,是在DefaultPermissionGrantPolicy類裏面進行的。DefaultPermissionGrantPolicy在PermissionManagerService的構造函數中被創建。

frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java

    PermissionManagerService(Context context,
            @NonNull Object externalLock) {
        ...

        mDefaultPermissionGrantPolicy = new DefaultPermissionGrantPolicy(
                context, mHandlerThread.getLooper(), this);

  在PMS的systemReady階段中,會調用DefaultPermissionGrantPolicy#grantDefaultPermissions爲每一個修改過運行時權限的userid提前授予運行時權限(創建新用戶也會觸發授權,此處略過):

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

    @Override
    public void systemReady() {
        ...
        // If we upgraded grant all default permissions before kicking off.
        for (int userId : grantPermissionsUserIds) {
            mDefaultPermissionPolicy.grantDefaultPermissions(userId);
        }

  提前授權的步驟分三步:1.系統特權組件授權;2.系統默認組件授權;3.特定文件指定授權。

frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java

    public void grantDefaultPermissions(int userId) {
        grantPermissionsToSysComponentsAndPrivApps(userId);
        grantDefaultSystemHandlerPermissions(userId);
        grantDefaultPermissionExceptions(userId);
        synchronized (mLock) {
            mDefaultPermissionsGrantedUsers.put(userId, userId);
        }
    }

grantPermissionsToSysComponentsAndPrivApps系統特定組件授權

  首先列出主用戶下所有已安裝的包,過濾掉以下包:1.不支持運行時權限的(targetsdk小於M);2.沒有聲明申請權限的;3.不屬於特權apk的;4.如果是屬於更新過後的系統應用,原來的系統應用不是persistent的;5.如果不屬於更新過後的系統應用,此應用不是persistent的;
6.沒有系統(platform)簽名的。其他包和UID小於10000(應用程序的首個UID)的包會被授予運行時權限。

frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java

    private void grantPermissionsToSysComponentsAndPrivApps(int userId) {
        Log.i(TAG, "Granting permissions to platform components for user " + userId);
        List<PackageInfo> packages = mContext.getPackageManager().getInstalledPackagesAsUser(
                DEFAULT_PACKAGE_INFO_QUERY_FLAGS, UserHandle.USER_SYSTEM);
        for (PackageInfo pkg : packages) {
            if (pkg == null) {
                continue;
            }
            if (!isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
                    || !doesPackageSupportRuntimePermissions(pkg)
                    || ArrayUtils.isEmpty(pkg.requestedPermissions)) {
                continue;
            }
            grantRuntimePermissionsForSystemPackage(userId, pkg);
        }
    }

frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java

    private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageInfo pkg) {
        if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
            return true;
        }
        if (!pkg.applicationInfo.isPrivilegedApp()) {
            return false;
        }
        final PackageInfo disabledPkg = getSystemPackageInfo(
                mServiceInternal.getDisabledSystemPackageName(pkg.applicationInfo.packageName));
        if (disabledPkg != null) {
            ApplicationInfo disabledPackageAppInfo = disabledPkg.applicationInfo;
            if (disabledPackageAppInfo != null
                    && (disabledPackageAppInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
                return false;
            }
        } else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
            return false;
        }
        return mServiceInternal.isPlatformSigned(pkg.packageName);
    }

  對於這部分符合要求的系統組件,系統的策略是儘可能授予組件需要的任何運行時權限。

frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java

    private void grantRuntimePermissionsForSystemPackage(int userId, PackageInfo pkg) {
        Set<String> permissions = new ArraySet<>();
        for (String permission : pkg.requestedPermissions) {
            final BasePermission bp = mPermissionManager.getPermission(permission);
            if (bp == null) {
                continue;
            }
            if (bp.isRuntime()) {
                permissions.add(permission);
            }
        }
        if (!permissions.isEmpty()) {
            grantRuntimePermissions(pkg, permissions, true /*systemFixed*/, userId);
        }
    }

grantDefaultSystemHandlerPermissions系統默認組件授權

  系統需要相應一部分重要的intent的默認包被授予特定的運行時權限,所以就通過grantDefaultSystemHandlerPermissions爲這些包授予特定的運行時權限。

frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java

    private void grantDefaultSystemHandlerPermissions(int userId) {
        Log.i(TAG, "Granting permissions to default platform handlers for user " + userId);

        final PackagesProvider locationPackagesProvider;
        final PackagesProvider locationExtraPackagesProvider;
        final PackagesProvider voiceInteractionPackagesProvider;
        final PackagesProvider smsAppPackagesProvider;
        final PackagesProvider dialerAppPackagesProvider;
        final PackagesProvider simCallManagerPackagesProvider;
        final PackagesProvider useOpenWifiAppPackagesProvider;
        final SyncAdapterPackagesProvider syncAdapterPackagesProvider;

        synchronized (mLock) {
            locationPackagesProvider = mLocationPackagesProvider;
            locationExtraPackagesProvider = mLocationExtraPackagesProvider;
            voiceInteractionPackagesProvider = mVoiceInteractionPackagesProvider;
            smsAppPackagesProvider = mSmsAppPackagesProvider;
            dialerAppPackagesProvider = mDialerAppPackagesProvider;
            simCallManagerPackagesProvider = mSimCallManagerPackagesProvider;
            useOpenWifiAppPackagesProvider = mUseOpenWifiAppPackagesProvider;
            syncAdapterPackagesProvider = mSyncAdapterPackagesProvider;
        }

        String[] voiceInteractPackageNames = (voiceInteractionPackagesProvider != null)
                ? voiceInteractionPackagesProvider.getPackages(userId) : null;
        String[] locationPackageNames = (locationPackagesProvider != null)
                ? locationPackagesProvider.getPackages(userId) : null;
        String[] locationExtraPackageNames = (locationExtraPackagesProvider != null)
                ? locationExtraPackagesProvider.getPackages(userId) : null;
        String[] smsAppPackageNames = (smsAppPackagesProvider != null)
                ? smsAppPackagesProvider.getPackages(userId) : null;
        String[] dialerAppPackageNames = (dialerAppPackagesProvider != null)
                ? dialerAppPackagesProvider.getPackages(userId) : null;
        String[] simCallManagerPackageNames = (simCallManagerPackagesProvider != null)
                ? simCallManagerPackagesProvider.getPackages(userId) : null;
        String[] useOpenWifiAppPackageNames = (useOpenWifiAppPackagesProvider != null)
                ? useOpenWifiAppPackagesProvider.getPackages(userId) : null;
        String[] contactsSyncAdapterPackages = (syncAdapterPackagesProvider != null) ?
                syncAdapterPackagesProvider.getPackages(ContactsContract.AUTHORITY, userId) : null;
        String[] calendarSyncAdapterPackages = (syncAdapterPackagesProvider != null) ?
                syncAdapterPackagesProvider.getPackages(CalendarContract.AUTHORITY, userId) : null;

        // Installer
        grantSystemFixedPermissionsToSystemPackage(
                ArrayUtils.firstOrNull(getKnownPackages(
                        PackageManagerInternal.PACKAGE_INSTALLER, userId)),
                userId, STORAGE_PERMISSIONS);

        // Verifier
        final String verifier = ArrayUtils.firstOrNull(getKnownPackages(
                PackageManagerInternal.PACKAGE_VERIFIER, userId));
        grantSystemFixedPermissionsToSystemPackage(verifier, userId, STORAGE_PERMISSIONS);
        grantPermissionsToSystemPackage(verifier, userId, PHONE_PERMISSIONS, SMS_PERMISSIONS);

        // SetupWizard
        grantPermissionsToSystemPackage(
                ArrayUtils.firstOrNull(getKnownPackages(
                        PackageManagerInternal.PACKAGE_SETUP_WIZARD, userId)), userId,
                PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
                CAMERA_PERMISSIONS);

        // Camera
        grantPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackage(MediaStore.ACTION_IMAGE_CAPTURE, userId),
                userId, CAMERA_PERMISSIONS, MICROPHONE_PERMISSIONS, STORAGE_PERMISSIONS);

        // Sound recorder
        grantPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackage(
                        MediaStore.Audio.Media.RECORD_SOUND_ACTION, userId),
                userId, MICROPHONE_PERMISSIONS);

        // Media provider
        grantSystemFixedPermissionsToSystemPackage(
                getDefaultProviderAuthorityPackage(MediaStore.AUTHORITY, userId), userId,
                STORAGE_PERMISSIONS, PHONE_PERMISSIONS);

        // Downloads provider
        grantSystemFixedPermissionsToSystemPackage(
                getDefaultProviderAuthorityPackage("downloads", userId), userId,
                STORAGE_PERMISSIONS);

        // Downloads UI
        grantSystemFixedPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackage(
                        DownloadManager.ACTION_VIEW_DOWNLOADS, userId),
                userId, STORAGE_PERMISSIONS);

        // Storage provider
        grantSystemFixedPermissionsToSystemPackage(
                getDefaultProviderAuthorityPackage("com.android.externalstorage.documents", userId),
                userId, STORAGE_PERMISSIONS);

        // CertInstaller
        grantSystemFixedPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackage(Credentials.INSTALL_ACTION, userId), userId,
                STORAGE_PERMISSIONS);

        // Dialer
        if (dialerAppPackageNames == null) {
            String dialerPackage =
                    getDefaultSystemHandlerActivityPackage(Intent.ACTION_DIAL, userId);
            grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId);
        } else {
            for (String dialerAppPackageName : dialerAppPackageNames) {
                grantDefaultPermissionsToDefaultSystemDialerApp(dialerAppPackageName, userId);
            }
        }

        // Sim call manager
        if (simCallManagerPackageNames != null) {
            for (String simCallManagerPackageName : simCallManagerPackageNames) {
                grantDefaultPermissionsToDefaultSystemSimCallManager(
                        simCallManagerPackageName, userId);
            }
        }

        // Use Open Wifi
        if (useOpenWifiAppPackageNames != null) {
            for (String useOpenWifiPackageName : useOpenWifiAppPackageNames) {
                grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(
                        useOpenWifiPackageName, userId);
            }
        }

        // SMS
        if (smsAppPackageNames == null) {
            String smsPackage = getDefaultSystemHandlerActivityPackageForCategory(
                    Intent.CATEGORY_APP_MESSAGING, userId);
            grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
        } else {
            for (String smsPackage : smsAppPackageNames) {
                grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
            }
        }

        // Cell Broadcast Receiver
        grantSystemFixedPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackage(Intents.SMS_CB_RECEIVED_ACTION, userId),
                userId, SMS_PERMISSIONS);

        // Carrier Provisioning Service
        grantPermissionsToSystemPackage(
                getDefaultSystemHandlerServicePackage(Intents.SMS_CARRIER_PROVISION_ACTION, userId),
                userId, SMS_PERMISSIONS);

        // Calendar
        grantPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackageForCategory(
                        Intent.CATEGORY_APP_CALENDAR, userId),
                userId, CALENDAR_PERMISSIONS, CONTACTS_PERMISSIONS);

        // Calendar provider
        String calendarProvider =
                getDefaultProviderAuthorityPackage(CalendarContract.AUTHORITY, userId);
        grantPermissionsToSystemPackage(calendarProvider, userId,
                CONTACTS_PERMISSIONS, STORAGE_PERMISSIONS);
        grantSystemFixedPermissionsToSystemPackage(calendarProvider, userId, CALENDAR_PERMISSIONS);

        // Calendar provider sync adapters
        grantPermissionToEachSystemPackage(
                getHeadlessSyncAdapterPackages(calendarSyncAdapterPackages, userId),
                userId, CALENDAR_PERMISSIONS);

        // Contacts
        grantPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackageForCategory(
                        Intent.CATEGORY_APP_CONTACTS, userId),
                userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);

        // Contacts provider sync adapters
        grantPermissionToEachSystemPackage(
                getHeadlessSyncAdapterPackages(contactsSyncAdapterPackages, userId),
                userId, CONTACTS_PERMISSIONS);

        // Contacts provider
        String contactsProviderPackage =
                getDefaultProviderAuthorityPackage(ContactsContract.AUTHORITY, userId);
        grantSystemFixedPermissionsToSystemPackage(contactsProviderPackage, userId,
                CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
        grantPermissionsToSystemPackage(contactsProviderPackage, userId, STORAGE_PERMISSIONS);

        // Device provisioning
        grantPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackage(
                        DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, userId),
                userId, CONTACTS_PERMISSIONS);

        // Maps
        grantPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackageForCategory(Intent.CATEGORY_APP_MAPS, userId),
                userId, ALWAYS_LOCATION_PERMISSIONS);

        // Gallery
        grantPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackageForCategory(
                        Intent.CATEGORY_APP_GALLERY, userId),
                userId, STORAGE_PERMISSIONS);

        // Email
        grantPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackageForCategory(
                        Intent.CATEGORY_APP_EMAIL, userId),
                userId, CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS);

        // Browser
        String browserPackage = ArrayUtils.firstOrNull(getKnownPackages(
                PackageManagerInternal.PACKAGE_BROWSER, userId));
        if (browserPackage == null) {
            browserPackage = getDefaultSystemHandlerActivityPackageForCategory(
                    Intent.CATEGORY_APP_BROWSER, userId);
            if (!isSystemPackage(browserPackage)) {
                browserPackage = null;
            }
        }
        grantPermissionsToPackage(browserPackage, userId, false /* ignoreSystemPackage */,
                true /*whitelistRestrictedPermissions*/, ALWAYS_LOCATION_PERMISSIONS);

        // Voice interaction
        if (voiceInteractPackageNames != null) {
            for (String voiceInteractPackageName : voiceInteractPackageNames) {
                grantPermissionsToSystemPackage(voiceInteractPackageName, userId,
                        CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
                        PHONE_PERMISSIONS, SMS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
            }
        }

        if (ActivityManager.isLowRamDeviceStatic()) {
            // Allow voice search on low-ram devices
            grantPermissionsToSystemPackage(
                    getDefaultSystemHandlerActivityPackage(
                            SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
                    userId, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
        }

        // Voice recognition
        Intent voiceRecoIntent = new Intent(RecognitionService.SERVICE_INTERFACE)
                .addCategory(Intent.CATEGORY_DEFAULT);
        grantPermissionsToSystemPackage(
                getDefaultSystemHandlerServicePackage(voiceRecoIntent, userId), userId,
                MICROPHONE_PERMISSIONS);

        // Location
        if (locationPackageNames != null) {
            for (String packageName : locationPackageNames) {
                grantPermissionsToSystemPackage(packageName, userId,
                        CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
                        PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS,
                        SENSORS_PERMISSIONS, STORAGE_PERMISSIONS);
                grantSystemFixedPermissionsToSystemPackage(packageName, userId,
                        ALWAYS_LOCATION_PERMISSIONS, ACTIVITY_RECOGNITION_PERMISSIONS);
            }
        }
        if (locationExtraPackageNames != null) {
            // Also grant location permission to location extra packages.
            for (String packageName : locationExtraPackageNames) {
                grantPermissionsToSystemPackage(packageName, userId, ALWAYS_LOCATION_PERMISSIONS);
            }
        }

        // Music
        Intent musicIntent = new Intent(Intent.ACTION_VIEW)
                .addCategory(Intent.CATEGORY_DEFAULT)
                .setDataAndType(Uri.fromFile(new File("foo.mp3")), AUDIO_MIME_TYPE);
        grantPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackage(musicIntent, userId), userId,
                STORAGE_PERMISSIONS);

        // Home
        Intent homeIntent = new Intent(Intent.ACTION_MAIN)
                .addCategory(Intent.CATEGORY_HOME)
                .addCategory(Intent.CATEGORY_LAUNCHER_APP);
        grantPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackage(homeIntent, userId), userId,
                ALWAYS_LOCATION_PERMISSIONS);

        // Watches
        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0)) {
            // Home application on watches

            String wearPackage = getDefaultSystemHandlerActivityPackageForCategory(
                    Intent.CATEGORY_HOME_MAIN, userId);
            grantPermissionsToSystemPackage(wearPackage, userId,
                    CONTACTS_PERMISSIONS, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
            grantSystemFixedPermissionsToSystemPackage(wearPackage, userId, PHONE_PERMISSIONS);

            // Fitness tracking on watches
            grantPermissionsToSystemPackage(
                    getDefaultSystemHandlerActivityPackage(ACTION_TRACK, userId), userId,
                    SENSORS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
        }

        // Print Spooler
        grantSystemFixedPermissionsToSystemPackage(PrintManager.PRINT_SPOOLER_PACKAGE_NAME, userId,
                ALWAYS_LOCATION_PERMISSIONS);

        // EmergencyInfo
        grantSystemFixedPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackage(
                        TelephonyManager.ACTION_EMERGENCY_ASSISTANCE, userId),
                userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);

        // NFC Tag viewer
        Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW)
                .setType("vnd.android.cursor.item/ndef_msg");
        grantPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackage(nfcTagIntent, userId), userId,
                CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);

        // Storage Manager
        grantSystemFixedPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackage(
                        StorageManager.ACTION_MANAGE_STORAGE, userId),
                userId, STORAGE_PERMISSIONS);

        // Companion devices
        grantSystemFixedPermissionsToSystemPackage(
                CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME, userId,
                ALWAYS_LOCATION_PERMISSIONS);

        // Ringtone Picker
        grantSystemFixedPermissionsToSystemPackage(
                getDefaultSystemHandlerActivityPackage(
                        RingtoneManager.ACTION_RINGTONE_PICKER, userId),
                userId, STORAGE_PERMISSIONS);

        // TextClassifier Service
        String textClassifierPackageName =
                mContext.getPackageManager().getSystemTextClassifierPackageName();
        if (!TextUtils.isEmpty(textClassifierPackageName)) {
            grantPermissionsToSystemPackage(textClassifierPackageName, userId,
                    PHONE_PERMISSIONS, SMS_PERMISSIONS, CALENDAR_PERMISSIONS,
                    ALWAYS_LOCATION_PERMISSIONS, CONTACTS_PERMISSIONS);
        }

        // Atthention Service
        String attentionServicePackageName =
                mContext.getPackageManager().getAttentionServicePackageName();
        if (!TextUtils.isEmpty(attentionServicePackageName)) {
            grantPermissionsToSystemPackage(attentionServicePackageName, userId,
                    CAMERA_PERMISSIONS);
        }

        // There is no real "marker" interface to identify the shared storage backup, it is
        // hardcoded in BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE.
        grantSystemFixedPermissionsToSystemPackage("com.android.sharedstoragebackup", userId,
                STORAGE_PERMISSIONS);

        // System Captions Service
        String systemCaptionsServicePackageName =
                mContext.getPackageManager().getSystemCaptionsServicePackageName();
        if (!TextUtils.isEmpty(systemCaptionsServicePackageName)) {
            grantPermissionsToSystemPackage(systemCaptionsServicePackageName, userId,
                    MICROPHONE_PERMISSIONS);
        }

grantDefaultPermissionExceptions特定文件指定授權

  系統中{partition}/etc/default-permissions目錄下的xml文件可以爲特定包提前授予運行時權限。

frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java

    private void grantDefaultPermissionExceptions(int userId) {
        mHandler.removeMessages(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);

        synchronized (mLock) {
            // mGrantExceptions is null only before the first read and then
            // it serves as a cache of the default grants that should be
            // performed for every user. If there is an entry then the app
            // is on the system image and supports runtime permissions.
            if (mGrantExceptions == null) {
                mGrantExceptions = readDefaultPermissionExceptionsLocked();
            }
        }

        Set<String> permissions = null;
        final int exceptionCount = mGrantExceptions.size();
        for (int i = 0; i < exceptionCount; i++) {
            String packageName = mGrantExceptions.keyAt(i);
            PackageInfo pkg = getSystemPackageInfo(packageName);
            List<DefaultPermissionGrant> permissionGrants = mGrantExceptions.valueAt(i);
            final int permissionGrantCount = permissionGrants.size();
            for (int j = 0; j < permissionGrantCount; j++) {
                DefaultPermissionGrant permissionGrant = permissionGrants.get(j);
                if (!isPermissionDangerous(permissionGrant.name)) {
                    Log.w(TAG, "Ignoring permission " + permissionGrant.name
                            + " which isn't dangerous");
                    continue;
                }
                if (permissions == null) {
                    permissions = new ArraySet<>();
                } else {
                    permissions.clear();
                }
                permissions.add(permissionGrant.name);


                grantRuntimePermissions(pkg, permissions, permissionGrant.fixed,
                        permissionGrant.whitelisted, true /*whitelistRestrictedPermissions*/,
                        userId);
            }
        }
    }

  `以下是其中一個xml default-permissions-google.xml的內容。package表示要額外處理的包名,sha256-cert-digest目前還沒用上,permission 的name是要提前授予的權限名稱,permission的fixed表示授權後是否可以被非系統組件修改權限,permission還有個whitelisted,表示是否可以爲限制權限添加限制免除標誌位。

<exceptions>
  <exception
    package="com.google.android.apps.restore"
    sha256-cert-digest="56:BE:13:2B:78:06:56:FE:24:44:CD:34:32:6E:B5:D7:AA:C9:1D:20:96:AB:F0:FE:67:3A:99:27:06:22:EC:87">
    <!-- External storage -->
    <permission name="android.permission.READ_EXTERNAL_STORAGE" fixed="false"/>
    <permission name="android.permission.WRITE_EXTERNAL_STORAGE" fixed="false"/>
    <!-- Contacts -->
    <permission name="android.permission.READ_CONTACTS" fixed="false"/>
    <permission name="android.permission.WRITE_CONTACTS" fixed="false"/>
  </exception>

  <exception
    package="com.google.android.apps.assistant"
    sha256-cert-digest="43:0B:20:EB:61:96:7E:9C:5B:BE:02:59:9B:07:35:16:80:7D:AE:72:D7:86:FE:92:7F:48:96:B7:C7:F2:96:1F">
    <!-- Record audio -->
    <permission name="android.permission.RECORD_AUDIO" fixed="false"/>
  </exception>

  <exception
    package="com.google.android.projection.gearhead"
    sha256-cert-digest="FD:B0:0C:43:DB:DE:8B:51:CB:31:2A:A8:1D:3B:5F:A1:77:13:AD:B9:4B:28:F5:98:D7:7F:8E:B8:9D:AC:EE:DF">
    <permission name="android.permission.ACCESS_FINE_LOCATION" fixed="false"/>
    <permission name="android.permission.CALL_PHONE" fixed="false"/>
    <permission name="android.permission.READ_CALL_LOG" fixed="false"/>
    <permission name="android.permission.READ_CONTACTS" fixed="false"/>
    <permission name="android.permission.READ_PHONE_STATE" fixed="false"/>
    <permission name="android.permission.RECEIVE_SMS" fixed="false"/>
    <permission name="android.permission.RECORD_AUDIO" fixed="false"/>
    <permission name="android.permission.SEND_SMS" fixed="false"/>
    <permission name="android.permission.PROCESS_OUTGOING_CALLS" fixed="false"/>
    <permission name="android.permission.READ_SMS" fixed="false"/>
    <permission name="android.permission.RECEIVE_MMS" fixed="false"/>
    <permission name="android.permission.WRITE_CALL_LOG" fixed="false"/>
    <permission name="android.permission.ACCESS_COARSE_LOCATION" fixed="false"/>
  </exception>
</exceptions>

統一授權入口grantRuntimePermissions

  無論是grantPermissionsToSystemPackage還是grantSystemFixedPermissionsToSystemPackage,還是grantPermissionsToSystemPackage。它們最終都會調用到grantRuntimePermissions,只是入參的值不一樣而已。
  第一個參數pkg是包的信息封裝PackageInfo對象,第二個參數permissionsWithoutSplits是未被分割(split permission)的要被授予的運行時權限,第三個參數systemFixed表示本次授予的權限是否帶上系統固定(FLAG_PERMISSION_SYSTEM_FIXED)標誌位,以免被非系統組件修改,第四個參數ignoreSystemPackage表示授權時是否考慮放置在system分區下的原應用,第五個參數whitelistRestrictedPermissions表示是否爲限制權限添加限制免除(FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT)標誌位,第六個參數是要授予的運行時權限對應的userid。

frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java

    private void grantRuntimePermissions(PackageInfo pkg, Set<String> permissionsWithoutSplits,
            boolean systemFixed, boolean ignoreSystemPackage,
            boolean whitelistRestrictedPermissions, int userId) {
        UserHandle user = UserHandle.of(userId);
        if (pkg == null) {
            return;
        }

        String[] requestedPermissions = pkg.requestedPermissions;
        if (ArrayUtils.isEmpty(requestedPermissions)) {
            return;
        }

        // Intersect the requestedPermissions for a factory image with that of its current update
        // in case the latter one removed a <uses-permission>
        String[] requestedByNonSystemPackage = getPackageInfo(pkg.packageName).requestedPermissions;
        int size = requestedPermissions.length;
        for (int i = 0; i < size; i++) {
            if (!ArrayUtils.contains(requestedByNonSystemPackage, requestedPermissions[i])) {
                requestedPermissions[i] = null;
            }
        }
        requestedPermissions = ArrayUtils.filterNotNull(requestedPermissions, String[]::new);

        PackageManager pm;
        try {
            pm = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
                    user).getPackageManager();
        } catch (NameNotFoundException doesNotHappen) {
            throw new IllegalStateException(doesNotHappen);
        }

        final ArraySet<String> permissions = new ArraySet<>(permissionsWithoutSplits);
        ApplicationInfo applicationInfo = pkg.applicationInfo;
       //添加默認授權(FLAG_PERMISSION_GRANTED_BY_DEFAULT)標誌位
        int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
        if (systemFixed) {
            //添加系統固定(FLAG_PERMISSION_SYSTEM_FIXED)標誌位
            newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
        }

        // Automatically attempt to grant split permissions to older APKs
        //如果要授予的權限含有split permission,把對應的new permission也加入到授權集合中
        final List<PermissionManager.SplitPermissionInfo> splitPermissions =
                mContext.getSystemService(PermissionManager.class).getSplitPermissions();
        final int numSplitPerms = splitPermissions.size();
        for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
            final PermissionManager.SplitPermissionInfo splitPerm =
                    splitPermissions.get(splitPermNum);

            if (applicationInfo != null
                    && applicationInfo.targetSdkVersion < splitPerm.getTargetSdk()
                    && permissionsWithoutSplits.contains(splitPerm.getSplitPermission())) {
                permissions.addAll(splitPerm.getNewPermissions());
            }
        }

        Set<String> grantablePermissions = null;

        // In some cases, like for the Phone or SMS app, we grant permissions regardless
        // of if the version on the system image declares the permission as used since
        // selecting the app as the default for that function the user makes a deliberate
        // choice to grant this app the permissions needed to function. For all other
        // apps, (default grants on first boot and user creation) we don't grant default
        // permissions if the version on the system image does not declare them.
        //入參ignoreSystemPackage爲false且目標包是更新過的system app的時候,則按system下面的包聲明申請的權限爲標準進行篩選
        if (!ignoreSystemPackage
                && applicationInfo != null
                && applicationInfo.isUpdatedSystemApp()) {
            final PackageInfo disabledPkg = getSystemPackageInfo(
                    mServiceInternal.getDisabledSystemPackageName(pkg.packageName));
            if (disabledPkg != null) {
                if (ArrayUtils.isEmpty(disabledPkg.requestedPermissions)) {
                    return;
                }
                if (!Arrays.equals(requestedPermissions, disabledPkg.requestedPermissions)) {
                    grantablePermissions = new ArraySet<>(Arrays.asList(requestedPermissions));
                    requestedPermissions = disabledPkg.requestedPermissions;
                }
            }
        }

        final int numRequestedPermissions = requestedPermissions.length;

        // Sort requested permissions so that all permissions that are a foreground permission (i.e.
        // permissions that have a background permission) are before their background permissions.
        final String[] sortedRequestedPermissions = new String[numRequestedPermissions];
        int numForeground = 0;
        int numOther = 0;
        for (int i = 0; i < numRequestedPermissions; i++) {
            String permission = requestedPermissions[i];
            if (getBackgroundPermission(permission) != null) {
                sortedRequestedPermissions[numForeground] = permission;
                numForeground++;
            } else {
                sortedRequestedPermissions[numRequestedPermissions - 1 - numOther] =
                        permission;
                numOther++;
            }
        }

        for (int requestedPermissionNum = 0; requestedPermissionNum < numRequestedPermissions;
                requestedPermissionNum++) {
            //如果是入參pkg是更新過的包且入參ignoreSystemPackage爲false,這裏遍歷的是對應的system分區的聲明申請權限;否則遍歷的是目標包的聲明申請權限
            String permission = requestedPermissions[requestedPermissionNum];

            // If there is a disabled system app it may request a permission the updated
            // version ot the data partition doesn't, In this case skip the permission.
            //如果存在更新包對應在system分區的包,system分區的包聲明瞭某個權限,但是更新的data分區的包沒有聲明這個權限,則忽略這個權限
            if (grantablePermissions != null && !grantablePermissions.contains(permission)) {
                continue;
            }

            if (permissions.contains(permission)) {//如果包聲明申請的權限在本次調用所要申請的權限集合中
                final int flags = mContext.getPackageManager().getPermissionFlags(
                        permission, pkg.packageName, user);

                // If we are trying to grant as system fixed and already system fixed
                // then the system can change the system fixed grant state.
                final boolean changingGrantForSystemFixed = systemFixed
                        && (flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0;

                // Certain flags imply that the permission's current state by the system or
                // device/profile owner or the user. In these cases we do not want to clobber the
                // current state.
                //
                // Unless the caller wants to override user choices. The override is
                // to make sure we can grant the needed permission to the default
                // sms and phone apps after the user chooses this in the UI.
                //如果1.權限不是用戶設置或者固定的 2.入參ignoreSystemPackage 爲false 3,嘗試改變帶有系統固定(FLAG_PERMISSION_SYSTEM_FIXED)標誌位的權限狀態 三個條件滿足之一
                if (!isFixedOrUserSet(flags) || ignoreSystemPackage
                        || changingGrantForSystemFixed) {
                    // Never clobber policy fixed permissions.
                    // We must allow the grant of a system-fixed permission because
                    // system-fixed is sticky, but the permission itself may be revoked.
                    //如果權限帶有devicepolicy固定(FLAG_PERMISSION_POLICY_FIXED)標誌位,跳過該權限
                    if ((flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
                        continue;
                    }

                    // Preserve whitelisting flags.
                    //保留所有的限制免除標誌位
                    newFlags |= (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT);

                    // If we are whitelisting the permission, update the exempt flag before grant.
                    //如果入參whitelistRestrictedPermissions爲true,目標權限是限制權限,爲該權限添加系統限制免除(FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT)標誌位
                    if (whitelistRestrictedPermissions && isPermissionRestricted(permission)) {
                        mContext.getPackageManager().updatePermissionFlags(permission,
                                pkg.packageName,
                                PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT,
                                PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, user);
                    }

                    // If the system tries to change a system fixed permission from one fixed
                    // state to another we need to drop the fixed flag to allow the grant.
                    //如果嘗試爲一個帶系統固定(FLAG_PERMISSION_SYSTEM_FIXED)標誌位的權限添加系統固定(FLAG_PERMISSION_SYSTEM_FIXED)標誌位,先把原來的系統固定(FLAG_PERMISSION_SYSTEM_FIXED)標誌位移除掉
                    if (changingGrantForSystemFixed) {
                        mContext.getPackageManager().updatePermissionFlags(permission,
                                pkg.packageName, flags,
                                flags & ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, user);
                    }

                    if (pm.checkPermission(permission, pkg.packageName)
                            != PackageManager.PERMISSION_GRANTED) {//授予權限
                        mContext.getPackageManager()
                                .grantRuntimePermission(pkg.packageName, permission, user);
                    }
                    //更新權限標誌位
                    mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
                            newFlags, newFlags, user);

                    int uid = UserHandle.getUid(userId,
                            UserHandle.getAppId(pkg.applicationInfo.uid));
                    //如果目標權限是一個後臺權限,遍歷其對應的所有前臺權限,如果對於目標包某個前臺權限是授權了的,那麼目標包的uid進行前臺權限操作將通過appops設置成允許
                    List<String> fgPerms = mPermissionManager.getBackgroundPermissions()
                            .get(permission);
                    if (fgPerms != null) {
                        int numFgPerms = fgPerms.size();
                        for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
                            String fgPerm = fgPerms.get(fgPermNum);

                            if (pm.checkPermission(fgPerm, pkg.packageName)
                                    == PackageManager.PERMISSION_GRANTED) {
                                // Upgrade the app-op state of the fg permission to allow bg access
                                // TODO: Dont' call app ops from package manager code.
                                mContext.getSystemService(AppOpsManager.class).setUidMode(
                                        AppOpsManager.permissionToOp(fgPerm), uid,
                                        AppOpsManager.MODE_ALLOWED);

                                break;
                            }
                        }
                    }
                                  
                    String bgPerm = getBackgroundPermission(permission);
                    String op = AppOpsManager.permissionToOp(permission);
                    if (bgPerm == null) {//如果目標權限沒有對應的後臺權限,直接將權限操作通過appops設置爲允許
                        if (op != null) {
                            // TODO: Dont' call app ops from package manager code.
                            mContext.getSystemService(AppOpsManager.class).setUidMode(op, uid,
                                    AppOpsManager.MODE_ALLOWED);
                        }
                    } else {//如果目標權限有對應的後臺權限,檢查對應的後臺權限是否授予給目標包了,有的話將權限操作通過appops設置爲允許,沒有的話將權限操作通過appops設置爲前臺允許
                        int mode;
                        if (pm.checkPermission(bgPerm, pkg.packageName)
                                == PackageManager.PERMISSION_GRANTED) {
                            mode = AppOpsManager.MODE_ALLOWED;
                        } else {
                            mode = AppOpsManager.MODE_FOREGROUND;
                        }

                        mContext.getSystemService(AppOpsManager.class).setUidMode(op, uid, mode);
                    }

                    if (DEBUG) {
                        Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ")
                                + permission + " to default handler " + pkg);

                        int appOp = AppOpsManager.permissionToOpCode(permission);
                        if (appOp != AppOpsManager.OP_NONE
                                && AppOpsManager.opToDefaultMode(appOp)
                                        != AppOpsManager.MODE_ALLOWED) {
                            // Permission has a corresponding appop which is not allowed by default
                            // We must allow it as well, as it's usually checked alongside the
                            // permission
                            if (DEBUG) {
                                Log.i(TAG, "Granting OP_" + AppOpsManager.opToName(appOp)
                                        + " to " + pkg.packageName);
                            }
                            mContext.getSystemService(AppOpsManager.class).setUidMode(
                                    appOp, pkg.applicationInfo.uid, AppOpsManager.MODE_ALLOWED);
                        }
                    }
                }

                // If a component gets a permission for being the default handler A
                // and also default handler B, we grant the weaker grant form.
                if ((flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0
                        && (flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0
                        && !systemFixed) {
                    if (DEBUG) {
                        Log.i(TAG, "Granted not fixed " + permission + " to default handler "
                                + pkg);
                    }
                    mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
                            PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, user);
                }
            }
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章