PackageManagerService权限分析

1.文档简介

1.1.文档目的

了解PKMS/App中,权限相关知识;精通安卓系统权限相关设计思路,能够进行权限方面功能定制,调查和解决权限相关问题。

1.2.文档内容

本文主要介绍权限相关内容,主要包含以下几部分:
权限创建流程
权限分类
非运行时权限授权流程
运行时权限授权流程
重置运行时权限流程
常用的权限调查命令

1.3.权限相关功能的学习计划

调查framework-re.apk安装过程中,创建权限相关流程;
根据代码确认权限分类;
调查非运行时权限授权流程;
应用申请Camera权限,调查运行时权限授予流程;
Settings应用取消Camera授权,跟进取消授权流程;

2.权限简介

本章节包含权限分类,授权流程图示等内容

2.1.常见的权限示例

2.1.1.权限创建示例

frameworks/base/core/res/AndroidManifest.xml
<permission android:name="android.permission.CAMERA"
    android:permissionGroup="android.permission-group.UNDEFINED"
    android:label="@string/permlab_camera"
    android:description="@string/permdesc_camera"
android:protectionLevel="dangerous|instant" />

android:label="@string/permlab_camera"字符串:
“拍摄照片和视频”
android:description="@string/permdesc_camera"字符串:
“此应用可随时使用相机拍摄照片和录制视频”

2.1.2.权限组创建示例

未定义时,默认的权限组:

frameworks/base/core/res/AndroidManifest.xml
<permission-group android:name="android.permission-group.UNDEFINED"
android:priority="100" />

联系人权限组:

<permission-group android:name="android.permission-group.CONTACTS"
    android:icon="@drawable/perm_group_contacts"
    android:label="@string/permgrouplab_contacts"
    android:description="@string/permgroupdesc_contacts"
    android:request="@string/permgrouprequest_contacts"
    android:priority="100" />

2.1.3.应用程序创建权限示例

packages/apps/Bluetooth/AndroidManifest.xml
<permission android:name="android.permission.ACCESS_BLUETOOTH_SHARE"
        android:label="@string/permlab_bluetoothShareManager"
        android:description="@string/permdesc_bluetoothShareManager"
        android:protectionLevel="signature" />

2.1.4.申请权限示例

packages/apps/Bluetooth/AndroidManifest.xml
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" />

2.2.按照保护级别进行的权限分类

权限类型 举例 说明
dangerous
signature
privileged
Instant
runtime
normal
appop
setup
documenter
……

protectionLevel描述:
/**

  • Characterizes the potential risk implied in a permission and
  • indicates the procedure the system should follow when determining
  • whether to grant the permission to an application requesting it. {@link
  • android.Manifest.permission Standard permissions} have a predefined and
  • permanent protectionLevel. If you are creating a custom permission in an
  • application, you can define a protectionLevel attribute with one of the
  • values listed below. If no protectionLevel is defined for a custom
  • permission, the system assigns the default (“normal”).
  • Each protection level consists of a base permission type and zero or

  • more flags. Use the following functions to extract those.
  • int basePermissionType = permissionInfo.getProtection();
  • int permissionFlags = permissionInfo.getProtectionFlags();
  • Must be one or more (separated by '|') of the following constant values.

  • ConstantValueDescription
  • appPredictor200000Additional flag from base permission type: this permission can be automatically
  • granted to the system app predictor
  • appop40Additional flag from base permission type: this permission is closely
  • associated with an app op for controlling access.
  • configurator80000Additional flag from base permission type: this permission automatically
  • granted to device configurator
  • dangerous1Base permission type: a higher-risk permission that
  • would give a requesting application access to private user data or
  • control over the device that can negatively impact the user. Because
  • this type of permission introduces potential risk, the system may
  • not automatically grant it to the requesting application. For example,
  • any dangerous permissions requested by an application may be displayed
  • to the user and require confirmation before proceeding, or some other
  • approach may be taken to avoid the user automatically allowing
  • the use of such facilities.
  • development20Additional flag from base permission type: this permission can also
  • (optionally) be granted to development applications.
  • documenter40000Additional flag from base permission type: this permission can be automatically
  • granted to the document manager
  • incidentReportApprover100000Additional flag from base permission type: this permission designates the app
  • that will approve the sharing of incident reports.
  • installer100Additional flag from base permission type: this permission can be automatically
  • granted to system apps that install packages.
  • instant1000Additional flag from base permission type: this permission can be granted to instant
  • apps
  • normal0Base permission type: a lower-risk permission that gives
  • an application access to isolated application-level features, with minimal
  • risk to other applications, the system, or the user. The system
  • automatically grants this type of permission to a requesting application at
  • installation, without asking for the user’s explicit approval (though the
  • user always has the option to review these permissions before installing).
  • oem4000Additional flag from base permission type: this permission can be granted only
  • if its protection level is signature, the requesting app resides on the OEM partition,
  • and the OEM has white-listed the app to receive this permission by the OEM.
  • pre2380Additional flag from base permission type: this permission can be automatically
  • granted to apps that target API levels below
  • {@link android.os.Build.VERSION_CODES#M} (before runtime permissions
  • were introduced).
  • preinstalled400Additional flag from base permission type: this permission can be automatically
  • granted any application pre-installed on the system image (not just privileged
  • apps).
  • privileged10Additional flag from base permission type: this permission can also
  • be granted to any applications installed as privileged apps on the system image.
  • Please avoid using this option, as the
  • signature protection level should be sufficient for most needs and
  • works regardless of exactly where applications are installed. This
  • permission flag is used for certain special situations where multiple
  • vendors have applications built in to a system image which need
  • to share specific features explicitly because they are being built
  • together.
  • runtime2000Additional flag from base permission type: this permission can only be granted to apps
  • that target runtime permissions ({@link android.os.Build.VERSION_CODES#M} and above)
  • setup800Additional flag from base permission type: this permission can be automatically
  • granted to the setup wizard app
  • signature2Base permission type: a permission that the system is
  • to grant only if the requesting application is signed with the same
  • certificate as the application that declared the permission. If the
  • certificates match, the system automatically grants the permission
  • without notifying the user or asking for the user’s explicit approval.
  • signatureOrSystem3Old synonym for "signature|privileged". Deprecated in API level 23.
  • Base permission type: a permission that the system is to grant only
  • to packages in the Android system image or that are signed
  • with the same certificates. Please avoid using this option, as the
  • signature protection level should be sufficient for most needs and
  • works regardless of exactly where applications are installed. This
  • permission is used for certain special situations where multiple
  • vendors have applications built in to a system image which need
  • to share specific features explicitly because they are being built
  • together.
  • system10Old synonym for "privileged". Deprecated in API level 23.
  • textClassifier10000Additional flag from base permission type: this permission can be automatically
  • granted to the system default text classifier
  • vendorPrivileged8000Additional flag from base permission type: this permission can be granted to
  • privileged apps in vendor partition.
  • verifier200Additional flag from base permission type: this permission can be automatically
  • granted to system apps that verify packages.
  • wellbeing20000Additional flag from base permission type: this permission will be granted to the
  • wellbeing app, as defined by the OEM.
  • @apiSince 1
    */

