PackageManagerService分析

2017-01-14 15:50:17来源:http://www.jianshu.com/p/0b0d6f684580作者:紫苓人点击

1.PackageManagerService的初始化在SystemServer中进行
// Start the package manager.
traceBeginAndSlog("StartPackageManagerService");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

2.PackageManagerService.main(Context c, Installer i,boolean factoryTest, boolean onlyCore)
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;
}

3.PackageManagerService构造函数超级长,这里一个点一个点粗略来过一下
3.1首先是Setting的相关信息处理
// 存储系统运行过程中的一些设置信息
mSettings = new Settings(mPackages);
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

3.2 Setting构造函数:主要是一些文件初始化工作
Settings(Object lock) {
// Environment.getDataDirectory() : /data
this(Environment.getDataDirectory(), lock);
}
Settings(File dataDir, Object lock) {
mLock = lock;
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
mSystemDir = new File(dataDir, "system");// /data/system
mSystemDir.mkdirs();
FileUtils.setPermissions(mSystemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
// /data/system/packages.xml
mSettingsFilename = new File(mSystemDir, "packages.xml");
// /data/system/packages-backup.xml
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
// /data/system/packages.list
mPackageListFilename = new File(mSystemDir, "packages.list");
FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
// Deprecated: Needed for migration
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}

3.3 Settings.addSharedUserLPw()
/**
* name = "android.uid.system",
* uid = Process.SYSTEM_UID(1000),
* pkgFlags = ApplicationInfo.FLAG_SYSTEM ,表示该应用安装在系统进程中,属于系统应用
* pkgPrivateFlags = ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
*/
SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
// mSharedUsers:ArrayMap<String, SharedUserSetting> 是一个Map,key值为uid字符窜描述,value为SharedUserSetting
SharedUserSetting s = mSharedUsers.get(name);
if (s != null) {// 从Map中直接取出来
if (s.userId == uid) {
return s;
}
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared user, keeping first: " + name);
return null;
}
// Map中没有,生成一个
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
s.userId = uid;
if (addUserIdLPw(uid, s, name)) {
mSharedUsers.put(name, s);
return s;
}
return null;
}

private boolean addUserIdLPw(int uid, Object obj, Object name) {
if (uid > Process.LAST_APPLICATION_UID) {// uid > 19999
return false;
}
if (uid >= Process.FIRST_APPLICATION_UID) {// uid >= 10000 && uid <= 19999-->普通APK所在的进程UID
int N = mUserIds.size();
final int index = uid - Process.FIRST_APPLICATION_UID;
while (index >= N) {
mUserIds.add(null);
N++;
}
if (mUserIds.get(index) != null) {
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate user id: " + uid
+ " name=" + name);
return false;
}
mUserIds.set(index, obj);
} else { // uid < 10000 && uid > 0-->系统APK所在的进程UID
if (mOtherUserIds.get(uid) != null) {
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared id: " + uid
+ " name=" + name);
return false;
}
mOtherUserIds.put(uid, obj);
}
return true;
}

相关类图:



QQ截图20160805164615.png

上面这些到底在设置些啥信息呢?这个要从AndroidManifest.xml的<manifest>标签的android:sharedUserId配置说起,如果多个APK设置的android:sharedUserId都是一样的话,那这些APK则具有相同的权限,可共享彼此的数据,并且可运行在同一个进程当中(<application>标签配置android:process为一样即可);
SharedUserSetting这个类是用来保存共享数据的,其中的name属性保存的就是sharedUserId指定的字符窜也就是共享用户名,userId属性存储的是共享用户UID,packages保存的就是sharedUserId配置为一样的所有的APK信息。PackageSetting对应的是其中某个APK相关信息。
Android系统中的UID,是用户ID的缩写,一般而言,每个进程都会有一个UID,表示该进程属于哪个用户,不同的用户具有不同的权限,一个进程也可以分属不同的用户组,表示每个用户组具有相应的权限。
这个怎么理解,拿Android来说,它分为系统进程和应用进程,系统进程对应一个UID,某个应用进程对应另外一个UID,系统进程具有它自己的权限,应用进程对应的也有它自己相应的权限;对于系统进程或是某个应用进程来说,它属于本进程的用户组,它也可以属于其他进程中的某个用户组(sharedUserId),比如framework-res.apk和SettingsProvider,它们都运行在"system"进程当中,它们的android:sharedUserId都是"android.uid.system",这就意味着它们不但具有获取它们各自本身的数据的权限,还具有获取彼此共享数据的权限。假如还有某个APK设置的process也为system,但是没有设置android:sharedUserId,那么它具有的权限就是只能访问它自己的数据了。
以上,就是Settings简要分析,总结来说,就是对几个特殊的将来可能用来保存共享数据的进程进行初始化工作,比如该进程具有什么权限,支持什么功能等等。


