diff options
| -rw-r--r-- | services/core/java/com/android/server/pm/DeletePackageHelper.java | 13 | ||||
| -rw-r--r-- | services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt | 148 |
2 files changed, 161 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java index 339d5d4fe021..c3b479219853 100644 --- a/services/core/java/com/android/server/pm/DeletePackageHelper.java +++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java @@ -43,6 +43,7 @@ import android.content.pm.PackageChangeEvent; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.SharedLibraryInfo; +import android.content.pm.UserInfo; import android.content.pm.VersionedPackage; import android.net.Uri; import android.os.Binder; @@ -163,6 +164,18 @@ final class DeletePackageHelper { return PackageManager.DELETE_FAILED_INTERNAL_ERROR; } + if (PackageManagerServiceUtils.isSystemApp(uninstalledPs) + && ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) { + UserInfo userInfo = mUserManagerInternal.getUserInfo(userId); + if (userInfo == null || (!userInfo.isAdmin() && !mUserManagerInternal.getUserInfo( + mUserManagerInternal.getProfileParentId(userId)).isAdmin())) { + Slog.w(TAG, "Not removing package " + packageName + + " as only admin user (or their profile) may downgrade system apps"); + EventLog.writeEvent(0x534e4554, "170646036", -1, packageName); + return PackageManager.DELETE_FAILED_USER_RESTRICTED; + } + } + disabledSystemPs = mPm.mSettings.getDisabledSystemPkgLPr(packageName); // 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. diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt new file mode 100644 index 000000000000..3c3172ba3a13 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2022 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 + +import android.content.pm.PackageManager +import android.content.pm.UserInfo +import android.os.Build +import android.util.Log +import com.android.server.testutils.any +import com.android.server.testutils.spy +import com.android.server.testutils.whenever +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.Mockito.doAnswer + +@RunWith(JUnit4::class) +class DeletePackageHelperTest { + + @Rule + @JvmField + val rule = MockSystemRule() + + private lateinit var mPms: PackageManagerService + private lateinit var mUserManagerInternal: UserManagerInternal + + @Before + @Throws(Exception::class) + fun setup() { + Log.i("system.out", "setup", Exception()) + rule.system().stageNominalSystemState() + rule.system().stageScanExistingPackage( + "a.data.package", 1L, rule.system().dataAppDirectory) + + mUserManagerInternal = rule.mocks().injector.userManagerInternal + whenever(mUserManagerInternal.getUserIds()).thenReturn(intArrayOf(0, 1)) + + mPms = createPackageManagerService() + doAnswer { false }.`when`(mPms).isPackageDeviceAdmin(any(), any()) + doAnswer { null }.`when`(mPms).freezePackageForDelete(any(), any(), any(), any()) + } + + private fun createPackageManagerService(): PackageManagerService { + return spy(PackageManagerService(rule.mocks().injector, + false /*coreOnly*/, + false /*factoryTest*/, + MockSystem.DEFAULT_VERSION_INFO.fingerprint, + false /*isEngBuild*/, + false /*isUserDebugBuild*/, + Build.VERSION_CODES.CUR_DEVELOPMENT, + Build.VERSION.INCREMENTAL)) + } + + @Test + fun deleteSystemPackageFailsIfNotAdminAndNotProfile() { + val ps = mPms.mSettings.getPackageLPr("a.data.package") + whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true) + whenever(mUserManagerInternal.getUserInfo(1)).thenReturn(UserInfo(1, "test", 0)) + whenever(mUserManagerInternal.getProfileParentId(1)).thenReturn(1) + + val dph = DeletePackageHelper(mPms) + val result = dph.deletePackageX("a.data.package", 1L, 1, 0, false) + + assertThat(result).isEqualTo(PackageManager.DELETE_FAILED_USER_RESTRICTED) + } + + @Test + fun deleteSystemPackageFailsIfProfileOfNonAdmin() { + val userId = 1 + val parentId = 5 + val ps = mPms.mSettings.getPackageLPr("a.data.package") + whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true) + whenever(mUserManagerInternal.getUserInfo(userId)).thenReturn( + UserInfo(userId, "test", UserInfo.FLAG_PROFILE)) + whenever(mUserManagerInternal.getProfileParentId(userId)).thenReturn(parentId) + whenever(mUserManagerInternal.getUserInfo(parentId)).thenReturn( + UserInfo(userId, "testparent", 0)) + + val dph = DeletePackageHelper(mPms) + val result = dph.deletePackageX("a.data.package", 1L, userId, 0, false) + + assertThat(result).isEqualTo(PackageManager.DELETE_FAILED_USER_RESTRICTED) + } + + @Test + fun deleteSystemPackageSucceedsIfAdmin() { + val ps = mPms.mSettings.getPackageLPr("a.data.package") + whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true) + whenever(mUserManagerInternal.getUserInfo(1)).thenReturn( + UserInfo(1, "test", UserInfo.FLAG_ADMIN)) + + val dph = DeletePackageHelper(mPms) + val result = dph.deletePackageX("a.data.package", 1L, 1, + PackageManager.DELETE_SYSTEM_APP, false) + + assertThat(result).isEqualTo(PackageManager.DELETE_SUCCEEDED) + } + + @Test + fun deleteSystemPackageSucceedsIfProfileOfAdmin() { + val userId = 1 + val parentId = 5 + val ps = mPms.mSettings.getPackageLPr("a.data.package") + whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true) + whenever(mUserManagerInternal.getUserInfo(userId)).thenReturn( + UserInfo(userId, "test", UserInfo.FLAG_PROFILE)) + whenever(mUserManagerInternal.getProfileParentId(userId)).thenReturn(parentId) + whenever(mUserManagerInternal.getUserInfo(parentId)).thenReturn( + UserInfo(userId, "testparent", UserInfo.FLAG_ADMIN)) + + val dph = DeletePackageHelper(mPms) + val result = dph.deletePackageX("a.data.package", 1L, userId, + PackageManager.DELETE_SYSTEM_APP, false) + + assertThat(result).isEqualTo(PackageManager.DELETE_SUCCEEDED) + } + + @Test + fun deleteSystemPackageSucceedsIfNotAdminButDeleteSystemAppSpecified() { + val ps = mPms.mSettings.getPackageLPr("a.data.package") + whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true) + whenever(mUserManagerInternal.getUserInfo(1)).thenReturn(UserInfo(1, "test", 0)) + whenever(mUserManagerInternal.getProfileParentId(1)).thenReturn(1) + + val dph = DeletePackageHelper(mPms) + val result = dph.deletePackageX("a.data.package", 1L, 1, + PackageManager.DELETE_SYSTEM_APP, false) + + assertThat(result).isEqualTo(PackageManager.DELETE_SUCCEEDED) + } +} |