Loading services/core/java/com/android/server/pm/ShortcutPackage.java +25 −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 @@ -191,6 +193,9 @@ class ShortcutPackage extends ShortcutPackageItem { private long mLastKnownForegroundElapsedTime; @GuardedBy("mLock") private long mLastReportedTime; @GuardedBy("mLock") private boolean mIsAppSearchSchemaUpToDate; Loading Loading @@ -1673,6 +1678,26 @@ 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 (currentTS - mLastReportedTime > s.mSaveDelayMillis) { mLastReportedTime = currentTS; } else { return; } final long token = s.injectClearCallingIdentity(); try { usageStatsManagerInternal.reportShortcutUsage(getPackageName(), shortcutId, getPackageUserId()); } 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 −15 Original line number Diff line number Diff line Loading @@ -371,7 +371,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 @@ -2291,7 +2291,7 @@ public class ShortcutService extends IShortcutService.Stub { packageShortcutsChanged(ps, changedShortcuts, removedShortcuts); reportShortcutUsedInternal(packageName, shortcut.getId(), userId); ps.reportShortcutUsed(mUsageStatsManagerInternal, shortcut.getId()); verifyStates(); } Loading Loading @@ -2695,25 +2695,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 Loading @@ -5202,13 +5194,11 @@ public class ShortcutService extends IShortcutService.Stub { } // Injection point. @VisibleForTesting long injectClearCallingIdentity() { return Binder.clearCallingIdentity(); } // Injection point. @VisibleForTesting void injectRestoreCallingIdentity(long token) { Binder.restoreCallingIdentity(token); } Loading services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +53 −2 Original line number Diff line number Diff line Loading @@ -406,8 +406,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 @@ -545,6 +545,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); { final ShortcutInfo si = makeShortcut("s0"); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_1), eq("s0"), eq(USER_0)); Mockito.reset(mMockUsageStatsManagerInternal); for (int i = 2; 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); { final ShortcutInfo si = makeShortcut("s1"); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_2), eq("s1"), eq(USER_0)); Mockito.reset(mMockUsageStatsManagerInternal); for (int i = 2; 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 Loading
services/core/java/com/android/server/pm/ShortcutPackage.java +25 −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 @@ -191,6 +193,9 @@ class ShortcutPackage extends ShortcutPackageItem { private long mLastKnownForegroundElapsedTime; @GuardedBy("mLock") private long mLastReportedTime; @GuardedBy("mLock") private boolean mIsAppSearchSchemaUpToDate; Loading Loading @@ -1673,6 +1678,26 @@ 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 (currentTS - mLastReportedTime > s.mSaveDelayMillis) { mLastReportedTime = currentTS; } else { return; } final long token = s.injectClearCallingIdentity(); try { usageStatsManagerInternal.reportShortcutUsage(getPackageName(), shortcutId, getPackageUserId()); } 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 −15 Original line number Diff line number Diff line Loading @@ -371,7 +371,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 @@ -2291,7 +2291,7 @@ public class ShortcutService extends IShortcutService.Stub { packageShortcutsChanged(ps, changedShortcuts, removedShortcuts); reportShortcutUsedInternal(packageName, shortcut.getId(), userId); ps.reportShortcutUsed(mUsageStatsManagerInternal, shortcut.getId()); verifyStates(); } Loading Loading @@ -2695,25 +2695,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 Loading @@ -5202,13 +5194,11 @@ public class ShortcutService extends IShortcutService.Stub { } // Injection point. @VisibleForTesting long injectClearCallingIdentity() { return Binder.clearCallingIdentity(); } // Injection point. @VisibleForTesting void injectRestoreCallingIdentity(long token) { Binder.restoreCallingIdentity(token); } Loading
services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +53 −2 Original line number Diff line number Diff line Loading @@ -406,8 +406,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 @@ -545,6 +545,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); { final ShortcutInfo si = makeShortcut("s0"); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_1), eq("s0"), eq(USER_0)); Mockito.reset(mMockUsageStatsManagerInternal); for (int i = 2; 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); { final ShortcutInfo si = makeShortcut("s1"); mManager.pushDynamicShortcut(si); } verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_2), eq("s1"), eq(USER_0)); Mockito.reset(mMockUsageStatsManagerInternal); for (int i = 2; 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