2.3.检查权限授权状态时序图

权限授权状态,保存在system_server进程中的PackageManagerService相关数据结构中。
每个应用程序在PackageManagerService中,都有唯一一个PackageSetting对象,保存了应用的数据,包括应用的权限授权状态。
以下是应用程序检查授权状态流程图:
PackageManagerService权限分析_第1张图片

2.4.运行时权限授权流程图

应用程序申请权限时,系统应用弹出授权提示框界面,提醒用户是否要授予对应权限。
这里弹出授权提示框的系统应用,在安卓9及之前,是PackageInstaller.apk,新的安卓版本,是PermissionController.apk程序。
用户点击授权按钮,调用PackageManagerService接口,修改此应用的授权状态。

PackageManagerService权限分析_第2张图片

2.5.非运行时权限授权流程图

非运行时权限授权状态,是在应用安装阶段就确定了的,不给用户提供可以修改的途径。
应用安装阶段,根据应用安装位置、应用签名、应用sharedUserId属性、应用目标版本、被重新安装应用的授权状态等信息,来决定非运行时权限的授权状态。
以下是应用安装阶段,修改应用授权状态的代码调用时序图:
PackageManagerService权限分析_第3张图片

3.权限相关问题调查方法

这里介绍了常见权限相关问题的调查方法和思路。

3.1.查看权限的定义和保护级别

我们在申请某个权限时,通常需要关注此权限的protectionLevel标签,这样我们才能知道,我们的应用应该具备什么条件,才能获取此权限。
例如:
normal类型权限,只要声明就被授予;
Dangerous类型权限,需要动态申请,请用户点击授权才能获取;
System类型权限,需要将应用预置到系统开机扫描的目录(system、vendor等)才能获取;
Signature类型权限,需要我们的应用,跟声明权限的应用,具备相同签名;
获取protectionLevel标签的adb 命令如下:
adb shell dumpsys package |grep “android.permission.CAMERA” |grep prot
输出如下:
android.permission.CAMERA: prot=dangerous|instant, INSTALLED
可以看到android.permission.CAMERA是dangerous|instant类型的protectionLevel,只有动态申请权限,或instant类型的app,才能获取此权限。

3.2.查看某个应用是否具备某个权限

通过以下命令,可以看到某个应用的权限情况,如创建权限的情况,声明权限情况,权限授予情况等信息:
adb shell dumpsys package com.android.calendar

输入如下:

Packages:
  Package [com.android.calendar] (e61dece):
    userId=10138
    pkg=Package{2e2d1ef com.android.calendar}
...
    requested permissions:
      android.permission.GET_ACCOUNTS
      android.permission.MANAGE_ACCOUNTS
      android.permission.INTERNET
      android.permission.VIBRATE
      android.permission.READ_CONTACTS
      android.permission.READ_CALENDAR
      android.permission.WRITE_CALENDAR
      android.permission.WAKE_LOCK
      android.permission.USE_CREDENTIALS
      android.permission.READ_SYNC_SETTINGS
      android.permission.RECEIVE_BOOT_COMPLETED
      com.google.android.googleapps.permission.GOOGLE_AUTH.mail
    install permissions:
      android.permission.USE_CREDENTIALS: granted=true
      android.permission.MANAGE_ACCOUNTS: granted=true
      android.permission.RECEIVE_BOOT_COMPLETED: granted=true
      android.permission.INTERNET: granted=true
      android.permission.READ_SYNC_SETTINGS: granted=true
      android.permission.VIBRATE: granted=true
      android.permission.WAKE_LOCK: granted=true
    User 0: ceDataInode=122984 installed=true hidden=false suspended=false distractionFlags=0 stopped=false notLaunched=false enabled=0 instant=false virtual=false
      gids=[3003]
      runtime permissions:
        android.permission.READ_CALENDAR: granted=true, flags=[ GRANTED_BY_DEFAULT|USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
    User 10: ceDataInode=262385 installed=true hidden=false suspended=false distractionFlags=0 stopped=false notLaunched=false enabled=0 instant=false virtual=false
      gids=[3003]
      runtime permissions:
        android.permission.READ_CALENDAR: granted=true, flags=[ GRANTED_BY_DEFAULT|USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]

根据以上输出信息,可以看到以下信息:
requested permissions数据是应用申请的权限数据;
install permissions数据是安装时就决定了的权限数据,不区分用户;
runtime permissions数据是区分用户的,每个用户都有自己的授权状态,可以独立控制授权状态;
granted=true数据代表此权限已授予;

3.3.授予运行时权限命令

可以通过以下命令,授予运行时权限,也可以添加–user 10参数,指定用户授予权限:
adb shell pm grant com.demo.test android.permission.CAMERA

我们先写一个测试app,包名为com.demo.test,先来用dumpsys +包名看下权限情况:

    requested permissions:
      android.permission.INTERNET
      android.permission.FORCE_STOP_PACKAGES
      android.permission.CAMERA
    install permissions:
      android.permission.INTERNET: granted=true
    User 0: ceDataInode=123209 installed=true hidden=false suspended=false distractionFlags=0 stopped=true notLaunched=true enabled=0 instant=false virtual=false
      gids=[3003]
      runtime permissions:
        android.permission.CAMERA: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
    User 10: ceDataInode=262769 installed=true hidden=false suspended=false distractionFlags=0 stopped=false notLaunched=false enabled=0 instant=false virtual=false
      gids=[3003]
      runtime permissions:
        android.permission.CAMERA: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]

