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

Commit e86f8e00 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

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

parents 340a1267 76121eb7
Loading
Loading
Loading
Loading
+33 −0
Original line number Original line Diff line number Diff line
@@ -32,6 +32,7 @@ import android.app.appsearch.SearchResult;
import android.app.appsearch.SearchResults;
import android.app.appsearch.SearchResults;
import android.app.appsearch.SearchSpec;
import android.app.appsearch.SearchSpec;
import android.app.appsearch.SetSchemaRequest;
import android.app.appsearch.SetSchemaRequest;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Intent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter;
@@ -46,6 +47,7 @@ import android.graphics.drawable.Icon;
import android.os.Binder;
import android.os.Binder;
import android.os.PersistableBundle;
import android.os.PersistableBundle;
import android.os.StrictMode;
import android.os.StrictMode;
import android.os.SystemClock;
import android.text.format.Formatter;
import android.text.format.Formatter;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.ArraySet;
@@ -56,6 +58,7 @@ import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.Xml;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ArrayUtils;
@@ -158,6 +161,9 @@ class ShortcutPackage extends ShortcutPackageItem {
    private static final String KEY_BITMAPS = "bitmaps";
    private static final String KEY_BITMAPS = "bitmaps";
    private static final String KEY_BITMAP_BYTES = "bitmapBytes";
    private static final String KEY_BITMAP_BYTES = "bitmapBytes";


    @VisibleForTesting
    public static final int REPORT_USAGE_BUFFER_SIZE = 3;

    private final Object mLock = new Object();
    private final Object mLock = new Object();


    /**
    /**
@@ -195,6 +201,9 @@ class ShortcutPackage extends ShortcutPackageItem {
    private boolean mIsNewApp;
    private boolean mIsNewApp;
    private List<ShortcutInfo> mManifestShortcuts;
    private List<ShortcutInfo> mManifestShortcuts;


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

    private ShortcutPackage(ShortcutUser shortcutUser,
    private ShortcutPackage(ShortcutUser shortcutUser,
            int packageUserId, String packageName, ShortcutPackageInfo spi) {
            int packageUserId, String packageName, ShortcutPackageInfo spi) {
        super(shortcutUser, packageUserId, packageName,
        super(shortcutUser, packageUserId, packageName,
@@ -1690,6 +1699,30 @@ class ShortcutPackage extends ShortcutPackageItem {
        return condition[0];
        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) {
    public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) {
        pw.println();
        pw.println();


+7 −16
Original line number Original line Diff line number Diff line
@@ -361,7 +361,7 @@ public class ShortcutService extends IShortcutService.Stub {
    private CompressFormat mIconPersistFormat;
    private CompressFormat mIconPersistFormat;
    private int mIconPersistQuality;
    private int mIconPersistQuality;


    private int mSaveDelayMillis;
    int mSaveDelayMillis;


    private final IPackageManager mIPackageManager;
    private final IPackageManager mIPackageManager;
    private final PackageManagerInternal mPackageManagerInternal;
    private final PackageManagerInternal mPackageManagerInternal;
@@ -2253,11 +2253,11 @@ public class ShortcutService extends IShortcutService.Stub {
                List<ShortcutInfo> changedShortcuts = new ArrayList<>();
                List<ShortcutInfo> changedShortcuts = new ArrayList<>();
                List<ShortcutInfo> removedShortcuts = null;
                List<ShortcutInfo> removedShortcuts = null;


                final ShortcutPackage ps;
                synchronized (mLock) {
                synchronized (mLock) {
                    throwIfUserLockedL(userId);
                    throwIfUserLockedL(userId);


                    final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName,
                    ps = getPackageShortcutsForPublisherLocked(packageName, userId);
                            userId);


                    ps.ensureNotImmutable(shortcut.getId(), /*ignoreInvisible=*/ true);
                    ps.ensureNotImmutable(shortcut.getId(), /*ignoreInvisible=*/ true);
                    fillInDefaultActivity(Arrays.asList(shortcut));
                    fillInDefaultActivity(Arrays.asList(shortcut));
@@ -2295,7 +2295,7 @@ public class ShortcutService extends IShortcutService.Stub {


                packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
                packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);


                reportShortcutUsedInternal(packageName, shortcut.getId(), userId);
                ps.reportShortcutUsed(mUsageStatsManagerInternal, shortcut.getId());


                verifyStates();
                verifyStates();


@@ -2874,11 +2874,11 @@ public class ShortcutService extends IShortcutService.Stub {
                            shortcutId, packageName, userId));
                            shortcutId, packageName, userId));
                }
                }


                final ShortcutPackage ps;
                synchronized (mLock) {
                synchronized (mLock) {
                    throwIfUserLockedL(userId);
                    throwIfUserLockedL(userId);


                    final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName,
                    ps = getPackageShortcutsForPublisherLocked(packageName, userId);
                            userId);


                    if (ps.findShortcutById(shortcutId) == null) {
                    if (ps.findShortcutById(shortcutId) == null) {
                        Log.w(TAG, String.format(
                        Log.w(TAG, String.format(
@@ -2889,7 +2889,7 @@ public class ShortcutService extends IShortcutService.Stub {
                    }
                    }
                }
                }


                reportShortcutUsedInternal(packageName, shortcutId, userId);
                ps.reportShortcutUsed(mUsageStatsManagerInternal, shortcutId);
                ret.complete(true);
                ret.complete(true);
            } catch (Exception e) {
            } catch (Exception e) {
                ret.completeExceptionally(e);
                ret.completeExceptionally(e);
@@ -2898,15 +2898,6 @@ public class ShortcutService extends IShortcutService.Stub {
        return ret;
        return ret;
    }
    }


    private void reportShortcutUsedInternal(String packageName, String shortcutId, int userId) {
        final long token = injectClearCallingIdentity();
        try {
            mUsageStatsManagerInternal.reportShortcutUsage(packageName, shortcutId, userId);
        } finally {
            injectRestoreCallingIdentity(token);
        }
    }

    @Override
    @Override
    public boolean isRequestPinItemSupported(int callingUserId, int requestType) {
    public boolean isRequestPinItemSupported(int callingUserId, int requestType) {
        verifyCallerUserId(callingUserId);
        verifyCallerUserId(callingUserId);
+53 −2
Original line number Original line Diff line number Diff line
@@ -399,8 +399,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {


    public void testPushDynamicShortcut() {
    public void testPushDynamicShortcut() {
        // Change the max number of shortcuts.
        // 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);
        setCaller(CALLING_PACKAGE_1, USER_0);


        final ShortcutInfo s1 = makeShortcut("s1");
        final ShortcutInfo s1 = makeShortcut("s1");
@@ -538,6 +538,57 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
                eq(CALLING_PACKAGE_1), eq("s9"), eq(USER_0));
                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() {
    public void testUnlimitedCalls() {
        setCaller(CALLING_PACKAGE_1, USER_0);
        setCaller(CALLING_PACKAGE_1, USER_0);


+2 −0
Original line number Original line Diff line number Diff line
@@ -2136,6 +2136,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {


    public void testReportShortcutUsed() {
    public void testReportShortcutUsed() {
        mRunningUsers.put(USER_10, true);
        mRunningUsers.put(USER_10, true);
        mService.updateConfigurationLocked(
                ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=1");


        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
            reset(mMockUsageStatsManagerInternal);
            reset(mMockUsageStatsManagerInternal);