Android Runtime permission研究分析

前言:

带着问题研究问题,如下分析就是按照这种思路进行的分析。

背景:

运行时权限是Android 6.0 变更中尤为突出的一点。6以下的手机在安装时候提示权限列表,用户全部同意后才能安装程序;6以后的手机直接安装,在运行过程中动态的向用户申请所需权限,另外用户可以在设置界面对程序的各个权限进行管理。

Android 中的权限可以分为三类:

普通权限(Normal Permissions)

危险权限(Dangerous Permissions)

特殊权限(Special Permissions)

普通权限不涉及用户隐私,在AndroidManifest.xml中声明即获取;危险权限涉及用户的隐私,在用户授权之后方能使用。另外,Google 对危险权限进行了分组,当某一个组中的某一个权限被授权之后应用同时就获取到了整个组的所有权限。而且,调用 API 申请权限时系统将向用户显示一个标准对话框,该对话框上的提示权限说明是针对整个组的说明,应用无法配置或更改此对话框。

问题:

1.怎么默认就给予了apk相应的权限?

案例一:怎么默认就给予了apk相应的权限?

条件:

Android 8.1系统源码分析

过程:

我们了解到PackageManagerService(简称:PMS)管理着所有跟package相关的工作,例如安装、卸载应用等,所以,应该大概从PMS入手。

我们系统开机的过程,init进程拉起Zygote进程,Zygote进程拉起了system_server进程,而system_server初始化Binder通信服务,这里包含PMS。

代码:

framework/base/services/java/com/android/server/SystemServer.java

public static void main(String[] args) {

        new SystemServer().run();

}

private void run() {

······

startBootstrapServices();

/// M: For mtk systemserver

sMtkSystemServerIns.startMtkBootstrapServices();

startCoreServices();

/// M: for mtk other service.

sMtkSystemServerIns.startMtkCoreServices();

startOtherServices();

······

}

private void startBootstrapServices() {

······

traceBeginAndSlog("StartPackageManagerService");

mPackageManagerService = PackageManagerService.main(mSystemContext, installer,

                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);

mFirstBoot = mPackageManagerService.isFirstBoot();

······

}

private void startOtherServices() {

      ······

        traceBeginAndSlog("MakePackageManagerServiceReady");

        try {

            mPackageManagerService.systemReady();

        } catch (Throwable e) {

            reportWtf("making Package Manager Service ready", e);

        }

        traceEnd();

        ······

}
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

public void systemReady() {

······

    // If we upgraded grant all default permissions before kicking off.

    for (int userId : grantPermissionsUserIds) {

        mDefaultPermissionPolicy.grantDefaultPermissions(userId);

    }

······

}


frameworks/base/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java

public void grantDefaultPermissions(int userId) {

        **// 方案一:只要强制把FEATURE_EMBEDDED 打开,这样默认授权了所有apk的权限**

        if (mService.hasSystemFeature(PackageManager.FEATURE_EMBEDDED, 0)) {

            grantAllRuntimePermissions(userId);

        } else {

            // 系统组件和priv-app下面的默认授权

            grantPermissionsToSysComponentsAndPrivApps(userId);

            //系统特殊处理的apk

            grantDefaultSystemHandlerPermissions(userId);

            grantDefaultPermissionExceptions(userId);

        }

}

方案二:

第一部分:

// 1.isSysComponentOrPersistentPlatformSignedPrivAppLPr

//    a.priv-app b.apk为persist属性 c.apk签名一致

// 2.doesPackageSupportRuntimePermission

//    apk的版本大于LOLLIPOP_MR1

// 3.pkg.requestedPermissions.isEmpty()

//    没有权限的apk

