您的位置:首页 > 移动开发 > Android开发

Android6.0 framework层权限相关源码分析

2016-07-19 16:17 393 查看
1、概述。

此处只研究了一下framework层的权限相关的代码和逻辑,至于和linux层的对应后续再跟踪。分析6.0的权限模型,其实就是分

析应用apk被解析安装到手机上时,是如何解析apk的manifest清单文件中的关于权限的一些配置的。此处从两方面着手的安装流程,

一方面是系统解析本身就有的apk,一方面是下载到手机里面的apk,然后点击安装。

2、解析系统应用。

此处就从SystemServer开始介绍,前面开机如何加载这个服务就不介绍了。





Step1.PackageManagerService.main

public static PackageManagerService main(Context context, Installer
installer,

boolean factoryTest, boolean onlyCore) {

PackageManagerService m = new PackageManagerService(context, installer,

factoryTest, onlyCore);

ServiceManager.addService("package", m);

return m;

}

这个函数创建了一个PMS的实例,然后把这个服务添加到ServicesManager中去。那么创建这个实例的时候就会去走

PMS的构造,如下。

public PackageManagerService(Context context, Installer installer,

boolean
factoryTest, boolean onlyCore) {

......

mSettings = new Settings(mPackages); //实例化一个Settings类的对象,用于在解析这个apk的过程中存放各种变量

......

//加载一些全局的系统的配置,如system/etc/Permissions 文件下面的各个xml的解析(有权限,有特征等等)

//然后放到相应的成员变量如:

//1、final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();每个权限名字对应一个

//PermissionEntry,这个成员变量解析的是<permission>的标签。

//2、final
SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();每个uid,所对应的所有

//权限,这个成员变量是解析<assign-permission>标签下的权限。

SystemConfig systemConfig = SystemConfig.getInstance();

......

ArrayMap<String, SystemConfig.PermissionEntry> permConfig = systemConfig.getPermissions();

for (int i=0; i<permConfig.size(); i++) {
SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
BasePermission bp = mSettings.mPermissions.get(perm.name);
if (bp == null) {
//一个权限对应一个BasePermission,和是那个应用的权限无关。最终都放到mSettings.mPermissions
bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
mSettings.mPermissions.put(perm.name, bp);
}
if (perm.gids != null) {
bp.setGids(perm.gids, perm.perUser);
}
}

......

File frameworkDir = new File(Environment.getRootDirectory(),
"framework");

File vendorOverlayDir
= new File(VENDOR_OVERLAY_DIR);

//扫描/vendor/overlay

scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
//扫描 /system/framework

scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);

//扫描 /system/priv-app
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");

scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);

//扫描 /system/app
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

//扫描vendor/app
File vendorAppDir = new File("/vendor/app");
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

// 扫描oem/app
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
//以上会调用scanDirLI函数来设备上的指定目录下的apk文件,注意其传入的参数有各种系统级别的解析才传入的以
//来证明是系统应用等等。
......

}

Step2.PackageManagerService.scanDirLI

private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {

final File[] files = dir.listFiles();

......

for (File file : files) {

//是否是个apk文件或者是个目录。

final boolean isPackage = (isApkFile(file) || file.isDirectory())&&
!PackageInstallerService.isStageName(file.getName());

if (!isPackage) {

// Ignore entries which are not packages
continue;

}

.............

try {

//调用scanPackageLI进一步解析

scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,

scanFlags, currentTime, null);

} catch (PackageManagerException e) {......}

}

}
此函数就是解析传过来的第一个参数,如果是apk文件或者是目录,就对其一一调用scanPackageLI进行解析。

Step3.PackageManagerService. scanPackageLI

private PackageParser.Package scanPackageLI(File scanFile,
int parseFlags, int scanFlags,

long currentTime, UserHandle user) throws PackageManagerException {

PackageParser pp = new PackageParser();

......

final PackageParser.Package pkg;

try {

pkg = pp.parsePackage(scanFile, parseFlags);

} catch (PackageParserException e) {...}
......

| SCAN_UPDATE_SIGNATURE, currentTime, user);
......
return scannedPkg;

}