看到android.permission.CAMERA是未授权状态,我们用上面的grant命令授权后,再来用dumpsys +包名查看授权情况:

    requested permissions:
      android.permission.INTERNET
      android.permission.FORCE_STOP_PACKAGES
      android.permission.CAMERA
    install permissions:
      android.permission.INTERNET: granted=true
    User 0: ceDataInode=123209 installed=true hidden=false suspended=false distractionFlags=0 stopped=true notLaunched=true enabled=0 instant=false virtual=false
      gids=[3003]
      runtime permissions:
        android.permission.CAMERA: granted=true, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
    User 10: ceDataInode=262769 installed=true hidden=false suspended=false distractionFlags=0 stopped=false notLaunched=false enabled=0 instant=false virtual=false
      gids=[3003]
      runtime permissions:
        android.permission.CAMERA: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]

我们可以看到,我们为用户0上的此应用,授予了android.permission.CAMERA权限,命令生效了!

再来指定用户–user 10试下,用dumpsys +包名查看权限:

    requested permissions:
      android.permission.INTERNET
      android.permission.FORCE_STOP_PACKAGES
      android.permission.CAMERA
    install permissions:
      android.permission.INTERNET: granted=true
    User 0: ceDataInode=123209 installed=true hidden=false suspended=false distractionFlags=0 stopped=true notLaunched=true enabled=0 instant=false virtual=false
      gids=[3003]
      runtime permissions:
        android.permission.CAMERA: granted=true, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
    User 10: ceDataInode=262769 installed=true hidden=false suspended=false distractionFlags=0 stopped=false notLaunched=false enabled=0 instant=false virtual=false
      gids=[3003]
      runtime permissions:
        android.permission.CAMERA: granted=true, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]

可以看到,用户10上的此应用,也授予了CAMERA权限!

3.4.取消授予运行时权限

可以通过以下命令,授予某个应用获取的运行时权限,注意此命令无法指定权限来取消授权,只能全部恢复为安装时的未授权状态:
adb shell pm reset-permissions -a com.demo.test

dumsys +包名会发现,3.3章节授予的CAMERA权限已经恢复为安装时的未授权状态:

    requested permissions:
      android.permission.INTERNET
      android.permission.FORCE_STOP_PACKAGES
      android.permission.CAMERA
    install permissions:
      android.permission.INTERNET: granted=true
    User 0: ceDataInode=123209 installed=true hidden=false suspended=false distractionFlags=0 stopped=true notLaunched=true enabled=0 instant=false virtual=false
      gids=[3003]
      runtime permissions:
        android.permission.CAMERA: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
    User 10: ceDataInode=262769 installed=true hidden=false suspended=false distractionFlags=0 stopped=false notLaunched=false enabled=0 instant=false virtual=false
      gids=[3003]
      runtime permissions:
        android.permission.CAMERA: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]

4.权限创建相关流程代码

PackageManagerService的构造函数中,会扫描系统apk并识别系统apk创建的权限。
以这个场景来跟踪权限创建流程。

4.1.PKMS扫描系统apk代码

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

public PackageManagerService(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {

...
mPermissionManager = PermissionManagerService.create(context,
        mPackages /*externalLock*/);
mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();
mSettings = new Settings(Environment.getDataDirectory(),
        mPermissionManager.getPermissionSettings(), mPackages);
...

// Set flag to monitor and not change apk file paths when
// scanning install directories.
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;

if (mIsUpgrade || mFirstBoot) {
    scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
}


// /system/framework/
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
// Find base frameworks (resource packages without code).
scanDirTracedLI(frameworkDir,
        mDefParseFlags
        | PackageParser.PARSE_IS_SYSTEM_DIR,
        scanFlags
        | SCAN_NO_DEX
        | SCAN_AS_SYSTEM
        | SCAN_AS_PRIVILEGED,
        0);
...
}

来看下scanDirTracedLI对/system/framework/的扫描。

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime) {
    try {
        scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
    } finally {...
    }
}

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
    final File[] files = scanDir.listFiles();
    ...
    try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
            mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
            mParallelPackageParserCallback)) {
        // Submit files for parsing in parallel
        int fileCount = 0;
        for (File file : files) {
            final boolean isPackage = (isApkFile(file) || file.isDirectory())
                    && !PackageInstallerService.isStageName(file.getName());
            if (!isPackage) {
                // Ignore entries which are not packages
                continue;
            }
// 注意这里会解析framework-res.apk的AndroidManifest.xml
// 会包含权限的创建和获取权限的声明代码。
            parallelPackageParser.submit(file, parseFlags);
            fileCount++;
        }

        // Process results one by one
        for (; fileCount > 0; fileCount--) {
            ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
            Throwable throwable = parseResult.throwable;
            int errorCode = PackageManager.INSTALL_SUCCEEDED;

            if (throwable == null) {
                ...
                try {
// 开始扫描安装framework-res.apk
                    scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
                            currentTime, null);
                } catch (PackageManagerException e) {
                    errorCode = e.error;
                    Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
                }
            } else if (throwable instanceof PackageParser.PackageParserException) {
                ...
            } else {
                ...
            }

            // Delete invalid userdata apps
            if ((scanFlags & SCAN_AS_SYSTEM) == 0 &&
                    errorCode != PackageManager.INSTALL_SUCCEEDED) {
                logCriticalInfo(Log.WARN,
                        "Deleting invalid package at " + parseResult.scanFile);
                removeCodePathLI(parseResult.scanFile);
            }
        }
    }
}

4.2.Manifest权限解析流程

parallelPackageParser.submit(file, parseFlags)方法会调用到以下流程,开始解析;
以下方法部分逻辑包含了权限创建和权限申请相关功能。待分析

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/core/java/android/content/pm/PackageParser.java

private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
        XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
        IOException {
...
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
        && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
..
// 声明创建权限组
} else if (tagName.equals(TAG_PERMISSION_GROUP)) {
    if (!parsePermissionGroup(pkg, flags, res, parser, outError)) {
        return null;
    }
// 声明创建权限
} else if (tagName.equals(TAG_PERMISSION)) {
    if (!parsePermission(pkg, res, parser, outError)) {
        return null;
    }
// 声明创建权限树
} else if (tagName.equals(TAG_PERMISSION_TREE)) {
    if (!parsePermissionTree(pkg, res, parser, outError)) {
        return null;
    }
// 声明要获取的权限
} else if (tagName.equals(TAG_USES_PERMISSION)) {
    if (!parseUsesPermission(pkg, res, parser)) {
        return null;
    }
// 声明其他要使用权限相关功能
} else if (tagName.equals(TAG_USES_PERMISSION_SDK_M)
        || tagName.equals(TAG_USES_PERMISSION_SDK_23)) {
    if (!parseUsesPermission(pkg, res, parser)) {
        return null;
    }
}
...
    return pkg;
}

