Android的包管理机制浅析(二)

上篇刚好说到获取到了签名信息,以下进入安装过程,直接上源代码:

    private void installNewPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, UserHandle user,
String installerPackageName, PackageInstalledInfo res) {
// Remember this for later, in case we need to rollback this install
String pkgName = pkg.packageName; if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
...................
 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
System.currentTimeMillis(), user);
if (newPackage == null) {
Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
}
} else {
updateSettingsLI(newPackage, installerPackageName, ull, null, res);
// delete the partially installed application. the data directory will have to be
// restored if it was already existing
if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
// remove package from internal structures. Note that we want deletePackageX to
// delete the package data and cache directories that it created in
// scanPackageLocked, unless those directories existed before we even tried to
// install.
deletePackageLI(pkgName, UserHandle.ALL, false, null, null, dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
res.removedInfo, true);
}
}
}

主要逻辑是扫描当前的Package假设扫描成功然后更新Settings内容,更新失败要删除package信息。

scanPackageLI方法比較长。所以仅仅列出了当中我觉得比較重要的环节

private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, long currentTime, UserHandle user) {
//前面是一个APK完整性、是否反复的推断以及针对SystemApp的特殊设置
........................
// Initialize package source and resource directories
File destCodeFile = new File(pkg.applicationInfo.sourceDir);
File destResourceFile = new File(pkg.applicationInfo.publicSourceDir); SharedUserSetting suid = null;
PackageSetting pkgSetting = null; // writer
// 这里是一段针对SystemApp的改动安装操作
....................................
//假设有设置shareUID的必需要推断属于同一个id的是否採用了相同的签名。首先获取到这个签名信息。
if (pkg.mSharedUserId != null) {
                suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, true);
                if (suid == null) {
                    Slog.w(TAG, "Creating application package " + pkg.packageName
                            + " for shared user failed");
                    mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                    return null;
                }
            }
// Just create the setting, don't add it yet. For already existing packages
// the PkgSetting exists already and doesn't have to be created.
pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
destResourceFile, pkg.applicationInfo.nativeLibraryDir,
pkg.applicationInfo.cpuAbi,
pkg.applicationInfo.flags, user, false);
if (pkgSetting == null) {
Slog.w(TAG, "Creating application package " + pkg.packageName + " failed");
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
} pkg.applicationInfo.uid = pkgSetting.appId;
pkg.mExtras = pkgSetting;
//假设有security的xml文件。则进行seinfo的赋值,这个是基于linux安全机制的
//要了解具体内容能够參看:http://blog.csdn.net/innost/article/details/19299937
if (mFoundPolicyFile) {
                SELinuxMMAC.assignSeinfoValue(pkg);
            }  //这里是对当前应用的签名信息进行验证,包含系统特殊组的特殊签名
