Android 启动时应用的安装解析过程《一》

avatar
作者
筋斗云
阅读量:0

应用对于Android系统来说至关重要,系统会有几个时机对APP进行解析,一个是APK安装的时候会进行解析,还有一个就是系统在重启之后会进行解析,这里就简单的记录一下重启的时候APK的解析过程。

一、SystemServer

系统在启动之后从内核层启动第一个用户控件Init进程,再通过Init进程启动系统中第一个java 进程zygote,随之zygote fock出SystemServer,SystemServer再开始启动一些列系统服务,其中就包括PackageMangerService,在startBootstrapServices函数中:

public final void startBootstrapServices(TimingsTraceAndSlog timingsTraceAndSlog) { .....     // 先调用了PackageManagerService的main函数  	Pair<PackageManagerService, IPackageManager> main = PackageManagerService.main(context, installer, domainVerificationService, z, this.mOnlyCore);  	// main 函数创建了PackageManagerService 和IPackageManager 的实例     this.mPackageManagerService = (PackageManagerService) main.first;     IPackageManager iPackageManager = (IPackageManager) main.second;     Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");     // 该方法将在 BaseDexClassLoader 中安装一个报告器,同时还将强制报告系统服务器已加载的任何 dex 文件     SystemServerDexLoadReporter.configureSystemServerDexReporter(iPackageManager);     this.mFirstBoot = this.mPackageManagerService.isFirstBoot();     this.mPackageManager = this.mSystemContext.getPackageManager(); 

二、PackageManagerService

在SystemServer中是先调用PackageManagerService的main函数来初始化它自己的,来看看它做了什么:

public static Pair<PackageManagerService, IPackageManager> main(Context context,             Installer installer, @NonNull DomainVerificationService domainVerificationService,             boolean factoryTest, boolean onlyCore) { 		PackageManagerServiceCompilerMapping.checkProperties();         final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",                 Trace.TRACE_TAG_PACKAGE_MANAGER);         t.traceBegin("create package manager");         final PackageManagerTracedLock lock = new PackageManagerTracedLock();         final Object installLock = new Object();         // 创建自带handler的线程         HandlerThread backgroundThread = new ServiceThread("PackageManagerBg",                 Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);         backgroundThread.start();         Handler backgroundHandler = new Handler(backgroundThread.getLooper());         // 创建PackageManagerServiceInjector 用来持有管理其他一系列重要的类实例 		PackageManagerServiceInjector injector = new PackageManagerServiceInjector(                 context, lock, installer, installLock, new PackageAbiHelperImpl(),                 backgroundHandler,                 SYSTEM_PARTITIONS,                 // 解析compnent的                 (i, pm) -> new ComponentResolver(i.getUserManagerService(), pm.mUserNeedsBadging),                 // 权限管理服务                 (i, pm) -> PermissionManagerService.create(context,                         i.getSystemConfig().getAvailableFeatures()),                 // 用户管理服务                 (i, pm) -> new UserManagerService(context, pm,                         new UserDataPreparer(installer, installLock, context, onlyCore),                         lock),                // 系统数据库,用来访问系统数据库的                 (i, pm) -> new Settings(Environment.getDataDirectory(),                         RuntimePermissionsPersistence.createInstance(),                         i.getPermissionManagerServiceInternal(),                         domainVerificationService, backgroundHandler, lock),                 (i, pm) -> AppsFilterImpl.create(i,                         i.getLocalService(PackageManagerInternal.class)),                  // compat服务用来管理一些系统特性                 (i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),                 // 系统配置服务,预置的系统的权限、硬件feature还有其他的一些配置在这里面解析                 (i, pm) -> SystemConfig.getInstance(),                 // 在软件包上运行 dexopt 命令的辅助类。                 (i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),                         i.getContext(), "*dexopt*"),                 // dex 行为管理类会保存所有包的dex位置                 (i, pm) -> new DexManager(i.getContext(), i.getPackageDexOptimizer(),                         i.getInstaller(), i.getInstallLock()),                 (i, pm) -> new ArtManagerService(i.getContext(), i.getInstaller(),                         i.getInstallLock()),                 (i, pm) -> ApexManager.getInstance(),                 (i, pm) -> new ViewCompiler(i.getInstallLock(), i.getInstaller()),                 (i, pm) -> (IncrementalManager)                         i.getContext().getSystemService(Context.INCREMENTAL_SERVICE),                 (i, pm) -> new DefaultAppProvider(() -> context.getSystemService(RoleManager.class),                         () -> LocalServices.getService(UserManagerInternal.class)),                 (i, pm) -> new DisplayMetrics(),                 // 包解析类                 (i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,                         i.getDisplayMetrics(), pm.mCacheDir,                         pm.mPackageParserCallback) /* scanningCachingPackageParserProducer */,                  (i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,                         i.getDisplayMetrics(), null,                         pm.mPackageParserCallback) /* scanningPackageParserProducer */,                 (i, pm) -> new PackageParser2(pm.mSeparateProcesses, false, i.getDisplayMetrics(),                         null, pm.mPackageParserCallback) /* preparingPackageParserProducer */,                 // Prepare a supplier of package parser for the staging manager to parse apex file                 // during the staging installation.                 // 包安装服务                 (i, pm) -> new PackageInstallerService(                         i.getContext(), pm, i::getScanningPackageParser),                 (i, pm, cn) -> new InstantAppResolverConnection(                         i.getContext(), cn, Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE),                 (i, pm) -> new ModuleInfoProvider(i.getContext()),                 (i, pm) -> LegacyPermissionManagerService.create(i.getContext()),                 (i, pm) -> domainVerificationService,                 (i, pm) -> {                     HandlerThread thread = new ServiceThread(TAG,                             Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);                     thread.start();                     return new PackageHandler(thread.getLooper(), pm);                 },                  new DefaultSystemWrapper(),                 LocalServices::getService,                 context::getSystemService,                 (i, pm) -> new BackgroundDexOptService(i.getContext(), i.getDexManager(), pm),                 (i, pm) -> IBackupManager.Stub.asInterface(ServiceManager.getService(                         Context.BACKUP_SERVICE)),                 (i, pm) -> new SharedLibrariesImpl(pm, i));                 if (Build.VERSION.SDK_INT <= 0) {             Slog.w(TAG, "**** ro.build.version.sdk not set!");         }         // 初始化PackageManagerService         PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest, PackagePartitions.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG, Build.VERSION.SDK_INT, Build.VERSION.INCREMENTAL);         t.traceEnd(); // "create package manager"         final CompatChange.ChangeListener selinuxChangeListener = packageName -> {             synchronized (m.mInstallLock) {                 final Computer snapshot = m.snapshotComputer();                 final PackageStateInternal packageState =                         snapshot.getPackageStateInternal(packageName);                 if (packageState == null) {                     Slog.e(TAG, "Failed to find package setting " + packageName);                     return;                 }                  AndroidPackage pkg = packageState.getPkg();                 SharedUserApi sharedUser = snapshot.getSharedUser(                         packageState.getSharedUserAppId());                 String oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, packageState);                                  if (pkg == null) {                     Slog.e(TAG, "Failed to find package " + packageName);                     return;                 }                 final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser,                         m.mInjector.getCompatibility());                                  if (!newSeInfo.equals(oldSeInfo)) {                     Slog.i(TAG, "Updating seInfo for package " + packageName + " from: "                             + oldSeInfo + " to: " + newSeInfo);                     m.commitPackageStateMutation(null, packageName,                             state -> state.setOverrideSeInfo(newSeInfo));                     m.mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);                 }             }         }; 		//监听selinux的一些变化 		injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES,                 selinuxChangeListener);         injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_R_CHANGES,                 selinuxChangeListener);         // ota完或者第一次开机为所有用户安装其被         m.installAllowlistedSystemPackages();         // 初始化 IPackageManagerImpl          IPackageManagerImpl iPackageManager = m.new IPackageManagerImpl();         ServiceManager.addService("package", iPackageManager);         // 初始化PackageManagerNative          final PackageManagerNative pmn = new PackageManagerNative(m);         ServiceManager.addService("package_native", pmn);         LocalManagerRegistry.addManager(PackageManagerLocal.class, m.new PackageManagerLocalImpl());         return Pair.create(m, iPackageManager);     } 

简单的介绍了一下main,下面重头戏在PackageManagerService的初始化过程,它总共有两个构造函数,注意一个只做了赋值,我们这里调用的不是这个构造函数而是另一个

public PackageManagerService(PackageManagerServiceInjector injector, boolean onlyCore,             boolean factoryTest, final String buildFingerprint, final boolean isEngBuild,             final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) { 	mIsEngBuild = isEngBuild; 	...... 	// 这里部分主要是给PackageMangerService的一些属性赋值 	...... 	// CHECKSTYLE:ON IndentationCheck     t.traceEnd(); 	t.traceBegin("addSharedUsers"); 	// 注册各种UID     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);     mSettings.addSharedUserLPw("android.uid.se", SE_UID,                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);     mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);     mSettings.addSharedUserLPw("android.uid.uwb", UWB_UID,                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);     t.traceEnd();     ......     // 又是一堆初始化赋值     ......     // 从systemconfig获取对于机器来说可用的硬件feature,可以在这里之前对feature进行修改     t.traceBegin("get system config");     SystemConfig systemConfig = injector.getSystemConfig();     mAvailableFeatures = systemConfig.getAvailableFeatures();     t.traceEnd();     ......     // 这里是读取在mac_permissions.xml下面配置的一些se策略可以有效的限制一些应用的权限     SELinuxMMAC.readInstallPolicy();     ......     final VersionInfo ver = mSettings.getInternalVersion();     // 指纹信息是否有更新     mIsUpgrade =             !buildFingerprint.equals(ver.fingerprint);     if (mIsUpgrade) {            PackageManagerServiceUtils.logCriticalInfo(Log.INFO, "Upgrading from "                         + ver.fingerprint + " to " + PackagePartitions.FINGERPRINT);    }       mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,                 mInjector.getSystemPartitions());      // when upgrading from pre-M, promote system app permissions from install to runtime     // 是否从M升上来     mPromoteSystemApps =                     mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;     // When upgrading from pre-N, we need to handle package extraction like first boot,    // as there is no profiling data available.    // 是否从N 升上来    mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;    // 是否从n mr升上来    mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;   // 是否从Q升上来    mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q;    ......    // 根据不同的版本类型创建缓存目录,如果已存在则不创建    mCacheDir = PackageManagerServiceUtils.preparePackageParserCache(                     mIsEngBuild, mIsUserDebugBuild, mIncrementalVersion);     final int[] userIds = mUserManager.getUserIds();    PackageParser2 packageParser = mInjector.getScanningCachingPackageParser();    // 初始化安装系统级APP    mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds,                     startTime);    // 初始化安装非系统级APP    mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime);    packageParser.close();    ...... } 

可以从上面PackageManagerService的初始化可以看到,机器开机的时候安装APP的任务是交给InitAppsHelper这个类来做的,两个函数一个initSystemApps一个initNonSystemApps,分别是初始化系统app和非系统app,两个函数都是对系统中的应用进行安装解析,区别就是针对系统app还是非系统app,我们先从系统app来看看。

三、InitAppsHelper

public OverlayConfig initSystemApps(PackageParser2 packageParser,             WatchedArrayMap<String, PackageSetting> packageSettings,             int[] userIds, long startTime)  

initSystemApps有四个参数,看下其中比较重要的两个参数怎么来的

1、PackageParser2

第一个参数实在PackageManagerService初始化的时候从mInjector获取的,而这里的PackageParser2是在PackaManagerService的main函数初始化的

PackageParser2 packageParser = mInjector.getScanningCachingPackageParser(); 

2、WatchedArrayMap<String, PackageSetting>

首先这个参数是通过PackageMangerService的成员变量mSettings获取:

final WatchedArrayMap<String, PackageSetting> packageSettings =                 mSettings.getPackagesLocked(); 

Settings.getPackagesLocked

 WatchedArrayMap<String, PackageSetting> getPackagesLocked() {         return mPackages;     } 

Settings.addPackageLPw 中添加数据

 PackageSetting addPackageLPw(String name, String realName, File codePath, int uid, int pkgFlags,                                  int pkgPrivateFlags, @NonNull UUID domainSetId) {         PackageSetting p = mPackages.get(name);         if (p != null) {             if (p.getAppId() == uid) {                 return p;             }             PackageManagerService.reportSettingsProblem(Log.ERROR,                     "Adding duplicate package, keeping first: " + name);             return null;         }         p = new PackageSetting(name, realName, codePath, pkgFlags, pkgPrivateFlags, domainSetId)                 .setAppId(uid);         if (mAppIds.registerExistingAppId(uid, p, name)) {             mPackages.put(name, p);             return p;         }         return null;     } 

Settings.readSettingsLPw,这个函数中对应用的一些配置信息进行解析,这些信息主要是存在/data/system目录下面

 boolean readSettingsLPw(@NonNull Computer computer, @NonNull List<UserInfo> users,             ArrayMap<String, Long> originalFirstInstallTimes) {         mPendingPackages.clear();         mInstallerPackages.clear();         originalFirstInstallTimes.clear();          ArrayMap<Long, Integer> keySetRefs = new ArrayMap<>();         ArrayList<Signature> readSignatures = new ArrayList<>();       	// 获取一系列配置文件,文件位于/data/system/下面,在setings初始化的时候被赋值       	/**       	mSystemDir = new File(dataDir, "system");         mSystemDir.mkdirs(); 		 mSettingsFilename = new File(mSystemDir, "packages.xml");          mSettingsReserveCopyFilename = new File(mSystemDir, "packages.xml.reservecopy");          mPreviousSettingsFilename = new File(mSystemDir, "packages-backup.xml");          下面就是对这些配置文件进行解析 		*/         try (ResilientAtomicFile atomicFile = getSettingsFile()) {             FileInputStream str = null;             try {                 str = atomicFile.openRead();                 if (str == null) {                     // Not necessary, but will avoid wtf-s in the "finally" section.                     findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent();                     findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent();                     return false;                 }                 final TypedXmlPullParser parser = Xml.resolvePullParser(str);                  int type;                 while ((type = parser.next()) != XmlPullParser.START_TAG                         && type != XmlPullParser.END_DOCUMENT) {                     // nothing                 }                  if (type != XmlPullParser.START_TAG) {                     mReadMessages.append("No start tag found in settings file\n");                     PackageManagerService.reportSettingsProblem(Log.WARN,                             "No start tag found in package manager settings");                     Slog.wtf(PackageManagerService.TAG,                             "No start tag found in package manager settings");                     return false;                 }                  int outerDepth = parser.getDepth();                 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT                         && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {                     if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {                         continue;                     }                      String tagName = parser.getName();                     if (tagName.equals("package")) {                     //读取包信息                         readPackageLPw(parser, readSignatures, keySetRefs, users,                                 originalFirstInstallTimes);                     } else if (tagName.equals("permissions")) {                         mPermissions.readPermissions(parser);                     } else if (tagName.equals("permission-trees")) {                         mPermissions.readPermissionTrees(parser);                     } else if (tagName.equals("shared-user")) {                         readSharedUserLPw(parser, readSignatures, users);                     } else if (tagName.equals("preferred-packages")) {                         // no longer used.                     } else if (tagName.equals("preferred-activities")) {                         // Upgrading from old single-user implementation;                         // these are the preferred activities for user 0.                         readPreferredActivitiesLPw(parser, 0);                     } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {                         // TODO: check whether this is okay! as it is very                         // similar to how preferred-activities are treated                         readPersistentPreferredActivitiesLPw(parser, 0);                     } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {                         // TODO: check whether this is okay! as it is very                         // similar to how preferred-activities are treated                         readCrossProfileIntentFiltersLPw(parser, 0);                     } else if (tagName.equals(TAG_DEFAULT_BROWSER)) {                         readDefaultAppsLPw(parser, 0);                     } else if (tagName.equals("updated-package")) {                         readDisabledSysPackageLPw(parser, users);                     } else if (tagName.equals("renamed-package")) {                         String nname = parser.getAttributeValue(null, "new");                         String oname = parser.getAttributeValue(null, "old");                         if (nname != null && oname != null) {                             mRenamedPackages.put(nname, oname);                         }                     } else if (tagName.equals("last-platform-version")) {                         // Upgrade from older XML schema                         final VersionInfo internal = findOrCreateVersion(                                 StorageManager.UUID_PRIVATE_INTERNAL);                         final VersionInfo external = findOrCreateVersion(                                 StorageManager.UUID_PRIMARY_PHYSICAL);                          internal.sdkVersion = parser.getAttributeInt(null, "internal", 0);                         external.sdkVersion = parser.getAttributeInt(null, "external", 0);                         internal.buildFingerprint = external.buildFingerprint =                                 XmlUtils.readStringAttribute(parser, "buildFingerprint");                         internal.fingerprint = external.fingerprint =                                 XmlUtils.readStringAttribute(parser, "fingerprint");                      } else if (tagName.equals("database-version")) {                         // Upgrade from older XML schema                         final VersionInfo internal = findOrCreateVersion(                                 StorageManager.UUID_PRIVATE_INTERNAL);                         final VersionInfo external = findOrCreateVersion(                                 StorageManager.UUID_PRIMARY_PHYSICAL);                          internal.databaseVersion = parser.getAttributeInt(null, "internal", 0);                         external.databaseVersion = parser.getAttributeInt(null, "external", 0);                      } else if (tagName.equals("verifier")) {                         final String deviceIdentity = parser.getAttributeValue(null, "device");                         mVerifierDeviceIdentity = VerifierDeviceIdentity.parse(deviceIdentity);                     } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {                         // No longer used.                     } else if (tagName.equals("keyset-settings")) {                         mKeySetManagerService.readKeySetsLPw(parser, keySetRefs);                     } else if (TAG_VERSION.equals(tagName)) {                         final String volumeUuid = XmlUtils.readStringAttribute(parser,                                 ATTR_VOLUME_UUID);                         final VersionInfo ver = findOrCreateVersion(volumeUuid);                         ver.sdkVersion = parser.getAttributeInt(null, ATTR_SDK_VERSION);                         ver.databaseVersion = parser.getAttributeInt(null, ATTR_DATABASE_VERSION);                         ver.buildFingerprint = XmlUtils.readStringAttribute(parser,                                 ATTR_BUILD_FINGERPRINT);                         ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT);                     } else if (tagName.equals(                             DomainVerificationPersistence.TAG_DOMAIN_VERIFICATIONS)) {                         mDomainVerificationManager.readSettings(computer, parser);                     } else if (tagName.equals(                             DomainVerificationLegacySettings.TAG_DOMAIN_VERIFICATIONS_LEGACY)) {                         mDomainVerificationManager.readLegacySettings(parser);                     } else {                         Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "                                 + parser.getName());                         XmlUtils.skipCurrentTag(parser);                     }                 }                  str.close();             } catch (IOException | XmlPullParserException | ArrayIndexOutOfBoundsException e) {                 // Remove corrupted file and retry.                 atomicFile.failRead(str, e);                  // Ignore the result to not mark this as a "first boot".                 readSettingsLPw(computer, users, originalFirstInstallTimes);             }         }          return true;     } 

从上面的函数可以看出Settings这个类的主要职责就是存储修改解析应用的配置信息,这里涉及的东西比较多,不再赘述有兴趣可以自行查阅相关源码。

            mFirstBoot = !mSettings.readLPw(computer,                     mInjector.getUserManagerInternal().getUsers(                     /* excludePartial= */ true,                     /* excludeDying= */ false,                     /* excludePreCreated= */ false)); 

这里是Settings解析的开始在PackageMangerService的构造函数中,这是第二个参数的由来,接着第三个四个参数就比较简单分别是uid和时间戳。

篇幅有限下一篇展开细说

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!