Loading core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +6 −0 Original line number Diff line number Diff line Loading @@ -573,6 +573,12 @@ public final class SystemUiDeviceConfigFlags { public static final String GENERATED_PREVIEW_API_MAX_CALLS_PER_INTERVAL = "generated_preview_api_max_calls_per_interval"; /* * (int) The max number of providers for which to keep generated previews. */ public static final String GENERATED_PREVIEW_API_MAX_PROVIDERS = "generated_preview_api_max_providers"; private SystemUiDeviceConfigFlags() { } } services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +38 −14 Original line number Diff line number Diff line Loading @@ -213,6 +213,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Duration.ofHours(1).toMillis(); // Default max API calls per reset interval for generated preview API rate limiting. private static final int DEFAULT_GENERATED_PREVIEW_MAX_CALLS_PER_INTERVAL = 2; // Default max number of providers for which to keep previews. private static final int DEFAULT_GENERATED_PREVIEW_MAX_PROVIDERS = 50; // XML attribute for widget ids that are pending deletion. // See {@link Provider#pendingDeletedWidgetIds}. private static final String PENDING_DELETED_IDS_ATTR = "pending_deleted_ids"; Loading Loading @@ -358,10 +360,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_RESET_INTERVAL_MS, DEFAULT_GENERATED_PREVIEW_RESET_INTERVAL_MS); final int generatedPreviewMaxCallsPerInterval = DeviceConfig.getInt(NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_RESET_INTERVAL_MS, SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_CALLS_PER_INTERVAL, DEFAULT_GENERATED_PREVIEW_MAX_CALLS_PER_INTERVAL); final int generatedPreviewsMaxProviders = DeviceConfig.getInt(NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_PROVIDERS, DEFAULT_GENERATED_PREVIEW_MAX_PROVIDERS); mGeneratedPreviewsApiCounter = new ApiCounter(generatedPreviewResetInterval, generatedPreviewMaxCallsPerInterval); generatedPreviewMaxCallsPerInterval, generatedPreviewsMaxProviders); DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_SYSTEMUI, new HandlerExecutor(mCallbackHandler), this::handleSystemUiDeviceConfigChange); Loading Loading @@ -4660,6 +4665,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku /* defaultValue= */ mGeneratedPreviewsApiCounter.getMaxCallsPerInterval()); mGeneratedPreviewsApiCounter.setMaxCallsPerInterval(maxCallsPerInterval); } if (changed.contains( SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_PROVIDERS)) { int maxProviders = properties.getInt( SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_PROVIDERS, /* defaultValue= */ mGeneratedPreviewsApiCounter.getMaxProviders()); mGeneratedPreviewsApiCounter.setMaxProviders(maxProviders); } } } Loading Loading @@ -5444,17 +5456,22 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private long mResetIntervalMs; // The max number of API calls per interval. private int mMaxCallsPerInterval; // The max number of providers to keep call records for. Any call to tryApiCall for new // providers will return false after this limit. private int mMaxProviders; // Returns the current time (monotonic). By default this is SystemClock.elapsedRealtime. private LongSupplier mMonotonicClock; ApiCounter(long resetIntervalMs, int maxCallsPerInterval) { this(resetIntervalMs, maxCallsPerInterval, SystemClock::elapsedRealtime); ApiCounter(long resetIntervalMs, int maxCallsPerInterval, int maxProviders) { this(resetIntervalMs, maxCallsPerInterval, maxProviders, SystemClock::elapsedRealtime); } ApiCounter(long resetIntervalMs, int maxCallsPerInterval, ApiCounter(long resetIntervalMs, int maxCallsPerInterval, int maxProviders, LongSupplier monotonicClock) { mResetIntervalMs = resetIntervalMs; mMaxCallsPerInterval = maxCallsPerInterval; mMaxProviders = maxProviders; mMonotonicClock = monotonicClock; } Loading @@ -5474,12 +5491,27 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku return mMaxCallsPerInterval; } public void setMaxProviders(int maxProviders) { mMaxProviders = maxProviders; } public int getMaxProviders() { return mMaxProviders; } /** * Returns true if the API call for the provider should be allowed, false if it should be * rate-limited. */ public boolean tryApiCall(@NonNull ProviderId provider) { final ApiCallRecord record = getOrCreateRecord(provider); if (!mCallCount.containsKey(provider)) { if (mCallCount.size() >= mMaxProviders) { return false; } mCallCount.put(provider, new ApiCallRecord()); } ApiCallRecord record = mCallCount.get(provider); final long now = mMonotonicClock.getAsLong(); final long timeSinceLastResetMs = now - record.lastResetTimeMs; // If the last reset was beyond the reset interval, reset now. Loading @@ -5500,14 +5532,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku public void remove(@NonNull ProviderId id) { mCallCount.remove(id); } @NonNull private ApiCallRecord getOrCreateRecord(@NonNull ProviderId provider) { if (!mCallCount.containsKey(provider)) { mCallCount.put(provider, new ApiCallRecord()); } return mCallCount.get(provider); } } private class LoadedWidgetState { Loading services/tests/servicestests/src/com/android/server/appwidget/ApiCounterTest.kt +20 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ class ApiCounterTest { private companion object { const val RESET_INTERVAL_MS = 10L const val MAX_CALLS_PER_INTERVAL = 2 const val MAX_PROVIDERS = 10 } private var currentTime = 0L Loading @@ -34,7 +35,9 @@ class ApiCounterTest { /* uid= */ 123, ComponentName("com.android.server.appwidget", "FakeProviderClass") ) private val counter = ApiCounter(RESET_INTERVAL_MS, MAX_CALLS_PER_INTERVAL) { currentTime } private val counter = ApiCounter(RESET_INTERVAL_MS, MAX_CALLS_PER_INTERVAL, MAX_PROVIDERS) { currentTime } @Test fun tryApiCall() { Loading @@ -58,4 +61,20 @@ class ApiCounterTest { counter.remove(id) assertThat(counter.tryApiCall(id)).isTrue() } @Test fun maxProviders() { for (i in 0 until MAX_PROVIDERS) { for (j in 0 until MAX_CALLS_PER_INTERVAL) { assertThat(counter.tryApiCall(providerId(i))).isTrue() } } assertThat(counter.tryApiCall(providerId(MAX_PROVIDERS))).isFalse() // remove will allow another provider to be added counter.remove(providerId(0)) assertThat(counter.tryApiCall(providerId(MAX_PROVIDERS))).isTrue() } private fun providerId(i: Int) = AppWidgetServiceImpl.ProviderId(/* uid= */ i, id.componentName) } Loading
core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +6 −0 Original line number Diff line number Diff line Loading @@ -573,6 +573,12 @@ public final class SystemUiDeviceConfigFlags { public static final String GENERATED_PREVIEW_API_MAX_CALLS_PER_INTERVAL = "generated_preview_api_max_calls_per_interval"; /* * (int) The max number of providers for which to keep generated previews. */ public static final String GENERATED_PREVIEW_API_MAX_PROVIDERS = "generated_preview_api_max_providers"; private SystemUiDeviceConfigFlags() { } }
services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +38 −14 Original line number Diff line number Diff line Loading @@ -213,6 +213,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Duration.ofHours(1).toMillis(); // Default max API calls per reset interval for generated preview API rate limiting. private static final int DEFAULT_GENERATED_PREVIEW_MAX_CALLS_PER_INTERVAL = 2; // Default max number of providers for which to keep previews. private static final int DEFAULT_GENERATED_PREVIEW_MAX_PROVIDERS = 50; // XML attribute for widget ids that are pending deletion. // See {@link Provider#pendingDeletedWidgetIds}. private static final String PENDING_DELETED_IDS_ATTR = "pending_deleted_ids"; Loading Loading @@ -358,10 +360,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_RESET_INTERVAL_MS, DEFAULT_GENERATED_PREVIEW_RESET_INTERVAL_MS); final int generatedPreviewMaxCallsPerInterval = DeviceConfig.getInt(NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_RESET_INTERVAL_MS, SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_CALLS_PER_INTERVAL, DEFAULT_GENERATED_PREVIEW_MAX_CALLS_PER_INTERVAL); final int generatedPreviewsMaxProviders = DeviceConfig.getInt(NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_PROVIDERS, DEFAULT_GENERATED_PREVIEW_MAX_PROVIDERS); mGeneratedPreviewsApiCounter = new ApiCounter(generatedPreviewResetInterval, generatedPreviewMaxCallsPerInterval); generatedPreviewMaxCallsPerInterval, generatedPreviewsMaxProviders); DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_SYSTEMUI, new HandlerExecutor(mCallbackHandler), this::handleSystemUiDeviceConfigChange); Loading Loading @@ -4660,6 +4665,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku /* defaultValue= */ mGeneratedPreviewsApiCounter.getMaxCallsPerInterval()); mGeneratedPreviewsApiCounter.setMaxCallsPerInterval(maxCallsPerInterval); } if (changed.contains( SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_PROVIDERS)) { int maxProviders = properties.getInt( SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_PROVIDERS, /* defaultValue= */ mGeneratedPreviewsApiCounter.getMaxProviders()); mGeneratedPreviewsApiCounter.setMaxProviders(maxProviders); } } } Loading Loading @@ -5444,17 +5456,22 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private long mResetIntervalMs; // The max number of API calls per interval. private int mMaxCallsPerInterval; // The max number of providers to keep call records for. Any call to tryApiCall for new // providers will return false after this limit. private int mMaxProviders; // Returns the current time (monotonic). By default this is SystemClock.elapsedRealtime. private LongSupplier mMonotonicClock; ApiCounter(long resetIntervalMs, int maxCallsPerInterval) { this(resetIntervalMs, maxCallsPerInterval, SystemClock::elapsedRealtime); ApiCounter(long resetIntervalMs, int maxCallsPerInterval, int maxProviders) { this(resetIntervalMs, maxCallsPerInterval, maxProviders, SystemClock::elapsedRealtime); } ApiCounter(long resetIntervalMs, int maxCallsPerInterval, ApiCounter(long resetIntervalMs, int maxCallsPerInterval, int maxProviders, LongSupplier monotonicClock) { mResetIntervalMs = resetIntervalMs; mMaxCallsPerInterval = maxCallsPerInterval; mMaxProviders = maxProviders; mMonotonicClock = monotonicClock; } Loading @@ -5474,12 +5491,27 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku return mMaxCallsPerInterval; } public void setMaxProviders(int maxProviders) { mMaxProviders = maxProviders; } public int getMaxProviders() { return mMaxProviders; } /** * Returns true if the API call for the provider should be allowed, false if it should be * rate-limited. */ public boolean tryApiCall(@NonNull ProviderId provider) { final ApiCallRecord record = getOrCreateRecord(provider); if (!mCallCount.containsKey(provider)) { if (mCallCount.size() >= mMaxProviders) { return false; } mCallCount.put(provider, new ApiCallRecord()); } ApiCallRecord record = mCallCount.get(provider); final long now = mMonotonicClock.getAsLong(); final long timeSinceLastResetMs = now - record.lastResetTimeMs; // If the last reset was beyond the reset interval, reset now. Loading @@ -5500,14 +5532,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku public void remove(@NonNull ProviderId id) { mCallCount.remove(id); } @NonNull private ApiCallRecord getOrCreateRecord(@NonNull ProviderId provider) { if (!mCallCount.containsKey(provider)) { mCallCount.put(provider, new ApiCallRecord()); } return mCallCount.get(provider); } } private class LoadedWidgetState { Loading
services/tests/servicestests/src/com/android/server/appwidget/ApiCounterTest.kt +20 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ class ApiCounterTest { private companion object { const val RESET_INTERVAL_MS = 10L const val MAX_CALLS_PER_INTERVAL = 2 const val MAX_PROVIDERS = 10 } private var currentTime = 0L Loading @@ -34,7 +35,9 @@ class ApiCounterTest { /* uid= */ 123, ComponentName("com.android.server.appwidget", "FakeProviderClass") ) private val counter = ApiCounter(RESET_INTERVAL_MS, MAX_CALLS_PER_INTERVAL) { currentTime } private val counter = ApiCounter(RESET_INTERVAL_MS, MAX_CALLS_PER_INTERVAL, MAX_PROVIDERS) { currentTime } @Test fun tryApiCall() { Loading @@ -58,4 +61,20 @@ class ApiCounterTest { counter.remove(id) assertThat(counter.tryApiCall(id)).isTrue() } @Test fun maxProviders() { for (i in 0 until MAX_PROVIDERS) { for (j in 0 until MAX_CALLS_PER_INTERVAL) { assertThat(counter.tryApiCall(providerId(i))).isTrue() } } assertThat(counter.tryApiCall(providerId(MAX_PROVIDERS))).isFalse() // remove will allow another provider to be added counter.remove(providerId(0)) assertThat(counter.tryApiCall(providerId(MAX_PROVIDERS))).isTrue() } private fun providerId(i: Int) = AppWidgetServiceImpl.ProviderId(/* uid= */ i, id.componentName) }