diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 78352319e1567..356515442386c 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -113,6 +113,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.function.Predicate; @@ -316,7 +317,7 @@ public class ShortcutService extends IShortcutService.Stub { int LAUNCHER_PERMISSION_CHECK = 4; int CLEANUP_DANGLING_BITMAPS = 5; int GET_ACTIVITIES_WITH_METADATA = 6; - int GET_INSTALLED_APPLICATIONS = 7; + int GET_INSTALLED_PACKAGES = 7; int CHECK_PACKAGE_CHANGES = 8; int COUNT = CHECK_PACKAGE_CHANGES + 1; @@ -2282,11 +2283,17 @@ public class ShortcutService extends IShortcutService.Stub { cleanUpPackageLocked(pu.packageName, ownerUserId, pu.userId); } } + final long now = injectCurrentTimeMillis(); // Then for each installed app, publish manifest shortcuts when needed. - forInstalledApplications(ownerUserId, ai -> { + forUpdatedPackages(ownerUserId, user.getLastAppScanTime(), ai -> { user.handlePackageAddedOrUpdated(ai.packageName); }); + + // 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); } } finally { logDurationStat(Stats.CHECK_PACKAGE_CHANGES, start); @@ -2424,12 +2431,12 @@ public class ShortcutService extends IShortcutService.Stub { @Nullable @VisibleForTesting - List injectInstalledApplications(@UserIdInt int userId) { + List injectInstalledPackages(@UserIdInt int userId) { final long start = injectElapsedRealtime(); final long token = injectClearCallingIdentity(); try { - final ParceledListSlice parceledList = - mIPackageManager.getInstalledApplications(PACKAGE_MATCH_FLAGS, userId); + final ParceledListSlice parceledList = + mIPackageManager.getInstalledPackages(PACKAGE_MATCH_FLAGS, userId); if (parceledList == null) { return Collections.emptyList(); } @@ -2441,18 +2448,25 @@ public class ShortcutService extends IShortcutService.Stub { } finally { injectRestoreCallingIdentity(token); - logDurationStat(Stats.GET_INSTALLED_APPLICATIONS, start); + logDurationStat(Stats.GET_INSTALLED_PACKAGES, start); } } - private void forInstalledApplications(@UserIdInt int userId, + private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime, Consumer callback) { - final List list = injectInstalledApplications(userId); + if (DEBUG) { + Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime); + } + final List list = injectInstalledPackages(userId); for (int i = list.size() - 1; i >= 0; i--) { - final ApplicationInfo ai = list.get(i); + final PackageInfo pi = list.get(i); - if ((ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { - callback.accept(ai); + if (((pi.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) + && (pi.lastUpdateTime >= lastScanTime)) { + if (DEBUG) { + Slog.d(TAG, "Found updated package " + pi.packageName); + } + callback.accept(pi.applicationInfo); } } } @@ -2612,7 +2626,7 @@ public class ShortcutService extends IShortcutService.Stub { dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo"); dumpStatLS(pw, p, Stats.CLEANUP_DANGLING_BITMAPS, "cleanupDanglingBitmaps"); dumpStatLS(pw, p, Stats.GET_ACTIVITIES_WITH_METADATA, "getActivities+metadata"); - dumpStatLS(pw, p, Stats.GET_INSTALLED_APPLICATIONS, "getInstalledApplications"); + dumpStatLS(pw, p, Stats.GET_INSTALLED_PACKAGES, "getInstalledPackages"); dumpStatLS(pw, p, Stats.CHECK_PACKAGE_CHANGES, "checkPackageChanges"); } diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java index 840c3df97cc34..f8ee3251055bc 100644 --- a/services/core/java/com/android/server/pm/ShortcutUser.java +++ b/services/core/java/com/android/server/pm/ShortcutUser.java @@ -52,6 +52,7 @@ class ShortcutUser { private static final String ATTR_VALUE = "value"; private static final String ATTR_KNOWN_LOCALE_CHANGE_SEQUENCE_NUMBER = "locale-seq-no"; + private static final String ATTR_LAST_APP_SCAN_TIME = "last-app-scan-time"; static final class PackageWithUser { final int userId; @@ -107,6 +108,8 @@ class ShortcutUser { private long mKnownLocaleChangeSequenceNumber; + private long mLastAppScanTime; + public ShortcutUser(ShortcutService service, int userId) { mService = service; mUserId = userId; @@ -116,6 +119,14 @@ class ShortcutUser { return mUserId; } + public long getLastAppScanTime() { + return mLastAppScanTime; + } + + public void setLastAppScanTime(long lastAppScanTime) { + mLastAppScanTime = lastAppScanTime; + } + // We don't expose this directly to non-test code because only ShortcutUser should add to/ // remove from it. @VisibleForTesting @@ -258,6 +269,8 @@ class ShortcutUser { ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALE_CHANGE_SEQUENCE_NUMBER, mKnownLocaleChangeSequenceNumber); + ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME, + mLastAppScanTime); ShortcutService.writeTagValue(out, TAG_LAUNCHER, mDefaultLauncherComponent); @@ -299,6 +312,13 @@ class ShortcutUser { ret.mKnownLocaleChangeSequenceNumber = ShortcutService.parseLongAttribute(parser, ATTR_KNOWN_LOCALE_CHANGE_SEQUENCE_NUMBER); + // If lastAppScanTime is in the future, that means the clock went backwards. + // Just scan all apps again. + final long lastAppScanTime = ShortcutService.parseLongAttribute(parser, + ATTR_LAST_APP_SCAN_TIME); + final long currentTime = s.injectCurrentTimeMillis(); + ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0; + final int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT @@ -361,6 +381,8 @@ class ShortcutUser { pw.print(mUserId); pw.print(" Known locale seq#: "); pw.print(mKnownLocaleChangeSequenceNumber); + pw.print(" Last app scan: "); + pw.print(mLastAppScanTime); pw.println(); prefix += prefix + " "; diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index ed53b7782e46d..d33047b68757e 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -302,8 +302,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } @Override - List injectInstalledApplications(@UserIdInt int userId) { - return getInstalledApplications(userId); + List injectInstalledPackages(@UserIdInt int userId) { + return getInstalledPackages(userId); } @Override @@ -793,6 +793,27 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { return ret; } + private void addPackageInfo(PackageInfo pi, List list) { + if (pi != null) { + list.add(pi); + } + } + + private List getInstalledPackages(int userId) { + final ArrayList ret = new ArrayList<>(); + + addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret); + addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret); + addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret); + addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret); + addPackageInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret); + addPackageInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret); + addPackageInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret); + addPackageInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret); + + return ret; + } + protected void addManifestShortcutResource(ComponentName activity, int resId) { final String packageName = activity.getPackageName(); LinkedHashMap map = mActivityMetadataResId.get(packageName);