3.2系统权限配置信息读取和package.xml文件扫描解析
//......
// SystemConfig这个类扫描/etc/sysconfig和/etc/permissions/目录,
//解析XML文件获取到系统所有权限配置信息。
ArrayMap<String, SystemConfig.PermissionEntry> permConfig
= systemConfig.getPermissions();
//扫描解析/data/system/package.xml文件,这个文件保存的是安装包对应的相关信息:包名、权限、签名等
//当有程序安装、卸载、更新等操作时,这个文件会发生变更
mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
mSdkVersion, mOnlyCore);

3.3 相关jar和apk dex优化处理(/system/framework/目录下相关的jar和apk)
// Set flag to monitor and not change apk file paths when
// scanning install directories.
final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING | SCAN_INITIAL;
final ArraySet<String> alreadyDexOpted = new ArraySet<String>();
/**
* Add everything in the in the boot class path to the
* list of process files because dexopt will have been run
* if necessary during zygote startup.
*/
final String bootClassPath = System.getenv("BOOTCLASSPATH");
final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
if (bootClassPath != null) {
String[] bootClassPathElements = splitString(bootClassPath, ':');
for (String element : bootClassPathElements) {
alreadyDexOpted.add(element);
}
} else {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
if (systemServerClassPath != null) {
String[] systemServerClassPathElements = splitString(systemServerClassPath, ':');
for (String element : systemServerClassPathElements) {
alreadyDexOpted.add(element);
}
} else {
Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
}
final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();
final String[] dexCodeInstructionSets =
getDexCodeInstructionSets(
allInstructionSets.toArray(new String[allInstructionSets.size()]));
/**
* Ensure all external libraries have had dexopt run on them.
* 确保所有的依赖库都进行dex优化
*/
if (mSharedLibraries.size() > 0) {
// NOTE: For now, we're compiling these system "shared libraries"
// (and framework jars) into all available architectures. It's possible
// to compile them only when we come across an app that uses them (there's
// already logic for that in scanPackageLI) but that adds some complexity.
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {
final String lib = libEntry.path;
if (lib == null) {
continue;
}
try {
int dexoptNeeded = DexFile.getDexOptNeeded(lib, dexCodeInstructionSet,
"speed", false);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
alreadyDexOpted.add(lib);
mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
} catch (IOException e) {
Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
+ e.getMessage());
}
}
}
}
// /system/framework/
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
// Gross hack for now: we know this file doesn't contain any
// code, so don't dexopt it to avoid the resulting log spew.
// 该APK不含任何代码,所以不需要进行dex优化,以减少启动时间
alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");
// Gross hack for now: we know this file is only part of
// the boot class path for art, so don't dexopt it to
// avoid the resulting log spew.
alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");
/**
* There are a number of commands implemented in Java, which
* we currently need to do the dexopt on so that they can be
* run from a non-root shell.
*/
String[] frameworkFiles = frameworkDir.list();// 获取/system/framework/所有子目录
if (frameworkFiles != null) {
// TODO: We could compile these only for the most preferred ABI. We should
// first double check that the dex files for these commands are not referenced
// by other system apps.
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (int i=0; i<frameworkFiles.length; i++) {
File libPath = new File(frameworkDir, frameworkFiles[i]);
String path = libPath.getPath();
// Skip the file if we already did it.
if (alreadyDexOpted.contains(path)) {
continue;
}
// Skip the file if it is not a type we want to dexopt.
// 只对APK文件和JAR文件进行dex优化处理
if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
continue;
}
try {
int dexoptNeeded = DexFile.getDexOptNeeded(path, dexCodeInstructionSet,
"speed", false);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
// 对相关jar和apk文件进行dex优化
mInstaller.dexopt(path, Process.SYSTEM_UID, dexCodeInstructionSet,
dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
} catch (IOException e) {
Slog.w(TAG, "Exception reading jar: " + path, e);
}
}
}
}
final VersionInfo ver = mSettings.getInternalVersion();
mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
// when upgrading from pre-M, promote system app permissions from install to runtime
// 当版本升级到22的时候,权限从原来的安装的时候就设置好变成在运行给出提示让用户选择是否允许相关操作
mPromoteSystemApps =
mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;
// save off the names of pre-existing system packages prior to scanning; we don't
// want to automatically grant runtime permissions for new system apps
if (mPromoteSystemApps) {
Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
while (pkgSettingIter.hasNext()) {
PackageSetting ps = pkgSettingIter.next();
if (isSystemApp(ps)) {
mExistingSystemPackages.add(ps.name);
}
}
}

