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

Commit 48e77cbe authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 7419753 from c50e8c3a to sc-release

Change-Id: Iddc3e2b0d2bcc8b7d0f85bc5c28c2f24812e8b6c
parents 46716e3f c50e8c3a
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
drops {
  android_build_drop {
    build_id: "7351002"
    build_id: "7396576"
    target: "CtsShim"
    source_file: "aosp_arm64/CtsShimPriv.apk"
  }
@@ -9,4 +9,5 @@ drops {
  version_group: ""
  git_project: "platform/frameworks/base"
  git_branch: "sc-dev"
  transform: TRANSFORM_NONE
}
+2 −1
Original line number Diff line number Diff line
drops {
  android_build_drop {
    build_id: "7351002"
    build_id: "7396576"
    target: "CtsShim"
    source_file: "aosp_arm64/CtsShim.apk"
  }
@@ -9,4 +9,5 @@ drops {
  version_group: ""
  git_project: "platform/frameworks/base"
  git_branch: "sc-dev"
  transform: TRANSFORM_NONE
}
+2 −1
Original line number Diff line number Diff line
drops {
  android_build_drop {
    build_id: "7351002"
    build_id: "7396576"
    target: "CtsShim"
    source_file: "aosp_x86_64/CtsShimPriv.apk"
  }
@@ -9,4 +9,5 @@ drops {
  version_group: ""
  git_project: "platform/frameworks/base"
  git_branch: "sc-dev"
  transform: TRANSFORM_NONE
}
+2 −1
Original line number Diff line number Diff line
drops {
  android_build_drop {
    build_id: "7351002"
    build_id: "7396576"
    target: "CtsShim"
    source_file: "aosp_x86_64/CtsShim.apk"
  }
@@ -9,4 +9,5 @@ drops {
  version_group: ""
  git_project: "platform/frameworks/base"
  git_branch: "sc-dev"
  transform: TRANSFORM_NONE
}
+249 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.appsearch;

import android.annotation.NonNull;
import android.os.Bundle;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.OnPropertiesChangedListener;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;

import java.util.Objects;
import java.util.concurrent.Executor;

/**
 * It contains all the keys for the flags, as well as caches some of latest flag values from
 * DeviceConfig.
 *
 * <p>Though the latest flag values can always be retrieved by calling {@code
 * DeviceConfig.getProperty}, we want to cache some of those values. For example, the sampling
 * intervals for logging, they are needed for each api call and it would be a little expensive to
 * call
 * {@code DeviceConfig.getProperty} every time.
 *
 * <p>Listener is registered to DeviceConfig keep the cached value up to date.
 *
 * <p>This class is thread-safe.
 *
 * @hide
 */
public final class AppSearchConfig implements AutoCloseable {
    /**
     * It would be used as default min time interval between samples in millis if there is no value
     * set for {@link AppSearchConfig#KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS} in DeviceConfig.
     */
    @VisibleForTesting
    static final long DEFAULT_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS = 50;

    /**
     * It would be used as default sampling interval if there is no value
     * set for {@link AppSearchConfig#KEY_SAMPLING_INTERVAL_DEFAULT} in DeviceConfig.
     */
    @VisibleForTesting
    static final int DEFAULT_SAMPLING_INTERVAL = 10;

    /*
     * Keys for ALL the flags stored in DeviceConfig.
     */
    public static final String KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS =
            "min_time_interval_between_samples_millis";
    public static final String KEY_SAMPLING_INTERVAL_DEFAULT = "sampling_interval_default";
    public static final String KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS =
            "sampling_interval_for_batch_call_stats";
    public static final String KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS =
            "sampling_interval_for_put_document_stats";

    // Array contains all the corresponding keys for the cached values.
    private static final String[] KEYS_TO_ALL_CACHED_VALUES = {
            KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
            KEY_SAMPLING_INTERVAL_DEFAULT,
            KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
            KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS
    };

    // Lock needed for all the operations in this class.
    private final Object mLock = new Object();

    /**
     * Bundle to hold all the cached flag values corresponding to
     * {@link AppSearchConfig#KEYS_TO_ALL_CACHED_VALUES}.
     */
    @GuardedBy("mLock")
    private final Bundle mBundleLocked = new Bundle();


    @GuardedBy("mLock")
    private boolean mIsClosedLocked = false;

    /** Listener to update cached flag values from DeviceConfig. */
    private final OnPropertiesChangedListener mOnDeviceConfigChangedListener =
            properties -> {
                if (!properties.getNamespace().equals(DeviceConfig.NAMESPACE_APPSEARCH)) {
                    return;
                }

                updateCachedValues(properties);
            };

    /**
     * Creates an instance of {@link AppSearchConfig}.
     *
     * @param executor used to fetch and cache the flag values from DeviceConfig during creation or
     *                 config change.
     */
    @NonNull
    public static AppSearchConfig create(@NonNull Executor executor) {
        Objects.requireNonNull(executor);
        AppSearchConfig configManager = new AppSearchConfig();
        configManager.initialize(executor);
        return configManager;
    }

    private AppSearchConfig() {
    }

    /**
     * Initializes the {@link AppSearchConfig}
     *
     * <p>It fetches the custom properties from DeviceConfig if available.
     *
     * @param executor listener would be run on to handle P/H flag change.
     */
    private void initialize(@NonNull Executor executor) {
        executor.execute(() -> {
            // Attach the callback to get updates on those properties.
            DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APPSEARCH,
                    executor,
                    mOnDeviceConfigChangedListener);

            DeviceConfig.Properties properties = DeviceConfig.getProperties(
                    DeviceConfig.NAMESPACE_APPSEARCH, KEYS_TO_ALL_CACHED_VALUES);
            updateCachedValues(properties);
        });
    }

    // TODO(b/173532925) check this will be called. If we have a singleton instance for this
    //  class, probably we don't need it.
    @Override
    public void close() {
        synchronized (mLock) {
            if (mIsClosedLocked) {
                return;
            }

            DeviceConfig.removeOnPropertiesChangedListener(mOnDeviceConfigChangedListener);
            mIsClosedLocked = true;
        }
    }

    /** Returns cached value for minTimeIntervalBetweenSamplesMillis. */
    public long getCachedMinTimeIntervalBetweenSamplesMillis() {
        synchronized (mLock) {
            throwIfClosedLocked();
            return mBundleLocked.getLong(KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
                    DEFAULT_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS);
        }
    }

    /**
     * Returns cached value for default sampling interval for all the stats NOT listed in
     * the configuration.
     *
     * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
     */
    public int getCachedSamplingIntervalDefault() {
        synchronized (mLock) {
            throwIfClosedLocked();
            return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_DEFAULT, DEFAULT_SAMPLING_INTERVAL);
        }
    }

    /**
     * Returns cached value for sampling interval for batch calls.
     *
     * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
     */
    public int getCachedSamplingIntervalForBatchCallStats() {
        synchronized (mLock) {
            throwIfClosedLocked();
            return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
                    getCachedSamplingIntervalDefault());
        }
    }

    /**
     * Returns cached value for sampling interval for putDocument.
     *
     * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
     */
    public int getCachedSamplingIntervalForPutDocumentStats() {
        synchronized (mLock) {
            throwIfClosedLocked();
            return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS,
                    getCachedSamplingIntervalDefault());
        }
    }

    @GuardedBy("mLock")
    private void throwIfClosedLocked() {
        if (mIsClosedLocked) {
            throw new IllegalStateException("Trying to use a closed AppSearchConfig instance.");
        }
    }

    private void updateCachedValues(@NonNull DeviceConfig.Properties properties) {
        for (String key : properties.getKeyset()) {
            updateCachedValue(key, properties);
        }
    }

    private void updateCachedValue(@NonNull String key,
            @NonNull DeviceConfig.Properties properties) {
        if (properties.getString(key, /*defaultValue=*/ null) == null) {
            // Key is missing or value is just null. That is not expected if the key is
            // defined in the configuration.
            //
            // We choose NOT to put the default value in the bundle.
            // Instead, we let the getters handle what default value should be returned.
            //
            // Also we keep the old value in the bundle. So getters can still
            // return last valid value.
            return;
        }

        switch (key) {
            case KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS:
                synchronized (mLock) {
                    mBundleLocked.putLong(key,
                            properties.getLong(key,
                                    DEFAULT_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS));
                }
                break;
            case KEY_SAMPLING_INTERVAL_DEFAULT:
            case KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS:
            case KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS:
                synchronized (mLock) {
                    mBundleLocked.putInt(key, properties.getInt(key, DEFAULT_SAMPLING_INTERVAL));
                }
                break;
            default:
                break;
        }
    }
}
Loading