ManagePermissionsActivity
package com.android.packageinstaller.permission.ui;
import android.app.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.Window;
import android.view.WindowManager;
import com.android.packageinstaller.DeviceUtils;
import com.android.packageinstaller.permission.ui.handheld.ManageStandardPermissionsFragment;
import com.android.packageinstaller.permission.ui.wear.AppPermissionsFragmentWear;
public final class ManagePermissionsActivity extends OverlayTouchActivity {
private static final String LOG_TAG = "ManagePermissionsActivity";
public static final String EXTRA_ALL_PERMISSIONS =
"com.android.packageinstaller.extra.ALL_PERMISSIONS";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//重新设置Window属性
Window window = getWindow();
WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.height = 750;
layoutParams.gravity = Gravity.CENTER;
layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
window.setAttributes(layoutParams);
if (savedInstanceState != null) {
return;
}
//这里fragement的赋值其实是工厂模式
Fragment fragment;
String action = getIntent().getAction();
switch (action) {
case Intent.ACTION_MANAGE_PERMISSIONS: {
if (DeviceUtils.isTelevision(this)) {
fragment = com.android.packageinstaller.permission.ui.television
.ManagePermissionsFragment.newInstance();
} else {
fragment = ManageStandardPermissionsFragment.newInstance();
}
} break;
case Intent.ACTION_MANAGE_APP_PERMISSIONS: {
String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
if (packageName == null) {
Log.i(LOG_TAG, "Missing mandatory argument EXTRA_PACKAGE_NAME");
finish();
return;
}
if (DeviceUtils.isWear(this)) {
fragment = AppPermissionsFragmentWear.newInstance(packageName);
} else if (DeviceUtils.isTelevision(this)) {
//tv应用管理中的权限管理会进入这里,初始化一个AppPermissionsFragment
fragment = com.android.packageinstaller.permission.ui.television
.AppPermissionsFragment.newInstance(packageName);
} else {
final boolean allPermissions = getIntent().getBooleanExtra(
EXTRA_ALL_PERMISSIONS, false);
if (allPermissions) {
fragment = com.android.packageinstaller.permission.ui.handheld
.AllAppPermissionsFragment.newInstance(packageName);
} else {
fragment = com.android.packageinstaller.permission.ui.handheld
.AppPermissionsFragment.newInstance(packageName);
}
}
} break;
case Intent.ACTION_MANAGE_PERMISSION_APPS: {
String permissionName = getIntent().getStringExtra(Intent.EXTRA_PERMISSION_NAME);
if (permissionName == null) {
Log.i(LOG_TAG, "Missing mandatory argument EXTRA_PERMISSION_NAME");
finish();
return;
}
if (DeviceUtils.isTelevision(this)) {
fragment = com.android.packageinstaller.permission.ui.television
.PermissionAppsFragment.newInstance(permissionName);
} else {
fragment = com.android.packageinstaller.permission.ui.handheld
.PermissionAppsFragment.newInstance(permissionName);
}
} break;
default: {
Log.w(LOG_TAG, "Unrecognized action " + action);
finish();
return;
}
}
getFragmentManager().beginTransaction().replace(android.R.id.content, fragment).commit();//将初始化的fragment替换content的位置
}
}
AppPermissionsFragment下面分析,先分析一下几个类
Permission类,表示一个权限的类
package com.android.packageinstaller.permission.model;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
public final class Permission {
//几个Permission的重要属性
private final String mName;//Permission的name
private final String mAppOp;//这个没弄懂
private boolean mGranted;//Permission是否被授权
private boolean mAppOpAllowed;//这个没弄懂
private int mFlags;//一种标志位,能够获取权限的更多属性信息
private boolean mIsEphemeral;//是不是短暂的
private boolean mIsRuntimeOnly;//是不是只是运行时的
public Permission(String name, boolean granted,
String appOp, boolean appOpAllowed, int flags, int protectionLevel) {
//构造方法就是给属性值赋值
mName = name;
mGranted = granted;
mAppOp = appOp;
mAppOpAllowed = appOpAllowed;
mFlags = flags;
mIsEphemeral = (protectionLevel & PermissionInfo.PROTECTION_FLAG_EPHEMERAL) != 0;
mIsRuntimeOnly = (protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0;
}
public String getName() {
return mName;
}
public String getAppOp() {
return mAppOp;
}
public int getFlags() {
return mFlags;
}
public boolean hasAppOp() {
return mAppOp != null;
}
public boolean isGranted() {
return mGranted;
}
public boolean isReviewRequired() {
return (mFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
}
public void resetReviewRequired() {
mFlags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
}
public void setGranted(boolean mGranted) {
this.mGranted = mGranted;
}
public boolean isAppOpAllowed() {
return mAppOpAllowed;
}
public boolean isUserFixed() {
return (mFlags & PackageManager.FLAG_PERMISSION_USER_FIXED) != 0;
}
public void setUserFixed(boolean userFixed) {
if (userFixed) {
mFlags |= PackageManager.FLAG_PERMISSION_USER_FIXED;
} else {
mFlags &= ~PackageManager.FLAG_PERMISSION_USER_FIXED;
}
}
public boolean isSystemFixed() {//是不是系统固定的权限
return (mFlags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0;
}
public boolean isPolicyFixed() {
return (mFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0;
}
public boolean isUserSet() {
return (mFlags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
}
public boolean isGrantedByDefault() {
return (mFlags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0;
}
public void setUserSet(boolean userSet) {
if (userSet) {
mFlags |= PackageManager.FLAG_PERMISSION_USER_SET;
} else {
mFlags &= ~PackageManager.FLAG_PERMISSION_USER_SET;
}
}
public void setPolicyFixed(boolean policyFixed) {
if (policyFixed) {
mFlags |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
} else {
mFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
}
}
public boolean shouldRevokeOnUpgrade() {
return (mFlags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;
}
public void setRevokeOnUpgrade(boolean revokeOnUpgrade) {
if (revokeOnUpgrade) {
mFlags |= PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
} else {
mFlags &= ~PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
}
}
public void setAppOpAllowed(boolean mAppOpAllowed) {
this.mAppOpAllowed = mAppOpAllowed;
}
public boolean isEphemeral() {
return mIsEphemeral;
}
public boolean isRuntimeOnly() {
return mIsRuntimeOnly;
}
//权限是否允许授权
public boolean isGrantingAllowed(boolean isEphemeralApp, boolean supportsRuntimePermissions) {
return (!isEphemeralApp || isEphemeral())
&& (supportsRuntimePermissions || !isRuntimeOnly());
}
}
AppPermissionGroup类,很重要,管理了一组具有相同group的权限,例如存储相关的,WiFi相关的,相机相关的
package com.android.packageinstaller.permission.model;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
import android.util.ArrayMap;
import com.android.packageinstaller.R;
import com.android.packageinstaller.permission.utils.ArrayUtils;
import com.android.packageinstaller.permission.utils.LocationUtils;
import java.util.ArrayList;
import java.util.List;
public final class AppPermissionGroup implements Comparable {
private static final String PLATFORM_PACKAGE_NAME = "android";
private static final String KILL_REASON_APP_OP_CHANGE = "Permission related app op changed";
private final Context mContext;
private final UserHandle mUserHandle;
private final PackageManager mPackageManager;
private final AppOpsManager mAppOps;
private final ActivityManager mActivityManager;
private final PackageInfo mPackageInfo;
private final String mName;//AppPermissionGroup的name
private final String mDeclaringPackage;//声明的Package
private final CharSequence mLabel;//标签
private final CharSequence mDescription;//描述
private final ArrayMap mPermissions = new ArrayMap<>();//存储了应用中属于同一个group中的Permission
private final String mIconPkg;
private final int mIconResId;
private final boolean mAppSupportsRuntimePermissions;//app是否支持运行时权限
private final boolean mIsEphemeralApp;//是不是即时应用
private boolean mContainsEphemeralPermission;
private boolean mContainsPreRuntimePermission;
public static AppPermissionGroup create(Context context, PackageInfo packageInfo,
String permissionName) {
PermissionInfo permissionInfo;
try {
permissionInfo = context.getPackageManager().getPermissionInfo(permissionName, 0);
//通过permissionName获取到对应的类PermissionInfo的对象permissionInfo
} catch (PackageManager.NameNotFoundException e) {
return null;
}
if ((permissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
!= PermissionInfo.PROTECTION_DANGEROUS
|| (permissionInfo.flags & PermissionInfo.FLAG_INSTALLED) == 0
|| (permissionInfo.flags & PermissionInfo.FLAG_REMOVED) != 0) {
return null;
}
PackageItemInfo groupInfo = permissionInfo;//将PermissionInfo向上转型为PackageItemInfo对象groupInfo
if (permissionInfo.group != null) {//如果permissionInfo的group属性不为空,也就是permissionInfo有归属的group
try {
groupInfo = context.getPackageManager().getPermissionGroupInfo(
permissionInfo.group, 0);//通过permissionInfo的group属性获取到对应group的属性信息对象赋值给groupInfo
} catch (PackageManager.NameNotFoundException e) {
/* ignore */
}
}
List permissionInfos = null;//permissionInfos是保存归属于同一个group的所有PermissionInfo的列表
if (groupInfo instanceof PermissionGroupInfo) {
try {
permissionInfos = context.getPackageManager().queryPermissionsByGroup(
groupInfo.name, 0);//通过group的name属性获取到属于这个group的所有PermissionInfo,并赋值给permissionInfos
} catch (PackageManager.NameNotFoundException e) {
/* ignore */
}
}
return create(context, packageInfo, groupInfo, permissionInfos,
Process.myUserHandle());
}
public static AppPermissionGroup create(Context context, PackageInfo packageInfo,
PackageItemInfo groupInfo, List permissionInfos,
UserHandle userHandle) {
AppPermissionGroup group = new AppPermissionGroup(context, packageInfo, groupInfo.name,
groupInfo.packageName, groupInfo.loadLabel(context.getPackageManager()),
loadGroupDescription(context, groupInfo), groupInfo.packageName, groupInfo.icon,
userHandle);//groupInfo.name赋值给name,groupInfo.packageName赋值给declaringPackage
if (groupInfo instanceof PermissionInfo) {
permissionInfos = new ArrayList<>();
permissionInfos.add((PermissionInfo) groupInfo);
}
if (permissionInfos == null || permissionInfos.isEmpty()) {
return null;
}
final int permissionCount = packageInfo.requestedPermissions.length;
//获取应用请求的Permission数量
for (int i = 0; i < permissionCount; i++) {//依次取请求的Permission的字符全称
String requestedPermission = packageInfo.requestedPermissions[i];
PermissionInfo requestedPermissionInfo = null;
for (PermissionInfo permissionInfo : permissionInfos) {
//依次取同属于一个group的所有permissionInfo,比较应用请求的Permission字符全称与group中的哪一个permissionInfo.name相同
if (requestedPermission.equals(permissionInfo.name)) {
requestedPermissionInfo = permissionInfo;//找到相同的permissionInfo赋值给requestedPermissionInfo
break;
}
}
if (requestedPermissionInfo == null) {
continue;
}
// Collect only runtime permissions.
if ((requestedPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
!= PermissionInfo.PROTECTION_DANGEROUS) {
continue;
}
// Don't allow toggling non-platform permission groups for legacy apps via app ops.
if (packageInfo.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1
&& !PLATFORM_PACKAGE_NAME.equals(groupInfo.packageName)) {
continue;
}
final boolean granted = (packageInfo.requestedPermissionsFlags[i]
& PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;//应用当前请求的permission是否被授权
final String appOp = PLATFORM_PACKAGE_NAME.equals(requestedPermissionInfo.packageName)
? AppOpsManager.permissionToOp(requestedPermissionInfo.name) : null;
final boolean appOpAllowed = appOp != null
&& context.getSystemService(AppOpsManager.class).checkOpNoThrow(appOp,
packageInfo.applicationInfo.uid, packageInfo.packageName)
== AppOpsManager.MODE_ALLOWED;
final int flags = context.getPackageManager().getPermissionFlags(
requestedPermission, packageInfo.packageName, userHandle);//获取应用当前请求的permission的flags
Permission permission = new Permission(requestedPermission, granted,
appOp, appOpAllowed, flags, requestedPermissionInfo.protectionLevel);
group.addPermission(permission);
//将权限对应的Permission类对象permission加入group(AppPermissionGroup),就是加入ArrayMap对象
}
return group;
}
private static CharSequence loadGroupDescription(Context context, PackageItemInfo group) {
CharSequence description = null;
if (group instanceof PermissionGroupInfo) {
description = ((PermissionGroupInfo) group).loadDescription(
context.getPackageManager());
} else if (group instanceof PermissionInfo) {
description = ((PermissionInfo) group).loadDescription(
context.getPackageManager());
}
if (description == null || description.length() <= 0) {
description = context.getString(R.string.default_permission_description);
}
return description;
}
private AppPermissionGroup(Context context, PackageInfo packageInfo, String name,
String declaringPackage, CharSequence label, CharSequence description,
String iconPkg, int iconResId, UserHandle userHandle) {
mContext = context;
mUserHandle = userHandle;
mPackageManager = mContext.getPackageManager();
mPackageInfo = packageInfo;
mAppSupportsRuntimePermissions = packageInfo.applicationInfo
.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
mIsEphemeralApp = packageInfo.applicationInfo.isInstantApp();
mAppOps = context.getSystemService(AppOpsManager.class);
mActivityManager = context.getSystemService(ActivityManager.class);
mDeclaringPackage = declaringPackage;
mName = name;
mLabel = label;
mDescription = description;
if (iconResId != 0) {
mIconPkg = iconPkg;
mIconResId = iconResId;
} else {
mIconPkg = context.getPackageName();
mIconResId = R.drawable.ic_perm_device_info;
}
}
public boolean doesSupportRuntimePermissions() {
return mAppSupportsRuntimePermissions;
}
public boolean isGrantingAllowed() {
return (!mIsEphemeralApp || mContainsEphemeralPermission)
&& (mAppSupportsRuntimePermissions || mContainsPreRuntimePermission);
//(不是即时应用 || 包含即时权限)&&(支持运行时权限 || 包含非Runtime Only权限)
}
public boolean isReviewRequired() {
if (mAppSupportsRuntimePermissions) {
return false;
}
final int permissionCount = mPermissions.size();
for (int i = 0; i < permissionCount; i++) {
Permission permission = mPermissions.valueAt(i);
if (permission.isReviewRequired()) {
return true;
}
}
return false;
}
public void resetReviewRequired() {
final int permissionCount = mPermissions.size();
for (int i = 0; i < permissionCount; i++) {
Permission permission = mPermissions.valueAt(i);
if (permission.isReviewRequired()) {
permission.resetReviewRequired();
mPackageManager.updatePermissionFlags(permission.getName(),
mPackageInfo.packageName,
PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED,
0, mUserHandle);
}
}
}
public boolean hasGrantedByDefaultPermission() {
final int permissionCount = mPermissions.size();
for (int i = 0; i < permissionCount; i++) {
Permission permission = mPermissions.valueAt(i);
if (permission.isGrantedByDefault()) {
return true;
}
}
return false;
}
public PackageInfo getApp() {
return mPackageInfo;
}
public String getName() {
return mName;
}
public String getDeclaringPackage() {
return mDeclaringPackage;
}
public String getIconPkg() {
return mIconPkg;
}
public int getIconResId() {
return mIconResId;
}
public CharSequence getLabel() {
return mLabel;
}
public CharSequence getDescription() {
return mDescription;
}
public int getUserId() {
return mUserHandle.getIdentifier();
}
public boolean hasPermission(String permission) {
return mPermissions.get(permission) != null;
//判断group中是否包含某个权限
}
public boolean areRuntimePermissionsGranted() {
return areRuntimePermissionsGranted(null);
}
public boolean areRuntimePermissionsGranted(String[] filterPermissions) {
//如果字符串filterPermissions中包含group中的某个权限并且该权限被授权,则返回true
if (LocationUtils.isLocationGroupAndProvider(mName, mPackageInfo.packageName)) {
return LocationUtils.isLocationEnabled(mContext);
}
final int permissionCount = mPermissions.size();
for (int i = 0; i < permissionCount; i++) {
Permission permission = mPermissions.valueAt(i);
if (filterPermissions != null
&& !ArrayUtils.contains(filterPermissions, permission.getName())) {
continue;
}
if (mAppSupportsRuntimePermissions) {
if (permission.isGranted()) {
return true;
}
} else if (permission.isGranted() && (permission.getAppOp() == null
|| permission.isAppOpAllowed())) {
return true;
}
}
return false;
}
public boolean grantRuntimePermissions(boolean fixedByTheUser) {
return grantRuntimePermissions(fixedByTheUser, null);
}
public boolean grantRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) {
final int uid = mPackageInfo.applicationInfo.uid;
// We toggle permissions only to apps that support runtime
// permissions, otherwise we toggle the app op corresponding
// to the permission if the permission is granted to the app.
for (Permission permission : mPermissions.values()) {
//依次给group中的permission授权
if (filterPermissions != null
&& !ArrayUtils.contains(filterPermissions, permission.getName())) {
continue;
}
if (!permission.isGrantingAllowed(mIsEphemeralApp, mAppSupportsRuntimePermissions)) {
// Skip unallowed permissions.
continue;
}
if (mAppSupportsRuntimePermissions) {//app是否支持运行时权限
// Do not touch permissions fixed by the system.
if (permission.isSystemFixed()) {
//权限是不是系统固定的,如果是,不可授权
return false;
}
// Ensure the permission app op enabled before the permission grant.
if (permission.hasAppOp() && !permission.isAppOpAllowed()) {
permission.setAppOpAllowed(true);
mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_ALLOWED);
}
// Grant the permission if needed.
if (!permission.isGranted()) {//如果权限没有被授权
permission.setGranted(true);//将权限置为授权状态
mPackageManager.grantRuntimePermission(mPackageInfo.packageName,
permission.getName(), mUserHandle);//这是给权限真正授权的地方
}
// Update the permission flags.
if (!fixedByTheUser) {
// Now the apps can ask for the permission as the user
// no longer has it fixed in a denied state.
if (permission.isUserFixed() || permission.isUserSet()) {
permission.setUserFixed(false);
permission.setUserSet(false);
mPackageManager.updatePermissionFlags(permission.getName(),
mPackageInfo.packageName,
PackageManager.FLAG_PERMISSION_USER_FIXED
| PackageManager.FLAG_PERMISSION_USER_SET,
0, mUserHandle);
}
}
} else {
// Legacy apps cannot have a not granted permission but just in case.
if (!permission.isGranted()) {
continue;
}
int killUid = -1;
int mask = 0;
// If the permissions has no corresponding app op, then it is a
// third-party one and we do not offer toggling of such permissions.
if (permission.hasAppOp()) {
if (!permission.isAppOpAllowed()) {
permission.setAppOpAllowed(true);
// Enable the app op.
mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_ALLOWED);
// Legacy apps do not know that they have to retry access to a
// resource due to changes in runtime permissions (app ops in this
// case). Therefore, we restart them on app op change, so they
// can pick up the change.
killUid = uid;
}
// Mark that the permission should not be be granted on upgrade
// when the app begins supporting runtime permissions.
if (permission.shouldRevokeOnUpgrade()) {
permission.setRevokeOnUpgrade(false);
mask |= PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
}
}
if (mask != 0) {
mPackageManager.updatePermissionFlags(permission.getName(),
mPackageInfo.packageName, mask, 0, mUserHandle);
}
if (killUid != -1) {
mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE);
}
}
}
return true;
}
public boolean revokeRuntimePermissions(boolean fixedByTheUser) {
return revokeRuntimePermissions(fixedByTheUser, null);
}
public boolean revokeRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) {
final int uid = mPackageInfo.applicationInfo.uid;
// We toggle permissions only to apps that support runtime
// permissions, otherwise we toggle the app op corresponding
// to the permission if the permission is granted to the app.
for (Permission permission : mPermissions.values()) {
if (filterPermissions != null
&& !ArrayUtils.contains(filterPermissions, permission.getName())) {
continue;
}
if (mAppSupportsRuntimePermissions) {
// Do not touch permissions fixed by the system.
if (permission.isSystemFixed()) {
return false;
}
// Revoke the permission if needed.
if (permission.isGranted()) {//如果权限已经被授权
permission.setGranted(false);//permission置为未授权状态
mPackageManager.revokeRuntimePermission(mPackageInfo.packageName,
permission.getName(), mUserHandle);//这里时真正移除授权的位置
}
// Update the permission flags.
if (fixedByTheUser) {
// Take a note that the user fixed the permission.
if (permission.isUserSet() || !permission.isUserFixed()) {
permission.setUserSet(false);
permission.setUserFixed(true);
mPackageManager.updatePermissionFlags(permission.getName(),
mPackageInfo.packageName,
PackageManager.FLAG_PERMISSION_USER_SET
| PackageManager.FLAG_PERMISSION_USER_FIXED,
PackageManager.FLAG_PERMISSION_USER_FIXED,
mUserHandle);
}
} else {
if (!permission.isUserSet() || permission.isUserFixed()) {
permission.setUserSet(true);
permission.setUserFixed(false);
// Take a note that the user already chose once.
mPackageManager.updatePermissionFlags(permission.getName(),
mPackageInfo.packageName,
PackageManager.FLAG_PERMISSION_USER_SET
| PackageManager.FLAG_PERMISSION_USER_FIXED,
PackageManager.FLAG_PERMISSION_USER_SET,
mUserHandle);
}
}
} else {
// Legacy apps cannot have a non-granted permission but just in case.
if (!permission.isGranted()) {
continue;
}
int mask = 0;
int flags = 0;
int killUid = -1;
// If the permission has no corresponding app op, then it is a
// third-party one and we do not offer toggling of such permissions.
if (permission.hasAppOp()) {
if (permission.isAppOpAllowed()) {
permission.setAppOpAllowed(false);
// Disable the app op.
mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_IGNORED);
// Disabling an app op may put the app in a situation in which it
// has a handle to state it shouldn't have, so we have to kill the
// app. This matches the revoke runtime permission behavior.
killUid = uid;
}
// Mark that the permission should not be granted on upgrade
// when the app begins supporting runtime permissions.
if (!permission.shouldRevokeOnUpgrade()) {
permission.setRevokeOnUpgrade(true);
mask |= PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
flags |= PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
}
}
if (mask != 0) {
mPackageManager.updatePermissionFlags(permission.getName(),
mPackageInfo.packageName, mask, flags, mUserHandle);
}
if (killUid != -1) {
mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE);
}
}
}
return true;
}
public void setPolicyFixed() {
final int permissionCount = mPermissions.size();
for (int i = 0; i < permissionCount; i++) {
Permission permission = mPermissions.valueAt(i);
permission.setPolicyFixed(true);
mPackageManager.updatePermissionFlags(permission.getName(),
mPackageInfo.packageName,
PackageManager.FLAG_PERMISSION_POLICY_FIXED,
PackageManager.FLAG_PERMISSION_POLICY_FIXED,
mUserHandle);
}
}
public List getPermissions() {
return new ArrayList<>(mPermissions.values());//将ArrayMap转换为ArrayList
}
public int getFlags() {
int flags = 0;
final int permissionCount = mPermissions.size();
for (int i = 0; i < permissionCount; i++) {
Permission permission = mPermissions.valueAt(i);
flags |= permission.getFlags();
}
return flags;
}
public boolean isUserFixed() {
//group中有一个permission是UserFixed,则group就是UserFixed
final int permissionCount = mPermissions.size();
for (int i = 0; i < permissionCount; i++) {
Permission permission = mPermissions.valueAt(i);
if (permission.isUserFixed()) {
return true;
}
}
return false;
}
public boolean isPolicyFixed() {
final int permissionCount = mPermissions.size();
for (int i = 0; i < permissionCount; i++) {
Permission permission = mPermissions.valueAt(i);
if (permission.isPolicyFixed()) {
return true;
}
}
return false;
}
public boolean isUserSet() {
final int permissionCount = mPermissions.size();
for (int i = 0; i < permissionCount; i++) {
Permission permission = mPermissions.valueAt(i);
if (permission.isUserSet()) {
return true;
}
}
return false;
}
public boolean isSystemFixed() {
//group中有一个permission是系统固定的,则group就是系统固定的
final int permissionCount = mPermissions.size();
for (int i = 0; i < permissionCount; i++) {
Permission permission = mPermissions.valueAt(i);
if (permission.isSystemFixed()) {
return true;
}
}
return false;
}
@Override
public int compareTo(AppPermissionGroup another) {
final int result = mLabel.toString().compareTo(another.mLabel.toString());
if (result == 0) {
// Unbadged before badged.
return mPackageInfo.applicationInfo.uid
- another.mPackageInfo.applicationInfo.uid;
}
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
AppPermissionGroup other = (AppPermissionGroup) obj;
if (mName == null) {
if (other.mName != null) {
return false;
}
} else if (!mName.equals(other.mName)) {
return false;
}
return true;
}
@Override
public int hashCode() {
return mName != null ? mName.hashCode() : 0;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(getClass().getSimpleName());
builder.append("{name=").append(mName);
if (!mPermissions.isEmpty()) {
builder.append(", }");
} else {
builder.append('}');
}
return builder.toString();
}
private void addPermission(Permission permission) {
mPermissions.put(permission.getName(), permission);
if (permission.isEphemeral()) {
mContainsEphemeralPermission = true;
//如果AppPermissionGroup中有一个permission是暂时的,group的mContainsEphemeralPermission属性就为true
}
if (!permission.isRuntimeOnly()) {
mContainsPreRuntimePermission = true;
//如果AppPermissionGroup中有一个permission不是RuntimeOnly,group的mContainsPreRuntimePermission属性就为true
}
}
}
AppPermissions类,用来保存应用对应的AppPermissionGroup
package com.android.packageinstaller.permission.model;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.text.BidiFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
public final class AppPermissions {
private final ArrayList mGroups = new ArrayList<>();
//这个是关键,用ArrayList来保存应用对应哪些AppPermissionGroup
private final LinkedHashMap mNameToGroupMap = new LinkedHashMap<>();
//用LinedHashMap来保存应用对应的AppPermissionGroup
private final Context mContext;
private final String[] mFilterPermissions;
private final CharSequence mAppLabel;
private final Runnable mOnErrorCallback;
private final boolean mSortGroups;
private PackageInfo mPackageInfo;
public AppPermissions(Context context, PackageInfo packageInfo, String[] filterPermissions,
boolean sortGroups, Runnable onErrorCallback) {
mContext = context;
mPackageInfo = packageInfo;
mFilterPermissions = filterPermissions;
mAppLabel = BidiFormatter.getInstance().unicodeWrap(
packageInfo.applicationInfo.loadSafeLabel(
context.getPackageManager()).toString());
mSortGroups = sortGroups;
mOnErrorCallback = onErrorCallback;
loadPermissionGroups();
}
public PackageInfo getPackageInfo() {
return mPackageInfo;
}
public void refresh() {
loadPackageInfo();
loadPermissionGroups();
}
public CharSequence getAppLabel() {
return mAppLabel;
}
public AppPermissionGroup getPermissionGroup(String name) {
return mNameToGroupMap.get(name);//根据权限名称获取对应的AppPermissionGroup
}
public List getPermissionGroups() {
return mGroups;
}
public boolean isReviewRequired() {
if (!mContext.getPackageManager().isPermissionReviewModeEnabled()) {
return false;
}
final int groupCount = mGroups.size();
for (int i = 0; i < groupCount; i++) {
AppPermissionGroup group = mGroups.get(i);
if (group.isReviewRequired()) {
return true;
}
}
return false;
}
private void loadPackageInfo() {
try {
mPackageInfo = mContext.getPackageManager().getPackageInfo(
mPackageInfo.packageName, PackageManager.GET_PERMISSIONS);
} catch (PackageManager.NameNotFoundException e) {
if (mOnErrorCallback != null) {
mOnErrorCallback.run();
}
}
}
private void loadPermissionGroups() {
mGroups.clear();
if (mPackageInfo.requestedPermissions == null) {
return;
}
if (mFilterPermissions != null) {
for (String filterPermission : mFilterPermissions) {
for (String requestedPerm : mPackageInfo.requestedPermissions) {
if (!filterPermission.equals(requestedPerm)) {
continue;
}
addPermissionGroupIfNeeded(requestedPerm);
break;
}
}
} else {
for (String requestedPerm : mPackageInfo.requestedPermissions) {
addPermissionGroupIfNeeded(requestedPerm);
}
}
if (mSortGroups) {
Collections.sort(mGroups);
}
mNameToGroupMap.clear();
for (AppPermissionGroup group : mGroups) {
mNameToGroupMap.put(group.getName(), group);
}
}
private void addPermissionGroupIfNeeded(String permission) {
if (hasGroupForPermission(permission)) {
return;
}//这里是去重的地方,如果mGroups中已经存在某一个permission对应的APPPermissionGroup,则不加入直接返回
AppPermissionGroup group = AppPermissionGroup.create(mContext,
mPackageInfo, permission);
if (group == null) {
return;
}
mGroups.add(group);//向ArrayList中加入AppPermissionGroup
}
private boolean hasGroupForPermission(String permission) {
//判断mGroup中是否已经存在某一个permission对应的APPPermissionGroup
for (AppPermissionGroup group : mGroups) {
if (group.hasPermission(permission)) {
return true;
}
}
return false;
}
}
AppPermissionsFragment分析
package com.android.packageinstaller.permission.ui.television;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.AndroidResources;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import com.android.packageinstaller.R;
import com.android.packageinstaller.permission.model.AppPermissionGroup;
import com.android.packageinstaller.permission.model.AppPermissions;
import com.android.packageinstaller.permission.ui.ReviewPermissionsActivity;
import com.android.packageinstaller.permission.utils.LocationUtils;
import com.android.packageinstaller.permission.utils.SafetyNetLogger;
import com.android.packageinstaller.permission.utils.Utils;
import java.util.ArrayList;
import java.util.List;
public final class AppPermissionsFragment extends SettingsWithHeader
implements OnPreferenceChangeListener {
private static final String LOG_TAG = "ManagePermsFragment";
static final String EXTRA_HIDE_INFO_BUTTON = "hideInfoButton";
private static final int MENU_ALL_PERMS = 0;
private List mToggledGroups;
private AppPermissions mAppPermissions;
private PreferenceScreen mExtraScreen;
private boolean mHasConfirmedRevoke;
public static AppPermissionsFragment newInstance(String packageName) {
return setPackageName(new AppPermissionsFragment(), packageName);
}
private static T setPackageName(T fragment, String packageName) {
Bundle arguments = new Bundle();
arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
fragment.setArguments(arguments);//fragment携带带有包名的Bundle信息
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setLoading(true /* loading */, false /* animate */);
setHasOptionsMenu(true);
final ActionBar ab = getActivity().getActionBar();
if (ab != null) {
ab.setDisplayHomeAsUpEnabled(true);
}
String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
//获取包名
Activity activity = getActivity();
PackageInfo packageInfo = getPackageInfo(activity, packageName);
//根据包名获取PackageInfo对象
if (packageInfo == null) {
Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show();
activity.finish();
return;
}
//实例化AppPermissions,同时生成应用对应的AppPrmissionGroup
mAppPermissions = new AppPermissions(activity, packageInfo, null, true, new Runnable() {
@Override
public void run() {
getActivity().finish();
}
});
if (mAppPermissions.isReviewRequired()) {
Intent intent = new Intent(getActivity(), ReviewPermissionsActivity.class);
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
startActivity(intent);
getActivity().finish();
return;
}
loadPreferences();
}
@Override
public void onResume() {
super.onResume();
mAppPermissions.refresh();
loadPreferences();
setPreferencesCheckedState();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home: {
getActivity().finish();
return true;
}
case MENU_ALL_PERMS: {
Fragment frag = AllAppPermissionsFragment.newInstance(
getArguments().getString(Intent.EXTRA_PACKAGE_NAME));
getFragmentManager().beginTransaction()
.replace(android.R.id.content, frag)
.addToBackStack("AllPerms")
.commit();
return true;
}
}
return super.onOptionsItemSelected(item);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (mAppPermissions != null) {
bindUi(this, mAppPermissions.getPackageInfo());
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.add(Menu.NONE, MENU_ALL_PERMS, Menu.NONE, R.string.all_permissions);
}
private static void bindUi(SettingsWithHeader fragment, PackageInfo packageInfo) {
Activity activity = fragment.getActivity();
PackageManager pm = activity.getPackageManager();
ApplicationInfo appInfo = packageInfo.applicationInfo;
Intent infoIntent = null;
if (!activity.getIntent().getBooleanExtra(EXTRA_HIDE_INFO_BUTTON, false)) {
infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
.setData(Uri.fromParts("package", packageInfo.packageName, null));
}
Drawable icon = appInfo.loadIcon(pm);//获取应用的图片
CharSequence label = appInfo.loadLabel(pm);//获取应用的名称
fragment.getHeader().findViewById(R.id.back_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fragment.getActivity().finish();
}
});//fragment的头部内容在父类SettingWithHeader中
fragment.setHeader(icon, label, infoIntent, fragment.getString(
R.string.app_permissions_decor_title));
}
private void loadPreferences() {
Context context = getPreferenceManager().getContext();
if (context == null) {
return;
}
PreferenceScreen screen = getPreferenceScreen();
screen.removeAll();
screen.addPreference(createHeaderLineTwoPreference(context));//这里加入应用图片和名称
if (mExtraScreen != null) {
mExtraScreen.removeAll();
mExtraScreen = null;
}
final Preference extraPerms = new Preference(context);
extraPerms.setIcon(R.drawable.ic_toc);
extraPerms.setTitle(R.string.additional_permissions);
for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) {
//给screen依次加入Preferenc对象
if (!Utils.shouldShowPermission(group, mAppPermissions.getPackageInfo().packageName)) {
//判断权限是否能够显示
continue;
}
boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG);
SwitchPreference preference = new SwitchPreference(context){
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
final TextView titleView = (TextView) holder.findViewById(android.R.id.title);
titleView.setTextColor(getResources().getColor(R.color.text_black));
final ImageView imageView = (ImageView) holder.findViewById(android.R.id.icon);
imageView.setColorFilter(getResources().getColor(R.color.line_gray));
final Switch switchView = (Switch)holder.findViewById(AndroidResources.ANDROID_R_SWITCH_WIDGET);
switchView.setTrackDrawable(getResources().getDrawable(R.drawable.select_switch_track));
}
};
preference.setOnPreferenceChangeListener(this);
preference.setKey(group.getName());
Drawable icon = Utils.loadDrawable(context.getPackageManager(),
group.getIconPkg(), group.getIconResId());
preference.setIcon(Utils.applyTint(getContext(), icon,
android.R.attr.colorControlNormal));
preference.setTitle(group.getLabel());
if (group.isPolicyFixed()) {
preference.setSummary(getString(R.string.permission_summary_enforced_by_policy));
}
preference.setPersistent(false);
preference.setEnabled(!group.isPolicyFixed());
preference.setChecked(group.areRuntimePermissionsGranted());
if (isPlatform) {
screen.addPreference(preference);
} else {
if (mExtraScreen == null) {
mExtraScreen = getPreferenceManager().createPreferenceScreen(context);
mExtraScreen.addPreference(createHeaderLineTwoPreference(context));
}
mExtraScreen.addPreference(preference);
}
}
if (mExtraScreen != null) {
extraPerms.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
AdditionalPermissionsFragment frag = new AdditionalPermissionsFragment();
setPackageName(frag, getArguments().getString(Intent.EXTRA_PACKAGE_NAME));
frag.setTargetFragment(AppPermissionsFragment.this, 0);
getFragmentManager().beginTransaction()
.replace(android.R.id.content, frag)
.addToBackStack(null)
.commit();
return true;
}
});
int count = mExtraScreen.getPreferenceCount();
extraPerms.setSummary(getResources().getQuantityString(
R.plurals.additional_permissions_more, count, count));
screen.addPreference(extraPerms);
}
setLoading(false /* loading */, true /* animate */);
}
/**
* Creates a heading below decor_title and above the rest of the preferences. This heading
* displays the app name and banner icon. It's used in both system and additional permissions
* fragments for each app. The styling used is the same as a leanback preference with a
* customized background color
* @param context The context the preferences created on
* @return The preference header to be inserted as the first preference in the list.
*/
private Preference createHeaderLineTwoPreference(Context context) {
Preference headerLineTwo = new Preference(context) {
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
holder.itemView.setBackgroundColor(
getResources().getColor(R.color.background_white));
final TextView titleView = (TextView) holder.findViewById(android.R.id.title);
titleView.setTextColor(getResources().getColor(R.color.text_black));
}
};
headerLineTwo.setKey(HEADER_PREFERENCE_KEY);
headerLineTwo.setSelectable(false);
headerLineTwo.setTitle(mLabel);
headerLineTwo.setIcon(mIcon);
return headerLineTwo;
}
@Override
public boolean onPreferenceChange(final Preference preference, Object newValue) {
String groupName = preference.getKey();
final AppPermissionGroup group = mAppPermissions.getPermissionGroup(groupName);
if (group == null) {
return false;
}
addToggledGroup(group);
if (LocationUtils.isLocationGroupAndProvider(group.getName(), group.getApp().packageName)) {
LocationUtils.showLocationDialog(getContext(), mAppPermissions.getAppLabel());
return false;
}
if (newValue == Boolean.TRUE) {
group.grantRuntimePermissions(false);//true对权限进行授权
} else {
final boolean grantedByDefault = group.hasGrantedByDefaultPermission();
if (grantedByDefault || (!group.doesSupportRuntimePermissions()
&& !mHasConfirmedRevoke)) {
new AlertDialog.Builder(getContext())
.setMessage(grantedByDefault ? R.string.system_warning
: R.string.old_sdk_deny_warning)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.grant_dialog_button_deny_anyway,
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
((SwitchPreference) preference).setChecked(false);
group.revokeRuntimePermissions(false);
if (!grantedByDefault) {
mHasConfirmedRevoke = true;
}
}
})
.show();
return false;
} else {
group.revokeRuntimePermissions(false);//false对权限进行授权移除
}
}
return true;
}
@Override
public void onPause() {
super.onPause();
logToggledGroups();
}
private void addToggledGroup(AppPermissionGroup group) {
if (mToggledGroups == null) {
mToggledGroups = new ArrayList<>();
}
// Double toggle is back to initial state.
if (mToggledGroups.contains(group)) {
mToggledGroups.remove(group);
} else {
mToggledGroups.add(group);
}
}
private void logToggledGroups() {
if (mToggledGroups != null) {
String packageName = mAppPermissions.getPackageInfo().packageName;
SafetyNetLogger.logPermissionsToggled(packageName, mToggledGroups);
mToggledGroups = null;
}
}
private void setPreferencesCheckedState() {
setPreferencesCheckedState(getPreferenceScreen());
if (mExtraScreen != null) {
setPreferencesCheckedState(mExtraScreen);
}
}
private void setPreferencesCheckedState(PreferenceScreen screen) {
int preferenceCount = screen.getPreferenceCount();
for (int i = 0; i < preferenceCount; i++) {
Preference preference = screen.getPreference(i);
if (preference instanceof SwitchPreference) {
SwitchPreference switchPref = (SwitchPreference) preference;
AppPermissionGroup group = mAppPermissions.getPermissionGroup(switchPref.getKey());
if (group != null) {
switchPref.setChecked(group.areRuntimePermissionsGranted());
//根据权限是否已经被授权来更新preferences状态
}
}
}
}
private static PackageInfo getPackageInfo(Activity activity, String packageName) {
try {
return activity.getPackageManager().getPackageInfo(
packageName, PackageManager.GET_PERMISSIONS);
} catch (PackageManager.NameNotFoundException e) {
Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e);
return null;
}
}
public static class AdditionalPermissionsFragment extends SettingsWithHeader {
AppPermissionsFragment mOuterFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
mOuterFragment = (AppPermissionsFragment) getTargetFragment();
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferenceScreen(mOuterFragment.mExtraScreen);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
bindUi(this, getPackageInfo(getActivity(), packageName));
}
private static void bindUi(SettingsWithHeader fragment, PackageInfo packageInfo) {
Activity activity = fragment.getActivity();
PackageManager pm = activity.getPackageManager();
ApplicationInfo appInfo = packageInfo.applicationInfo;
Intent infoIntent = null;
if (!activity.getIntent().getBooleanExtra(EXTRA_HIDE_INFO_BUTTON, false)) {
infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
.setData(Uri.fromParts("package", packageInfo.packageName, null));
}
Drawable icon = appInfo.loadIcon(pm);
CharSequence label = appInfo.loadLabel(pm);
fragment.setHeader(icon, label, infoIntent, fragment.getString(
R.string.additional_permissions_decor_title));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getFragmentManager().popBackStack();
return true;
}
return super.onOptionsItemSelected(item);
}
}
}