Android11版本更新提示解析软件包出现问题 安卓11解析安装包

您所在的位置:网站首页 解析程序包出现问题怎么解决手机软件 Android11版本更新提示解析软件包出现问题 安卓11解析安装包

Android11版本更新提示解析软件包出现问题 安卓11解析安装包

2023-12-21 09:33| 来源: 网络整理| 查看: 265

1、开篇

在上一篇文章中提到Settings类会在PackageManagerService启动过程中对packages.xml等一些列xml文件进行解析。那么有以下问题:

这些文件记录了什么内容?为什么需要这些文件?

让我们一起通过阅读源码解决这些问题吧。

2、packages.xml文件详解

要在真机上拿到packages.xml殊为不易,所以我这里是在模拟器上通过adb命令拉取了一份:

adb pull /data/system/packages.xml

文件内容精简后如下:

... ... ...

可以看到,packages.xml主要记录了以下几方面的信息:

权限信息,permission-trees标签和permissions标签。这里记录的是系统里所有的权限条目安装的App信息,包括系统App和用户自行安装的App,package和updated-package标签。其中package标签用户记录一般App的信息;而updated-package通常用于被用户手动升级了的系统App,比如说手机自带了计算器App,这个自带的App的版本是1.0,而厂商又在它的应用商店发布了计算器2.0,当我们在应用商店更新成2.0版本的时候,在系统分区和用户安装分区会各存在一个计算器App。这也是为什么我们在系统应用管理界面删除更新后的计算器2.0后,手机上还是会有计算器1.0版本,而不是彻底消失的原因。 package标签的属性记录了包名、代码路径、版本等各项信息。另外,package还会有一些子标签,sigs记录App的签名信息,perms记录App的权限信息,注意这里的权限是manifest中声明的权限而不是已经授予的权限。共享用户信息,shared-user标签。一般来说一个Android系统会为每一个App分配一个user id,但是我们也可以在manifest元素中指定android:sharedUserId属性,使多个App具有同样的user id从而可以共享数据等等。但是除了系统App,Android强烈建议我们不要使用它,并且在未来的版本可能会被移除,所以了解即可。签名信息,keyset-settings标签,记录的是应用签名的公钥。

packages.xml也不止以上这些标签,具体可以参考Settings类对packages.xml的解析:

