Loading services/core/java/com/android/server/pm/PackageArchiver.java +21 −13 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.VersionedPackage; import android.graphics.Bitmap; import android.graphics.BitmapFactory; Loading @@ -48,6 +50,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.Environment; import android.os.ParcelableException; import android.os.Process; import android.os.SELinux; import android.os.UserHandle; import android.text.TextUtils; Loading Loading @@ -162,15 +165,13 @@ public class PackageArchiver { }); } /** * Creates archived state for the package and user. */ public CompletableFuture<ArchiveState> createArchiveState(String packageName, int userId) /** Creates archived state for the package and user. */ private CompletableFuture<ArchiveState> createArchiveState(String packageName, int userId) throws PackageManager.NameNotFoundException { PackageStateInternal ps = getPackageState(packageName, mPm.snapshotComputer(), Binder.getCallingUid(), userId); String responsibleInstallerPackage = getResponsibleInstallerPackage(ps); verifyInstaller(responsibleInstallerPackage); verifyInstaller(responsibleInstallerPackage, userId); List<LauncherActivityInfo> mainActivities = getLauncherActivityInfos(ps.getPackageName(), userId); Loading Loading @@ -268,27 +269,34 @@ public class PackageArchiver { return iconFile.toPath(); } private void verifyInstaller(String installerPackage) private void verifyInstaller(String installerPackage, int userId) throws PackageManager.NameNotFoundException { if (TextUtils.isEmpty(installerPackage)) { throw new PackageManager.NameNotFoundException("No installer found"); } if (!verifySupportsUnarchival(installerPackage)) { // Allow shell for easier development. if ((Binder.getCallingUid() != Process.SHELL_UID) && !verifySupportsUnarchival(installerPackage, userId)) { throw new PackageManager.NameNotFoundException("Installer does not support unarchival"); } } /** * @return true if installerPackage support unarchival: * - has an action Intent.ACTION_UNARCHIVE_PACKAGE, * - has permissions to install packages. * Returns true if {@code installerPackage} supports unarchival being able to handle * {@link Intent#ACTION_UNARCHIVE_PACKAGE} */ public boolean verifySupportsUnarchival(String installerPackage) { // TODO(b/278553670) Check if installerPackage supports unarchival. public boolean verifySupportsUnarchival(String installerPackage, int userId) { if (TextUtils.isEmpty(installerPackage)) { return false; } return true; Intent intent = new Intent(Intent.ACTION_UNARCHIVE_PACKAGE).setPackage(installerPackage); ParceledListSlice<ResolveInfo> intentReceivers = Binder.withCleanCallingIdentity( () -> mPm.queryIntentReceivers(mPm.snapshotComputer(), intent, /* resolvedType= */ null, /* flags= */ 0, userId)); return intentReceivers != null && !intentReceivers.getList().isEmpty(); } void requestUnarchive( Loading services/core/java/com/android/server/pm/PackageInstallerSession.java +1 −1 Original line number Diff line number Diff line Loading @@ -3445,7 +3445,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } if (!mPm.mInstallerService.mPackageArchiver.verifySupportsUnarchival( getInstallSource().mInstallerPackageName)) { getInstallSource().mInstallerPackageName, userId)) { throw new PackageManagerException( PackageManager.INSTALL_FAILED_SESSION_INVALID, "Installer has to support unarchival in order to install archived " Loading services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +26 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.doReturn; Loading @@ -44,6 +45,8 @@ import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.VersionedPackage; import android.content.res.Resources; import android.graphics.Bitmap; Loading Loading @@ -122,6 +125,8 @@ public class PackageArchiverTest { private PackageSetting mPackageSetting; private PackageManagerService mPackageManagerService; private PackageArchiver mArchiveManager; @Before Loading @@ -130,7 +135,7 @@ public class PackageArchiverTest { rule.system().stageNominalSystemState(); when(rule.mocks().getInjector().getPackageInstallerService()).thenReturn( mInstallerService); PackageManagerService pm = spy(new PackageManagerService(rule.mocks().getInjector(), mPackageManagerService = spy(new PackageManagerService(rule.mocks().getInjector(), /* factoryTest= */false, MockSystem.Companion.getDEFAULT_VERSION_INFO().fingerprint, /* isEngBuild= */ false, Loading @@ -154,15 +159,18 @@ public class PackageArchiverTest { when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps); when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn( mLauncherActivityInfos); doReturn(mComputer).when(pm).snapshotComputer(); doReturn(mComputer).when(mPackageManagerService).snapshotComputer(); when(mComputer.getPackageUid(eq(CALLER_PACKAGE), eq(0L), eq(mUserId))).thenReturn( Binder.getCallingUid()); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getResourcesForApplication(eq(PACKAGE))).thenReturn( mock(Resources.class)); doReturn(new ParceledListSlice<>(List.of(mock(ResolveInfo.class)))) .when(mPackageManagerService).queryIntentReceivers(any(), any(), any(), anyLong(), eq(mUserId)); mArchiveManager = spy(new PackageArchiver(mContext, pm)); mArchiveManager = spy(new PackageArchiver(mContext, mPackageManagerService)); doReturn(ICON_PATH).when(mArchiveManager).storeIcon(eq(PACKAGE), any(LauncherActivityInfo.class), eq(mUserId), anyInt()); doReturn(mIcon).when(mArchiveManager).decodeIcon( Loading Loading @@ -236,6 +244,21 @@ public class PackageArchiverTest { assertThat(e.getCause()).hasMessageThat().isEqualTo("No installer found"); } @Test public void archiveApp_installerDoesntSupportUnarchival() { doReturn(new ParceledListSlice<>(List.of())) .when(mPackageManagerService).queryIntentReceivers(any(), any(), any(), anyLong(), eq(mUserId)); Exception e = assertThrows( ParcelableException.class, () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT)); assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); assertThat(e.getCause()).hasMessageThat().isEqualTo( "Installer does not support unarchival"); } @Test public void archiveApp_noMainActivities() { when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn( Loading Loading
services/core/java/com/android/server/pm/PackageArchiver.java +21 −13 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.VersionedPackage; import android.graphics.Bitmap; import android.graphics.BitmapFactory; Loading @@ -48,6 +50,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.Environment; import android.os.ParcelableException; import android.os.Process; import android.os.SELinux; import android.os.UserHandle; import android.text.TextUtils; Loading Loading @@ -162,15 +165,13 @@ public class PackageArchiver { }); } /** * Creates archived state for the package and user. */ public CompletableFuture<ArchiveState> createArchiveState(String packageName, int userId) /** Creates archived state for the package and user. */ private CompletableFuture<ArchiveState> createArchiveState(String packageName, int userId) throws PackageManager.NameNotFoundException { PackageStateInternal ps = getPackageState(packageName, mPm.snapshotComputer(), Binder.getCallingUid(), userId); String responsibleInstallerPackage = getResponsibleInstallerPackage(ps); verifyInstaller(responsibleInstallerPackage); verifyInstaller(responsibleInstallerPackage, userId); List<LauncherActivityInfo> mainActivities = getLauncherActivityInfos(ps.getPackageName(), userId); Loading Loading @@ -268,27 +269,34 @@ public class PackageArchiver { return iconFile.toPath(); } private void verifyInstaller(String installerPackage) private void verifyInstaller(String installerPackage, int userId) throws PackageManager.NameNotFoundException { if (TextUtils.isEmpty(installerPackage)) { throw new PackageManager.NameNotFoundException("No installer found"); } if (!verifySupportsUnarchival(installerPackage)) { // Allow shell for easier development. if ((Binder.getCallingUid() != Process.SHELL_UID) && !verifySupportsUnarchival(installerPackage, userId)) { throw new PackageManager.NameNotFoundException("Installer does not support unarchival"); } } /** * @return true if installerPackage support unarchival: * - has an action Intent.ACTION_UNARCHIVE_PACKAGE, * - has permissions to install packages. * Returns true if {@code installerPackage} supports unarchival being able to handle * {@link Intent#ACTION_UNARCHIVE_PACKAGE} */ public boolean verifySupportsUnarchival(String installerPackage) { // TODO(b/278553670) Check if installerPackage supports unarchival. public boolean verifySupportsUnarchival(String installerPackage, int userId) { if (TextUtils.isEmpty(installerPackage)) { return false; } return true; Intent intent = new Intent(Intent.ACTION_UNARCHIVE_PACKAGE).setPackage(installerPackage); ParceledListSlice<ResolveInfo> intentReceivers = Binder.withCleanCallingIdentity( () -> mPm.queryIntentReceivers(mPm.snapshotComputer(), intent, /* resolvedType= */ null, /* flags= */ 0, userId)); return intentReceivers != null && !intentReceivers.getList().isEmpty(); } void requestUnarchive( Loading
services/core/java/com/android/server/pm/PackageInstallerSession.java +1 −1 Original line number Diff line number Diff line Loading @@ -3445,7 +3445,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } if (!mPm.mInstallerService.mPackageArchiver.verifySupportsUnarchival( getInstallSource().mInstallerPackageName)) { getInstallSource().mInstallerPackageName, userId)) { throw new PackageManagerException( PackageManager.INSTALL_FAILED_SESSION_INVALID, "Installer has to support unarchival in order to install archived " Loading
services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +26 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.doReturn; Loading @@ -44,6 +45,8 @@ import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.VersionedPackage; import android.content.res.Resources; import android.graphics.Bitmap; Loading Loading @@ -122,6 +125,8 @@ public class PackageArchiverTest { private PackageSetting mPackageSetting; private PackageManagerService mPackageManagerService; private PackageArchiver mArchiveManager; @Before Loading @@ -130,7 +135,7 @@ public class PackageArchiverTest { rule.system().stageNominalSystemState(); when(rule.mocks().getInjector().getPackageInstallerService()).thenReturn( mInstallerService); PackageManagerService pm = spy(new PackageManagerService(rule.mocks().getInjector(), mPackageManagerService = spy(new PackageManagerService(rule.mocks().getInjector(), /* factoryTest= */false, MockSystem.Companion.getDEFAULT_VERSION_INFO().fingerprint, /* isEngBuild= */ false, Loading @@ -154,15 +159,18 @@ public class PackageArchiverTest { when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps); when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn( mLauncherActivityInfos); doReturn(mComputer).when(pm).snapshotComputer(); doReturn(mComputer).when(mPackageManagerService).snapshotComputer(); when(mComputer.getPackageUid(eq(CALLER_PACKAGE), eq(0L), eq(mUserId))).thenReturn( Binder.getCallingUid()); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getResourcesForApplication(eq(PACKAGE))).thenReturn( mock(Resources.class)); doReturn(new ParceledListSlice<>(List.of(mock(ResolveInfo.class)))) .when(mPackageManagerService).queryIntentReceivers(any(), any(), any(), anyLong(), eq(mUserId)); mArchiveManager = spy(new PackageArchiver(mContext, pm)); mArchiveManager = spy(new PackageArchiver(mContext, mPackageManagerService)); doReturn(ICON_PATH).when(mArchiveManager).storeIcon(eq(PACKAGE), any(LauncherActivityInfo.class), eq(mUserId), anyInt()); doReturn(mIcon).when(mArchiveManager).decodeIcon( Loading Loading @@ -236,6 +244,21 @@ public class PackageArchiverTest { assertThat(e.getCause()).hasMessageThat().isEqualTo("No installer found"); } @Test public void archiveApp_installerDoesntSupportUnarchival() { doReturn(new ParceledListSlice<>(List.of())) .when(mPackageManagerService).queryIntentReceivers(any(), any(), any(), anyLong(), eq(mUserId)); Exception e = assertThrows( ParcelableException.class, () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT)); assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); assertThat(e.getCause()).hasMessageThat().isEqualTo( "Installer does not support unarchival"); } @Test public void archiveApp_noMainActivities() { when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn( Loading