继续上一篇:PackageManagerService Android 8.1 源码解读 06
h、requestPermissions源码流程解析:
1、android6.0 动态申请权限的前戏:
Google在 Android 6.0 开始引入了权限申请机制,将所有权限分成了正常权限和危险权限。注意:App每次在使用危险权限时需要动态的申请并得到用户的授权才能使用。
2、权限的分类:系统权限分为两类:正常权限 和 危险权限。
2.1、正常权限不会直接给用户隐私权带来风险。如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。
2.2、危险权限会授予应用访问用户机密数据的权限。如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。如果您列出了危险权限,则用户必须明确批准您的应用使用这些权限。那么,那些是危险权限呢,为什么是危险权限呢?
<!-- 权限组:CALENDAR == 日历读取的权限申请 -->
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<!-- 权限组:CAMERA == 相机打开的权限申请 -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 权限组:CONTACTS == 联系人通讯录信息获取/写入的权限申请 -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<!-- 权限组:LOCATION == 位置相关的权限申请 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 权限组:PHONE == 拨号相关的权限申请 -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 权限组:SMS == 短信相关的权限申请 -->
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<!-- 权限组:STORAGE == 读取存储相关的权限申请 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
3、四个核心函数
1、ContextCompat.checkSelfPermission();
检查应用是否具有某个危险权限。
2、ActivityCompat.requestPermissions();
应用可以通过这个方法动态申请权限,调用后会弹出一个对话框提示用户授权所申请的权限
3、ActivityCompat.shouldShowRequestPermissionRationale
如果应用之前请求过此权限但用户拒绝了请求,此方法将返回 true。如果用户在过去拒绝了权限请求,并在
权限请求系统对话框中选择了 Don't ask again 选项,此方法将返回 false。如果设备规范禁止应用具
有该权限,此方法也会返回 false。
4、onRequestPermissionsResult
当应用请求权限时,系统将向用户显示一个对话框。当用户响应时,系统将调用应用
的onRequestPermissionsResult() 方法,向其传递用户响应,处理对应的场景。
4、现在演示,上面 “核心函数” 实例:
<!-- 第一步:在AndroidManifest.xml中添加所需权限。 -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
package com.rocky;
import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.wildma.androidnotes.R;
public class TestPermissionActivity extends AppCompatActivity {
private static final String TAG = "TestPermissionActivity";
private static final int MY_PERMISSIONS_REQUEST_READ_CONTACTS = 0x44;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermission();
}
// 第二步:封装了一个requestPermission方法来动态检查和申请权限
private void requestPermission() {
Log.i(TAG,"requestPermission");
// 同学们注意:先检查之前有没有申请过这个READ_CONTACTS权限,如果么有申请过,才申请
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
Log.i(TAG,"checkSelfPermission");
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS)) {
Log.i(TAG,"shouldShowRequestPermissionRationale 原来你个货,之前拒绝过申请权限");
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
// 申请 联系人读取权限
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
} else {
Log.i(TAG,"requestPermissions 之前没有拒绝过,正常的申请权限");
// No explanation needed, we can request the permission.
// 申请 联系人读取权限
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
}
// 第三步:重写onRequestPermissionsResult方法根据用户的不同选择做出响应。
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG,"onRequestPermissionsResult granted");
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
Log.i(TAG,"onRequestPermissionsResult denied");
// permission denied, boo! Disable the
// functionality that depends on this permission.
showWaringDialog();
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
// 如果点击 拒绝,就会弹出这个 提示框
private void showWaringDialog() {
new AlertDialog.Builder(this)
.setTitle("警告!")
.setMessage("请前往设置->应用->PermissionDemo->权限中打开相关权限,否则功能无法正常运行!")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 一般情况下如果用户不授权的话,功能是无法运行的,做退出处理
finish();
}
}).show();
}
}
运行效果:
5、requestPermissions源码整体, 总结上面的几个 ”核心函数
检查权限
checkSelfPermission(@NonNull String permission)
申请权限
requestPermissions(@NonNull String[] permissions, int requestCode)
处理结果回调
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
是否需要显示UI界面提示用户为什么需要这个权限
shouldShowRequestPermissionRationale(@NonNull String permission)
6、权限申请源码流程总结:
第一步:TestPermissionActivity 调用 requestPermissions 进行动态权限申请;
第二步:requestPermissions函数通过隐士意图,激活PackageInstaller的GrantPermissionsActivity界面,让用户选择是否授权;
第三步:经过PKMS把相关信息传递给PermissionManagerService处理;
第四步:PermissionManagerService处理结束后回调给---->PKMS中的onPermissionGranted方法把处理结果返回;
第五步:PKMS通知过程中权限变化,并调用writeRuntimePermissionsForUserLPr函数让
PackageManager的settings记录下相关授 权信息
7、 ActivityCompat.requestPermissions,
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
public static void requestPermissions(final @NonNull Activity activity,
final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode) {
if (Build.VERSION.SDK_INT >= 23) {
if (activity instanceof RequestPermissionsRequestCodeValidator) {
((RequestPermissionsRequestCodeValidator) activity)
.validateRequestPermissionsRequestCode(requestCode);
}
// 通过Activity类申请权限
activity.requestPermissions(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);
}
});
}
}
8、Activity.requestPermissions()方法:
public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
if (requestCode < 0) {
throw new IllegalArgumentException("requestCode should be >= 0");
}
if (mHasCurrentPermissionsRequest) {
Log.w(TAG, "Can reqeust only one set of permissions at a time");
// Dispatch the callback with empty arrays which means a cancellation.
onRequestPermissionsResult(requestCode, new String[0], new int[0]);
return;
}
// 构造一个Intent对象,调用PackageManager对象中的方法
Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
mHasCurrentPermissionsRequest = true;
}
9、调用PackageManager.buildRequestPermissionsIntent()方法
@SystemApi
public static final String ACTION_REQUEST_PERMISSIONS =
"android.content.pm.action.REQUEST_PERMISSIONS";
@SystemApi
public static final String EXTRA_REQUEST_PERMISSIONS_NAMES =
"android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) {
if (ArrayUtils.isEmpty(permissions)) {
throw new IllegalArgumentException("permission cannot be null or empty");
}
Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions);
intent.setPackage(getPermissionControllerPackageName());
return intent;
}
10、Activity.startActivityForResult()
@Override
public void startActivityForResult(
String who, Intent intent, int requestCode, @Nullable Bundle options) {
Uri referrer = onProvideReferrer();
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
// options 为 null
options = transferSpringboardActivityOptions(options);
// 启动 Activity,这里的Activity是GrantPermissionsActivity
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, who,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, who, requestCode,
ar.getResultCode(), ar.getResultData());
}
cancelInputsAndStartExitTransition(options);
}
11、打开GrantPermissionsActivity;在AndroidManfiest.xml中注册的,与上面的action对应
<activity android:name=".permission.ui.GrantPermissionsActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:excludeFromRecents="true"
android:theme="@style/GrantPermissions"
android:visibleToInstantApps="true">
<intent-filter android:priority="1">
<!-- 那么我们就根据”android.content.pm.action.REQUEST_PERMISSIONS“
表示动作来找到需要激活的某个Activity不就行了 -->
<action android:name="android.content.pm.action.REQUEST_PERMISSIONS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
12、onPermissionGrantResult 函数:
原来GrantPermissionsActivity也就是我们常见的权限申请界面,用户可以根据提示选择是否授权给应用相应的权限。用户操作后的结果会通过回调GrantPermissionsActivity的onPermissionGrantResult方法返回。在onPermissionGrantResult方法中会根据返回结果去决定是走授予权限还是撤销权限流程,然后会更新授权结果,最后返回结果并结束自己:
@Override
public void onPermissionGrantResult(String name, boolean granted, boolean doNotAskAgain) {
KeyguardManager kgm = getSystemService(KeyguardManager.class);
if (kgm.isDeviceLocked()) {
kgm.requestDismissKeyguard(this, new KeyguardManager.KeyguardDismissCallback() {
@Override
public void onDismissError() {
Log.e(LOG_TAG, "Cannot dismiss keyguard perm=" + name + " granted="
+ granted + " doNotAskAgain=" + doNotAskAgain);
}
@Override
public void onDismissCancelled() {
// do nothing (i.e. stay at the current permission group)
}
@Override
public void onDismissSucceeded() {
// Now the keyguard is dismissed, hence the device is not locked
// anymore
onPermissionGrantResult(name, granted, doNotAskAgain);
}
});
return;
}
GroupState groupState = mRequestGrantPermissionGroups.get(name);
if (groupState.mGroup != null) {
if (granted) {
// 【注意】重点是这个 授予权限, 下面会分析这个函数grantRuntimePermissions授予权限
groupState.mGroup.grantRuntimePermissions(doNotAskAgain,
groupState.affectedPermissions);
groupState.mState = GroupState.STATE_ALLOWED;
} else {
// 撤销权限
groupState.mGroup.revokeRuntimePermissions(doNotAskAgain,
groupState.affectedPermissions);
groupState.mState = GroupState.STATE_DENIED;
int numRequestedPermissions = mRequestedPermissions.length;
for (int i = 0; i < numRequestedPermissions; i++) {
String permission = mRequestedPermissions[i];
if (groupState.mGroup.hasPermission(permission)) {
EventLogger.logPermissionDenied(this, permission,
mAppPermissions.getPackageInfo().packageName);
}
}
}
// 更新授权结果
updateGrantResults(groupState.mGroup);
}
if (!showNextPermissionGroupGrantRequest()) {
// 返回授权结果并结束自己
setResultAndFinish();
}
}
13、接下来继续跟踪AppPermissionGroup.grantRuntimePermissions方法分析授权流程。
AppPermissionGroup.grantRuntimePermissions方法中会判断targetSdkVersion是否大于LOLLIPOP_MR1(22),如果大于则做动态权限申请处理
packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/model/AppPermissionGroup.java
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()) {
.......
// Grant the permission if needed.
if (!permission.isGranted()) {
permission.setGranted(true);
// 授权
mPackageManager.grantRuntimePermission(mPackageInfo.packageName,
permission.getName(), mUserHandle);
}
......
}
return true;
}
14、进入ApplicationPackageManager.java类中grantRuntimePermission()授权方法;因为ApplicationPackageManager类继承自PackageManager的抽象类
private final IPackageManager mPM;
@Override
public void grantRuntimePermission(String packageName, String permissionName,
UserHandle user) {
try {
// 调用PKMS的方法进行授权操作
mPM.grantRuntimePermission(packageName, permissionName, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
这个mPM其实就是PKMS的服务代理类
15、PKMS.grantRuntimePermission()方法->grantRuntimePermission()->PermissionsState.grantRuntimePermission()->grantPermission()->ensurePermissionData(),这是调用栈
// -->>>PermissionsState.java类,授权添加到ArrayMap集合中
private PermissionData ensurePermissionData(BasePermission permission) {
// 判断mPermissions集合是否为空,null则创建集合对象
if (mPermissions == null) {
mPermissions = new ArrayMap<>();
}
// 通过权限的名称从集合中获取权限对象:permissionData
PermissionData permissionData = mPermissions.get(permission.name);
if (permissionData == null) {
permissionData = new PermissionData(permission);
// 添加权限对象
mPermissions.put(permission.name, permissionData);
}
// 返回权限对象
return permissionData;
}
16、下面一个一个方法来看:到PKMS服务类中,代码量就很多了
private void grantRuntimePermission(String packageName, String name, final int userId,
boolean overridePolicy) {
// 判断userId是否存在,不存在直接返回
if (!sUserManager.exists(userId)) {
Log.e(TAG, "No such user:" + userId);
return;
}
// 记录Binder调用的uid
final int callingUid = Binder.getCallingUid();
// 强制检测调用uid是否有申请了运行时的授权权限
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
"grantRuntimePermission");
enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, true /* checkShell */,
"grantRuntimePermission");
final int uid;
final PackageSetting ps;
synchronized (mPackages) {
// 根据包名获取Package对象
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
// 通过权限名称获取基础权限对象
final BasePermission bp = mSettings.mPermissions.get(name);
if (bp == null) {
throw new IllegalArgumentException("Unknown permission: " + name);
}
// 获取PackageSetting对象
ps = (PackageSetting) pkg.mExtras;
if (ps == null
|| filterAppAccessLPr(ps, callingUid, userId)) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
// to keep the review required permission flag per user while an
// install permission's state is shared across all users.
if (mPermissionReviewRequired
&& pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
&& bp.isRuntime()) {
return;
}
uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
// 通过ps获取 PermissionsState 对象
final PermissionsState permissionsState = ps.getPermissionsState();
// 获取权限的flags标志
final int flags = permissionsState.getPermissionFlags(name, userId);
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
throw new SecurityException("Cannot grant system fixed permission "
+ name + " for package " + packageName);
}
if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
throw new SecurityException("Cannot grant policy fixed permission "
+ name + " for package " + packageName);
}
// 忽略开发者模式
if (bp.isDevelopment()) {
// Development permissions must be handled specially, since they are not
// normal runtime permissions. For now they apply to all users.
if (permissionsState.grantInstallPermission(bp) !=
PermissionsState.PERMISSION_OPERATION_FAILURE) {
scheduleWriteSettingsLocked();
}
return;
}
// 判断是否为及时apk
if (ps.getInstantApp(userId) && !bp.isInstant()) {
throw new SecurityException("Cannot grant non-ephemeral permission"
+ name + " for package " + packageName);
}
// sdk版本小于M,直接返回
if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
Slog.w(TAG, "Cannot grant runtime permission to a legacy app");
return;
}
// 通过 grantRuntimePermission 函数开始授权权限,然后得到结果
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() {
// kill uid
killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED);
}
});
}
break;
}
// 判断是否为运行时,打印权限授权
if (bp.isRuntime()) {
logPermissionGranted(mContext, name, packageName);
}
// 回调权限更新的监听器
mOnPermissionChangeListeners.onPermissionsChanged(uid);
//
//如果丢失不重要-应用程序必须再次请求。向文件中写运行时的权限
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
// Only need to do this if user is initialized. Otherwise it's a new user
// and there are no processes running as the user yet and there's no need
// to make an expensive call to remount processes for the changed permissions.
// 判断权限是否为读写外置存储的权限,如果是,则回调相关信息
if (READ_EXTERNAL_STORAGE.equals(name)
|| WRITE_EXTERNAL_STORAGE.equals(name)) {
final long token = Binder.clearCallingIdentity();
try {
if (sUserManager.isInitialized(userId)) {
StorageManagerInternal storageManagerInternal = LocalServices.getService(
StorageManagerInternal.class);
storageManagerInternal.onExternalStoragePolicyChanged(uid, packageName);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
}
上面有三个比较重要的方法,后面会分析
PermissionsState.grantRuntimePermission->授权权限
mOnPermissionChangeListeners.onPermissionsChanged->更新权限的监听器
mSettings.writeRuntimePermissionsForUserLPr->将运行时的权限写入到文件中,就是Settings类
16.1、第一步:PermissionsState.grantRuntimePermission()方法干了什么事情呢?主要是将权限写入到内存集合中
private ArrayMap<String, PermissionData> mPermissions;
public int grantRuntimePermission(BasePermission permission, int userId) {
enforceValidUserId(userId);
// 判断userId,到哪里都有这个userId
if (userId == UserHandle.USER_ALL) {
return PERMISSION_OPERATION_FAILURE;
}
// 调用下一个方法->grantPermission
return grantPermission(permission, userId);
}
// 继续授权权限的处理
private int grantPermission(BasePermission permission, int userId) {
//判断这个权限是否已授权
if (hasPermission(permission.name, userId)) {
return PERMISSION_OPERATION_FAILURE;
}
final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
// 调用 ensurePermissionData 方法确认权限数据,将数据将入到集合中
PermissionData permissionData = ensurePermissionData(permission);
// 判断返回的对象是否已经有授权,没有授权,直接返回
if (!permissionData.grant(userId)) {
return PERMISSION_OPERATION_FAILURE;
}
if (hasGids) {
final int[] newGids = computeGids(userId);
if (oldGids.length != newGids.length) {
return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
}
}
// 授权成功,返回正确的结果
return PERMISSION_OPERATION_SUCCESS;
}
// 确认权限数据,也就是将BasePermission加入到集合中,这是加载到内存,下面还会写入到权限文件中
private PermissionData ensurePermissionData(BasePermission permission) {
if (mPermissions == null) {
mPermissions = new ArrayMap<>();
}
PermissionData permissionData = mPermissions.get(permission.name);
if (permissionData == null) {
permissionData = new PermissionData(permission);
mPermissions.put(permission.name, permissionData);
}
return permissionData;
}
16.2、第二步:更新权限mOnPermissionChangeListeners.onPermissionsChanged 回调到PackageInstaller应用中;
// --->>PackageManagerService.java类
// 申明一个权限改变的监听器;其实就是一个Handler发送消息
private final OnPermissionChangeListeners mOnPermissionChangeListeners;
private final static class OnPermissionChangeListeners extends Handler {
private static final int MSG_ON_PERMISSIONS_CHANGED = 1;
// 外部添加的权限改变监听器对象都在这个集合中保存
private final RemoteCallbackList<IOnPermissionsChangeListener> mPermissionListeners =
new RemoteCallbackList<>();
public OnPermissionChangeListeners(Looper looper) {
super(looper);
}
// handler消息处理方法
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_ON_PERMISSIONS_CHANGED: {
final int uid = msg.arg1;
handleOnPermissionsChanged(uid);
} break;
}
}
// 添加监听器
public void addListenerLocked(IOnPermissionsChangeListener listener) {
mPermissionListeners.register(listener);
}
// 移除监听器
public void removeListenerLocked(IOnPermissionsChangeListener listener) {
mPermissionListeners.unregister(listener);
}
// 权限改变调用,发送消息
public void onPermissionsChanged(int uid) {
if (mPermissionListeners.getRegisteredCallbackCount() > 0) {
obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
}
}
// 这里是对调给各个对象
private void handleOnPermissionsChanged(int uid) {
final int count = mPermissionListeners.beginBroadcast();
try {
// 遍历监听器,跨进程全部更新
for (int i = 0; i < count; i++) {
IOnPermissionsChangeListener callback = mPermissionListeners
.getBroadcastItem(i);
try {
callback.onPermissionsChanged(uid);
} catch (RemoteException e) {
Log.e(TAG, "Permission listener is dead", e);
}
}
} finally {
mPermissionListeners.finishBroadcast();
}
}
}
// 添加权限,这是一个可以跨进程调用的方法,将监听器添加到集合中
@Override
public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS,
"addOnPermissionsChangeListener");
synchronized (mPackages) {
mOnPermissionChangeListeners.addListenerLocked(listener);
}
}
geInstaller应用,在PackageInstaller安装器应用添加的监听器:
// --->>>packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/model/PermissionGroups.java
// 实现 PackageManager.OnPermissionsChangedListener 的方法
private static final class PermissionsLoader extends AsyncTaskLoader<List<PermissionGroup>>
implements PackageManager.OnPermissionsChangedListener {
public PermissionsLoader(Context context) {
super(context);
}
@Override
protected void onStartLoading() {
// 跨进程向PKMS服务中添加权限改变的监听器
getContext().getPackageManager().addOnPermissionsChangeListener(this);
forceLoad();
}
@Override
protected void onStopLoading() {
// 移除监听器
getContext().getPackageManager().removeOnPermissionsChangeListener(this);
}
......省略代码
@Override
public void onPermissionsChanged(int uid) {
// 强制加载权限
forceLoad();
}
}
16.3、mSettings.writeRuntimePermissionsForUserLPr 将运行权限写入到xml文件中,就是这个方法了;在Settings中执行
frameworks/base/services/core/java/com/android/server/pm/Settings.java
// 内部类
private final RuntimePermissionPersistence mRuntimePermissionsPersistence;
// 是同步写权限还是异步写,sync参数是false,异步写权限到xml文件中
public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) {
if (sync) {
mRuntimePermissionsPersistence.writePermissionsForUserSyncLPr(userId);
} else {
mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
}
}
//-------------------->>>>>>>>>>>>>>>>>>>>>
private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 200;
public void writePermissionsForUserAsyncLPr(int userId) {
final long currentTimeMillis = SystemClock.uptimeMillis();
// 判断userId是否有任务,如果有就进入if体,删除这个消息,再发送延迟消息
if (mWriteScheduled.get(userId)) {
mHandler.removeMessages(userId);
......省略代码
Message message = mHandler.obtainMessage(userId);
mHandler.sendMessageDelayed(message, writeDelayMillis);
} else {
mLastNotWrittenMutationTimesMillis.put(userId, currentTimeMillis);
Message message = mHandler.obtainMessage(userId);
mHandler.sendMessageDelayed(message, WRITE_PERMISSIONS_DELAY_MILLIS);
mWriteScheduled.put(userId, true);
}
}
//-------------------->>>>>>>>>>>>>>>>>>>>>
private final Handler mHandler = new MyHandler();
// 就调用一个方法
private final class MyHandler extends Handler {
public MyHandler() {
super(BackgroundThread.getHandler().getLooper());
}
@Override
public void handleMessage(Message message) {
final int userId = message.what;
Runnable callback = (Runnable) message.obj;
// 执行同步写权限
writePermissionsSync(userId);
if (callback != null) {
callback.run();
}
}
}
private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml";
// 获取用户运行权限的文件,获取到的文件:
private File getUserRuntimePermissionsFile(int userId) {
// 获取 /data/system/users/0/ 目录
File userDir = new File(new File(mSystemDir, "users"), Integer.toString(userId));
// 创建文件:/data/system/users/0/runtime-permissions.xml
return new File(userDir, RUNTIME_PERMISSIONS_FILE_NAME);
}
// 同步向runtime-permissions.xml文件中执行写权限的数据
private void writePermissionsSync(int userId) {
// 获取原子操作的文件:/data/system/users/0/runtime-permissions.xml
AtomicFile destination = new AtomicFile(getUserRuntimePermissionsFile(userId));
//定义两个集合
ArrayMap<String, List<PermissionState>> permissionsForPackage = new ArrayMap<>();
ArrayMap<String, List<PermissionState>> permissionsForSharedUser = new ArrayMap<>();
synchronized (mLock) {
// 删除userId
mWriteScheduled.delete(userId);
// 获取 apk的包个数
final int packageCount = mPackages.size();
for (int i = 0; i < packageCount; i++) {
// 获取包名
String packageName = mPackages.keyAt(i);
// 获取包的设置对象:PackageSetting
PackageSetting packageSetting = mPackages.valueAt(i);
// 判断sharedUID,然后通过userId为每个apk,动态获取权限对象:PermissionsState
if (packageSetting.sharedUser == null) {
// 获取权限对象:PermissionsState
PermissionsState permissionsState = packageSetting.getPermissionsState();
// 通过userId获取权限集合
List<PermissionState> permissionsStates = permissionsState
.getRuntimePermissionStates(userId);
// 将permissionsStates 添加到上面定义的集合中,需要写入到文件中的
if (!permissionsStates.isEmpty()) {
permissionsForPackage.put(packageName, permissionsStates);
}
}
}
// 获取shareUid的个数也就是,那几个共享的shareUid
final int sharedUserCount = mSharedUsers.size();
for (int i = 0; i < sharedUserCount; i++) {
String sharedUserName = mSharedUsers.keyAt(i);
SharedUserSetting sharedUser = mSharedUsers.valueAt(i);
PermissionsState permissionsState = sharedUser.getPermissionsState();
List<PermissionState> permissionsStates = permissionsState
.getRuntimePermissionStates(userId);
if (!permissionsStates.isEmpty()) {
permissionsForSharedUser.put(sharedUserName, permissionsStates);
}
}
}
// 开始向文件中写数据
FileOutputStream out = null;
try {
out = destination.startWrite();
XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(out, StandardCharsets.UTF_8.name());
serializer.setFeature(
"http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startDocument(null, true);
// 写标签:"runtime-permissions"
serializer.startTag(null, TAG_RUNTIME_PERMISSIONS);
// 获取fingerprint字符串,然后写属性:"fingerprint"
String fingerprint = mFingerprints.get(userId);
if (fingerprint != null) {
serializer.attribute(null, ATTR_FINGERPRINT, fingerprint);
}
// 写apk个数的运行权限
final int packageCount = permissionsForPackage.size();
for (int i = 0; i < packageCount; i++) {
String packageName = permissionsForPackage.keyAt(i);
List<PermissionState> permissionStates = permissionsForPackage.valueAt(i);
serializer.startTag(null, TAG_PACKAGE);
serializer.attribute(null, ATTR_NAME, packageName);
writePermissions(serializer, permissionStates);
serializer.endTag(null, TAG_PACKAGE);
}
// shareUser共享用户的运行权限
final int sharedUserCount = permissionsForSharedUser.size();
for (int i = 0; i < sharedUserCount; i++) {
String packageName = permissionsForSharedUser.keyAt(i);
List<PermissionState> permissionStates = permissionsForSharedUser.valueAt(i);
serializer.startTag(null, TAG_SHARED_USER);
serializer.attribute(null, ATTR_NAME, packageName);
writePermissions(serializer, permissionStates);
serializer.endTag(null, TAG_SHARED_USER);
}
// 写结束
serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);
.......省略代码
serializer.endDocument();
destination.finishWrite(out);
if (Build.FINGERPRINT.equals(fingerprint)) {
mDefaultPermissionsGranted.put(userId, true);
}
// Any error while writing is fatal.
} catch (Throwable t) {
Slog.wtf(PackageManagerService.TAG,
"Failed to write settings, restoring backup", t);
destination.failWrite(out);
} finally {
IoUtils.closeQuietly(out);
}
}
这个runtime-permissions.xml文件的格式如下:
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<runtime-permissions fingerprint="alps/full_k37mv1_bsp/k37mv1_bsp:8.1.0/O11019/1599907289:user/test-keys">
.......省略很多
<pkg name="com.autonavi.amapauto">
<item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="20" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="0" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="20" />
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="0" />
<item name="android.permission.CAMERA" granted="true" flags="0" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="0" />
<item name="android.permission.RECORD_AUDIO" granted="true" flags="0" />
</pkg>
<pkg name="com.android.packageinstaller">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="30" />
</pkg>
<shared-user name="android.media">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="30" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="30" />
</shared-user>
<shared-user name="com.iflytek.speechcloud">
<item name="android.permission.READ_CALL_LOG" granted="true" flags="40" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="40" />
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="40" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="40" />
<item name="android.permission.RECORD_AUDIO" granted="true" flags="40" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="40" />
</shared-user>
<shared-user name="com.aispeech.aios">
<item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="40" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="40" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="40" />
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="40" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="40" />
<item name="android.permission.RECORD_AUDIO" granted="true" flags="40" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="40" />
</shared-user>
<shared-user name="android.uid.bluetooth">
<item name="android.permission.READ_SMS" granted="true" flags="30" />
<item name="android.permission.READ_CALL_LOG" granted="true" flags="30" />
<item name="android.permission.RECEIVE_SMS" granted="true" flags="30" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="30" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="30" />
<item name="android.permission.SEND_SMS" granted="true" flags="30" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="30" />
<item name="android.permission.WRITE_CALL_LOG" granted="true" flags="30" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="30" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="30" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
</shared-user>
<shared-user name="android.uid.shared">
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="30" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="30" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="30" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
</shared-user>
<shared-user name="android.uid.system">
<item name="android.permission.READ_SMS" granted="true" flags="30" />
<item name="android.permission.READ_CALL_LOG" granted="true" flags="30" />
<item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="30" />
<item name="android.permission.RECEIVE_WAP_PUSH" granted="true" flags="30" />
<item name="android.permission.RECEIVE_SMS" granted="true" flags="30" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="30" />
<item name="com.mediatek.permission.CTA_CONFERENCE_CALL" granted="true" flags="30" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="30" />
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="30" />
<item name="android.permission.CALL_PHONE" granted="true" flags="30" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="30" />
<item name="android.permission.CAMERA" granted="true" flags="30" />
<item name="android.permission.WRITE_CALL_LOG" granted="true" flags="30" />
<item name="android.permission.PROCESS_OUTGOING_CALLS" granted="true" flags="30" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="30" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="30" />
<item name="android.permission.RECORD_AUDIO" granted="true" flags="30" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
</shared-user>
......省略很多
</runtime-permissions>
这里为止,整个运行权限的授权过程基本上就结束了;