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

Commit 5d108838 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Binary Cpu Time Proc File Reader"

parents 2757d757 2ab01442
Loading
Loading
Loading
Loading
+36 −8
Original line number Diff line number Diff line
@@ -110,7 +110,10 @@ import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
@@ -12334,7 +12337,7 @@ public class BatteryStatsImpl extends BatteryStats {
    @VisibleForTesting
    public void readKernelUidCpuActiveTimesLocked(boolean onBattery) {
        final long startTimeMs = mClocks.uptimeMillis();
        mKernelUidCpuActiveTimeReader.readDelta((uid, cpuActiveTimesUs) -> {
        mKernelUidCpuActiveTimeReader.readDelta((uid, cpuActiveTimesMs) -> {
            uid = mapUid(uid);
            if (Process.isIsolated(uid)) {
                mKernelUidCpuActiveTimeReader.removeUid(uid);
@@ -12347,7 +12350,7 @@ public class BatteryStatsImpl extends BatteryStats {
                return;
            }
            final Uid u = getUidStatsLocked(uid);
            u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesUs, onBattery);
            u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesMs, onBattery);
        });
        final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
@@ -12363,7 +12366,7 @@ public class BatteryStatsImpl extends BatteryStats {
    @VisibleForTesting
    public void readKernelUidCpuClusterTimesLocked(boolean onBattery) {
        final long startTimeMs = mClocks.uptimeMillis();
        mKernelUidCpuClusterTimeReader.readDelta((uid, cpuClusterTimesUs) -> {
        mKernelUidCpuClusterTimeReader.readDelta((uid, cpuClusterTimesMs) -> {
            uid = mapUid(uid);
            if (Process.isIsolated(uid)) {
                mKernelUidCpuClusterTimeReader.removeUid(uid);
@@ -12376,7 +12379,7 @@ public class BatteryStatsImpl extends BatteryStats {
                return;
            }
            final Uid u = getUidStatsLocked(uid);
            u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesUs, onBattery);
            u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesMs, onBattery);
        });
        final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
@@ -13326,17 +13329,20 @@ public class BatteryStatsImpl extends BatteryStats {
                = "read_binary_cpu_time";
        public static final String KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS
                = "proc_state_cpu_times_read_delay_ms";
        public static final String KEY_KERNEL_UID_READERS_THROTTLE_TIME
                = "kernel_uid_readers_throttle_time";
        private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = true;
        private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
        private static final boolean DEFAULT_READ_BINARY_CPU_TIME = false;
        private static final long DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS = 5_000;
        private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 10_000;
        public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE;
        public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
        // Not used right now.
        public boolean READ_BINARY_CPU_TIME = DEFAULT_READ_BINARY_CPU_TIME;
        public long PROC_STATE_CPU_TIMES_READ_DELAY_MS = DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS;
        public long KERNEL_UID_READERS_THROTTLE_TIME = DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME;
        private ContentResolver mResolver;
        private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -13374,11 +13380,14 @@ public class BatteryStatsImpl extends BatteryStats {
                                DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE));
                TRACK_CPU_ACTIVE_CLUSTER_TIME = mParser.getBoolean(
                        KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME, DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME);
                READ_BINARY_CPU_TIME = mParser.getBoolean(
                        KEY_READ_BINARY_CPU_TIME, DEFAULT_READ_BINARY_CPU_TIME);
                updateReadBinaryCpuTime(READ_BINARY_CPU_TIME,
                        mParser.getBoolean(KEY_READ_BINARY_CPU_TIME, DEFAULT_READ_BINARY_CPU_TIME));
                updateProcStateCpuTimesReadDelayMs(PROC_STATE_CPU_TIMES_READ_DELAY_MS,
                        mParser.getLong(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS,
                                DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS));
                updateKernelUidReadersThrottleTime(KERNEL_UID_READERS_THROTTLE_TIME,
                        mParser.getLong(KEY_KERNEL_UID_READERS_THROTTLE_TIME,
                                DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME));
            }
        }
@@ -13394,6 +13403,13 @@ public class BatteryStatsImpl extends BatteryStats {
            }
        }
        private void updateReadBinaryCpuTime(boolean oldEnabled, boolean isEnabled) {
            READ_BINARY_CPU_TIME = isEnabled;
            if (oldEnabled != isEnabled) {
                mKernelUidCpuFreqTimeReader.setReadBinary(isEnabled);
            }
        }
        private void updateProcStateCpuTimesReadDelayMs(long oldDelayMillis, long newDelayMillis) {
            PROC_STATE_CPU_TIMES_READ_DELAY_MS = newDelayMillis;
            if (oldDelayMillis != newDelayMillis) {
@@ -13403,6 +13419,16 @@ public class BatteryStatsImpl extends BatteryStats {
            }
        }
        private void updateKernelUidReadersThrottleTime(long oldTimeMs, long newTimeMs) {
            KERNEL_UID_READERS_THROTTLE_TIME = newTimeMs;
            if (oldTimeMs != newTimeMs) {
                mKernelUidCpuFreqTimeReader.setThrottleInterval(KERNEL_UID_READERS_THROTTLE_TIME);
                mKernelUidCpuActiveTimeReader.setThrottleInterval(KERNEL_UID_READERS_THROTTLE_TIME);
                mKernelUidCpuClusterTimeReader
                        .setThrottleInterval(KERNEL_UID_READERS_THROTTLE_TIME);
            }
        }
        public void dumpLocked(PrintWriter pw) {
            pw.print(KEY_TRACK_CPU_TIMES_BY_PROC_STATE); pw.print("=");
            pw.println(TRACK_CPU_TIMES_BY_PROC_STATE);
@@ -13412,6 +13438,8 @@ public class BatteryStatsImpl extends BatteryStats {
            pw.println(READ_BINARY_CPU_TIME);
            pw.print(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS); pw.print("=");
            pw.println(PROC_STATE_CPU_TIMES_READ_DELAY_MS);
            pw.print(KEY_KERNEL_UID_READERS_THROTTLE_TIME); pw.print("=");
            pw.println(KERNEL_UID_READERS_THROTTLE_TIME);
        }
    }
+3 −2
Original line number Diff line number Diff line
@@ -50,13 +50,14 @@ public class CpuPowerCalculator extends PowerCalculator {
                cpuPowerMaUs += cpuSpeedStepPower;
            }
        }
        cpuPowerMaUs += u.getCpuActiveTime() * mProfile.getAveragePower(
        cpuPowerMaUs += u.getCpuActiveTime() * 1000 * mProfile.getAveragePower(
                PowerProfile.POWER_CPU_ACTIVE);
        long[] cpuClusterTimes = u.getCpuClusterTimes();
        if (cpuClusterTimes != null) {
            if (cpuClusterTimes.length == numClusters) {
                for (int i = 0; i < numClusters; i++) {
                    double power = cpuClusterTimes[i] * mProfile.getAveragePowerForCpuCluster(i);
                    double power =
                            cpuClusterTimes[i] * 1000 * mProfile.getAveragePowerForCpuCluster(i);
                    cpuPowerMaUs += power;
                    if (DEBUG) {
                        Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + i + " clusterTimeUs="
+159 −0
Original line number Diff line number Diff line
/*
 * 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.os.StrictMode;
import android.os.SystemClock;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
 * Reads cpu time proc files with throttling (adjustable interval).
 *
 * KernelCpuProcReader is implemented as singletons for built-in kernel proc files. Get___Instance()
 * method will return corresponding reader instance. In order to prevent frequent GC,
 * KernelCpuProcReader reuses a {@link ByteBuffer} to store data read from proc files.
 *
 * A KernelCpuProcReader instance keeps an error counter. When the number of read errors within that
 * instance accumulates to 5, this instance will reject all further read requests.
 *
 * Each KernelCpuProcReader instance also has a throttler. Throttle interval can be adjusted via
 * {@link #setThrottleInterval(long)} method. Default throttle interval is 3000ms. If current
 * timestamp based on {@link SystemClock#elapsedRealtime()} is less than throttle interval from
 * the last read timestamp, {@link #readBytes()} will return previous result.
 *
 * A KernelCpuProcReader instance is thread-unsafe. Caller needs to hold a lock on this object while
 * accessing its instance methods or digesting the return values.
 */
public class KernelCpuProcReader {
    private static final String TAG = "KernelCpuProcReader";
    private static final int ERROR_THRESHOLD = 5;
    // Throttle interval in milliseconds
    private static final long DEFAULT_THROTTLE_INTERVAL = 3000L;
    private static final int INITIAL_BUFFER_SIZE = 8 * 1024;
    private static final int MAX_BUFFER_SIZE = 1024 * 1024;
    private static final String PROC_UID_FREQ_TIME = "/proc/uid_cpupower/time_in_state";
    private static final String PROC_UID_ACTIVE_TIME = "/proc/uid_cpupower/concurrent_active_time";
    private static final String PROC_UID_CLUSTER_TIME = "/proc/uid_cpupower/concurrent_policy_time";

    private static final KernelCpuProcReader mFreqTimeReader = new KernelCpuProcReader(
            PROC_UID_FREQ_TIME);
    private static final KernelCpuProcReader mActiveTimeReader = new KernelCpuProcReader(
            PROC_UID_ACTIVE_TIME);
    private static final KernelCpuProcReader mClusterTimeReader = new KernelCpuProcReader(
            PROC_UID_CLUSTER_TIME);

    public static KernelCpuProcReader getFreqTimeReaderInstance() {
        return mFreqTimeReader;
    }

    public static KernelCpuProcReader getActiveTimeReaderInstance() {
        return mActiveTimeReader;
    }

    public static KernelCpuProcReader getClusterTimeReaderInstance() {
        return mClusterTimeReader;
    }

    private int mErrors;
    private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL;
    private long mLastReadTime = Long.MIN_VALUE;
    private final Path mProc;
    private ByteBuffer mBuffer;

    @VisibleForTesting
    public KernelCpuProcReader(String procFile) {
        mProc = Paths.get(procFile);
        mBuffer = ByteBuffer.allocateDirect(INITIAL_BUFFER_SIZE);
        mBuffer.clear();
    }

    /**
     * Reads all bytes from the corresponding proc file.
     *
     * If elapsed time since last call to this method is less than the throttle interval, it will
     * return previous result. When IOException accumulates to 5, it will always return null. This
     * method is thread-unsafe, so is the return value. Caller needs to hold a lock on this
     * object while calling this method and digesting its return value.
     *
     * @return a {@link ByteBuffer} containing all bytes from the proc file.
     */
    public ByteBuffer readBytes() {
        if (mErrors >= ERROR_THRESHOLD) {
            return null;
        }
        if (SystemClock.elapsedRealtime() < mLastReadTime + mThrottleInterval) {
            if (mBuffer.limit() > 0 && mBuffer.limit() < mBuffer.capacity()) {
                // mBuffer has data.
                return mBuffer.asReadOnlyBuffer().order(ByteOrder.nativeOrder());
            }
            return null;
        }
        mLastReadTime = SystemClock.elapsedRealtime();
        mBuffer.clear();
        final int oldMask = StrictMode.allowThreadDiskReadsMask();
        try (FileChannel fc = FileChannel.open(mProc, StandardOpenOption.READ)) {
            while (fc.read(mBuffer) == mBuffer.capacity()) {
                if (!resize()) {
                    mErrors++;
                    Slog.e(TAG, "Proc file is too large: " + mProc);
                    return null;
                }
                fc.position(0);
            }
        } catch (IOException e) {
            mErrors++;
            Slog.e(TAG, "Error reading: " + mProc, e);
            return null;
        } finally {
            StrictMode.setThreadPolicyMask(oldMask);
        }
        mBuffer.flip();
        return mBuffer.asReadOnlyBuffer().order(ByteOrder.nativeOrder());
    }

    /**
     * Sets the throttle interval. Set to 0 will disable throttling. Thread-unsafe, holding a lock
     * on this object is recommended.
     *
     * @param throttleInterval throttle interval in milliseconds
     */
    public void setThrottleInterval(long throttleInterval) {
        if (throttleInterval >= 0) {
            mThrottleInterval = throttleInterval;
        }
    }

    private boolean resize() {
        if (mBuffer.capacity() >= MAX_BUFFER_SIZE) {
            return false;
        }
        int newSize = Math.min(mBuffer.capacity() << 1, MAX_BUFFER_SIZE);
        // Slog.i(TAG, "Resize buffer " + mBuffer.capacity() + " => " + newSize);
        mBuffer = ByteBuffer.allocateDirect(newSize);
        return true;
    }
}
+93 −86
Original line number Diff line number Diff line
@@ -17,130 +17,137 @@
package com.android.internal.os;

import android.annotation.Nullable;
import android.os.StrictMode;
import android.os.SystemClock;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;

import com.android.internal.annotations.VisibleForTesting;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;

/**
 * Reads /proc/uid_concurrent_active_time which has the format:
 * active: X (X is # cores)
 * [uid0]: [time-0] [time-1] [time-2] ... (# entries = # cores)
 * [uid1]: [time-0] [time-1] [time-2] ... ...
 * Reads binary proc file /proc/uid_cpupower/concurrent_active_time and reports CPU active time to
 * BatteryStats to compute {@link PowerProfile#POWER_CPU_ACTIVE}.
 *
 * concurrent_active_time is an array of u32's in the following format:
 * [n, uid0, time0a, time0b, ..., time0n,
 * uid1, time1a, time1b, ..., time1n,
 * uid2, time2a, time2b, ..., time2n, etc.]
 * where n is the total number of cpus (num_possible_cpus)
 * ...
 * Time-N means the CPU time a UID spent running concurrently with N other processes.
 * timeXn means the CPU time that a UID X spent running concurrently with n other processes.
 * The file contains a monotonically increasing count of time for a single boot. This class
 * maintains the previous results of a call to {@link #readDelta} in order to provide a
 * proper delta.
 *
 * This class uses a throttler to reject any {@link #readDelta} call within
 * {@link #mThrottleInterval}. This is different from the throttler in {@link KernelCpuProcReader},
 * which has a shorter throttle interval and returns cached result from last read when the request
 * is throttled.
 *
 * This class is NOT thread-safe and NOT designed to be accessed by more than one caller (due to
 * the nature of {@link #readDelta(Callback)}).
 */
public class KernelUidCpuActiveTimeReader {
    private static final boolean DEBUG = false;
    private static final String TAG = "KernelUidCpuActiveTimeReader";
    private static final String UID_TIMES_PROC_FILE = "/proc/uid_concurrent_active_time";
    // Throttle interval in milliseconds
    private static final long DEFAULT_THROTTLE_INTERVAL = 10_000L;

    private int mCoreCount;
    private long mLastTimeReadMs;
    private long mNowTimeMs;
    private SparseArray<long[]> mLastUidCpuActiveTimeMs = new SparseArray<>();
    private final KernelCpuProcReader mProcReader;
    private long mLastTimeReadMs = Long.MIN_VALUE;
    private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL;
    private SparseArray<Double> mLastUidCpuActiveTimeMs = new SparseArray<>();

    public interface Callback {
        /**
         * Notifies when new data is available.
         *
         * @param uid             uid int
         * @param cpuActiveTimeMs cpu active time spent by this uid in milliseconds
         */
        void onUidCpuActiveTime(int uid, long cpuActiveTimeMs);
    }

    public void readDelta(@Nullable Callback cb) {
        final int oldMask = StrictMode.allowThreadDiskReadsMask();
        try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) {
            mNowTimeMs = SystemClock.elapsedRealtime();
            readDeltaInternal(reader, cb);
            mLastTimeReadMs = mNowTimeMs;
        } catch (IOException e) {
            Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
        } finally {
            StrictMode.setThreadPolicyMask(oldMask);
        }
    public KernelUidCpuActiveTimeReader() {
        mProcReader = KernelCpuProcReader.getActiveTimeReaderInstance();
    }

    public void removeUid(int uid) {
        mLastUidCpuActiveTimeMs.delete(uid);
    @VisibleForTesting
    public KernelUidCpuActiveTimeReader(KernelCpuProcReader procReader) {
        mProcReader = procReader;
    }

    public void removeUidsInRange(int startUid, int endUid) {
        if (endUid < startUid) {
            Slog.w(TAG, "End UID " + endUid + " is smaller than start UID " + startUid);
    public void readDelta(@Nullable Callback cb) {
        if (SystemClock.elapsedRealtime() < mLastTimeReadMs + mThrottleInterval) {
            Slog.w(TAG, "Throttle");
            return;
        }
        mLastUidCpuActiveTimeMs.put(startUid, null);
        mLastUidCpuActiveTimeMs.put(endUid, null);
        final int firstIndex = mLastUidCpuActiveTimeMs.indexOfKey(startUid);
        final int lastIndex = mLastUidCpuActiveTimeMs.indexOfKey(endUid);
        mLastUidCpuActiveTimeMs.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
        synchronized (mProcReader) {
            final ByteBuffer bytes = mProcReader.readBytes();
            if (bytes == null || bytes.remaining() <= 4) {
                // Error already logged in mProcReader.
                return;
            }

    @VisibleForTesting
    public void readDeltaInternal(BufferedReader reader, @Nullable Callback cb) throws IOException {
        String line = reader.readLine();
        if (line == null || !line.startsWith("active:")) {
            Slog.e(TAG, String.format("Malformed proc file: %s ", UID_TIMES_PROC_FILE));
            if ((bytes.remaining() & 3) != 0) {
                Slog.wtf(TAG,
                        "Cannot parse active time proc bytes to int: " + bytes.remaining());
                return;
            }
        if (mCoreCount == 0) {
            mCoreCount = Integer.parseInt(line.substring(line.indexOf(' ')+1));
            final IntBuffer buf = bytes.asIntBuffer();
            final int cores = buf.get();
            if (cores <= 0 || buf.remaining() % (cores + 1) != 0) {
                Slog.wtf(TAG,
                        "Cpu active time format error: " + buf.remaining() + " / " + (cores
                                + 1));
                return;
            }
        while ((line = reader.readLine()) != null) {
            final int index = line.indexOf(' ');
            final int uid = Integer.parseInt(line.substring(0, index - 1), 10);
            readTimesForUid(uid, line.substring(index + 1), cb);
            int numUids = buf.remaining() / (cores + 1);
            for (int i = 0; i < numUids; i++) {
                int uid = buf.get();
                boolean corrupted = false;
                double curTime = 0;
                for (int j = 1; j <= cores; j++) {
                    int time = buf.get();
                    if (time < 0) {
                        Slog.e(TAG, "Corrupted data from active time proc: " + time);
                        corrupted = true;
                    } else {
                        curTime += (double) time * 10 / j; // Unit is 10ms.
                    }
                }
                double delta = curTime - mLastUidCpuActiveTimeMs.get(uid, 0.0);
                if (delta > 0 && !corrupted) {
                    mLastUidCpuActiveTimeMs.put(uid, curTime);
                    if (cb != null) {
                        cb.onUidCpuActiveTime(uid, (long) delta);
                    }
                }

    private void readTimesForUid(int uid, String line, @Nullable Callback cb) {
        long[] lastActiveTime = mLastUidCpuActiveTimeMs.get(uid);
        if (lastActiveTime == null) {
            lastActiveTime = new long[mCoreCount];
            mLastUidCpuActiveTimeMs.put(uid, lastActiveTime);
        }
        final String[] timesStr = line.split(" ");
        if (timesStr.length != mCoreCount) {
            Slog.e(TAG, String.format("# readings don't match # cores, readings: %d, CPU cores: %d",
                    timesStr.length, mCoreCount));
            return;
            }
        long sumDeltas = 0;
        final long[] curActiveTime = new long[mCoreCount];
        boolean notify = false;
        for (int i = 0; i < mCoreCount; i++) {
            // Times read will be in units of 10ms
            curActiveTime[i] = Long.parseLong(timesStr[i], 10) * 10;
            long delta = curActiveTime[i] - lastActiveTime[i];
            if (delta < 0 || curActiveTime[i] < 0) {
                if (DEBUG) {
                    final StringBuilder sb = new StringBuilder();
                    sb.append(String.format("Malformed cpu active time for UID=%d\n", uid));
                    sb.append(String.format("data=(%d,%d)\n", lastActiveTime[i], curActiveTime[i]));
                    sb.append("times=(");
                    TimeUtils.formatDuration(mLastTimeReadMs, sb);
                    sb.append(",");
                    TimeUtils.formatDuration(mNowTimeMs, sb);
                    sb.append(")");
                    Slog.e(TAG, sb.toString());
            // Slog.i(TAG, "Read uids: " + numUids);
        }
                return;
        mLastTimeReadMs = SystemClock.elapsedRealtime();
    }
            notify |= delta > 0;
            sumDeltas += delta / (i + 1);

    public void setThrottleInterval(long throttleInterval) {
        if (throttleInterval >= 0) {
            mThrottleInterval = throttleInterval;
        }
        if (notify) {
            System.arraycopy(curActiveTime, 0, lastActiveTime, 0, mCoreCount);
            if (cb != null) {
                cb.onUidCpuActiveTime(uid, sumDeltas);
    }

    public void removeUid(int uid) {
        mLastUidCpuActiveTimeMs.delete(uid);
    }

    public void removeUidsInRange(int startUid, int endUid) {
        if (endUid < startUid) {
            Slog.w(TAG, "End UID " + endUid + " is smaller than start UID " + startUid);
            return;
        }
        mLastUidCpuActiveTimeMs.put(startUid, null);
        mLastUidCpuActiveTimeMs.put(endUid, null);
        final int firstIndex = mLastUidCpuActiveTimeMs.indexOfKey(startUid);
        final int lastIndex = mLastUidCpuActiveTimeMs.indexOfKey(endUid);
        mLastUidCpuActiveTimeMs.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
    }
}
+156 −112

File changed.

Preview size limit exceeded, changes collapsed.

Loading