Merge "Add AppSearchConfig in AppSearch" into sc-dev

This commit is contained in:
Xiaoyu Jin
2021-06-02 22:13:37 +00:00
committed by Android (Google) Code Review
5 changed files with 623 additions and 84 deletions

View File

@@ -0,0 +1,249 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.appsearch;
import android.annotation.NonNull;
import android.os.Bundle;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.OnPropertiesChangedListener;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.util.Objects;
import java.util.concurrent.Executor;
/**
* It contains all the keys for the flags, as well as caches some of latest flag values from
* DeviceConfig.
*
* <p>Though the latest flag values can always be retrieved by calling {@code
* DeviceConfig.getProperty}, we want to cache some of those values. For example, the sampling
* intervals for logging, they are needed for each api call and it would be a little expensive to
* call
* {@code DeviceConfig.getProperty} every time.
*
* <p>Listener is registered to DeviceConfig keep the cached value up to date.
*
* <p>This class is thread-safe.
*
* @hide
*/
public final class AppSearchConfig implements AutoCloseable {
/**
* It would be used as default min time interval between samples in millis if there is no value
* set for {@link AppSearchConfig#KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS} in DeviceConfig.
*/
@VisibleForTesting
static final long DEFAULT_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS = 50;
/**
* It would be used as default sampling interval if there is no value
* set for {@link AppSearchConfig#KEY_SAMPLING_INTERVAL_DEFAULT} in DeviceConfig.
*/
@VisibleForTesting
static final int DEFAULT_SAMPLING_INTERVAL = 10;
/*
* Keys for ALL the flags stored in DeviceConfig.
*/
public static final String KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS =
"min_time_interval_between_samples_millis";
public static final String KEY_SAMPLING_INTERVAL_DEFAULT = "sampling_interval_default";
public static final String KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS =
"sampling_interval_for_batch_call_stats";
public static final String KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS =
"sampling_interval_for_put_document_stats";
// Array contains all the corresponding keys for the cached values.
private static final String[] KEYS_TO_ALL_CACHED_VALUES = {
KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
KEY_SAMPLING_INTERVAL_DEFAULT,
KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS
};
// Lock needed for all the operations in this class.
private final Object mLock = new Object();
/**
* Bundle to hold all the cached flag values corresponding to
* {@link AppSearchConfig#KEYS_TO_ALL_CACHED_VALUES}.
*/
@GuardedBy("mLock")
private final Bundle mBundleLocked = new Bundle();
@GuardedBy("mLock")
private boolean mIsClosedLocked = false;
/** Listener to update cached flag values from DeviceConfig. */
private final OnPropertiesChangedListener mOnDeviceConfigChangedListener =
properties -> {
if (!properties.getNamespace().equals(DeviceConfig.NAMESPACE_APPSEARCH)) {
return;
}
updateCachedValues(properties);
};
/**
* Creates an instance of {@link AppSearchConfig}.
*
* @param executor used to fetch and cache the flag values from DeviceConfig during creation or
* config change.
*/
@NonNull
public static AppSearchConfig create(@NonNull Executor executor) {
Objects.requireNonNull(executor);
AppSearchConfig configManager = new AppSearchConfig();
configManager.initialize(executor);
return configManager;
}
private AppSearchConfig() {
}
/**
* Initializes the {@link AppSearchConfig}
*
* <p>It fetches the custom properties from DeviceConfig if available.
*
* @param executor listener would be run on to handle P/H flag change.
*/
private void initialize(@NonNull Executor executor) {
executor.execute(() -> {
// Attach the callback to get updates on those properties.
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APPSEARCH,
executor,
mOnDeviceConfigChangedListener);
DeviceConfig.Properties properties = DeviceConfig.getProperties(
DeviceConfig.NAMESPACE_APPSEARCH, KEYS_TO_ALL_CACHED_VALUES);
updateCachedValues(properties);
});
}
// TODO(b/173532925) check this will be called. If we have a singleton instance for this
// class, probably we don't need it.
@Override
public void close() {
synchronized (mLock) {
if (mIsClosedLocked) {
return;
}
DeviceConfig.removeOnPropertiesChangedListener(mOnDeviceConfigChangedListener);
mIsClosedLocked = true;
}
}
/** Returns cached value for minTimeIntervalBetweenSamplesMillis. */
public long getCachedMinTimeIntervalBetweenSamplesMillis() {
synchronized (mLock) {
throwIfClosedLocked();
return mBundleLocked.getLong(KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
DEFAULT_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS);
}
}
/**
* Returns cached value for default sampling interval for all the stats NOT listed in
* the configuration.
*
* <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
*/
public int getCachedSamplingIntervalDefault() {
synchronized (mLock) {
throwIfClosedLocked();
return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_DEFAULT, DEFAULT_SAMPLING_INTERVAL);
}
}
/**
* Returns cached value for sampling interval for batch calls.
*
* <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
*/
public int getCachedSamplingIntervalForBatchCallStats() {
synchronized (mLock) {
throwIfClosedLocked();
return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
getCachedSamplingIntervalDefault());
}
}
/**
* Returns cached value for sampling interval for putDocument.
*
* <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
*/
public int getCachedSamplingIntervalForPutDocumentStats() {
synchronized (mLock) {
throwIfClosedLocked();
return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS,
getCachedSamplingIntervalDefault());
}
}
@GuardedBy("mLock")
private void throwIfClosedLocked() {
if (mIsClosedLocked) {
throw new IllegalStateException("Trying to use a closed AppSearchConfig instance.");
}
}
private void updateCachedValues(@NonNull DeviceConfig.Properties properties) {
for (String key : properties.getKeyset()) {
updateCachedValue(key, properties);
}
}
private void updateCachedValue(@NonNull String key,
@NonNull DeviceConfig.Properties properties) {
if (properties.getString(key, /*defaultValue=*/ null) == null) {
// Key is missing or value is just null. That is not expected if the key is
// defined in the configuration.
//
// We choose NOT to put the default value in the bundle.
// Instead, we let the getters handle what default value should be returned.
//
// Also we keep the old value in the bundle. So getters can still
// return last valid value.
return;
}
switch (key) {
case KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS:
synchronized (mLock) {
mBundleLocked.putLong(key,
properties.getLong(key,
DEFAULT_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS));
}
break;
case KEY_SAMPLING_INTERVAL_DEFAULT:
case KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS:
case KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS:
synchronized (mLock) {
mBundleLocked.putInt(key, properties.getInt(key, DEFAULT_SAMPLING_INTERVAL));
}
break;
default:
break;
}
}
}

