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 mPackages =
new ArrayMap();
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
//把pkg保存到PMS的成员变量
mPackages
中,Stirng对应于包名。
//
final ArrayMap mPackages =
new ArrayMap();
mPackages.put(pkg.applicationInfo.packageName, pkg);
......
int N = pkg.providers.size();
......//解析
providers 把相应的provider添加到mProviders当中。
N = pkg.services
.size();
......//解析services
把相应的
services
添加到mS
ervices
当中。
N = pkg.receivers
.size();
......//解析receivers
把相应的
receivers
添加到
mR
eceivers
当中。
N = pkg.activities
.size();
......//解析activities
把相应的
activities
添加到
mA
ctivities
当中。
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 mPermissions;
//key对应于权限名字,Values对应于一个用于封装的
PermissionData类
PermissionsState permissionsState = ps.getPermissionsState();
PermissionsState origPermissions = permissionsState;
......
//已经在Step 5中完成了解析。
final int N = pkg.requestedPermissions.size();
for (int i=0; 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.PackageManager
Service
.
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;
//此处的解析和前面所说的解析系统应用的刘晨个相同,注意一下某些参数和标志位的区别即可。
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
} catch (PackageParserException e) {
......
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 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 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 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 mPermissions =
new ArrayMap():每个权限字符串对应一
个BasePermission类。
final ArrayMap mPackages =
new ArrayMap():每一个包名对应一个
Packag
eSetting类。
PackageManagerService的成员变量:
final ArrayMap mPackages =
new ArrayMap():
每一个包名
对应一个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