解析权限TAG相关逻辑包含以下几个分支,来跟进下这几个方法调用。
parsePermissionGroup(pkg, flags, res, parser, outError)
parsePermission(pkg, res, parser, outError)
parsePermissionTree(pkg, res, parser, outError)
parseUsesPermission(pkg, res, parser)

4.3.解析PermissionGroup

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/core/java/android/content/pm/PackageParser.java

private boolean parsePermissionGroup(Package owner, int flags, Resources res,
        XmlResourceParser parser, String[] outError)
        throws XmlPullParserException, IOException {
// 获取PermissionGroup xml相关的属性
    TypedArray sa = res.obtainAttributes(parser,
            com.android.internal.R.styleable.AndroidManifestPermissionGroup);

    int requestDetailResourceId = sa.getResourceId(
            com.android.internal.R.styleable.AndroidManifestPermissionGroup_requestDetail, 0);
    int backgroundRequestResourceId = sa.getResourceId(
            com.android.internal.R.styleable.AndroidManifestPermissionGroup_backgroundRequest,
            0);
    int backgroundRequestDetailResourceId = sa.getResourceId(
            com.android.internal.R.styleable
                    .AndroidManifestPermissionGroup_backgroundRequestDetail, 0);

// 创建PermissionGroup对象,并填充解析到的属性
    PermissionGroup perm = new PermissionGroup(owner, requestDetailResourceId,
            backgroundRequestResourceId, backgroundRequestDetailResourceId);

    if (!parsePackageItemInfo(owner, perm.info, outError,
            "", sa, true /*nameRequired*/,
            com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
            com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
            com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,
            com.android.internal.R.styleable.AndroidManifestPermissionGroup_roundIcon,
            com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo,
            com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
        sa.recycle();
        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
        return false;
    }

    perm.info.descriptionRes = sa.getResourceId(
            com.android.internal.R.styleable.AndroidManifestPermissionGroup_description,
            0);
    perm.info.requestRes = sa.getResourceId(
            com.android.internal.R.styleable.AndroidManifestPermissionGroup_request, 0);
    perm.info.flags = sa.getInt(
            com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0);
    perm.info.priority = sa.getInt(
            com.android.internal.R.styleable.AndroidManifestPermissionGroup_priority, 0);

    sa.recycle();

    if (!parseAllMetaData(res, parser, "", perm,
            outError)) {
        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
        return false;
    }

// 将PermissionGroup 对象perm添加到Package-owner的permissionGroups对象中。
// permissionGroups是一个ArrayList对象。
    owner.permissionGroups.add(perm);

    return true;
}

我们看到Package中还包含以下几个数据结构,应该跟接下来的parsePermission等方法相关,一起来确认下。
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/core/java/android/content/pm/PackageParser.java
ArrayList permissions
ArrayList requestedPermissions
ArrayList implicitPermissions

4.4.解析创建权限标签

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/core/java/android/content/pm/PackageParser.java

private boolean parsePermission(Package owner, Resources res,
        XmlResourceParser parser, String[] outError)
    throws XmlPullParserException, IOException {

    TypedArray sa = res.obtainAttributes(parser,
            com.android.internal.R.styleable.AndroidManifestPermission);

    ...

//创建Permission对象
    Permission perm = new Permission(owner, backgroundPermission);
    if (!parsePackageItemInfo(owner, perm.info, outError,
            "", sa, true /*nameRequired*/,
            com.android.internal.R.styleable.AndroidManifestPermission_name,
            com.android.internal.R.styleable.AndroidManifestPermission_label,
            com.android.internal.R.styleable.AndroidManifestPermission_icon,
            com.android.internal.R.styleable.AndroidManifestPermission_roundIcon,
            com.android.internal.R.styleable.AndroidManifestPermission_logo,
            com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
        sa.recycle();
        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
        return false;
    }

    // Note: don't allow this value to be a reference to a resource
    // that may change.
    perm.info.group = sa.getNonResourceString(
            com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup);
    if (perm.info.group != null) {
        perm.info.group = perm.info.group.intern();
    }

    ...
    perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);
...
    // 将Permission对象添加到permissions中。
owner.permissions.add(perm);

    return true;
}

后面几个方法类似,PermissionTree相关属性,也会加入owner.permissions中;
UsesPermission被添加到了owner.requestedPermissions中。
至此,权限相关xml的扫描工作结束,创建的权限和想要申请的权限,都被添加到了Package对象中。
接下来继续看scanPackageChildLI方法后续流程,是如何保存创建的权限的。

4.5.保存创建的权限和权限组

以下流程会执行应用安装流程,我们直接去看安装流程中跟权限相关内容。

先看保存到内中的相关处理:
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

private PackageParser.Package scanPackageChildLI
-> addForInitLI

final ScanResult scanResult = scanPackageNewLI(pkg, parseFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user);

reconcilePackagesLocked(

commitReconciledScanResultLocked(reconcileResult.get(pkgName));

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private void commitPackageSettings(PackageParser.Package pkg,
@Nullable PackageParser.Package oldPkg, PackageSetting pkgSetting,
final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {

mPermissionManager.addAllPermissionGroups(pkg, chatty);

mPermissionManager.addAllPermissions(pkg, chatty);

}

若没有重名的PermissionGroup,则此权限组有效,可以添加到mSettings.mPermissionGroups中。
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
private void addAllPermissionGroups(PackageParser.Package pkg, boolean chatty) {
final int N = pkg.permissionGroups.size();
StringBuilder r = null;
for (int i=0; i final PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
final PackageParser.PermissionGroup cur = mSettings.mPermissionGroups.get(pg.info.name);
final String curPackageName = (cur == null) ? null : cur.info.packageName;
final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
if (cur == null || isPackageUpdate) {
mSettings.mPermissionGroups.put(pg.info.name, pg);

} else {
Slog.w(TAG, "Permission group " + pg.info.name + " from package "
+ pg.info.packageName + " ignored: original from "
+ cur.info.packageName);

}

}

添加此应用创建的权限
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
private void addAllPermissions(PackageParser.Package pkg, boolean chatty) {
final int N = pkg.permissions.size();
for (int i=0; i PackageParser.Permission p = pkg.permissions.get(i);

    // Assume by default that we did not install this permission into the system.
    p.info.flags &= ~PermissionInfo.FLAG_INSTALLED;

    synchronized (PermissionManagerService.this.mLock) {
        // Now that permission groups have a special meaning, we ignore permission
        // groups for legacy apps to prevent unexpected behavior. In particular,
        // permissions for one app being granted to someone just because they happen
        // to be in a group defined by another app (before this had no implications).
        if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
            p.group = mSettings.mPermissionGroups.get(p.info.group);
            // Warn for a permission in an unknown group.
            if (DEBUG_PERMISSIONS
                    && p.info.group != null && p.group == null) {
                Slog.i(TAG, "Permission " + p.info.name + " from package "
                        + p.info.packageName + " in an unknown group " + p.info.group);
            }
        }

        if (p.tree) {
            final BasePermission bp = BasePermission.createOrUpdate(
                    mSettings.getPermissionTreeLocked(p.info.name), p, pkg,
                    mSettings.getAllPermissionTreesLocked(), chatty);
            mSettings.putPermissionTreeLocked(p.info.name, bp);
        } else {
            final BasePermission bp = BasePermission.createOrUpdate(
                    mSettings.getPermissionLocked(p.info.name),
                    p, pkg, mSettings.getAllPermissionTreesLocked(), chatty);
            mSettings.putPermissionLocked(p.info.name, bp);
        }
    }
}

}
将Permission转为BasePermission对象,保存到mSettings.mPermissions数据结构中。

到这里权限组和权限已经都保存到内存中了,分别对应了两种数据结构,为PackageParser.PermissionGroup和BasePermission。
到这里我们已经了解了权限创建流程和创建的对象。

4.6.已创建权限的持久化操作

安装应用的最后流程-updateSettingsLi-mSettings.writeLPr();
把已创建的权限写入到/data/system/packages.xml中
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/Settings.java

try {
FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
BufferedOutputStream str = new BufferedOutputStream(fstr);

//XmlSerializer serializer = XmlUtils.serializerInstance();
XmlSerializer serializer = new FastXmlSerializer();


mPermissions.writePermissionTrees(serializer);
serializer.endTag(null, “permission-trees”);

serializer.startTag(null, “permissions”);
mPermissions.writePermissions(serializer);

writeAllRuntimePermissionsLPr();

}

来看下写入了哪些数据:
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionSettings.java
public void writePermissions(XmlSerializer serializer) throws IOException {
synchronized (mLock) {
for (BasePermission bp : mPermissions.values()) {
bp.writeLPr(serializer);
}
}
}

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/permission/BasePermission.java
public void writeLPr(@NonNull XmlSerializer serializer) throws IOException {
if (sourcePackageName == null) {
return;
}
serializer.startTag(null, TAG_ITEM);// item
serializer.attribute(null, ATTR_NAME, name);// name
serializer.attribute(null, ATTR_PACKAGE, sourcePackageName);// 来源包名
if (protectionLevel != PermissionInfo.PROTECTION_NORMAL) {// protectionLevel
serializer.attribute(null, “protection”, Integer.toString(protectionLevel));
}
if (type == BasePermission.TYPE_DYNAMIC) {
final PermissionInfo pi = perm != null ? perm.info : pendingPermissionInfo;
if (pi != null) {
serializer.attribute(null, “type”, “dynamic”);
if (pi.icon != 0) {
serializer.attribute(null, “icon”, Integer.toString(pi.icon));
}
if (pi.nonLocalizedLabel != null) {
serializer.attribute(null, “label”, pi.nonLocalizedLabel.toString());
}
}
}
serializer.endTag(null, TAG_ITEM);
}
到这里权限创建流程全部结束。
需要注意,断电重启后,PKMS会从/data/system/packages中读取缓存数据,而不是重新解析apk文件,这会加快开机启动速度。
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {

mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));

}

权限授权流程分为两部分,非运行时权限和运行时权限授权流程。
非运行时权限授权流程如下,在安装完成后进行授权。

5.非运行时权限授权流程

我们知道非运行时权限不是动态的,是在应用安装过程中,就确认下来的。
来看下安装过程中的授权流程:

5.1.1.安装过程修改授权状态

@GuardedBy(“mPackages”)
private void commitPackagesLocked(final CommitRequest request) {

updateSettingsLI(pkg, reconciledPkg.installArgs.installerPackageName, request.mAllUsers,
res, reconciledPkg.installArgs.user, reconciledPkg.installArgs.installReason);

}

// 更新此应用的权限信息
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private void updateSettingsInternalLI(PackageParser.Package pkg,
String installerPackageName, int[] allUsers, int[] installedForUsers,
PackageInstalledInfo res, UserHandle user, int installReason) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, “updateSettings”);

    final String pkgName = pkg.packageName;

    if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.codePath);
    synchronized (mPackages) {

// NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions
mPermissionManager.updatePermissions(pkg.packageName, pkg, true, mPackages.values(), mPermissionCallback);

}

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
private void updatePermissions(String packageName, PackageParser.Package pkg,
boolean replaceGrant, Collection allPackages,
PermissionCallback callback) {
final int flags = (pkg != null ? UPDATE_PERMISSIONS_ALL : 0) |
(replaceGrant ? UPDATE_PERMISSIONS_REPLACE_PKG : 0);
updatePermissions(
packageName, pkg, getVolumeUuidForPackage(pkg), flags, allPackages, callback);

}

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
private void updatePermissions(String changingPkgName, PackageParser.Package changingPkg,
String replaceVolumeUuid, int flags, Collection allPackages,
PermissionCallback callback) {
flags = updatePermissionTrees(changingPkgName, changingPkg, flags);
flags = updatePermissions(changingPkgName, changingPkg, flags);

Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, “restorePermissionState”);

