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

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

Merge "Added throttle when reporting shortcut usage" into main

parents 4ce2270c 85f27940
Loading
Loading
Loading
Loading
+25 −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;
@@ -191,6 +193,9 @@ class ShortcutPackage extends ShortcutPackageItem {

    private long mLastKnownForegroundElapsedTime;

    @GuardedBy("mLock")
    private long mLastReportedTime;

    @GuardedBy("mLock")
    private boolean mIsAppSearchSchemaUpToDate;

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

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