private void grantPermissionsToSysComponentsAndPrivApps(int userId) {

        Log.i(TAG, "Granting permissions to platform components for user " + userId);

        synchronized (mService.mPackages) {

            for (PackageParser.Package pkg : mService.mPackages.values()) {

                if (!isSysComponentOrPersistentPlatformSignedPrivAppLPr(pkg)

                        || !doesPackageSupportRuntimePermissions(pkg)

                        || pkg.requestedPermissions.isEmpty()) {

                    continue;

                }

                grantRuntimePermissionsForPackageLocked(userId, pkg);

            }

        }

    }

    private boolean isSysComponentOrPersistentPlatformSignedPrivAppLPr(PackageParser.Package pkg) {

        if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {

            return true;

        }

        if (!pkg.isPrivilegedApp()) {//priv-app

            return false;

        }

        PackageSetting sysPkg = mService.mSettings.getDisabledSystemPkgLPr(pkg.packageName);

        if (sysPkg != null && sysPkg.pkg != null) {//特别说明,app的AndroidManifest.xml中application可以设置persist属性

            if ((sysPkg.pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {

                return false;

            }

        } else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {//persistent app

            return false;

        }

        return PackageManagerService.compareSignatures(mService.mPlatformPackage.mSignatures,

                pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;//apk签名一致

    } 

第二部分:

private void grantDefaultSystemHandlerPermissions(int userId) {

······

//可以参考方法内部对各种apk的权限处理

//或者直接参考grantAllRuntimePermissions(userId);中对apk的权限处理

······

}

第三部分:

private void grantDefaultPermissionExceptions(int userId) {
    ······
    if (mGrantExceptions == null) {
        //读取的是system/etc/default-permissions下面的xml文件
        //也就是说,我们只要把想要获取动态权限的apk,按照既定格式
        //放到此目录下面,也是可以让apk默认给予权限的
        mGrantExceptions = readDefaultPermissionExceptionsLPw();
    }
    ······
    for (int i = 0; i < exceptionCount; i++) {
          String packageName = mGrantExceptions.keyAt(i);
          //从这里继续研究跟踪下去可知:这是system app条件
          PackageParser.Package pkg = getSystemPackageLPr(packageName);
          ······
    }
    ······
 }

详细分析如下:
 private @NonNull ArrayMap>
            readDefaultPermissionExceptionsLPw() {
       File[] files = getDefaultPermissionFiles();//获取的目录
       ·······
       try (
                InputStream str = new BufferedInputStream(new FileInputStream(file))
            ) {
                XmlPullParser parser = Xml.newPullParser();
                parser.setInput(str, null);
                parse(parser, grantExceptions);//既定格式
            } catch (XmlPullParserException | IOException e) {
                Slog.w(TAG, "Error reading default permissions file " + file, e);
            }
        ······
  }
  
private File[] getDefaultPermissionFiles() {
        ArrayList ret = new ArrayList();
        File dir = new File(Environment.getRootDirectory(), "etc/default-permissions");
        if (dir.isDirectory() && dir.canRead()) {
            Collections.addAll(ret, dir.listFiles());
        }
        dir = new File(Environment.getVendorDirectory(), "etc/default-permissions");
        if (dir.isDirectory() && dir.canRead()) {
            Collections.addAll(ret, dir.listFiles());
        }
        return ret.isEmpty() ? null : ret.toArray(new File[0]);
 }          
 
 private void parse(XmlPullParser parser, Map>
            outGrantExceptions) throws IOException, XmlPullParserException {
        //简单说明格式
        //
        //
        //
        //
        //
        // 
        //重点说明:fixed的意思:如果为true代表其状态跟谁系统状态而定,如果为false,代表强制默认打开
        //介绍处:PackageManager.FLAG_PERMISSION_SYSTEM_FIXED/PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT
 }
 
 private PackageParser.Package getSystemPackageLPr(String packageName) {
        PackageParser.Package pkg = getPackageLPr(packageName);
        if (pkg != null && pkg.isSystemApp()) {//代表满足isSystemApp的apk都是可以这么做,例如:system/app system/priv-app vendor/app vendor/priv-app
            return !isSysComponentOrPersistentPlatformSignedPrivAppLPr(pkg) ? pkg : null;
        }
        return null;
}

总结:系统默认了3种实现方式默认给apk授权权限

补充说明:
问题点:不管是系统默认操作还是我们手动操作,最后的动态权限是否保存在文件中?

关键部分:
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

public void updatePermissionFlags(String name, String packageName, int flagMask,
            int flagValues, int userId) {
 ······
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
······
}

frameworks/base/services/core/java/com/android/server/pm/Settings.java

public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) {
        if (sync) {
            mRuntimePermissionsPersistence.writePermissionsForUserSyncLPr(userId);
        } else {
            mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
        }
}

public void writePermissionsForUserAsyncLPr(int userId) {
    ······
    if (mWriteScheduled.get(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 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 void writePermissionsSync(int userId) {
//写入的是这个文件:/data/system/users/0/runtime-permissions.xml
}

案例二:检查权限和默认授予权限是怎么关联起来的?

关键点:
Context.checkSelfPermission
Activity.requestPermissions
Activity.onRequestPermissionsResult
Activity.shouldShowRequestPermissionRationale

从Activity.requestPermissions入手分析
Activity.java -->AMS-->PackageInstaller(GrantPermissionsActivity.java)-->PMS:updatePermissionFlags

关键代码:
PackageManagerService.java
public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
   return getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
                flags, Binder.getCallingUid(), userId);
}

 private PackageInfo getPackageInfoInternal(String packageName, int versionCode,
            int flags, int filterCallingUid, int userId) {
 //从这段方法可以知道,最终的数据来自mSettings
 //因为基本上PackageSetting来自mSettings
 //所以,初始化mSettings很重要
 //这里涉及PMS构造方法中的这句语句:mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
 //把mSettings的各种权限状态都初始化了,特别注意boolean readLPw(@NonNull List users)中的
 //mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id);这是runtime权限初始化的地方
 ·····
 }
 
 private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
       //重点在PermissionsState
       //这里的初始化的动作都在PMS中
       ······
       final PermissionsState permissionsState = ps.getPermissionsState();

        // Compute GIDs only if requested
        final int[] gids = (flags & PackageManager.GET_GIDS) == 0
                ? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
        // Compute granted permissions only if package has requested permissions
        final Set permissions = ArrayUtils.isEmpty(p.requestedPermissions)
                ? Collections.emptySet() : permissionsState.getPermissions(userId);
         ······
         PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags,
                ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
         ······
 }



从Context.checkSelfPermission入手分析

ContextImpl.java
public int checkSelfPermission(String permission) {
        if (permission == null) {
            throw new IllegalArgumentException("permission is null");
        }
        return checkPermission(permission, Process.myPid(), Process.myUid());
}

public int checkPermission(String permission, int pid, int uid) {
        if (permission == null) {
            throw new IllegalArgumentException("permission is null");
        }

        final IActivityManager am = ActivityManager.getService();
        if (am == null) {
            // Well this is super awkward; we somehow don't have an active
            // ActivityManager instance. If we're testing a root or system
            // UID, then they totally have whatever permission this is.
            final int appId = UserHandle.getAppId(uid);
            if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
                Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission);
                return PackageManager.PERMISSION_GRANTED;
            }
        }

        try {
            return am.checkPermission(permission, pid, uid);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
}

ActivityManagerService.java
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);
}