// 更新所有应用,不包含当前应用的权限信息
// Now update the permissions for all packages, in particular
// replace the granted permissions of the system packages.
if ((flags & UPDATE_PERMISSIONS_ALL) != 0) {
for (PackageParser.Package pkg : allPackages) {
if (pkg != changingPkg) {
// Only replace for packages on requested volume
final String volumeUuid = getVolumeUuidForPackage(pkg);
final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0)
&& Objects.equals(replaceVolumeUuid, volumeUuid);
restorePermissionState(pkg, replace, changingPkgName, callback);
}
}
}

// 更新当前应用的权限信息
if (changingPkg != null) {
// Only replace for packages on requested volume
final String volumeUuid = getVolumeUuidForPackage(changingPkg);
final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0)
&& Objects.equals(replaceVolumeUuid, volumeUuid);
restorePermissionState(changingPkg, replace, changingPkgName, callback);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}

更新权限信息,来看下授予权限后,修改的数据结构有哪些。
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
private void restorePermissionState(@NonNull PackageParser.Package pkg, boolean replace,
@Nullable String packageOfInterest, @Nullable PermissionCallback callback) {
// IMPORTANT: There are two types of permissions: install and runtime.
// Install time permissions are granted when the app is installed to
// all device users and users added in the future. Runtime permissions
// are granted at runtime explicitly to specific users. Normal and signature
// protected permissions are install time permissions. Dangerous permissions
// are install permissions if the app’s target SDK is Lollipop MR1 or older,
// otherwise they are runtime permissions. This function does not manage
// runtime permissions except for the case an app targeting Lollipop MR1
// being upgraded to target a newer SDK, in which case dangerous permissions
// are transformed from install time to runtime ones.
// 获取此应用的PackageSetting 对象
final PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null) {
return;
}

