/* * Copyright (C) 2018 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.internal.os; import android.annotation.Nullable; import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.os.UserHandle; import android.provider.Settings; import android.util.KeyValueListParser; import android.util.Range; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Service that handles settings for {@link KernelCpuThreadReader} * *
N.B.: The `collected_uids` setting takes a string representation of what UIDs to collect data
* for. A string representation is used as we will want to express UID ranges, therefore an integer
* array could not be used. The format of the string representation is detailed here: {@link
* UidPredicate#fromString}.
*
* @hide Only for use within the system server
*/
public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
private static final String TAG = "KernelCpuThreadReaderSettingsObserver";
/** The number of frequency buckets to report */
private static final String NUM_BUCKETS_SETTINGS_KEY = "num_buckets";
private static final int NUM_BUCKETS_DEFAULT = 8;
/** List of UIDs to report data for */
private static final String COLLECTED_UIDS_SETTINGS_KEY = "collected_uids";
private static final String COLLECTED_UIDS_DEFAULT = "0-0;1000-1000";
/** Minimum total CPU usage to report */
private static final String MINIMUM_TOTAL_CPU_USAGE_MILLIS_SETTINGS_KEY =
"minimum_total_cpu_usage_millis";
private static final int MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT = 10000;
private final Context mContext;
@Nullable private final KernelCpuThreadReader mKernelCpuThreadReader;
@Nullable private final KernelCpuThreadReaderDiff mKernelCpuThreadReaderDiff;
/**
* @return returns a created {@link KernelCpuThreadReader} that will be modified by any change
* in settings, returns null if creation failed
*/
@Nullable
public static KernelCpuThreadReaderDiff getSettingsModifiedReader(Context context) {
// Create the observer
KernelCpuThreadReaderSettingsObserver settingsObserver =
new KernelCpuThreadReaderSettingsObserver(context);
// Register the observer to listen for setting changes
Uri settingsUri = Settings.Global.getUriFor(Settings.Global.KERNEL_CPU_THREAD_READER);
context.getContentResolver()
.registerContentObserver(
settingsUri, false, settingsObserver, UserHandle.USER_SYSTEM);
// Return the observer's reader
return settingsObserver.mKernelCpuThreadReaderDiff;
}
private KernelCpuThreadReaderSettingsObserver(Context context) {
super(BackgroundThread.getHandler());
mContext = context;
mKernelCpuThreadReader =
KernelCpuThreadReader.create(
NUM_BUCKETS_DEFAULT, UidPredicate.fromString(COLLECTED_UIDS_DEFAULT));
mKernelCpuThreadReaderDiff =
mKernelCpuThreadReader == null
? null
: new KernelCpuThreadReaderDiff(
mKernelCpuThreadReader, MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT);
}
@Override
public void onChange(boolean selfChange, Collection UID ranges are a pair of integers separated by a '-'. If you want to specify a single
* UID (e.g. UID 1000), you can use {@code 1000-1000}. Lists of ranges are separated by a
* single ';'. For example, this would be a valid string representation: {@code
* "1000-1999;2003-2003;2004-2004;2050-2060"}.
*
* We do not use ',' to delimit as it is already used in separating different setting
* arguments.
*
* @throws NumberFormatException if the input string is incorrectly formatted
* @throws IllegalArgumentException if an UID range has a lower end than start
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public static UidPredicate fromString(String predicateString) throws NumberFormatException {
final List