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