3.4扫描指定目录下的APK文件,然后解析APK文件
//......
// Find base frameworks (resource packages without code).
// /system/framework/
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);
// Collect ordinary system packages.
// /system/app/ 系统应用APK放置路径
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// 扫描解析/data/app/目录下的APK,我们安装的APK放在这个目录下面
scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
//......

/**
*扫描指定目录下面的文件,获取APK文件或是子目录,
*然后通过scanPackageLI对APK文件或是子目录进行处理
*/
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = dir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + dir);
return;
}
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
+ " flags=0x" + Integer.toHexString(parseFlags));
}
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {// APK文件或是目录才会处理
// Ignore entries which are not packages
continue;
}
try {
scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
scanFlags, currentTime, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
// Delete invalid userdata apps
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
if (file.isDirectory()) {
mInstaller.rmPackageDir(file.getAbsolutePath());
} else {
file.delete();
}
}
}
}
}

private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
}
final PackageParser.Package pkg;
try {
// 对文件进行解析处理,APK数据保存在PackageParser.Package 对象中
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
//APK更新升级相关逻辑
//......
}

PackageParser.parsePackage()


public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {// 包含APK的路径 比如/data/app/xxxx
return parseClusterPackage(packageFile, flags);
} else {//直接解析一个APK文件,比如/system/framework/framework-res.apk
return parseMonolithicPackage(packageFile, flags);
}
}

先看直接解析APK的方法:parseMonolithicPackage()


public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
if (mOnlyCoreApps) {
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
if (!lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"Not a coreApp: " + apkFile);
}
}
// AssetManager初始化
final AssetManager assets = new AssetManager();
try {
final Package pkg = parseBaseApk(apkFile, assets, flags);
pkg.codePath = apkFile.getAbsolutePath();
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}

创建了一个AssetManager对象,然后通过parseBaseApk()来解析APK文件,parseBaseApk主要是对AndroidManifest.xml文件进行解析,然后把解析后的数据保存到Package中,详细的解析过程这里略过,相关的数据保存对象如下图:



QQ截图20160811114726.png
3.5 对解析APK获取的PackageParser.Package配置进程相关信息,填充3.1中的Settings信息,最后保存到ArrayMap<String, PackageParser.Package> mPackages这个Map中。
3.6 packagemanagerservice构造函数主要的工作总结如下:

1)对特定的一些系统进程信息进行设置处理,保存到Settings中;
2)通过解析/etc/permissions下的相关xml文件取得系统相关权限、系统具备的相关功能等信息;
3)通过解析/data/system/package.xml文件获取已安装应用相关信息;
4)对相关的apk和jar进行dex优化处理,主要是/system/framework/目录下的相关jar和apk,framework-res.apk就放置在该目录下面;
5)解析特定目录下的APK文件(主要是解析AndroidManifest.xml),获取APK相关信息,保存到PackageParser.Package这个对象中;
6)依据sharedUserId这个配置来确定APK运行在哪个进程,然后把运行的相关进程信息加入到Settings中,使得系统能够知道每个APK运行在哪个进程里面。




最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台