From 8a6daa61035fd9c0d61e098ce40b7a52f8297b25 Mon Sep 17 00:00:00 2001 From: Winson Date: Mon, 27 Jul 2020 15:20:23 -0700 Subject: [PATCH 1/2] Refactor PackageSetting codePath and remove resourcePath There was a bug that caused codePath/resourcePath and their codePathString/resourcePathString equivalents to become mismatched in Settings#createNewSetting. To resolve this and prevent future issues, this moves codePath to a private field and exposes a setter which assigns both the File and cached String representation at once. The deprecated and effectively unused resourcePath variants were removed from the server side PackageSettingBase. The ApplicationInfo app side variable was kept as-is, since it's publicly mutable through @UnsupportedAppUsage and could break compatibility if it was removed. Test: atest android.content.pm.PackageManagerTests Test: atest com.android.server.pm.PackageManagerSettingsTests Test: atest com.android.server.pm.ScanTests Change-Id: I815775003bc5fcc5be6d61a24e30d8076b1c024a --- .../server/pm/PackageInstallerSession.java | 2 +- .../server/pm/PackageManagerService.java | 130 +++++++----------- .../com/android/server/pm/PackageSetting.java | 4 +- .../android/server/pm/PackageSettingBase.java | 37 ++--- .../java/com/android/server/pm/Settings.java | 85 ++++-------- ...geManagerComponentLabelIconOverrideTest.kt | 3 +- .../com/android/server/pm/AppsFilterTest.java | 2 - .../server/pm/KeySetManagerServiceTest.java | 3 +- .../server/pm/PackageManagerServiceTest.java | 3 +- .../pm/PackageManagerSettingsTests.java | 40 ++---- .../android/server/pm/PackageParserTest.java | 3 +- .../server/pm/PackageSettingBuilder.java | 14 +- .../server/pm/PackageSignaturesTest.java | 6 +- .../src/com/android/server/pm/ScanTests.java | 6 +- 14 files changed, 124 insertions(+), 214 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 7765f18300fed..6e9a02c6c43c1 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -2091,7 +2091,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (ps == null) { return 0; } - final File apkDirOrPath = ps.codePath; + final File apkDirOrPath = ps.getCodePath(); if (apkDirOrPath == null) { return 0; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index a726c8d26b98d..00ad661e39da0 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3010,7 +3010,7 @@ public class PackageManagerService extends IPackageManager.Stub 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()) + if (!isExternal(ps) && (ps.getCodePath() == null || !ps.getCodePath().exists()) && mSettings.getDisabledSystemPkgLPr(ps.name) != null) { mSettings.mPackages.removeAt(i); mSettings.enableSystemPackageLPw(ps.name); @@ -3175,11 +3175,11 @@ public class PackageManagerService extends IPackageManager.Stub logCriticalInfo(Log.WARN, "Expecting better updated system app for " + ps.name + "; removing system app. Last known" - + " codePath=" + ps.codePathString + + " codePath=" + ps.getCodePathString() + ", versionCode=" + ps.versionCode + "; scanned versionCode=" + scannedPkg.getLongVersionCode()); removePackageLI(scannedPkg, true); - mExpectingBetter.put(ps.name, ps.codePath); + mExpectingBetter.put(ps.name, ps.getCodePath()); } continue; @@ -3202,14 +3202,14 @@ public class PackageManagerService extends IPackageManager.Stub // code path, but, changes the package name. final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name); - if (disabledPs.codePath == null || !disabledPs.codePath.exists() + if (disabledPs.getCodePath() == null || !disabledPs.getCodePath().exists() || disabledPs.pkg == null) { possiblyDeletedUpdatedSystemApps.add(ps.name); } else { // We're expecting that the system app should remain disabled, but add // it to expecting better to recover in case the data version cannot // be scanned. - mExpectingBetter.put(disabledPs.name, disabledPs.codePath); + mExpectingBetter.put(disabledPs.name, disabledPs.getCodePath()); } } } @@ -9150,7 +9150,7 @@ public class PackageManagerService extends IPackageManager.Stub : getLastModifiedTime(parsedPackage); final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(parsedPackage); if (ps != null && !forceCollect - && ps.codePathString.equals(parsedPackage.getCodePath()) + && ps.getCodePathString().equals(parsedPackage.getCodePath()) && ps.timeStamp == lastModifiedTime && !isCompatSignatureUpdateNeeded(settingsVersionForPackage) && !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) { @@ -9383,8 +9383,8 @@ public class PackageManagerService extends IPackageManager.Stub } } - final boolean newPkgChangedPaths = - pkgAlreadyExists && !pkgSetting.codePathString.equals(parsedPackage.getCodePath()); + final boolean newPkgChangedPaths = pkgAlreadyExists + && !pkgSetting.getCodePathString().equals(parsedPackage.getCodePath()); final boolean newPkgVersionGreater = pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode; final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated @@ -9403,11 +9403,11 @@ public class PackageManagerService extends IPackageManager.Stub "System package updated;" + " name: " + pkgSetting.name + "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode() - + "; " + pkgSetting.codePathString + " --> " + parsedPackage.getCodePath()); + + "; " + pkgSetting.getCodePathString() + + " --> " + parsedPackage.getCodePath()); final InstallArgs args = createInstallArgsForExisting( - pkgSetting.codePathString, - pkgSetting.resourcePathString, getAppDexInstructionSets( + pkgSetting.getCodePathString(), getAppDexInstructionSets( pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString)); args.cleanUpResourcesLI(); synchronized (mLock) { @@ -9482,11 +9482,10 @@ public class PackageManagerService extends IPackageManager.Stub + " name: " + pkgSetting.name + "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode() - + "; " + pkgSetting.codePathString + " --> " + + "; " + pkgSetting.getCodePathString() + " --> " + parsedPackage.getCodePath()); InstallArgs args = createInstallArgsForExisting( - pkgSetting.codePathString, - pkgSetting.resourcePathString, getAppDexInstructionSets( + pkgSetting.getCodePathString(), getAppDexInstructionSets( pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString)); synchronized (mInstallLock) { args.cleanUpResourcesLI(); @@ -9499,7 +9498,7 @@ public class PackageManagerService extends IPackageManager.Stub logCriticalInfo(Log.INFO, "System package disabled;" + " name: " + pkgSetting.name - + "; old: " + pkgSetting.codePathString + " @ " + + "; old: " + pkgSetting.getCodePathString() + " @ " + pkgSetting.versionCode + "; new: " + parsedPackage.getCodePath() + " @ " + parsedPackage.getCodePath()); @@ -11325,7 +11324,7 @@ public class PackageManagerService extends IPackageManager.Stub if (changedAbiCodePath == null) { changedAbiCodePath = new ArrayList<>(); } - changedAbiCodePath.add(ps.codePathString); + changedAbiCodePath.add(ps.getCodePathString()); } } } @@ -11421,7 +11420,6 @@ public class PackageManagerService extends IPackageManager.Stub // Initialize package source and resource directories final File destCodeFile = new File(parsedPackage.getCodePath()); - final File destResourceFile = new File(parsedPackage.getCodePath()); // We keep references to the derived CPU Abis from settings in oder to reuse // them in the case where we're not upgrading or booting for the first time. @@ -11479,7 +11477,7 @@ public class PackageManagerService extends IPackageManager.Stub // REMOVE SharedUserSetting from method; update in a separate call pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(), originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting, - destCodeFile, destResourceFile, parsedPackage.getNativeLibraryRootDir(), + destCodeFile, parsedPackage.getNativeLibraryRootDir(), AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage), AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage), parsedPackage.getVersionCode(), pkgFlags, pkgPrivateFlags, user, @@ -11497,7 +11495,7 @@ public class PackageManagerService extends IPackageManager.Stub // secondaryCpuAbi are not known at this point so we always update them // to null here, only to reset them at a later point. Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting, - destCodeFile, destResourceFile, parsedPackage.getNativeLibraryDir(), + destCodeFile, parsedPackage.getNativeLibraryDir(), AndroidPackageUtils.getPrimaryCpuAbi(parsedPackage, pkgSetting), AndroidPackageUtils.getSecondaryCpuAbi(parsedPackage, pkgSetting), PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting), @@ -12066,15 +12064,13 @@ public class PackageManagerService extends IPackageManager.Stub if (known != null) { if (DEBUG_PACKAGE_SCANNING) { Log.d(TAG, "Examining " + pkg.getCodePath() - + " and requiring known paths " + known.codePathString - + " & " + known.resourcePathString); + + " and requiring known path " + known.getCodePathString()); } - if (!pkg.getCodePath().equals(known.codePathString) - || !pkg.getCodePath().equals(known.resourcePathString)) { + if (!pkg.getCodePath().equals(known.getCodePathString())) { throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED, "Application package " + pkg.getPackageName() + " found at " + pkg.getCodePath() - + " but expected at " + known.codePathString + + " but expected at " + known.getCodePathString() + "; ignoring."); } } else { @@ -15586,9 +15582,8 @@ public class PackageManagerService extends IPackageManager.Stub * Create args that describe an existing installed package. Typically used * when cleaning up old installs, or used as a move source. */ - private InstallArgs createInstallArgsForExisting(String codePath, - String resourcePath, String[] instructionSets) { - return new FileInstallArgs(codePath, resourcePath, instructionSets); + private InstallArgs createInstallArgsForExisting(String codePath, String[] instructionSets) { + return new FileInstallArgs(codePath, instructionSets); } static abstract class InstallArgs { @@ -15669,10 +15664,8 @@ public class PackageManagerService extends IPackageManager.Stub abstract boolean doRename(int status, ParsedPackage parsedPackage); abstract int doPostInstall(int status, int uid); - /** @see PackageSettingBase#codePathString */ + /** @see PackageSettingBase#getCodePath() */ abstract String getCodePath(); - /** @see PackageSettingBase#resourcePathString */ - abstract String getResourcePath(); // Need installer lock especially for dex file removal. abstract void cleanUpResourcesLI(); @@ -15743,14 +15736,13 @@ public class PackageManagerService extends IPackageManager.Stub } /** Existing install */ - FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) { + FileInstallArgs(String codePath, String[] instructionSets) { super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY, null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0, PackageParser.SigningDetails.UNKNOWN, PackageManager.INSTALL_REASON_UNKNOWN, false, DataLoaderType.NONE); this.codeFile = (codePath != null) ? new File(codePath) : null; - this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null; } int copyApk() { @@ -15766,7 +15758,6 @@ public class PackageManagerService extends IPackageManager.Stub if (origin.staged) { if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy"); codeFile = origin.file; - resourceFile = origin.file; return PackageManager.INSTALL_SUCCEEDED; } @@ -15775,7 +15766,6 @@ public class PackageManagerService extends IPackageManager.Stub final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral); codeFile = tempDir; - resourceFile = tempDir; } catch (IOException e) { Slog.w(TAG, "Failed to create copy file: " + e); return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; @@ -15846,7 +15836,6 @@ public class PackageManagerService extends IPackageManager.Stub // Reflect the rename internally codeFile = afterCodeFile; - resourceFile = afterCodeFile; // Reflect the rename in scanned details try { @@ -15875,11 +15864,6 @@ public class PackageManagerService extends IPackageManager.Stub return (codeFile != null) ? codeFile.getAbsolutePath() : null; } - @Override - String getResourcePath() { - return (resourceFile != null) ? resourceFile.getAbsolutePath() : null; - } - private boolean cleanUp() { if (codeFile == null || !codeFile.exists()) { return false; @@ -15892,10 +15876,6 @@ public class PackageManagerService extends IPackageManager.Stub removeCodePathLI(codeFile); - if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) { - resourceFile.delete(); - } - return true; } @@ -15927,7 +15907,6 @@ public class PackageManagerService extends IPackageManager.Stub */ class MoveInstallArgs extends InstallArgs { private File codeFile; - private File resourceFile; /** New install */ MoveInstallArgs(InstallParams params) { @@ -15950,7 +15929,6 @@ public class PackageManagerService extends IPackageManager.Stub final String toPathName = new File(move.fromCodePath).getName(); codeFile = new File(Environment.getDataAppDirectory(move.toUuid), toPathName); - resourceFile = codeFile; if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + codeFile); return PackageManager.INSTALL_SUCCEEDED; @@ -15987,11 +15965,6 @@ public class PackageManagerService extends IPackageManager.Stub return (codeFile != null) ? codeFile.getAbsolutePath() : null; } - @Override - String getResourcePath() { - return (resourceFile != null) ? resourceFile.getAbsolutePath() : null; - } - private boolean cleanUp(String volumeUuid) { final String toPathName = new File(move.fromCodePath).getName(); final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid), @@ -16776,7 +16749,6 @@ public class PackageManagerService extends IPackageManager.Stub // which means we are replacing another update that is already // installed. We need to make sure to delete the older one's .apk. res.removedInfo.args = createInstallArgsForExisting( - oldPackage.getCodePath(), oldPackage.getCodePath(), getAppDexInstructionSets( AndroidPackageUtils.getPrimaryCpuAbi(oldPackage, @@ -18998,7 +18970,7 @@ public class PackageManagerService extends IPackageManager.Stub // Install the system package if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs); try { - installPackageFromSystemLIF(disabledPs.codePathString, allUserHandles, + installPackageFromSystemLIF(disabledPs.getCodePathString(), allUserHandles, outInfo == null ? null : outInfo.origUsers, deletedPs.getPermissionsState(), writeSettings); } catch (PackageManagerException e) { @@ -19123,7 +19095,7 @@ public class PackageManagerService extends IPackageManager.Stub // Delete application code and resources only for parent packages if (deleteCodeAndResources && (outInfo != null)) { outInfo.args = createInstallArgsForExisting( - ps.codePathString, ps.resourcePathString, getAppDexInstructionSets( + ps.getCodePathString(), getAppDexInstructionSets( ps.primaryCpuAbiString, ps.secondaryCpuAbiString)); if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args); } @@ -19660,7 +19632,7 @@ public class PackageManagerService extends IPackageManager.Stub final String[] packageNames = { packageName }; final long[] ceDataInodes = { ps.getCeDataInode(userId) }; - final String[] codePaths = { ps.codePathString }; + final String[] codePaths = { ps.getCodePathString() }; try { mInstaller.getAppSize(ps.volumeUuid, packageNames, userId, 0, @@ -22582,11 +22554,11 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mInstallLock) { final AndroidPackage pkg; try { - pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0, null); + pkg = scanPackageTracedLI(ps.getCodePath(), parseFlags, SCAN_INITIAL, 0, null); loaded.add(pkg); } catch (PackageManagerException e) { - Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage()); + Slog.w(TAG, "Failed to scan " + ps.getCodePath() + ": " + e.getMessage()); } if (!Build.FINGERPRINT.equals(ver.fingerprint)) { @@ -22657,33 +22629,33 @@ public class PackageManagerService extends IPackageManager.Stub final ArrayList unloaded = new ArrayList<>(); synchronized (mInstallLock) { - synchronized (mLock) { - final List packages = mSettings.getVolumePackagesLPr(volumeUuid); - for (PackageSetting ps : packages) { - if (ps.pkg == null) continue; + synchronized (mLock) { + final List packages = mSettings.getVolumePackagesLPr(volumeUuid); + for (PackageSetting ps : packages) { + if (ps.pkg == null) continue; - final AndroidPackage pkg = ps.pkg; - final int deleteFlags = PackageManager.DELETE_KEEP_DATA; - final PackageRemovedInfo outInfo = new PackageRemovedInfo(this); + final AndroidPackage pkg = ps.pkg; + final int deleteFlags = PackageManager.DELETE_KEEP_DATA; + final PackageRemovedInfo outInfo = new PackageRemovedInfo(this); - try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags, - "unloadPrivatePackagesInner")) { - if (deletePackageLIF(ps.name, null, false, null, deleteFlags, outInfo, - false, null)) { - unloaded.add(pkg); - } else { - Slog.w(TAG, "Failed to unload " + ps.codePath); + try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags, + "unloadPrivatePackagesInner")) { + if (deletePackageLIF(ps.name, null, false, null, deleteFlags, outInfo, + false, null)) { + unloaded.add(pkg); + } else { + Slog.w(TAG, "Failed to unload " + ps.getCodePath()); + } } + + // Try very hard to release any references to this package + // so we don't risk the system server being killed due to + // open FDs + AttributeCache.instance().removePackage(ps.name); } - // Try very hard to release any references to this package - // so we don't risk the system server being killed due to - // open FDs - AttributeCache.instance().removePackage(ps.name); + mSettings.writeLPr(); } - - mSettings.writeLPr(); - } } if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded); @@ -22726,7 +22698,7 @@ public class PackageManagerService extends IPackageManager.Stub final int packageCount = mSettings.mPackages.size(); for (int i = 0; i < packageCount; i++) { final PackageSetting ps = mSettings.mPackages.valueAt(i); - codePaths.add(ps.codePath.getAbsolutePath()); + codePaths.add(ps.getCodePath().getAbsolutePath()); } return codePaths; } diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 432d7f335ebc3..a3a727367c56f 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -71,13 +71,13 @@ public class PackageSetting extends PackageSettingBase { private PackageStateUnserialized pkgState = new PackageStateUnserialized(); @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public PackageSetting(String name, String realName, File codePath, File resourcePath, + public PackageSetting(String name, String realName, @NonNull File codePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, long pVersionCode, int pkgFlags, int privateFlags, int sharedUserId, String[] usesStaticLibraries, long[] usesStaticLibrariesVersions, Map> mimeGroups) { - super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString, + super(name, realName, codePath, legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, pVersionCode, pkgFlags, privateFlags, usesStaticLibraries, usesStaticLibrariesVersions); diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 834303cc14c62..6010344b8c65d 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -64,10 +64,8 @@ public abstract class PackageSettingBase extends SettingBase { * this is path to single base APK file; for cluster packages this is * path to the cluster directory. */ - File codePath; - String codePathString; - File resourcePath; - String resourcePathString; + private File mCodePath; + private String mCodePathString; String[] usesStaticLibraries; long[] usesStaticLibrariesVersions; @@ -138,7 +136,7 @@ public abstract class PackageSettingBase extends SettingBase { boolean forceQueryableOverride; - PackageSettingBase(String name, String realName, File codePath, File resourcePath, + PackageSettingBase(String name, String realName, @NonNull File codePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, long pVersionCode, int pkgFlags, int pkgPrivateFlags, @@ -148,10 +146,7 @@ public abstract class PackageSettingBase extends SettingBase { this.realName = realName; this.usesStaticLibraries = usesStaticLibraries; this.usesStaticLibrariesVersions = usesStaticLibrariesVersions; - this.codePath = codePath; - this.codePathString = codePath.toString(); - this.resourcePath = resourcePath; - this.resourcePathString = resourcePath.toString(); + setCodePath(codePath); this.legacyNativeLibraryPathString = legacyNativeLibraryPathString; this.primaryCpuAbiString = primaryCpuAbiString; this.secondaryCpuAbiString = secondaryCpuAbiString; @@ -235,8 +230,7 @@ public abstract class PackageSettingBase extends SettingBase { } private void doCopy(PackageSettingBase orig) { - codePath = orig.codePath; - codePathString = orig.codePathString; + setCodePath(orig.getCodePath()); cpuAbiOverrideString = orig.cpuAbiOverrideString; firstInstallTime = orig.firstInstallTime; installPermissionsFixed = orig.installPermissionsFixed; @@ -246,8 +240,6 @@ public abstract class PackageSettingBase extends SettingBase { legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString; // Intentionally skip mOldCodePaths; it's not relevant for copies primaryCpuAbiString = orig.primaryCpuAbiString; - resourcePath = orig.resourcePath; - resourcePathString = orig.resourcePathString; secondaryCpuAbiString = orig.secondaryCpuAbiString; signatures = orig.signatures; timeStamp = orig.timeStamp; @@ -705,6 +697,20 @@ public abstract class PackageSettingBase extends SettingBase { return userState.harmfulAppWarning; } + PackageSettingBase setCodePath(@NonNull File codePath) { + this.mCodePath = codePath; + this.mCodePathString = codePath.toString(); + return this; + } + + File getCodePath() { + return mCodePath; + } + + String getCodePathString() { + return mCodePathString; + } + /** * @see PackageUserState#overrideLabelAndIcon(ComponentName, String, Integer) * @@ -727,10 +733,7 @@ public abstract class PackageSettingBase extends SettingBase { protected PackageSettingBase updateFrom(PackageSettingBase other) { super.copyFrom(other); - this.codePath = other.codePath; - this.codePathString = other.codePathString; - this.resourcePath = other.resourcePath; - this.resourcePathString = other.resourcePathString; + setCodePath(other.getCodePath()); this.usesStaticLibraries = other.usesStaticLibraries; this.usesStaticLibrariesVersions = other.usesStaticLibrariesVersions; this.legacyNativeLibraryPathString = other.legacyNativeLibraryPathString; diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 1805713387ae0..0061480c97f1b 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -538,7 +538,7 @@ public final class Settings { return null; } p.getPkgState().setUpdatedSystemApp(false); - PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath, + PackageSetting ret = addPackageLPw(name, p.realName, p.getCodePath(), p.legacyNativeLibraryPathString, p.primaryCpuAbiString, p.secondaryCpuAbiString, p.cpuAbiOverrideString, p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags, @@ -558,7 +558,7 @@ public final class Settings { mDisabledSysPackages.remove(name); } - PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath, + PackageSetting addPackageLPw(String name, String realName, File codePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, long vc, int pkgFlags, int pkgPrivateFlags, String[] usesStaticLibraries, @@ -572,10 +572,9 @@ public final class Settings { "Adding duplicate package, keeping first: " + name); return null; } - p = new PackageSetting(name, realName, codePath, resourcePath, - legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, - cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags, - 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames, + p = new PackageSetting(name, realName, codePath, legacyNativeLibraryPathString, + primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, vc, pkgFlags, + pkgPrivateFlags, 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames, mimeGroups); p.appId = uid; if (registerExistingAppIdLPw(uid, p, name)) { @@ -635,7 +634,7 @@ public final class Settings { */ static @NonNull PackageSetting createNewSetting(String pkgName, PackageSetting originalPkg, PackageSetting disabledPkg, String realPkgName, SharedUserSetting sharedUser, - File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi, + File codePath, String legacyNativeLibraryPath, String primaryCpuAbi, String secondaryCpuAbi, long versionCode, int pkgFlags, int pkgPrivateFlags, UserHandle installUser, boolean allowInstall, boolean instantApp, boolean virtualPreload, UserManagerService userManager, @@ -646,12 +645,11 @@ public final class Settings { if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package " + pkgName + " is adopting original package " + originalPkg.name); pkgSetting = new PackageSetting(originalPkg, pkgName /*realPkgName*/); - pkgSetting.codePath = codePath; + pkgSetting.setCodePath(codePath); pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath; pkgSetting.pkgFlags = pkgFlags; pkgSetting.pkgPrivateFlags = pkgPrivateFlags; pkgSetting.primaryCpuAbiString = primaryCpuAbi; - pkgSetting.resourcePath = resourcePath; pkgSetting.secondaryCpuAbiString = secondaryCpuAbi; // NOTE: Create a deeper copy of the package signatures so we don't // overwrite the signatures in the original package setting. @@ -662,7 +660,7 @@ public final class Settings { // Update new package state. pkgSetting.setTimeStamp(codePath.lastModified()); } else { - pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath, + pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi, null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags, 0 /*sharedUserId*/, usesStaticLibraries, @@ -756,10 +754,9 @@ public final class Settings { */ static void updatePackageSetting(@NonNull PackageSetting pkgSetting, @Nullable PackageSetting disabledPkg, @Nullable SharedUserSetting sharedUser, - @NonNull File codePath, File resourcePath, - @Nullable String legacyNativeLibraryPath, @Nullable String primaryCpuAbi, - @Nullable String secondaryCpuAbi, int pkgFlags, int pkgPrivateFlags, - @NonNull UserManagerService userManager, + @NonNull File codePath, @Nullable String legacyNativeLibraryPath, + @Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi, int pkgFlags, + int pkgPrivateFlags, @NonNull UserManagerService userManager, @Nullable String[] usesStaticLibraries, @Nullable long[] usesStaticLibrariesVersions, @Nullable Set mimeGroupNames) throws PackageManagerException { @@ -773,12 +770,12 @@ public final class Settings { "Updating application package " + pkgName + " failed"); } - if (!pkgSetting.codePath.equals(codePath)) { + if (!pkgSetting.getCodePath().equals(codePath)) { final boolean isSystem = pkgSetting.isSystem(); Slog.i(PackageManagerService.TAG, "Update" + (isSystem ? " system" : "") + " package " + pkgName - + " code path from " + pkgSetting.codePathString + + " code path from " + pkgSetting.getCodePathString() + " to " + codePath.toString() + "; Retain data and using new"); if (!isSystem) { @@ -800,19 +797,7 @@ public final class Settings { // internal to external storage or vice versa. pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath; } - pkgSetting.codePath = codePath; - pkgSetting.codePathString = codePath.toString(); - } - if (!pkgSetting.resourcePath.equals(resourcePath)) { - final boolean isSystem = pkgSetting.isSystem(); - Slog.i(PackageManagerService.TAG, - "Update" + (isSystem ? " system" : "") - + " package " + pkgName - + " resource path from " + pkgSetting.resourcePathString - + " to " + resourcePath.toString() - + "; Retain data and using new"); - pkgSetting.resourcePath = resourcePath; - pkgSetting.resourcePathString = resourcePath.toString(); + pkgSetting.setCodePath(codePath); } // If what we are scanning is a system (and possibly privileged) package, // then make it so, regardless of whether it was previously installed only @@ -2812,14 +2797,11 @@ public final class Settings { if (pkg.realName != null) { serializer.attribute(null, "realName", pkg.realName); } - serializer.attribute(null, "codePath", pkg.codePathString); + serializer.attribute(null, "codePath", pkg.getCodePathString()); serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp)); serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime)); serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime)); serializer.attribute(null, "version", String.valueOf(pkg.versionCode)); - if (!pkg.resourcePathString.equals(pkg.codePathString)) { - serializer.attribute(null, "resourcePath", pkg.resourcePathString); - } if (pkg.legacyNativeLibraryPathString != null) { serializer.attribute(null, "nativeLibraryPath", pkg.legacyNativeLibraryPathString); } @@ -2857,10 +2839,7 @@ public final class Settings { if (pkg.realName != null) { serializer.attribute(null, "realName", pkg.realName); } - serializer.attribute(null, "codePath", pkg.codePathString); - if (!pkg.resourcePathString.equals(pkg.codePathString)) { - serializer.attribute(null, "resourcePath", pkg.resourcePathString); - } + serializer.attribute(null, "codePath", pkg.getCodePathString()); if (pkg.legacyNativeLibraryPathString != null) { serializer.attribute(null, "nativeLibraryPath", pkg.legacyNativeLibraryPathString); @@ -3559,13 +3538,10 @@ public final class Settings { String name = parser.getAttributeValue(null, ATTR_NAME); String realName = parser.getAttributeValue(null, "realName"); String codePathStr = parser.getAttributeValue(null, "codePath"); - String resourcePathStr = parser.getAttributeValue(null, "resourcePath"); String legacyCpuAbiStr = parser.getAttributeValue(null, "requiredCpuAbi"); String legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); - String parentPackageName = parser.getAttributeValue(null, "parentPackageName"); - String primaryCpuAbiStr = parser.getAttributeValue(null, "primaryCpuAbi"); String secondaryCpuAbiStr = parser.getAttributeValue(null, "secondaryCpuAbi"); String cpuAbiOverrideStr = parser.getAttributeValue(null, "cpuAbiOverride"); @@ -3574,9 +3550,6 @@ public final class Settings { primaryCpuAbiStr = legacyCpuAbiStr; } - if (resourcePathStr == null) { - resourcePathStr = codePathStr; - } String version = parser.getAttributeValue(null, "version"); long versionCode = 0; if (version != null) { @@ -3593,9 +3566,8 @@ public final class Settings { pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; } PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr), - new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr, - secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags, - 0 /*sharedUserId*/, null, null, null); + legacyNativeLibraryPathStr, primaryCpuAbiStr, secondaryCpuAbiStr, cpuAbiOverrideStr, + versionCode, pkgFlags, pkgPrivateFlags, 0 /*sharedUserId*/, null, null, null); String timeStampStr = parser.getAttributeValue(null, "ft"); if (timeStampStr != null) { try { @@ -3666,7 +3638,6 @@ public final class Settings { String idStr = null; String sharedIdStr = null; String codePathStr = null; - String resourcePathStr = null; String legacyCpuAbiString = null; String legacyNativeLibraryPathStr = null; String primaryCpuAbiString = null; @@ -3700,7 +3671,6 @@ public final class Settings { uidError = parser.getAttributeValue(null, "uidError"); sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); codePathStr = parser.getAttributeValue(null, "codePath"); - resourcePathStr = parser.getAttributeValue(null, "resourcePath"); legacyCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi"); @@ -3818,9 +3788,6 @@ public final class Settings { + " sharedUserId=" + sharedIdStr); final int userId = idStr != null ? Integer.parseInt(idStr) : 0; final int sharedUserId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; - if (resourcePathStr == null) { - resourcePathStr = codePathStr; - } if (realName != null) { realName = realName.intern(); } @@ -3834,10 +3801,10 @@ public final class Settings { + parser.getPositionDescription()); } else if (userId > 0) { packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr), - new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString, - secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags, - pkgPrivateFlags, null /*usesStaticLibraries*/, - null /*usesStaticLibraryVersions*/, null /*mimeGroups*/); + legacyNativeLibraryPathStr, primaryCpuAbiString, secondaryCpuAbiString, + cpuAbiOverrideString, userId, versionCode, pkgFlags, pkgPrivateFlags, + null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/, + null /*mimeGroups*/); if (PackageManagerService.DEBUG_SETTINGS) Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId=" + userId + " pkg=" + packageSetting); @@ -3852,8 +3819,8 @@ public final class Settings { } } else if (sharedIdStr != null) { if (sharedUserId > 0) { - packageSetting = new PackageSetting(name.intern(), realName, new File( - codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr, + packageSetting = new PackageSetting(name.intern(), realName, + new File(codePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, versionCode, pkgFlags, pkgPrivateFlags, sharedUserId, null /*usesStaticLibraries*/, @@ -4657,9 +4624,9 @@ public final class Settings { pw.print(prefix); pw.print(" sharedUser="); pw.println(ps.sharedUser); } pw.print(prefix); pw.print(" pkg="); pw.println(pkg); - pw.print(prefix); pw.print(" codePath="); pw.println(ps.codePathString); + pw.print(prefix); pw.print(" codePath="); pw.println(ps.getCodePathString()); if (permissionNames == null) { - pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.resourcePathString); + pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.getCodePathString()); pw.print(prefix); pw.print(" legacyNativeLibraryDir="); pw.println(ps.legacyNativeLibraryPathString); pw.print(prefix); pw.print(" primaryCpuAbi="); pw.println(ps.primaryCpuAbiString); diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt index ecdb30f5e84b6..09552082e4af2 100644 --- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt +++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt @@ -33,7 +33,6 @@ import com.android.server.pm.parsing.pkg.PackageImpl import com.android.server.pm.parsing.pkg.ParsedPackage import com.android.server.pm.permission.PermissionManagerServiceInternal import com.android.server.pm.test.override.PackageManagerComponentLabelIconOverrideTest.Companion.Params.AppType -import com.android.server.pm.test.override.R import com.android.server.testutils.TestHandler import com.android.server.testutils.mock import com.android.server.testutils.mockThrowOnUnmocked @@ -266,7 +265,7 @@ class PackageManagerComponentLabelIconOverrideTest { .hideAsFinal() private fun makePkgSetting(pkgName: String) = spy(PackageSetting(pkgName, null, File("/test"), - File("/test"), null, null, null, null, 0, 0, 0, 0, null, null, null)) { + null, null, null, null, 0, 0, 0, 0, null, null, null)) { this.pkgState.isUpdatedSystemApp = params.isUpdatedSystemApp } diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index f991dff2797f0..db56657e208cd 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -550,7 +550,6 @@ public class AppsFilterTest { .setAppId(DUMMY_TARGET_APPID) .setName("com.some.package") .setCodePath("/") - .setResourcePath("/") .setPVersionCode(1L) .build(); PackageSetting calling = simulateAddPackage(appsFilter, @@ -874,7 +873,6 @@ public class AppsFilterTest { .setAppId(appId) .setName(newPkg.getPackageName()) .setCodePath("/") - .setResourcePath("/") .setPVersionCode(1L); final PackageSetting setting = (action == null ? settingBuilder : action.withBuilder(settingBuilder)).build(); diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java index 164bd725dd66d..90edaef4294fc 100644 --- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java @@ -38,8 +38,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase { public PackageSetting generateFakePackageSetting(String name) { return new PackageSetting(name, name, new File(mContext.getCacheDir(), "fakeCodePath"), - new File(mContext.getCacheDir(), "fakeResPath"), "", "", "", - "", 1, 0, 0, 0 /*sharedUserId*/, null /*usesStaticLibraries*/, + "", "", "", "", 1, 0, 0, 0 /*sharedUserId*/, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/, null /*mimeGroups*/); } diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java index c4e25b53d5d56..80f145b16147c 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java @@ -86,8 +86,7 @@ public class PackageManagerServiceTest { // Create a real (non-null) PackageSetting and confirm that the removed // users are copied properly setting = new PackageSetting("name", "realName", new File("codePath"), - new File("resourcePath"), "legacyNativeLibraryPathString", - "primaryCpuAbiString", "secondaryCpuAbiString", + "legacyNativeLibraryPathString", "primaryCpuAbiString", "secondaryCpuAbiString", "cpuAbiOverrideString", 0, 0, 0, 0, null, null, null); pri.populateUsers(new int[] { diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index aa92ba49d190b..0bf06bb4dda7a 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -439,7 +439,6 @@ public class PackageManagerSettingsTests { PACKAGE_NAME, REAL_PACKAGE_NAME, INITIAL_CODE_PATH /*codePath*/, - INITIAL_CODE_PATH /*resourcePath*/, null /*legacyNativeLibraryPathString*/, "x86_64" /*primaryCpuAbiString*/, "x86" /*secondaryCpuAbiString*/, @@ -461,7 +460,6 @@ public class PackageManagerSettingsTests { PACKAGE_NAME /*pkgName*/, REAL_PACKAGE_NAME /*realPkgName*/, INITIAL_CODE_PATH /*codePath*/, - INITIAL_CODE_PATH /*resourcePath*/, null /*legacyNativeLibraryPathString*/, "x86_64" /*primaryCpuAbiString*/, "x86" /*secondaryCpuAbiString*/, @@ -477,7 +475,6 @@ public class PackageManagerSettingsTests { PACKAGE_NAME /*pkgName*/, REAL_PACKAGE_NAME /*realPkgName*/, UPDATED_CODE_PATH /*codePath*/, - UPDATED_CODE_PATH /*resourcePath*/, null /*legacyNativeLibraryPathString*/, null /*primaryCpuAbiString*/, null /*secondaryCpuAbiString*/, @@ -507,7 +504,6 @@ public class PackageManagerSettingsTests { null /*disabledPkg*/, null /*sharedUser*/, UPDATED_CODE_PATH /*codePath*/, - UPDATED_CODE_PATH /*resourcePath*/, null /*legacyNativeLibraryPath*/, "arm64-v8a" /*primaryCpuAbi*/, "armeabi" /*secondaryCpuAbi*/, @@ -541,7 +537,6 @@ public class PackageManagerSettingsTests { null /*disabledPkg*/, null /*sharedUser*/, UPDATED_CODE_PATH /*codePath*/, - UPDATED_CODE_PATH /*resourcePath*/, null /*legacyNativeLibraryPath*/, "arm64-v8a" /*primaryCpuAbi*/, "armeabi" /*secondaryCpuAbi*/, @@ -581,7 +576,6 @@ public class PackageManagerSettingsTests { null /*disabledPkg*/, testUserSetting01 /*sharedUser*/, UPDATED_CODE_PATH /*codePath*/, - null /*resourcePath*/, null /*legacyNativeLibraryPath*/, "arm64-v8a" /*primaryCpuAbi*/, "armeabi" /*secondaryCpuAbi*/, @@ -609,7 +603,6 @@ public class PackageManagerSettingsTests { null /*realPkgName*/, null /*sharedUser*/, UPDATED_CODE_PATH /*codePath*/, - UPDATED_CODE_PATH /*resourcePath*/, null /*legacyNativeLibraryPath*/, "arm64-v8a" /*primaryCpuAbi*/, "armeabi" /*secondaryCpuAbi*/, @@ -624,12 +617,11 @@ public class PackageManagerSettingsTests { null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/, null /*mimeGroups*/); - assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH)); + assertThat(testPkgSetting01.getCodePath(), is(UPDATED_CODE_PATH)); assertThat(testPkgSetting01.name, is(PACKAGE_NAME)); assertThat(testPkgSetting01.pkgFlags, is(ApplicationInfo.FLAG_SYSTEM)); assertThat(testPkgSetting01.pkgPrivateFlags, is(ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)); assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a")); - assertThat(testPkgSetting01.resourcePath, is(UPDATED_CODE_PATH)); assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi")); // signatures object must be different assertNotSame(testPkgSetting01.signatures, originalSignatures); @@ -649,7 +641,6 @@ public class PackageManagerSettingsTests { null /*realPkgName*/, null /*sharedUser*/, INITIAL_CODE_PATH /*codePath*/, - INITIAL_CODE_PATH /*resourcePath*/, null /*legacyNativeLibraryPath*/, "x86_64" /*primaryCpuAbiString*/, "x86" /*secondaryCpuAbiString*/, @@ -665,12 +656,11 @@ public class PackageManagerSettingsTests { null /*usesStaticLibrariesVersions*/, null /*mimeGroups*/); assertThat(testPkgSetting01.appId, is(0)); - assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH)); + assertThat(testPkgSetting01.getCodePath(), is(INITIAL_CODE_PATH)); assertThat(testPkgSetting01.name, is(PACKAGE_NAME)); assertThat(testPkgSetting01.pkgFlags, is(0)); assertThat(testPkgSetting01.pkgPrivateFlags, is(0)); assertThat(testPkgSetting01.primaryCpuAbiString, is("x86_64")); - assertThat(testPkgSetting01.resourcePath, is(INITIAL_CODE_PATH)); assertThat(testPkgSetting01.secondaryCpuAbiString, is("x86")); assertThat(testPkgSetting01.versionCode, is(INITIAL_VERSION_CODE)); // by default, the package is considered stopped @@ -695,7 +685,6 @@ public class PackageManagerSettingsTests { null /*realPkgName*/, testUserSetting01 /*sharedUser*/, INITIAL_CODE_PATH /*codePath*/, - INITIAL_CODE_PATH /*resourcePath*/, null /*legacyNativeLibraryPath*/, "x86_64" /*primaryCpuAbiString*/, "x86" /*secondaryCpuAbiString*/, @@ -711,12 +700,11 @@ public class PackageManagerSettingsTests { null /*usesStaticLibrariesVersions*/, null /*mimeGroups*/); assertThat(testPkgSetting01.appId, is(10064)); - assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH)); + assertThat(testPkgSetting01.getCodePath(), is(INITIAL_CODE_PATH)); assertThat(testPkgSetting01.name, is(PACKAGE_NAME)); assertThat(testPkgSetting01.pkgFlags, is(0)); assertThat(testPkgSetting01.pkgPrivateFlags, is(0)); assertThat(testPkgSetting01.primaryCpuAbiString, is("x86_64")); - assertThat(testPkgSetting01.resourcePath, is(INITIAL_CODE_PATH)); assertThat(testPkgSetting01.secondaryCpuAbiString, is("x86")); assertThat(testPkgSetting01.versionCode, is(INITIAL_VERSION_CODE)); final PackageUserState userState = testPkgSetting01.readUserState(0); @@ -738,7 +726,6 @@ public class PackageManagerSettingsTests { null /*realPkgName*/, null /*sharedUser*/, UPDATED_CODE_PATH /*codePath*/, - UPDATED_CODE_PATH /*resourcePath*/, null /*legacyNativeLibraryPath*/, "arm64-v8a" /*primaryCpuAbi*/, "armeabi" /*secondaryCpuAbi*/, @@ -754,12 +741,11 @@ public class PackageManagerSettingsTests { null /*usesStaticLibrariesVersions*/, null /*mimeGroups*/); assertThat(testPkgSetting01.appId, is(10064)); - assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH)); + assertThat(testPkgSetting01.getCodePath(), is(UPDATED_CODE_PATH)); assertThat(testPkgSetting01.name, is(PACKAGE_NAME)); assertThat(testPkgSetting01.pkgFlags, is(0)); assertThat(testPkgSetting01.pkgPrivateFlags, is(0)); assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a")); - assertThat(testPkgSetting01.resourcePath, is(UPDATED_CODE_PATH)); assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi")); assertNotSame(testPkgSetting01.signatures, disabledSignatures); assertThat(testPkgSetting01.versionCode, is(UPDATED_VERSION_CODE)); @@ -806,10 +792,10 @@ public class PackageManagerSettingsTests { private void verifySettingCopy(PackageSetting origPkgSetting, PackageSetting testPkgSetting) { assertThat(origPkgSetting, is(not(testPkgSetting))); assertThat(origPkgSetting.appId, is(testPkgSetting.appId)); - assertSame(origPkgSetting.codePath, testPkgSetting.codePath); - assertThat(origPkgSetting.codePath, is(testPkgSetting.codePath)); - assertSame(origPkgSetting.codePathString, testPkgSetting.codePathString); - assertThat(origPkgSetting.codePathString, is(testPkgSetting.codePathString)); + assertSame(origPkgSetting.getCodePath(), testPkgSetting.getCodePath()); + assertThat(origPkgSetting.getCodePath(), is(testPkgSetting.getCodePath())); + assertSame(origPkgSetting.getCodePathString(), testPkgSetting.getCodePathString()); + assertThat(origPkgSetting.getCodePathString(), is(testPkgSetting.getCodePathString())); assertSame(origPkgSetting.cpuAbiOverrideString, testPkgSetting.cpuAbiOverrideString); assertThat(origPkgSetting.cpuAbiOverrideString, is(testPkgSetting.cpuAbiOverrideString)); assertThat(origPkgSetting.firstInstallTime, is(testPkgSetting.firstInstallTime)); @@ -823,7 +809,9 @@ public class PackageManagerSettingsTests { testPkgSetting.legacyNativeLibraryPathString); assertThat(origPkgSetting.legacyNativeLibraryPathString, is(testPkgSetting.legacyNativeLibraryPathString)); - assertNotSame(origPkgSetting.mimeGroups, testPkgSetting.mimeGroups); + if (origPkgSetting.mimeGroups != null) { + assertNotSame(origPkgSetting.mimeGroups, testPkgSetting.mimeGroups); + } assertThat(origPkgSetting.mimeGroups, is(testPkgSetting.mimeGroups)); assertNotSame(origPkgSetting.mPermissionsState, testPkgSetting.mPermissionsState); assertThat(origPkgSetting.mPermissionsState, is(testPkgSetting.mPermissionsState)); @@ -839,10 +827,6 @@ public class PackageManagerSettingsTests { assertSame(origPkgSetting.primaryCpuAbiString, testPkgSetting.primaryCpuAbiString); assertThat(origPkgSetting.primaryCpuAbiString, is(testPkgSetting.primaryCpuAbiString)); assertThat(origPkgSetting.realName, is(testPkgSetting.realName)); - assertSame(origPkgSetting.resourcePath, testPkgSetting.resourcePath); - assertThat(origPkgSetting.resourcePath, is(testPkgSetting.resourcePath)); - assertSame(origPkgSetting.resourcePathString, testPkgSetting.resourcePathString); - assertThat(origPkgSetting.resourcePathString, is(testPkgSetting.resourcePathString)); assertSame(origPkgSetting.secondaryCpuAbiString, testPkgSetting.secondaryCpuAbiString); assertThat(origPkgSetting.secondaryCpuAbiString, is(testPkgSetting.secondaryCpuAbiString)); assertSame(origPkgSetting.sharedUser, testPkgSetting.sharedUser); @@ -874,7 +858,6 @@ public class PackageManagerSettingsTests { PACKAGE_NAME, REAL_PACKAGE_NAME, INITIAL_CODE_PATH /*codePath*/, - INITIAL_CODE_PATH /*resourcePath*/, null /*legacyNativeLibraryPathString*/, "x86_64" /*primaryCpuAbiString*/, "x86" /*secondaryCpuAbiString*/, @@ -893,7 +876,6 @@ public class PackageManagerSettingsTests { packageName, packageName, INITIAL_CODE_PATH /*codePath*/, - INITIAL_CODE_PATH /*resourcePath*/, null /*legacyNativeLibraryPathString*/, "x86_64" /*primaryCpuAbiString*/, "x86" /*secondaryCpuAbiString*/, diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java index b0b5386a49bdb..2651cfa5449b4 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java @@ -312,8 +312,7 @@ public class PackageParserTest { private static PackageSetting mockPkgSetting(AndroidPackage pkg) { return new PackageSetting(pkg.getPackageName(), pkg.getRealPackage(), - new File(pkg.getCodePath()), new File(pkg.getCodePath()), null, - pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi(), + new File(pkg.getCodePath()), null, pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi(), null, pkg.getVersionCode(), PackageInfoUtils.appInfoFlags(pkg, null), PackageInfoUtils.appInfoPrivateFlags(pkg, null), diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java index d12ea89469b79..f8e92ad71d8ec 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java @@ -30,7 +30,6 @@ public class PackageSettingBuilder { private String mName; private String mRealName; private String mCodePath; - private String mResourcePath; private String mLegacyNativeLibraryPathString; private String mPrimaryCpuAbiString; private String mSecondaryCpuAbiString; @@ -74,11 +73,6 @@ public class PackageSettingBuilder { return this; } - public PackageSettingBuilder setResourcePath(String resourcePath) { - this.mResourcePath = resourcePath; - return this; - } - public PackageSettingBuilder setLegacyNativeLibraryPathString( String legacyNativeLibraryPathString) { this.mLegacyNativeLibraryPathString = legacyNativeLibraryPathString; @@ -162,10 +156,10 @@ public class PackageSettingBuilder { public PackageSetting build() { final PackageSetting packageSetting = new PackageSetting(mName, mRealName, - new File(mCodePath), new File(mResourcePath), - mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString, - mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mSharedUserId, - mUsesStaticLibraries, mUsesStaticLibrariesVersions, mMimeGroups); + new File(mCodePath), mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, + mSecondaryCpuAbiString, mCpuAbiOverrideString, mPVersionCode, mPkgFlags, + mPrivateFlags, mSharedUserId, mUsesStaticLibraries, mUsesStaticLibrariesVersions, + mMimeGroups); packageSetting.signatures = mSigningDetails != null ? new PackageSignatures(mSigningDetails) : new PackageSignatures(); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java index 55bc6812328ac..7108490f80f85 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java @@ -465,9 +465,9 @@ public class PackageSignaturesTest { // Generic PackageSetting object with values from a test app installed on a device to be // used to test the methods under the PackageSignatures signatures data member. File appPath = new File("/data/app/app"); - PackageSetting result = new PackageSetting("test.app", null, appPath, appPath, - "/data/app/app", null, null, null, - 1, 940097092, 0, 0 /*userId*/, null, null, null /*mimeGroups*/); + PackageSetting result = new PackageSetting("test.app", null, appPath, + "/data/app/app", null, null, null, 1, 940097092, 0, 0 /*userId*/, null, null, + null /*mimeGroups*/); return result; } } diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java index e7eff00c472e2..56dddb0a81121 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java @@ -484,8 +484,7 @@ public class ScanTests { private static PackageSettingBuilder createBasicPackageSettingBuilder(String packageName) { return new PackageSettingBuilder() .setName(packageName) - .setCodePath(createCodePath(packageName)) - .setResourcePath(createCodePath(packageName)); + .setCodePath(createCodePath(packageName)); } private static ScanRequestBuilder createBasicScanRequestBuilder(ParsingPackage pkg) { @@ -534,8 +533,7 @@ public class ScanTests { arrayContaining("some.static.library", "some.other.static.library")); assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L})); assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage)); - assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName)))); - assertThat(pkgSetting.resourcePath, is(new File(createCodePath(packageName)))); + assertThat(pkgSetting.getCodePath(), is(new File(createCodePath(packageName)))); assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345))); } From 328aa43bff66ee65173c6b6cd27f441502c369ef Mon Sep 17 00:00:00 2001 From: Winson Date: Thu, 23 Jul 2020 11:58:05 -0700 Subject: [PATCH 2/2] Fix uninstall/disable with multi-user compressed stubs Updates uninstall logic to ensure that only the user being acted on is affected. Previously, uninstalling from any user would disable the app for user 0. This updates it to only change the state of the stubbed package for the user that initiates the uninstall. This also changes the re-uncompression logic such that stubs are kept in their system-only state until any user has marked it installed and enabled. Also adds tests for all the uninstall scenarios for a stub system app. Some test cases are migrated from I6fdd3ed485db0d3f8135266010d6797d9ac37ea0. Only the corruption test isn't implemented, as this change doesn't verify the install/scan behavior at boot. Bug: 159204252 Test: atest com.android.server.pm.test.SystemStubMultiUserDisableUninstallTest Test: atest PackageManagerServiceHostTests Change-Id: I4ee2affc058d2bae363c537b3294d5d46a5051a0 --- .../server/pm/PackageManagerService.java | 50 +- .../server/pm/PackageManagerShellCommand.java | 10 +- .../host/Android.bp | 33 +- .../PackageManagerDummyAppVersion3Invalid.apk | Bin 2457 -> 0 bytes .../com/android/server/pm/test/HostUtils.kt | 56 +- .../server/pm/test/InvalidNewSystemAppTest.kt | 16 +- .../pm/test/OriginalPackageMigrationTest.kt | 17 +- ...SystemStubMultiUserDisableUninstallTest.kt | 650 ++++++++++++++++++ .../host/test-apps/Android.bp | 16 +- .../AndroidManifestOriginalOverride.xml | 4 +- .../test-apps/AndroidManifestVersion1.xml | 4 +- .../test-apps/AndroidManifestVersion2.xml | 4 +- .../test-apps/AndroidManifestVersion3.xml | 4 +- .../test-apps/AndroidManifestVersion4.xml | 4 +- .../internal/util/test/SystemPreparer.java | 23 +- 15 files changed, 820 insertions(+), 71 deletions(-) delete mode 100644 services/tests/PackageManagerServiceTests/host/resources/PackageManagerDummyAppVersion3Invalid.apk create mode 100644 services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 00ad661e39da0..e47dd6cad9f29 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -18530,7 +18530,6 @@ public class PackageManagerService extends IPackageManager.Stub // user handle installed state int[] allUsers; /** enabled state of the uninstalled application */ - final int origEnabledState; synchronized (mLock) { uninstalledPs = mSettings.mPackages.get(packageName); if (uninstalledPs == null) { @@ -18546,10 +18545,6 @@ public class PackageManagerService extends IPackageManager.Stub } disabledSystemPs = mSettings.getDisabledSystemPkgLPr(packageName); - // Save the enabled state before we delete the package. When deleting a stub - // application we always set the enabled state to 'disabled'. - origEnabledState = uninstalledPs == null - ? COMPONENT_ENABLED_STATE_DEFAULT : uninstalledPs.getEnabled(userId); // Static shared libs can be declared by any package, so let us not // allow removing a package if it provides a lib others depend on. pkg = mPackages.get(packageName); @@ -18628,20 +18623,32 @@ public class PackageManagerService extends IPackageManager.Stub if (stubPkg != null && stubPkg.isStub()) { final PackageSetting stubPs; synchronized (mLock) { - // restore the enabled state of the stub; the state is overwritten when - // the stub is uninstalled stubPs = mSettings.getPackageLPr(stubPkg.getPackageName()); - if (stubPs != null) { - stubPs.setEnabled(origEnabledState, userId, "android"); - } } - if (origEnabledState == COMPONENT_ENABLED_STATE_DEFAULT - || origEnabledState == COMPONENT_ENABLED_STATE_ENABLED) { - if (DEBUG_COMPRESSION) { - Slog.i(TAG, "Enabling system stub after removal; pkg: " - + stubPkg.getPackageName()); + + if (stubPs != null) { + boolean enable = false; + for (int aUserId : allUsers) { + if (stubPs.getInstalled(aUserId)) { + int enabled = stubPs.getEnabled(aUserId); + if (enabled == COMPONENT_ENABLED_STATE_DEFAULT + || enabled == COMPONENT_ENABLED_STATE_ENABLED) { + enable = true; + break; + } + } + } + + if (enable) { + if (DEBUG_COMPRESSION) { + Slog.i(TAG, "Enabling system stub after removal; pkg: " + + stubPkg.getPackageName()); + } + enableCompressedPackage(stubPkg, stubPs); + } else if (DEBUG_COMPRESSION) { + Slog.i(TAG, "System stub disabled for all users, leaving uncompressed " + + "after removal; pkg: " + stubPkg.getPackageName()); } - enableCompressedPackage(stubPkg, stubPs); } } } @@ -18985,8 +18992,15 @@ public class PackageManagerService extends IPackageManager.Stub // and re-enable it afterward. final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.getPackageName()); if (stubPs != null) { - stubPs.setEnabled( - COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android"); + int userId = action.user == null + ? UserHandle.USER_ALL : action.user.getIdentifier(); + if (userId == UserHandle.USER_ALL) { + for (int aUserId : allUserHandles) { + stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, aUserId, "android"); + } + } else if (userId >= UserHandle.USER_SYSTEM) { + stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, userId, "android"); + } } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 668f375e2e9b4..7aeec6d68d267 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -423,13 +423,15 @@ class PackageManagerShellCommand extends ShellCommand { final List list; if (packageName == null) { final ParceledListSlice packages = - mInterface.getInstalledApplications( - PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM); + mInterface.getInstalledApplications(PackageManager.MATCH_SYSTEM_ONLY + | PackageManager.MATCH_UNINSTALLED_PACKAGES, + UserHandle.USER_SYSTEM); list = packages.getList(); } else { list = new ArrayList<>(1); - list.add(mInterface.getApplicationInfo(packageName, - PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM)); + list.add(mInterface.getApplicationInfo(packageName, PackageManager.MATCH_SYSTEM_ONLY + | PackageManager.MATCH_UNINSTALLED_PACKAGES, + UserHandle.USER_SYSTEM)); } for (ApplicationInfo info : list) { if (info.isUpdatedSystemApp()) { diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp index 41dfade1a09a3..cffcdd8f94bdc 100644 --- a/services/tests/PackageManagerServiceTests/host/Android.bp +++ b/services/tests/PackageManagerServiceTests/host/Android.bp @@ -25,17 +25,28 @@ java_test_host { ], test_suites: ["general-tests"], java_resources: [ - ":PackageManagerDummyAppVersion1", - ":PackageManagerDummyAppVersion2", - ":PackageManagerDummyAppVersion3", - ":PackageManagerDummyAppVersion4", - ":PackageManagerDummyAppOriginalOverride", - ":PackageManagerServiceHostTestsResources", - ] + ":PackageManagerTestAppStub", + ":PackageManagerTestAppVersion1", + ":PackageManagerTestAppVersion2", + ":PackageManagerTestAppVersion3", + ":PackageManagerTestAppVersion3Invalid", + ":PackageManagerTestAppVersion4", + ":PackageManagerTestAppOriginalOverride", + ], } -filegroup { - name: "PackageManagerServiceHostTestsResources", - srcs: [ "resources/*" ], - path: "resources/" +genrule { + name: "PackageManagerTestAppVersion3Invalid", + tools: [ + "soong_zip", + "zipalign", + ], + srcs: [ + ":PackageManagerTestAppVersion3", + ], + out: ["PackageManagerTestAppVersion3Invalid.apk"], + cmd: "mkdir -p $(genDir)/apk && unzip $(in) -d $(genDir)/apk" + + " && truncate -s 800 $(genDir)/apk/META-INF/CERT.RSA" + + " && $(location soong_zip) -o $(genDir)/temp.apk -L 0 -C $(genDir)/apk -D $(genDir)/apk" + + " && $(location zipalign) -f 4 $(genDir)/temp.apk $(out)", } diff --git a/services/tests/PackageManagerServiceTests/host/resources/PackageManagerDummyAppVersion3Invalid.apk b/services/tests/PackageManagerServiceTests/host/resources/PackageManagerDummyAppVersion3Invalid.apk deleted file mode 100644 index 127886cf8e9e8c66d00a837f44f406d7c3cbfa11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2457 zcmWIWW@Zs#W?@}C`$tHT83u`w_RGcYhX=A{(nXQucj=4Ga(7MJK%hZp*8j;g_wtZ2Zb}rM5>-`;;*bU6{ znvy?o)-c;UrYwn0V1LtO_=9ho@=Mzv9Cpp}56pKst(&D*wN6>qD=K`IPq3&5^EJii zoxeQt4@LyVuHSgBRQzn?*UX33N3!@Um#7!aEPAeK`r*rrQ~FnI)~w1{{b0^Z(V&eA zdF($Wa@$m=M&-ZSYWVw&{)VGmcc-k-JR@=TPlUL5WNT^l-ma2nPxl117pL~|-rOna zb4o^;|J1HkKDYIPzsJizxs$e8*3oONZ{w8BWg9CND?hWgE#A0v_Hwb+t84E*zV_Ro z-}3FN#&^o^H`*=Qd?_?;Z^E)&YvqiuGd!E1@uzhIQ+VY0WAYo*&8qcZgfxlDT=EW& zzj^-3zLyr{HYq6g3ze@eX$N$MqthTJz9e$dh z`gl-f*EzYsAUsS;IrI*!Dkzi&wkB3TbMR& zaqwN`o~J)P0xAG*ayUd$jY2ugF^Izf*p-Al5QV6w({z;i{Iu>pEx&@k$bj5aK?s(8yXd)i#530 z4W<_-`K3kG1;(W zIdLlEiPo2?EJcyCBqVcE_1<^ydRq8o_1fFBc|_MfkN#hG$Bb9tK7+#lei!hSkS@E_`z7 zS^CVLnZ`9g@-EIZivRlfvQ6HB5|8)t<%%is))M=Qetz*@EIUu#Yx1M`vzzy5mOSY@ zb?Ugu&Bv}BQmN{5Pd2VuvzY1Sx))km{w!xR`X}!=c%bB8p>iJQnS|bY{pQFrqHlEw|?&*C7J|*7uEn z4$Fz&Ss-frMC_|Vhmy#V?2KzdTRL-sF6_TPt&8KHT>nhXTG^bunIBx{)bL29WoaFq zbuz7JN7Xm>9-ji4z0H0G-(N>`6=iRT&?$VJ?Iro$?8oWqj0ul=nERgXIP9mmeBq1( zF85iTzTx_te)D;j}77Z(As2(rt4 z9sNArT!TaOeBD0#o;mH~t*dvD*IQTX+?n&6gAA@1KY04+=_l_qzFUI|&UkB{I`7lC z^3v)PXCFT0`c`no)X4O5=}8~OLd&^cWHu@)%Np-p*&p1k!p8 z#SE!HUKyCwV<-TtDFO0|8A^b%DGa4Rkz9sKhIpXP0w5f!Kmin3KwtxB^#!{zpF(`m!fDVvgUzm4li3#j1JlEYYjAt0cs?SMi`B)1cn(6a(@f5(XjFu#fs~N z(ID3{ta69~(@;LL6__OjvK96$NUjH45$uLygY%UruqR+NM)+_rVCHCK8-60&fRw*c zZ23MT9&8JYMzTeY8CRwS#vT+bXslrcmL_Ofm=%(R(XwxVH!HBY#lXM@g!aGyc3}tc E0Ey-mLjV8( diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt index 234fcf19062df..8dfefaf9750f3 100644 --- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt +++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt @@ -21,8 +21,9 @@ import com.android.tradefed.device.ITestDevice import java.io.File import java.io.FileOutputStream -internal fun SystemPreparer.pushApk(file: String, partition: Partition) = - pushResourceFile(file, HostUtils.makePathForApk(file, partition).toString()) +internal fun SystemPreparer.pushApk(javaResourceName: String, partition: Partition) = + pushResourceFile(javaResourceName, HostUtils.makePathForApk(javaResourceName, partition) + .toString()) internal fun SystemPreparer.deleteApkFolders( partition: Partition, @@ -58,4 +59,55 @@ internal object HostUtils { } return file } + + /** + * dumpsys package and therefore device.getAppPackageInfo doesn't work immediately after reboot, + * so the following methods parse the package dump directly to see if the path matches. + */ + fun getCodePaths(device: ITestDevice, pkgName: String) = + device.executeShellCommand("pm dump $pkgName") + .lineSequence() + .map(String::trim) + .filter { it.startsWith("codePath=") } + .map { it.removePrefix("codePath=") } + .toList() + + private fun userIdLineSequence(device: ITestDevice, pkgName: String) = + device.executeShellCommand("pm dump $pkgName") + .lineSequence() + .dropWhile { !it.startsWith("Packages:") } + .takeWhile { + !it.startsWith("Hidden system packages:") && + !it.startsWith("Queries:") + } + .map(String::trim) + .filter { it.startsWith("User ") } + + fun getUserIdToPkgEnabledState(device: ITestDevice, pkgName: String) = + userIdLineSequence(device, pkgName).associate { + val userId = it.removePrefix("User ") + .takeWhile(Char::isDigit) + .toInt() + val enabled = it.substringAfter("enabled=") + .takeWhile(Char::isDigit) + .toInt() + .let { + when (it) { + 0, 1 -> true + else -> false + } + } + userId to enabled + } + + fun getUserIdToPkgInstalledState(device: ITestDevice, pkgName: String) = + userIdLineSequence(device, pkgName).associate { + val userId = it.removePrefix("User ") + .takeWhile(Char::isDigit) + .toInt() + val installed = it.substringAfter("installed=") + .takeWhile { !it.isWhitespace() } + .toBoolean() + userId to installed + } } diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt index 39b40d8d3195b..b7d135991ccd6 100644 --- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt +++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt @@ -33,11 +33,11 @@ import org.junit.runner.RunWith class InvalidNewSystemAppTest : BaseHostJUnit4Test() { companion object { - private const val TEST_PKG_NAME = "com.android.server.pm.test.dummy_app" - private const val VERSION_ONE = "PackageManagerDummyAppVersion1.apk" - private const val VERSION_TWO = "PackageManagerDummyAppVersion2.apk" - private const val VERSION_THREE_INVALID = "PackageManagerDummyAppVersion3Invalid.apk" - private const val VERSION_FOUR = "PackageManagerDummyAppVersion4.apk" + private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app" + private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk" + private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk" + private const val VERSION_THREE_INVALID = "PackageManagerTestAppVersion3Invalid.apk" + private const val VERSION_FOUR = "PackageManagerTestAppVersion4.apk" @get:ClassRule val deviceRebootRule = SystemPreparer.TestRuleDelegate(true) @@ -49,14 +49,14 @@ class InvalidNewSystemAppTest : BaseHostJUnit4Test() { @get:Rule val rules = RuleChain.outerRule(tempFolder).around(preparer)!! - private val filePath = HostUtils.makePathForApk("PackageManagerDummyApp.apk", Partition.PRODUCT) + private val filePath = HostUtils.makePathForApk("PackageManagerTestApp.apk", Partition.PRODUCT) @Before @After fun removeApk() { device.uninstallPackage(TEST_PKG_NAME) - device.deleteFile(filePath.parent.toString()) - device.reboot() + preparer.deleteFile(filePath.parent.toString()) + .reboot() } @Test diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt index fb0348c3146b3..4ae3ca5f72636 100644 --- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt +++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt @@ -33,11 +33,11 @@ import org.junit.runner.RunWith class OriginalPackageMigrationTest : BaseHostJUnit4Test() { companion object { - private const val TEST_PKG_NAME = "com.android.server.pm.test.dummy_app" - private const val VERSION_ONE = "PackageManagerDummyAppVersion1.apk" - private const val VERSION_TWO = "PackageManagerDummyAppVersion2.apk" - private const val VERSION_THREE = "PackageManagerDummyAppVersion3.apk" - private const val NEW_PKG = "PackageManagerDummyAppOriginalOverride.apk" + private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app" + private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk" + private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk" + private const val VERSION_THREE = "PackageManagerTestAppVersion3.apk" + private const val NEW_PKG = "PackageManagerTestAppOriginalOverride.apk" @get:ClassRule val deviceRebootRule = SystemPreparer.TestRuleDelegate(true) @@ -55,6 +55,7 @@ class OriginalPackageMigrationTest : BaseHostJUnit4Test() { fun deleteApkFolders() { preparer.deleteApkFolders(Partition.SYSTEM, VERSION_ONE, VERSION_TWO, VERSION_THREE, NEW_PKG) + .reboot() } @Test @@ -99,9 +100,7 @@ class OriginalPackageMigrationTest : BaseHostJUnit4Test() { } private fun assertCodePath(apk: String) { - // dumpsys package and therefore device.getAppPackageInfo doesn't work here for some reason, - // so parse the package dump directly to see if the path matches. - assertThat(device.executeShellCommand("pm dump $TEST_PKG_NAME")) - .contains(HostUtils.makePathForApk(apk, Partition.SYSTEM).parent.toString()) + assertThat(HostUtils.getCodePaths(device, TEST_PKG_NAME)) + .containsExactly(HostUtils.makePathForApk(apk, Partition.SYSTEM).parent.toString()) } } diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt new file mode 100644 index 0000000000000..bc478b0e2c90b --- /dev/null +++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt @@ -0,0 +1,650 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test + +import com.android.internal.util.test.SystemPreparer +import com.android.tradefed.device.ITestDevice +import com.android.tradefed.device.UserInfo +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test +import com.google.common.truth.Truth.assertThat +import org.junit.AfterClass +import org.junit.Before +import org.junit.ClassRule +import org.junit.Rule +import org.junit.Test +import org.junit.rules.RuleChain +import org.junit.rules.TemporaryFolder +import org.junit.runner.RunWith +import java.io.File +import java.util.zip.GZIPOutputStream + +@RunWith(DeviceJUnit4ClassRunner::class) +class SystemStubMultiUserDisableUninstallTest : BaseHostJUnit4Test() { + + companion object { + private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app" + private const val VERSION_STUB = "PackageManagerTestAppStub.apk" + private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk" + + /** + * How many total users on device to test, including primary. This will clean up any + * users created specifically for this test. + */ + private const val USER_COUNT = 3 + + /** + * Whether to manually reset state at each test method without rebooting + * for faster iterative development. + */ + private const val DEBUG_NO_REBOOT = false + + @get:ClassRule + val deviceRebootRule = SystemPreparer.TestRuleDelegate(true) + + private val parentClassName = SystemStubMultiUserDisableUninstallTest::class.java.simpleName + + private val deviceCompressedFile = + HostUtils.makePathForApk("$parentClassName.apk", Partition.PRODUCT).parent + .resolve("$parentClassName.apk.gz") + + private val stubFile = + HostUtils.makePathForApk("$parentClassName-Stub.apk", Partition.PRODUCT) + + private val secondaryUsers = mutableListOf() + private val usersToRemove = mutableListOf() + private var savedDevice: ITestDevice? = null + private var savedPreparer: SystemPreparer? = null + + private fun setUpUsers(device: ITestDevice) { + if (this.savedDevice != null) return + this.savedDevice = device + secondaryUsers.clear() + secondaryUsers += device.userInfos.values.map(UserInfo::userId).filterNot { it == 0 } + while (secondaryUsers.size < USER_COUNT) { + secondaryUsers += device.createUser(parentClassName + secondaryUsers.size) + .also { usersToRemove += it } + } + } + + @JvmStatic + @AfterClass + fun cleanUp() { + savedDevice ?: return + + usersToRemove.forEach { + savedDevice?.removeUser(it) + } + + savedDevice?.uninstallPackage(TEST_PKG_NAME) + savedDevice?.deleteFile(stubFile.parent.toString()) + savedDevice?.deleteFile(deviceCompressedFile.parent.toString()) + savedDevice?.reboot() + savedDevice = null + + if (DEBUG_NO_REBOOT) { + savedPreparer?.after() + savedPreparer = null + } + } + } + + private val tempFolder = TemporaryFolder() + private val preparer: SystemPreparer = SystemPreparer(tempFolder, + SystemPreparer.RebootStrategy.START_STOP, deviceRebootRule) { this.device } + + @get:Rule + val rules = RuleChain.outerRule(tempFolder).let { + if (DEBUG_NO_REBOOT) { + it!! + } else { + it.around(preparer)!! + } + } + + private var hostCompressedFile: File? = null + + private val previousCodePaths = mutableListOf() + + @Before + fun ensureUserAndCompressStubAndInstall() { + setUpUsers(device) + + val initialized = hostCompressedFile != null + if (!initialized) { + hostCompressedFile = tempFolder.newFile() + hostCompressedFile!!.outputStream().use { + javaClass.classLoader + .getResource(VERSION_ONE)!! + .openStream() + .use { input -> + GZIPOutputStream(it).use { output -> + input.copyTo(output) + } + } + } + } + + device.uninstallPackage(TEST_PKG_NAME) + + if (!initialized || !DEBUG_NO_REBOOT) { + savedPreparer = preparer + preparer.pushResourceFile(VERSION_STUB, stubFile.toString()) + .pushFile(hostCompressedFile, deviceCompressedFile.toString()) + .reboot() + } + + // This test forces the state to installed/enabled for all users, + // since it only tests the uninstall/disable side. + installExisting(User.PRIMARY) + installExisting(User.SECONDARY) + + ensureEnabled() + + // Ensure data app isn't re-installed multiple times by comparing against the original path + val codePath = HostUtils.getCodePaths(device, TEST_PKG_NAME).first() + assertThat(codePath).contains("/data/app") + assertThat(codePath).contains(TEST_PKG_NAME) + + previousCodePaths.clear() + previousCodePaths += codePath + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + } + + @Test + fun disablePrimaryFirstAndUninstall() { + toggleEnabled(false, User.PRIMARY) + + assertState( + primaryInstalled = true, primaryEnabled = false, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + + toggleEnabled(false, User.SECONDARY) + + assertState( + primaryInstalled = true, primaryEnabled = false, + secondaryInstalled = true, secondaryEnabled = false, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + + device.uninstallPackage(TEST_PKG_NAME) + + assertState( + primaryInstalled = true, primaryEnabled = false, + secondaryInstalled = true, secondaryEnabled = false, + codePaths = listOf(CodePath.SYSTEM) + ) + } + + @Test + fun disableSecondaryFirstAndUninstall() { + toggleEnabled(false, User.SECONDARY) + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = false, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + + toggleEnabled(false, User.PRIMARY) + + assertState( + primaryInstalled = true, primaryEnabled = false, + secondaryInstalled = true, secondaryEnabled = false, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + + device.uninstallPackage(TEST_PKG_NAME) + + assertState( + primaryInstalled = true, primaryEnabled = false, + secondaryInstalled = true, secondaryEnabled = false, + codePaths = listOf(CodePath.SYSTEM) + ) + } + + @Test + fun disabledUninstalledEnablePrimaryFirst() { + toggleEnabled(false, User.PRIMARY) + toggleEnabled(false, User.SECONDARY) + device.uninstallPackage(TEST_PKG_NAME) + + toggleEnabled(true, User.PRIMARY) + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = false, + codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM) + ) + + toggleEnabled(true, User.SECONDARY) + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + } + + @Test + fun disabledUninstalledEnableSecondaryFirst() { + toggleEnabled(false, User.PRIMARY) + toggleEnabled(false, User.SECONDARY) + device.uninstallPackage(TEST_PKG_NAME) + + toggleEnabled(true, User.SECONDARY) + + assertState( + primaryInstalled = true, primaryEnabled = false, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM) + ) + + toggleEnabled(true, User.PRIMARY) + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + } + + @Test + fun uninstallPrimaryFirstByUserAndInstallExistingPrimaryFirst() { + uninstall(User.PRIMARY) + + assertState( + primaryInstalled = false, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM) + ) + + uninstall(User.SECONDARY) + + assertState( + primaryInstalled = false, primaryEnabled = true, + secondaryInstalled = false, secondaryEnabled = true, + codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM) + ) + + installExisting(User.PRIMARY) + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = false, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + + installExisting(User.SECONDARY) + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + } + + @Test + fun uninstallSecondaryFirstByUserAndInstallExistingSecondaryFirst() { + uninstall(User.PRIMARY) + + assertState( + primaryInstalled = false, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM) + ) + + uninstall(User.SECONDARY) + + assertState( + primaryInstalled = false, primaryEnabled = true, + secondaryInstalled = false, secondaryEnabled = true, + codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM) + ) + + installExisting(User.SECONDARY) + + assertState( + primaryInstalled = false, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + + installExisting(User.PRIMARY) + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + } + + @Test + fun uninstallUpdatesAndEnablePrimaryFirst() { + device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME") + + // Uninstall-system-updates always disables system user 0 + // TODO: Is this intentional? There is no user argument for this command. + assertState( + primaryInstalled = true, primaryEnabled = false, + secondaryInstalled = true, secondaryEnabled = true, + // If any user is enabled when uninstalling updates, /data is re-uncompressed + codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM) + ) + + toggleEnabled(true, User.PRIMARY) + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + + // Test enabling secondary to ensure path does not change, even though it's already enabled + toggleEnabled(true, User.SECONDARY) + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + } + + @Test + fun uninstallUpdatesAndEnableSecondaryFirst() { + device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME") + + // Uninstall-system-updates always disables system user 0 + assertState( + primaryInstalled = true, primaryEnabled = false, + secondaryInstalled = true, secondaryEnabled = true, + // If any user is enabled when uninstalling updates, /data is re-uncompressed + codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM) + ) + + toggleEnabled(true, User.SECONDARY) + + assertState( + primaryInstalled = true, primaryEnabled = false, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + + toggleEnabled(true, User.PRIMARY) + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + } + + @Test + fun disabledUninstallUpdatesAndEnablePrimaryFirst() { + toggleEnabled(false, User.PRIMARY) + toggleEnabled(false, User.SECONDARY) + + device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME") + + assertState( + primaryInstalled = true, primaryEnabled = false, + secondaryInstalled = true, secondaryEnabled = false, + codePaths = listOf(CodePath.SYSTEM) + ) + + toggleEnabled(true, User.PRIMARY) + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = false, + codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM) + ) + + toggleEnabled(true, User.SECONDARY) + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + } + + @Test + fun disabledUninstallUpdatesAndEnableSecondaryFirst() { + toggleEnabled(false, User.PRIMARY) + toggleEnabled(false, User.SECONDARY) + + device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME") + + assertState( + primaryInstalled = true, primaryEnabled = false, + secondaryInstalled = true, secondaryEnabled = false, + codePaths = listOf(CodePath.SYSTEM) + ) + + toggleEnabled(true, User.SECONDARY) + + assertState( + primaryInstalled = true, primaryEnabled = false, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM) + ) + + toggleEnabled(true, User.PRIMARY) + + assertState( + primaryInstalled = true, primaryEnabled = true, + secondaryInstalled = true, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + } + + @Test + fun uninstalledUninstallUpdatesAndEnablePrimaryFirst() { + uninstall(User.PRIMARY) + uninstall(User.SECONDARY) + + device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME") + + // Uninstall-system-updates always disables system user 0 + assertState( + primaryInstalled = false, primaryEnabled = false, + secondaryInstalled = false, secondaryEnabled = true, + codePaths = listOf(CodePath.SYSTEM) + ) + + toggleEnabled(true, User.PRIMARY) + + assertState( + primaryInstalled = false, primaryEnabled = true, + secondaryInstalled = false, secondaryEnabled = true, + codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM) + ) + + toggleEnabled(true, User.SECONDARY) + + assertState( + primaryInstalled = false, primaryEnabled = true, + secondaryInstalled = false, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + } + + @Test + fun uninstalledUninstallUpdatesAndEnableSecondaryFirst() { + uninstall(User.PRIMARY) + uninstall(User.SECONDARY) + + device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME") + + // Uninstall-system-updates always disables system user 0 + assertState( + primaryInstalled = false, primaryEnabled = false, + secondaryInstalled = false, secondaryEnabled = true, + codePaths = listOf(CodePath.SYSTEM) + ) + + toggleEnabled(true, User.SECONDARY) + + assertState( + primaryInstalled = false, primaryEnabled = false, + secondaryInstalled = false, secondaryEnabled = true, + codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM) + ) + + toggleEnabled(true, User.PRIMARY) + + assertState( + primaryInstalled = false, primaryEnabled = true, + secondaryInstalled = false, secondaryEnabled = true, + codePaths = listOf(CodePath.SAME, CodePath.SYSTEM) + ) + } + + private fun ensureEnabled() { + toggleEnabled(true, User.PRIMARY) + toggleEnabled(true, User.SECONDARY) + + assertThat(HostUtils.getUserIdToPkgEnabledState(device, TEST_PKG_NAME).all { it.value }) + .isTrue() + } + + private fun toggleEnabled(enabled: Boolean, user: User, pkgName: String = TEST_PKG_NAME) { + val command = if (enabled) "enable" else "disable" + @Suppress("UNUSED_VARIABLE") val exhaust: Any = when (user) { + User.PRIMARY -> { + device.executeShellCommand("pm $command --user 0 $pkgName") + } + User.SECONDARY -> { + secondaryUsers.forEach { + device.executeShellCommand("pm $command --user $it $pkgName") + } + } + } + } + + private fun uninstall(user: User, pkgName: String = TEST_PKG_NAME) { + @Suppress("UNUSED_VARIABLE") val exhaust: Any = when (user) { + User.PRIMARY -> { + device.executeShellCommand("pm uninstall --user 0 $pkgName") + } + User.SECONDARY -> { + secondaryUsers.forEach { + device.executeShellCommand("pm uninstall --user $it $pkgName") + } + } + } + } + + private fun installExisting(user: User, pkgName: String = TEST_PKG_NAME) { + @Suppress("UNUSED_VARIABLE") val exhaust: Any = when (user) { + User.PRIMARY -> { + device.executeShellCommand("pm install-existing --user 0 $pkgName") + } + User.SECONDARY -> { + secondaryUsers.forEach { + device.executeShellCommand("pm install-existing --user $it $pkgName") + } + } + } + } + + private fun assertState( + primaryInstalled: Boolean, + primaryEnabled: Boolean, + secondaryInstalled: Boolean, + secondaryEnabled: Boolean, + codePaths: List + ) { + HostUtils.getUserIdToPkgInstalledState(device, TEST_PKG_NAME) + .forEach { (userId, installed) -> + if (userId == 0) { + assertThat(installed).isEqualTo(primaryInstalled) + } else { + assertThat(installed).isEqualTo(secondaryInstalled) + } + } + + HostUtils.getUserIdToPkgEnabledState(device, TEST_PKG_NAME) + .forEach { (userId, enabled) -> + if (userId == 0) { + assertThat(enabled).isEqualTo(primaryEnabled) + } else { + assertThat(enabled).isEqualTo(secondaryEnabled) + } + } + + assertCodePaths(codePaths.first(), codePaths.getOrNull(1)) + } + + private fun assertCodePaths(firstCodePath: CodePath, secondCodePath: CodePath? = null) { + val codePaths = HostUtils.getCodePaths(device, TEST_PKG_NAME) + assertThat(codePaths).hasSize(listOfNotNull(firstCodePath, secondCodePath).size) + + when (firstCodePath) { + CodePath.SAME -> { + assertThat(codePaths[0]).contains("/data/app") + assertThat(codePaths[0]).contains(TEST_PKG_NAME) + assertThat(codePaths[0]).isEqualTo(previousCodePaths.last()) + } + CodePath.DIFFERENT -> { + assertThat(codePaths[0]).contains("/data/app") + assertThat(codePaths[0]).contains(TEST_PKG_NAME) + assertThat(previousCodePaths).doesNotContain(codePaths[0]) + previousCodePaths.add(codePaths[0]) + } + CodePath.SYSTEM -> assertThat(codePaths[0]).isEqualTo(stubFile.parent.toString()) + } + + when (secondCodePath) { + CodePath.SAME, CodePath.DIFFERENT -> + throw AssertionError("secondDataPath cannot be a data path") + CodePath.SYSTEM -> assertThat(codePaths[1]).isEqualTo(stubFile.parent.toString()) + } + } + + enum class User { + /** The primary system user 0 */ + PRIMARY, + + /** + * All other users on the device that are not 0. This is split into an enum so that all + * methods that handle secondary act on all non-system users. Some behaviors only occur + * if a package state is marked for all non-primary users on the device, which can be + * more than just 1. + */ + SECONDARY + } + + enum class CodePath { + /** The data code path hasn't changed */ + SAME, + + /** New data code path */ + DIFFERENT, + + /** The static system code path */ + SYSTEM + } +} diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp index c9b29275a7319..4a3076e4736af 100644 --- a/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp +++ b/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp @@ -13,26 +13,32 @@ // limitations under the License. android_test_helper_app { - name: "PackageManagerDummyAppVersion1", + name: "PackageManagerTestAppStub", + manifest: "AndroidManifestVersion1.xml", + srcs: [] +} + +android_test_helper_app { + name: "PackageManagerTestAppVersion1", manifest: "AndroidManifestVersion1.xml" } android_test_helper_app { - name: "PackageManagerDummyAppVersion2", + name: "PackageManagerTestAppVersion2", manifest: "AndroidManifestVersion2.xml" } android_test_helper_app { - name: "PackageManagerDummyAppVersion3", + name: "PackageManagerTestAppVersion3", manifest: "AndroidManifestVersion3.xml" } android_test_helper_app { - name: "PackageManagerDummyAppVersion4", + name: "PackageManagerTestAppVersion4", manifest: "AndroidManifestVersion4.xml" } android_test_helper_app { - name: "PackageManagerDummyAppOriginalOverride", + name: "PackageManagerTestAppOriginalOverride", manifest: "AndroidManifestOriginalOverride.xml" } diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml index f16e1bc8a927e..cba580e440658 100644 --- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml +++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml @@ -16,10 +16,10 @@ --> - + diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml index b492a31349fc2..efc7372a177ca 100644 --- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml +++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml @@ -16,12 +16,12 @@ --> diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml index 25e9f8eb2a673..620054c5dd578 100644 --- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml +++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml @@ -16,12 +16,12 @@ --> diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml index 935f5e62f5082..1997771783dda 100644 --- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml +++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml @@ -16,12 +16,12 @@ --> diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml index d0643cbb2aeb4..d6ade0304189f 100644 --- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml +++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml @@ -16,12 +16,12 @@ --> diff --git a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java index f30c35aca8da6..c2a5459ae125e 100644 --- a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java +++ b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java @@ -34,6 +34,8 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import javax.annotation.Nullable; @@ -49,7 +51,7 @@ import javax.annotation.Nullable; public class SystemPreparer extends ExternalResource { private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000; - // The paths of the files pushed onto the device through this rule. + // The paths of the files pushed onto the device through this rule to be removed after. private ArrayList mPushedFiles = new ArrayList<>(); // The package names of packages installed through this rule. @@ -81,7 +83,7 @@ public class SystemPreparer extends ExternalResource { final ITestDevice device = mDeviceProvider.getDevice(); remount(); assertTrue(device.pushFile(copyResourceToTemp(filePath), outputPath)); - mPushedFiles.add(outputPath); + addPushedFile(device, outputPath); return this; } @@ -91,10 +93,23 @@ public class SystemPreparer extends ExternalResource { final ITestDevice device = mDeviceProvider.getDevice(); remount(); assertTrue(device.pushFile(file, outputPath)); - mPushedFiles.add(outputPath); + addPushedFile(device, outputPath); return this; } + private void addPushedFile(ITestDevice device, String outputPath) + throws DeviceNotAvailableException { + Path pathCreated = Paths.get(outputPath); + + // Find the top most parent that is new to the device + while (pathCreated.getParent() != null + && !device.doesFileExist(pathCreated.getParent().toString())) { + pathCreated = pathCreated.getParent(); + } + + mPushedFiles.add(pathCreated.toString()); + } + /** Deletes the given path from the device */ public SystemPreparer deleteFile(String file) throws DeviceNotAvailableException { final ITestDevice device = mDeviceProvider.getDevice(); @@ -203,7 +218,7 @@ public class SystemPreparer extends ExternalResource { /** Removes installed packages and files that were pushed to the device. */ @Override - protected void after() { + public void after() { final ITestDevice device = mDeviceProvider.getDevice(); try { remount();