if (!verifySignaturesLP(pkgSetting, pkg)) {
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
return null;
}
// The signature has changed, but this package is in the system
// image... let's recover!
pkgSetting.signatures.mSignatures = pkg.mSignatures;
// However... if this package is part of a shared user, but it
// doesn't match the signature of the shared user, let's fail.
// What this means is that you can't change the signatures
// associated with an overall shared user, which doesn't seem all
// that unreasonable.
//这里完毕相同shareUid的签名推断
 if (pkgSetting.sharedUser != null) {
if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
Log.w(TAG, "Signature mismatch for shared user : " + pkgSetting.sharedUser);
mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
return null;
}
}
// File a report about this.
String msg = "System package " + pkg.packageName
+ " signature changed; retaining data.";
reportSettingsProblem(Log.WARN, msg);
} // Verify that this new package doesn't have any content providers
// that conflict with existing packages. Only do this if the
// package isn't already installed, since we don't want to break
// things that are installed.
if ((scanMode&SCAN_NEW_INSTALL) != 0) {
final int N = pkg.providers.size();
int i;
for (i=0; i<N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
if (p.info.authority != null) {
String names[] = p.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
if (mProvidersByAuthority.containsKey(names[j])) {
PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
Slog.w(TAG, "Can't install because provider name " + names[j] +
" (in package " + pkg.applicationInfo.packageName +
") is already used by "
+ ((other != null && other.getComponentName() != null)
? other.getComponentName().getPackageName() : "? "));
mLastScanError = PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
return null;
}
}
}
}
}
//这里是处理同组权限授权。即处于同一组能够设置从其它同组APK中获得指定的权限。这个是须要Manifest文件里配置adopt-permissions标签
if (pkg.mAdoptPermissions != null) {
// This package wants to adopt ownership of permissions from
// another package.
for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
final String origName = pkg.mAdoptPermissions.get(i);
final PackageSetting orig = mSettings.peekPackageLPr(origName);
if (orig != null) {
if (verifyPackageUpdateLPr(orig, pkg)) {
Slog.i(TAG, "Adopting permissions from " + origName + " to "
+ pkg.packageName);
mSettings.transferPermissionsLPw(origName, pkg.packageName);
}
}
}
}
} final String pkgName = pkg.packageName; final long scanFileTime = scanFile.lastModified();
final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0;
//进程名,假设配置了进程名就以配置为准。没有就是默认包名
pkg.applicationInfo.processName = fixProcessName(
pkg.applicationInfo.packageName,
pkg.applicationInfo.processName,
pkg.applicationInfo.uid);
//以下都是针对安装APK的data文件夹进行处理
File dataPath;
if (mPlatformPackage == pkg) {
// The system package is special.
dataPath = new File (Environment.getDataDirectory(), "system");
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
// This is a normal package, need to make its data directory.
dataPath = getDataPathForPackage(pkg.packageName, 0); boolean uidError = false;
//处理应用数据存储路径存在的情况
if (dataPath.exists()) {
int currentUid = 0;
try {
StructStat stat = Os.stat(dataPath.getPath());
currentUid = stat.st_uid;
} catch (ErrnoException e) {
Slog.e(TAG, "Couldn't stat path " + dataPath.getPath(), e);
} // If we have mismatched owners for the data path, we have a problem.
if (currentUid != pkg.applicationInfo.uid) {
boolean recovered = false;
//这里是处理相同的APK改动了UID的情况
if (currentUid == 0) {
// The directory somehow became owned by root. Wow.
// This is probably because the system was stopped while
// installd was in the middle of messing with its libs
// directory. Ask installd to fix that.
int ret = mInstaller.fixUid(pkgName, pkg.applicationInfo.uid,
pkg.applicationInfo.uid);
if (ret >= 0) {
recovered = true;
String msg = "Package " + pkg.packageName
+ " unexpectedly changed to uid 0; recovered to " +
+ pkg.applicationInfo.uid;
reportSettingsProblem(Log.WARN, msg);
}
}
//系统APK须要删除Data文件夹后又一次创建
if (!recovered && ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
|| (scanMode&SCAN_BOOTING) != 0)) {
// If this is a system app, we can at least delete its
// current data so the application will still work.
int ret = removeDataDirsLI(pkgName);
if (ret >= 0) {
// TODO: Kill the processes first
// Old data gone!
String prefix = (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
? "System package " : "Third party package ";
String msg = prefix + pkg.packageName
+ " has changed from uid: "
+ currentUid + " to "
+ pkg.applicationInfo.uid + "; old data erased";
reportSettingsProblem(Log.WARN, msg);
recovered = true; // And now re-install the app.
ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid,
pkg.applicationInfo.seinfo);
if (ret == -1) {
// Ack should not happen!
msg = prefix + pkg.packageName
+ " could not have data directory re-created after delete.";
reportSettingsProblem(Log.WARN, msg);
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
}
}
if (!recovered) {
mHasSystemUidErrors = true;
}
} else if (!recovered) {
// If we allow this install to proceed, we will be broken.
// Abort, abort!
mLastScanError = PackageManager.INSTALL_FAILED_UID_CHANGED;
return null;
} if (!recovered) {
pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
+ pkg.applicationInfo.uid + "/fs_"
+ currentUid;
pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir;
String msg = "Package " + pkg.packageName
+ " has mismatched uid: "
+ currentUid + " on disk, "
+ pkg.applicationInfo.uid + " in settings";
// writer
synchronized (mPackages) {
mSettings.mReadMessages.append(msg);
mSettings.mReadMessages.append('\n');
uidError = true;
if (!pkgSetting.uidError) {
reportSettingsProblem(Log.ERROR, msg);
}
}
}
}
pkg.applicationInfo.dataDir = dataPath.getPath();
//假设须要恢复seinfo运行恢复操作
if (mShouldRestoreconData) {
Slog.i(TAG, "SELinux relabeling of " + pkg.packageName + " issued.");
mInstaller.restoreconData(pkg.packageName, pkg.applicationInfo.seinfo,
pkg.applicationInfo.uid);
}
} else {
//假设应用数据存储路径不存在则直接创建
if (DEBUG_PACKAGE_SCANNING) {
if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
Log.v(TAG, "Want this data dir: " + dataPath);
}
//invoke installer to do the actual installation
int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid,
pkg.applicationInfo.seinfo);
if (ret < 0) {
// Error from installer
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
} if (dataPath.exists()) {
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
Slog.w(TAG, "Unable to create data directory: " + dataPath);
pkg.applicationInfo.dataDir = null;
}
} /*
* Set the data dir to the default "/data/data/<package name>/lib"
* if we got here without anyone telling us different (e.g., apps
* stored on SD card have their native libraries stored in the ASEC
* container with the APK).
*
* This happens during an upgrade from a package settings file that
* doesn't have a native library path attribute at all.
*/
if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) {
if (pkgSetting.nativeLibraryPathString == null) {
setInternalAppNativeLibraryPath(pkg, pkgSetting);
} else {
pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString;
}
}
pkgSetting.uidError = uidError;
} String path = scanFile.getPath();
/* Note: We don't want to unpack the native binaries for
* system applications, unless they have been updated
* (the binaries are already under /system/lib).
* Also, don't unpack libs for apps on the external card
* since they should have their libraries in the ASEC
* container already.
*
* In other words, we're going to unpack the binaries
* only for non-system apps and system app upgrades.
*/
if (pkg.applicationInfo.nativeLibraryDir != null) {
//这里面的操作针对APK的本地Lib文件的处理,包含复制文件以及对CPU ABI支持进行推断
}
pkg.mScanPath = path; if ((scanMode&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
// We don't do this here during boot because we can do it all
// at once after scanning all existing packages.
//
// We also do this *before* we perform dexopt on this package, so that
// we can avoid redundant dexopts, and also to make sure we've got the
// code and package path correct.
if (!adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
pkg, forceDex, (scanMode & SCAN_DEFER_DEX) != 0)) {
mLastScanError = PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE;
return null;
}
}
//进行odex的优化
if ((scanMode&SCAN_NO_DEX) == 0) {
if (performDexOptLI(pkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false)
== DEX_OPT_FAILED) {
mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
return null;
}
} if (mFactoryTest && pkg.requestedPermissions.contains(
android.Manifest.permission.FACTORY_TEST)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
} ArrayList<PackageParser.Package> clientLibPkgs = null; // writer
synchronized (mPackages) {
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
// Only system apps can add new shared libraries.
if (pkg.libraryNames != null) {
for (int i=0; i<pkg.libraryNames.size(); i++) {
String name = pkg.libraryNames.get(i);
boolean allowed = false;
if (isUpdatedSystemApp(pkg)) {
// New library entries can only be added through the
// system image. This is important to get rid of a lot
// of nasty edge cases: for example if we allowed a non-
// system update of the app to add a library, then uninstalling
// the update would make the library go away, and assumptions
// we made such as through app install filtering would now
// have allowed apps on the device which aren't compatible
// with it. Better to just have the restriction here, be
// conservative, and create many fewer cases that can negatively
// impact the user experience.
final PackageSetting sysPs = mSettings
.getDisabledSystemPkgLPr(pkg.packageName);
if (sysPs.pkg != null && sysPs.pkg.libraryNames != null) {
for (int j=0; j<sysPs.pkg.libraryNames.size(); j++) {
if (name.equals(sysPs.pkg.libraryNames.get(j))) {
allowed = true;
allowed = true;
break;
}
}
}
} else {
allowed = true;
}
if (allowed) {
if (!mSharedLibraries.containsKey(name)) {
mSharedLibraries.put(name, new SharedLibraryEntry(null, pkg.packageName));
} else if (!name.equals(pkg.packageName)) {
Slog.w(TAG, "Package " + pkg.packageName + " library "
+ name + " already exists; skipping");
}
} else {
Slog.w(TAG, "Package " + pkg.packageName + " declares lib "
+ name + " that is not declared on system image; skipping");
}
}
if ((scanMode&SCAN_BOOTING) == 0) {
// If we are not booting, we need to update any applications
// that are clients of our shared library. If we are booting,
// this will all be done once the scan is complete.
clientLibPkgs = updateAllSharedLibrariesLPw(pkg);
}
}
}
} // We also need to dexopt any apps that are dependent on this library. Note that
// if these fail, we should abort the install since installing the library will
// result in some apps being broken.
if (clientLibPkgs != null) {
if ((scanMode&SCAN_NO_DEX) == 0) {
for (int i=0; i<clientLibPkgs.size(); i++) {
PackageParser.Package clientPkg = clientLibPkgs.get(i);
if (performDexOptLI(clientPkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false)
== DEX_OPT_FAILED) {
mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
return null;
}
}
}
} // Request the ActivityManager to kill the process(only for existing packages)
// so that we do not end up in a confused state while the user is still using the older
// version of the application while the new one gets installed.
if ((parseFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
// If the package lives in an asec, tell everyone that the container is going
// away so they can clean up any references to its resources (which would prevent
// vold from being able to unmount the asec)
if (isForwardLocked(pkg) || isExternal(pkg)) {
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + pkg + " is ASEC-hosted -> UNAVAILABLE");
}
final int[] uidArray = new int[] { pkg.applicationInfo.uid };
final ArrayList<String> pkgList = new ArrayList<String>(1);
pkgList.add(pkg.applicationInfo.packageName);
sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
} // Post the request that it be killed now that the going-away broadcast is en route
killApplication(pkg.applicationInfo.packageName,
pkg.applicationInfo.uid, "update pkg");
} // Also need to kill any apps that are dependent on the library.
if (clientLibPkgs != null) {
for (int i=0; i<clientLibPkgs.size(); i++) {
PackageParser.Package clientPkg = clientLibPkgs.get(i);
killApplication(clientPkg.applicationInfo.packageName,
clientPkg.applicationInfo.uid, "update lib");
}
} // writer
synchronized (mPackages) {
// We don't expect installation to fail beyond this point,
if ((scanMode&SCAN_MONITOR) != 0) {
mAppDirs.put(pkg.mPath, pkg);
}
// Add the new setting to mSettings
// Add the new setting to mPackages
// Make sure we don't accidentally delete its data.
// Take care of first install / last update times.
// Add the package's KeySets to the global KeySetManager
// 后面的就是将当前安装APK的provider,receiver,activity。权限等等一些信息保存到PackageManagerService的类成员变量中。以后其它逻辑能够直接获取
// 比方启动Activity时直接从mActivities中查询,这是一个ActivityIntentResolver它里面有一个ComponentName跟PackageParser.Activity的键值对。 其它的也相似
// 这就相当于将当前APK的信息注冊到了系统中
} return pkg;
}