通过创建PackagePaser实例并调用它的parsePackage来解析pkg文件,注意这个函数的参数也是通过path路劲来解析的,最终还

得需要另外的一个重写的scanPackageLI方法来实现包解析玩的pkg保存在PMS中。

Step4.PackageParser.parsePackage

public
Package parsePackage(File packageFile, int flags) throws PackageParserException {

//通过判断是一个apk文件还是一个目录

if (packageFile.isDirectory()) {

return parseClusterPackage(packageFile, flags);

} else {

return parseMonolithicPackage(packageFile, flags);

}

}
此函数会进一步的判断传入的是一个apk文件还是一个目录,进而在调用不同的解析方法。最终都会调用到parseBaseApk里
private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
throws PackageParserException {
if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
"Invalid package file: " + apkPath);
}

// The AssetManager guarantees uniqueness for asset paths, so if this asset path
// already exists in the AssetManager, addAssetPath will only return the cookie
// assigned to it.
int cookie = assets.addAssetPath(apkPath);
if (cookie == 0) {
throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Failed adding asset path: " + apkPath);
}
return cookie;
}

private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
......
Resources res = null;
XmlResourceParser parser = null;
try {
res = new Resources(assets, mMetrics, null);
......
//zy this method is main to get ANDROID_MANIFEST_FILENAME out
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

final String[] outError = new String[1];
final Package pkg = parseBaseApk(res, parser, flags, outError);
......
return pkg;

} catch (PackageParserException e) {...... } catch (Exception e) {......
} finally {
IoUtils.closeQuietly(parser);
}
}

这个函数就是先进行一些基本的判断那,如路径合不合法等,并且解析出apk文件中的AndroidManifest.xml文件,然后调用另一

个 重载的parsePackage函数对这个文件进行进一步的解析。

private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,

String[] outError) throws XmlPullParserException, IOException {

......

final Package pkg = new Package(pkgName);//第一次出现这个类,用于封装包的各种信息

......

int outerDepth = parser.getDepth();

//没有到AndroidManifest.xml文件的结尾处,就一直循环。

while ((type = parser.next()) != XmlPullParser.END_DOCUMENT

&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {

......

String tagName = parser.getName();

if (tagName.equals("application")) {

......

} else if (tagName.equals("overlay")) {                                           ......		                           } else if (tagName.equals("key-sets")) {                                           ......		   } else if (tagName.equals("permission-group")) {                       if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) {                        return null;                        }		   }else if(tagName.equals("permission")) {                     if (parsePermission(pkg, res, parser, attrs, outError) == null) {
return null;                            }		  } else if (tagName.equals("permission-tree")) {	               if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {
return null;                            }	          } else if(tagName.equals("uses-permission")) {	              if (!parseUsesPermission(pkg, res, parser, attrs)) {
return null;                             }		  } else if (tagName.equals("uses-permission-sdk-m")                          || tagName.equals("uses-permission-sdk-23")) {
if (!parseUsesPermission(pkg, res, parser, attrs)) {
return null;
}
}                                        .......//解析各种标签,然调用本类的相应的方法,完成解析并保存在pkg的变量当中,最后把pkg返回。                                 }


return pkg;

}

这个函数用来完成对AndroidManifest.xml文件的各个标签进行解析,此处我们只关心和权限相关的uses-permission标签。

各个标签的含义:http://developer.android.com/guide/topics/manifest/manifest-intro.html

Step5 PackageParser.parseUsesPermission

private boolean parseUsesPermission(Package pkg,
Resources res, XmlResourceParser parser,

AttributeSet attrs) throws XmlPullParserException, IOException {

......

if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) {

if (name != null) {

int index = pkg.requestedPermissions.indexOf(name);

if (index == -1) {

pkg.requestedPermissions.add(name.intern());

} else {...... }

}

}

return true;

}
此函数就是把Uses-Permission标签下的每一个权限的名字添加到pkg.requestedPermissions的变量当中。
然后一层层返回到step3中

Step.6 PackageManagerService.scanPackageLI

private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,

int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {

boolean success = false;

try {

final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,

currentTime, user);

success = true;

return res;

} finally {...... }

}

继续调用scanPackageDirtyLI来完成解析。注意到现在为止pkg里面已经有了大量的信息。