View File

@@ -72,7 +72,7 @@ public final class PlatformLogger implements AppSearchLogger {
*
* <p> We can have correct extrapolated number by adding those counts back when we log
* the same type of stats next time. E.g. the true count of an event could be estimated as:
* SUM(sampling_ratio * (num_skipped_sample + 1)) as est_count
* SUM(sampling_interval * (num_skipped_sample + 1)) as est_count
*
* <p>The key to the SparseArray is {@link CallStats.CallType}
*/
@@ -105,42 +105,42 @@ public final class PlatformLogger implements AppSearchLogger {
// logging again.
private final long mMinTimeIntervalBetweenSamplesMillis;
// Default sampling ratio for all types of stats
private final int mDefaultSamplingRatio;
// Default sampling interval for all types of stats
private final int mDefaultSamplingInterval;
/**
* Sampling ratios for different types of stats
* Sampling intervals for different types of stats
*
* <p>This SparseArray is passed by client and is READ-ONLY. The key to that SparseArray is
* {@link CallStats.CallType}
*
* <p>If sampling ratio is missing for certain stats type,
* {@link Config#mDefaultSamplingRatio} will be used.
* <p>If sampling interval is missing for certain stats type,
* {@link Config#mDefaultSamplingInterval} will be used.
*
* <p>E.g. sampling ratio=10 means that one out of every 10 stats was logged. If sampling
* ratio is 1, we will log each sample and it acts as if the sampling is disabled.
* <p>E.g. sampling interval=10 means that one out of every 10 stats was logged. If sampling
* interval is 1, we will log each sample and it acts as if the sampling is disabled.
*/
@NonNull
private final SparseIntArray mSamplingRatios;
private final SparseIntArray mSamplingIntervals;
/**
* Configuration for {@link PlatformLogger}
*
* @param minTimeIntervalBetweenSamplesMillis minimum time interval apart in Milliseconds
* required for two consecutive stats logged
* @param defaultSamplingRatio default sampling ratio
* @param samplingRatios SparseArray to customize sampling ratio for
* @param defaultSamplingInterval default sampling interval
* @param samplingIntervals SparseArray to customize sampling interval for
* different stat types
*/
public Config(long minTimeIntervalBetweenSamplesMillis,
int defaultSamplingRatio,
@NonNull SparseIntArray samplingRatios) {
int defaultSamplingInterval,
@NonNull SparseIntArray samplingIntervals) {
// TODO(b/173532925) Probably we can get rid of those three after we have p/h flags
// for them.
// e.g. we can just call DeviceConfig.get(SAMPLING_RATIO_FOR_PUT_DOCUMENTS).
// e.g. we can just call DeviceConfig.get(SAMPLING_INTERVAL_FOR_PUT_DOCUMENTS).
mMinTimeIntervalBetweenSamplesMillis = minTimeIntervalBetweenSamplesMillis;
mDefaultSamplingRatio = defaultSamplingRatio;
mSamplingRatios = samplingRatios;
mDefaultSamplingInterval = defaultSamplingInterval;
mSamplingIntervals = samplingIntervals;
}
}
@@ -150,14 +150,14 @@ public final class PlatformLogger implements AppSearchLogger {
static final class ExtraStats {
// UID for the calling package of the stats.
final int mPackageUid;
// sampling ratio for the call type of the stats.
final int mSamplingRatio;
// sampling interval for the call type of the stats.
final int mSamplingInterval;
// number of samplings skipped before the current one for the same call type.
final int mSkippedSampleCount;
ExtraStats(int packageUid, int samplingRatio, int skippedSampleCount) {
ExtraStats(int packageUid, int samplingInterval, int skippedSampleCount) {
mPackageUid = packageUid;
mSamplingRatio = samplingRatio;
mSamplingInterval = samplingInterval;
mSkippedSampleCount = skippedSampleCount;
}
}
@@ -224,7 +224,7 @@ public final class PlatformLogger implements AppSearchLogger {
*
* @return removed UID for the package, or {@code INVALID_UID} if package was not previously
* cached.
*/
*/
public int removeCachedUidForPackage(@NonNull String packageName) {
// TODO(b/173532925) This needs to be called when we get PACKAGE_REMOVED intent
Objects.requireNonNull(packageName);
@@ -243,7 +243,7 @@ public final class PlatformLogger implements AppSearchLogger {
try {
int hashCodeForDatabase = calculateHashCodeMd5(database);
AppSearchStatsLog.write(AppSearchStatsLog.APP_SEARCH_CALL_STATS_REPORTED,
extraStats.mSamplingRatio,
extraStats.mSamplingInterval,
extraStats.mSkippedSampleCount,
extraStats.mPackageUid,
hashCodeForDatabase,
@@ -275,7 +275,7 @@ public final class PlatformLogger implements AppSearchLogger {
try {
int hashCodeForDatabase = calculateHashCodeMd5(database);
AppSearchStatsLog.write(AppSearchStatsLog.APP_SEARCH_PUT_DOCUMENT_STATS_REPORTED,
extraStats.mSamplingRatio,
extraStats.mSamplingInterval,
extraStats.mSkippedSampleCount,
extraStats.mPackageUid,
hashCodeForDatabase,
@@ -312,7 +312,7 @@ public final class PlatformLogger implements AppSearchLogger {
try {
int hashCodeForDatabase = calculateHashCodeMd5(database);
AppSearchStatsLog.write(AppSearchStatsLog.APP_SEARCH_QUERY_STATS_REPORTED,
extraStats.mSamplingRatio,
extraStats.mSamplingInterval,
extraStats.mSkippedSampleCount,
extraStats.mPackageUid,
hashCodeForDatabase,
@@ -355,7 +355,7 @@ public final class PlatformLogger implements AppSearchLogger {
ExtraStats extraStats = createExtraStatsLocked(/*packageName=*/ null,
CallStats.CALL_TYPE_INITIALIZE);
AppSearchStatsLog.write(AppSearchStatsLog.APP_SEARCH_INITIALIZE_STATS_REPORTED,
extraStats.mSamplingRatio,
extraStats.mSamplingInterval,
extraStats.mSkippedSampleCount,
extraStats.mPackageUid,
stats.getStatusCode(),
@@ -428,14 +428,14 @@ public final class PlatformLogger implements AppSearchLogger {
packageUid = getPackageUidAsUserLocked(packageName);
}
int samplingRatio = mConfig.mSamplingRatios.get(callType,
mConfig.mDefaultSamplingRatio);
int samplingInterval = mConfig.mSamplingIntervals.get(callType,
mConfig.mDefaultSamplingInterval);
int skippedSampleCount = mSkippedSampleCountLocked.get(callType,
/*valueOfKeyIfNotFound=*/ 0);
mSkippedSampleCountLocked.put(callType, 0);
return new ExtraStats(packageUid, samplingRatio, skippedSampleCount);
return new ExtraStats(packageUid, samplingInterval, skippedSampleCount);
}
/**
@@ -450,11 +450,11 @@ public final class PlatformLogger implements AppSearchLogger {
// rate limiting.
@VisibleForTesting
boolean shouldLogForTypeLocked(@CallStats.CallType int callType) {
int samplingRatio = mConfig.mSamplingRatios.get(callType,
mConfig.mDefaultSamplingRatio);
int samplingInterval = mConfig.mSamplingIntervals.get(callType,
mConfig.mDefaultSamplingInterval);
// Sampling
if (!shouldSample(samplingRatio)) {
if (!shouldSample(samplingInterval)) {
return false;
}
@@ -475,15 +475,15 @@ public final class PlatformLogger implements AppSearchLogger {
/**
* Checks if the stats should be "sampled"
*
* @param samplingRatio sampling ratio
* @param samplingInterval sampling interval
* @return if the stats should be sampled
*/
private boolean shouldSample(int samplingRatio) {
if (samplingRatio <= 0) {
private boolean shouldSample(int samplingInterval) {
if (samplingInterval <= 0) {
return false;
}
return mRng.nextInt((int) samplingRatio) == 0;
return mRng.nextInt((int) samplingInterval) == 0;
}
/**

View File

@@ -31,7 +31,10 @@ android_test {
name: "FrameworksMockingServicesTests",
defaults: ["FrameworkMockingServicesTests-jni-defaults"],
srcs: ["src/**/*.java", "src/**/*.kt"],
srcs: [
"src/**/*.java",
"src/**/*.kt",
],
static_libs: [
"services.core",
@@ -41,6 +44,7 @@ android_test {
"service-jobscheduler",
"service-permission.impl",
"service-blobstore",
"service-appsearch",
"androidx.test.runner",
"androidx.test.ext.truth",
"mockito-target-extended-minus-junit4",

View File

@@ -0,0 +1,286 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.appsearch;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import static com.google.common.truth.Truth.assertThat;
import android.provider.DeviceConfig;
import com.android.server.testables.TestableDeviceConfig;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
/**
* Tests for {@link AppSearchConfig}.
*
* <p>Build/Install/Run: atest FrameworksMockingServicesTests:AppSearchConfigTest
*/
public class AppSearchConfigTest {
@Rule
public final TestableDeviceConfig.TestableDeviceConfigRule
mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule();
@Test
public void testDefaultValues_allCachedValue() {
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
assertThat(appSearchConfig.getCachedMinTimeIntervalBetweenSamplesMillis()).isEqualTo(
AppSearchConfig.DEFAULT_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS);
assertThat(appSearchConfig.getCachedSamplingIntervalDefault()).isEqualTo(
AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo(
AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo(
AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
}
@Test
public void testCustomizedValue_minTimeIntervalBetweenSamplesMillis() {
final long minTimeIntervalBetweenSamplesMillis = -1;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
Long.toString(minTimeIntervalBetweenSamplesMillis),
false);
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
assertThat(appSearchConfig.getCachedMinTimeIntervalBetweenSamplesMillis()).isEqualTo(
minTimeIntervalBetweenSamplesMillis);
}
@Test
public void testCustomizedValueOverride_minTimeIntervalBetweenSamplesMillis() {
long minTimeIntervalBetweenSamplesMillis = -1;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
Long.toString(minTimeIntervalBetweenSamplesMillis),
false);
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
minTimeIntervalBetweenSamplesMillis = -2;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
Long.toString(minTimeIntervalBetweenSamplesMillis),
false);
assertThat(appSearchConfig.getCachedMinTimeIntervalBetweenSamplesMillis()).isEqualTo(
minTimeIntervalBetweenSamplesMillis);
}
@Test
public void testCustomizedValue_allSamplingIntervals() {
final int samplingIntervalDefault = -1;
final int samplingIntervalPutDocumentStats = -2;
final int samplingIntervalBatchCallStats = -3;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS,
Integer.toString(samplingIntervalPutDocumentStats),
false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
Integer.toString(samplingIntervalBatchCallStats),
false);
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
assertThat(appSearchConfig.getCachedSamplingIntervalDefault()).isEqualTo(
samplingIntervalDefault);
assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo(
samplingIntervalPutDocumentStats);
assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo(
samplingIntervalBatchCallStats);
}
@Test
public void testCustomizedValueOverride_allSamplingIntervals() {
int samplingIntervalDefault = -1;
int samplingIntervalPutDocumentStats = -2;
int samplingIntervalBatchCallStats = -3;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS,
Integer.toString(samplingIntervalPutDocumentStats),
false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
Integer.toString(samplingIntervalBatchCallStats),
false);
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
// Overrides
samplingIntervalDefault = -4;
samplingIntervalPutDocumentStats = -5;
samplingIntervalBatchCallStats = -6;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS,
Integer.toString(samplingIntervalPutDocumentStats),
false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
Integer.toString(samplingIntervalBatchCallStats),
false);
assertThat(appSearchConfig.getCachedSamplingIntervalDefault()).isEqualTo(
samplingIntervalDefault);
assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo(
samplingIntervalPutDocumentStats);
assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo(
samplingIntervalBatchCallStats);
}
/**
* Tests if we fall back to {@link AppSearchConfig#DEFAULT_SAMPLING_INTERVAL} if both default
* sampling
* interval and custom value are not set in DeviceConfig, and there is some other sampling
* interval
* set.
*/
@Test
public void testFallbackToDefaultSamplingValue_useHardCodedDefault() {
final int samplingIntervalPutDocumentStats = -1;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS,
Integer.toString(samplingIntervalPutDocumentStats),
false);
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo(
samplingIntervalPutDocumentStats);
assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo(
AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
}
// Tests if we fall back to configured default sampling interval if custom value is not set in
// DeviceConfig.
@Test
public void testFallbackDefaultSamplingValue_useConfiguredDefault() {
final int samplingIntervalPutDocumentStats = -1;
final int samplingIntervalDefault = -2;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS,
Integer.toString(samplingIntervalPutDocumentStats),
false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
false);
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo(
samplingIntervalPutDocumentStats);
assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo(
samplingIntervalDefault);
}
// Tests that cached values should reflect latest values in DeviceConfig.
@Test
public void testFallbackDefaultSamplingValue_defaultValueChanged() {
int samplingIntervalPutDocumentStats = -1;
int samplingIntervalDefault = -2;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS,
Integer.toString(samplingIntervalPutDocumentStats),
false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
false);
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
// Sampling values changed.
samplingIntervalPutDocumentStats = -3;
samplingIntervalDefault = -4;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS,
Integer.toString(samplingIntervalPutDocumentStats),
false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
false);
assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo(
samplingIntervalPutDocumentStats);
assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo(
samplingIntervalDefault);
}
// Tests default sampling interval won't affect custom sampling intervals if they are set.
@Test
public void testShouldNotFallBack_ifValueConfigured() {
int samplingIntervalDefault = -1;
int samplingIntervalBatchCallStats = -2;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
Integer.toString(samplingIntervalBatchCallStats),
false);
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
// Default sampling interval changed.
samplingIntervalDefault = -3;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
false);
assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo(
samplingIntervalBatchCallStats);
}
@Test
public void testNotUsable_afterClose() {
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
appSearchConfig.close();
Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
IllegalStateException.class,
() -> appSearchConfig.getCachedMinTimeIntervalBetweenSamplesMillis());
Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
IllegalStateException.class,
() -> appSearchConfig.getCachedSamplingIntervalDefault());
Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
IllegalStateException.class,
() -> appSearchConfig.getCachedSamplingIntervalForBatchCallStats());
Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
IllegalStateException.class,
() -> appSearchConfig.getCachedSamplingIntervalForPutDocumentStats());
}
}

View File

@@ -46,7 +46,7 @@ import java.security.NoSuchAlgorithmException;
public class PlatformLoggerTest {
private static final int TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS = 100;
private static final int TEST_DEFAULT_SAMPLING_RATIO = 10;
private static final int TEST_DEFAULT_SAMPLING_INTERVAL = 10;
private static final String TEST_PACKAGE_NAME = "packageName";
private MockPackageManager mMockPackageManager = new MockPackageManager();
private Context mContext;
@@ -72,63 +72,63 @@ public class PlatformLoggerTest {
}
@Test
public void testCreateExtraStatsLocked_nullSamplingRatioMap_returnsDefaultSamplingRatio() {
public void testCreateExtraStatsLocked_nullSamplingIntervalMap_returnsDefault() {
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
UserHandle.of(UserHandle.USER_NULL),
new PlatformLogger.Config(
TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
TEST_DEFAULT_SAMPLING_RATIO,
/*samplingRatios=*/ new SparseIntArray()));
TEST_DEFAULT_SAMPLING_INTERVAL,
/*samplingIntervals=*/ new SparseIntArray()));
// Make sure default sampling ratio is used if samplingMap is not provided.
// Make sure default sampling interval is used if samplingMap is not provided.
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
CallStats.CALL_TYPE_UNKNOWN).mSamplingRatio).isEqualTo(
TEST_DEFAULT_SAMPLING_RATIO);
CallStats.CALL_TYPE_UNKNOWN).mSamplingInterval).isEqualTo(
TEST_DEFAULT_SAMPLING_INTERVAL);
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
CallStats.CALL_TYPE_INITIALIZE).mSamplingRatio).isEqualTo(
TEST_DEFAULT_SAMPLING_RATIO);
CallStats.CALL_TYPE_INITIALIZE).mSamplingInterval).isEqualTo(
TEST_DEFAULT_SAMPLING_INTERVAL);
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
CallStats.CALL_TYPE_SEARCH).mSamplingRatio).isEqualTo(
TEST_DEFAULT_SAMPLING_RATIO);
CallStats.CALL_TYPE_SEARCH).mSamplingInterval).isEqualTo(
TEST_DEFAULT_SAMPLING_INTERVAL);
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
CallStats.CALL_TYPE_FLUSH).mSamplingRatio).isEqualTo(
TEST_DEFAULT_SAMPLING_RATIO);
CallStats.CALL_TYPE_FLUSH).mSamplingInterval).isEqualTo(
TEST_DEFAULT_SAMPLING_INTERVAL);
}
@Test
public void testCreateExtraStatsLocked_with_samplingRatioMap_returnsConfiguredSamplingRatio() {
int putDocumentSamplingRatio = 1;
int querySamplingRatio = 2;
final SparseIntArray samplingRatios = new SparseIntArray();
samplingRatios.put(CallStats.CALL_TYPE_PUT_DOCUMENT, putDocumentSamplingRatio);
samplingRatios.put(CallStats.CALL_TYPE_SEARCH, querySamplingRatio);
public void testCreateExtraStatsLocked_with_samplingIntervalMap_returnsConfigured() {
int putDocumentSamplingInterval = 1;
int querySamplingInterval = 2;
final SparseIntArray samplingIntervals = new SparseIntArray();
samplingIntervals.put(CallStats.CALL_TYPE_PUT_DOCUMENT, putDocumentSamplingInterval);
samplingIntervals.put(CallStats.CALL_TYPE_SEARCH, querySamplingInterval);
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
UserHandle.of(UserHandle.USER_NULL),
new PlatformLogger.Config(
TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
TEST_DEFAULT_SAMPLING_RATIO,
samplingRatios));
TEST_DEFAULT_SAMPLING_INTERVAL,
samplingIntervals));
// The default sampling ratio should be used if no sampling ratio is
// The default sampling interval should be used if no sampling interval is
// provided for certain call type.
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
CallStats.CALL_TYPE_INITIALIZE).mSamplingRatio).isEqualTo(
TEST_DEFAULT_SAMPLING_RATIO);
CallStats.CALL_TYPE_INITIALIZE).mSamplingInterval).isEqualTo(
TEST_DEFAULT_SAMPLING_INTERVAL);
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
CallStats.CALL_TYPE_FLUSH).mSamplingRatio).isEqualTo(
TEST_DEFAULT_SAMPLING_RATIO);
CallStats.CALL_TYPE_FLUSH).mSamplingInterval).isEqualTo(
TEST_DEFAULT_SAMPLING_INTERVAL);
// The configured sampling ratio is used if sampling ratio is available
// The configured sampling interval is used if sampling interval is available
// for certain call type.
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
CallStats.CALL_TYPE_PUT_DOCUMENT).mSamplingRatio).isEqualTo(
putDocumentSamplingRatio);
CallStats.CALL_TYPE_PUT_DOCUMENT).mSamplingInterval).isEqualTo(
putDocumentSamplingInterval);
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
CallStats.CALL_TYPE_SEARCH).mSamplingRatio).isEqualTo(
querySamplingRatio);
CallStats.CALL_TYPE_SEARCH).mSamplingInterval).isEqualTo(
querySamplingInterval);
}
@Test
@@ -202,16 +202,16 @@ public class PlatformLoggerTest {
}
@Test
public void testShouldLogForTypeLocked_trueWhenSampleRatioIsOne() {
final int samplingRatio = 1;
public void testShouldLogForTypeLocked_trueWhenSampleIntervalIsOne() {
final int samplingInterval = 1;
final String testPackageName = "packageName";
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
UserHandle.of(UserHandle.USER_NULL),
new PlatformLogger.Config(
TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
samplingRatio,
/*samplingRatios=*/ new SparseIntArray()));
samplingInterval,
/*samplingIntervals=*/ new SparseIntArray()));
// Sample should always be logged for the first time if sampling is disabled(value is one).
assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isTrue();
@@ -220,18 +220,18 @@ public class PlatformLoggerTest {
}
@Test
public void testShouldLogForTypeLocked_falseWhenSampleRatioIsNegative() {
final int samplingRatio = -1;
public void testShouldLogForTypeLocked_falseWhenSampleIntervalIsNegative() {
final int samplingInterval = -1;
final String testPackageName = "packageName";
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
UserHandle.of(UserHandle.USER_NULL),
new PlatformLogger.Config(
TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
samplingRatio,
/*samplingRatios=*/ new SparseIntArray()));
samplingInterval,
/*samplingIntervals=*/ new SparseIntArray()));
// Makes sure sample will be excluded due to sampling if sample ratio is negative.
// Makes sure sample will be excluded due to sampling if sample interval is negative.
assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isFalse();
// Skipped count should be 0 since it doesn't pass the sampling.
assertThat(logger.createExtraStatsLocked(testPackageName,
@@ -241,7 +241,7 @@ public class PlatformLoggerTest {
@Test
public void testShouldLogForTypeLocked_falseWhenWithinCoolOffInterval() {
// Next sample won't be excluded due to sampling.
final int samplingRatio = 1;
final int samplingInterval = 1;
// Next sample would guaranteed to be too close.
final int minTimeIntervalBetweenSamplesMillis = Integer.MAX_VALUE;
final String testPackageName = "packageName";
@@ -250,8 +250,8 @@ public class PlatformLoggerTest {
UserHandle.of(UserHandle.USER_NULL),
new PlatformLogger.Config(
minTimeIntervalBetweenSamplesMillis,
samplingRatio,
/*samplingRatios=*/ new SparseIntArray()));
samplingInterval,
/*samplingIntervals=*/ new SparseIntArray()));
logger.setLastPushTimeMillisLocked(SystemClock.elapsedRealtime());
// Makes sure sample will be excluded due to rate limiting if samples are too close.
@@ -263,7 +263,7 @@ public class PlatformLoggerTest {
@Test
public void testShouldLogForTypeLocked_trueWhenOutsideOfCoolOffInterval() {
// Next sample won't be excluded due to sampling.
final int samplingRatio = 1;
final int samplingInterval = 1;
// Next sample would guaranteed to be included.
final int minTimeIntervalBetweenSamplesMillis = 0;
final String testPackageName = "packageName";
@@ -272,8 +272,8 @@ public class PlatformLoggerTest {
UserHandle.of(UserHandle.USER_NULL),
new PlatformLogger.Config(
minTimeIntervalBetweenSamplesMillis,
samplingRatio,
/*samplingRatios=*/ new SparseIntArray()));
samplingInterval,
/*samplingIntervals=*/ new SparseIntArray()));
logger.setLastPushTimeMillisLocked(SystemClock.elapsedRealtime());
// Makes sure sample will be logged if it is not too close to previous sample.
@@ -292,8 +292,8 @@ public class PlatformLoggerTest {
mContext.getUser(),
new PlatformLogger.Config(
TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
TEST_DEFAULT_SAMPLING_RATIO,
/*samplingRatios=*/ new SparseIntArray()));
TEST_DEFAULT_SAMPLING_INTERVAL,
/*samplingIntervals=*/ new SparseIntArray()));
mMockPackageManager.mockGetPackageUidAsUser(testPackageName, mContext.getUserId(), testUid);
//