summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java32
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java55
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java2
4 files changed, 92 insertions, 15 deletions
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 8456927b2cdf..00da2439ced8 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -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;
@@ -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;
@@ -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;
/**
@@ -196,6 +201,9 @@ class ShortcutPackage extends ShortcutPackageItem {
private long mLastKnownForegroundElapsedTime;
@GuardedBy("mLock")
+ private List<Long> mLastReportedTime = new ArrayList<>();
+
+ @GuardedBy("mLock")
private boolean mIsAppSearchSchemaUpToDate;
private ShortcutPackage(ShortcutUser shortcutUser,
@@ -1677,6 +1685,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();
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index c6aba2ab9cbe..77ec06878e23 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -369,7 +369,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;
@@ -2282,7 +2282,7 @@ public class ShortcutService extends IShortcutService.Stub {
packageShortcutsChanged(ps, changedShortcuts, removedShortcuts);
- reportShortcutUsedInternal(packageName, shortcut.getId(), userId);
+ ps.reportShortcutUsed(mUsageStatsManagerInternal, shortcut.getId());
verifyStates();
}
@@ -2686,25 +2686,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
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 7c1845fcd54e..77e3a988790f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -404,8 +404,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");
@@ -543,6 +543,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);
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 1cfaf7c83584..27c981aba85c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -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);