private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,

int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {

......

//通过pkg创建一个PackageSetting对象,也是临时保存一个指定的package的数据和信息。

//如此出会找到这个package的uid、还会通过层层的父类的初始化new PermissionsState()类。

pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,

destResourceFile,
pkg.applicationInfo.nativeLibraryRootDir,

pkg.applicationInfo.primaryCpuAbi,

pkg.applicationInfo.secondaryCpuAbi,

pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,

user, false);

......

pkg.applicationInfo.uid = pkgSetting.appId; //赋值uid

pkg.mExtras = pkgSetting;

......

synchronized (mPackages) {

//把pkgSetting保存到Settings的变量mPackages中, String对应于包名。

//final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<String, PackageSetting>();

mSettings.insertPackageSettingLPw(pkgSetting, pkg);

//把pkg保存到PMS的成员变量mPackages 中,Stirng对应于包名。

//final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<String, PackageParser.Package>();

mPackages.put(pkg.applicationInfo.packageName, pkg);

......

int N = pkg.providers.size();

......//解析providers 把相应的provider添加到mProviders当中。

N = pkg.services.size();
......//解析services 把相应的services添加到mServices当中。

N = pkg.receivers.size();
......//解析receivers 把相应的receivers 添加到mReceivers 当中。

N = pkg.activities.size();
......//解析activities 把相应的activities 添加到mActivities 当中。

N = pkg.permissionGroups.size();

......//解析permissionGroups把相应的permissionGroups添加到mPermissionGroups当中。

N = pkg.permissions.size();

......//解析permissions把相应的permissions添加到permissionMap当中。

N = pkg.instrumentation.size();

......//解析instrumentation把相应的instrumentation添加到mInstrumentation当中。

......

}

return pkg;

}

此函数现在看来除啦进一步解析pkg外,还把pkg的一些属性添加到PMS的成员变量中。

Step7.PackageManagerService

至此完成了对系统中的相应的目录下的apk的解析,那么它们的权限怎么设定的那?完全没有踪影啊,别急。接下来继续回到

PMS的构造当中。

public PackageManagerService(Context context, Installer installer,

boolean
factoryTest, boolean onlyCore) {

//此处接着Step1的步骤分析。
......
int updateFlags = UPDATE_PERMISSIONS_ALL;
if (ver.sdkVersion != mSdkVersion) {
updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
}
updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);/

}

在构造中解析完系统的apk后调用updatePermissionsLPw来设定应用的权限。

Step 8.PackageManagerService. updatePermissionsLPw

private void updatePermissionsLPw(String changingPkg,

PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags) {

......

//下面的这个flags从PMS构造中传入,所以符合条件可以进入,并且replace为false。

if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {

//mPackages,在Step 6中已经完成保存

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

if (pkg != pkgInfo) {

final String volumeUuid = getVolumeUuidForPackage(pkg);

final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0)

&& Objects.equals(replaceVolumeUuid, volumeUuid);

grantPermissionsLPw(pkg, replace, changingPkg);

}

}

//从PMS构造中传过来的是null,此处一般手动安装的应用会走,并且replace 为true。

if (pkgInfo != null) {

final String volumeUuid = getVolumeUuidForPackage(pkgInfo);

final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0)

&& Objects.equals(replaceVolumeUuid, volumeUuid);

grantPermissionsLPw(pkgInfo, replace, changingPkg);

}

}

此函数更具传入的参数的不同调用方法中不同地方的grantPermissionsLPw,并把相应的参数传入.

Step 9.PackageManagerService. grantPermissionsLPw

private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace,

