diff options
| -rw-r--r-- | services/core/java/com/android/server/pm/ShortcutService.java | 40 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java | 152 |
2 files changed, 167 insertions, 25 deletions
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 44df9264d748..d5767b4cad8a 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -2601,17 +2601,9 @@ public class ShortcutService extends IShortcutService.Stub { /* appStillExists = */ false); } } - final long now = injectCurrentTimeMillis(); - // Then for each installed app, publish manifest shortcuts when needed. - forUpdatedPackages(ownerUserId, user.getLastAppScanTime(), ai -> { - user.rescanPackageIfNeeded(ai.packageName, /* forceRescan=*/ false); - }); - - // Write the time just before the scan, because there may be apps that have just - // been updated, and we want to catch them in the next time. - user.setLastAppScanTime(now); - scheduleSaveUser(ownerUserId); + rescanUpdatedPackagesLocked(ownerUserId, user.getLastAppScanTime(), + /* forceRescan=*/ false); } } finally { logDurationStat(Stats.CHECK_PACKAGE_CHANGES, start); @@ -2619,6 +2611,24 @@ public class ShortcutService extends IShortcutService.Stub { verifyStates(); } + private void rescanUpdatedPackagesLocked(@UserIdInt int userId, long lastScanTime, + boolean forceRescan) { + final ShortcutUser user = getUserShortcutsLocked(userId); + + final long now = injectCurrentTimeMillis(); + + // Then for each installed app, publish manifest shortcuts when needed. + forUpdatedPackages(userId, lastScanTime, ai -> { + user.attemptToRestoreIfNeededAndSave(this, ai.packageName, userId); + user.rescanPackageIfNeeded(ai.packageName, forceRescan); + }); + + // Write the time just before the scan, because there may be apps that have just + // been updated, and we want to catch them in the next time. + user.setLastAppScanTime(now); + scheduleSaveUser(userId); + } + private void handlePackageAdded(String packageName, @UserIdInt int userId) { if (DEBUG) { Slog.d(TAG, String.format("handlePackageAdded: %s user=%d", packageName, userId)); @@ -3119,12 +3129,10 @@ public class ShortcutService extends IShortcutService.Stub { } mUsers.put(userId, user); - // Then purge all the save images. - final File bitmapPath = getUserBitmapFilePath(userId); - final boolean success = FileUtils.deleteContents(bitmapPath); - if (!success) { - Slog.w(TAG, "Failed to delete " + bitmapPath); - } + // Rescan all packages to re-publish manifest shortcuts and do other checks. + rescanUpdatedPackagesLocked(userId, + 0, // lastScanTime = 0; rescan all packages. + /* forceRescan= */ true); saveUserLocked(userId); } diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index 4bd0d6fb9b38..75a34272d82b 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -57,13 +57,11 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.Manifest.permission; import android.app.ActivityManager; @@ -82,6 +80,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.os.Process; import android.os.UserHandle; import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; @@ -5153,7 +5152,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } - public void testBackupAndRestore_manifestNotRestored() { + public void testBackupAndRestore_manifestRePublished() { // Publish two manifest shortcuts. addManifestShortcutResource( new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), @@ -5162,9 +5161,15 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mService.mPackageMonitor.onReceive(mServiceContext, genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + assertTrue(mManager.setDynamicShortcuts(list( + makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); + }); + // Pin from launcher 1. runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1", "ms2"), HANDLE_USER_0); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, + list("ms1", "ms2", "s1", "s2"), HANDLE_USER_0); }); // Update and now ms2 is gone -> disabled. @@ -5178,9 +5183,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Make sure the manifest shortcuts have been published. runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertWith(getCallerShortcuts()) - .areAllPinned() - .haveIds("ms1", "ms2") + .selectManifest() + .haveIds("ms1") + .revertToOriginalList() + .selectDynamic() + .haveIds("s1", "s2", "s3") + + .revertToOriginalList() + .selectPinned() + .haveIds("ms1", "ms2", "s1", "s2") + + .revertToOriginalList() .selectByIds("ms1") .areAllManifest() .areAllEnabled() @@ -5191,10 +5205,130 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .areAllDisabled(); }); - // Now do the regular backup & restore test. - // The existence of the manifest shortcuts shouldn't affect the result. - prepareCrossProfileDataSet(); backupAndRestore(); + + // When re-installing the app, the manifest shortcut should be re-published. + mService.mPackageMonitor.onReceive(mServiceContext, + genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + mService.mPackageMonitor.onReceive(mServiceContext, + genPackageAddIntent(LAUNCHER_1, USER_0)); + + runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + assertWith(getCallerVisibleShortcuts()) + .selectPinned() + // ms2 was disabled, so not restored. + .haveIds("ms1", "s1", "s2") + .areAllEnabled() + + .revertToOriginalList() + .selectByIds("ms1") + .areAllManifest() + + .revertToOriginalList() + .selectByIds("s1", "s2") + .areAllNotDynamic() + ; + }); + } + + /** + * It's the case with preintalled apps -- when applyRestore() is called, the system + * apps are already installed, so manifest shortcuts need to be re-published. + */ + public void testBackupAndRestore_appAlreadyInstalledWhenRestored() { + // Pre-backup. Same as testBackupAndRestore_manifestRePublished(). + + // Publish two manifest shortcuts. + addManifestShortcutResource( + new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), + R.xml.shortcut_2); + updatePackageVersion(CALLING_PACKAGE_1, 1); + mService.mPackageMonitor.onReceive(mServiceContext, + genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + + runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + assertTrue(mManager.setDynamicShortcuts(list( + makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); + }); + + // Pin from launcher 1. + runWithCaller(LAUNCHER_1, USER_0, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, + list("ms1", "ms2", "s1", "s2"), HANDLE_USER_0); + }); + + // Update and now ms2 is gone -> disabled. + addManifestShortcutResource( + new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), + R.xml.shortcut_1); + updatePackageVersion(CALLING_PACKAGE_1, 1); + mService.mPackageMonitor.onReceive(mServiceContext, + genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + + // Make sure the manifest shortcuts have been published. + runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + assertWith(getCallerShortcuts()) + .selectManifest() + .haveIds("ms1") + + .revertToOriginalList() + .selectDynamic() + .haveIds("s1", "s2", "s3") + + .revertToOriginalList() + .selectPinned() + .haveIds("ms1", "ms2", "s1", "s2") + + .revertToOriginalList() + .selectByIds("ms1") + .areAllManifest() + .areAllEnabled() + + .revertToOriginalList() + .selectByIds("ms2") + .areAllNotManifest() + .areAllDisabled(); + }); + + // Backup and *without restarting the service, just call applyRestore()*. + { + int prevUid = mInjectedCallingUid; + mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it. + + dumpsysOnLogcat("Before backup"); + + final byte[] payload = mService.getBackupPayload(USER_0); + if (ENABLE_DUMP) { + final String xml = new String(payload); + Log.v(TAG, "Backup payload:"); + for (String line : xml.split("\n")) { + Log.v(TAG, line); + } + } + mService.applyRestore(payload, USER_0); + + dumpsysOnLogcat("After restore"); + + mInjectedCallingUid = prevUid; + } + + // The check is also the same as testBackupAndRestore_manifestRePublished(). + runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + assertWith(getCallerVisibleShortcuts()) + .selectPinned() + // ms2 was disabled, so not restored. + .haveIds("ms1", "s1", "s2") + .areAllEnabled() + + .revertToOriginalList() + .selectByIds("ms1") + .areAllManifest() + + .revertToOriginalList() + .selectByIds("s1", "s2") + .areAllNotDynamic() + ; + }); } public void testSaveAndLoad_crossProfile() { |