// permissionsState 包含ArrayMap mPermissions数据结构。
// 代表了申请的每个权限,以及权限的授权状态,授权状态区分用户。
final PermissionsState permissionsState = ps.getPermissionsState();
PermissionsState origPermissions = permissionsState;

final int[] currentUserIds = UserManagerService.getInstance().getUserIds();

boolean runtimePermissionsRevoked = false;
int[] updatedUserIds = EMPTY_INT_ARRAY;

boolean changedInstallPermission = false;
// 将申请的权限复制到permissionsState中
if (replace) {
ps.setInstallPermissionsFixed(false);
if (!ps.isSharedUser()) {
origPermissions = new PermissionsState(permissionsState);
permissionsState.reset();
} else {…}
}
}

synchronized (mLock) {
ArraySet newImplicitPermissions = new ArraySet<>();
// 遍历此应用申请的所有权限
final int N = pkg.requestedPermissions.size();
for (int i = 0; i < N; i++) {
final String permName = pkg.requestedPermissions.get(i);// 申请的权限名称

    final BasePermission bp = mSettings.getPermissionLocked(permName);
    final boolean appSupportsRuntimePermissions =
            pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M;
    String upgradedActivityRecognitionPermission = null;

    if (DEBUG_INSTALL) {
        Log.i(TAG, "Package " + pkg.packageName + " checking " + permName + ": " + bp);
    }

    if (bp == null || bp.getSourcePackageSetting() == null) {
        ...
    }

final String perm = bp.getName();
boolean allowedSig = false;
int grant = GRANT_DENIED;

if (bp.isNormal()) {// 普通权限,安装时就授权
// For all apps normal permissions are install time ones.
grant = GRANT_INSTALL;
} else if (bp.isRuntime()) {// 运行时类型权限,protectionLevel为dangerous
if (origPermissions.hasInstallPermission(bp.getName())
|| upgradedActivityRecognitionPermission != null) {
// Before Q we represented some runtime permissions as install permissions,
// in Q we cannot do this anymore. Hence upgrade them all.
grant = GRANT_UPGRADE;
} else {
// For modern apps keep runtime permissions unchanged.
grant = GRANT_RUNTIME;
}
} else if (bp.isSignature()) {// 需要签名验证的权限,需要跟创建权限的apk权限一样才能授权。
// For all apps signature permissions are install time ones.
allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
if (allowedSig) {// 若验证签名正确,则授予权限,否则grant为默认的GRANT_DENIED
grant = GRANT_INSTALL;
}
}

// 即将对此权限进行授权确认
if (DEBUG_PERMISSIONS) {
Slog.i(TAG, "Considering granting permission " + perm + " to package "
+ pkg.packageName);
}

if (grant != GRANT_DENIED) {

// 根据不同的授权类型,进行不同的授权判断
switch (grant) {
case GRANT_INSTALL: {//安装时授权类型

// 记录更改的用户id
updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);

// 授予权限,其实就是更改PermissionState.mGranted = true;
// Grant an install permission.
if (permissionsState.grantInstallPermission(bp) !=
PERMISSION_OPERATION_FAILURE) {
changedInstallPermission = true;
}
} break;
//运行时权限授权类型,这里需要处理带有hardRestricted 和softRestricted flag的权限
case GRANT_RUNTIME: {
boolean hardRestricted = bp.isHardRestricted();
boolean softRestricted = bp.isSoftRestricted();
} break;

    case GRANT_UPGRADE: {
...

}
} else { // grant == GRANT_DENIED的情况,需要把granted改为false
if (permissionsState.revokeInstallPermission(bp) !=
PERMISSION_OPERATION_FAILURE) {

}
}

// Persist the runtime permissions state for users with changes. If permissions
// were revoked because no app in the shared user declares them we have to
// write synchronously to avoid losing runtime permissions state.
if (callback != null) {// 进行权限改变的持久化操作。
callback.onPermissionUpdated(updatedUserIds, runtimePermissionsRevoked);
}

for (int userId : updatedUserIds) {
notifyRuntimePermissionStateChanged(pkg.packageName, userId);
}
}

5.1.2.授权状态的持久化操作

根据前面的逻辑可知,callback是PackageManagerService里的mPermissionCallback对象,来一起看下权限更新后的持久化逻辑。
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private PermissionCallback mPermissionCallback = new PermissionCallback() {

@Override
public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
synchronized (mPackages) {
// 遍历修改权限所在的用户,修改这些用户下,记录运行时权限的文件
for (int userId : updatedUserIds) {
mSettings.writeRuntimePermissionsForUserLPr(userId, sync);
}
}
}

};

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/Settings.java
public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) {
if (sync) {
mRuntimePermissionsPersistence.writePermissionsForUserSyncLPr(userId);
} else {
mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
}
}

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/Settings.java
@GuardedBy(“Settings.this.mLock”)
public void writePermissionsForUserAsyncLPr(int userId) {
final long currentTimeMillis = SystemClock.uptimeMillis();

if (mWriteScheduled.get(userId)) {
    ...
} else {
    mLastNotWrittenMutationTimesMillis.put(userId, currentTimeMillis);
    Message message = mHandler.obtainMessage(userId);

//延迟200ms,用户应该不会感知到?安装成功到用户使用应该大于200ms吧?
mHandler.sendMessageDelayed(message, WRITE_PERMISSIONS_DELAY_MILLIS);
mWriteScheduled.put(userId, true);
}
}

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/Settings.java
private final class MyHandler extends Handler {
public MyHandler() {
super(BackgroundThread.getHandler().getLooper());
}

@Override
public void handleMessage(Message message) {
    final int userId = message.what;
    Runnable callback = (Runnable) message.obj;
    writePermissionsSync(userId);//在handler里执行此同步方法
    if (callback != null) {
        callback.run();
    }
}

}

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/Settings.java
private void writePermissionsSync(int userId) {
// 保存每个用户对应的权限的路径为/data/system/users/0,10,11等用户id/runtime-permissions.xml

AtomicFile destination = new AtomicFile(getUserRuntimePermissionsFile(userId),
        "package-perms-" + userId);


FileOutputStream out = null; // 通过文件输出流写数据到文件。
try {
out = destination.startWrite();

XmlSerializer serializer = Xml.newSerializer();


final int packageCount = permissionsForPackage.size();
for (int i = 0; i < packageCount; i++) {
String packageName = permissionsForPackage.keyAt(i);
List permissionStates = permissionsForPackage.valueAt(i);
serializer.startTag(null, TAG_PACKAGE);
serializer.attribute(null, ATTR_NAME, packageName);
//在文件中写入此package的permissionStates数据
writePermissions(serializer, permissionStates);
serializer.endTag(null, TAG_PACKAGE);
}

}

// 每个permissionState需要保存以下3个数据,权限名称,授权状态,flag标志。
// 写入item,name,granted和flags标签和数据。
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/Settings.java
private void writePermissions(XmlSerializer serializer,
List permissionStates) throws IOException {
for (PermissionState permissionState : permissionStates) {
serializer.startTag(null, TAG_ITEM);
serializer.attribute(null, ATTR_NAME,permissionState.getName());
serializer.attribute(null, ATTR_GRANTED,
String.valueOf(permissionState.isGranted()));
serializer.attribute(null, ATTR_FLAGS,
Integer.toHexString(permissionState.getFlags()));
serializer.endTag(null, TAG_ITEM);
}
}

至此,非运行时权限安装流程就清楚了!
是在安装阶段,根据权限类型和apk类型,来决定是否要授予此权限,并修改PackageSettings内存中的granted状态,然后持久化到每个用户对应的runtime-permissions.xml文件中。

6.运行时权限授权流程

我们来分析下运行时权限的授权流程。
应用申请运行时权限时,会弹出授权提示框,点击grant(授予、确认授权)即授予此应用的这个权限。

6.1.授权弹窗显示流程

// 应用在一个界面中,申请某个运行时权限
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/core/java/android/app/Activity.java
public final void requestPermissions(@NonNull String[] permissions, int requestCode) {

Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
// intent action为android.content.pm.action.REQUEST_PERMISSIONS
// 且intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions);
// REQUEST_PERMISSIONS_WHO_PREFIX = “@android:requestPermissions:”
startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
mHasCurrentPermissionsRequest = true;
}

跳转到PermissionController app,P之前的版本,是在PackageInstaller app中
/home/chen/disk2/project/aosp/q_aosp/packages/apps/PermissionController/AndroidManifest.xml






/home/chen/disk2/project/aosp/q_aosp/packages/apps/PermissionController/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java

// oncreate中获取申请权限的应用,userId,权限列表
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);

