Loading services/core/java/com/android/server/pm/ShortcutPackage.java +32 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import android.app.appsearch.SearchResult; import android.app.appsearch.SearchResults; import android.app.appsearch.SearchSpec; import android.app.appsearch.SetSchemaRequest; import android.app.usage.UsageStatsManagerInternal; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; Loading @@ -47,6 +48,7 @@ import android.graphics.drawable.Icon; import android.os.Binder; import android.os.PersistableBundle; import android.os.StrictMode; import android.os.SystemClock; import android.text.format.Formatter; import android.util.ArrayMap; import android.util.ArraySet; Loading Loading @@ -160,6 +162,9 @@ class ShortcutPackage extends ShortcutPackageItem { private static final String KEY_BITMAPS = "bitmaps"; private static final String KEY_BITMAP_BYTES = "bitmapBytes"; @VisibleForTesting public static final int REPORT_USAGE_BUFFER_SIZE = 3; private final Executor mExecutor; /** Loading Loading @@ -195,6 +200,9 @@ class ShortcutPackage extends ShortcutPackageItem { private long mLastKnownForegroundElapsedTime; @GuardedBy("mLock") private List<Long> mLastReportedTime = new ArrayList<>(); @GuardedBy("mLock") private boolean mIsAppSearchSchemaUpToDate; Loading Loading @@ -1673,6 +1681,30 @@ class ShortcutPackage extends ShortcutPackageItem { return condition[0]; } void reportShortcutUsed(@NonNull final UsageStatsManagerInternal usageStatsManagerInternal, @NonNull final String shortcutId) { synchronized (mLock) { final long currentTS = SystemClock.elapsedRealtime(); final ShortcutService s = mShortcutUser.mService; if (mLastReportedTime.isEmpty() || mLastReportedTime.size() < REPORT_USAGE_BUFFER_SIZE) { mLastReportedTime.add(currentTS); } else if (currentTS - mLastReportedTime.get(0) > s.mSaveDelayMillis) { mLastReportedTime.remove(0); mLastReportedTime.add(currentTS); } else { return; } final long token = s.injectClearCallingIdentity(); try { usageStatsManagerInternal.reportShortcutUsage(getPackageName(), shortcutId, getUser().getUserId()); } finally { s.injectRestoreCallingIdentity(token); } } } public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) { pw.println(); Loading services/core/java/com/android/server/pm/ShortcutService.java +5 −13 Original line number Diff line number Diff line Loading @@ -364,7 +364,7 @@ public class ShortcutService extends IShortcutService.Stub { private CompressFormat mIconPersistFormat; private int mIconPersistQuality; private int mSaveDelayMillis; int mSaveDelayMillis; private final IPackageManager mIPackageManager; private final PackageManagerInternal mPackageManagerInternal; Loading Loading @@ -2268,7 +2268,7 @@ public class ShortcutService extends IShortcutService.Stub { packageShortcutsChanged(ps, changedShortcuts, removedShortcuts); reportShortcutUsedInternal(packageName, shortcut.getId(), userId); ps.reportShortcutUsed(mUsageStatsManagerInternal, shortcut.getId()); verifyStates(); } Loading Loading @@ -2669,25 +2669,17 @@ public class ShortcutService extends IShortcutService.Stub { Slog.d(TAG, String.format("reportShortcutUsed: Shortcut %s package %s used on user %d", shortcutId, packageName, userId)); } final ShortcutPackage ps; synchronized (mLock) { throwIfUserLockedL(userId); final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); ps = getPackageShortcutsForPublisherLocked(packageName, userId); if (ps.findShortcutById(shortcutId) == null) { Log.w(TAG, String.format("reportShortcutUsed: package %s doesn't have shortcut %s", packageName, shortcutId)); return; } } reportShortcutUsedInternal(packageName, shortcutId, userId); } private void reportShortcutUsedInternal(String packageName, String shortcutId, int userId) { final long token = injectClearCallingIdentity(); try { mUsageStatsManagerInternal.reportShortcutUsage(packageName, shortcutId, userId); } finally { injectRestoreCallingIdentity(token); } ps.reportShortcutUsed(mUsageStatsManagerInternal, shortcutId); } @Override Loading services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +53 −2 Original line number Diff line number Diff line Loading @@ -402,8 +402,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { public void testPushDynamicShortcut() { // Change the max number of shortcuts. mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=5"); mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=5," + ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=1"); setCaller(CALLING_PACKAGE_1, USER_0); final ShortcutInfo s1 = makeShortcut("s1"); Loading Loading @@ -541,6 +541,57 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { eq(CALLING_PACKAGE_1), eq("s9"), eq(USER_0)); } public void testPushDynamicShortcut_CallsToUsageStatsManagerAreThrottled() throws InterruptedException { mService.updateConfigurationLocked( ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=500"); // Verify calls to UsageStatsManagerInternal#reportShortcutUsage are throttled. setCaller(CALLING_PACKAGE_1, USER_0); for (int i = 0; i < ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i++) { final ShortcutInfo si = makeShortcut("s" + i); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_1), eq("s1"), eq(USER_0)); Mockito.reset(mMockUsageStatsManagerInternal); for (int i = ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i <= 10; i++) { final ShortcutInfo si = makeShortcut("s" + i); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage( any(), any(), anyInt()); // Verify pkg2 isn't blocked by pkg1, but consecutive calls from pkg2 are throttled as well. setCaller(CALLING_PACKAGE_2, USER_0); for (int i = 0; i < ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i++) { final ShortcutInfo si = makeShortcut("s" + i); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_2), eq("s1"), eq(USER_0)); Mockito.reset(mMockUsageStatsManagerInternal); for (int i = ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i <= 10; i++) { final ShortcutInfo si = makeShortcut("s" + i); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage( any(), any(), anyInt()); Mockito.reset(mMockUsageStatsManagerInternal); // Let time passes which resets the throttle Thread.sleep(505); // Verify UsageStatsManagerInternal#reportShortcutUsed can be called again setCaller(CALLING_PACKAGE_1, USER_0); mManager.pushDynamicShortcut(makeShortcut("s10")); setCaller(CALLING_PACKAGE_2, USER_0); mManager.pushDynamicShortcut(makeShortcut("s10")); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_1), any(), eq(USER_0)); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_2), any(), eq(USER_0)); } public void testUnlimitedCalls() { setCaller(CALLING_PACKAGE_1, USER_0); Loading services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +2 −0 Original line number Diff line number Diff line Loading @@ -2175,6 +2175,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { public void testReportShortcutUsed() { mRunningUsers.put(USER_10, true); mService.updateConfigurationLocked( ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=1"); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { reset(mMockUsageStatsManagerInternal); Loading Loading
services/core/java/com/android/server/pm/ShortcutPackage.java +32 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import android.app.appsearch.SearchResult; import android.app.appsearch.SearchResults; import android.app.appsearch.SearchSpec; import android.app.appsearch.SetSchemaRequest; import android.app.usage.UsageStatsManagerInternal; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; Loading @@ -47,6 +48,7 @@ import android.graphics.drawable.Icon; import android.os.Binder; import android.os.PersistableBundle; import android.os.StrictMode; import android.os.SystemClock; import android.text.format.Formatter; import android.util.ArrayMap; import android.util.ArraySet; Loading Loading @@ -160,6 +162,9 @@ class ShortcutPackage extends ShortcutPackageItem { private static final String KEY_BITMAPS = "bitmaps"; private static final String KEY_BITMAP_BYTES = "bitmapBytes"; @VisibleForTesting public static final int REPORT_USAGE_BUFFER_SIZE = 3; private final Executor mExecutor; /** Loading Loading @@ -195,6 +200,9 @@ class ShortcutPackage extends ShortcutPackageItem { private long mLastKnownForegroundElapsedTime; @GuardedBy("mLock") private List<Long> mLastReportedTime = new ArrayList<>(); @GuardedBy("mLock") private boolean mIsAppSearchSchemaUpToDate; Loading Loading @@ -1673,6 +1681,30 @@ class ShortcutPackage extends ShortcutPackageItem { return condition[0]; } void reportShortcutUsed(@NonNull final UsageStatsManagerInternal usageStatsManagerInternal, @NonNull final String shortcutId) { synchronized (mLock) { final long currentTS = SystemClock.elapsedRealtime(); final ShortcutService s = mShortcutUser.mService; if (mLastReportedTime.isEmpty() || mLastReportedTime.size() < REPORT_USAGE_BUFFER_SIZE) { mLastReportedTime.add(currentTS); } else if (currentTS - mLastReportedTime.get(0) > s.mSaveDelayMillis) { mLastReportedTime.remove(0); mLastReportedTime.add(currentTS); } else { return; } final long token = s.injectClearCallingIdentity(); try { usageStatsManagerInternal.reportShortcutUsage(getPackageName(), shortcutId, getUser().getUserId()); } finally { s.injectRestoreCallingIdentity(token); } } } public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) { pw.println(); Loading
services/core/java/com/android/server/pm/ShortcutService.java +5 −13 Original line number Diff line number Diff line Loading @@ -364,7 +364,7 @@ public class ShortcutService extends IShortcutService.Stub { private CompressFormat mIconPersistFormat; private int mIconPersistQuality; private int mSaveDelayMillis; int mSaveDelayMillis; private final IPackageManager mIPackageManager; private final PackageManagerInternal mPackageManagerInternal; Loading Loading @@ -2268,7 +2268,7 @@ public class ShortcutService extends IShortcutService.Stub { packageShortcutsChanged(ps, changedShortcuts, removedShortcuts); reportShortcutUsedInternal(packageName, shortcut.getId(), userId); ps.reportShortcutUsed(mUsageStatsManagerInternal, shortcut.getId()); verifyStates(); } Loading Loading @@ -2669,25 +2669,17 @@ public class ShortcutService extends IShortcutService.Stub { Slog.d(TAG, String.format("reportShortcutUsed: Shortcut %s package %s used on user %d", shortcutId, packageName, userId)); } final ShortcutPackage ps; synchronized (mLock) { throwIfUserLockedL(userId); final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); ps = getPackageShortcutsForPublisherLocked(packageName, userId); if (ps.findShortcutById(shortcutId) == null) { Log.w(TAG, String.format("reportShortcutUsed: package %s doesn't have shortcut %s", packageName, shortcutId)); return; } } reportShortcutUsedInternal(packageName, shortcutId, userId); } private void reportShortcutUsedInternal(String packageName, String shortcutId, int userId) { final long token = injectClearCallingIdentity(); try { mUsageStatsManagerInternal.reportShortcutUsage(packageName, shortcutId, userId); } finally { injectRestoreCallingIdentity(token); } ps.reportShortcutUsed(mUsageStatsManagerInternal, shortcutId); } @Override Loading
services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +53 −2 Original line number Diff line number Diff line Loading @@ -402,8 +402,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { public void testPushDynamicShortcut() { // Change the max number of shortcuts. mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=5"); mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=5," + ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=1"); setCaller(CALLING_PACKAGE_1, USER_0); final ShortcutInfo s1 = makeShortcut("s1"); Loading Loading @@ -541,6 +541,57 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { eq(CALLING_PACKAGE_1), eq("s9"), eq(USER_0)); } public void testPushDynamicShortcut_CallsToUsageStatsManagerAreThrottled() throws InterruptedException { mService.updateConfigurationLocked( ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=500"); // Verify calls to UsageStatsManagerInternal#reportShortcutUsage are throttled. setCaller(CALLING_PACKAGE_1, USER_0); for (int i = 0; i < ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i++) { final ShortcutInfo si = makeShortcut("s" + i); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_1), eq("s1"), eq(USER_0)); Mockito.reset(mMockUsageStatsManagerInternal); for (int i = ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i <= 10; i++) { final ShortcutInfo si = makeShortcut("s" + i); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage( any(), any(), anyInt()); // Verify pkg2 isn't blocked by pkg1, but consecutive calls from pkg2 are throttled as well. setCaller(CALLING_PACKAGE_2, USER_0); for (int i = 0; i < ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i++) { final ShortcutInfo si = makeShortcut("s" + i); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_2), eq("s1"), eq(USER_0)); Mockito.reset(mMockUsageStatsManagerInternal); for (int i = ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i <= 10; i++) { final ShortcutInfo si = makeShortcut("s" + i); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage( any(), any(), anyInt()); Mockito.reset(mMockUsageStatsManagerInternal); // Let time passes which resets the throttle Thread.sleep(505); // Verify UsageStatsManagerInternal#reportShortcutUsed can be called again setCaller(CALLING_PACKAGE_1, USER_0); mManager.pushDynamicShortcut(makeShortcut("s10")); setCaller(CALLING_PACKAGE_2, USER_0); mManager.pushDynamicShortcut(makeShortcut("s10")); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_1), any(), eq(USER_0)); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_2), any(), eq(USER_0)); } public void testUnlimitedCalls() { setCaller(CALLING_PACKAGE_1, USER_0); Loading
services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +2 −0 Original line number Diff line number Diff line Loading @@ -2175,6 +2175,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { public void testReportShortcutUsed() { mRunningUsers.put(USER_10, true); mService.updateConfigurationLocked( ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=1"); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { reset(mMockUsageStatsManagerInternal); Loading