总结一下这个过程,就是先检查APK的合法性,包含文件合法性和签名验证。然后是对data的数据文件夹做相应的处理。对lib文件夹进行处理;下来是进行odex的优化;再接下来是重新启动进程和通知资源改变。最后就是将安装的APK的全部基本信息保存到服务的各类全局变量中,以便在系统执行时进行获取和处理。

解析成功之后。还须要更新一下Settings这个东东,这里面干了不好有效的事情呢。注意一下这里有两个安装的状态:PKG_INSTALL_INCOMPLETE和PKG_INSTALL_COMPLETE两种。没有把dex文件移动成功还是会失败的哟。

以下把grantPermissionsLPw单独拿出来看看。

    private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
int[] allUsers, boolean[] perUserInstalled,
PackageInstalledInfo res) {
String pkgName = newPackage.packageName;
synchronized (mPackages) {
//write settings. the installStatus will be incomplete at this stage.
//note that the new package setting would have already been
//added to mPackages. It hasn't been persisted yet.
mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_INCOMPLETE);
mSettings.writeLPr();
} if ((res.returnCode = moveDexFilesLI(newPackage))
!= PackageManager.INSTALL_SUCCEEDED) {
// Discontinue if moving dex files failed.
return;
} if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.mPath); synchronized (mPackages) {
updatePermissionsLPw(newPackage.packageName, newPackage,
UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
? UPDATE_PERMISSIONS_ALL : 0));
// For system-bundled packages, we assume that installing an upgraded version
// of the package implies that the user actually wants to run that new code,
// so we enable the package.
if (isSystemApp(newPackage)) {
// NB: implicit assumption that system package upgrades apply to all users
if (DEBUG_INSTALL) {
Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
}
PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
if (res.origUsers != null) {
for (int userHandle : res.origUsers) {
ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
userHandle, installerPackageName);
}
}
// Also convey the prior install/uninstall state
if (allUsers != null && perUserInstalled != null) {
for (int i = 0; i < allUsers.length; i++) {
if (DEBUG_INSTALL) {
Slog.d(TAG, " user " + allUsers[i]
+ " => " + perUserInstalled[i]);
}
ps.setInstalled(perUserInstalled[i], allUsers[i]);
}
// these install state changes will be persisted in the
// upcoming call to mSettings.writeLPr().
}
}
}
res.name = pkgName;
res.uid = newPackage.applicationInfo.uid;
res.pkg = newPackage;
mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
mSettings.setInstallerPackageName(pkgName, installerPackageName);
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
//to update install status
mSettings.writeLPr();
}
}
    private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace) {
final PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null) {
return;
}
final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
HashSet<String> origPermissions = gp.grantedPermissions;
boolean changedPermission = false; //假设是替换的话,先要保存原始的权限,然后清空。
if (replace) {
 ps.permissionsFixed = false;
if (gp == ps) {
origPermissions = new HashSet<String>(gp.grantedPermissions);
gp.grantedPermissions.clear();
gp.gids = mGlobalGids;
}
} if (gp.gids == null) {
gp.gids = mGlobalGids;
}
//这里是列出了全部当前应用请求授予的权限
final int N = pkg.requestedPermissions.size();
for (int i=0; i<N; i++) {
final String name = pkg.requestedPermissions.get(i);
final boolean required = pkg.requestedPermissionsRequired.get(i);
final BasePermission bp = mSettings.mPermissions.get(name);
if (DEBUG_INSTALL) {
if (gp != ps) {
Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
}
}
// 系统没有不论什么人声明过的权限未知的是无论的
if (bp == null || bp.packageSetting == null) {
Slog.w(TAG, "Unknown permission " + name
+ " in package " + pkg.packageName);
continue;
} final String perm = bp.name;
boolean allowed;
boolean allowedSig = false;
final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
if (level == PermissionInfo.PROTECTION_NORMAL
|| level == PermissionInfo.PROTECTION_DANGEROUS) {
// 以下这段是权限授予的准则。请注意这段凝视含义
 // We grant a normal or dangerous permission if any of the following
// are true:
// 1) The permission is required
// 2) The permission is optional, but was granted in the past
// 3) The permission is optional, but was requested by an
// app in /system (not /data)
//
// Otherwise, reject the permission.
allowed = (required || origPermissions.contains(perm)
|| (isSystemApp(ps) && !isUpdatedSystemApp(ps)));
} else if (bp.packageSetting == null) {
// This permission is invalid; skip it.
allowed = false;
} else if (level == PermissionInfo.PROTECTION_SIGNATURE) {
allowed = grantSignaturePermission(perm, pkg, bp, origPermissions);
if (allowed) {
allowedSig = true;
}
} else {
allowed = false;
}
if (DEBUG_INSTALL) {
if (gp != ps) {
Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
}
}
if (allowed) {
// 最终在以下修成正果了,得到了自己想要的权利
 if (!isSystemApp(ps) && ps.permissionsFixed) {
// If this is an existing, non-system package, then
// we can't add any new permissions to it.
if (!allowedSig && !gp.grantedPermissions.contains(perm)) {
// Except... if this is a permission that was added
// to the platform (note: need to only do this when
// updating the platform).
// 这个仅仅针对非PROTECTION_SIGNATURE级别的权限
  allowed = isNewPlatformPermissionForPackage(perm, pkg);
}
}
if (allowed) {
if (!gp.grantedPermissions.contains(perm)) {
changedPermission = true;
gp.grantedPermissions.add(perm);
gp.gids = appendInts(gp.gids, bp.gids);
} else if (!ps.haveGids) {
gp.gids = appendInts(gp.gids, bp.gids);
}
} else {
Slog.w(TAG, "Not granting permission " + perm
+ " to package " + pkg.packageName
+ " because it was previously installed without");
}
} else {
if (gp.grantedPermissions.remove(perm)) {
changedPermission = true;
gp.gids = removeInts(gp.gids, bp.gids);
Slog.i(TAG, "Un-granting permission " + perm
+ " from package " + pkg.packageName
+ " (protectionLevel=" + bp.protectionLevel
+ " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ ")");
} else {
Slog.w(TAG, "Not granting permission " + perm
+ " to package " + pkg.packageName
+ " (protectionLevel=" + bp.protectionLevel
+ " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ ")");
}
}
} if ((changedPermission || replace) && !ps.permissionsFixed &&
!isSystemApp(ps) || isUpdatedSystemApp(ps)){
// This is the first that we have heard about this package, so the
// permissions we have now selected are fixed until explicitly
// changed.
ps.permissionsFixed = true;
}
ps.haveGids = true;
}