String packageOfInterest) {

//在Step 6 已经赋值 pkg.mExtras。

final PackageSetting ps = (PackageSetting) pkg.mExtras;

if (ps == null) {

return;

}
//此时的permissionsState不为null,因为在初始化PackageSetting 时,已经实例化它,但是它的成员变量很多
//都是null因为实例化它的时候用的是无参数的构造,如:public ArrayMap<String, PermissionData> mPermissions;
//key对应于权限名字,Values对应于一个用于封装的PermissionData类
PermissionsState permissionsState = ps.getPermissionsState();
PermissionsState origPermissions = permissionsState;
......
//已经在Step 5中完成了解析。
final int N = pkg.requestedPermissions.size();
for (int i=0; i<N; i++) {
final String name = pkg.requestedPermissions.get(i);
//在Step1中(还有别的地方)已经初始化此项
final BasePermission bp = mSettings.mPermissions.get(name);
......

final String perm = bp.name;
boolean allowedSig = false;
int grant = GRANT_DENIED;
......
//从何处导致的protectionLevel的不同,暂时还没分析出来!!!!??????
final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
switch (level) {
case PermissionInfo.PROTECTION_NORMAL: {
// 当不是PROTECTION_DANGEROUS类型的时候都安装为安装权限。
grant = GRANT_INSTALL;
} break;

case PermissionInfo.PROTECTION_DANGEROUS: {
if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
// 当targtversion小于6.0是赋值这个。
grant = GRANT_INSTALL_LEGACY;
} else if (origPermissions.hasInstallPermission(bp.name)) {
// For legacy apps that became modern, install becomes runtime.
grant = GRANT_UPGRADE;
} else if (mPromoteSystemApps&& isSystemApp(ps)
&& mExistingSystemPackages.contains(ps.name)) {
grant = GRANT_UPGRADE;
} else {
// 想是正常的6.0的第一次安装的时候,就会赋值此处。
grant = GRANT_RUNTIME;
}
} break;

case PermissionInfo.PROTECTION_SIGNATURE: {
// For all apps signature permissions are install time ones.
allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
if (allowedSig) {
grant = GRANT_INSTALL;
}
} break;
}
......
}
if(grant != GRANT_DENIED){
......
switch (grant) {
case GRANT_INSTALL: {

for (int userId : UserManagerService.getInstance().getUserIds()) {

if (origPermissions.getRuntimePermissionState( bp.name, userId) != null) {

origPermissions.revokeRuntimePermission(bp, userId);

origPermissions.updatePermissionFlags(bp, userId,
PackageManager.MASK_PERMISSION_FLAGS, 0);

changedRuntimePermissionUserIds = ArrayUtils.appendInt(

changedRuntimePermissionUserIds, userId);

}

}

// 允许所有的安装时的权限,通过grantInstallPermission。此处的逻辑在最后单独分析。

int flag = permissionsState.grantInstallPermission(bp);

android.util.Log.d("zy_test","GRANT_INSTALL flag = "+flag);

if (flag != PermissionsState.PERMISSION_OPERATION_FAILURE) {

changedInstallPermission = true;

}

} break;

case GRANT_INSTALL_LEGACY: {
//当应用的targetversion<23并且权限是运行时权限,才会走到这里。也是全部允许。
int flag = permissionsState.grantInstallPermission(bp);
if (flag !=PermissionsState.PERMISSION_OPERATION_FAILURE) {
changedInstallPermission = true;
}
} break;

case GRANT_RUNTIME: {
for (int userId : UserManagerService.getInstance().getUserIds()) {
PermissionState permissionState = origPermissions .getRuntimePermissionState(bp.name, userId);
final int flags = permissionState != null ? permissionState.getFlags() : 0;
//此时hasRuntimePermission会返回false,由于origPermissions.mPermissions==null
if (origPermissions.hasRuntimePermission(bp.name, userId)) {
//所以不会进入到这里进而允许所有的运行时权限。
if (permissionsState.grantRuntimePermission(bp, userId) ==
PermissionsState.PERMISSION_OPERATION_FAILURE) {
changedRuntimePermissionUserIds = ArrayUtils.appendInt(
changedRuntimePermissionUserIds, userId);
}
}
permissionsState.updatePermissionFlags(bp, userId, flags, flags);
}
} break;

case GRANT_UPGRADE: {......}
......

}else{
......
}
}
......

}

此函数真正的初始化了每个应用的framework层的权限设置,根据不同的权限类型和应用的targetversion。但是这样的话系统应用

很多必要的权限默认也是不允许的,这样体验很不好。

Step 10 PackageManagerService.systemReady()

systemServer调用完PMS的main方法后,会调用PMS的systemReady。

