了解PKMS/App中,权限相关知识;精通安卓系统权限相关设计思路,能够进行权限方面功能定制,调查和解决权限相关问题。
本文主要介绍权限相关内容,主要包含以下几部分:
权限创建流程
权限分类
非运行时权限授权流程
运行时权限授权流程
重置运行时权限流程
常用的权限调查命令
调查framework-re.apk安装过程中,创建权限相关流程;
根据代码确认权限分类;
调查非运行时权限授权流程;
应用申请Camera权限,调查运行时权限授予流程;
Settings应用取消Camera授权,跟进取消授权流程;
本章节包含权限分类,授权流程图示等内容
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"字符串:
“此应用可随时使用相机拍摄照片和录制视频”
未定义时,默认的权限组:
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" />
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" />
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" />
权限类型 举例 说明
dangerous
signature
privileged
Instant
runtime
normal
appop
setup
documenter
……
protectionLevel描述:
/**
Each protection level consists of a base permission type and zero or
Must be one or more (separated by '|') of the following constant values.
权限授权状态,保存在system_server进程中的PackageManagerService相关数据结构中。
每个应用程序在PackageManagerService中,都有唯一一个PackageSetting对象,保存了应用的数据,包括应用的权限授权状态。
以下是应用程序检查授权状态流程图:
应用程序申请权限时,系统应用弹出授权提示框界面,提醒用户是否要授予对应权限。
这里弹出授权提示框的系统应用,在安卓9及之前,是PackageInstaller.apk,新的安卓版本,是PermissionController.apk程序。
用户点击授权按钮,调用PackageManagerService接口,修改此应用的授权状态。
非运行时权限授权状态,是在应用安装阶段就确定了的,不给用户提供可以修改的途径。
应用安装阶段,根据应用安装位置、应用签名、应用sharedUserId属性、应用目标版本、被重新安装应用的授权状态等信息,来决定非运行时权限的授权状态。
以下是应用安装阶段,修改应用授权状态的代码调用时序图:
这里介绍了常见权限相关问题的调查方法和思路。
我们在申请某个权限时,通常需要关注此权限的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,才能获取此权限。
通过以下命令,可以看到某个应用的权限情况,如创建权限的情况,声明权限情况,权限授予情况等信息:
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数据代表此权限已授予;
可以通过以下命令,授予运行时权限,也可以添加–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权限!
可以通过以下命令,授予某个应用获取的运行时权限,注意此命令无法指定权限来取消授权,只能全部恢复为安装时的未授权状态:
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]
PackageManagerService的构造函数中,会扫描系统apk并识别系统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);
}
}
}
}
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)
/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
/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方法后续流程,是如何保存创建的权限的。
以下流程会执行应用安装流程,我们直接去看安装流程中跟权限相关内容。
先看保存到内中的相关处理:
/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 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
// 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。
到这里我们已经了解了权限创建流程和创建的对象。
安装应用的最后流程-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));
…
}
权限授权流程分为两部分,非运行时权限和运行时权限授权流程。
非运行时权限授权流程如下,在安装完成后进行授权。
我们知道非运行时权限不是动态的,是在应用安装过程中,就确认下来的。
来看下安装过程中的授权流程:
@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
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
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
// 代表了申请的每个权限,以及权限的授权状态,授权状态区分用户。
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);
}
}
根据前面的逻辑可知,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文件中。
我们来分析下运行时权限的授权流程。
应用申请运行时权限时,会弹出授权提示框,点击grant(授予、确认授权)即授予此应用的这个权限。
// 应用在一个界面中,申请某个运行时权限
/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);
…
}
/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中,上面已经分析过此流程,这里不再赘述。
至此运行时权限授权流程分析完毕,流程比较简单。
检查应用权限,可以调用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;
}
// 在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
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;
……
}
跟资源打包,AssertManager相关,暂未分析,todo。
安卓系统中的应用权限功能,提供了一种访问限制的方法,让安卓设备更加安全。
理解权限的设计思路,可以帮助开发人员更好,更合理地设计、声明和使用权限。