Loading services/core/java/com/android/server/pm/InstallPackageHelper.java +2 −5 Original line number Diff line number Diff line Loading @@ -175,7 +175,6 @@ import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; import com.android.server.EventLogTags; import com.android.server.SystemConfig; import com.android.server.criticalevents.CriticalEventLog; import com.android.server.pm.dex.DexManager; import com.android.server.pm.parsing.PackageCacher; Loading Loading @@ -336,8 +335,7 @@ final class InstallPackageHelper { final String oldUpdateOwner = pkgAlreadyExists ? oldPkgSetting.getInstallSource().mUpdateOwnerPackageName : null; final String updateOwnerFromSysconfig = isApex || !pkgSetting.isSystem() ? null : mPm.mInjector.getSystemConfig().getSystemAppUpdateOwnerPackageName( parsedPackage.getPackageName()); : mPm.getSystemAppUpdateOwnerPackageName(parsedPackage.getPackageName()); final boolean isUpdateOwnershipDenylisted = mUpdateOwnershipHelper.isUpdateOwnershipDenylisted(parsedPackage.getPackageName()); final boolean isUpdateOwnershipEnabled = oldUpdateOwner != null; Loading Loading @@ -483,12 +481,11 @@ final class InstallPackageHelper { if (listItems != null && !listItems.isEmpty()) { mUpdateOwnershipHelper.addToUpdateOwnerDenyList(pkgSetting.getPackageName(), listItems); SystemConfig config = SystemConfig.getInstance(); synchronized (mPm.mLock) { for (String unownedPackage : listItems) { PackageSetting unownedSetting = mPm.mSettings.getPackageLPr(unownedPackage); if (unownedSetting != null && config.getSystemAppUpdateOwnerPackageName(unownedPackage) == null) { && mPm.getSystemAppUpdateOwnerPackageName(unownedPackage) == null) { unownedSetting.setUpdateOwnerPackage(null); } } Loading services/core/java/com/android/server/pm/PackageInstallerSession.java +86 −7 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFIC import static android.content.pm.PackageManager.INSTALL_STAGED; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.content.pm.verify.developer.DeveloperVerificationSession.DEVELOPER_VERIFICATION_BYPASSED_REASON_ADB; import static android.content.pm.verify.developer.DeveloperVerificationSession.DEVELOPER_VERIFICATION_BYPASSED_REASON_EMERGENCY; import static android.content.pm.verify.developer.DeveloperVerificationSession.DEVELOPER_VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE; import static android.os.Process.INVALID_UID; import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; Loading Loading @@ -3090,18 +3091,63 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return false; } } return true; } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) boolean shouldAllowDeveloperVerificationEmergencyBypass(String packageName, Computer snapshot) { final String verifierPackageName = mDeveloperVerifierController.getVerifierPackageName(); synchronized (mLock) { if (TextUtils.equals(verifierPackageName, mPackageName)) { // The verifier itself is being updated. Skip. // TODO(b/360129657): log bypass reason and this bypass should only happen if the // current verifier cannot be connected or isn't responding. Slog.w(TAG, "Skipping verification service because the verifier is being updated"); if (verifierPackageName == null) { // Impossible condition. The verifier must exist because otherwise we wouldn't get // here. Added to prevent lint warnings. return false; } if (packageName == null) { return false; } PackageStateInternal ps = snapshot.getPackageStateInternal(packageName, Process.SYSTEM_UID); if (ps == null || !ps.isSystem()) { // The app being installed must be a system app to be considered a critical app for // the emergency bypass. return false; } // Check if app being installed is the verifier itself. if (TextUtils.equals(verifierPackageName, packageName)) { Slog.d(TAG, "Bypassing developer verification because the verifier is being updated"); return true; } // Check if app being installed is the sysconfig-specified update-owner of the verifier. final String updateOwnerPackageName = mPm.getSystemAppUpdateOwnerPackageName( verifierPackageName); if (updateOwnerPackageName == null) { // No sysconfig-specified update-owner for the verifier. No need to check further. return false; } if (TextUtils.equals(updateOwnerPackageName, packageName)) { Slog.d(TAG, "Bypassing verification service because the sysconfig-specified " + "update owner of the verifier is being updated"); return true; } // Check if app being installed is the emergency installer of the sysconfig-specified // update-owner of the verifier. if (isEmergencyInstallerEnabled(updateOwnerPackageName, snapshot, userId, ps.getAppId())) { final PackageStateInternal psUpdateOwner = snapshot.getPackageStateInternal( updateOwnerPackageName, Process.SYSTEM_UID); if (psUpdateOwner == null || psUpdateOwner.getPkg() == null) { // Impossible condition, because the if clause above already checked this. // Added to prevent lint warnings. return false; } String emergencyInstallerPackageName = psUpdateOwner.getPkg().getEmergencyInstaller(); if (emergencyInstallerPackageName != null && TextUtils.equals(emergencyInstallerPackageName, packageName)) { Slog.d(TAG, "Bypassing verification service because the " + "emergency installer of the verifier's update owner is being updated"); return true; } } return false; } private void retryDeveloperVerificationSession(Supplier<Computer> snapshotSupplier) { final SigningInfo signingInfo; Loading Loading @@ -3241,6 +3287,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { resumeVerify(); return; } if (shouldAllowDeveloperVerificationEmergencyBypass( getPackageName(), mPm.snapshotComputer())) { // Bypass verification when critical package is being updated and the verifier // cannot be connected. synchronized (mMetrics) { mMetrics.onDeveloperVerificationBypassed( DEVELOPER_VERIFICATION_BYPASSED_REASON_EMERGENCY); } resumeVerify(); return; } mVerificationUserActionNeededReason = DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN; Loading @@ -3267,6 +3324,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { resumeVerify(); return; } if (shouldAllowDeveloperVerificationEmergencyBypass( getPackageName(), mPm.snapshotComputer())) { // Bypass verification when critical package is being updated and the verifier // cannot be connected. synchronized (mMetrics) { mMetrics.onDeveloperVerificationBypassed( DEVELOPER_VERIFICATION_BYPASSED_REASON_EMERGENCY); } resumeVerify(); return; } mVerificationUserActionNeededReason = DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN; Loading Loading @@ -3304,6 +3372,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { resumeVerify(); return; } if (shouldAllowDeveloperVerificationEmergencyBypass( getPackageName(), mPm.snapshotComputer())) { // Bypass verification when critical package is being updated and the verifier // has timed out. synchronized (mMetrics) { mMetrics.onDeveloperVerificationBypassed( DEVELOPER_VERIFICATION_BYPASSED_REASON_EMERGENCY); } resumeVerify(); return; } mVerificationUserActionNeededReason = DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN; Loading services/core/java/com/android/server/pm/PackageManagerService.java +8 −0 Original line number Diff line number Diff line Loading @@ -8450,4 +8450,12 @@ public class PackageManagerService implements PackageSender, TestUtilityService String getDeveloperVerificationPolicyDelegatePackageName() { return mDeveloperVerificationPolicyDelegatePackage; } /** * @return The update-owner of the given package name as specified in the system config file. */ @Nullable public String getSystemAppUpdateOwnerPackageName(String packageName) { return mInjector.getSystemConfig().getSystemAppUpdateOwnerPackageName(packageName); } } services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt +141 −2 Original line number Diff line number Diff line Loading @@ -28,11 +28,14 @@ import android.content.pm.verify.domain.DomainSet import android.os.Parcel import android.os.PersistableBundle import android.os.Process import android.os.UserHandle import android.platform.test.annotations.Presubmit import android.util.AtomicFile import android.util.Slog import android.util.Xml import com.android.internal.os.BackgroundThread import com.android.internal.pm.parsing.pkg.AndroidPackageInternal import com.android.server.pm.pkg.PackageStateInternal import com.android.server.pm.verify.developer.DeveloperVerifierController import com.android.server.testutils.whenever import com.google.common.truth.Truth.assertThat Loading @@ -49,6 +52,7 @@ import org.junit.rules.TemporaryFolder import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyLong import org.mockito.ArgumentMatchers.anyString import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.MockitoAnnotations Loading @@ -62,6 +66,7 @@ class PackageInstallerSessionTest { private const val TAG_SESSIONS = "sessions" private const val TEST_KEY_FOR_EXTENSION_PARAMS = "testKey" private const val TEST_VALUE_FOR_EXTENSION_PARAMS = "testValue" private const val USER_ID = 456 } @JvmField Loading @@ -73,6 +78,8 @@ class PackageInstallerSessionTest { @Mock lateinit var mMockPackageManagerInternal: PackageManagerService @Mock lateinit var mMockDeveloperVerifierController: DeveloperVerifierController @Mock lateinit var mSnapshot: Computer Loading Loading @@ -151,6 +158,138 @@ class PackageInstallerSessionTest { writeRestoreAssert(listOf(session, childSession1, childSession2)) } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassReturnsFalseForNullPackageName() { // Test no package name val session = createSession() assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( null, mSnapshot)).isFalse() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassReturnsFalseForNonVerifierPackageName() { // Test no verifier package name whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn(null) val session = createSession() assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( "testPackageName", mSnapshot)).isFalse() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassReturnsFalseForNonPreinstalledApp() { val testPackageName = "testPackageName" val session = createSession() whenever(mSnapshot.getPackageStateInternal(eq(testPackageName), eq(Process.SYSTEM_UID))) .thenReturn(null) assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( testPackageName, mSnapshot)).isFalse() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassReturnsFalseForNonSystemApp() { val testPackageName = "testPackageName" val session = createSession() val mockPs = mock(PackageStateInternal::class.java) whenever(mockPs.isSystem).thenReturn(false) whenever(mSnapshot.getPackageStateInternal(eq(testPackageName), eq(Process.SYSTEM_UID))) .thenReturn(mockPs) assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( testPackageName, mSnapshot)).isFalse() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassForVerifier() { val verifierPackageName = "verifierPackageName" val mockPs = mock(PackageStateInternal::class.java) whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn( verifierPackageName) whenever(mockPs.isSystem).thenReturn(true) whenever(mSnapshot.getPackageStateInternal( eq(verifierPackageName), eq(Process.SYSTEM_UID))) .thenReturn(mockPs) val session = createSession() assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( verifierPackageName, mSnapshot)).isTrue() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassReturnsFalseForNonUpdateOwner() { val verifierPackageName = "verifierPackageName" val updateOwnerName = "updateOwnerPackageName" val mockPs = mock(PackageStateInternal::class.java) whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn( verifierPackageName) whenever(mockPs.isSystem).thenReturn(true) whenever(mSnapshot.getPackageStateInternal( eq(updateOwnerName), eq(Process.SYSTEM_UID))) .thenReturn(mockPs) whenever(mMockPackageManagerInternal.getSystemAppUpdateOwnerPackageName( anyString())).thenReturn(null) val session = createSession() assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( updateOwnerName, mSnapshot)).isFalse() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassForUpdateOwner() { val verifierPackageName = "verifierPackageName" val updateOwnerName = "updateOwnerPackageName" val mockPs = mock(PackageStateInternal::class.java) whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn( verifierPackageName) whenever(mockPs.isSystem).thenReturn(true) whenever(mSnapshot.getPackageStateInternal( eq(updateOwnerName), eq(Process.SYSTEM_UID))) .thenReturn(mockPs) whenever(mMockPackageManagerInternal.getSystemAppUpdateOwnerPackageName( eq(verifierPackageName))).thenReturn(updateOwnerName) val session = createSession() assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( updateOwnerName, mSnapshot)).isTrue() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassForEmergencyInstaller() { val verifierPackageName = "verifierPackageName" val updateOwnerName = "updateOwnerPackageName" val emergencyInstallerPackageName = "emergencyInstallerPackageName" val mockPs = mock(PackageStateInternal::class.java) val mockUpdateOwnerPs = mock(PackageStateInternal::class.java) val mockUpdateOwnerPkg = mock(AndroidPackageInternal::class.java) val mockUid = 10001 val mockUpdateOwnerUid = 10200 whenever(mockPs.appId).thenReturn(mockUid) whenever(mockUpdateOwnerPs.appId).thenReturn(mockUpdateOwnerUid) whenever(mockUpdateOwnerPkg.emergencyInstaller).thenReturn( emergencyInstallerPackageName) whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn( verifierPackageName) whenever(mockPs.isSystem).thenReturn(true) whenever(mockUpdateOwnerPs.isSystem).thenReturn(true) whenever(mockUpdateOwnerPs.pkg).thenReturn(mockUpdateOwnerPkg) whenever(mSnapshot.getPackageStateInternal( eq(updateOwnerName), eq(Process.SYSTEM_UID))) .thenReturn(mockUpdateOwnerPs) whenever(mSnapshot.getPackageStateInternal( eq(updateOwnerName))) .thenReturn(mockUpdateOwnerPs) whenever(mSnapshot.getPackageStateInternal( eq(emergencyInstallerPackageName), eq(Process.SYSTEM_UID))) .thenReturn(mockPs) whenever(mSnapshot.getPackagesForUid(eq(mockUid))).thenReturn( listOf(emergencyInstallerPackageName).toTypedArray()) whenever(mSnapshot.checkUidPermission(anyString(), eq(UserHandle.getUid(USER_ID, mockUpdateOwnerUid)))) .thenReturn(PackageManager.PERMISSION_GRANTED) whenever(mSnapshot.checkUidPermission(anyString(), eq(mockUid))) .thenReturn(PackageManager.PERMISSION_GRANTED) whenever(mMockPackageManagerInternal.getSystemAppUpdateOwnerPackageName( eq(verifierPackageName))).thenReturn(updateOwnerName) val session = createSession() assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( emergencyInstallerPackageName, mSnapshot)).isTrue() } private fun createSession( staged: Boolean = false, sessionId: Int = 123, Loading Loading @@ -183,7 +322,7 @@ class PackageInstallerSessionTest { /* looper */ BackgroundThread.getHandler().looper, /* stagingManager */ null, /* sessionId */ sessionId, /* userId */ 456, /* userId */ USER_ID, /* installerUid */ Process.myUid(), /* installSource */ installSource, /* sessionParams */ params, Loading @@ -205,7 +344,7 @@ class PackageInstallerSessionTest { /* stagedSessionErrorCode */ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, /* stagedSessionErrorMessage */ "some error", /* preVerifiedDomains */ DomainSet(setOf("com.foo", "com.bar")), /* VerifierController */ mock(DeveloperVerifierController::class.java), /* VerifierController */ mMockDeveloperVerifierController, /* initialVerificationPolicy */ DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_OPEN, /* currentVerificationPolicy */ DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_CLOSED, /* installDependencyHelper */ null Loading Loading
services/core/java/com/android/server/pm/InstallPackageHelper.java +2 −5 Original line number Diff line number Diff line Loading @@ -175,7 +175,6 @@ import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; import com.android.server.EventLogTags; import com.android.server.SystemConfig; import com.android.server.criticalevents.CriticalEventLog; import com.android.server.pm.dex.DexManager; import com.android.server.pm.parsing.PackageCacher; Loading Loading @@ -336,8 +335,7 @@ final class InstallPackageHelper { final String oldUpdateOwner = pkgAlreadyExists ? oldPkgSetting.getInstallSource().mUpdateOwnerPackageName : null; final String updateOwnerFromSysconfig = isApex || !pkgSetting.isSystem() ? null : mPm.mInjector.getSystemConfig().getSystemAppUpdateOwnerPackageName( parsedPackage.getPackageName()); : mPm.getSystemAppUpdateOwnerPackageName(parsedPackage.getPackageName()); final boolean isUpdateOwnershipDenylisted = mUpdateOwnershipHelper.isUpdateOwnershipDenylisted(parsedPackage.getPackageName()); final boolean isUpdateOwnershipEnabled = oldUpdateOwner != null; Loading Loading @@ -483,12 +481,11 @@ final class InstallPackageHelper { if (listItems != null && !listItems.isEmpty()) { mUpdateOwnershipHelper.addToUpdateOwnerDenyList(pkgSetting.getPackageName(), listItems); SystemConfig config = SystemConfig.getInstance(); synchronized (mPm.mLock) { for (String unownedPackage : listItems) { PackageSetting unownedSetting = mPm.mSettings.getPackageLPr(unownedPackage); if (unownedSetting != null && config.getSystemAppUpdateOwnerPackageName(unownedPackage) == null) { && mPm.getSystemAppUpdateOwnerPackageName(unownedPackage) == null) { unownedSetting.setUpdateOwnerPackage(null); } } Loading
services/core/java/com/android/server/pm/PackageInstallerSession.java +86 −7 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFIC import static android.content.pm.PackageManager.INSTALL_STAGED; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.content.pm.verify.developer.DeveloperVerificationSession.DEVELOPER_VERIFICATION_BYPASSED_REASON_ADB; import static android.content.pm.verify.developer.DeveloperVerificationSession.DEVELOPER_VERIFICATION_BYPASSED_REASON_EMERGENCY; import static android.content.pm.verify.developer.DeveloperVerificationSession.DEVELOPER_VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE; import static android.os.Process.INVALID_UID; import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; Loading Loading @@ -3090,18 +3091,63 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return false; } } return true; } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) boolean shouldAllowDeveloperVerificationEmergencyBypass(String packageName, Computer snapshot) { final String verifierPackageName = mDeveloperVerifierController.getVerifierPackageName(); synchronized (mLock) { if (TextUtils.equals(verifierPackageName, mPackageName)) { // The verifier itself is being updated. Skip. // TODO(b/360129657): log bypass reason and this bypass should only happen if the // current verifier cannot be connected or isn't responding. Slog.w(TAG, "Skipping verification service because the verifier is being updated"); if (verifierPackageName == null) { // Impossible condition. The verifier must exist because otherwise we wouldn't get // here. Added to prevent lint warnings. return false; } if (packageName == null) { return false; } PackageStateInternal ps = snapshot.getPackageStateInternal(packageName, Process.SYSTEM_UID); if (ps == null || !ps.isSystem()) { // The app being installed must be a system app to be considered a critical app for // the emergency bypass. return false; } // Check if app being installed is the verifier itself. if (TextUtils.equals(verifierPackageName, packageName)) { Slog.d(TAG, "Bypassing developer verification because the verifier is being updated"); return true; } // Check if app being installed is the sysconfig-specified update-owner of the verifier. final String updateOwnerPackageName = mPm.getSystemAppUpdateOwnerPackageName( verifierPackageName); if (updateOwnerPackageName == null) { // No sysconfig-specified update-owner for the verifier. No need to check further. return false; } if (TextUtils.equals(updateOwnerPackageName, packageName)) { Slog.d(TAG, "Bypassing verification service because the sysconfig-specified " + "update owner of the verifier is being updated"); return true; } // Check if app being installed is the emergency installer of the sysconfig-specified // update-owner of the verifier. if (isEmergencyInstallerEnabled(updateOwnerPackageName, snapshot, userId, ps.getAppId())) { final PackageStateInternal psUpdateOwner = snapshot.getPackageStateInternal( updateOwnerPackageName, Process.SYSTEM_UID); if (psUpdateOwner == null || psUpdateOwner.getPkg() == null) { // Impossible condition, because the if clause above already checked this. // Added to prevent lint warnings. return false; } String emergencyInstallerPackageName = psUpdateOwner.getPkg().getEmergencyInstaller(); if (emergencyInstallerPackageName != null && TextUtils.equals(emergencyInstallerPackageName, packageName)) { Slog.d(TAG, "Bypassing verification service because the " + "emergency installer of the verifier's update owner is being updated"); return true; } } return false; } private void retryDeveloperVerificationSession(Supplier<Computer> snapshotSupplier) { final SigningInfo signingInfo; Loading Loading @@ -3241,6 +3287,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { resumeVerify(); return; } if (shouldAllowDeveloperVerificationEmergencyBypass( getPackageName(), mPm.snapshotComputer())) { // Bypass verification when critical package is being updated and the verifier // cannot be connected. synchronized (mMetrics) { mMetrics.onDeveloperVerificationBypassed( DEVELOPER_VERIFICATION_BYPASSED_REASON_EMERGENCY); } resumeVerify(); return; } mVerificationUserActionNeededReason = DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN; Loading @@ -3267,6 +3324,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { resumeVerify(); return; } if (shouldAllowDeveloperVerificationEmergencyBypass( getPackageName(), mPm.snapshotComputer())) { // Bypass verification when critical package is being updated and the verifier // cannot be connected. synchronized (mMetrics) { mMetrics.onDeveloperVerificationBypassed( DEVELOPER_VERIFICATION_BYPASSED_REASON_EMERGENCY); } resumeVerify(); return; } mVerificationUserActionNeededReason = DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN; Loading Loading @@ -3304,6 +3372,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { resumeVerify(); return; } if (shouldAllowDeveloperVerificationEmergencyBypass( getPackageName(), mPm.snapshotComputer())) { // Bypass verification when critical package is being updated and the verifier // has timed out. synchronized (mMetrics) { mMetrics.onDeveloperVerificationBypassed( DEVELOPER_VERIFICATION_BYPASSED_REASON_EMERGENCY); } resumeVerify(); return; } mVerificationUserActionNeededReason = DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN; Loading
services/core/java/com/android/server/pm/PackageManagerService.java +8 −0 Original line number Diff line number Diff line Loading @@ -8450,4 +8450,12 @@ public class PackageManagerService implements PackageSender, TestUtilityService String getDeveloperVerificationPolicyDelegatePackageName() { return mDeveloperVerificationPolicyDelegatePackage; } /** * @return The update-owner of the given package name as specified in the system config file. */ @Nullable public String getSystemAppUpdateOwnerPackageName(String packageName) { return mInjector.getSystemConfig().getSystemAppUpdateOwnerPackageName(packageName); } }
services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt +141 −2 Original line number Diff line number Diff line Loading @@ -28,11 +28,14 @@ import android.content.pm.verify.domain.DomainSet import android.os.Parcel import android.os.PersistableBundle import android.os.Process import android.os.UserHandle import android.platform.test.annotations.Presubmit import android.util.AtomicFile import android.util.Slog import android.util.Xml import com.android.internal.os.BackgroundThread import com.android.internal.pm.parsing.pkg.AndroidPackageInternal import com.android.server.pm.pkg.PackageStateInternal import com.android.server.pm.verify.developer.DeveloperVerifierController import com.android.server.testutils.whenever import com.google.common.truth.Truth.assertThat Loading @@ -49,6 +52,7 @@ import org.junit.rules.TemporaryFolder import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyLong import org.mockito.ArgumentMatchers.anyString import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.MockitoAnnotations Loading @@ -62,6 +66,7 @@ class PackageInstallerSessionTest { private const val TAG_SESSIONS = "sessions" private const val TEST_KEY_FOR_EXTENSION_PARAMS = "testKey" private const val TEST_VALUE_FOR_EXTENSION_PARAMS = "testValue" private const val USER_ID = 456 } @JvmField Loading @@ -73,6 +78,8 @@ class PackageInstallerSessionTest { @Mock lateinit var mMockPackageManagerInternal: PackageManagerService @Mock lateinit var mMockDeveloperVerifierController: DeveloperVerifierController @Mock lateinit var mSnapshot: Computer Loading Loading @@ -151,6 +158,138 @@ class PackageInstallerSessionTest { writeRestoreAssert(listOf(session, childSession1, childSession2)) } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassReturnsFalseForNullPackageName() { // Test no package name val session = createSession() assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( null, mSnapshot)).isFalse() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassReturnsFalseForNonVerifierPackageName() { // Test no verifier package name whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn(null) val session = createSession() assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( "testPackageName", mSnapshot)).isFalse() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassReturnsFalseForNonPreinstalledApp() { val testPackageName = "testPackageName" val session = createSession() whenever(mSnapshot.getPackageStateInternal(eq(testPackageName), eq(Process.SYSTEM_UID))) .thenReturn(null) assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( testPackageName, mSnapshot)).isFalse() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassReturnsFalseForNonSystemApp() { val testPackageName = "testPackageName" val session = createSession() val mockPs = mock(PackageStateInternal::class.java) whenever(mockPs.isSystem).thenReturn(false) whenever(mSnapshot.getPackageStateInternal(eq(testPackageName), eq(Process.SYSTEM_UID))) .thenReturn(mockPs) assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( testPackageName, mSnapshot)).isFalse() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassForVerifier() { val verifierPackageName = "verifierPackageName" val mockPs = mock(PackageStateInternal::class.java) whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn( verifierPackageName) whenever(mockPs.isSystem).thenReturn(true) whenever(mSnapshot.getPackageStateInternal( eq(verifierPackageName), eq(Process.SYSTEM_UID))) .thenReturn(mockPs) val session = createSession() assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( verifierPackageName, mSnapshot)).isTrue() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassReturnsFalseForNonUpdateOwner() { val verifierPackageName = "verifierPackageName" val updateOwnerName = "updateOwnerPackageName" val mockPs = mock(PackageStateInternal::class.java) whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn( verifierPackageName) whenever(mockPs.isSystem).thenReturn(true) whenever(mSnapshot.getPackageStateInternal( eq(updateOwnerName), eq(Process.SYSTEM_UID))) .thenReturn(mockPs) whenever(mMockPackageManagerInternal.getSystemAppUpdateOwnerPackageName( anyString())).thenReturn(null) val session = createSession() assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( updateOwnerName, mSnapshot)).isFalse() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassForUpdateOwner() { val verifierPackageName = "verifierPackageName" val updateOwnerName = "updateOwnerPackageName" val mockPs = mock(PackageStateInternal::class.java) whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn( verifierPackageName) whenever(mockPs.isSystem).thenReturn(true) whenever(mSnapshot.getPackageStateInternal( eq(updateOwnerName), eq(Process.SYSTEM_UID))) .thenReturn(mockPs) whenever(mMockPackageManagerInternal.getSystemAppUpdateOwnerPackageName( eq(verifierPackageName))).thenReturn(updateOwnerName) val session = createSession() assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( updateOwnerName, mSnapshot)).isTrue() } @Test fun testShouldAllowDeveloperVerificationEmergencyBypassForEmergencyInstaller() { val verifierPackageName = "verifierPackageName" val updateOwnerName = "updateOwnerPackageName" val emergencyInstallerPackageName = "emergencyInstallerPackageName" val mockPs = mock(PackageStateInternal::class.java) val mockUpdateOwnerPs = mock(PackageStateInternal::class.java) val mockUpdateOwnerPkg = mock(AndroidPackageInternal::class.java) val mockUid = 10001 val mockUpdateOwnerUid = 10200 whenever(mockPs.appId).thenReturn(mockUid) whenever(mockUpdateOwnerPs.appId).thenReturn(mockUpdateOwnerUid) whenever(mockUpdateOwnerPkg.emergencyInstaller).thenReturn( emergencyInstallerPackageName) whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn( verifierPackageName) whenever(mockPs.isSystem).thenReturn(true) whenever(mockUpdateOwnerPs.isSystem).thenReturn(true) whenever(mockUpdateOwnerPs.pkg).thenReturn(mockUpdateOwnerPkg) whenever(mSnapshot.getPackageStateInternal( eq(updateOwnerName), eq(Process.SYSTEM_UID))) .thenReturn(mockUpdateOwnerPs) whenever(mSnapshot.getPackageStateInternal( eq(updateOwnerName))) .thenReturn(mockUpdateOwnerPs) whenever(mSnapshot.getPackageStateInternal( eq(emergencyInstallerPackageName), eq(Process.SYSTEM_UID))) .thenReturn(mockPs) whenever(mSnapshot.getPackagesForUid(eq(mockUid))).thenReturn( listOf(emergencyInstallerPackageName).toTypedArray()) whenever(mSnapshot.checkUidPermission(anyString(), eq(UserHandle.getUid(USER_ID, mockUpdateOwnerUid)))) .thenReturn(PackageManager.PERMISSION_GRANTED) whenever(mSnapshot.checkUidPermission(anyString(), eq(mockUid))) .thenReturn(PackageManager.PERMISSION_GRANTED) whenever(mMockPackageManagerInternal.getSystemAppUpdateOwnerPackageName( eq(verifierPackageName))).thenReturn(updateOwnerName) val session = createSession() assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass( emergencyInstallerPackageName, mSnapshot)).isTrue() } private fun createSession( staged: Boolean = false, sessionId: Int = 123, Loading Loading @@ -183,7 +322,7 @@ class PackageInstallerSessionTest { /* looper */ BackgroundThread.getHandler().looper, /* stagingManager */ null, /* sessionId */ sessionId, /* userId */ 456, /* userId */ USER_ID, /* installerUid */ Process.myUid(), /* installSource */ installSource, /* sessionParams */ params, Loading @@ -205,7 +344,7 @@ class PackageInstallerSessionTest { /* stagedSessionErrorCode */ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, /* stagedSessionErrorMessage */ "some error", /* preVerifiedDomains */ DomainSet(setOf("com.foo", "com.bar")), /* VerifierController */ mock(DeveloperVerifierController::class.java), /* VerifierController */ mMockDeveloperVerifierController, /* initialVerificationPolicy */ DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_OPEN, /* currentVerificationPolicy */ DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_CLOSED, /* installDependencyHelper */ null Loading