PMS系列:
1、PackageManagerService服務(wù)框架詳解
2滴劲、PackageManagerService啟動(dòng)分析
3、PackageManagerService之a(chǎn)pp數(shù)據(jù)類(Settings)分析
4、PackageManagerService掃描安裝apk詳解
5、本文PackageManagerService根據(jù)權(quán)限等級(jí)管理權(quán)限(默認(rèn)賦予apk權(quán)限)
android權(quán)限管理分為兩種:
SDK<23:在manifest中聲明寸潦,安裝時(shí)賦予所有聲明權(quán)限,不同意則不安裝社痛;
SDK>=23:1见转、普通權(quán)限、聲明即可直接賦予蒜哀,不會(huì)在設(shè)置中顯示給客戶池户;
2、危險(xiǎn)權(quán)限和特殊權(quán)限凡怎,需要聲明且發(fā)送請求用戶授權(quán)的intent,可自由開關(guān)每個(gè)權(quán)限赊抖;
以下主要針對SDK>=23
系統(tǒng)中的定義權(quán)限位置在:
framework/base/core/res/AndroidManifest.xml
framework/base/data/etc/platform.xml
一统倒、權(quán)限級(jí)別(ProtectionLevel)
<permission android:name="android.permission.SEND_SMS"
android:permissionGroup="android.permission-group.COST_MONEY"
android:protectionLevel="dangerous"
android:label="@string/permlab_sendSms"
android:description="@string/permdesc_sendSms" />
protectionLevel定義了權(quán)限的級(jí)別
1.Normal
2.Dangerous
3.Signature
4.SignatureOrSystem
1.1 Normal
android:protectionLevel="normal"
對用戶隱私或者安全都不會(huì)帶來影響
1.2 Dangerous
android:protectionLevel="dangerous"
需要在mainifest中聲明且發(fā)送請求用戶授權(quán)的intent,賦予某個(gè)組中的其中一個(gè)權(quán)限氛雪,自動(dòng)賦予組內(nèi)其他所有權(quán)限房匆;
可用命令adb shell pm list permissions -d -g查看
1.3 Signature
android:protectionLevel="signature"
兩類應(yīng)用可使用
1.只有和定義了這個(gè)權(quán)限的apk用相同的私鑰簽名的應(yīng)用才可以申請?jiān)摍?quán)限
2.與系統(tǒng)簽名相同的system app,即與廠商簽名(廠商ROM中的系統(tǒng)app簽名)相同的app
1.4 SignatureOrSystem
android:protectionLevel="signature|privileged"
三類應(yīng)用可使用
1.只有和定義了這個(gè)權(quán)限的apk用相同的私鑰簽名的應(yīng)用才可以申請?jiān)摍?quán)限
2.與系統(tǒng)簽名相同的app报亩,即與廠商簽名(廠商ROM中的系統(tǒng)app簽名)相同的app
3.任意app只要標(biāo)記了privileged(可暫理解為放到了/system/priv-app)就可以使用signatureOrSystem級(jí)別的權(quán)限
1.5 install權(quán)限和runtime權(quán)限
install權(quán)限:
安裝時(shí)權(quán)限浴鸿,是指在安裝app的時(shí)候,賦予app的權(quán)限弦追。normal和signature級(jí)別(包括SignatureOrSystem)的權(quán)限都是安裝時(shí)權(quán)限岳链。不會(huì)給用戶提示界面,系統(tǒng)自動(dòng)決定權(quán)限的賦予或拒絕劲件。
runtime權(quán)限:
運(yùn)行時(shí)權(quán)限掸哑,是指在app運(yùn)行過程中约急,賦予app的權(quán)限。這個(gè)過程中苗分,會(huì)顯示明顯的權(quán)限授予界面厌蔽,讓用戶決定是否授予權(quán)限。dangerous權(quán)限就是運(yùn)行時(shí)權(quán)限摔癣。(以下主要針對SDK<23時(shí)dangerous權(quán)限就變成了install權(quán)限)
二奴饮、app種類
1、system app (有ApplicationInfo.FLAG_SYSTEM標(biāo)記)
2择浊、privileged app (有ApplicationInfo.FLAG_SYSTEM和ApplicationInfo.PRIVATE_FLAG_PRIVILEGE兩個(gè)標(biāo)記)
2.1 system app
system app 定義很明了戴卜,就是在PMS初始化安裝app的時(shí)候賦予了ApplicationInfo.FLAG_SYSTEM這個(gè)標(biāo)記
1、特定shareUID的app
代碼在PMS的構(gòu)造函數(shù)中
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
2近她、掃描安裝特定目錄的app
代碼在PMS的構(gòu)造函數(shù)中叉瘩,掃描安裝時(shí)給予PackageParser.PARSE_IS_SYSTEM標(biāo)記的app,例如/vendor/overlay粘捎,/system/framework薇缅,/system/priv-app,/system/app攒磨,/vendor/app泳桦,/oem/app等,給予的PackageParser.PARSE_IS_SYSTEM最終會(huì)轉(zhuǎn)換為ApplicationInfo.FLAG_SYSTEM娩缰,部分代碼如下
File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
scanDirTracedLI(vendorOverlayDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
File customFrameworkDir = new File("/custom/framework");
scanDirLI(customFrameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags | SCAN_NO_DEX, 0);
scanDirTracedLI(frameworkDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);
flag轉(zhuǎn)換的過程大致如下
-> scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime)
-> scanPackageTracedLI(PackageParser.Package pkg, final int policyFlags,
int scanFlags, long currentTime, UserHandle user)
-> scanPackageLI(PackageParser.Package pkg, final int policyFlags,
int scanFlags, long currentTime, UserHandle user)
-> scanPackageDirtyLI(PackageParser.Package pkg,
final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
//在scanPackageDirtyLI方法中將flag轉(zhuǎn)換
// Apply policy
if ((policyFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
...
}
2.2 privileged app
privileged app在ApplicationInfo.FLAG_SYSTEM基礎(chǔ)上還必須有ApplicationInfo.PRIVATE_FLAG_PRIVILEGED標(biāo)記
1灸撰、特定shareUID的app
特定shareUID的app有ApplicationInfo.FLAG_SYSTEM的同時(shí)都有ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
2、掃描特定目錄app時(shí)拼坎,給予了PackageParser.PARSE_IS_SYSTEM標(biāo)記和PackageParser.PARSE_IS_PRIVILEGED標(biāo)記浮毯,目錄有三個(gè):system/framework,system/priv-app,vendor/priv-app
例如:
//vender/framework目錄下有PackageParser.PARSE_IS_SYSTEM沒有PackageParser.PARSE_IS_PRIVILEGED標(biāo)記
File vendorFrameworkDir = new File(Environment.getVendorDirectory(), "framework");
scanDirTracedLI(vendorFrameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags | SCAN_NO_DEX, 0);
//system/framework目錄下兩個(gè)標(biāo)記都有
scanDirTracedLI(frameworkDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);
PackageParser.PARSE_IS_PRIVILEGED也是在scanPackageDirtyLI方法中轉(zhuǎn)換的
if ((policyFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
三、PMS賦予apk的runtime權(quán)限
3.1 入口
PMS(PackageManagerService)在SystemServer中初始化完成最后調(diào)用PMS::systemReady,在systemReady方法中開始授予默認(rèn)權(quán)限
final DefaultPermissionGrantPolicy mDefaultPermissionPolicy;
for (int userId : grantPermissionsUserIds) {
mDefaultPermissionPolicy.grantDefaultPermissions(userId);
}
DefaultPermissionGrantPolicy這個(gè)類就是管理默認(rèn)權(quán)限的泰鸡,最終的實(shí)現(xiàn)都是在PMS代碼中
public void grantDefaultPermissions(int userId) {
// 系統(tǒng)組件賦予Dangerous權(quán)限
grantPermissionsToSysComponentsAndPrivApps(userId);
// 指定app的指定權(quán)限
grantDefaultSystemHandlerPermissions(userId);
}
3.2 系統(tǒng)組件賦予Dangerous權(quán)限
private void grantPermissionsToSysComponentsAndPrivApps(int userId) {
Log.i(TAG, "Granting permissions to platform components for user " + userId);
synchronized (mService.mPackages) {
for (PackageParser.Package pkg : mService.mPackages.values()) {
// 過濾掉privileged app , FLAG_PERSISTENT標(biāo)記app ,系統(tǒng)簽名相同的app
if (!isSysComponentOrPersistentPlatformSignedPrivAppLPr(pkg)
// 判斷targetSdkVersion > 22
|| !doesPackageSupportRuntimePermissions(pkg)
// 請求權(quán)限列表為空
|| pkg.requestedPermissions.isEmpty()) {
continue;
}
Set<String> permissions = new ArraySet<>();
final int permissionCount = pkg.requestedPermissions.size();
for (int i = 0; i < permissionCount; i++) {
String permission = pkg.requestedPermissions.get(i);
BasePermission bp = mService.mSettings.mPermissions.get(permission);
// 權(quán)限為Dangerous權(quán)限
if (bp != null && bp.isRuntime()) {
permissions.add(permission);
}
}
if (!permissions.isEmpty()) {
// 添加權(quán)限
grantRuntimePermissionsLPw(pkg, permissions, true, userId);
}
}
}
}
接下來看下isSysComponentOrPersistentPlatformSignedPrivAppLPr和isRuntime的內(nèi)容
private boolean isSysComponentOrPersistentPlatformSignedPrivAppLPr(PackageParser.Package pkg) {
// UserID 小于10000
if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
return true;
}
// privileged app過濾
if (!pkg.isPrivilegedApp()) {
return false;
}
// 這兩個(gè)判斷過濾掉FLAG_PERSISTENT
PackageSetting sysPkg = mService.mSettings.getDisabledSystemPkgLPr(pkg.packageName);
if (sysPkg != null && sysPkg.pkg != null) {
if ((sysPkg.pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
return false;
}
} else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
return false;
}
// 過濾掉系統(tǒng)簽名相同的apk
return PackageManagerService.compareSignatures(mService.mPlatformPackage.mSignatures,
pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
}
public boolean isRuntime() {
// protectionLevel & PermissionInfo.PROTECTION_MASK_BASE 表示當(dāng)前等級(jí)
return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
== PermissionInfo.PROTECTION_DANGEROUS;
}
3.3 指定app的指定權(quán)限
這里是給指定某個(gè)app,給予它指定的幾個(gè)權(quán)限债蓝,這里的代碼十分類似,截取片段如下
private void grantDefaultSystemHandlerPermissions(int userId) {
...
// Dialer
if (dialerAppPackageNames == null) {
Intent dialerIntent = new Intent(Intent.ACTION_DIAL);
PackageParser.Package dialerPackage = getDefaultSystemHandlerActivityPackageLPr(
dialerIntent, userId);
if (dialerPackage != null) {
grantDefaultPermissionsToDefaultSystemDialerAppLPr(dialerPackage, userId);
}
} else {
for (String dialerAppPackageName : dialerAppPackageNames) {
PackageParser.Package dialerPackage = getSystemPackageLPr(dialerAppPackageName);
if (dialerPackage != null) {
grantDefaultPermissionsToDefaultSystemDialerAppLPr(dialerPackage, userId);
}
}
}
// SMS
if (smsAppPackageNames == null) {
Intent smsIntent = new Intent(Intent.ACTION_MAIN);
smsIntent.addCategory(Intent.CATEGORY_APP_MESSAGING);
PackageParser.Package smsPackage = getDefaultSystemHandlerActivityPackageLPr(
smsIntent, userId);
if (smsPackage != null) {
grantDefaultPermissionsToDefaultSystemSmsAppLPr(smsPackage, userId);
}
} else {
for (String smsPackageName : smsAppPackageNames) {
PackageParser.Package smsPackage = getSystemPackageLPr(smsPackageName);
if (smsPackage != null) {
grantDefaultPermissionsToDefaultSystemSmsAppLPr(smsPackage, userId);
}
}
}
...
}
private void grantDefaultPermissionsToDefaultSystemDialerAppLPr(
PackageParser.Package dialerPackage, int userId) {
if (doesPackageSupportRuntimePermissions(dialerPackage)) {
boolean isPhonePermFixed =
mService.hasSystemFeature(PackageManager.FEATURE_WATCH, 0);
grantRuntimePermissionsLPw(
dialerPackage, PHONE_PERMISSIONS, isPhonePermFixed, userId);
grantRuntimePermissionsLPw(dialerPackage, CONTACTS_PERMISSIONS, userId);
grantRuntimePermissionsLPw(dialerPackage, SMS_PERMISSIONS, userId);
grantRuntimePermissionsLPw(dialerPackage, MICROPHONE_PERMISSIONS, userId);
}
}
兩種添加最后都走到了grantRuntimePermissionsLPw盛龄,我們接著分析grantRuntimePermissionsLPw函數(shù)
3.4 添加權(quán)限grantRuntimePermissionsLPw
grantRuntimePermissionsLPw賦予權(quán)限的代碼,最終是交給PMS來處理饰迹,經(jīng)過一些列判斷后調(diào)用關(guān)鍵方法mService.grantRuntimePermission和mService.updatePermissionFlags,代碼片段如下
private final PackageManagerService mService;
private void grantRuntimePermissionsLPw(PackageParser.Package pkg, Set<String> permissions,
boolean systemFixed, boolean isDefaultPhoneOrSms, int userId) {
...
mService.grantRuntimePermission(pkg.packageName, permission, userId);
...
mService.updatePermissionFlags(permission, pkg.packageName,
newFlags, newFlags, userId);
...
}
接著看PMS的grantRuntimePermission如何添加權(quán)限
public void grantRuntimePermission(String packageName, String name, final int userId) {
...
// 要添加權(quán)限余舶,也需要“添加”權(quán)限
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
"grantRuntimePermission");
enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, true /* checkShell */,
"grantRuntimePermission");
...
// 添加權(quán)限
final int result = permissionsState.grantRuntimePermission(bp, userId);
switch (result) {
case PermissionsState.PERMISSION_OPERATION_FAILURE: {
return;
}
case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
mHandler.post(new Runnable() {
@Override
public void run() {
killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED);
}
});
}
break;
}
// PermissionsChanged監(jiān)聽
mOnPermissionChangeListeners.onPermissionsChanged(uid);
// 把數(shù)據(jù)更新到runtime-permissions.xml中
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
最后grantRuntimePermission就是把permission存到mPermissions數(shù)據(jù)map中啊鸭,再把數(shù)據(jù)跟新到/data/system/users/0/runtime-permissions.xml中,片段如下
<pkg name="com.google.android.apps.messaging">
<item name="android.permission.READ_SMS" granted="true" flags="20" />
<item name="android.permission.RECEIVE_WAP_PUSH" granted="true" flags="20" />
<item name="android.permission.RECEIVE_MMS" granted="true" flags="20" />
<item name="android.permission.RECEIVE_SMS" granted="true" flags="20" />
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="20" />
<item name="android.permission.SEND_SMS" granted="true" flags="20" />
<item name="android.permission.CALL_PHONE" granted="true" flags="20" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="20" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="20" />
</pkg>
<pkg name="com.google.android.setupwizard">
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="20" />
<item name="android.permission.CALL_PHONE" granted="true" flags="20" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="20" />
<item name="android.permission.CAMERA" granted="true" flags="20" />
<item name="android.permission.PROCESS_OUTGOING_CALLS" granted="true" flags="20" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="20" />
</pkg>
四匿值、PMS賦予apk安裝權(quán)限
過程精簡如下:
-> scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime)
-> scanPackageTracedLI(PackageParser.Package pkg, final int policyFlags,
int scanFlags, long currentTime, UserHandle user)
-> scanPackageLI(PackageParser.Package pkg, final int policyFlags,
int scanFlags, long currentTime, UserHandle user)
-> scanPackageDirtyLI(PackageParser.Package pkg,
final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
-> updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
int[] allUsers, PackageInstalledInfo res, UserHandle user)
-> updateSettingsInternalLI(PackageParser.Package newPackage,
String installerPackageName, int[] allUsers, int[] installedForUsers,
PackageInstalledInfo res, UserHandle user)
-> updatePermissionsLPw(String changingPkg, PackageParser.Package pkgInfo,
int flags)
-> updatePermissionsLPw(String changingPkg,
PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags)
-> grantPermissionsLPw(PackageParser.Package pkg, boolean replace,
String packageOfInterest)
在grantPermissionsLPw函數(shù)中做最后權(quán)限賦予操作赠制,代碼片段如下:
private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace,
String packageOfInterest) {
for (int i=0; i<N; i++) {
final String name = pkg.requestedPermissions.get(i); // 權(quán)限名字
final BasePermission bp = mSettings.mPermissions.get(name); // 權(quán)限信息
...
final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE; // 權(quán)限級(jí)別ProtectionLevel
final boolean appSupportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
>= Build.VERSION_CODES.M;
// 根據(jù)權(quán)限級(jí)別定義grant
switch (level) {
case PermissionInfo.PROTECTION_NORMAL: {
// For all apps normal permissions are install time ones.
grant = GRANT_INSTALL;
} break;
case PermissionInfo.PROTECTION_DANGEROUS: {
if (!appSupportsRuntimePermissions && !Build.isPermissionReviewRequired()) {
// For legacy apps dangerous permissions are install time ones.
grant = GRANT_INSTALL;
} else if (origPermissions.hasInstallPermission(bp.name)) {
// For legacy apps that became modern, install becomes runtime.
grant = GRANT_UPGRADE;
} else if (mPromoteSystemApps
&& isSystemApp(ps)
&& mExistingSystemPackages.contains(ps.name)) {
// For legacy system apps, install becomes runtime.
// We cannot check hasInstallPermission() for system apps since those
// permissions were granted implicitly and not persisted pre-M.
grant = GRANT_UPGRADE;
} else {
// For modern apps keep runtime permissions unchanged.
grant = GRANT_RUNTIME;
}
} break;
case PermissionInfo.PROTECTION_SIGNATURE: {
// For all apps signature permissions are install time ones.
allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
if (allowedSig) {
grant = GRANT_INSTALL;
}
} break;
}
...
if (grant != GRANT_DENIED) {
if (!isSystemApp(ps) && ps.installPermissionsFixed) {
// If this is an existing, non-system package, then
// we can't add any new permissions to it.
if (!allowedSig && !origPermissions.hasInstallPermission(perm)) {
// Except... if this is a permission that was added
// to the platform (note: need to only do this when
// updating the platform).
if (!isNewPlatformPermissionForPackage(perm, pkg)) {
grant = GRANT_DENIED;
}
}
}
// 根據(jù)grant 選擇權(quán)限給予方式
switch (grant) {
case GRANT_INSTALL: {
for (int userId : UserManagerService.getInstance().getUserIds()) {
if (origPermissions.getRuntimePermissionState(
bp.name, userId) != null) {
// Revoke the runtime permission and clear the flags.
origPermissions.revokeRuntimePermission(bp, userId);
origPermissions.updatePermissionFlags(bp, userId,
PackageManager.MASK_PERMISSION_FLAGS, 0);
// If we revoked a permission permission, we have to write.
changedRuntimePermissionUserIds = ArrayUtils.appendInt(
changedRuntimePermissionUserIds, userId);
}
}
// install權(quán)限
if (permissionsState.grantInstallPermission(bp) !=
PermissionsState.PERMISSION_OPERATION_FAILURE) {
changedInstallPermission = true;
}
} break;
case GRANT_RUNTIME: {
// Grant previously granted runtime permissions.
for (int userId : UserManagerService.getInstance().getUserIds()) {
PermissionState permissionState = origPermissions
.getRuntimePermissionState(bp.name, userId);
int flags = permissionState != null
? permissionState.getFlags() : 0;
if (origPermissions.hasRuntimePermission(bp.name, userId)) {
if (permissionsState.grantRuntimePermission(bp, userId) ==
PermissionsState.PERMISSION_OPERATION_FAILURE) {
// If we cannot put the permission as it was, we have to write.
changedRuntimePermissionUserIds = ArrayUtils.appendInt(
changedRuntimePermissionUserIds, userId);
}
// If the app supports runtime permissions no need for a review.
/// M: CTA requirement - permission control
if (Build.isPermissionReviewRequired()
&& appSupportsRuntimePermissions
&& (flags & PackageManager
.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
flags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
// Since we changed the flags, we have to write.
changedRuntimePermissionUserIds = ArrayUtils.appendInt(
changedRuntimePermissionUserIds, userId);
}
/// M: CTA requirement - permission control
} else if (Build.isPermissionReviewRequired()
&& !appSupportsRuntimePermissions) {
if (CtaUtils.isPlatformPermission(bp.sourcePackage, bp.name)
&& pkgReviewRequired) {
if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
/// M: CTA requirement - review UI for all apps @{
Slog.d(TAG, "add review UI for legacy pkg = " +
pkg.packageName + ", permission = " +
bp.name + ", userId = " + userId +
", uid = " + pkg.mSharedUserId);
///@}
flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
// We changed the flags, hence have to write.
changedRuntimePermissionUserIds = ArrayUtils.appendInt(
changedRuntimePermissionUserIds, userId);
}
}
// runtime權(quán)限
if (permissionsState.grantRuntimePermission(bp, userId)
!= PermissionsState.PERMISSION_OPERATION_FAILURE) {
// We changed the permission, hence have to write.
changedRuntimePermissionUserIds = ArrayUtils.appendInt(
changedRuntimePermissionUserIds, userId);
}
/// M: CTA requirement - review UI for all apps @{
} else if (appSupportsRuntimePermissions &&
pkgReviewRequired) {
if (CtaUtils.isPlatformPermission(bp.sourcePackage, bp.name)) {
if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0 &&
(flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)
== 0) {
Slog.d(TAG, "add review UI for non-legacy pkg = " +
pkg.packageName + ", permission = " +
bp.name + ", userId = " + userId +
", uid = " + pkg.mSharedUserId);
flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
// We changed the flags, hence have to write.
changedRuntimePermissionUserIds = ArrayUtils.appendInt(
changedRuntimePermissionUserIds, userId);
}
}
}
///@}
// Propagate the permission flags.
permissionsState.updatePermissionFlags(bp, userId, flags, flags);
}
} break;
case GRANT_UPGRADE: {
// Grant runtime permissions for a previously held install permission.
PermissionState permissionState = origPermissions
.getInstallPermissionState(bp.name);
final int flags = permissionState != null ? permissionState.getFlags() : 0;
if (origPermissions.revokeInstallPermission(bp)
!= PermissionsState.PERMISSION_OPERATION_FAILURE) {
// 跟新應(yīng)用的權(quán)限
origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL,
PackageManager.MASK_PERMISSION_FLAGS, 0);
changedInstallPermission = true;
}
// If the permission runtime-permissions.xmlis not to be promoted to runtime we ignore it and
// also its other flags as they are not applicable to install permissions.
if ((flags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) == 0) {
for (int userId : currentUserIds) {
if (permissionsState.grantRuntimePermission(bp, userId) !=
PermissionsState.PERMISSION_OPERATION_FAILURE) {
// Transfer the permission flags.
permissionsState.updatePermissionFlags(bp, userId,
flags, flags);
// If we granted the permission, we have to write.
changedRuntimePermissionUserIds = ArrayUtils.appendInt(
changedRuntimePermissionUserIds, userId);
}
}
}
} break;
default: {
if (packageOfInterest == null
|| packageOfInterest.equals(pkg.packageName)) {
Slog.w(TAG, "Not granting permission " + perm
+ " to package " + pkg.packageName
+ " because it was previously installed without");
}
} break;
}
} else {
if (permissionsState.revokeInstallPermission(bp) !=
PermissionsState.PERMISSION_OPERATION_FAILURE) {
// Also drop the permission flags.
permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
PackageManager.MASK_PERMISSION_FLAGS, 0);
changedInstallPermission = true;
Slog.i(TAG, "Un-granting permission " + perm
+ " from package " + pkg.packageName
+ " (protectionLevel=" + bp.protectionLevel
+ " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ ")");
} else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) {
// Don't print warning for app op permissions, since it is fine for them
// not to be granted, there is a UI for the user to decide.
if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
Slog.w(TAG, "Not granting permission " + perm
+ " to package " + pkg.packageName
+ " (protectionLevel=" + bp.protectionLevel
+ " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ ")");
}
}
}
}
if ((changedInstallPermission || replace) && !ps.installPermissionsFixed &&
!isSystemApp(ps) || isUpdatedSystemApp(ps)){
// This is the first that we have heard about this package, so the
// permissions we have now selected are fixed until explicitly
// changed.
ps.installPermissionsFixed = true;
}
// 把runtime權(quán)限跟新到runtime-permissions.xml中
for (int userId : changedRuntimePermissionUserIds) {
mSettings.writeRuntimePermissionsForUserLPr(userId, runtimePermissionsRevoked);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
grantPermissionsLPw函數(shù)根據(jù)權(quán)限等級(jí),來賦予權(quán)限挟憔。注意:這里的安裝時(shí)賦予的runtime權(quán)限是之前已經(jīng)賦予過此apk的權(quán)限才會(huì)執(zhí)行到GRANT_RUNTIME
回到上面的精簡過程:
updateSettingsInternalLI方法中調(diào)用updatePermissionsLPw后憎妙,最后會(huì)調(diào)用mSettings.writeLPr();
這些權(quán)限信息就被寫到data/system/packages.xml中了库正,舉例片段代碼:
...
<package name="com.android.settings" codePath="/system/priv-app/Settings" nativeLibraryPath="/system/priv-app/Settings/lib" primaryCpuAbi="arm64-v8a" publicFlags="944258629" privateFlags="8" ft="15f7a5ec8a8" it="15f7a5ec8a8" ut="15f7a5ec8a8" version="25" sharedUserId="1000" isOrphaned="true">
<sigs count="1">
<cert index="1" />
</sigs>
<perms>
<item name="android.permission.BIND_INCALL_SERVICE" granted="true" flags="0" />
<item name="android.permission.WRITE_SETTINGS" granted="true" flags="0" />
<item name="com.google.android.gm.permission.WRITE_GMAIL" granted="true" flags="0" />
<item name="android.permission.CONFIGURE_WIFI_DISPLAY" granted="true" flags="0" />
<item name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE" granted="true" flags="0" />
<item name="android.permission.ACCESS_WIMAX_STATE" granted="true" flags="0" />
<item name="com.qualcomm.permission.READPROC" granted="true" flags="0" />
<item name="android.permission.RESTART_PACKAGES" granted="true" flags="0" />
<item name="android.permission.USE_CREDENTIALS" granted="true" flags="0" />
<item name="android.permission.MODIFY_AUDIO_SETTINGS" granted="true" flags="0" />
<item name="android.permission.ACCESS_CHECKIN_PROPERTIES" granted="true" flags="0" />
<item name="android.permission.MODIFY_AUDIO_ROUTING" granted="true" flags="0" />
...
五、小結(jié)
1厘唾、PMS掃描安裝時(shí)賦予安裝權(quán)限
2褥符、PMS在systemReady函數(shù)中調(diào)用mDefaultPermissionPolicy.grantDefaultPermissions來賦予運(yùn)行權(quán)限即dangerous權(quán)限
權(quán)限的等級(jí)劃分,大大的提高了安卓的安全抚垃,比以往的一刀切著實(shí)好了很多喷楣。
Read the fucking sources code!