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

Commit 5f44ba83 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 7444394 from 27475c6e to sc-release

Change-Id: I7f15b14da1fc20bf6941662c36859dd790180bc7
parents e4ea550b 27475c6e
Loading
Loading
Loading
Loading
+23 −1
Original line number Diff line number Diff line
@@ -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;
    }

    /**
+9 −5
Original line number Diff line number Diff line
@@ -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++) {
+6 −16
Original line number Diff line number Diff line
@@ -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")
@@ -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;
+43 −59
Original line number Diff line number Diff line
@@ -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);
@@ -372,7 +327,9 @@ public final class PlatformLogger implements AppSearchLogger {
                stats.getSchemaStoreRecoveryLatencyMillis(),
                stats.getDocumentStoreDataStatus(),
                stats.getDocumentCount(),
                stats.getSchemaTypeCount());
                stats.getSchemaTypeCount(),
                stats.hasReset(),
                stats.getResetStatusCode());
    }

    /**
@@ -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);
@@ -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;
@@ -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);
@@ -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
    //
+100 −14
Original line number Diff line number Diff line
@@ -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;
@@ -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.
@@ -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;
@@ -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();
        }
@@ -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
@@ -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