public void systemReady() {

......

for (int userId : grantPermissionsUserIds) {
//此处初始化所有用户的一些默认的权限。

mDefaultPermissionPolicy.grantDefaultPermissions(userId);

}
......

}

我们只分析和权限相关的,mDefaultPermissionPolicy 是DefaultPermissionGrantPolicy类的实例,在PMS创建的时候就完成了实

例化,通过调用grantDefaultPermissions来初始化一些应用的默认权限。

Step 11 DefaultPermissionGrantPolicy. grantDefaultPermissions

public void grantDefaultPermissions(int userId) {

grantPermissionsToSysComponentsAndPrivApps(userId);//对PMS.mPackages里面的符合一定条件pkg的权限的初始化。

grantDefaultSystemHandlerPermissions(userId);//对如:Mms、Dialer、Contact等应用的权限的初始化

}

此函数分别通过再次调用另外的方法,完成最终的某些应用的权限的初始化,此处就不再深入分析,有兴趣的可以自己在往下看,

也 很简单。最终是通过PMS的grantRuntimePermission(,,)来完成对应用的权限的设置。至此我们完成了系统的apk的解析和默

认权限的设置,当中忽略了很多细节有兴趣可以自己深入研究,此文只起到抛砖引玉作用。

3、解析下载好的apk(手动点击安装)

手动点击安装和系统的解析很多地方都会走相同的代码,只是一开始的入口方式不同,此处就不重复讨论相同的地方了。且下面的分析

省略了具体的PackageInstaller对点击安装apk往外发送的广播的处理,直接分析最终的在PMS的实现。





Step 1.PackageManagerService.installPackage

此处就直接从安装的接口调用处开始分析。

public void installPackage(String originPath, IPackageInstallObserver2 observer,

int installFlags, String installerPackageName, VerificationParams verificationParams,

String packageAbiOverride) {

installPackageAsUser(originPath, observer, installFlags, installerPackageName,

verificationParams, packageAbiOverride, UserHandle.getCallingUserId());

}
直接调用了另外的一个函数installPackageAsUser。
public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, VerificationParams verificationParams,
String packageAbiOverride, int userId) {

......

final Message msg = mHandler.obtainMessage(INIT_COPY);

msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,

null, verificationParams, user, packageAbiOverride, null);

mHandler.sendMessage(msg);

}

此函数主要就是做些基本的判断,如:是否有权限、是否可以默认允许安装时权限。最后往mHandler发送消息,进行处理。

Step 2.PackageManagerService.PackageHandler

PackageHandler.doHandleMessage(.)会被多次调用进行一些必要的处理,如:判断APK路径是否合法,把Apk复制过来,

检查签名和包名是否合法等等。最终在某个消息中会调用到,processPendingInstall。

Step 3.PackageManagerService.processPendingInstall

private void processPendingInstall(final InstallArgs args, final int currentStatus) {

......

mHandler.post(new Runnable() {

......

if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {

args.doPreInstall(res.returnCode);

synchronized (mInstallLock) {

installPackageLI(args, res);

}

args.doPostInstall(res.returnCode, res.uid);

}
......

});

}

此函数被异步调用,一直在等待安装的flag变为INSTALL_SUCCEEDED。最后调用installPackageLI开始真正的安装。

Step 4.PackageManagerService.installPackageLI

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {

......

PackageParser pp = new PackageParser();

......

final PackageParser.Package pkg;

try {

//此处的解析和前面所说的解析系统应用的刘晨个相同,注意一下某些参数和标志位的区别即可。

pkg = pp.parsePackage(tmpPackageFile, parseFlags);

} catch (PackageParserException e) {

return;

}

......
if (replace) {
replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
installerPackageName, volumeUuid, res);
} else {
//第一次安装apk时,会走到这里。
installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res);
}

}

此函数主要是通过parsePackage解析apk的manifest的一些属性。然后调用installNewPackageLI方法。

Step 5.PackageManagerService.installNewPackageLI

private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,

UserHandle user,
String installerPackageName, String volumeUuid,

PackageInstalledInfo res) {

......

PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,

System.currentTimeMillis(), user);

updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);

.......

}