更新Settings中各个APK的信息和状态,这些会同步写到  "data/system/packages.xml"、"packages-backup.xml")、 "packages.list")、"packages-stopped.xml")和 "packages-stopped-backup.xml"几个系统配置文件里。当中比較重要的grantPermissionsLPw()拿出来看看,这里是进行APK权限的授予,包含普通权限的直接授予,特殊权限的组(签名)认证以及同组权限的共享。

Android在linux UID之上的权限管理及安全的核心就在这里,主要是签名、用户组和权限级别控制,那么它们之间有哪些关系了。这一部分我们单独拿出来说一下:从ShareUserSettings和GrantedPermissions类的构成就能够看出一二了。用户组在Android上的本质上就是一系列被授予权限集合的概念(当然了。它包括的UID是linux的用户管理机制),能够用非常多的Package採用同样的用户组,而且它们必须具有同样的数字签名。

final class SharedUserSetting extends GrantedPermissions {
    final String name;     int userId;     // flags that are associated with this uid, regardless of any package flags
    int uidFlags;     final HashSet<PackageSetting> packages = new HashSet<PackageSetting>();     final PackageSignatures signatures = new PackageSignatures();     SharedUserSetting(String _name, int _pkgFlags) {
        super(_pkgFlags);
        uidFlags =  _pkgFlags;
        name = _name;
    }     @Override
    public String toString() {
        return "SharedUserSetting{" + Integer.toHexString(System.identityHashCode(this)) + " "
                + name + "/" + userId + "}";
    }     void removePackage(PackageSetting packageSetting) {
        if (packages.remove(packageSetting)) {
            // recalculate the pkgFlags for this shared user if needed
            if ((this.pkgFlags & packageSetting.pkgFlags) != 0) {
                int aggregatedFlags = uidFlags;
                for (PackageSetting ps : packages) {
                    aggregatedFlags |= ps.pkgFlags;
                }
                setFlags(aggregatedFlags);
            }
        }
    }     void addPackage(PackageSetting packageSetting) {
        if (packages.add(packageSetting)) {
            setFlags(this.pkgFlags | packageSetting.pkgFlags);
        }
    }
}
class GrantedPermissions {
int pkgFlags; HashSet<String> grantedPermissions = new HashSet<String>(); int[] gids; GrantedPermissions(int pkgFlags) {
setFlags(pkgFlags);
} @SuppressWarnings("unchecked")
GrantedPermissions(GrantedPermissions base) {
pkgFlags = base.pkgFlags;
grantedPermissions = (HashSet<String>) base.grantedPermissions.clone(); if (base.gids != null) {
gids = base.gids.clone();
}
} void setFlags(int pkgFlags) {
this.pkgFlags = pkgFlags
& (ApplicationInfo.FLAG_SYSTEM
| ApplicationInfo.FLAG_PRIVILEGED
| ApplicationInfo.FLAG_FORWARD_LOCK
| ApplicationInfo.FLAG_EXTERNAL_STORAGE);
}
}

