Android运行时权限

Android 运行时权限
一.Android 权限发展史
二.Android6.0 权限简介
1.Normal Permissions (普通权限)
2.Dangerous Permissions (危险权限)
三.Android6.0 运行时权限流程
1.权限的申请
2.权限的检查
(1)checkSelfPermission()
(2)enforceCallingOrSelfPermission()
3.手机重启后权限的恢复
4.默认授权
四.Android6.0 权限申请示例代码

一d .Android 权限发展史
Google从 4.3开始就试图引入AppOpsManager动态权限管理模型,但是,由于感觉技术不太成熟,
在Release版本中,这个功能都是被隐藏掉的,所以官方 Rom一直没有动态权限管理机制。直到
Android6.0,为了简化安装流程和方便用户控制权限,Google正式推出了runtime permission
机制,至此,Android才算有了一套成熟的动态权限管理机制。
虽然6.0之前,Google的正式版本没有动态权限管理,但是有一些手机厂商却在 AppOpsManager基
础上修改出自己的一套动态的权限管理功能。其本质是:将权限放在每个服务内部,比如,如果 App要
申请定位权限,定位服务LocationManagerService会向 AppOpsService查询是否授予了当前App
定位权限,如果需要授权,就弹出一个系统对话框让用户操作,并根据用户的操作将结果持久化在文件
中,如果用户主动在Setting里更新了相应的权限,也会去更新,并持保存到文
件/data/system/appops.xml,下次再次申请服务的时候,服务便能够选择性授予权限。
在Android6.0之前,所有的权限都是在安装的时候授予,而在 6.0之后,允许用户在运行的时候动态
控制权限。
二. .0 Android6.0 权限简介
Android6.0系统把权限分为两个级别:
一个是Normal Permissions,即普通权限,这类权限不会潜藏有侵害用户隐私和安全的问题,比如,
访问网络的权限,访问WIFI的权限等;
另一类是Dangerous Permissions,即危险权限,这类权限会直接的威胁到用户的安全和隐私问题,
比如说访问短信,相册等权限。
1.Normal Permissions (普通权限)
•ACCESS_LOCATION_EXTRA_COMMANDS
•ACCESS_NETWORK_STATE
•ACCESS_NOTIFICATION_POLICY
•ACCESS_WIFI_STATE
•BLUETOOTH
•BLUETOOTH_ADMIN
•BROADCAST_STICKY
•CHANGE_NETWORK_STATE
•CHANGE_WIFI_MULTICAST_STATE
•CHANGE_WIFI_STATE
•DISABLE_KEYGUARD
•EXPAND_STATUS_BAR
•GET_PACKAGE_SIZE
•INSTALL_SHORTCUT
•INTERNET
•KILL_BACKGROUND_PROCESSES
•MODIFY_AUDIO_SETTINGS
•NFC
•READ_SYNC_SETTINGS
•READ_SYNC_STATS
•RECEIVE_BOOT_COMPLETED
•REORDER_TASKS
•REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
•REQUEST_INSTALL_PACKAGES
•SET_ALARM
•SET_TIME_ZONE
•SET_WALLPAPER
•SET_WALLPAPER_HINTS
•TRANSMIT_IR
•UNINSTALL_SHORTCUT
•USE_FINGERPRINT
•VIBRATE
•WAKE_LOCK
•WRITE_SYNC_SETTINGS
使用以上权限是不会威胁到用户安全的,所以这类权限是可以直接的在 manifest里面直接的使用,而
且在安装后也会直接的生效了。
2.Dangerous Permissions (危险权限)
• SMS(短信)
•SEND_SMS
•RECEIVE_SMS
•READ_SMS
•RECEIVE_WAP_PUSH
•RECEIVE_MMS
• STORAGE(存储卡)
•READ_EXTERNAL_STORAGE
•WRITE_EXTERNAL_STORAGE
• CONTACTS(联系人)
•READ_CONTACTS
•WRITE_CONTACTS
•GET_ACCOUNTS
• PHONE(手机)
•READ_PHONE_STATE
•CALL_PHONE
•READ_CALL_LOG
•WRITE_CALL_LOG
•ADD_VOICEMAIL
•USE_SIP
•PROCESS_OUTGOING_CALLS
• CALENDAR(日历)
•READ_CALENDAR
•WRITE_CALENDAR
• CAMERA(相机)
•CAMERA
• LOCATION(位置)
•ACCESS_FINE_LOCATION
•ACCESS_COARSE_LOCATION
• SENSORS(传感器)
•BODY_SENSORS
• MICROPHONE(麦克风)
•RECORD_AUDIO
危险权限和普通权限也有区别,普通权限是单条的权限,而危险权限是以组展示的,也就是说,当你接
受一个危险权限时,它所在这个组里面的其他所有访问权限也将会被自动获取权限,比如,一旦
WRITE_CONTACTS被授权了,App也有 READ_CONTACTS和 GET_ACCOUNTS的权限了。
值得注意的是,这类权限也是需要在manifest中注册的。
当targetSdkVersion >= 23,且 android 版本 >= 23时,即使在 manifest中添加了相应的
危险权限,但代码中没有动态申请权限,会出现限权的异常,这时 manifest中的危险权限并没有起作
用,必须在代码中也添加动态申请权限。
当targetSdkVersion < 23,且 android 版本 >= 23时,只需在 manifest中申请的危险权限。
代码中不添加动态申请权限仍可获取对应权限。
当真机系统版本 < 23时,不管我们项目的targetSdkVersion 值是否大于 23,都不会影响我们在
manifest里面申请的权限。
三.Android6.0 运行时权限流程
1.权限的申请
首先去检查 SDK 版本,如果版本小于 23 ,就调用
PackageManager 的 checkPermission 方法去检查包安装时已授
予的权限然后传回结果。如果 SDK 大于等于23首先去检查是不是
已获取了对应权限,如果已获取则调用
onRequestPermissionsResult 传回结果。如果未获取权限则
启动授权处理界面 GrantPermissionsActivity 。
GrantPermissionsActivity 首先加载权限处理的 View(权限
处理View有两个类分别是 GrantPermissionsTvViewHandler 和
GrantPermissionsDefaultViewHandler 前者是处理 TV 权限界面
的)。在这里有一个内部类 GroupState 用来记录记录需要申请的
所有权限状态,首先会更新 GroupState 中每个权限的状态,部分
自动授予的权限将在这里自动申请授权,不需要用户手动授权,在
申请权限时只会申请状态为 STATE_UNKNOWN 的权限。待所有
权限申请完成后会调用 onRequestPermissionsResult 传回结果。
这里授权调用的是 PackageManager 的
requestPermissions()
ActivityCompat23.java
PackageInstaller
grantRuntimePermission()方法。
这里首先会检查是否在 Menifest 中声明过申请的权限、是否属于危
险权限。然后调用 PermissionsState 的
grantRuntimePermission()方法完成权限状态的切换。接下来会
发送一个权限切换的广播,然后调用 Settings 的
writeRuntimePermissionsForUserLPr()将权限状态
写入本地 xml 文件
data/system/users/0/runtime-permissions.xml。
frameworks/support/v4/java/android/support/v4/app/ActivityCompat.javaframewo
rks/support/v4/api23/android/support/v4/app/ActivityCompat23.javaframeworks/
base/core/java/android/app/Activity.javaframeworks/base/core/java/android/co
ntent/pm/PackageManager.java
从ActivityCompat的 requestPermissions方法开始,这里做了对 6.0之前版本的兼容处理。首
先检查SDK版本,如果小于 23 直接去检查 app是否定义了对应的权限(6.0 之前的权限信息全部保存
在packages.xml 文件中)
然后回调 onRequestPermissionsResult 传回结果。
public static void requestPermissions(final @NonNull Activity activity,
final @NonNull String[] permissions, final int requestCode) {
if (Build.VERSION.SDK_INT >= 23) {
ActivityCompatApi23.requestPermissions(activity, permissions, requestCode);
} else if (activity instanceof OnRequestPermissionsResultCallback) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
final int[] grantResults = new int[permissions.length];
PackageManager packageManager = activity.getPackageManager();
String packageName = activity.getPackageName();
final int permissionCount = permissions.length;
for (int i = 0; i < permissionCount; i++) {
grantResults[i] = packageManager.checkPermission(
permissions[i], packageName);
}
((OnRequestPermissionsResultCallback)
activity).onRequestPermissionsResult(
requestCode, permissions, grantResults);
}
});
}
}
sdk大于等于23调用
ActivityCompatApi23.requestPermissions(activity, permissions, requestCode)
这里首先对 requestCode 做了检查,然后调用
activity.requestPermissions(permissions, requestCode);
这里首先会检测是否已有申请的权限,如果已有权限则直接调用回调函数取消操作。
如果没有获取需要申请的权限则通过Intent 启动了一个 Activity
PackageManagerService
4005 public final void requestPermissions(@NonNull String[] permissions, int
requestCode) {
4006 if ( mHasCurrentPermissionsRequest) {
4007 Log.w( TAG, “Can reqeust only one set of permissions at a
time”);
4008 // Dispatch the callback with empty arrays which means a
cancellation.
4009 onRequestPermissionsResult(requestCode, new String[0], new
int[0]);
4010 return;
4011 }
4012 Intent intent =
getPackageManager().buildRequestPermissionsIntent(permissions);
4013 startActivityForResult( REQUEST_PERMISSIONS_WHO_PREFIX, intent,
requestCode, null);
4014 mHasCurrentPermissionsRequest = true;
4015 }
这个Intent 从PackageManager.java获取
Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
2631 intent.putExtra( EXTRA_REQUEST_PERMISSIONS_NAMES,
permissions);
2632 intent.setPackage( getPermissionControllerPackageName());
2633 return intent;
aciton 是
public static final java.lang.String ACTION_REQUEST_PERMISSIONS =
“android.content.pm.action.REQUEST_PERMISSIONS”;
最终启动了GrantPermissionsActivity.java弹出授权界面。
packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/u
i/GrantPermissionsActivity.java
packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/u
i/GrantPermissionsViewHandler.java
packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/u
i/GrantPermissionsTvViewHandler.java
packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/u
i/GrantPermissionsDefaultViewHandler.java
packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/m
odel/AppPermissions.java
packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/m
odel/AppPermissionGroup.java
packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/m
odel/Permission.java
权限处理界面有两个类分别是 GrantPermissionsTvViewHandler 和
GrantPermissionsDefaultViewHandler 前者是处理 TV 权限界面的。
GrantPermissionsActivity中有一个内部类 GroupState用来记录权限组状态,先将所有需要申
请的权限状态置STATE_UNKNOWN(部分权限会自动授权或拒绝授权
DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT 或者
DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY),
然后循环调用showNextPermissionGroupGrantRequest(),
当用户点击授权或者拒绝时会调用 onPermissionGrantResult 函数
代码如下:
@Override
public void onPermissionGrantResult(String name, boolean granted, boolean
doNotAskAgain) {
if (isObscuredTouch()) {
showOverlayDialog();
finish();
return;
}
GroupState groupState = mRequestGrantPermissionGroups.get(name);
if (groupState.mGroup != null) {
if (granted) {
groupState.mGroup.grantRuntimePermissions(doNotAskAgain);
groupState.mState = GroupState.STATE_ALLOWED;
} else {
groupState.mGroup.revokeRuntimePermissions(doNotAskAgain);
groupState.mState = GroupState.STATE_DENIED;
}
updateGrantResults(groupState.mGroup);
}
if (!showNextPermissionGroupGrantRequest()) {
setResultAndFinish();
}
}
groupState.mGroup.grantRuntimePermissions(doNotAskAgain);
调用了 AppPermissionGroup的 grantRuntimePermissions 方法
这里首先会检查是否支持运行时权限,如不支持,直接授予权限。
这里还会处理应用程序升级后的权限问题。如果应用程序升级后支持运行时权限,此时不再自动授予权
限。
permission.setGranted(true);
mPackageManager.grantRuntimePermission(mPackageInfo.packageName,
permission.getName(), mUserHandle);
permission 的几种flags
public static final int FLAG_PERMISSION_USER_SET = 1 << 0;
public static final int FLAG_PERMISSION_USER_FIXED = 1 << 1;
public static final int FLAG_PERMISSION_POLICY_FIXED = 1 << 2;
public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 1 << 3;
public static final int FLAG_PERMISSION_SYSTEM_FIXED = 1 << 4;
public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 1 <<
5;
所有权限处理完后会调用onRequestPermissionsResult 传回结果。
frameworks/base/core/java/android/content/pm/PackageManager.java
frameworks/base/core/java/android/content/pm/IPackageManager.aidl
frameworks/base/services/core/java/com/android/server/pm/PackageManagerServi
ce.java
frameworks/base/services/core/java/com/android/server/pm/PermissionsState.java
frameworks/base/core/java/android/app/ApplicationPackageManager.java
frameworks/base/core/java/android/content/pm/IOnPermissionsChangeListener.ai
dl
frameworks/base/services/core/java/com/android/server/LocationManagerService
.java
grantRuntimePermission 实现于 PackageManagerService
@Override
public void grantRuntimePermission(String packageName, String name,
final int userId) {
synchronized (mPackages) {

enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);

final int result = permissionsState.grantRuntimePermission(bp,
userId);
mOnPermissionChangeListeners.onPermissionsChanged(uid);
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
}
检查是否在Menifest中声明过对应的权限和对应的权限是否属于危险权限。
enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
切换权限状态并获得切换结果。
final int result = permissionsState.grantRuntimePermission(bp, userId);
grantPermission(permission, userId);
最终在 PermissionsState的内部类 permissionData中完成权限状态更改。
permissionData.grant(userId)
发送权限切换广播
mOnPermissionChangeListeners.onPermissionsChanged(uid);
将权限状态写入本地
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
在 在 mSettings.writeRuntimePermissionsForUserLPr(userId, false); 中
执行了Settings的
writePermissionsForUserAsyncLPr(userId)
这里发送了一个广播,广播处理执行了writePermissionsSync(userId);
writePermissionsSync(userId);将权限信息写入本地 xml文件
private static final String RUNTIME_PERMISSIONS_FILE_NAME = “runtime-
permissions.xml”;
文件存放位置位置
data/system/users/0/runtime-permissions.xml
再看
mOnPermissionChangeListeners.onPermissionsChanged(uid);
这里发送了一个广播
obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
消息处理执行了
handleOnPermissionsChanged(uid);
调用了 IOnPermissionsChangeListener 的 onPermissionsChanged
实现于 ApplicationPackageManager.java
这里又发送了一个广播
mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
调用了mListener.onPermissionsChanged(uid);
这里的mListener 为OnPermissionsChangedListener 是 PackageManager 的一个接口
实现于 LocationManagerService
从而获取使用网络和GPS获取手机位置,最终会调用到 vonder中的 GPS处理代码,我们对此不做深究。
2.权限的检查
这里会先检测调用者的 pid , MY_PID、ROOT_UID、SYSTEM_UID这三个进程拥有所有权限。最终会从
PermissionsState的 hasPermission 方法读取对应的权限状态。
(1)checkSelfPermission()
检查自己是否已经获取了某项权限,在申请权限前执行。
frameworks/support/v4/java/android/support/v4/content/ContextCompat.javafram
eworks/base/core/java/android/content/Context.javaframeworks/base/core/java/
android/app/ContextImpl.java
382 public static int
checkSelfPermission(@NonNull Context context, @NonNull String permission) {
383 if ( permission == null) {
384 throw new IllegalArgumentException(“permission is null”);
385 }
386 //modify by yangyangni 2016.4.19 for 1949666 begin
387 if(context != null){
388 return context.checkPermission( permission,
android.os.Process.myPid(), Process.myUid());
389 } else {
390 return -1;
391 }
392 //modify by yangyangni 2016.4.19 for 1949666 end
393 }
调用了 context 的 checkPermission
public abstract int checkPermission(@NonNull String permission, int
pid, int uid);
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
throw new IllegalArgumentException(“permission is null”);
}
checkSelfPermission enforceCallingOrSelfPermission
Context.checkPermission
ActivityManagerService.checkPermission
try {
return ActivityManagerNative.getDefault().checkPermission(
permission, pid, uid);
} catch (RemoteException e) {
return PackageManager.PERMISSION_DENIED;
}
}
这里的 ActivityManagerNative.getDefault() 返回一个 IActivityManager
frameworks/base/core/java/android/app/IActivityManager.ja
va
public int checkPermission(String permission, int pid, int uid)
throws RemoteException;
实现于 ActivityManagerService
frameworks/base/services/core/java/com/android/server/am/
ActivityManagerService.java
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
return PackageManager.PERMISSION_DENIED;
}
return checkComponentPermission(permission, pid, uid, -1, true);
}
ActivityManagerService 拥有所权限。
int checkComponentPermission(String permission, int pid, int uid,
int owningUid, boolean exported) {
if (pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
return ActivityManager.checkComponentPermission(permission, uid,
owningUid, exported);
}
root 和 systemservice 拥有所有权限。
/** @hide /
public static int checkComponentPermission(String permission, int uid,
int owningUid, boolean exported) {
// Root, system server get to do everything.
final int appId = UserHandle.getAppId(uid);
if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
return PackageManager.PERMISSION_GRANTED;
}
// Isolated processes don’t get any permissions.
if (UserHandle.isIsolated(uid)) {
return PackageManager.PERMISSION_DENIED;
}
// If there is a uid that owns whatever is being accessed, it has
// blanket access to it regardless of the permissions it requires.
if (owningUid >= 0 && UserHandle.isSameApp(uid, owningUid)) {
return PackageManager.PERMISSION_GRANTED;
}
// If the target is not exported, then nobody else can get to it.
if (!exported) {
/

RuntimeException here = new RuntimeException(“here”);
here.fillInStackTrace();
Slog.w(TAG, “Permission denied: checkComponentPermission() owningUid=”

  • owningUid,
    here);
    /
    return PackageManager.PERMISSION_DENIED;
    }
    if (permission == null) {
    return PackageManager.PERMISSION_GRANTED;
    }
    try {
    return AppGlobals.getPackageManager()
    .checkUidPermission(permission, uid);
    } catch (RemoteException e) {
    // Should never happen, but if it does… deny!
    Slog.e(TAG, “PackageManager is dead?!?”, e);
    }
    return PackageManager.PERMISSION_DENIED;
    }
    @Override
    public int checkUidPermission(String permName, int uid) {
    final int userId = UserHandle.getUserId(uid);
    if (!sUserManager.exists(userId)) {
    return PackageManager.PERMISSION_DENIED;
    }
    synchronized (mPackages) {
    Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
    if (obj != null) {
    final SettingBase ps = (SettingBase) obj;
    final PermissionsState permissionsState = ps.getPermissionsState();
    if (permissionsState.hasPermission(permName, userId)) {
    return PackageManager.PERMISSION_GRANTED;
    }
    // Special case: ACCESS_FINE_LOCATION permission includes
    ACCESS_COARSE_LOCATION
    if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName)
    && permissionsState
    .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION,
    userId)) {
    return PackageManager.PERMISSION_GRANTED;
    }
    } else {
    ArraySet perms = mSystemPermissions.get(uid);
    if (perms != null) {
    if (perms.contains(permName)) {
    return PackageManager.PERMISSION_GRANTED;
    }
    if
    (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && perms
    .contains(Manifest.permission.ACCESS_FINE_LOCATION)) {
    return PackageManager.PERMISSION_GRANTED;
    }
    }
    }
    }
    return PackageManager.PERMISSION_DENIED;
    }
    frameworks/base/services/core/java/com/android/server/pm/
    PermissionsState.java
    最后从PermissionsState的 hasPermission 方法读取权限。
    (2) enforceCallingOrSelfPermission()
    从 enforceCallingOrSelfPermission–> enforce–> checkCallingOrSelfPermission->
    checkPermission-> checkComponentPermission
    源码
    @Override
    public void enforceCallingOrSelfPermission(
    String permission, String message) {
    enforce(permission,
    checkCallingOrSelfPermission(permission),
    true,
    Binder.getCallingUid(),
    message);
    }
    private void enforce(
    String permission, int resultOfCheck,
    boolean selfToo, int uid, String message) {
    if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
    throw new SecurityException(
    (message != null ? (message + ": ") : “”) +
    (selfToo
    ? "Neither user " + uid + " nor current process has
    "
    : "uid " + uid + " does not have ") +
    permission +
    “.”);
    }
    }
    enforce 检查了一下是否已授权并在未取得权限时抛出了异常
    @Override
    public int checkCallingOrSelfPermission(String permission) {
    if (permission == null) {
    throw new IllegalArgumentException(“permission is null”);
    }
    return checkPermission(permission, Binder.getCallingPid(),
    Binder.getCallingUid());
    }
    这里主要对空的权限名称做了检查并抛出了异常然后调用了 checkPermission 方法
    @Override
    public int checkPermission(String permission, int pid, int uid) {
    if (permission == null) {
    throw new IllegalArgumentException(“permission is null”);
    }
    try {
    return ActivityManagerNative.getDefault().checkPermission(
    permission, pid, uid);
    } catch (RemoteException e) {
    return PackageManager.PERMISSION_DENIED;
    }
    }
    frameworks/base/services/core/java/com/android/server/am/
    ActivityManagerService.java
    @Override
    public int checkPermission(String permission, int pid, int uid) {
    if (permission == null) {
    return PackageManager.PERMISSION_DENIED;
    }
    return checkComponentPermission(permission, pid, uid, -1, true);
    }
    int checkComponentPermission(String permission, int pid, int uid,
    int owningUid, boolean exported) {
    if (pid == MY_PID) {
    return PackageManager.PERMISSION_GRANTED;
    }
    return ActivityManager.checkComponentPermission(permission, uid,
    owningUid, exported);
    }
    frameworks/base/services/core/java/com/android/server/am/
    ActivityManagerService.java
    /
    * @hide /
    public static int checkComponentPermission(String permission, int uid,
    int owningUid, boolean exported) {
    // Root, system server get to do everything.
    final int appId = UserHandle.getAppId(uid);
    if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
    return PackageManager.PERMISSION_GRANTED;
    }
    // Isolated processes don’t get any permissions.
    if (UserHandle.isIsolated(uid)) {
    return PackageManager.PERMISSION_DENIED;
    }
    // If there is a uid that owns whatever is being accessed, it has
    // blanket access to it regardless of the permissions it requires.
    if (owningUid >= 0 && UserHandle.isSameApp(uid, owningUid)) {
    return PackageManager.PERMISSION_GRANTED;
    }
    // If the target is not exported, then nobody else can get to it.
    if (!exported) {
    /

    RuntimeException here = new RuntimeException(“here”);
    here.fillInStackTrace();
    Slog.w(TAG, “Permission denied: checkComponentPermission() owningUid=”
  • owningUid,
    here);
    */
    return PackageManager.PERMISSION_DENIED;
    }
    if (permission == null) {
    return PackageManager.PERMISSION_GRANTED;
    }
    try {
    return AppGlobals.getPackageManager()
    .checkUidPermission(permission, uid);
    } catch (RemoteException e) {
    // Should never happen, but if it does… deny!
    Slog.e(TAG, “PackageManager is dead?!?”, e);
    }
    return PackageManager.PERMISSION_DENIED;
    }
    frameworks/base/core/java/android/app/ActivityManager.jav
    a
    @Override
    public int checkUidPermission(String permName, int uid) {
    final int userId = UserHandle.getUserId(uid);
    if (!sUserManager.exists(userId)) {
    return PackageManager.PERMISSION_DENIED;
    }
    synchronized (mPackages) {
    Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
    if (obj != null) {
    final SettingBase ps = (SettingBase) obj;
    final PermissionsState permissionsState = ps.getPermissionsState();
    if (permissionsState.hasPermission(permName, userId)) {
    return PackageManager.PERMISSION_GRANTED;
    }
    // Special case: ACCESS_FINE_LOCATION permission includes
    ACCESS_COARSE_LOCATION
    if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName)
    && permissionsState
    .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION,
    userId)) {
    return PackageManager.PERMISSION_GRANTED;
    }
    } else {
    ArraySet perms = mSystemPermissions.get(uid);
    if (perms != null) {
    if (perms.contains(permName)) {
    return PackageManager.PERMISSION_GRANTED;
    }
    if
    (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && perms
    .contains(Manifest.permission.ACCESS_FINE_LOCATION)) {
    return PackageManager.PERMISSION_GRANTED;
    }
    }
    }
    }
    return PackageManager.PERMISSION_DENIED;
    }
    frameworks/base/services/core/java/com/android/server/pm/
    PermissionsState.java
    最后从 PermissionsState 的 hasPermission 方法获取权限。
    3.手机重启后权限的恢复
    本地保存的权限会在手机重新启动的时候由 PKMS 读取。开机时,PKMS扫描 Apk,将 APK
    AndroidManifest 中的信息按照需求更新到内存或者/data/system/packages.xml 文件,在权限管理
    方面,packages.xml 主要包含的是 install permission,就是一些普通权限,之后 APK 升级、安装、
    卸载时,都会更新packages.xml,普通权限从 package.xml 读取,而运行时权限则从
    data/system/0/runtime-permissions.xml 读取。
    由PackageManagerService调用 Settings 的 readLPw 方法来解析 xml 文件读取权限信息。
    readPackageLPw 用来解析 packages.xml , readInstallPermissionsLPr 解析 runtime-
    permissions.xml 最后再在 permissionsState 中更新授权状态。
    Settings.readLPw
    readPackageLPw readInstallPermissionsLPr
    PackageManagerService
    主要代码:
    boolean readLPw(PackageManagerService service, List users, int
    sdkVersion,
    boolean onlyCore) {
    FileInputStream str = null;
    ……
    str = new FileInputStream(mSettingsFilename);
    XmlPullParser parser = Xml.newPullParser();
    parser.setInput(str, StandardCharsets.UTF_8.name());
    int type;
    while ((type = parser.next()) != XmlPullParser.START_TAG
    && type != XmlPullParser.END_DOCUMENT) {
    ;
    }
    if (type != XmlPullParser.START_TAG) {
    mReadMessages.append(“No start tag found in settings file\n”);
    PackageManagerService.reportSettingsProblem(Log.WARN,
    “No start tag found in package manager settings”);
    Slog.wtf(PackageManagerService.TAG,
    “No start tag found in package manager settings”);
    return false;
    }
    int outerDepth = parser.getDepth();
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    && (type != XmlPullParser.END_TAG || parser.getDepth() >
    outerDepth)) {
    if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
    continue;
    }
    String tagName = parser.getName();
    if (tagName.equals(“package”)) {
    readPackageLPw(parser);
    } else if (tagName.equals(“permissions”)) {
    readPermissionsLPw(mPermissions, parser);
    } else if (tagName.equals(“permission-trees”)) {
    readPermissionsLPw(mPermissionTrees, parser);
    } else if (tagName.equals(“shared-user”)) {
    readSharedUserLPw(parser);
    ……
    } catch (XmlPullParserException e) {
    ……
    for (UserInfo user : users) {
    mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id);
    }
    }
    这里面解析了很多 xml 文件, parser 就是解析 packages.xml 的
    mSettingsFilename = new File(mSystemDir, “packages.xml”);
    其中 readPackageLPw(parser); 是用来读取 packages.xml 中对应包的权限的。
    private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException,
    IOException {
    ……
    } else if (tagName.equals(TAG_PERMISSIONS)) {
    readInstallPermissionsLPr(parser,
    packageSetting.getPermissionsState());
    packageSetting.installPermissionsFixed = true;
    private static final String TAG_PERMISSIONS = “perms”;package.xml 权限标签
    这里又调用了 readInstallPermissionsLPr
    void readInstallPermissionsLPr(XmlPullParser parser,
    PermissionsState permissionsState) throws IOException,
    XmlPullParserException {
    int outerDepth = parser.getDepth();
    int type;
    while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
    && (type != XmlPullParser.END_TAG
    || parser.getDepth() > outerDepth)) {
    if (type == XmlPullParser.END_TAG
    || type == XmlPullParser.TEXT) {
    continue;
    }
    String tagName = parser.getName();
    if (tagName.equals(TAG_ITEM)) {
    String name = parser.getAttributeValue(null, ATTR_NAME);
    BasePermission bp = mPermissions.get(name);
    if (bp == null) {
    Slog.w(PackageManagerService.TAG, "Unknown permission: " +
    name);
    XmlUtils.skipCurrentTag(parser);
    continue;
    }
    String grantedStr = parser.getAttributeValue(null, ATTR_GRANTED);
    final boolean granted = grantedStr == null
    || Boolean.parseBoolean(grantedStr);
    String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS);
    final int flags = (flagsStr != null)
    ? Integer.parseInt(flagsStr, 16) : 0;
    if (granted) {
    if (permissionsState.grantInstallPermission(bp) ==
    PermissionsState.PERMISSION_OPERATION_FAILURE) {
    Slog.w(PackageManagerService.TAG, "Permission already added:
    " + name);
    XmlUtils.skipCurrentTag(parser);
    } else {
    permissionsState.updatePermissionFlags(bp,
    UserHandle.USER_ALL,
    PackageManager.MASK_PERMISSION_FLAGS, flags);
    }
    } else {
    if (permissionsState.revokeInstallPermission(bp) ==
    PermissionsState.PERMISSION_OPERATION_FAILURE) {
    Slog.w(PackageManagerService.TAG, "Permission already added:
    " + name);
    XmlUtils.skipCurrentTag(parser);
    } else {
    permissionsState.updatePermissionFlags(bp,
    UserHandle.USER_ALL,
    PackageManager.MASK_PERMISSION_FLAGS, flags);
    }
    }
    } else {
    Slog.w(PackageManagerService.TAG, "Unknown element under
    : "
  • parser.getName());
    XmlUtils.skipCurrentTag(parser);
    }
    }
    }
    读取到 xml 中对应权限,然后更新 permissionsState
    再看 runtime 权限
    public void readStateForUserSyncLPr(int userId) {
    File permissionsFile = getUserRuntimePermissionsFile(userId);

    try {
    XmlPullParser parser = Xml.newPullParser();
    parser.setInput(in, null);
    parseRuntimePermissionsLPr(parser, userId);
    } catch (XmlPullParserException | IOException e) {
    throw new IllegalStateException("Failed parsing permissions file: "
  • permissionsFile , e);
    } finally {
    IoUtils.closeQuietly(in);
    }
    }
    调用了 parseRuntimePermissionsLPr
    private void parseRuntimePermissionsLPr(XmlPullParser parser, int userId)
    throws IOException, XmlPullParserException {
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    switch (parser.getName()) {
    case TAG_PACKAGE: {
    String name = parser.getAttributeValue(null, ATTR_NAME);
    PackageSetting ps = mPackages.get(name);
    if (ps == null) {
    Slog.w(PackageManagerService.TAG, “Unknown package:” +
    name);
    XmlUtils.skipCurrentTag(parser);
    continue;
    }
    parsePermissionsLPr(parser, ps.getPermissionsState(), userId);
    } break;
    case TAG_SHARED_USER: {
    String name = parser.getAttributeValue(null, ATTR_NAME);
    SharedUserSetting sus = mSharedUsers.get(name);
    if (sus == null) {
    Slog.w(PackageManagerService.TAG, “Unknown shared user:” +
    name);
    XmlUtils.skipCurrentTag(parser);
    continue;
    }
    parsePermissionsLPr(parser, sus.getPermissionsState(), userId);
    } break;
    }
    }
    }
    private void parsePermissionsLPr(XmlPullParser parser, PermissionsState
    permissionsState,
    int userId) throws IOException, XmlPullParserException {
    ……
    switch (parser.getName()) {
    case TAG_ITEM: {
    ……
    final boolean granted = grantedStr == null
    || Boolean.parseBoolean(grantedStr);
    String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS);
    final int flags = (flagsStr != null)
    ? Integer.parseInt(flagsStr, 16) : 0;
    if (granted) {
    permissionsState.grantRuntimePermission(bp, userId);
    permissionsState.updatePermissionFlags(bp, userId,
    PackageManager.MASK_PERMISSION_FLAGS, flags);
    } else {
    permissionsState.updatePermissionFlags(bp, userId,
    PackageManager.MASK_PERMISSION_FLAGS, flags);
    }
    } break;
    }
    }
    }
    读取到 xml 中对应权限,然后对 permissionsState 进行更新。
    4.默认授权
    systemReady
    有一些permission 可以预先授权给相应的系统默认的一些基础功能的 app。比如 ACTION_CALLL 就会
    预先授权给系统默认的打电话app.而短信相关的一些 permmisions 会预先授权给短信 app.默认授予是
    在PackageManagerService 执行 systemReady的时候执行的,主要是这个类
    DefaultPermissionGrantPolicy
    public void systemReady() {
    ……
    // If we upgraded grant all default permissions before kicking off.
    for (int userId : grantPermissionsUserIds) {
    mDefaultPermissionPolicy.grantDefaultPermissions(userId);
    }
    ……
    }
    public void grantDefaultPermissions(int userId) {
    // 系统组件和 Privileged 的应用做默认权限的处理
    grantPermissionsToSysComponentsAndPrivApps(userId);
    // 符合系统处理原则的模块进行默认权限的处理
    grantDefaultSystemHandlerPermissions(userId);
    }
    grantPermissionsToSysComponentsAndPrivApps 和
    grantDefaultSystemHandlerPermissions 都调用了
    grantRuntimePermissionsLPw(pkg, permissions, true, userId);
    最后调用
    mService.grantRuntimePermission(pkg.packageName, permission, userId);
    授权
    然后更新 flags
    mService.updatePermissionFlags(permission, pkg.packageName,
    newFlags, newFlags, userId);
    DefaultPermissionGrantPolicy.grantDefaultPermissions
    grantPermissionsToSysComponentsAndPrivApps grantDefaultSystemHandlerPermissions
    grantRuntimePermissionsLPw
    grantRuntimePermission
    updatePermissionFlags
    示例:
    // Browser
    PackageParser.Package browserPackage = null;
    String defaultBrowserPackage = mService.getDefaultBrowserPackageName(userId);
    if (defaultBrowserPackage != null) {
    browserPackage = getPackageLPr(defaultBrowserPackage);
    }
    if (browserPackage != null
    && doesPackageSupportRuntimePermissions(browserPackage)) {
    grantRuntimePermissionsLPw(browserPackage, LOCATION_PERMISSIONS, userId);
    }
    四.Android6.0 权限申请示例代码
    Android Studio 中targetSdkVersion在 build.gradle中配置
    android {
    compileSdkVersion 25
    buildToolsVersion “25.0.3”
    defaultConfig {
    applicationId “com.example.max.permissionssample”
    minSdkVersion 15
    targetSdkVersion 25 //sdk 版本必须大于等于 23
    versionCode 1
    versionName “1.0”
    testInstrumentationRunner “android.support.test.runner.AndroidJUnitRunner”
    }
    权限申请示例:
    public class MainActivity extends Activity {
    private TextView sms;
    private final int SMS_REQUEST_CODE = 1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    sms = (TextView)findViewById(R.id.id_count);
    }
    public void btnCLick(View v) {
    //首次申请权限被拒,再次申请权限时调用
    if (ActivityCompat.shouldShowRequestPermissionRationale(this,
    Manifest.permission.READ_SMS)) {
    new AlertDialog.Builder(this)
    .setTitle(“再次申请权限”)
    .setMessage(“没有读写取短信的权限功能将无法使用!”)
    .setNegativeButton(“再次拒绝”, new
    DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
    Toast.makeText(MainActivity.this, “权限申请再次被拒绝!”,
    Toast.LENGTH_SHORT).show();
    }
    })
    .setPositiveButton(“立即授权”, new
    DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
    ActivityCompat.requestPermissions(MainActivity.this,
    new String[] {android.Manifest.permission.READ_SMS,
    Manifest.permission.SEND_SMS}, SMS_REQUEST_CODE);
    }
    })
    .create()
    .show();
    }
    else {
    if (ActivityCompat.checkSelfPermission(this,
    android.Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED
    && ActivityCompat.checkSelfPermission(this,
    Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_GRANTED) {
    smsTest();
    }
    else {
    ActivityCompat.requestPermissions(MainActivity.this, new String[]
    {android.Manifest.permission.READ_SMS, Manifest.permission.SEND_SMS},
    SMS_REQUEST_CODE);;
    }
    }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[]
    permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == SMS_REQUEST_CODE) {
    Log.d(“mjx”, "count = " + grantResults.length);
    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    smsTest();
    }
    else {
    Toast.makeText(this, “权限申请被拒绝!”,
    Toast.LENGTH_SHORT).show();
    }
    }
    }
    private void smsTest() {
    Uri uri = Uri.parse(“content://sms/inbox”);
    String [] selection = new String []{“date”};
    ContentResolver res = getContentResolver();
    Cursor cur = res.query(uri, selection, null, null, null);
    sms.setText(“短信总数:” + cur.getCount());
    cur.close();
    SmsManager sm = SmsManager.getDefault();
    sm.sendTextMessage(“10010”, null, “01”, null, null);
    }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值