此函数通过scanPackageLI进行进一步的解析,此处解析和解析系统应用的Step 6相同,此处不再重复分析。通过它完成

了对apk的解析,最终在调用updateSettingsLI来实现对此应用权限相关的默认设置。

Step 6.PackageManagerService.updateSettingsLI

private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,

String volumeUuid, int[] allUsers, boolean[] perUserInstalled, PackageInstalledInfo res,

UserHandle user)
{

......

updatePermissionsLPw(newPackage.packageName, newPackage, // zy updatePermissionsLPw??

UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0

? UPDATE_PERMISSIONS_ALL : 0));
...

}

函数调用updatePermissionsLPw来实现权限的默认设置,和解析系统应用的Step 8~9功能相同的。

至此就完成了普通的apk的安装解析和设置权限的流程,可以看出核心功能和解析系统的并无两样。综上可以看到对于M基线的

权限设置,核心是不区分系统应用和普通应用的,只在一些开始解析时传入的flag上有些区别。也就是说在安装解析完后,默认

的对于targetversion<23的应用,所有的基本和危险权限默认允许,对于targetversion=23的,所有的安装权限默认允许,危险权

限全部默认拒绝。至于系统的一些应用默认就允许一些权限,是解析完后转门对应用的权限进行了设置(Step11)。

4、权限PermissionsState的机制分析。

在解析系统应用的Step 9中我们,我们只是分析道调用grantInstallPermission,没有具体的跟踪再往下的逻辑。还有

hasRuntimePermission的实现等。

PermissionsState基本囊括了一个应用的所有权限的状态。

public final class PermissionsState {

......

public ArrayMap<String, PermissionData> mPermissions;//key :权限名字,value : PermissionData 对单个权限的封装

......

public PermissionsState() {

/* do nothing */ //空的构造,在前面解析系统应用的Step 6中 pkgSetting = mSettings.getPackageLPw(...)
//内部就调用啦这个构造函数,这就导致成员变量mPermissions==null.

}

public PermissionsState(PermissionsState prototype) {

copyFrom(prototype);//从另一个PermissionsState获取数据,此时一般mPermissions都不是null。
//此处就不详细分析这个方,就是简单的获取一下。

}
//查看是否有这个权限,此时的有不仅仅是权限列表有,还需要已经允许(包含运行时和安装时通过userId区分)

public boolean hasPermission(String name, int userId) {
//如果mPermissions==null,正好对应到系统解析的Step 9中,刚空构造初始化完毕,为允许任何权限的时候。
if (mPermissions == null) {
return false;
}

PermissionData permissionData = mPermissions.get(name);
//只有当PermissionData != null, 并且权限已经允许时才返回true。
return permissionData != null && permissionData.isGranted(userId);
}

private int grantPermission(BasePermission permission, int userId) {
//如果已经允许这个权限了,那么就没必要再允许一次了。
if (hasPermission(permission.name, userId)) {
return PERMISSION_OPERATION_FAILURE;
}
//此处不太懂可能是要和Linux中的gid是相对应。???
final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
//下面这个方法很关键,用来实例化PermissionData 的.
PermissionData permissionData = ensurePermissionData(permission);

//然后通过调用permissionData 的grant方法来完成权限的允许过程。
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;
}

private PermissionData ensurePermissionData(BasePermission permission) {
if (mPermissions == null) {
mPermissions = new ArrayMap<>();//当第一次到这mPermissions 为null时,初始化一个
}
//第一次获取某个权限时必定为null。
PermissionData permissionData = mPermissions.get(permission.name);
if (permissionData == null) {
permissionData = new PermissionData(permission);//实例化PermissionData。
mPermissions.put(permission.name, permissionData);//添加到mPermissions当中。
}
return permissionData;
}

private int revokePermission(BasePermission permission, int userId) {
//如果已经拒绝了就没必要操作了。
if (!hasPermission(permission.name, userId)) {
return PERMISSION_OPERATION_FAILURE;
}
......
PermissionData permissionData = mPermissions.get(permission.name);
//调用permissionData revoke方法来完成拒绝的操作
if (!permissionData.revoke(userId)) {
return PERMISSION_OPERATION_FAILURE;
}
......
return PERMISSION_OPERATION_SUCCESS;
}

......

private static final class PermissionData {

private final BasePermission mPerm; //一个权限对应一个BasePermission
//mUserStates ,由于一个权限对应一个PermissionData,所以此处其实mUserStates 的大小只为1,key = userid,
//Value = PermissionState.
private SparseArray<PermissionState> mUserStates = new SparseArray<>();

public PermissionData(BasePermission perm) {
mPerm = perm;
}

public PermissionData(PermissionData other) {
this(other.mPerm);
......//此处不做分析
}
......
//此处仅仅写出了重要的方法,且以允许权限为例。
public boolean grant(int userId) {

...... //前面进行一些判断,是否有必要进行接下来的允许工作
PermissionState userState = mUserStates.get(userId);//第一次获取的时候必然为null
if (userState == null) {
//此处new一个单个权限对应的PermissionState,以权限的名字为参数。

userState = new PermissionState(mPerm.name);
mUserStates.put(userId, userState);//然后放到成员变量mUserStates中。以userid为key。(反正只有一个)
}

userState.mGranted = true; //最后改变这个成员变量来标记是否允许。
return true;
}

public boolean revoke(int userId) {
...... //也是一些有没有必要继续执行的判断,应该是加快工作效率的吧

PermissionState userState = mUserStates.get(userId);
userState.mGranted = false;//直接把变量mGranted 至为false
if (userState.isDefault()) {//如果默认就是ifalse,那么移除这个
mUserStates.remove(userId);
}
return true;
}

......
}

//单一的某个权限,对它的封装,此处封装的是名字和,状态。

public static final class PermissionState {
private final String mName;
private boolean mGranted;
private int mFlags;

public PermissionState(String name) {
mName = name;
}

public PermissionState(PermissionState other) {

mName = other.mName;
mGranted = other.mGranted;
mFlags = other.mFlags;
}

public boolean isGranted() {
return mGranted;
}

}

}

