diff options
9 files changed, 101 insertions, 26 deletions
diff --git a/core/java/android/content/pm/ArchivedActivityParcel.aidl b/core/java/android/content/pm/ArchivedActivityParcel.aidl index 7ab7ed1cc5df..74953fff40d8 100644 --- a/core/java/android/content/pm/ArchivedActivityParcel.aidl +++ b/core/java/android/content/pm/ArchivedActivityParcel.aidl @@ -16,9 +16,12 @@ package android.content.pm; +import android.content.ComponentName; + /** @hide */ parcelable ArchivedActivityParcel { String title; + ComponentName originalComponentName; // PNG compressed bitmaps. byte[] iconBitmap; byte[] monochromeIconBitmap; diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto index eb14db070f9f..068f4dd07ccb 100644 --- a/core/proto/android/service/package.proto +++ b/core/proto/android/service/package.proto @@ -115,6 +115,9 @@ message PackageProto { // Only set if the app defined a monochrome icon. optional string monochrome_icon_bitmap_path = 3; + + // The component name of the original activity (pre-archival). + optional string original_component_name = 4; } /** Information about main activities. */ diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java index f59188e9fd93..0fb1f7a0780c 100644 --- a/services/core/java/com/android/server/pm/PackageArchiver.java +++ b/services/core/java/com/android/server/pm/PackageArchiver.java @@ -196,8 +196,12 @@ public class PackageArchiver { for (int i = 0, size = mainActivities.length; i < size; ++i) { var mainActivity = mainActivities[i]; Path iconPath = storeIconForParcel(packageName, mainActivity, userId, i); - ArchiveActivityInfo activityInfo = new ArchiveActivityInfo( - mainActivity.title, iconPath, null); + ArchiveActivityInfo activityInfo = + new ArchiveActivityInfo( + mainActivity.title, + mainActivity.originalComponentName, + iconPath, + null); archiveActivityInfos.add(activityInfo); } @@ -215,8 +219,12 @@ public class PackageArchiver { for (int i = 0, size = mainActivities.size(); i < size; i++) { LauncherActivityInfo mainActivity = mainActivities.get(i); Path iconPath = storeIcon(packageName, mainActivity, userId, i); - ArchiveActivityInfo activityInfo = new ArchiveActivityInfo( - mainActivity.getLabel().toString(), iconPath, null); + ArchiveActivityInfo activityInfo = + new ArchiveActivityInfo( + mainActivity.getLabel().toString(), + mainActivity.getComponentName(), + iconPath, + null); archiveActivityInfos.add(activityInfo); } @@ -593,6 +601,7 @@ public class PackageArchiver { } var archivedActivity = new ArchivedActivityParcel(); archivedActivity.title = info.getTitle(); + archivedActivity.originalComponentName = info.getOriginalComponentName(); archivedActivity.iconBitmap = bytesFromBitmapFile(info.getIconBitmap()); archivedActivity.monochromeIconBitmap = bytesFromBitmapFile( info.getMonochromeIconBitmap()); @@ -624,6 +633,7 @@ public class PackageArchiver { } var archivedActivity = new ArchivedActivityParcel(); archivedActivity.title = info.getLabel().toString(); + archivedActivity.originalComponentName = info.getComponentName(); archivedActivity.iconBitmap = info.getActivityInfo().getIconResource() == 0 ? null : bytesFromBitmap( drawableToBitmap(info.getIcon(/* density= */ 0))); diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 2e6006465bd9..215a31910da5 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -1201,6 +1201,9 @@ public class PackageSetting extends SettingBase implements PackageStateInternal long activityInfoToken = proto.start( PackageProto.UserInfoProto.ArchiveState.ACTIVITY_INFOS); proto.write(ArchiveActivityInfo.TITLE, activityInfo.getTitle()); + proto.write( + ArchiveActivityInfo.ORIGINAL_COMPONENT_NAME, + activityInfo.getOriginalComponentName().flattenToString()); if (activityInfo.getIconBitmap() != null) { proto.write(ArchiveActivityInfo.ICON_BITMAP_PATH, activityInfo.getIconBitmap().toAbsolutePath().toString()); diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 6e3b538c4849..64411d3738f8 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -368,6 +368,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile private static final String ATTR_VALUE = "value"; private static final String ATTR_FIRST_INSTALL_TIME = "first-install-time"; private static final String ATTR_ARCHIVE_ACTIVITY_TITLE = "activity-title"; + private static final String ATTR_ARCHIVE_ORIGINAL_COMPONENT_NAME = "original-component-name"; private static final String ATTR_ARCHIVE_INSTALLER_TITLE = "installer-title"; private static final String ATTR_ARCHIVE_ICON_PATH = "icon-path"; private static final String ATTR_ARCHIVE_MONOCHROME_ICON_PATH = "monochrome-icon-path"; @@ -2068,6 +2069,8 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile if (tagName.equals(TAG_ARCHIVE_ACTIVITY_INFO)) { String title = parser.getAttributeValue(null, ATTR_ARCHIVE_ACTIVITY_TITLE); + String originalComponentName = + parser.getAttributeValue(null, ATTR_ARCHIVE_ORIGINAL_COMPONENT_NAME); String iconAttribute = parser.getAttributeValue(null, ATTR_ARCHIVE_ICON_PATH); Path iconPath = iconAttribute == null ? null : Path.of(iconAttribute); @@ -2076,17 +2079,27 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile Path monochromeIconPath = monochromeAttribute == null ? null : Path.of( monochromeAttribute); - if (title == null || iconPath == null) { - Slog.wtf(TAG, - TextUtils.formatSimple("Missing attributes in tag %s. %s: %s, %s: %s", - TAG_ARCHIVE_ACTIVITY_INFO, ATTR_ARCHIVE_ACTIVITY_TITLE, title, + if (title == null || originalComponentName == null || iconPath == null) { + Slog.wtf( + TAG, + TextUtils.formatSimple( + "Missing attributes in tag %s. %s: %s, %s: %s, %s: %s", + TAG_ARCHIVE_ACTIVITY_INFO, + ATTR_ARCHIVE_ACTIVITY_TITLE, + title, + ATTR_ARCHIVE_ORIGINAL_COMPONENT_NAME, + originalComponentName, ATTR_ARCHIVE_ICON_PATH, iconPath)); continue; } activityInfos.add( - new ArchiveState.ArchiveActivityInfo(title, iconPath, monochromeIconPath)); + new ArchiveState.ArchiveActivityInfo( + title, + ComponentName.unflattenFromString(originalComponentName), + iconPath, + monochromeIconPath)); } } return activityInfos; @@ -2458,6 +2471,10 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile for (ArchiveState.ArchiveActivityInfo activityInfo : archiveState.getActivityInfos()) { serializer.startTag(null, TAG_ARCHIVE_ACTIVITY_INFO); serializer.attribute(null, ATTR_ARCHIVE_ACTIVITY_TITLE, activityInfo.getTitle()); + serializer.attribute( + null, + ATTR_ARCHIVE_ORIGINAL_COMPONENT_NAME, + activityInfo.getOriginalComponentName().flattenToString()); if (activityInfo.getIconBitmap() != null) { serializer.attribute(null, ATTR_ARCHIVE_ICON_PATH, activityInfo.getIconBitmap().toAbsolutePath().toString()); diff --git a/services/core/java/com/android/server/pm/pkg/ArchiveState.java b/services/core/java/com/android/server/pm/pkg/ArchiveState.java index 4916a4a6d72a..1e40d44bd4ca 100644 --- a/services/core/java/com/android/server/pm/pkg/ArchiveState.java +++ b/services/core/java/com/android/server/pm/pkg/ArchiveState.java @@ -16,9 +16,11 @@ package com.android.server.pm.pkg; +import android.content.ComponentName; import android.annotation.NonNull; import android.annotation.Nullable; +import com.android.internal.util.AnnotationValidations; import com.android.internal.util.DataClass; import java.nio.file.Path; @@ -56,6 +58,10 @@ public class ArchiveState { @NonNull private final String mTitle; + /** The component name of the original activity (pre-archival). */ + @NonNull + private final ComponentName mOriginalComponentName; + /** * The path to the stored icon of the activity in the app's locale. Null if the app does * not define any icon (default icon would be shown on the launcher). @@ -96,11 +102,13 @@ public class ArchiveState { @DataClass.Generated.Member public ArchiveActivityInfo( @NonNull String title, + @NonNull ComponentName originalComponentName, @Nullable Path iconBitmap, @Nullable Path monochromeIconBitmap) { this.mTitle = title; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mTitle); + this.mOriginalComponentName = originalComponentName; + AnnotationValidations.validate(NonNull.class, null, mTitle); + AnnotationValidations.validate(NonNull.class, null, mOriginalComponentName); this.mIconBitmap = iconBitmap; this.mMonochromeIconBitmap = monochromeIconBitmap; @@ -116,6 +124,14 @@ public class ArchiveState { } /** + * The component name of the original activity (pre-archival). + */ + @DataClass.Generated.Member + public @NonNull ComponentName getOriginalComponentName() { + return mOriginalComponentName; + } + + /** * The path to the stored icon of the activity in the app's locale. Null if the app does * not define any icon (default icon would be shown on the launcher). */ @@ -140,6 +156,7 @@ public class ArchiveState { return "ArchiveActivityInfo { " + "title = " + mTitle + ", " + + "originalComponentName = " + mOriginalComponentName + ", " + "iconBitmap = " + mIconBitmap + ", " + "monochromeIconBitmap = " + mMonochromeIconBitmap + " }"; @@ -159,6 +176,7 @@ public class ArchiveState { //noinspection PointlessBooleanExpression return true && java.util.Objects.equals(mTitle, that.mTitle) + && java.util.Objects.equals(mOriginalComponentName, that.mOriginalComponentName) && java.util.Objects.equals(mIconBitmap, that.mIconBitmap) && java.util.Objects.equals(mMonochromeIconBitmap, that.mMonochromeIconBitmap); } @@ -171,6 +189,7 @@ public class ArchiveState { int _hash = 1; _hash = 31 * _hash + java.util.Objects.hashCode(mTitle); + _hash = 31* _hash + java.util.Objects.hashCode(mOriginalComponentName); _hash = 31 * _hash + java.util.Objects.hashCode(mIconBitmap); _hash = 31 * _hash + java.util.Objects.hashCode(mMonochromeIconBitmap); return _hash; @@ -180,7 +199,8 @@ public class ArchiveState { time = 1693590309015L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/ArchiveState.java", - inputSignatures = "private final @android.annotation.NonNull java.lang.String mTitle\nprivate final @android.annotation.Nullable java.nio.file.Path mIconBitmap\nprivate final @android.annotation.Nullable java.nio.file.Path mMonochromeIconBitmap\nclass ArchiveActivityInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true)") + inputSignatures = + "private final @android.annotation.NonNull java.lang.String mTitle\nprivate final @android.annotation.NonNull android.content.ComponentName mOriginalComponentName\nprivate final @android.annotation.Nullable java.nio.file.Path mIconBitmap\nprivate final @android.annotation.Nullable java.nio.file.Path mMonochromeIconBitmap\nclass ArchiveActivityInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true)") @Deprecated private void __metadata() {} @@ -224,11 +244,9 @@ public class ArchiveState { @NonNull List<ArchiveActivityInfo> activityInfos, @NonNull String installerTitle) { this.mActivityInfos = activityInfos; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mActivityInfos); + AnnotationValidations.validate(NonNull.class, null, mActivityInfos); this.mInstallerTitle = installerTitle; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mInstallerTitle); + AnnotationValidations.validate(NonNull.class, null, mInstallerTitle); // onConstructed(); // You can define this method to get a callback } diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java index 2889c749f679..326218ce997c 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -41,6 +41,7 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.app.PropertyInvalidatedCache; +import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.SuspendDialogInfo; @@ -871,12 +872,20 @@ public class PackageManagerSettingsTests { .setUid(packageSetting.getAppId()) .hideAsFinal()); - ArchiveState archiveState = new ArchiveState( - List.of(new ArchiveState.ArchiveActivityInfo("title1", Path.of("/path1"), - Path.of("/monochromePath1")), - new ArchiveState.ArchiveActivityInfo("title2", Path.of("/path2"), - Path.of("/monochromePath2"))), - "installerTitle"); + ArchiveState archiveState = + new ArchiveState( + List.of( + new ArchiveState.ArchiveActivityInfo( + "title1", + new ComponentName("pkg1", "class1"), + Path.of("/path1"), + Path.of("/monochromePath1")), + new ArchiveState.ArchiveActivityInfo( + "title2", + new ComponentName("pkg2", "class2"), + Path.of("/path2"), + Path.of("/monochromePath2"))), + "installerTitle"); packageSetting.modifyUserState(UserHandle.SYSTEM.getIdentifier()).setArchiveState( archiveState); settings.mPackages.put(PACKAGE_NAME_1, packageSetting); diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java index 58ae7406580e..87a297b0e86f 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import android.content.ComponentName; import android.content.pm.PackageManager; import android.content.pm.SuspendDialogInfo; import android.content.pm.overlay.OverlayPaths; @@ -192,8 +193,8 @@ public class PackageUserStateTest { return new SuspendParams(dialogInfo, appExtras, launcherExtras); } - private static PersistableBundle createPersistableBundle(String lKey, long lValue, String sKey, - String sValue, String dKey, double dValue) { + private static PersistableBundle createPersistableBundle( + String lKey, long lValue, String sKey, String sValue, String dKey, double dValue) { final PersistableBundle result = new PersistableBundle(3); if (lKey != null) { result.putLong("com.unit_test." + lKey, lValue); @@ -320,6 +321,7 @@ public class PackageUserStateTest { assertEquals(0L, state.getLastPackageUsageTimeInMills()[i]); } } + private static void assertLastPackageUsageSet( PackageStateUnserialized state, int reason, long value) throws Exception { for (int i = state.getLastPackageUsageTimeInMills().length - 1; i >= 0; --i) { @@ -330,6 +332,7 @@ public class PackageUserStateTest { } } } + @Test public void testPackageUseReasons() throws Exception { PackageSetting packageSetting = Mockito.mock(PackageSetting.class); @@ -377,6 +380,7 @@ public class PackageUserStateTest { assertTrue(testState.setOverlayPaths(new OverlayPaths.Builder().build())); assertFalse(testState.setOverlayPaths(null)); } + @Test public void testSharedLibOverlayPaths() { final PackageUserStateImpl testState = new PackageUserStateImpl(); @@ -401,8 +405,12 @@ public class PackageUserStateTest { @Test public void archiveState() { PackageUserStateImpl packageUserState = new PackageUserStateImpl(); - ArchiveState.ArchiveActivityInfo archiveActivityInfo = new ArchiveState.ArchiveActivityInfo( - "appTitle", Path.of("/path1"), Path.of("/path2")); + ArchiveState.ArchiveActivityInfo archiveActivityInfo = + new ArchiveState.ArchiveActivityInfo( + "appTitle", + new ComponentName("pkg", "class"), + Path.of("/path1"), + Path.of("/path2")); ArchiveState archiveState = new ArchiveState(List.of(archiveActivityInfo), "installerTitle"); packageUserState.setArchiveState(archiveState); diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java index eb50556821eb..610ea903767e 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java @@ -35,6 +35,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AppOpsManager; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentSender; @@ -427,6 +428,7 @@ public class PackageArchiverTest { for (LauncherActivityInfo mainActivity : createLauncherActivities()) { ArchiveState.ArchiveActivityInfo activityInfo = new ArchiveState.ArchiveActivityInfo( mainActivity.getLabel().toString(), + mainActivity.getComponentName(), ICON_PATH, null); activityInfos.add(activityInfo); } @@ -437,9 +439,11 @@ public class PackageArchiverTest { ActivityInfo activityInfo = mock(ActivityInfo.class); LauncherActivityInfo activity1 = mock(LauncherActivityInfo.class); when(activity1.getLabel()).thenReturn("activity1"); + when(activity1.getComponentName()).thenReturn(new ComponentName("pkg1", "class1")); when(activity1.getActivityInfo()).thenReturn(activityInfo); LauncherActivityInfo activity2 = mock(LauncherActivityInfo.class); when(activity2.getLabel()).thenReturn("activity2"); + when(activity2.getComponentName()).thenReturn(new ComponentName("pkg2", "class2")); when(activity2.getActivityInfo()).thenReturn(activityInfo); return List.of(activity1, activity2); } |