PackageManagerService Android 8.1 源码解读 07

继续上一篇: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函数通过隐士意图,激活PackageInstallerGrantPermissionsActivity界面,让用户选择是否授权

第三步:经过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>

这里为止,整个运行权限的授权过程基本上就结束了;
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值