至此我们分析完PermissionsState类的主要的一些方法和变量。然后对应到我们的解析系统应用的Step 9当中。

当权限是安装时权限的时候,调用的permissionsState.grantInstallPermission(bp)。最终会调用到grantPermis

sion的方法当中。此时首先判断hasPermission,由于mPermissions == null,返回的是false。接下来就调用ensure

PermissionData(..)和permission Data.grant(userId)完成最终的允许状态使,PermissionState.mGranted = =true.

当权限是运行时权限的时候,调用hasRuntimePermission(..)。最终也会调用到hasPermission。由于mPerm

issions == null。最终返回false。进而不会进入判断,也就不能调用grantRuntimePermission。

5、权限的检查、允许和禁止的机制。

权限的检查通过AMS里面的一些列封装,最后到PMS当中。

检查权限的方法主要有以下几种。

@Override

public int checkPermission(String permName, String pkgName, int userId) {
//判断用户id是否合法。

if (!sUserManager.exists(userId)) {

return PackageManager.PERMISSION_DENIED;

}

synchronized (mPackages) {

final PackageParser.Package p = mPackages.get(pkgName);

if (p != null && p.mExtras != null) {

final PackageSetting ps = (PackageSetting) p.mExtras;//取出ps

final PermissionsState permissionsState = ps.getPermissionsState();//取出permissionsState

if (permissionsState.hasPermission(permName, userId)) { //调用hasPermission,看看是否已经允许。

return PackageManager.PERMISSION_GRANTED;

}

//特殊的权限的处理

if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState

.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) {

return PackageManager.PERMISSION_GRANTED;

}

}

}

return PackageManager.PERMISSION_DENIED;//以上都不符合,那么默认就是不允许的

}

@Override
public int checkUidPermission(String permName, int uid) {
...... //userid、uid是否合法的判断
synchronized (mPackages) {
//此处取得的是SettingsBase也就是ps,此文没有具体分析到这一块。
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;
}
//特殊权限的处理
if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState
.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) {
return PackageManager.PERMISSION_GRANTED;
}
} else {
ArraySet<String> 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; //默认还是拒绝
}

权限允许的方法:

由于安装时权限是在安装的时候就已经允许的,所以此时的允许权限,其实就是允许运行时权限。在解析系统apk的Step 11

