上一章pms初步理解中提到SystemServer启动pms只创建了一个pms实例,那么重点在pms的实例化过程究竟做了什么事情,下面来研究下pms的构造方法。
PackageManagerService构造方法 ①:
[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, SystemClock.uptimeMillis());
mContext = context;
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
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);
构造方法内部首先获得一个系统级上下文mContext,并在实例化mSettings后,添加system, radio, log, nfc, bluetooth, shell 6种SharedUserSettings到mSettings。
Settings
Settings这个类包含所有安装后的apk信息,里面保存了一个mPackages映射表,根据apk包名映射对应的apk包信息,比如permissions权限信息 ,name, codePath, mSharedLibraries, restrictions, userid, version等等,这些信息将保存到一个名为 packages的XML文件中,pms服务启动时,如果packages.xml文件存在,那么会先读里面的内容初始化Settings实例,随后packages.xml文件里面的内容会随着apk安装信息的更新而更新。
Settings类结构如图(2)所示
(图2)
Settings的构造方法
Settings类的构造方法如下,主要创建data/system目录下的多个配置文件,例如packages.xml。
[/frameworks/base/services/core/java/com/android/server/pm/Settings.java]
Settings(Context context) {
this(context, Environment.getDataDirectory());
}
Settings(Context context, File dataDir) {
mSystemDir = new File(dataDir, "system");
mSystemDir.mkdirs();
FileUtils.setPermissions(mSystemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
mSettingsFilename = new File(mSystemDir, "packages.xml");
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
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");
}
//创建data/system目录
//创建data/system/packages.xml文件
//创建data/system/pacakges-backup.xml文件
//创建data/system/packages.list文件
//创建data/system/packages-stopped.xml文件
//创建data/system/packages-stopped-backup.xml文件
创建并添加SharedUserSetting
Settings实例化后,调用Settings的addSharedUserLPw方法添加6个系统的sharedUser,保存在Settings的mSharedUsers数组中。下图是SharedUserSettings的类结构,其中SettingBase是SharedUserSetting的基类,基类中包含pkgFlags/pkgPrivateFlags/PermissionsState,另外SettingBase也是PackageSetting的基类。
实例化SystemConfig并获得gids, systempermissions, features
PackageManagerService的构造方法体 ②:
[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
mInstaller = installer;
getDefaultDisplayMetrics(context, mMetrics);
SystemConfig systemConfig = SystemConfig.getInstance();
mGlobalGids = systemConfig.getGlobalGids();
mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();
通过实例化SystemConfig获得mGlobalGids, mSystemPermissions, mAvailableFeatures。
[/frameworks/base/services/core/java/com/android/server/SystemConfig.java]
int[] mGlobalGids;
final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();
final ArrayMap<String, String> mSharedLibraries = new ArrayMap<>();
final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();
final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();
final ArraySet<String> mAllowInPowerSave = new ArraySet<>();
final ArraySet<String> mFixedImeApps = new ArraySet<>();
SystemConfig() {
readPermissions(Environment.buildPath(Environment.getRootDirectory(), "etc", "sysconfig"), false);
readPermissions(Environment.buildPath(Environment.getRootDirectory(), "etc", "permissions"), false);
readPermissions(Environment.buildPath(Environment.getOemDirectory(), "etc", "sysconfig"), true);
readPermissions(Environment.buildPath(Environment.getOemDirectory(), "etc", "permissions"), true);
}
SystemConfig解析system/etc/sysconfig和permissions目录下面的所有xml,得到下面的信息:
(1) mGlobalGids,建立底层user ids和group ids同上层permissions之间的映射;可以指定一个权限和几个组id的对应。当一个APK被授予这个权限时,它也同时属于这几个组;
(2) mSystemPermissions,给一些底层用户分配权限,如给 shell 授予各种 permission 权限;把一个权限赋予一个UID,当进程使用这个 UID 运行时,就具备了这个权限;
(3) mSharedLibraries,系统增加的一些应用需要 link 的扩展 jar 库;
(4) mAvailableFeatures,系统所有支持的个硬件,如新增硬件支持,都要添加相应的feature;
解析结果mSystemPermissions,mSharedLibraries,mSettings.mPermissions,mAvailableFeatures 等几个集合中供系统查询和权限配置使用。
开始扫描并解析apk
PackageManagerService的构造方法体 ③:
[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
File dataDir = Environment.getDataDirectory();
mAppDataDir = new File(dataDir, "data");
mAppInstallDir = new File(dataDir, "app");
mAppLib32InstallDir = new File(dataDir, "app-lib");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
sUserManager = new UserManagerService(context, this, mInstallLock, mPackages);
首先上mInstallLock锁,关于这个锁,前面有注释,用于在做安装操作和其他耗时操作,一般调用到“LI”标签方法都需要上这个锁。
// Lock for state used when installing and doing other long running
// operations. Methods that must be called with this lock held have
// the suffix "LI".
final Object mInstallLock = new Object();
第二步上mPackages锁,mPackages的数据结构是包名和包对象的映射表,随着apk一个个的被解析,到最后mPackages会保存所有的已安装apk信息(重要)。同时为了线程安全,作为一个同步锁,在调用“LP”关键字结尾的方法都需要上这个锁。
// Keys are String (package name), values are Package. This also serves
// as the lock for the global state. Methods that must be called with
// this lock held have the prefix "LP".
final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<String, PackageParser.Package>();
第三步,建立PackageHandler消息循环,用于处理外部的apk安装请求消息,如adb install, PackageInstaller安装apk请求。并添加到watchdog中进行状态跟踪。可以看到服务首先创建了并运行了一个HandlerThread线程后进入阻塞,并将这个线程的Looper赋予了给PackageHandler,因此所有PackageHandler发的消息都交由这个HandlerThread线程处理并分发,关于PackageHandler,后面详细分析。
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
第四步,在data目录下建立多个系统目录,如/data/app(用于保存安装的第三方apk包), /data/data(用于保存apk数据), /data/app-lib, /data/app-asec, /data/user, /data/app-private
File dataDir = Environment.getDataDirectory();
mAppDataDir = new File(dataDir, "data");
mAppInstallDir = new File(dataDir, "app");
mAppLib32InstallDir = new File(dataDir, "app-lib");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
第五步,将system/etc/permissions目录解析出来的permissions信息以BasePermission形式保存到mSettings的mPermissions中。mSettings的mPermissions最终会随着所有apk的扫描解析而补全,可以认为mSettings的mPermissions保存了系统所有的权限声明。
将system/etc/permission目录解析出来的所有sharedlibs保存到PMS的mSharedLibraries,提供后面共享库的使用。
解析并读取/data/system/packages.xml文件信息保存到mRestoredSettings实例,如果是第一次开机,读取后mRestoredSettings实例为空。
获得默认的ResolverActivity,这个可以在framework/res的config_customResolverActivity做定制,一般为空。
PackageManagerService的构造方法体 ④:
[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
// Propagate permission configuration in to package manager.
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) {
bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
mSettings.mPermissions.put(perm.name, bp);
}
if (perm.gids != null) {
bp.gids = appendInts(bp.gids, perm.gids);
}
}
ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
for (int i=0; i<libConfig.size(); i++) {
mSharedLibraries.put(libConfig.keyAt(i), new SharedLibraryEntry(libConfig.valueAt(i), null));
}
mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false), mSdkVersion, mOnlyCore);
String customResolverActivity = Resources.getSystem().getString(R.string.config_customResolverActivity);
if (TextUtils.isEmpty(customResolverActivity)) {
customResolverActivity = null;
} else {
mCustomResolverComponentName = ComponentName.unflattenFromString(customResolverActivity);
}
第六步,获得服务启动时间,初始化scanFlags,随着后面的扫描,scanFlags会赋予更多的内容。读取bootClassPath和systemServerClassPath,解析所有运行环境动态jar包并添加到alreadyDexOpted列表中,表示这些动态jar已经DexOpt过。读取上面保存到mSharedLibraries并做DexOpt优化。读取system/framework目录下的所有jar和apk,逐个检查是否需要odex,如不需要添加到alreadyDexOpted列表中,若需要,调用Installer的dexopt,传入最优的ABI类型进行odex优化。
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,startTime);
final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
final ArraySet<String> alreadyDexOpted = new ArraySet<String>();
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);
}
}
if (systemServerClassPath != null) {
String[] systemServerClassPathElements = splitString(systemServerClassPath, ':');
for (String element : systemServerClassPathElements) {
alreadyDexOpted.add(element);
}
}
final List<String> allInstructionSets = getAllInstructionSets();
final String[] dexCodeInstructionSets =
getDexCodeInstructionSets(allInstructionSets.toArray(new String[allInstructionSets.size()]));
if (mSharedLibraries.size() > 0) {
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {
final String lib = libEntry.path;
try {
byte dexoptRequired = DexFile.isDexOptNeededInternal(lib, null,
dexCodeInstructionSet,false);
if (dexoptRequired != DexFile.UP_TO_DATE) {
alreadyDexOpted.add(lib);
if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
} else {
mInstaller.patchoat(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
}
}
} 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());
}
}
}
}
PackageManagerService的构造方法体 ⑤:
第七步,分别按照优先级扫描解析并安装/vendor/overlay > /system/framework >/system/priv-app > /system/app > /vendor/app >oemAppDir下的所有apk文件。
[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");
alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");
String[] frameworkFiles = frameworkDir.list();
if (frameworkFiles != null) {
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (int i=0; i<frameworkFiles.length; i++) {
File libPath = new File(frameworkDir, frameworkFiles[i]);
String path = libPath.getPath();
if (alreadyDexOpted.contains(path)) {
continue;
}
if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
continue;
}
try {
byte dexoptRequired = DexFile.isDexOptNeededInternal(path, null, dexCodeInstructionSet, false);
if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
} else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {
mInstaller.patchoat(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
}
}
File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED,scanFlags | SCAN_NO_DEX, 0);
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);
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
File vendorAppDir = new File("/vendor/app");
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
扫描安装流程图如下:
PackageManagerService的构造方法体 ⑥:
扫描system分区的几个保存apk文件的目录,得到目录下所有文件实例,是否apk以及apk命名是否合法。如果都没问题,调用scanPackageLI方法对apk文件进一步解析。
捕获安装异常后,如果非system应用,则删除有问题的apk目录和文件。
[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = dir.listFiles();
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
continue;
}
try {
scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK, scanFlags, currentTime, null);
} catch (PackageManagerException e) {
// 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()) {
FileUtils.deleteContents(file);
}
file.delete();
}
}
}
}
PackageManagerService的构造方法体 ⑦:
从scanDirLI传入apk的文件路径后,和默认parseFlags合成扫描标记。
创建PackageParser实例,有关PackageParser(包解析器)的结构,下面会详细描述。
pp.setDisplayMetrics方法传入手机的分辨率参数,用于初始化资源管理器。最后调用PackageParser的parsePackage方法返回解析的Package实例。
[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
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 {
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
PackageParser中定义多个静态内部类,如PackageParser.Package(表示一个apk安装包),这个内部类十分重要,apk解析后得到的所有信息都保存在这个类中,并添加拿到PackageManagerService的mPackages列表中。另外一个就是PackageParser.Component(表示一个应用组件),其中内部类Permission/Activity/Service/Provider都是它的子类,他们在PackageParser都是轻量级的组件表示,具体的组件表示分别是PermissionInfo/ActivityInfo/ServiceInfo/ProviderInfo。包解析类PackageParser的结构如图4:
[/frameworks/base/core/java/android/content/pm/PackageParser.java]
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(packageFile, flags);
} else {
return parseMonolithicPackage(packageFile, flags);
}
}
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
final PackageLite lite = parseClusterPackageLite(packageDir, 0);
final AssetManager assets = new AssetManager();
try {
loadApkIntoAssetManager(assets, lite.baseCodePath, flags);
if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
for (String path : lite.splitCodePaths) {
loadApkIntoAssetManager(assets, path, flags);
}
}
final File baseApk = new File(lite.baseCodePath);
final Package pkg = parseBaseApk(baseApk, assets, flags);
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}
private Package parseBaseApk(File apkFile, AssetManager assets, int flags) throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
mParseError = PackageManager.INSTALL_SUCCEEDED;
Resources res = null;
XmlResourceParser parser = null;
try {
res = new Resources(assets, mMetrics, null);
assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT);
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final String[] outError = new String[1];
final Package pkg = parseBaseApk(res, parser, flags, outError);
pkg.mSignatures = null;
return pkg;
} catch (PackageParserException e) {
throw e;
}
}
执行parseBaseApk方法通过XmlPullParser根据不同的深度,解析AndroidManifest.xml文件中的所有标签和元素,保存到对应的数组中。
private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
AttributeSet attrs = parser;
//…//
if (tagName.equals("key-sets")) {
//解析keysets并保存到publicKeyNames中
if (!parseKeySets(pkg, res, parser, attrs, outError)) {
return null;
}
} else if (tagName.equals("permission-group")) {
//解析permission group并保存到permissionGroups中
if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) {
return null;
}
} else if (tagName.equals("permission")) {
//解析permission并保存到permissions列表中
if (parsePermission(pkg, res, parser, attrs, outError) == null) {
return null;
}
} else if (tagName.equals("uses-permission")) {
//解析uses permission并保存到requestPermissions列表中
if (!parseUsesPermission(pkg, res, parser, attrs, outError)) {
return null;
}
}
//…//
String tagName = parser.getName();
//判断到<application>标签,调用parseBaseApplicatin方法逐层解析下面的元素
if (tagName.equals("application")) {
if (foundApp) {
if (RIGID_PARSER) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
} else {
XmlUtils.skipCurrentTag(parser);
continue;
}
}
foundApp = true;
//开始解析application标签里的activity/receive/provider/service/intentfilter…
if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {
return null;
}
}
//…//
private boolean parseBaseApplication(Package owner, Resources res, XmlPullParser parser,
AttributeSet attrs, int flags, String[] outError) throws XmlPullParserException, IOException {
final ApplicationInfo ai = owner.applicationInfo;
final String pkgName = owner.applicationInfo.packageName;
//…//
String tagName = parser.getName();
if (tagName.equals("activity")) {
Activity a =
parseActivity(owner, res, parser, attrs, flags, outError, false, owner.baseHardwareAccelerated);
owner.activities.add(a);
} else if (tagName.equals("receiver")) {
//解析receiver并添加到PackageParser.Package.receivers中
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false);
owner.receivers.add(a);
} else if (tagName.equals("service")) {
//解析service并添加到PackageParser.Package.services中
Service s = parseService(owner, res, parser, attrs, flags, outError);
owner.services.add(s);
} else if (tagName.equals("provider")) {
//解析provider并添加到PackageParser.Package.providers中
Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
owner.providers.add(p);
}
解析的标签以及层级结构如下图。
进一步解析apk
回到PackageManagerService中,通过PackageParser的parsePackage方法解析得到含apk所有基本信息的PackageParser.Package实例pkg,继续执行后续的安装操作。
PackageManagerService的构造方法体 ⑧:
PackageParser.parsePackage后得到当前扫描目录下apk文件的所有信息,并以pkg表示。接下来要更进一步的执行apk安装的操作,首先先来检查当前解析后pkg的老旧程度。这里主要针对system应用,一个首要原则是如果更新后的apk(data/app目录下)的version大于等于system/app目录下预装的同样一个apk,那这时候直接抛异常返回,不会继续往下跑,除非发现system目录下扫描的apk比之前更新的apk版本要新,那么会重新安装这个新版本的apk。
一般第一次开机执行apk扫描安装操作,ps都是空,这些地方都不会跑到,只有在开机一次后生成了cache,下次开机则需要比较cache中的内容。因此保存cache(packages.xml)对于第二次开机,速度上有很大的提升。
[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
PackageSetting ps = null;
PackageSetting updatedPkg;
// reader
synchronized (mPackages) {
//通过开机预加载的mSettings找到当前是否存在同样包名的旧apk
// Look to see if we already know about this package.
String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
if (ps == null) {
ps = mSettings.peekPackageLPr(pkg.packageName);
}
//通过开机预加载的mSettings看是否找到被disable掉的package
updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
}
boolean updatedPkgBetter = false;
if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
if (ps != null && !ps.codePath.equals(scanFile)) {
if (pkg.mVersionCode <= ps.versionCode) {
//发现cache中保存的另外一个目录(data/app)的apk版本比当前扫描的apk版本要新,
//那么跳出解析,沿用cache的apk
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, null);
} else {
synchronized (mPackages) {
//否则,重新激活当前扫描的apk
mSettings.enableSystemPackageLPw(ps.name);
}
updatedPkgBetter = true;
}
}
}
下一步搜集apk签名信息并比较,这部分会在(5)签名证书校验过程中详细分析。
// Verify certificates against what was last scanned
collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);
//搜集当前pkg签名信息
if (updatedPkg == null && ps != null && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
/*
* Check to make sure the signatures match first. If they don't,
* wipe the installed application and its data.
*/
if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
//比较签名,如果不匹配,删除apk和资源
deletePackageLI(pkg.packageName, null, true, null, null, 0, null, false);
ps = null;
}
}
初始化pkg.applicationInfo中的代码和资源路径后,进一步调用scanPackageLI执行pkg安装操作。
// Set application objects path explicitly.
pkg.applicationInfo.setCodePath(pkg.codePath);
pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
pkg.applicationInfo.setResourcePath(resourcePath);
pkg.applicationInfo.setBaseResourcePath(baseResourcePath);
pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
// Note that we invoke the following method only if we are about to unpack an application
//调用scanPackageLI执行进一步安装操作
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user);
scanPackageLI里面紧接着调用scanPackageDirtyLI,接下来详细分析scanPackageDirtyLI方法。
这个方法比较大,大概有一千两百多行,具体要分块来看。
第一步:根据parseFlags初始化pkg.applicationInfo的flags,这个flags对pkg类型和等级划分有很大的作用。
[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
//如果parseFlags含system,那么意味着这是一个system级pkg,
//所以也给这个pkg的flags加上system标签。
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM
}
if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
//如果parseFlags含privileged,那么意味着这是一个privileged级pkg,
//所以也给这个pkg的flags加上privileged标签。
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_PRIVILEGED;
}
if (mCustomResolverComponentName != null &&
mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
//找出默认的resolver包名
setUpCustomResolverActivity(pkg);
}
第二步:如果pkg包名是”android”,表示平台应用,实际上它就是framework/framework-res.apk,将该apk信息赋值给全局变量mAndroidApplication。
判断Resolver程序是否已经有,如果没有,则用系统默认的ResolveActivity作为菜单选择应用,一般都会用源生的ResolveActivity。
if (pkg.packageName.equals("android")) {
synchronized (mPackages) {
mPlatformPackage = pkg;
pkg.mVersionCode = mSdkVersion;
mAndroidApplication = pkg.applicationInfo;
if (!mResolverReplaced) {
mResolveActivity.applicationInfo = mAndroidApplication;
mResolveActivity.name = ResolverActivity.class.getName();
mResolveActivity.packageName = mAndroidApplication.packageName;
mResolveActivity.processName = "system:ui";
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
mResolveActivity.theme = R.style.Theme_Holo_Dialog_Alert;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
mResolveInfo.activityInfo = mResolveActivity;
mResolveInfo.priority = 0;
mResolveInfo.preferredOrder = 0;
mResolveInfo.match = 0;
mResolveComponentName = new ComponentName(mAndroidApplication.packageName,
mResolveActivity.name);
}
}
}
第三步:
1,判断解析后的pkg是否包含shareduser,如果有则取出来赋值给suid,如:shareduserid=”android.uid.system”,那么得到的suid就是systemuid的实例。
2,获得pkg对应的PackageSetting实例pkgSetting,首次开机会new一个PackageSetting实例,随后的开机则会重用cache(packages.xml)中的pkgSettings内容。 注意:这里会对应生成apk进程的uid保存到PackageSetting实例中,以appId表示。
3,如果disabledSystemPackage包含当前pkg,则给flags标记FLAG_UPDATED_SYSTEM_APP,表示更新后的system应用。如/data/app目录下的更新apk。
4,根据mSharedLibraries列表中的sharedlib来更新/data/app目录下所有apk需要用到的usesLibraryFiles。
5,保存uid和pkgSetting到pkg实例中。
注意:以后想要拿到对应pkg的pkgSetting信息,引用其mExtras即可。
synchronized (mPackages) {
if (pkg.mSharedUserId != null) {
suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, true);
if (suid == null) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Creating application package " + pkg.packageName + " for shared user failed"); package " + pkg.packageName + " for shared user failed");
}
}
pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
pkg.applicationInfo.primaryCpuAbi,
pkg.applicationInfo.secondaryCpuAbi,
pkg.applicationInfo.flags, user, false);
if (pkgSetting == null) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Creating application package " + pkg.packageName + " failed");
}
if (mSettings.isDisabledSystemPackageLPr(pkg.packageName)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
updateSharedLibrariesLPw(pkg, null);
}
pkg.applicationInfo.uid = pkgSetting.appId;
pkg.mExtras = pkgSetting;
第四步:检查cache中保存的签名信息和当前解析pkg的签名信息是否匹配,分4种情况:
1, cache中保存的签名信息没有标记为更新,或者包含sharedUser的情况下,需要比对签名
2, 如果签名和cache中保存的签名信息不匹配,但是system应用,直接以当前pkg签名覆盖
3, 包含sharedUser的,需要比对和其他sharedUser比对签名
4, Cache中签名信息有更新,比对后覆盖更新
注意:比对签名实际就是两个签名文件之间内容的比较。
if (!pkgSetting.keySetData.isUsingUpgradeKeySets() || pkgSetting.sharedUser != null) {
try {
// 1,cache中保存的签名没有更新或者包含sharedUser,
// 调用verifySignaturesLP比对签名
verifySignaturesLP(pkgSetting, pkg);
// 1,签名匹配,更新cache信息
pkgSetting.signatures.mSignatures = pkg.mSignatures;
} catch (PackageManagerException e) {
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
throw e;
}
// 2,虽然签名和cache不一致,但是system应用的话,直接以当前pkg的签名替换覆盖
pkgSetting.signatures.mSignatures = pkg.mSignatures;
if (pkgSetting.sharedUser != null) {
// 3,包含sharedUser的话,要比对和sharedUser之间的签名
if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
throw new PackageManagerException(
INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
"Signature mismatch for shared user : " + pkgSetting.sharedUser);
}
}
}
} else {
// 4,cache中签名信息有更新,比对新签名
if (!checkUpgradeKeySetLP(pkgSetting, pkg)) {
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"Package " + pkg.packageName + " upgrade keys do not match the " +
"previously installed version");
} else {
// 4,比对一致,以当前pkg签名信息为最新
pkgSetting.signatures.mSignatures = pkg.mSignatures;
}
}
第五步:
1,检查新安装的应用注册的provider是否和现有的provider冲突,如果冲突直接返回安装失败异常。
2,如果有AdoptPermissions,做旧版本pkg权限向新版本pkg权限传递(发生在系统应用更新过程中)。
if ((scanFlags & SCAN_NEW_INSTALL) != 0) {
for (int i=0; i<pkg.providers.size(); 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]);
final String otherPackageName = ((other != null && other.getComponentName()
!= null) ? other.getComponentName().getPackageName() : "?");
throw new PackageManagerException(INSTALL_FAILED_CONFLICTING_PROVIDER,
"Can't install because provider name " + names[j] +
" (in package " + pkg.applicationInfo.packageName
+ ") is already used by " + otherPackageName);
}
}
}
}
}
if (pkg.mAdoptPermissions != null) {
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)) {
mSettings.transferPermissionsLPw(origName, pkg.packageName);
}
}
}
}
第六步:
1,获得扫描文件最后一次修改时间scanFileTime,这个变量后面会用到。
2,判断是否需要FORCE_DEX,后面会用到。
3,根据pkg包名获得dataPath,如果包名是”android”,dataPath为/data/system,否则dataPath为/data/packageName。
3.1,首先判断该dataPath目录是否存在,如果存在,检查里面的有效性,如果失效或异常,重新安装
3.2,如果不存在改dataPath目录,首次安装,这时调用createDataDirsLI方法执行apk安装操作。
final String pkgName = pkg.packageName;
final long scanFileTime = scanFile.lastModified();
final boolean forceDex = (scanFlags & SCAN_FORCE_DEX) != 0;
pkg.applicationInfo.processName = fixProcessName(pkg.applicationInfo.packageName,
pkg.applicationInfo.processName, pkg.applicationInfo.uid);
File dataPath;
if (mPlatformPackage == pkg) {
// The system package is special.
dataPath = new File(Environment.getDataDirectory(), "system");
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
dataPath = getDataPathForPackage(pkg.packageName, 0);
boolean uidError = false;
if (dataPath.exists()) {
int currentUid = 0;
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid, pkg.applicationInfo.seinfo);
if (dataPath.exists()) {
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
Slog.w(TAG, "Unable to create data directory: " + dataPath);
pkg.applicationInfo.dataDir = null;
}
}
pkgSetting.uidError = uidError;
}
4,createDataDirsLI方法中调用mInstaller(Installer服务)中的install和createUserData方法,通过Socket和底层installd进程通讯,创建dataPath目录。 Installd执行安装过程后面会有分析。
private int createDataDirsLI(String packageName, int uid, String seinfo) {
int[] users = sUserManager.getUserIds();
int res = mInstaller.install(packageName, uid, uid, seinfo);
if (res < 0) {
return res;
}
for (int user : users) {
if (user != 0) {
res = mInstaller.createUserData(packageName,
UserHandle.getUid(user, uid), user, seinfo);
if (res < 0) {
return res;
}
}
}
return res;
}
第七步:解析system级和data级目录下apk的CpuAbi信息,这里的CpuAbi表示系统以哪种形式去动态加载so库。
【应用程序二进制接口(application binary interface,ABI) 描述了应用程序和操作系统之间,一个应用和它的库之间,或者应用的组成部分之间的低接口 。ABI 不同于 API ,API 定义了源代码和库之间的接口,因此同样的代码可以在支持这个 API 的任何系统中编译 ,然而 ABI 允许编译好的目标代码在使用兼容 ABI 的系统中无需改动就能运行。】
pkg.cpuAbiOverride ---> 用于应用跨进程运行,动态so的拷贝控制
pkg.applicationInfo.primaryCpuAbi ---> 基本CpuAbi,最优先以该形式起应用进程
pkg.applicationInfo.secondaryCpuAbi --->第二优先CpuAbi
pkg.applicationInfo.nativeLibraryRootDir --->本地库根目录
pkg.applicationInfo.nativeLibraryRootRequiresIsa --- >是否添加arm/arm64 (系统应用)
pkg.applicationInfo.nativeLibraryDir --- >本地库目录
pkg.applicationInfo.secondaryNativeLibraryDir ---> 第二优先本地库目录
针对系统应用和第三方应用,上述CpuAbi信息的获取方式是不同的,另外系统应用的CpuAbi信息在开机扫描安装过程中就已经固定下来。
系统应用获得CpuAbi信息的过程如下。
final String path = scanFile.getPath();
final String codePath = pkg.applicationInfo.getCodePath();
final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
setBundledAppAbisAndRoots(pkg, pkgSetting);
setNativeLibraryPaths(pkg);
}
private static void setBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
final File codeFile = new File(pkg.codePath);
final boolean has64BitLibs;
final boolean has32BitLibs;
if (isApkFile(codeFile)) {
// Monolithic install 单独apk文件形式
has64BitLibs = (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
} else {
// Cluster install 以文件夹形式安装方式
final File rootDir = new File(codeFile, LIB_DIR_NAME);
if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
&& !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
has64BitLibs = (new File(rootDir, isa)).exists();
}
if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
&& !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
has32BitLibs = (new File(rootDir, isa)).exists();
}
}
if (has64BitLibs && !has32BitLibs) {
// 只含64位so,系统支持64位,则primaryCpuAbi是arm64
pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
pkg.applicationInfo.secondaryCpuAbi = null;
} else if (has32BitLibs && !has64BitLibs) {
//只含32位so,系统支持32位,则primaryCpuAbi是armabi
pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
pkg.applicationInfo.secondaryCpuAbi = null;
} else if (has32BitLibs && has64BitLibs) {
//两个so都含,检查是否支持multiArch,否则抛异常
// primaryCpuAbi以列表顺序最高 secondaryCpuAbi为第二
if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
Slog.e(TAG, "Package: " + pkg + " has multiple bundled libs, but is not multiarch.");
}
if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
} else {
pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
}
} else {
//不包含so,则为空
pkg.applicationInfo.primaryCpuAbi = null;
pkg.applicationInfo.secondaryCpuAbi = null;
}
}
获得primaryCpuAbi和secondaryCpuAbi信息后,将这两个信息保存到pkgSettings中。然后执行setNativeLibraryPaths方法获得跟多nativeLibrary信息,如nativeLibraryRootDir, nativeLibraryDir…
非系统应用获得primaryCpuAbi和sceondaryCpuAbi信息就显得复杂很多,通过计算得到安装应用的primaryCpuAbi后,需要创建Link将so关联起来(注意:只为32位so创建link)。代码如下:
if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path);
final int[] userIds = sUserManager.getUserIds();
synchronized (mInstallLock) {
// Create a native library symlink only if we have native libraries
// and if the native libraries are 32 bit libraries. We do not provide
// this symlink for 64 bit libraries.
if (pkg.applicationInfo.primaryCpuAbi != null &&
!VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) {
final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir;
for (int userId : userIds) {
if (mInstaller.linkNativeLibraryDirectory(pkg.packageName,
nativeLibPath, userId) < 0) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
"Failed linking native library dir (user=" + userId + ")");
}
}
}
}
针对frameworks-res.apk的primaryCpuAbi有特殊的处理,根据VMRuntime是否允许64位来优先判断。
// This is a special case for the "system" package, where the ABI is
// dictated by the zygote configuration (and init.rc). We should keep track
// of this ABI so that we can deal with "normal" applications that run under
// the same UID correctly.
if (mPlatformPackage == pkg) {
pkg.applicationInfo.primaryCpuAbi = VMRuntime.getRuntime().is64Bit() ?
Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
}
第八步:primaryCpuAbi处理完成后,继续scanPackageDirtyLI方法收尾部分代码。
if ((scanFlags&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
// 此处做shareduser的CpuAbi适配动作,意思是shareduser的应用CpuAbi信息应该统一
// 这里判断如果是开机扫描过程,不用做这步,放在PMS构造方法最后去做
adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
pkg, forceDex, (scanFlags & SCAN_DEFER_DEX) != 0);
}
// 声明了FACTORY_TEST权限的应用,对应的applicationInfo中要记录一个标志位标识
if (mFactoryTest && pkg.requestedPermissions.contains(
android.Manifest.permission.FACTORY_TEST)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
}
// 筛选出应用中满足条件的shareLibrary并添加到mSharedLibraries总表中。
ArrayList<PackageParser.Package> clientLibPkgs = null;
// writer
synchronized (mPackages) {
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
// Only system apps can add new shared libraries.
for (int i=0; i<pkg.libraryNames.size(); i++) {
String name = pkg.libraryNames.get(i);
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");
}
}
}
}
//如果扫描flag带SCAN_REPLACING标志,意味着应用替换,请求AMS先杀死当前运行中的旧应用进程
if ((scanFlags & SCAN_REPLACING) != 0) {
killApplication(pkg.applicationInfo.packageName,
pkg.applicationInfo.uid, "update pkg");
}
// writer
synchronized (mPackages) {
// 当前pkgSettings添加到mSettings总表中
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// 当前pkg添加到mPackages总表中
mPackages.put(pkg.applicationInfo.packageName, pkg);
// 更新第一次安装和最后一次更新时间
if (currentTime != 0) {
if (pkgSetting.firstInstallTime == 0) {
pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
} else if ((scanFlags&SCAN_UPDATE_TIME) != 0) {
pkgSetting.lastUpdateTime = currentTime;
}
} else if (pkgSetting.firstInstallTime == 0) {
pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;
} else if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
if (scanFileTime != pkgSetting.timeStamp) {
pkgSetting.lastUpdateTime = scanFileTime;
}
}
// 添加安装应用签名key到KSMS中
KeySetManagerService ksms = mSettings.mKeySetManagerService;
ksms.removeAppKeySetDataLPw(pkg.packageName);
ksms.addSigningKeySetToPackageLPw(pkg.packageName, pkg.mSigningKeys);
// 将应用声明的providers添加到mProviders总表中
int N = pkg.providers.size();
StringBuilder r = null;
int i;
for (i=0; i<N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
p.info.processName, pkg.applicationInfo.uid);
mProviders.addProvider(p);
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Providers: " + r);
}
// 将应用声明的service添加到mServices总表中
N = pkg.services.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Service s = pkg.services.get(i);
s.info.processName = fixProcessName(pkg.applicationInfo.processName,
s.info.processName, pkg.applicationInfo.uid);
mServices.addService(s);
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Services: " + r);
}
// 将应用声明的recievers添加到mReceivers总表中
N = pkg.receivers.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.receivers.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
mReceivers.addActivity(a, "receiver");
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r);
}
// 将应用声明的activity添加到mActivities总表中
N = pkg.activities.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.activities.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
mActivities.addActivity(a, "activity");
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Activities: " + r);
}
// 将应用声明的permissionGroup添加到mPermissionGroups总表中
mPermissionGroups.put(pg.info.name, pg);
// 将应用声明的instrumentation添加到mInstrumentation总表中
N = pkg.instrumentation.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Instrumentation a = pkg.instrumentation.get(i);
a.info.packageName = pkg.applicationInfo.packageName;
a.info.sourceDir = pkg.applicationInfo.sourceDir;
a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs;
a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs;
a.info.dataDir = pkg.applicationInfo.dataDir;
a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
mInstrumentation.put(a.getComponentName(), a);
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r);
}
}
// scanPackageDirty方法执行完毕,返回安装后的pkg
return pkg;
至此,scanPackageDirty方法执行完毕,apk解析安装过程初步完成并返回解析出来的pkg实例。
要重点注意到pkg的mExtras引用指向了包含apk权限等各种信息的实例pkgSettings,同时pkg实例添加到了mPackages列表中,以后就可以通过mPackages列表找到这个pkg。
扫描安装过程如下图所示
pms构造方法结尾部分
分别扫描所有apk目录并安装解析所有apk后,回到pms构造方法中,主要完成两个事情,一个是清理多余或者无效的apk信息,另外一个是更新所有应用的sharedLibrary和权限信息。
清理多余或者无效的apk信息:
// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
final ArrayMap<String, File> expectingBetter = new ArrayMap<>();
//look for any incomplete package installations
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
//delete tmp files
deleteTempPackageFiles();
// Remove any shared userIDs that have no associated packages
mSettings.pruneSharedUsersLPw();
更新所有应用的sharedLibrary和权限信息:
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
updateAllSharedLibrariesLPw();
for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
// NOTE: We ignore potential failures here during a system scan (like
// the rest of the commands above) because there's precious little we
// can do about it. A settings error is reported, though.
adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */,
false /* force dexopt */, false /* defer dexopt */);
}
updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL | (regrantPermissions
? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
: 0));
关于updatePermissionsLPw这个方法十分重要,系统权限管理的分级以及分配规则就在这个方法里面。后面在系统权限管理中详细分析。
至此,pms的构造方法就分析完毕。
理解:构造方法中做了很多初始化的内容,以及扫描所有应用目录下的apk文件进行解析安装,最终都会添加到mPackages列表中,并在最后遍历mPackages列表中的所有应用,完成权限分配,共享库更新等功能。后续所有包管理任务都按照得到的mPackages来完成。