另外网上还有两个经典的观点这里也摘过来,这都是上面分析能够得出的:

1、 两个程序有同样的UID,并不意味着它们会执行在同一个进程中。

一个程序执行在哪一个进程,通常是由它的Package名称和UID来决定的,也就是说。UID同样可是Package名称不同的两个程序是执行两个不同的进程中的(同样的UID和签名并包名同样会覆盖安装)。这一点你能够看一下这篇文章:http://blog.csdn.net/luoshengyang/article/details/6689748

2、 给每个程序都分配一个UID是用来控制权限的,因此,两个程序具有同样的UID,就意味它们有同样的权限,能够进行资源共享。同样UID的资源共享仅仅是针对linux文件系统的訪问权控制,不同进程间的数据是无法共享訪问的(须要指出linux把全部的都抽象成文件。訪问设备也是訪问文件,所以常常看到訪问系统某些设备的权限)。

前面还有个细节问题在看的过程中忽略了。应用权限声明和授予权限是怎样生效的呢?事实上对服务来说,权限仅仅是一个字符串而已,一种是Framework定义好了的(事实上也是系统应用或者服务要检查用到了才定义),比方读写外部存储的权限等等,另一种是应用申明的(申明时还能够带上权限的级别)。全部这些权限都会保存在settings中,然后呢。权限都有一个级别的概念,对于普通和下面级别权限仅仅要应用在manifest文件里写上而且在settings中有就能够授予。危急级别的就须要系统APK和签名咯才会授予。至于详细起作用事实上是在应用请求时会去比对当前请求是否须要权限而且你这个应用是否被授予了这样的权限。

