Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b170427a authored by Pinyao Ting's avatar Pinyao Ting Committed by Android (Google) Code Review
Browse files

Merge "Added throttle when reporting shortcut usage" into tm-dev

parents ce1acd58 bd88f35c
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -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;

    /**
@@ -195,6 +200,9 @@ class ShortcutPackage extends ShortcutPackageItem {

    private long mLastKnownForegroundElapsedTime;

    @GuardedBy("mLock")
    private List<Long> mLastReportedTime = new ArrayList<>();

    @GuardedBy("mLock")
    private boolean mIsAppSearchSchemaUpToDate;

@@ -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();

+5 −13
Original line number Diff line number Diff line
@@ -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;
@@ -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();
    }
@@ -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
+53 −2
Original line number Diff line number Diff line
@@ -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");
@@ -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);

+2 −0
Original line number Diff line number Diff line
@@ -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);