12ab014426647bbc8960fdb4dadfe480b9806676eMike Ma/*
22ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * Copyright (C) 2018 The Android Open Source Project
32ab014426647bbc8960fdb4dadfe480b9806676eMike Ma *
42ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * Licensed under the Apache License, Version 2.0 (the "License");
52ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * you may not use this file except in compliance with the License.
62ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * You may obtain a copy of the License at
72ab014426647bbc8960fdb4dadfe480b9806676eMike Ma *
82ab014426647bbc8960fdb4dadfe480b9806676eMike Ma *      http://www.apache.org/licenses/LICENSE-2.0
92ab014426647bbc8960fdb4dadfe480b9806676eMike Ma *
102ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * Unless required by applicable law or agreed to in writing, software
112ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * distributed under the License is distributed on an "AS IS" BASIS,
122ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * See the License for the specific language governing permissions and
142ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * limitations under the License.
152ab014426647bbc8960fdb4dadfe480b9806676eMike Ma */
162ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
172ab014426647bbc8960fdb4dadfe480b9806676eMike Mapackage com.android.internal.os;
182ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
192ab014426647bbc8960fdb4dadfe480b9806676eMike Maimport android.os.StrictMode;
202ab014426647bbc8960fdb4dadfe480b9806676eMike Maimport android.os.SystemClock;
212ab014426647bbc8960fdb4dadfe480b9806676eMike Maimport android.util.Slog;
222ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
232ab014426647bbc8960fdb4dadfe480b9806676eMike Maimport com.android.internal.annotations.VisibleForTesting;
242ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
25363ccf7282787898c3eea2926adce3078611f394Mike Maimport java.io.FileNotFoundException;
262ab014426647bbc8960fdb4dadfe480b9806676eMike Maimport java.io.IOException;
272ab014426647bbc8960fdb4dadfe480b9806676eMike Maimport java.nio.ByteBuffer;
282ab014426647bbc8960fdb4dadfe480b9806676eMike Maimport java.nio.ByteOrder;
292ab014426647bbc8960fdb4dadfe480b9806676eMike Maimport java.nio.channels.FileChannel;
30363ccf7282787898c3eea2926adce3078611f394Mike Maimport java.nio.file.NoSuchFileException;
312ab014426647bbc8960fdb4dadfe480b9806676eMike Maimport java.nio.file.Path;
322ab014426647bbc8960fdb4dadfe480b9806676eMike Maimport java.nio.file.Paths;
332ab014426647bbc8960fdb4dadfe480b9806676eMike Maimport java.nio.file.StandardOpenOption;
342ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
352ab014426647bbc8960fdb4dadfe480b9806676eMike Ma/**
362ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * Reads cpu time proc files with throttling (adjustable interval).
372ab014426647bbc8960fdb4dadfe480b9806676eMike Ma *
382ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * KernelCpuProcReader is implemented as singletons for built-in kernel proc files. Get___Instance()
392ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * method will return corresponding reader instance. In order to prevent frequent GC,
402ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * KernelCpuProcReader reuses a {@link ByteBuffer} to store data read from proc files.
412ab014426647bbc8960fdb4dadfe480b9806676eMike Ma *
422ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * A KernelCpuProcReader instance keeps an error counter. When the number of read errors within that
432ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * instance accumulates to 5, this instance will reject all further read requests.
442ab014426647bbc8960fdb4dadfe480b9806676eMike Ma *
452ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * Each KernelCpuProcReader instance also has a throttler. Throttle interval can be adjusted via
462ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * {@link #setThrottleInterval(long)} method. Default throttle interval is 3000ms. If current
472ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * timestamp based on {@link SystemClock#elapsedRealtime()} is less than throttle interval from
482ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * the last read timestamp, {@link #readBytes()} will return previous result.
492ab014426647bbc8960fdb4dadfe480b9806676eMike Ma *
502ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * A KernelCpuProcReader instance is thread-unsafe. Caller needs to hold a lock on this object while
512ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * accessing its instance methods or digesting the return values.
522ab014426647bbc8960fdb4dadfe480b9806676eMike Ma */
532ab014426647bbc8960fdb4dadfe480b9806676eMike Mapublic class KernelCpuProcReader {
542ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private static final String TAG = "KernelCpuProcReader";
552ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private static final int ERROR_THRESHOLD = 5;
562ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    // Throttle interval in milliseconds
572ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private static final long DEFAULT_THROTTLE_INTERVAL = 3000L;
582ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private static final int INITIAL_BUFFER_SIZE = 8 * 1024;
592ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private static final int MAX_BUFFER_SIZE = 1024 * 1024;
602ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private static final String PROC_UID_FREQ_TIME = "/proc/uid_cpupower/time_in_state";
612ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private static final String PROC_UID_ACTIVE_TIME = "/proc/uid_cpupower/concurrent_active_time";
622ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private static final String PROC_UID_CLUSTER_TIME = "/proc/uid_cpupower/concurrent_policy_time";
632ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
642ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private static final KernelCpuProcReader mFreqTimeReader = new KernelCpuProcReader(
652ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            PROC_UID_FREQ_TIME);
662ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private static final KernelCpuProcReader mActiveTimeReader = new KernelCpuProcReader(
672ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            PROC_UID_ACTIVE_TIME);
682ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private static final KernelCpuProcReader mClusterTimeReader = new KernelCpuProcReader(
692ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            PROC_UID_CLUSTER_TIME);
702ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
712ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    public static KernelCpuProcReader getFreqTimeReaderInstance() {
722ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        return mFreqTimeReader;
732ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    }
742ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
752ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    public static KernelCpuProcReader getActiveTimeReaderInstance() {
762ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        return mActiveTimeReader;
772ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    }
782ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
792ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    public static KernelCpuProcReader getClusterTimeReaderInstance() {
802ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        return mClusterTimeReader;
812ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    }
822ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
832ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private int mErrors;
842ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL;
852ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private long mLastReadTime = Long.MIN_VALUE;
862ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private final Path mProc;
872ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private ByteBuffer mBuffer;
882ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
892ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    @VisibleForTesting
902ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    public KernelCpuProcReader(String procFile) {
912ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mProc = Paths.get(procFile);
922ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mBuffer = ByteBuffer.allocateDirect(INITIAL_BUFFER_SIZE);
932ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mBuffer.clear();
942ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    }
952ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
962ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    /**
972ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     * Reads all bytes from the corresponding proc file.
982ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     *
992ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     * If elapsed time since last call to this method is less than the throttle interval, it will
1002ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     * return previous result. When IOException accumulates to 5, it will always return null. This
1012ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     * method is thread-unsafe, so is the return value. Caller needs to hold a lock on this
1022ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     * object while calling this method and digesting its return value.
1032ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     *
1042ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     * @return a {@link ByteBuffer} containing all bytes from the proc file.
1052ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     */
1062ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    public ByteBuffer readBytes() {
1072ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        if (mErrors >= ERROR_THRESHOLD) {
1082ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            return null;
1092ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        }
1102ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        if (SystemClock.elapsedRealtime() < mLastReadTime + mThrottleInterval) {
1112ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            if (mBuffer.limit() > 0 && mBuffer.limit() < mBuffer.capacity()) {
1122ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                // mBuffer has data.
1132ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                return mBuffer.asReadOnlyBuffer().order(ByteOrder.nativeOrder());
1142ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            }
1152ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            return null;
1162ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        }
1172ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mLastReadTime = SystemClock.elapsedRealtime();
1182ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mBuffer.clear();
1192ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        final int oldMask = StrictMode.allowThreadDiskReadsMask();
1202ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        try (FileChannel fc = FileChannel.open(mProc, StandardOpenOption.READ)) {
1212ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            while (fc.read(mBuffer) == mBuffer.capacity()) {
1222ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                if (!resize()) {
1232ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                    mErrors++;
1242ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                    Slog.e(TAG, "Proc file is too large: " + mProc);
1252ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                    return null;
1262ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                }
1272ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                fc.position(0);
1282ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            }
129363ccf7282787898c3eea2926adce3078611f394Mike Ma        } catch (NoSuchFileException | FileNotFoundException e) {
130363ccf7282787898c3eea2926adce3078611f394Mike Ma            // Happens when the kernel does not provide this file. Not a big issue. Just log it.
131363ccf7282787898c3eea2926adce3078611f394Mike Ma            mErrors++;
132363ccf7282787898c3eea2926adce3078611f394Mike Ma            Slog.w(TAG, "File not exist: " + mProc);
133363ccf7282787898c3eea2926adce3078611f394Mike Ma            return null;
1342ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        } catch (IOException e) {
1352ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            mErrors++;
1362ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            Slog.e(TAG, "Error reading: " + mProc, e);
1372ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            return null;
1382ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        } finally {
1392ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            StrictMode.setThreadPolicyMask(oldMask);
1402ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        }
1412ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mBuffer.flip();
1422ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        return mBuffer.asReadOnlyBuffer().order(ByteOrder.nativeOrder());
1432ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    }
1442ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
1452ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    /**
1462ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     * Sets the throttle interval. Set to 0 will disable throttling. Thread-unsafe, holding a lock
1472ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     * on this object is recommended.
1482ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     *
1492ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     * @param throttleInterval throttle interval in milliseconds
1502ab014426647bbc8960fdb4dadfe480b9806676eMike Ma     */
1512ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    public void setThrottleInterval(long throttleInterval) {
1522ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        if (throttleInterval >= 0) {
1532ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            mThrottleInterval = throttleInterval;
1542ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        }
1552ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    }
1562ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
1572ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private boolean resize() {
1582ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        if (mBuffer.capacity() >= MAX_BUFFER_SIZE) {
1592ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            return false;
1602ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        }
1612ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        int newSize = Math.min(mBuffer.capacity() << 1, MAX_BUFFER_SIZE);
1622ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        // Slog.i(TAG, "Resize buffer " + mBuffer.capacity() + " => " + newSize);
1632ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mBuffer = ByteBuffer.allocateDirect(newSize);
1642ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        return true;
1652ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    }
1662ab014426647bbc8960fdb4dadfe480b9806676eMike Ma}
167