非常多地方都有类似于checkPermission的方法,终于都会调用到ActivityManager中的checkComponentPermission()这种方法。

    /** @hide */
public static int checkComponentPermission(String permission, int uid,
int owningUid, boolean exported) {
// Root, system server get to do everything.
if (uid == 0 || uid == Process.SYSTEM_UID) {
return PackageManager.PERMISSION_GRANTED;
}
// Isolated processes don't get any permissions.
if (UserHandle.isIsolated(uid)) {
return PackageManager.PERMISSION_DENIED;
}
// If there is a uid that owns whatever is being accessed, it has
// blanket access to it regardless of the permissions it requires.
if (owningUid >= 0 && UserHandle.isSameApp(uid, owningUid)) {
return PackageManager.PERMISSION_GRANTED;
}
// If the target is not exported, then nobody else can get to it.
if (!exported) {
return PackageManager.PERMISSION_DENIED;
}
if (permission == null) {
return PackageManager.PERMISSION_GRANTED;
}
try {
return AppGlobals.getPackageManager()
.checkUidPermission(permission, uid);
} catch (RemoteException e) {
// Should never happen, but if it does... deny!
Slog.e(TAG, "PackageManager is dead? !? ", e);
}
return PackageManager.PERMISSION_DENIED;
}

终于还是调用到了PackageManagerService中的checkUidPermission方法:

    @Override
public int checkUidPermission(String permName, int uid) {
synchronized (mPackages) {
Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
if (obj != null) {
GrantedPermissions gp = (GrantedPermissions)obj;
if (gp.grantedPermissions.contains(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
} else {
HashSet<String> perms = mSystemPermissions.get(uid);
if (perms != null && perms.contains(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
}
}
return PackageManager.PERMISSION_DENIED;
}

看到了吧,终于还是看gp.grantedPermissions中有没有这个字符串的问题。这跟前面授予权限就相应上了吧。

这两篇说的东西都非常杂,看完对包管理服务框架还是没有什么总体的认识,接下来我就要在下篇開始站高度啦。開始讲讲总体架构。

上一篇:spring log4j.properties


下一篇:ubuntu12.04软件中心打开错误和 ubuntu 包管理之“:E: 读错误 - read (5: 输入/输出错误) E: 无法解析或打开软件包的列表或是状态文件。”的解决