Loading apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java +23 −1 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); Loading @@ -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; } /** Loading apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +9 −5 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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)); Loading Loading @@ -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(); Loading Loading @@ -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++) { Loading Loading @@ -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++) { Loading apex/appsearch/service/java/com/android/server/appsearch/stats/LoggerInstanceManager.java +6 −16 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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") Loading Loading @@ -76,17 +70,13 @@ public final class LoggerInstanceManager { */ @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; Loading apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java +43 −59 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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: Loading Loading @@ -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. */ Loading @@ -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); Loading Loading @@ -372,7 +327,9 @@ public final class PlatformLogger implements AppSearchLogger { stats.getSchemaStoreRecoveryLatencyMillis(), stats.getDocumentStoreDataStatus(), stats.getDocumentCount(), stats.getSchemaTypeCount()); stats.getSchemaTypeCount(), stats.hasReset(), stats.getResetStatusCode()); } /** Loading Loading @@ -428,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); Loading @@ -450,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; Loading @@ -462,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); Loading Loading @@ -502,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 // Loading core/java/android/app/WallpaperColors.java +100 −14 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.util.Log; import android.util.Size; import com.android.internal.graphics.ColorUtils; import com.android.internal.graphics.cam.Cam; import com.android.internal.graphics.palette.CelebiQuantizer; import com.android.internal.graphics.palette.Palette; import com.android.internal.graphics.palette.VariationalKMeansQuantizer; Loading @@ -43,7 +44,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.Set; /** * Provides information about the colors of a wallpaper. Loading Loading @@ -176,7 +177,7 @@ public final class WallpaperColors implements Parcelable { shouldRecycle = true; Size optimalSize = calculateOptimalSize(bitmap.getWidth(), bitmap.getHeight()); bitmap = Bitmap.createScaledBitmap(bitmap, optimalSize.getWidth(), optimalSize.getHeight(), true /* filter */); optimalSize.getHeight(), false /* filter */); } final Palette palette; Loading @@ -189,7 +190,7 @@ public final class WallpaperColors implements Parcelable { } else { palette = Palette .from(bitmap, new CelebiQuantizer()) .maximumColorCount(5) .maximumColorCount(128) .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA) .generate(); } Loading Loading @@ -278,7 +279,7 @@ public final class WallpaperColors implements Parcelable { /** * Constructs a new object from a set of colors, where hints can be specified. * * @param populationByColor Map with keys of colors, and value representing the number of * @param colorToPopulation Map with keys of colors, and value representing the number of * occurrences of color in the wallpaper. * @param colorHints A combination of color hints. * @hide Loading @@ -286,20 +287,105 @@ public final class WallpaperColors implements Parcelable { * @see WallpaperColors#fromBitmap(Bitmap) * @see WallpaperColors#fromDrawable(Drawable) */ public WallpaperColors(@NonNull Map<Integer, Integer> populationByColor, public WallpaperColors(@NonNull Map<Integer, Integer> colorToPopulation, @ColorsHints int colorHints) { mAllColors = populationByColor; ArrayList<Map.Entry<Integer, Integer>> mapEntries = new ArrayList( populationByColor.entrySet()); mapEntries.sort((a, b) -> a.getValue().compareTo(b.getValue()) ); mMainColors = mapEntries.stream().map(entry -> Color.valueOf(entry.getKey())).collect( Collectors.toList()); mAllColors = colorToPopulation; final Map<Integer, Cam> colorToCam = new HashMap<>(); for (int color : colorToPopulation.keySet()) { colorToCam.put(color, Cam.fromInt(color)); } final double[] hueProportions = hueProportions(colorToCam, colorToPopulation); final Map<Integer, Double> colorToHueProportion = colorToHueProportion( colorToPopulation.keySet(), colorToCam, hueProportions); final Map<Integer, Double> colorToScore = new HashMap<>(); for (Map.Entry<Integer, Double> mapEntry : colorToHueProportion.entrySet()) { int color = mapEntry.getKey(); double proportion = mapEntry.getValue(); double score = score(colorToCam.get(color), proportion); colorToScore.put(color, score); } ArrayList<Map.Entry<Integer, Double>> mapEntries = new ArrayList(colorToScore.entrySet()); mapEntries.sort((a, b) -> b.getValue().compareTo(a.getValue())); List<Integer> colorsByScoreDescending = new ArrayList<>(); for (Map.Entry<Integer, Double> colorToScoreEntry : mapEntries) { colorsByScoreDescending.add(colorToScoreEntry.getKey()); } List<Integer> mainColorInts = new ArrayList<>(); findSeedColorLoop: for (int color : colorsByScoreDescending) { Cam cam = colorToCam.get(color); for (int otherColor : mainColorInts) { Cam otherCam = colorToCam.get(otherColor); if (hueDiff(cam, otherCam) < 15) { continue findSeedColorLoop; } } mainColorInts.add(color); } List<Color> mainColors = new ArrayList<>(); for (int colorInt : mainColorInts) { mainColors.add(Color.valueOf(colorInt)); } mMainColors = mainColors; mColorHints = colorHints; } private static double hueDiff(Cam a, Cam b) { return (180f - Math.abs(Math.abs(a.getHue() - b.getHue()) - 180f)); } private static double score(Cam cam, double proportion) { return cam.getChroma() + (proportion * 100); } private static Map<Integer, Double> colorToHueProportion(Set<Integer> colors, Map<Integer, Cam> colorToCam, double[] hueProportions) { Map<Integer, Double> colorToHueProportion = new HashMap<>(); for (int color : colors) { final int hue = wrapDegrees(Math.round(colorToCam.get(color).getHue())); double proportion = 0.0; for (int i = hue - 15; i < hue + 15; i++) { proportion += hueProportions[wrapDegrees(i)]; } colorToHueProportion.put(color, proportion); } return colorToHueProportion; } private static int wrapDegrees(int degrees) { if (degrees < 0) { return (degrees % 360) + 360; } else if (degrees >= 360) { return degrees % 360; } else { return degrees; } } private static double[] hueProportions(@NonNull Map<Integer, Cam> colorToCam, Map<Integer, Integer> colorToPopulation) { final double[] proportions = new double[360]; double totalPopulation = 0; for (Map.Entry<Integer, Integer> entry : colorToPopulation.entrySet()) { totalPopulation += entry.getValue(); } for (Map.Entry<Integer, Integer> entry : colorToPopulation.entrySet()) { final int color = (int) entry.getKey(); final int population = colorToPopulation.get(color); final Cam cam = colorToCam.get(color); final int hue = wrapDegrees(Math.round(cam.getHue())); proportions[hue] = proportions[hue] + ((double) population / totalPopulation); } return proportions; } public static final @android.annotation.NonNull Creator<WallpaperColors> CREATOR = new Creator<WallpaperColors>() { @Override public WallpaperColors createFromParcel(Parcel in) { Loading Loading
apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java +23 −1 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); Loading @@ -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; } /** Loading
apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +9 −5 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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)); Loading Loading @@ -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(); Loading Loading @@ -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++) { Loading Loading @@ -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++) { Loading
apex/appsearch/service/java/com/android/server/appsearch/stats/LoggerInstanceManager.java +6 −16 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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") Loading Loading @@ -76,17 +70,13 @@ public final class LoggerInstanceManager { */ @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; Loading
apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java +43 −59 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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: Loading Loading @@ -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. */ Loading @@ -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); Loading Loading @@ -372,7 +327,9 @@ public final class PlatformLogger implements AppSearchLogger { stats.getSchemaStoreRecoveryLatencyMillis(), stats.getDocumentStoreDataStatus(), stats.getDocumentCount(), stats.getSchemaTypeCount()); stats.getSchemaTypeCount(), stats.hasReset(), stats.getResetStatusCode()); } /** Loading Loading @@ -428,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); Loading @@ -450,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; Loading @@ -462,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); Loading Loading @@ -502,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 // Loading
core/java/android/app/WallpaperColors.java +100 −14 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.util.Log; import android.util.Size; import com.android.internal.graphics.ColorUtils; import com.android.internal.graphics.cam.Cam; import com.android.internal.graphics.palette.CelebiQuantizer; import com.android.internal.graphics.palette.Palette; import com.android.internal.graphics.palette.VariationalKMeansQuantizer; Loading @@ -43,7 +44,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.Set; /** * Provides information about the colors of a wallpaper. Loading Loading @@ -176,7 +177,7 @@ public final class WallpaperColors implements Parcelable { shouldRecycle = true; Size optimalSize = calculateOptimalSize(bitmap.getWidth(), bitmap.getHeight()); bitmap = Bitmap.createScaledBitmap(bitmap, optimalSize.getWidth(), optimalSize.getHeight(), true /* filter */); optimalSize.getHeight(), false /* filter */); } final Palette palette; Loading @@ -189,7 +190,7 @@ public final class WallpaperColors implements Parcelable { } else { palette = Palette .from(bitmap, new CelebiQuantizer()) .maximumColorCount(5) .maximumColorCount(128) .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA) .generate(); } Loading Loading @@ -278,7 +279,7 @@ public final class WallpaperColors implements Parcelable { /** * Constructs a new object from a set of colors, where hints can be specified. * * @param populationByColor Map with keys of colors, and value representing the number of * @param colorToPopulation Map with keys of colors, and value representing the number of * occurrences of color in the wallpaper. * @param colorHints A combination of color hints. * @hide Loading @@ -286,20 +287,105 @@ public final class WallpaperColors implements Parcelable { * @see WallpaperColors#fromBitmap(Bitmap) * @see WallpaperColors#fromDrawable(Drawable) */ public WallpaperColors(@NonNull Map<Integer, Integer> populationByColor, public WallpaperColors(@NonNull Map<Integer, Integer> colorToPopulation, @ColorsHints int colorHints) { mAllColors = populationByColor; ArrayList<Map.Entry<Integer, Integer>> mapEntries = new ArrayList( populationByColor.entrySet()); mapEntries.sort((a, b) -> a.getValue().compareTo(b.getValue()) ); mMainColors = mapEntries.stream().map(entry -> Color.valueOf(entry.getKey())).collect( Collectors.toList()); mAllColors = colorToPopulation; final Map<Integer, Cam> colorToCam = new HashMap<>(); for (int color : colorToPopulation.keySet()) { colorToCam.put(color, Cam.fromInt(color)); } final double[] hueProportions = hueProportions(colorToCam, colorToPopulation); final Map<Integer, Double> colorToHueProportion = colorToHueProportion( colorToPopulation.keySet(), colorToCam, hueProportions); final Map<Integer, Double> colorToScore = new HashMap<>(); for (Map.Entry<Integer, Double> mapEntry : colorToHueProportion.entrySet()) { int color = mapEntry.getKey(); double proportion = mapEntry.getValue(); double score = score(colorToCam.get(color), proportion); colorToScore.put(color, score); } ArrayList<Map.Entry<Integer, Double>> mapEntries = new ArrayList(colorToScore.entrySet()); mapEntries.sort((a, b) -> b.getValue().compareTo(a.getValue())); List<Integer> colorsByScoreDescending = new ArrayList<>(); for (Map.Entry<Integer, Double> colorToScoreEntry : mapEntries) { colorsByScoreDescending.add(colorToScoreEntry.getKey()); } List<Integer> mainColorInts = new ArrayList<>(); findSeedColorLoop: for (int color : colorsByScoreDescending) { Cam cam = colorToCam.get(color); for (int otherColor : mainColorInts) { Cam otherCam = colorToCam.get(otherColor); if (hueDiff(cam, otherCam) < 15) { continue findSeedColorLoop; } } mainColorInts.add(color); } List<Color> mainColors = new ArrayList<>(); for (int colorInt : mainColorInts) { mainColors.add(Color.valueOf(colorInt)); } mMainColors = mainColors; mColorHints = colorHints; } private static double hueDiff(Cam a, Cam b) { return (180f - Math.abs(Math.abs(a.getHue() - b.getHue()) - 180f)); } private static double score(Cam cam, double proportion) { return cam.getChroma() + (proportion * 100); } private static Map<Integer, Double> colorToHueProportion(Set<Integer> colors, Map<Integer, Cam> colorToCam, double[] hueProportions) { Map<Integer, Double> colorToHueProportion = new HashMap<>(); for (int color : colors) { final int hue = wrapDegrees(Math.round(colorToCam.get(color).getHue())); double proportion = 0.0; for (int i = hue - 15; i < hue + 15; i++) { proportion += hueProportions[wrapDegrees(i)]; } colorToHueProportion.put(color, proportion); } return colorToHueProportion; } private static int wrapDegrees(int degrees) { if (degrees < 0) { return (degrees % 360) + 360; } else if (degrees >= 360) { return degrees % 360; } else { return degrees; } } private static double[] hueProportions(@NonNull Map<Integer, Cam> colorToCam, Map<Integer, Integer> colorToPopulation) { final double[] proportions = new double[360]; double totalPopulation = 0; for (Map.Entry<Integer, Integer> entry : colorToPopulation.entrySet()) { totalPopulation += entry.getValue(); } for (Map.Entry<Integer, Integer> entry : colorToPopulation.entrySet()) { final int color = (int) entry.getKey(); final int population = colorToPopulation.get(color); final Cam cam = colorToCam.get(color); final int hue = wrapDegrees(Math.round(cam.getHue())); proportions[hue] = proportions[hue] + ((double) population / totalPopulation); } return proportions; } public static final @android.annotation.NonNull Creator<WallpaperColors> CREATOR = new Creator<WallpaperColors>() { @Override public WallpaperColors createFromParcel(Parcel in) { Loading