mCallingPackage = getCallingPackage();

mRequestedPermissions = getIntent().getStringArrayExtra(
PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);

mCallingUid = callingPackageInfo.applicationInfo.uid;

}

//用户点击授权按钮时,会调用此方法
@Override
public void onPermissionGrantResult(String name,
@GrantPermissionsViewHandler.Result int result) {

switch (result) {
case GRANTED_ALWAYS :
if (foregroundGroupState != null) {
onPermissionGrantResultSingleState(foregroundGroupState, true, false);
}
if (backgroundGroupState != null) {
onPermissionGrantResultSingleState(backgroundGroupState, true, false);
}
break;

// 处理点击授权的逻辑
private void onPermissionGrantResultSingleState(GroupState groupState, boolean granted,
boolean doNotAskAgain) {
if (groupState != null && groupState.mGroup != null
&& groupState.mState == GroupState.STATE_UNKNOWN) {
if (granted) {
groupState.mGroup.grantRuntimePermissions(doNotAskAgain,
groupState.affectedPermissions);

}

}

/home/chen/disk2/project/aosp/q_aosp/packages/apps/PermissionController/src/com/android/packageinstaller/permission/model/AppPermissionGroup.java
public boolean grantRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) {
boolean killApp = false;
boolean wasAllGranted = true;


if (!mDelayChanges) {
persistChanges(false);// 持久化授予的权限,就是调用pms接口授予权限

    if (killApp) {
        killApp(KILL_REASON_APP_OP_CHANGE);
    }
}

return wasAllGranted;

}

/home/chen/disk2/project/aosp/q_aosp/packages/apps/PermissionController/src/com/android/packageinstaller/permission/model/AppPermissionGroup.java

void persistChanges(boolean mayKillBecauseOfAppOpsChange) {
int uid = mPackageInfo.applicationInfo.uid;

int numPermissions = mPermissions.size();
boolean shouldKillApp = false;

for (int i = 0; i < numPermissions; i++) {
    Permission permission = mPermissions.valueAt(i);

    if (!permission.isSystemFixed()) {
        if (permission.isGranted()) {
            mPackageManager.grantRuntimePermission(mPackageInfo.packageName,
                    permission.getName(), mUserHandle);


}

6.2.PMS授予运行时权限流程

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/core/java/android/app/ApplicationPackageManager.java
@Override
public void grantRuntimePermission(String packageName, String permissionName,
UserHandle user) {
try {
mPM.grantRuntimePermission(packageName, permissionName, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
@Override
public void grantRuntimePermission(String packageName, String permName, final int userId) {
boolean overridePolicy = (checkUidPermission(
Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, Binder.getCallingUid())
== PackageManager.PERMISSION_GRANTED);

mPermissionManager.grantRuntimePermission(permName, packageName, overridePolicy,
        getCallingUid(), userId, mPermissionCallback);

}

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
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;
}
//检查调用者有GRANT_RUNTIME_PERMISSIONS的权限
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
“grantRuntimePermission”);
// 检查调用者有跨用户访问权限
enforceCrossUserPermission(callingUid, userId,
true, // requireFullPermission
true, // checkShell
false, // requirePermissionWhenSameUser
“grantRuntimePermission”);
// 获取package及对应的packageSettings对象
final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
if (pkg == null || pkg.mExtras == null) {
Log.e(TAG, "Unknown package: " + packageName);
return;
}
//检查想要申请的权限对象是否存在
final BasePermission bp;
synchronized(mLock) {
bp = mSettings.getPermissionLocked(permName);
}
if (bp == null) {
throw new IllegalArgumentException("Unknown permission: " + permName);
}

//确认此pkg声明了此权限,且此权限为运行时权限,否则抛出异常
bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);

// 确认pkg的targetSdkVersion 大于等于6.0,因为6.0及以上才支持运行时权限
if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
&& bp.isRuntime()) {
return;
}

//以上检查没有问题后,获取自己PackageSetting里的PermissionsState 对象
final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);

final PackageSetting ps = (PackageSetting) pkg.mExtras;
final PermissionsState permissionsState = ps.getPermissionsState();

// 授予运行时权限,其实就是更改内部对象PermissionData里的mGranted状态为true
final int result = permissionsState.grantRuntimePermission(bp, userId);

if (callback != null) {
callback.onPermissionGranted(uid, userId);
}

}

callback其实就是PackageManagerService中的mPermissionCallback对象,callback.onPermissionGranted(uid, userId)就是去把数据写入到runtime-permissions.xml中,上面已经分析过此流程,这里不再赘述。
至此运行时权限授权流程分析完毕,流程比较简单。

7.检查权限授权状态代码

7.1.检查应用权限方法和流程

检查应用权限,可以调用PackageManager的checkPermission方法。
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/core/java/android/app/ApplicationPackageManager.java
@Override
public int checkPermission(String permName, String pkgName) {
try {
return mPM.checkPermission(permName, pkgName, getUserId());
} catch (RemoteException e) { throw e.rethrowFromSystemServer(); }
}

// 通过pms检查权限此应用的权限,注意运行时权限是区分userId的。
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
@Override
public int checkPermission(String permName, String pkgName, int userId) {
final CheckPermissionDelegate checkPermissionDelegate;
synchronized (mPackages) {
if (mCheckPermissionDelegate == null) {
return checkPermissionImpl(permName, pkgName, userId);
}
checkPermissionDelegate = mCheckPermissionDelegate;
}
return checkPermissionDelegate.checkPermission(permName, pkgName, userId,
PackageManagerService.this::checkPermissionImpl);
}

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private int checkPermissionImpl(String permName, String pkgName, int userId) {
return mPermissionManager.checkPermission(permName, pkgName, getCallingUid(), userId);
}

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@Override
public int checkPermission(String permName, String packageName, int callingUid,
int userId) {
return PermissionManagerService.this.checkPermission(
permName, packageName, callingUid, userId);
}

/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
private int checkPermission(String permName, String pkgName, int callingUid, int userId) {
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
}

final PackageParser.Package pkg = mPackageManagerInt.getPackage(pkgName);
if (pkg != null && pkg.mExtras != null) {
    if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
        return PackageManager.PERMISSION_DENIED;
    }

//根据以上流程,授权状态是保存在每个应用一一对应的PackageSetting对象中。
final PackageSetting ps = (PackageSetting) pkg.mExtras;
final boolean instantApp = ps.getInstantApp(userId);
// 获取存储所有权限状态的PermissionsState对象。
final PermissionsState permissionsState = ps.getPermissionsState();
// 应用声明了此权限,且已授权
if (permissionsState.hasPermission(permName, userId)) {
if (instantApp) {
synchronized (mLock) {
BasePermission bp = mSettings.getPermissionLocked(permName);
if (bp != null && bp.isInstant()) {
// instantApp只能获取声明了instant 保护级别的权限?其他权限无法获取?
return PackageManager.PERMISSION_GRANTED;
}
}
} else {
return PackageManager.PERMISSION_GRANTED;
}
}
if (isImpliedPermissionGranted(permissionsState, permName, userId)) {
return PackageManager.PERMISSION_GRANTED;
}
}

return PackageManager.PERMISSION_DENIED;

}