ActivityManager.java
public static int checkComponentPermission(String permission, int uid,
            int owningUid, boolean exported) {
    ·······
    return AppGlobals.getPackageManager()
                    .checkUidPermission(permission, uid);
}

PackageManagerService.java
public int checkUidPermission(String permName, int uid){
    //关键点:mSettings、PermissionsState
    ``````
    Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
    ``````  
    final PermissionsState permissionsState = settingBase.getPermissionsState();
                if (permissionsState.hasPermission(permName, userId)) {
                    if (isUidInstantApp) {
                        BasePermission bp = mSettings.mPermissions.get(permName);
                        if (bp != null && bp.isInstant()) {
                            return PackageManager.PERMISSION_GRANTED;
                        }
                    } else {
                        return PackageManager.PERMISSION_GRANTED;
                    }
                }  
}
注:
Tips
a.权限涉及到的模块AMS、PMS、PackageInstaller(安装器)。动态权限的对话框也是安装器展示
b.PackageManager的实现类为ApplicationPackageManager

adb快速查看

查看系统所拥有的危险权限

adb shell pm list permissions -d -g 查看危险权限指令

查看某一个apk所拥有的权限

adb shell pm dump 包名 | findstr permission
例如:adb shell pm dump com.smart.launcher | findstr permission

参考学习

https://blog.csdn.net/sinat_20059415/article/details/80369872
https://blog.csdn.net/zchy198799/article/details/89341974
https://blog.csdn.net/u013553529/article/details/53167072
https://blog.csdn.net/csdnxialei/article/details/93628890

你可能感兴趣的:(Android Runtime permission研究分析)