boolean readLPw(@NonNull List users) { FileInputStream str = null; if (mBackupSettingsFilename.exists()) { try { str = new FileInputStream(mBackupSettingsFilename); mReadMessages.append("Reading from backup settings file\n"); PackageManagerService.reportSettingsProblem(Log.INFO, "Need to read from backup settings file"); if (mSettingsFilename.exists()) { // 两者都存在的时候,说明上次更新packages.xml时发生了异常 Slog.w(PackageManagerService.TAG, "Cleaning up settings file " + mSettingsFilename); mSettingsFilename.delete(); } } catch (java.io.IOException e) { // We'll try for the normal settings file. } } mPendingPackages.clear(); mPastSignatures.clear(); mKeySetRefs.clear(); mInstallerPackages.clear(); try { if (str == null) { if (!mSettingsFilename.exists()) { mReadMessages.append("No settings file found\n"); PackageManagerService.reportSettingsProblem(Log.INFO, "No settings file; creating initial state"); // It's enough to just touch version details to create them // with default values findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent(); findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent(); return false; } str = new FileInputStream(mSettingsFilename); } XmlPullParser parser = Xml.newPullParser(); parser.setInput(str, StandardCharsets.UTF_8.name()); int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { ; } 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); } 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); } else if (tagName.equals("preferred-packages")) { // 不再使用了,所以不做任何操作 } 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")) { // 注意这里,updated-package记录的package视为disabled readDisabledSysPackageLPw(parser); } 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("restored-ivi")) { readRestoredIntentFilterVerifications(parser); } 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 = XmlUtils.readIntAttribute(parser, "internal", 0); external.sdkVersion = XmlUtils.readIntAttribute(parser, "external", 0); 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 = XmlUtils.readIntAttribute(parser, "internal", 0); external.databaseVersion = XmlUtils.readIntAttribute(parser, "external", 0); } else if (tagName.equals("verifier")) { final String deviceIdentity = parser.getAttributeValue(null, "device"); try { mVerifierDeviceIdentity = VerifierDeviceIdentity.parse(deviceIdentity); } catch (IllegalArgumentException e) { Slog.w(PackageManagerService.TAG, "Discard invalid verifier device id: " + e.getMessage()); } } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) { final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT); mReadExternalStorageEnforced = "1".equals(enforcement) ? Boolean.TRUE : Boolean.FALSE; } else if (tagName.equals("keyset-settings")) { mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs); } else if (TAG_VERSION.equals(tagName)) { final String volumeUuid = XmlUtils.readStringAttribute(parser, ATTR_VOLUME_UUID); final VersionInfo ver = findOrCreateVersion(volumeUuid); ver.sdkVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION); ver.databaseVersion = XmlUtils.readIntAttribute(parser, ATTR_DATABASE_VERSION); ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT); } else { Slog.w(PackageManagerService.TAG, "Unknown element under : " + parser.getName()); XmlUtils.skipCurrentTag(parser); } } str.close(); } catch (XmlPullParserException e) { ... } catch (java.io.IOException e) { ... } ... return true; }3、Packages.xml的作用

在上篇文章中我们可以看到,packages.xml文件最终被解析和保存到了Settings的mPackages属性里了。来看一下PMS的构造方法里,它都发挥了什么作用吧

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) { ... mSettings = injector.getSettings(); ... t.traceBegin("addSharedUsers"); // 创建一些列系统shared user id 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); ... // CHECKSTYLE:OFF IndentationCheck synchronized (mInstallLock) { // writer synchronized (mLock) { ... // 读取packages.xml或packages-backup.xml,两者的格式一样,上次更新packages.xml出现异常的时候才会出现packages-backup.xml t.traceBegin("read user settings"); mFirstBoot = !mSettings.readLPw(mInjector.getUserManagerInternal().getUsers(false)); t.traceEnd(); // 清除代码路径不存在的package final int packageSettingCount = mSettings.mPackages.size(); for (int i = packageSettingCount - 1; i >= 0; i--) { PackageSetting ps = mSettings.mPackages.valueAt(i); if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists()) && mSettings.getDisabledSystemPkgLPr(ps.name) != null) { mSettings.mPackages.removeAt(i); mSettings.enableSystemPackageLPw(ps.name); } } if (!mOnlyCore && mFirstBoot) { requestCopyPreoptedFiles(); } ... // Save the names of pre-existing packages prior to scanning, so we can determine // which system packages are completely new due to an upgrade. // 在扫描之前保存预先存在的App的名称,以便确定哪些系统App由于升级完全新加的 if (isDeviceUpgrading()) { mExistingPackages = new ArraySet(mSettings.mPackages.size()); for (PackageSetting ps : mSettings.mPackages.values()) { mExistingPackages.add(ps.name); } } // 扫描系统App,这里代码省略 ... // Prune any system packages that no longer exist. final List possiblyDeletedUpdatedSystemApps = new ArrayList(); // Stub packages must either be replaced with full versions in the /data // partition or be disabled. final List stubSystemApps = new ArrayList(); if (!mOnlyCore) { ... final Iterator psit = mSettings.mPackages.values().iterator(); while (psit.hasNext()) { PackageSetting ps = psit.next(); // 非系统App跳过 if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) { continue; } final AndroidPackage scannedPkg = mPackages.get(ps.name); if (scannedPkg != null) { // packages.xml和即时扫描的结果都存在这个package // 如果系统App扫描到了,而且是disabled状态,也就是被记录在updated-package标签里,把这个记录删除,以期使用用户安装的版本 // 后面如果没有找到用户安装的版本,会恢复系统自带的版本 if (mSettings.isDisabledSystemPackageLPr(ps.name)) { logCriticalInfo(Log.WARN, "Expecting better updated system app for " + ps.name + "; removing system app. Last known" + " codePath=" + ps.codePathString + ", versionCode=" + ps.versionCode + "; scanned versionCode=" + scannedPkg.getLongVersionCode()); removePackageLI(scannedPkg, true); mExpectingBetter.put(ps.name, ps.codePath); } continue; } // packages.xml中存在的package如果没有被扫描到执行接下来的代码 if (!mSettings.isDisabledSystemPackageLPr(ps.name)) { // 不是disabled状态说明用户没有手动更新过,直接删除 psit.remove(); logCriticalInfo(Log.WARN, "System package " + ps.name + " no longer exists; it's data will be wiped"); // Assume package is truly gone and wipe residual permissions. mPermissionManager.updatePermissions(ps.name, null); // 真正删除代码和数据的操作会在后面执行 } else { // 在disabled list里,判断代码路径是不是还存在,存在的话可能是升级的时候改了包名,不存在则可能删除了 final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name); if (disabledPs.codePath == null || !disabledPs.codePath.exists() || disabledPs.pkg == null) { possiblyDeletedUpdatedSystemApps.add(ps.name); } else { // 加到mExpectingBetter,以便后续扫描到对应的升级版本的时候继续保持系统版本disabled,而使用用户版本,没有扫描到则再处理是删除还是保留 mExpectingBetter.put(disabledPs.name, disabledPs.codePath); } } } } final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get(); // 移除那些没有package关联的shared user id mSettings.pruneSharedUsersLPw(); ... // 扫描用户安装的App if (!mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0, packageParser, executorService); } packageParser.close(); List unfinishedTasks = executorService.shutdownNow(); if (!unfinishedTasks.isEmpty()) { throw new IllegalStateException("Not all tasks finished before calling close: " + unfinishedTasks); } if (!mOnlyCore) { // Remove disable package settings for updated system apps that were // removed via an OTA. If the update is no longer present, remove the // app completely. Otherwise, revoke their system privileges. // 系统升级中移除了App,如果App还存在于用户区(用户手动安装过新版本),剥夺App的系统级权限,否则完全删除 for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) { final String packageName = possiblyDeletedUpdatedSystemApps.get(i); final AndroidPackage pkg = mPackages.get(packageName); final String msg; // remove from the disabled system list; do this first so any future // scans of this package are performed without this state mSettings.removeDisabledSystemPackageLPw(packageName); if (pkg == null) { // 这里仍然没找到扫描结果,直接删除 msg = "Updated system package " + packageName + " no longer exists; removing its data"; // 真正删除代码和数据的操作会在后面执行 } else { // 扫描到了,剥夺系统级权限 msg = "Updated system package " + packageName + " no longer exists; rescanning package on data"; // NOTE: We don't do anything special if a stub is removed from the // system image. But, if we were [like removing the uncompressed // version from the /data partition], this is where it'd be done. // remove the package from the system and re-scan it without any // special privileges // 先删除,后重新扫描 removePackageLI(pkg, true); try { final File codePath = new File(pkg.getCodePath()); // 重新扫描 scanPackageTracedLI(codePath, 0, scanFlags, 0, null); } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse updated, ex-system package: " + e.getMessage()); } } // 最终确认结果 final PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null && mPackages.get(packageName) == null) { removePackageDataLIF(ps, null, null, 0, false); } logCriticalInfo(Log.WARN, msg); } /* * Make sure all system apps that we expected to appear on * the userdata partition actually showed up. If they never * appeared, crawl back and revive the system version. */ // 确保应该在用户区出现的系统App存在,不存在则使用系统区的版本 for (int i = 0; i < mExpectingBetter.size(); i++) { final String packageName = mExpectingBetter.keyAt(i); if (!mPackages.containsKey(packageName)) { final File scanFile = mExpectingBetter.valueAt(i); logCriticalInfo(Log.WARN, "Expected better " + packageName + " but never showed up; reverting to system"); @ParseFlags int reparseFlags = 0; @ScanFlags int rescanFlags = 0; for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) { final ScanPartition partition = mDirsToScanAsSystem.get(i1); if (partition.containsPrivApp(scanFile)) { reparseFlags = systemParseFlags; rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag; break; } if (partition.containsApp(scanFile)) { reparseFlags = systemParseFlags; rescanFlags = systemScanFlags | partition.scanFlag; break; } } if (rescanFlags == 0) { Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile); continue; } mSettings.enableSystemPackageLPw(packageName); try { scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null); } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse original system package: " + e.getMessage()); } } } ... } mExpectingBetter.clear(); ... 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. final List changedAbiCodePath = applyAdjustedAbiToSharedUser(setting, null /*scannedPackage*/, mInjector.getAbiHelper().getAdjustedAbiForSharedUser( setting.packages, null /*scannedPackage*/)); if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) { for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) { final String codePathString = changedAbiCodePath.get(i); try { mInstaller.rmdex(codePathString, getDexCodeInstructionSet(getPreferredInstructionSet())); } catch (InstallerException ignored) { } } } // Adjust seInfo to ensure apps which share a sharedUserId are placed in the same // SELinux domain. setting.fixSeInfoLocked(); setting.updateProcesses(); } // Now that we know all the packages we are keeping, // read and update their last usage times. mPackageUsage.read(mSettings.mPackages); ... t.traceBegin("write settings"); mSettings.writeLPr(); ... mSettings.setPermissionControllerVersion( getPackageInfo(mRequiredPermissionControllerPackage, 0, UserHandle.USER_SYSTEM).getLongVersionCode()); ... } // synchronized (mLock) } // synchronized (mInstallLock) ... }

这里删除了非常多的代码,只列出了关键性的。可以看到packages.xml的主要作用存储上一次启动时扫描和更新的结果,和本次启动扫描的结果进行比较,判断哪些该更新,哪些该删除。这就是它的主要作用。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3