Loading core/java/android/content/pm/IPackageInstaller.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,8 @@ interface IPackageInstaller { void bypassNextStagedInstallerCheck(boolean value); void bypassNextAllowedApexUpdateCheck(boolean value); void setAllowUnlimitedSilentUpdates(String installerPackageName); void setSilentUpdatesThrottleTime(long throttleTimeInSeconds); } core/java/android/content/pm/PackageManager.java +7 −0 Original line number Diff line number Diff line Loading @@ -1278,6 +1278,13 @@ public abstract class PackageManager { */ public static final int INSTALL_STAGED = 0x00200000; /** * Flag parameter for {@link #installPackage} to indicate that check whether given APEX can be * updated should be disabled for this install. * @hide */ public static final int INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK = 0x00400000; /** @hide */ @IntDef(flag = true, value = { DONT_KILL_APP, Loading core/java/com/android/server/SystemConfig.java +20 −0 Original line number Diff line number Diff line Loading @@ -240,6 +240,7 @@ public class SystemConfig { private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>(); private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>(); private final ArraySet<String> mAllowedPartnerApexes = new ArraySet<>(); /** * Map of system pre-defined, uniquely named actors; keys are namespace, Loading Loading @@ -410,6 +411,10 @@ public class SystemConfig { return mWhitelistedStagedInstallers; } public Set<String> getAllowedPartnerApexes() { return mAllowedPartnerApexes; } public ArraySet<String> getAppDataIsolationWhitelistedApps() { return mAppDataIsolationWhitelistedApps; } Loading Loading @@ -1212,6 +1217,21 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } break; case "allowed-partner-apex": { // TODO(b/189274479): should this be allowOemPermissions instead? if (allowAppConfigs) { String pkgName = parser.getAttributeValue(null, "package"); if (pkgName == null) { Slog.w(TAG, "<" + name + "> without package in " + permFile + " at " + parser.getPositionDescription()); } else { mAllowedPartnerApexes.add(pkgName); } } else { logNotAllowedInPartition(name, permFile, parser); } XmlUtils.skipCurrentTag(parser); } break; default: { Slog.w(TAG, "Tag " + name + " is unknown in " + permFile + " at " + parser.getPositionDescription()); Loading services/core/java/com/android/server/pm/PackageInstallerService.java +18 −0 Original line number Diff line number Diff line Loading @@ -157,6 +157,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements private volatile boolean mOkToSendBroadcasts = false; private volatile boolean mBypassNextStagedInstallerCheck = false; private volatile boolean mBypassNextAllowedApexUpdateCheck = false; /** * File storing persisted {@link #mSessions} metadata. Loading Loading @@ -651,6 +652,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements throw new IllegalArgumentException( "Non-staged APEX session doesn't support INSTALL_ENABLE_ROLLBACK"); } if (isCalledBySystemOrShell(callingUid) || mBypassNextAllowedApexUpdateCheck) { params.installFlags |= PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK; } else { // Only specific APEX updates (installed through ADB, or for CTS tests) can disable // allowed APEX update check. params.installFlags &= ~PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK; } } if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0 Loading @@ -675,6 +683,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } mBypassNextStagedInstallerCheck = false; mBypassNextAllowedApexUpdateCheck = false; if (!params.isMultiPackage) { // Only system components can circumvent runtime permissions when installing. if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0 Loading Loading @@ -1107,6 +1117,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements mBypassNextStagedInstallerCheck = value; } @Override public void bypassNextAllowedApexUpdateCheck(boolean value) { if (!isCalledBySystemOrShell(Binder.getCallingUid())) { throw new SecurityException("Caller not allowed to bypass allowed apex update check"); } mBypassNextAllowedApexUpdateCheck = value; } /** * Set an installer to allow for the unlimited silent updates. */ Loading services/core/java/com/android/server/pm/PackageInstallerSession.java +26 −0 Original line number Diff line number Diff line Loading @@ -149,6 +149,7 @@ import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.SystemConfig; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.dex.DexManager; import com.android.server.pm.parsing.pkg.AndroidPackage; Loading Loading @@ -2319,6 +2320,26 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } // Check if APEX update is allowed. We do this check in handleInstall, since this is one of // the places that: // * Shared between staged and non-staged APEX update flows. // * Only is called after boot completes. // The later is important, since isApexUpdateAllowed check depends on the // ModuleInfoProvider, which is only populated after device has booted. if (isApexSession()) { boolean checkApexUpdateAllowed = (params.installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK) == 0; synchronized (mLock) { if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName)) { onSessionValidationFailure(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, "Update of APEX package " + mPackageName + " is not allowed"); return; } } } if (params.isStaged) { // TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even // though ideally, we just need to send session committed broadcast. Loading Loading @@ -2803,6 +2824,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return sessionContains((s) -> !s.isApexSession()); } private boolean isApexUpdateAllowed(String apexPackageName) { return mPm.getModuleInfo(apexPackageName, 0) != null || SystemConfig.getInstance().getAllowedPartnerApexes().contains(apexPackageName); } /** * Validate apex install. * <p> Loading Loading
core/java/android/content/pm/IPackageInstaller.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,8 @@ interface IPackageInstaller { void bypassNextStagedInstallerCheck(boolean value); void bypassNextAllowedApexUpdateCheck(boolean value); void setAllowUnlimitedSilentUpdates(String installerPackageName); void setSilentUpdatesThrottleTime(long throttleTimeInSeconds); }
core/java/android/content/pm/PackageManager.java +7 −0 Original line number Diff line number Diff line Loading @@ -1278,6 +1278,13 @@ public abstract class PackageManager { */ public static final int INSTALL_STAGED = 0x00200000; /** * Flag parameter for {@link #installPackage} to indicate that check whether given APEX can be * updated should be disabled for this install. * @hide */ public static final int INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK = 0x00400000; /** @hide */ @IntDef(flag = true, value = { DONT_KILL_APP, Loading
core/java/com/android/server/SystemConfig.java +20 −0 Original line number Diff line number Diff line Loading @@ -240,6 +240,7 @@ public class SystemConfig { private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>(); private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>(); private final ArraySet<String> mAllowedPartnerApexes = new ArraySet<>(); /** * Map of system pre-defined, uniquely named actors; keys are namespace, Loading Loading @@ -410,6 +411,10 @@ public class SystemConfig { return mWhitelistedStagedInstallers; } public Set<String> getAllowedPartnerApexes() { return mAllowedPartnerApexes; } public ArraySet<String> getAppDataIsolationWhitelistedApps() { return mAppDataIsolationWhitelistedApps; } Loading Loading @@ -1212,6 +1217,21 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } break; case "allowed-partner-apex": { // TODO(b/189274479): should this be allowOemPermissions instead? if (allowAppConfigs) { String pkgName = parser.getAttributeValue(null, "package"); if (pkgName == null) { Slog.w(TAG, "<" + name + "> without package in " + permFile + " at " + parser.getPositionDescription()); } else { mAllowedPartnerApexes.add(pkgName); } } else { logNotAllowedInPartition(name, permFile, parser); } XmlUtils.skipCurrentTag(parser); } break; default: { Slog.w(TAG, "Tag " + name + " is unknown in " + permFile + " at " + parser.getPositionDescription()); Loading
services/core/java/com/android/server/pm/PackageInstallerService.java +18 −0 Original line number Diff line number Diff line Loading @@ -157,6 +157,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements private volatile boolean mOkToSendBroadcasts = false; private volatile boolean mBypassNextStagedInstallerCheck = false; private volatile boolean mBypassNextAllowedApexUpdateCheck = false; /** * File storing persisted {@link #mSessions} metadata. Loading Loading @@ -651,6 +652,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements throw new IllegalArgumentException( "Non-staged APEX session doesn't support INSTALL_ENABLE_ROLLBACK"); } if (isCalledBySystemOrShell(callingUid) || mBypassNextAllowedApexUpdateCheck) { params.installFlags |= PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK; } else { // Only specific APEX updates (installed through ADB, or for CTS tests) can disable // allowed APEX update check. params.installFlags &= ~PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK; } } if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0 Loading @@ -675,6 +683,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } mBypassNextStagedInstallerCheck = false; mBypassNextAllowedApexUpdateCheck = false; if (!params.isMultiPackage) { // Only system components can circumvent runtime permissions when installing. if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0 Loading Loading @@ -1107,6 +1117,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements mBypassNextStagedInstallerCheck = value; } @Override public void bypassNextAllowedApexUpdateCheck(boolean value) { if (!isCalledBySystemOrShell(Binder.getCallingUid())) { throw new SecurityException("Caller not allowed to bypass allowed apex update check"); } mBypassNextAllowedApexUpdateCheck = value; } /** * Set an installer to allow for the unlimited silent updates. */ Loading
services/core/java/com/android/server/pm/PackageInstallerSession.java +26 −0 Original line number Diff line number Diff line Loading @@ -149,6 +149,7 @@ import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.SystemConfig; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.dex.DexManager; import com.android.server.pm.parsing.pkg.AndroidPackage; Loading Loading @@ -2319,6 +2320,26 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } // Check if APEX update is allowed. We do this check in handleInstall, since this is one of // the places that: // * Shared between staged and non-staged APEX update flows. // * Only is called after boot completes. // The later is important, since isApexUpdateAllowed check depends on the // ModuleInfoProvider, which is only populated after device has booted. if (isApexSession()) { boolean checkApexUpdateAllowed = (params.installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK) == 0; synchronized (mLock) { if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName)) { onSessionValidationFailure(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, "Update of APEX package " + mPackageName + " is not allowed"); return; } } } if (params.isStaged) { // TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even // though ideally, we just need to send session committed broadcast. Loading Loading @@ -2803,6 +2824,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return sessionContains((s) -> !s.isApexSession()); } private boolean isApexUpdateAllowed(String apexPackageName) { return mPm.getModuleInfo(apexPackageName, 0) != null || SystemConfig.getInstance().getAllowedPartnerApexes().contains(apexPackageName); } /** * Validate apex install. * <p> Loading