Merge "Use AppSearchConfig in PlatformLogger" into sc-dev
This commit is contained in:
@@ -44,6 +44,8 @@ import java.util.concurrent.Executor;
|
||||
* @hide
|
||||
*/
|
||||
public final class AppSearchConfig implements AutoCloseable {
|
||||
private static volatile AppSearchConfig sConfig;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -101,12 +103,16 @@ public final class AppSearchConfig implements AutoCloseable {
|
||||
updateCachedValues(properties);
|
||||
};
|
||||
|
||||
private AppSearchConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of {@link AppSearchConfig}.
|
||||
*
|
||||
* @param executor used to fetch and cache the flag values from DeviceConfig during creation or
|
||||
* config change.
|
||||
*/
|
||||
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
|
||||
@NonNull
|
||||
public static AppSearchConfig create(@NonNull Executor executor) {
|
||||
Objects.requireNonNull(executor);
|
||||
@@ -115,7 +121,23 @@ public final class AppSearchConfig implements AutoCloseable {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
private AppSearchConfig() {
|
||||
/**
|
||||
* Gets an instance of {@link AppSearchConfig} to be used.
|
||||
*
|
||||
* <p>If no instance has been initialized yet, a new one will be created. Otherwise, the
|
||||
* existing instance will be returned.
|
||||
*/
|
||||
@NonNull
|
||||
public static AppSearchConfig getInstance(@NonNull Executor executor) {
|
||||
Objects.requireNonNull(executor);
|
||||
if (sConfig == null) {
|
||||
synchronized (AppSearchConfig.class) {
|
||||
if (sConfig == null) {
|
||||
sConfig = create(executor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -224,7 +224,7 @@ public class AppSearchManagerService extends SystemService {
|
||||
if (ImplInstanceManager.getAppSearchDir(userHandle).exists()) {
|
||||
// Only clear the package's data if AppSearch exists for this user.
|
||||
PlatformLogger logger = mLoggerInstanceManager.getOrCreatePlatformLogger(mContext,
|
||||
userHandle);
|
||||
userHandle, AppSearchConfig.getInstance(EXECUTOR));
|
||||
AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
|
||||
userHandle, logger);
|
||||
//TODO(b/145759910) clear visibility setting for package.
|
||||
@@ -1147,7 +1147,8 @@ public class AppSearchManagerService extends SystemService {
|
||||
try {
|
||||
verifyUserUnlocked(callingUser);
|
||||
logger = mLoggerInstanceManager.getOrCreatePlatformLogger(
|
||||
mContext, callingUser);
|
||||
mContext, callingUser,
|
||||
AppSearchConfig.getInstance(EXECUTOR));
|
||||
mImplInstanceManager.getOrCreateAppSearchImpl(mContext, callingUser, logger);
|
||||
++operationSuccessCount;
|
||||
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
|
||||
@@ -1313,7 +1314,8 @@ public class AppSearchManagerService extends SystemService {
|
||||
try {
|
||||
verifyUserUnlocked(userHandle);
|
||||
PlatformLogger logger = mLoggerInstanceManager.getOrCreatePlatformLogger(
|
||||
mContext, userHandle);
|
||||
mContext, userHandle,
|
||||
AppSearchConfig.getInstance(EXECUTOR));
|
||||
AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(
|
||||
mContext, userHandle, logger);
|
||||
stats.dataSize += impl.getStorageInfoForPackage(packageName).getSizeBytes();
|
||||
@@ -1341,7 +1343,8 @@ public class AppSearchManagerService extends SystemService {
|
||||
return;
|
||||
}
|
||||
PlatformLogger logger = mLoggerInstanceManager.getOrCreatePlatformLogger(
|
||||
mContext, userHandle);
|
||||
mContext, userHandle,
|
||||
AppSearchConfig.getInstance(EXECUTOR));
|
||||
AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(
|
||||
mContext, userHandle, logger);
|
||||
for (int i = 0; i < packagesForUid.length; i++) {
|
||||
@@ -1370,7 +1373,8 @@ public class AppSearchManagerService extends SystemService {
|
||||
return;
|
||||
}
|
||||
PlatformLogger logger = mLoggerInstanceManager.getOrCreatePlatformLogger(
|
||||
mContext, userHandle);
|
||||
mContext, userHandle,
|
||||
AppSearchConfig.getInstance(EXECUTOR));
|
||||
AppSearchImpl impl =
|
||||
mImplInstanceManager.getOrCreateAppSearchImpl(mContext, userHandle, logger);
|
||||
for (int i = 0; i < packagesForUser.size(); i++) {
|
||||
|
||||
@@ -20,9 +20,9 @@ import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.server.appsearch.AppSearchConfig;
|
||||
import com.android.server.appsearch.AppSearchManagerService;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -34,12 +34,6 @@ import java.util.Objects;
|
||||
* <p>These instances are managed per unique device-user.
|
||||
*/
|
||||
public final class LoggerInstanceManager {
|
||||
// TODO(b/173532925) flags to control those three
|
||||
// So probably we can't pass those three in the constructor but need to fetch the latest value
|
||||
// every time we need them in the logger.
|
||||
private static final int MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS = 100;
|
||||
private static final int DEFAULT_SAMPLING_RATIO = 10;
|
||||
|
||||
private static volatile LoggerInstanceManager sLoggerInstanceManager;
|
||||
|
||||
@GuardedBy("mInstancesLocked")
|
||||
@@ -70,23 +64,19 @@ public final class LoggerInstanceManager {
|
||||
/**
|
||||
* Gets an instance of PlatformLogger for the given user, or creates one if none exists.
|
||||
*
|
||||
* @param context The context
|
||||
* @param userHandle The multi-user handle of the device user calling AppSearch
|
||||
* @param context The context
|
||||
* @param userHandle The multi-user handle of the device user calling AppSearch
|
||||
* @return An initialized {@link PlatformLogger} for this user
|
||||
*/
|
||||
@NonNull
|
||||
public PlatformLogger getOrCreatePlatformLogger(
|
||||
@NonNull Context context, @NonNull UserHandle userHandle) {
|
||||
@NonNull Context context, @NonNull UserHandle userHandle,
|
||||
@NonNull AppSearchConfig config) {
|
||||
Objects.requireNonNull(userHandle);
|
||||
synchronized (mInstancesLocked) {
|
||||
PlatformLogger instance = mInstancesLocked.get(userHandle);
|
||||
if (instance == null) {
|
||||
instance = new PlatformLogger(context, userHandle, new PlatformLogger.Config(
|
||||
MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
|
||||
DEFAULT_SAMPLING_RATIO,
|
||||
// TODO(b/173532925) re-enable sampling ratios for different stats types
|
||||
// once we have P/H flag manager setup in ag/13977824
|
||||
/*samplingRatios=*/ new SparseIntArray()));
|
||||
instance = new PlatformLogger(context, userHandle, config);
|
||||
mInstancesLocked.put(userHandle, instance);
|
||||
}
|
||||
return instance;
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.util.SparseIntArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.appsearch.AppSearchConfig;
|
||||
import com.android.server.appsearch.external.localstorage.AppSearchLogger;
|
||||
import com.android.server.appsearch.external.localstorage.stats.CallStats;
|
||||
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
|
||||
@@ -60,15 +61,15 @@ public final class PlatformLogger implements AppSearchLogger {
|
||||
// User we're logging for.
|
||||
private final UserHandle mUserHandle;
|
||||
|
||||
// Configuration for the logger
|
||||
private final Config mConfig;
|
||||
// Manager holding the configuration flags
|
||||
private final AppSearchConfig mConfig;
|
||||
|
||||
private final Random mRng = new Random();
|
||||
private final Object mLock = new Object();
|
||||
|
||||
/**
|
||||
* SparseArray to track how many stats we skipped due to
|
||||
* {@link Config#mMinTimeIntervalBetweenSamplesMillis}.
|
||||
* {@link AppSearchConfig#getCachedMinTimeIntervalBetweenSamplesMillis()}.
|
||||
*
|
||||
* <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:
|
||||
@@ -97,53 +98,6 @@ public final class PlatformLogger implements AppSearchLogger {
|
||||
@GuardedBy("mLock")
|
||||
private long mLastPushTimeMillisLocked = 0;
|
||||
|
||||
/**
|
||||
* Class to configure the {@link PlatformLogger}
|
||||
*/
|
||||
public static final class Config {
|
||||
// Minimum time interval (in millis) since last message logged to Westworld before
|
||||
// logging again.
|
||||
private final long mMinTimeIntervalBetweenSamplesMillis;
|
||||
|
||||
// Default sampling interval for all types of stats
|
||||
private final int mDefaultSamplingInterval;
|
||||
|
||||
/**
|
||||
* 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 interval is missing for certain stats type,
|
||||
* {@link Config#mDefaultSamplingInterval} will be used.
|
||||
*
|
||||
* <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 mSamplingIntervals;
|
||||
|
||||
/**
|
||||
* Configuration for {@link PlatformLogger}
|
||||
*
|
||||
* @param minTimeIntervalBetweenSamplesMillis minimum time interval apart in Milliseconds
|
||||
* required for two consecutive stats logged
|
||||
* @param defaultSamplingInterval default sampling interval
|
||||
* @param samplingIntervals SparseArray to customize sampling interval for
|
||||
* different stat types
|
||||
*/
|
||||
public Config(long minTimeIntervalBetweenSamplesMillis,
|
||||
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_INTERVAL_FOR_PUT_DOCUMENTS).
|
||||
mMinTimeIntervalBetweenSamplesMillis = minTimeIntervalBetweenSamplesMillis;
|
||||
mDefaultSamplingInterval = defaultSamplingInterval;
|
||||
mSamplingIntervals = samplingIntervals;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to hold platform specific stats for Westworld.
|
||||
*/
|
||||
@@ -166,7 +120,8 @@ public final class PlatformLogger implements AppSearchLogger {
|
||||
* Westworld constructor
|
||||
*/
|
||||
public PlatformLogger(
|
||||
@NonNull Context context, @NonNull UserHandle userHandle, @NonNull Config config) {
|
||||
@NonNull Context context, @NonNull UserHandle userHandle,
|
||||
@NonNull AppSearchConfig config) {
|
||||
mContext = Objects.requireNonNull(context);
|
||||
mUserHandle = Objects.requireNonNull(userHandle);
|
||||
mConfig = Objects.requireNonNull(config);
|
||||
@@ -430,9 +385,12 @@ public final class PlatformLogger implements AppSearchLogger {
|
||||
packageUid = getPackageUidAsUserLocked(packageName);
|
||||
}
|
||||
|
||||
int samplingInterval = mConfig.mSamplingIntervals.get(callType,
|
||||
mConfig.mDefaultSamplingInterval);
|
||||
|
||||
// The sampling ratio here might be different from the one used in
|
||||
// shouldLogForTypeLocked if there is a config change in the middle.
|
||||
// Since it is only one sample, we can just ignore this difference.
|
||||
// Or we can retrieve samplingRatio at beginning and pass along
|
||||
// as function parameter, but it will make code less cleaner with some duplication.
|
||||
int samplingInterval = getSamplingIntervalFromConfig(callType);
|
||||
int skippedSampleCount = mSkippedSampleCountLocked.get(callType,
|
||||
/*valueOfKeyIfNotFound=*/ 0);
|
||||
mSkippedSampleCountLocked.put(callType, 0);
|
||||
@@ -452,9 +410,7 @@ public final class PlatformLogger implements AppSearchLogger {
|
||||
// rate limiting.
|
||||
@VisibleForTesting
|
||||
boolean shouldLogForTypeLocked(@CallStats.CallType int callType) {
|
||||
int samplingInterval = mConfig.mSamplingIntervals.get(callType,
|
||||
mConfig.mDefaultSamplingInterval);
|
||||
|
||||
int samplingInterval = getSamplingIntervalFromConfig(callType);
|
||||
// Sampling
|
||||
if (!shouldSample(samplingInterval)) {
|
||||
return false;
|
||||
@@ -464,7 +420,7 @@ public final class PlatformLogger implements AppSearchLogger {
|
||||
// Check the timestamp to see if it is too close to last logged sample
|
||||
long currentTimeMillis = SystemClock.elapsedRealtime();
|
||||
if (mLastPushTimeMillisLocked
|
||||
> currentTimeMillis - mConfig.mMinTimeIntervalBetweenSamplesMillis) {
|
||||
> currentTimeMillis - mConfig.getCachedMinTimeIntervalBetweenSamplesMillis()) {
|
||||
int count = mSkippedSampleCountLocked.get(callType, /*valueOfKeyIfNotFound=*/ 0);
|
||||
++count;
|
||||
mSkippedSampleCountLocked.put(callType, count);
|
||||
@@ -504,6 +460,32 @@ public final class PlatformLogger implements AppSearchLogger {
|
||||
return packageUid;
|
||||
}
|
||||
|
||||
/** Returns sampling ratio for stats type specified form {@link AppSearchConfig}. */
|
||||
private int getSamplingIntervalFromConfig(@CallStats.CallType int statsType) {
|
||||
switch (statsType) {
|
||||
case CallStats.CALL_TYPE_PUT_DOCUMENTS:
|
||||
case CallStats.CALL_TYPE_GET_DOCUMENTS:
|
||||
case CallStats.CALL_TYPE_REMOVE_DOCUMENTS_BY_ID:
|
||||
case CallStats.CALL_TYPE_REMOVE_DOCUMENTS_BY_SEARCH:
|
||||
return mConfig.getCachedSamplingIntervalForBatchCallStats();
|
||||
case CallStats.CALL_TYPE_PUT_DOCUMENT:
|
||||
return mConfig.getCachedSamplingIntervalForPutDocumentStats();
|
||||
case CallStats.CALL_TYPE_UNKNOWN:
|
||||
case CallStats.CALL_TYPE_INITIALIZE:
|
||||
case CallStats.CALL_TYPE_SET_SCHEMA:
|
||||
case CallStats.CALL_TYPE_GET_DOCUMENT:
|
||||
case CallStats.CALL_TYPE_REMOVE_DOCUMENT_BY_ID:
|
||||
case CallStats.CALL_TYPE_SEARCH:
|
||||
case CallStats.CALL_TYPE_OPTIMIZE:
|
||||
case CallStats.CALL_TYPE_FLUSH:
|
||||
case CallStats.CALL_TYPE_GLOBAL_SEARCH:
|
||||
case CallStats.CALL_TYPE_REMOVE_DOCUMENT_BY_SEARCH:
|
||||
// TODO(b/173532925) Some of them above will have dedicated sampling ratio config
|
||||
default:
|
||||
return mConfig.getCachedSamplingIntervalDefault();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Functions below are used for tests only
|
||||
//
|
||||
|
||||
@@ -45,6 +45,7 @@ android_test {
|
||||
"service-permission.impl",
|
||||
"service-blobstore",
|
||||
"service-appsearch",
|
||||
"androidx.test.core",
|
||||
"androidx.test.runner",
|
||||
"androidx.test.ext.truth",
|
||||
"mockito-target-extended-minus-junit4",
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* 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.stats;
|
||||
|
||||
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.DeviceConfig;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import com.android.server.appsearch.AppSearchConfig;
|
||||
import com.android.server.appsearch.external.localstorage.stats.CallStats;
|
||||
import com.android.server.testables.TestableDeviceConfig;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* Tests covering the functionalities in {@link PlatformLogger} requiring overriding some flags
|
||||
* in {@link DeviceConfig}.
|
||||
*
|
||||
* <p>To add tests NOT rely on overriding the configs, please add them in
|
||||
* the tests for {@link PlatformLogger} in servicetests.
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class PlatformLoggerTest {
|
||||
private static final int TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS = 100;
|
||||
private static final int TEST_DEFAULT_SAMPLING_INTERVAL = 10;
|
||||
private static final String TEST_PACKAGE_NAME = "packageName";
|
||||
private AppSearchConfig mAppSearchConfig;
|
||||
|
||||
@Rule
|
||||
public final TestableDeviceConfig.TestableDeviceConfigRule
|
||||
mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mAppSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateExtraStatsLocked_samplingIntervalNotSet_returnsDefault() {
|
||||
PlatformLogger logger = new PlatformLogger(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
UserHandle.of(UserHandle.USER_NULL),
|
||||
mAppSearchConfig);
|
||||
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
|
||||
AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
|
||||
Long.toString(TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS),
|
||||
false);
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
|
||||
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
|
||||
Integer.toString(TEST_DEFAULT_SAMPLING_INTERVAL),
|
||||
false);
|
||||
|
||||
// Make sure default sampling interval is used if there is no config set.
|
||||
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
|
||||
CallStats.CALL_TYPE_UNKNOWN).mSamplingInterval).isEqualTo(
|
||||
TEST_DEFAULT_SAMPLING_INTERVAL);
|
||||
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
|
||||
CallStats.CALL_TYPE_INITIALIZE).mSamplingInterval).isEqualTo(
|
||||
TEST_DEFAULT_SAMPLING_INTERVAL);
|
||||
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
|
||||
CallStats.CALL_TYPE_SEARCH).mSamplingInterval).isEqualTo(
|
||||
TEST_DEFAULT_SAMPLING_INTERVAL);
|
||||
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
|
||||
CallStats.CALL_TYPE_FLUSH).mSamplingInterval).isEqualTo(
|
||||
TEST_DEFAULT_SAMPLING_INTERVAL);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateExtraStatsLocked_samplingIntervalSet_returnsConfigured() {
|
||||
int putDocumentSamplingInterval = 1;
|
||||
int batchCallSamplingInterval = 2;
|
||||
PlatformLogger logger = new PlatformLogger(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
UserHandle.of(UserHandle.USER_NULL), mAppSearchConfig);
|
||||
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
|
||||
AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
|
||||
Long.toString(TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS),
|
||||
false);
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
|
||||
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
|
||||
Integer.toString(TEST_DEFAULT_SAMPLING_INTERVAL),
|
||||
false);
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
|
||||
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS,
|
||||
Integer.toString(putDocumentSamplingInterval),
|
||||
false);
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
|
||||
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
|
||||
Integer.toString(batchCallSamplingInterval),
|
||||
false);
|
||||
|
||||
// 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).mSamplingInterval).isEqualTo(
|
||||
TEST_DEFAULT_SAMPLING_INTERVAL);
|
||||
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
|
||||
CallStats.CALL_TYPE_FLUSH).mSamplingInterval).isEqualTo(
|
||||
TEST_DEFAULT_SAMPLING_INTERVAL);
|
||||
|
||||
// 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).mSamplingInterval).isEqualTo(
|
||||
putDocumentSamplingInterval);
|
||||
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
|
||||
CallStats.CALL_TYPE_PUT_DOCUMENTS).mSamplingInterval).isEqualTo(
|
||||
batchCallSamplingInterval);
|
||||
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
|
||||
CallStats.CALL_TYPE_REMOVE_DOCUMENTS_BY_SEARCH).mSamplingInterval).isEqualTo(
|
||||
batchCallSamplingInterval);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldLogForTypeLocked_trueWhenSampleIntervalIsOne() {
|
||||
final String testPackageName = "packageName";
|
||||
PlatformLogger logger = new PlatformLogger(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
UserHandle.of(UserHandle.USER_NULL),
|
||||
mAppSearchConfig);
|
||||
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
|
||||
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
|
||||
Long.toString(1),
|
||||
false);
|
||||
|
||||
// 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();
|
||||
assertThat(logger.createExtraStatsLocked(testPackageName,
|
||||
CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldLogForTypeLocked_falseWhenSampleIntervalIsNegative() {
|
||||
final String testPackageName = "packageName";
|
||||
PlatformLogger logger = new PlatformLogger(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
UserHandle.of(UserHandle.USER_NULL),
|
||||
mAppSearchConfig);
|
||||
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
|
||||
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
|
||||
Long.toString(-1),
|
||||
false);
|
||||
|
||||
// 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,
|
||||
CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldLogForTypeLocked_falseWhenWithinCoolOffInterval() {
|
||||
// Next sample won't be excluded due to sampling.
|
||||
final int samplingInterval = 1;
|
||||
// Next sample would guaranteed to be too close.
|
||||
final int minTimeIntervalBetweenSamplesMillis = Integer.MAX_VALUE;
|
||||
final String testPackageName = "packageName";
|
||||
PlatformLogger logger = new PlatformLogger(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
UserHandle.of(UserHandle.USER_NULL),
|
||||
mAppSearchConfig);
|
||||
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
|
||||
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
|
||||
Long.toString(samplingInterval),
|
||||
false);
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
|
||||
AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
|
||||
Long.toString(minTimeIntervalBetweenSamplesMillis),
|
||||
false);
|
||||
logger.setLastPushTimeMillisLocked(SystemClock.elapsedRealtime());
|
||||
|
||||
// Makes sure sample will be excluded due to rate limiting if samples are too close.
|
||||
assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isFalse();
|
||||
assertThat(logger.createExtraStatsLocked(testPackageName,
|
||||
CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldLogForTypeLocked_trueWhenOutsideOfCoolOffInterval() {
|
||||
// Next sample won't be excluded due to sampling.
|
||||
final int samplingInterval = 1;
|
||||
// Next sample would guaranteed to be included.
|
||||
final int minTimeIntervalBetweenSamplesMillis = 0;
|
||||
final String testPackageName = "packageName";
|
||||
PlatformLogger logger = new PlatformLogger(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
UserHandle.of(UserHandle.USER_NULL),
|
||||
mAppSearchConfig);
|
||||
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
|
||||
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
|
||||
Long.toString(samplingInterval),
|
||||
false);
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
|
||||
AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
|
||||
Long.toString(minTimeIntervalBetweenSamplesMillis),
|
||||
false);
|
||||
logger.setLastPushTimeMillisLocked(SystemClock.elapsedRealtime());
|
||||
|
||||
// Makes sure sample will be logged if it is not too close to previous sample.
|
||||
assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isTrue();
|
||||
assertThat(logger.createExtraStatsLocked(testPackageName,
|
||||
CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(0);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.appsearch.stats;
|
||||
|
||||
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
@@ -28,13 +30,12 @@ import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import com.android.server.appsearch.AppSearchConfig;
|
||||
import com.android.server.appsearch.external.localstorage.stats.CallStats;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -48,11 +49,14 @@ import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Tests covering the functionalities in {@link PlatformLogger} NOT requiring overriding any flags
|
||||
* in {@link android.provider.DeviceConfig}.
|
||||
*
|
||||
* <p>To add tests rely on overriding the flags, please add them in the
|
||||
* tests for {@link PlatformLogger} in mockingservicestests.
|
||||
*/
|
||||
public class PlatformLoggerTest {
|
||||
private static final int TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS = 100;
|
||||
private static final int TEST_DEFAULT_SAMPLING_INTERVAL = 10;
|
||||
private static final String TEST_PACKAGE_NAME = "packageName";
|
||||
|
||||
private final Map<UserHandle, PackageManager> mMockPackageManagers = new ArrayMap<>();
|
||||
private Context mContext;
|
||||
|
||||
@@ -72,66 +76,6 @@ public class PlatformLoggerTest {
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
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_INTERVAL,
|
||||
/*samplingIntervals=*/ new SparseIntArray()));
|
||||
|
||||
// Make sure default sampling interval is used if samplingMap is not provided.
|
||||
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
|
||||
CallStats.CALL_TYPE_UNKNOWN).mSamplingInterval).isEqualTo(
|
||||
TEST_DEFAULT_SAMPLING_INTERVAL);
|
||||
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
|
||||
CallStats.CALL_TYPE_INITIALIZE).mSamplingInterval).isEqualTo(
|
||||
TEST_DEFAULT_SAMPLING_INTERVAL);
|
||||
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
|
||||
CallStats.CALL_TYPE_SEARCH).mSamplingInterval).isEqualTo(
|
||||
TEST_DEFAULT_SAMPLING_INTERVAL);
|
||||
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
|
||||
CallStats.CALL_TYPE_FLUSH).mSamplingInterval).isEqualTo(
|
||||
TEST_DEFAULT_SAMPLING_INTERVAL);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
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_INTERVAL,
|
||||
samplingIntervals));
|
||||
|
||||
// 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).mSamplingInterval).isEqualTo(
|
||||
TEST_DEFAULT_SAMPLING_INTERVAL);
|
||||
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
|
||||
CallStats.CALL_TYPE_FLUSH).mSamplingInterval).isEqualTo(
|
||||
TEST_DEFAULT_SAMPLING_INTERVAL);
|
||||
|
||||
// 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).mSamplingInterval).isEqualTo(
|
||||
putDocumentSamplingInterval);
|
||||
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
|
||||
CallStats.CALL_TYPE_SEARCH).mSamplingInterval).isEqualTo(
|
||||
querySamplingInterval);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateHashCode_MD5_int32_shortString()
|
||||
throws NoSuchAlgorithmException, UnsupportedEncodingException {
|
||||
@@ -202,87 +146,6 @@ public class PlatformLoggerTest {
|
||||
assertThat(PlatformLogger.calculateHashCodeMd5(/*str=*/ null)).isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
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,
|
||||
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();
|
||||
assertThat(logger.createExtraStatsLocked(testPackageName,
|
||||
CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
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,
|
||||
samplingInterval,
|
||||
/*samplingIntervals=*/ new SparseIntArray()));
|
||||
|
||||
// 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,
|
||||
CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldLogForTypeLocked_falseWhenWithinCoolOffInterval() {
|
||||
// Next sample won't be excluded due to sampling.
|
||||
final int samplingInterval = 1;
|
||||
// Next sample would guaranteed to be too close.
|
||||
final int minTimeIntervalBetweenSamplesMillis = Integer.MAX_VALUE;
|
||||
final String testPackageName = "packageName";
|
||||
PlatformLogger logger = new PlatformLogger(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
UserHandle.of(UserHandle.USER_NULL),
|
||||
new PlatformLogger.Config(
|
||||
minTimeIntervalBetweenSamplesMillis,
|
||||
samplingInterval,
|
||||
/*samplingIntervals=*/ new SparseIntArray()));
|
||||
logger.setLastPushTimeMillisLocked(SystemClock.elapsedRealtime());
|
||||
|
||||
// Makes sure sample will be excluded due to rate limiting if samples are too close.
|
||||
assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isFalse();
|
||||
assertThat(logger.createExtraStatsLocked(testPackageName,
|
||||
CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldLogForTypeLocked_trueWhenOutsideOfCoolOffInterval() {
|
||||
// Next sample won't be excluded due to sampling.
|
||||
final int samplingInterval = 1;
|
||||
// Next sample would guaranteed to be included.
|
||||
final int minTimeIntervalBetweenSamplesMillis = 0;
|
||||
final String testPackageName = "packageName";
|
||||
PlatformLogger logger = new PlatformLogger(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
UserHandle.of(UserHandle.USER_NULL),
|
||||
new PlatformLogger.Config(
|
||||
minTimeIntervalBetweenSamplesMillis,
|
||||
samplingInterval,
|
||||
/*samplingIntervals=*/ new SparseIntArray()));
|
||||
logger.setLastPushTimeMillisLocked(SystemClock.elapsedRealtime());
|
||||
|
||||
// Makes sure sample will be logged if it is not too close to previous sample.
|
||||
assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isTrue();
|
||||
assertThat(logger.createExtraStatsLocked(testPackageName,
|
||||
CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(0);
|
||||
}
|
||||
|
||||
/** Makes sure the caching works while getting the UID for calling package. */
|
||||
@Test
|
||||
public void testGetPackageUidAsUser() throws Exception {
|
||||
@@ -291,10 +154,7 @@ public class PlatformLoggerTest {
|
||||
PlatformLogger logger = new PlatformLogger(
|
||||
mContext,
|
||||
mContext.getUser(),
|
||||
new PlatformLogger.Config(
|
||||
TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
|
||||
TEST_DEFAULT_SAMPLING_INTERVAL,
|
||||
/*samplingIntervals=*/ new SparseIntArray()));
|
||||
AppSearchConfig.create(DIRECT_EXECUTOR));
|
||||
PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
|
||||
when(mockPackageManager.getPackageUid(testPackageName, /*flags=*/0)).thenReturn(testUid);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user