也有说明,调用PMS的grantRuntimePermission.

public void grantRuntimePermission(String packageName, String name, final int userId) {

..... //一些权限和userid合法性的检查。

final int uid;

final SettingBase sb;

synchronized (mPackages) {

final PackageParser.Package pkg = mPackages.get(packageName);

......

final BasePermission bp = mSettings.mPermissions.get(name);

......

uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);

sb = (SettingBase) pkg.mExtras;

......

final int result = permissionsState.grantRuntimePermission(bp, userId);

...... //此处做完权限允许操作后,会先更具返回的result经行一些处理。最终再把这些操作信息

//持久化到文件中在/data/system/users/X/runtime-permissions.xml当中。此处在说另外几个xml

//packages.xml 、package.list 都存放在data/system/下面,文件里存放了所有apk的包的信息,如:包名

}

}

grantRuntimePermission最终也会调用到permissionsState 的grantPermission方法中。基本流程和上述一样。

权限禁止的方法。

此处也是指禁止运行时的权限,因为安装时的权限是不可控制的。安装时就已经允许。

@Override

public void revokeRuntimePermission(String packageName, String name, int userId) {

.......//前面的这些操作和允许运行时权限调用的类似,不再做分析

if (permissionsState.revokeRuntimePermission(bp, userId) ==

PermissionsState.PERMISSION_OPERATION_FAILURE)
{

return;
}

......

}

最终就是调用PermissonState的revoke方法把mGranted变量置为false。

6、解析安装APK时和去学奶奶相关的一些重要的类的成员变量。

Settings类的成员变量:

final ArrayMap<String, BasePermission> mPermissions = new ArrayMap<String, BasePermission>():每个权限字符串对应一

个BasePermission类。

final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<String, PackageSetting>():每一个包名对应一个Packag

eSetting类。

PackageManagerService的成员变量:

final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<String, PackageParser.Package>():每一个包名

对应一个PackageParser.Package对象。(很关键)

private static final int GRANT_DENIED = 1;

private static final int GRANT_INSTALL = 2;

private static final int GRANT_INSTALL_LEGACY = 3;

private static final int GRANT_RUNTIME = 4;

private static final int GRANT_UPGRADE = 5;

./system/core/include/private/android_filesystem_config.h :uid字符串和linux中的uid的对应。

7、重启手机后走的流程(不是第一次恢复出厂设置的加载。)

a、关机重启后应用安装问题

如果彻底关机之后再开机,那么系统就会重新安装一遍所有的应用程序的,因为关机之后,我们是可以改变系统中的应用

程序的, 例如,增加、删除或者修改系统中的应用程序。如果不重新检查一遍的话,那么就会有问题了。在实际使用中,我们

很少会彻底地关机,一 般意义上的关机只是让系统深度睡眠,这种情况不会导致系统重新安装一遍系统中的应用程序。系统除

了会把应用程序的安装 信息保存在内存中之外,还会保存在一个本地文件中,因为有些应用程序的安装信息无论安装多少次,

都是必须保持一致的,例如, 应用程序的Linux用户ID。如果不保存下来的话,那么每次应用程序重新安装之后,表现可能都

会不一致。 /data/system/packages.xml里面 会在构造中调用Settings类的readLPw进行读取。其实就是会重新解析,但是有些

属性配置不会变,会重新重xml里面读取。也会在addPackageLPw中new PackageSetting

b、shared UID相关问题

假设程序A要与程序B共享一个UID,那么程序B不需要配置Shared UID,它会获得一个普通的UID,需要配置Shared UID

的是程序A,这时候系统会将程序B的UID分配给程序A,这样就达到了共享UID的目的。两个程序有相同的UID,并不意味着

它们会运行在同一个进程中。一个程序运行在哪一个进程,一般是由它的Package名称和UID来决定的,也就是说,UID相同

但是Package名称不同的两个程序是运行两个不同的进程中的。给每一个程序都分配一个UID是用来控制权限的,因此,两

个程序具有相同的UID,就意味它们有相同的权限,可以进行资源共享。关于进程的创建可以看连接:

http://blog.csdn.net/luoshengyang/article/details/6689748
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息