7.2.PMS中保存授权状态的数据结构

// 在PackageSetting-PermissionsState中,每个权限都有一个PermissionData一一对应。
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionsState.java
public boolean hasPermission(String name, int userId) {
enforceValidUserId(userId);

synchronized (mLock) {
    if (mPermissions == null) {
        return false;
    }

// 获取permission对应的PermissionData 对象。
// private ArrayMap mPermissions;
PermissionData permissionData = mPermissions.get(name);

    return permissionData != null && permissionData.isGranted(userId);
}

}

// permissionData包含了区分用户的SparseArray mUserStates数据。
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionsState.java
public boolean isGranted(int userId) {
if (isInstallPermission()) { // 安装时权限,非运行时权限,则不区分user.
userId = UserHandle.USER_ALL;
}
// 注意区分PermissionsState和PermissionState,只差了一个s字母._.
// private SparseArray mUserStates = new SparseArray<>();
PermissionState userState = mUserStates.get(userId);
if (userState == null) {
return false;
}

return userState.mGranted;

}

// 授权状态Bean类.
/home/chen/disk2/project/aosp/q_aosp/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionsState.java
public static final class PermissionState {
private final String mName;//权限名称
private boolean mGranted;//授权状态
private int mFlags;
……
}

8.PackageParser解析清单文件流程

跟资源打包,AssertManager相关,暂未分析,todo。

9.文章总结

安卓系统中的应用权限功能,提供了一种访问限制的方法,让安卓设备更加安全。
理解权限的设计思路,可以帮助开发人员更好,更合理地设计、声明和使用权限。

你可能感兴趣的:(android,android)