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

Commit 5065db05 authored by Connor O'Brien's avatar Connor O'Brien
Browse files

Use bpf data when available for per-UID cpu stats



Update KernelCpuUidTimeReader and its subclasses to support reading
frequency, active & cluster times from BPF maps rather than proc files
on devices that support this approach. BPF-based accounting offers
improved accuracy as it can detect every context switch, whereas the
proc files attribute a full tick period to whatever happens to be
running when the tick occurs.
Add a KernelCpuUidBpfMapReader class modeled on
KernelCpuProcStringReader, with singletons for reading each distinct
set of data. These follow the locking approach used by
KernelCpuProcStringReader to ensure thread safety, but they collect
data by calling libtimeinstate functions via JNI rather than reading
text from proc files. They also provide a getDataDimensions() function
to retrieve information currently provided by the header rows of the
proc files, such as the list of available freqs or the number of cores
on each cluster.
Extend the KernelCpu*TimeReaderTest classes to exercise the BPF path
for each reader class, and add a KernelCpuUidBpfMapReaderTest modeled
on KernelProcStringReaderTest.

Bug: 138317993
Test: KernelCpu*TimeReaderTests and KernelCpuUidBpfMapReaderTest pass
Test: no regressions in BatteryStatsTests
Change-Id: Ie7c0b11a47289e16f72fd6868de4185e858c7e4f
Signed-off-by: default avatarConnor O'Brien <connoro@google.com>
parent 9a5d3ad5
Loading
Loading
Loading
Loading
+202 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 android.util.SparseArray;

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Reads cpu time bpf maps.
 *
 * It is implemented as singletons for each separate set of per-UID times. Get___Instance() method
 * returns the corresponding reader instance. In order to prevent frequent GC, it reuses the same
 * SparseArray to store data read from BPF maps.
 *
 * A KernelCpuUidBpfMapReader 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.
 *
 * Data fetched within last 500ms is considered fresh, since the reading lifecycle can take up to
 * 25ms. KernelCpuUidBpfMapReader always tries to use cache if it is fresh and valid, but it can
 * be disabled through a parameter.
 *
 * A KernelCpuUidBpfMapReader instance is thread-safe. It acquires a write lock when reading the bpf
 * map, releases it right after, then acquires a read lock before returning a BpfMapIterator. Caller
 * is responsible for closing BpfMapIterator (also auto-closable) after reading, otherwise deadlock
 * will occur.
 */
public abstract class KernelCpuUidBpfMapReader {
    private static final int ERROR_THRESHOLD = 5;
    private static final long FRESHNESS_MS = 500L;

    private static final KernelCpuUidBpfMapReader FREQ_TIME_READER =
        new KernelCpuUidFreqTimeBpfMapReader();

    private static final KernelCpuUidBpfMapReader ACTIVE_TIME_READER =
        new KernelCpuUidActiveTimeBpfMapReader();

    private static final KernelCpuUidBpfMapReader CLUSTER_TIME_READER =
        new KernelCpuUidClusterTimeBpfMapReader();

    static KernelCpuUidBpfMapReader getFreqTimeReaderInstance() {
        return FREQ_TIME_READER;
    }

    static KernelCpuUidBpfMapReader getActiveTimeReaderInstance() {
        return ACTIVE_TIME_READER;
    }

    static KernelCpuUidBpfMapReader getClusterTimeReaderInstance() {
        return CLUSTER_TIME_READER;
    }

    final String mTag = this.getClass().getSimpleName();
    private int mErrors = 0;
    private boolean mTracking = false;
    protected SparseArray<long[]> mData = new SparseArray<>();
    private long mLastReadTime = 0;
    protected final ReentrantReadWriteLock mLock = new ReentrantReadWriteLock();
    protected final ReentrantReadWriteLock.ReadLock mReadLock = mLock.readLock();
    protected final ReentrantReadWriteLock.WriteLock mWriteLock = mLock.writeLock();

    public native boolean startTrackingBpfTimes();

    protected abstract boolean readBpfData();

    /**
     * Returns an array of metadata used to inform the caller of 1) the size of array required by
     * getNextUid and 2) how to interpret the raw data copied to that array.
     */
    public abstract long[] getDataDimensions();

    public void removeUidsInRange(int startUid, int endUid) {
        if (mErrors > ERROR_THRESHOLD) {
            return;
        }
        mWriteLock.lock();
        int firstIndex = mData.indexOfKey(startUid);
        int lastIndex = mData.indexOfKey(endUid);
        mData.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
        mWriteLock.unlock();
    }

    public BpfMapIterator open() {
        return open(false);
    }

    public BpfMapIterator open(boolean ignoreCache) {
        if (mErrors > ERROR_THRESHOLD) {
            return null;
        }
        if (!mTracking && !startTrackingBpfTimes()) {
            Slog.w(mTag, "Failed to start tracking");
            mErrors++;
            return null;
        }
        if (ignoreCache) {
            mWriteLock.lock();
        } else {
            mReadLock.lock();
            if (dataValid()) {
                return new BpfMapIterator();
            }
            mReadLock.unlock();
            mWriteLock.lock();
            if (dataValid()) {
                mReadLock.lock();
                mWriteLock.unlock();
                return new BpfMapIterator();
            }
        }
        if (readBpfData()) {
            mLastReadTime = SystemClock.elapsedRealtime();
            mReadLock.lock();
            mWriteLock.unlock();
            return new BpfMapIterator();
        }

        mWriteLock.unlock();
        mErrors++;
        Slog.w(mTag, "Failed to read bpf times");
        return null;
    }

    private boolean dataValid() {
        return mData.size() > 0 && (SystemClock.elapsedRealtime() - mLastReadTime < FRESHNESS_MS);
    }

    public class BpfMapIterator implements AutoCloseable {
        private int mPos;

        public BpfMapIterator() {
        };

        public boolean getNextUid(long[] buf) {
            if (mPos >= mData.size()) {
                return false;
            }
            buf[0] = mData.keyAt(mPos);
            System.arraycopy(mData.valueAt(mPos), 0, buf, 1, mData.valueAt(mPos).length);
            mPos++;
            return true;
        }

        public void close() {
            mReadLock.unlock();
        }
    }

    public static class KernelCpuUidFreqTimeBpfMapReader extends KernelCpuUidBpfMapReader {

        private final native boolean removeUidRange(int startUid, int endUid);

        @Override
        protected final native boolean readBpfData();

        @Override
        public final native long[] getDataDimensions();

        @Override
        public void removeUidsInRange(int startUid, int endUid) {
            mWriteLock.lock();
            super.removeUidsInRange(startUid, endUid);
            removeUidRange(startUid, endUid);
            mWriteLock.unlock();
        }
    }

    public static class KernelCpuUidActiveTimeBpfMapReader extends KernelCpuUidBpfMapReader {

        @Override
        protected final native boolean readBpfData();

        @Override
        public final native long[] getDataDimensions();
    }

    public static class KernelCpuUidClusterTimeBpfMapReader extends KernelCpuUidBpfMapReader {

        @Override
        protected final native boolean readBpfData();

        @Override
        public final native long[] getDataDimensions();
    }
}
+264 −91
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.util.SparseArray;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.KernelCpuProcStringReader.ProcFileIterator;
import com.android.internal.os.KernelCpuUidBpfMapReader.BpfMapIterator;

import java.io.BufferedReader;
import java.io.FileWriter;
@@ -57,6 +58,8 @@ public abstract class KernelCpuUidTimeReader<T> {
    final SparseArray<T> mLastTimes = new SparseArray<>();
    final KernelCpuProcStringReader mReader;
    final boolean mThrottle;
    protected boolean mBpfTimesAvailable;
    final KernelCpuUidBpfMapReader mBpfReader;
    private long mMinTimeBetweenRead = DEFAULT_MIN_TIME_BETWEEN_READ;
    private long mLastReadTimeMs = 0;

@@ -73,9 +76,15 @@ public abstract class KernelCpuUidTimeReader<T> {
        void onUidCpuTime(int uid, T time);
    }

    KernelCpuUidTimeReader(KernelCpuProcStringReader reader, boolean throttle) {
    KernelCpuUidTimeReader(KernelCpuProcStringReader reader, @Nullable KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
        mReader = reader;
        mThrottle = throttle;
        mBpfReader = bpfReader;
        mBpfTimesAvailable = (mBpfReader != null);
    }

    KernelCpuUidTimeReader(KernelCpuProcStringReader reader, boolean throttle) {
        this(reader, null, throttle);
    }

    /**
@@ -151,9 +160,13 @@ public abstract class KernelCpuUidTimeReader<T> {
        }
        mLastTimes.put(startUid, null);
        mLastTimes.put(endUid, null);
        final int firstIndex = mLastTimes.indexOfKey(startUid);
        final int lastIndex = mLastTimes.indexOfKey(endUid);
        int firstIndex = mLastTimes.indexOfKey(startUid);
        int lastIndex = mLastTimes.indexOfKey(endUid);
        mLastTimes.removeAtRange(firstIndex, lastIndex - firstIndex + 1);

        if (mBpfTimesAvailable) {
            mBpfReader.removeUidsInRange(startUid, endUid);
        }
    }

    /**
@@ -323,13 +336,13 @@ public abstract class KernelCpuUidTimeReader<T> {

        public KernelCpuUidFreqTimeReader(boolean throttle) {
            this(UID_TIMES_PROC_FILE, KernelCpuProcStringReader.getFreqTimeReaderInstance(),
                    throttle);
                 KernelCpuUidBpfMapReader.getFreqTimeReaderInstance(), throttle);
        }

        @VisibleForTesting
        public KernelCpuUidFreqTimeReader(String procFile, KernelCpuProcStringReader reader,
                boolean throttle) {
            super(reader, throttle);
                KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
            super(reader, bpfReader, throttle);
            mProcFilePath = Paths.get(procFile);
        }

@@ -370,6 +383,10 @@ public abstract class KernelCpuUidTimeReader<T> {
            if (!mAllUidTimesAvailable) {
                return null;
            }
            if (mBpfTimesAvailable) {
                readFreqsThroughBpf();
            }
            if (mCpuFreqs == null) {
                final int oldMask = StrictMode.allowThreadDiskReadsMask();
                try (BufferedReader reader = Files.newBufferedReader(mProcFilePath)) {
                    if (readFreqs(reader.readLine()) == null) {
@@ -384,6 +401,7 @@ public abstract class KernelCpuUidTimeReader<T> {
                } finally {
                    StrictMode.setThreadPolicyMask(oldMask);
                }
            }
            // Check if the freqs in the proc file correspond to per-cluster freqs.
            final IntArray numClusterFreqs = extractClusterInfoFromProcFileFreqs();
            final int numClusters = powerProfile.getNumCpuClusters();
@@ -402,6 +420,21 @@ public abstract class KernelCpuUidTimeReader<T> {
            return mCpuFreqs;
        }

        private long[] readFreqsThroughBpf() {
            if (!mBpfTimesAvailable || mBpfReader == null) {
                return null;
            }
            mCpuFreqs = mBpfReader.getDataDimensions();
            if (mCpuFreqs == null) {
                return null;
            }
            mFreqCount = mCpuFreqs.length;
            mCurTimes = new long[mFreqCount];
            mDeltaTimes = new long[mFreqCount];
            mBuffer = new long[mFreqCount + 1];
            return mCpuFreqs;
        }

        private long[] readFreqs(String line) {
            if (line == null || line.trim().isEmpty()) {
                return null;
@@ -422,18 +455,7 @@ public abstract class KernelCpuUidTimeReader<T> {
            return mCpuFreqs;
        }

        @Override
        void readDeltaImpl(@Nullable Callback<long[]> cb) {
            try (ProcFileIterator iter = mReader.open(!mThrottle)) {
                if (!checkPrecondition(iter)) {
                    return;
                }
                CharBuffer buf;
                while ((buf = iter.nextLine()) != null) {
                    if (asLongs(buf, mBuffer) != mBuffer.length) {
                        Slog.wtf(mTag, "Invalid line: " + buf.toString());
                        continue;
                    }
        private void processUidDelta(@Nullable Callback<long[]> cb) {
            final int uid = (int) mBuffer[0];
            long[] lastTimes = mLastTimes.get(uid);
            if (lastTimes == null) {
@@ -459,11 +481,47 @@ public abstract class KernelCpuUidTimeReader<T> {
                }
            }
        }

        @Override
        void readDeltaImpl(@Nullable Callback<long[]> cb) {
            if (mBpfTimesAvailable) {
                try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
                    if (checkPrecondition(iter)) {
                        while (iter.getNextUid(mBuffer)) {
                            processUidDelta(cb);
                        }
                        return;
                    }
                }
            }
            try (ProcFileIterator iter = mReader.open(!mThrottle)) {
                if (!checkPrecondition(iter)) {
                    return;
                }
                CharBuffer buf;
                while ((buf = iter.nextLine()) != null) {
                    if (asLongs(buf, mBuffer) != mBuffer.length) {
                        Slog.wtf(mTag, "Invalid line: " + buf.toString());
                        continue;
                    }
                    processUidDelta(cb);
                }
            }
        }

        @Override
        void readAbsoluteImpl(Callback<long[]> cb) {
            if (mBpfTimesAvailable) {
                try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
                    if (checkPrecondition(iter)) {
                        while (iter.getNextUid(mBuffer)) {
                            copyToCurTimes();
                            cb.onUidCpuTime((int) mBuffer[0], mCurTimes);
                        }
                        return;
                    }
                }
            }
            try (ProcFileIterator iter = mReader.open(!mThrottle)) {
                if (!checkPrecondition(iter)) {
                    return;
@@ -481,11 +539,24 @@ public abstract class KernelCpuUidTimeReader<T> {
        }

        private void copyToCurTimes() {
            long factor = mBpfTimesAvailable ? 1 : 10;
            for (int i = 0; i < mFreqCount; i++) {
                mCurTimes[i] = mBuffer[i + 1] * 10;
                mCurTimes[i] = mBuffer[i + 1] * factor;
            }
        }

        private boolean checkPrecondition(BpfMapIterator iter) {
            if (iter == null) {
                mBpfTimesAvailable = false;
                return false;
            }
            if (mCpuFreqs != null) {
                return true;
            }
            mBpfTimesAvailable = (readFreqsThroughBpf() != null);
            return mBpfTimesAvailable;
        }

        private boolean checkPrecondition(ProcFileIterator iter) {
            if (iter == null || !iter.hasNextLine()) {
                // Error logged in KernelCpuProcStringReader.
@@ -544,16 +615,43 @@ public abstract class KernelCpuUidTimeReader<T> {
        private long[] mBuffer;

        public KernelCpuUidActiveTimeReader(boolean throttle) {
            super(KernelCpuProcStringReader.getActiveTimeReaderInstance(), throttle);
            super(KernelCpuProcStringReader.getActiveTimeReaderInstance(),
                  KernelCpuUidBpfMapReader.getActiveTimeReaderInstance(), throttle);
        }

        @VisibleForTesting
        public KernelCpuUidActiveTimeReader(KernelCpuProcStringReader reader, boolean throttle) {
            super(reader, throttle);
        public KernelCpuUidActiveTimeReader(KernelCpuProcStringReader reader, KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
            super(reader, bpfReader, throttle);
        }

        private void processUidDelta(@Nullable Callback<Long> cb) {
            int uid = (int) mBuffer[0];
            long cpuActiveTime = sumActiveTime(mBuffer, mBpfTimesAvailable ? 1 : 10);
            if (cpuActiveTime > 0) {
                long delta = cpuActiveTime - mLastTimes.get(uid, 0L);
                if (delta > 0) {
                    mLastTimes.put(uid, cpuActiveTime);
                    if (cb != null) {
                        cb.onUidCpuTime(uid, delta);
                    }
                } else if (delta < 0) {
                    Slog.e(mTag, "Negative delta from active time proc: " + delta);
                }
            }
        }

        @Override
        void readDeltaImpl(@Nullable Callback<Long> cb) {
            if (mBpfTimesAvailable) {
                try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
                    if (checkPrecondition(iter)) {
                        while (iter.getNextUid(mBuffer)) {
                            processUidDelta(cb);
                        }
                        return;
                    }
                }
            }
            try (ProcFileIterator iter = mReader.open(!mThrottle)) {
                if (!checkPrecondition(iter)) {
                    return;
@@ -564,25 +662,30 @@ public abstract class KernelCpuUidTimeReader<T> {
                        Slog.wtf(mTag, "Invalid line: " + buf.toString());
                        continue;
                    }
                    int uid = (int) mBuffer[0];
                    long cpuActiveTime = sumActiveTime(mBuffer);
                    if (cpuActiveTime > 0) {
                        long delta = cpuActiveTime - mLastTimes.get(uid, 0L);
                        if (delta > 0) {
                            mLastTimes.put(uid, cpuActiveTime);
                            if (cb != null) {
                                cb.onUidCpuTime(uid, delta);
                            }
                        } else if (delta < 0) {
                            Slog.e(mTag, "Negative delta from active time proc: " + delta);
                    processUidDelta(cb);
                }
            }
        }

        private void processUidAbsolute(@Nullable Callback<Long> cb) {
            long cpuActiveTime = sumActiveTime(mBuffer, mBpfTimesAvailable ? 1 : 10);
            if (cpuActiveTime > 0) {
                cb.onUidCpuTime((int) mBuffer[0], cpuActiveTime);
            }
        }

        @Override
        void readAbsoluteImpl(Callback<Long> cb) {
            if (mBpfTimesAvailable) {
                try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
                    if (checkPrecondition(iter)) {
                        while (iter.getNextUid(mBuffer)) {
                            processUidAbsolute(cb);
                        }
                        return;
                    }
                }
            }
            try (ProcFileIterator iter = mReader.open(!mThrottle)) {
                if (!checkPrecondition(iter)) {
                    return;
@@ -593,23 +696,38 @@ public abstract class KernelCpuUidTimeReader<T> {
                        Slog.wtf(mTag, "Invalid line: " + buf.toString());
                        continue;
                    }
                    long cpuActiveTime = sumActiveTime(mBuffer);
                    if (cpuActiveTime > 0) {
                        cb.onUidCpuTime((int) mBuffer[0], cpuActiveTime);
                    }
                    processUidAbsolute(cb);
                }
            }
        }

        private static long sumActiveTime(long[] times) {
        private static long sumActiveTime(long[] times, double factor) {
            // UID is stored at times[0].
            double sum = 0;
            for (int i = 1; i < times.length; i++) {
                sum += (double) times[i] * 10 / i; // Unit is 10ms.
                sum += (double) times[i] * factor / i; // Unit is 10ms.
            }
            return (long) sum;
        }

        private boolean checkPrecondition(BpfMapIterator iter) {
            if (iter == null) {
                mBpfTimesAvailable = false;
                return false;
            }
            if (mCores > 0) {
                return true;
            }
            long[] cores = mBpfReader.getDataDimensions();
            if (cores == null || cores.length < 1) {
                mBpfTimesAvailable = false;
                return false;
            }
            mCores = (int) cores[0];
            mBuffer = new long[mCores + 1];
            return true;
        }

        private boolean checkPrecondition(ProcFileIterator iter) {
            if (iter == null || !iter.hasNextLine()) {
                // Error logged in KernelCpuProcStringReader.
@@ -668,26 +786,17 @@ public abstract class KernelCpuUidTimeReader<T> {
        private long[] mDeltaTime;

        public KernelCpuUidClusterTimeReader(boolean throttle) {
            super(KernelCpuProcStringReader.getClusterTimeReaderInstance(), throttle);
            super(KernelCpuProcStringReader.getClusterTimeReaderInstance(),
                  KernelCpuUidBpfMapReader.getClusterTimeReaderInstance(), throttle);
        }

        @VisibleForTesting
        public KernelCpuUidClusterTimeReader(KernelCpuProcStringReader reader, boolean throttle) {
            super(reader, throttle);
        public KernelCpuUidClusterTimeReader(KernelCpuProcStringReader reader,
                                             KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
            super(reader, bpfReader, throttle);
        }

        @Override
        void readDeltaImpl(@Nullable Callback<long[]> cb) {
            try (ProcFileIterator iter = mReader.open(!mThrottle)) {
                if (!checkPrecondition(iter)) {
                    return;
                }
                CharBuffer buf;
                while ((buf = iter.nextLine()) != null) {
                    if (asLongs(buf, mBuffer) != mBuffer.length) {
                        Slog.wtf(mTag, "Invalid line: " + buf.toString());
                        continue;
                    }
        void processUidDelta(@Nullable Callback<long[]> cb) {
            int uid = (int) mBuffer[0];
            long[] lastTimes = mLastTimes.get(uid);
            if (lastTimes == null) {
@@ -712,11 +821,47 @@ public abstract class KernelCpuUidTimeReader<T> {
                }
            }
        }

        @Override
        void readDeltaImpl(@Nullable Callback<long[]> cb) {
            if (mBpfTimesAvailable) {
                try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
                    if (checkPrecondition(iter)) {
                        while (iter.getNextUid(mBuffer)) {
                            processUidDelta(cb);
                        }
                        return;
                    }
                }
            }
            try (ProcFileIterator iter = mReader.open(!mThrottle)) {
                if (!checkPrecondition(iter)) {
                    return;
                }
                CharBuffer buf;
                while ((buf = iter.nextLine()) != null) {
                    if (asLongs(buf, mBuffer) != mBuffer.length) {
                        Slog.wtf(mTag, "Invalid line: " + buf.toString());
                        continue;
                    }
                    processUidDelta(cb);
                }
            }
        }

        @Override
        void readAbsoluteImpl(Callback<long[]> cb) {
            if (mBpfTimesAvailable) {
                try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
                    if (checkPrecondition(iter)) {
                        while (iter.getNextUid(mBuffer)) {
                            sumClusterTime();
                            cb.onUidCpuTime((int) mBuffer[0], mCurTime);
                        }
                        return;
                    }
                }
            }
            try (ProcFileIterator iter = mReader.open(!mThrottle)) {
                if (!checkPrecondition(iter)) {
                    return;
@@ -734,17 +879,45 @@ public abstract class KernelCpuUidTimeReader<T> {
        }

        private void sumClusterTime() {
            double factor = mBpfTimesAvailable ? 1 : 10;
            // UID is stored at mBuffer[0].
            int core = 1;
            for (int i = 0; i < mNumClusters; i++) {
                double sum = 0;
                for (int j = 1; j <= mCoresOnClusters[i]; j++) {
                    sum += (double) mBuffer[core++] * 10 / j; // Unit is 10ms.
                    sum += (double) mBuffer[core++] * factor / j; // Unit is 10ms.
                }
                mCurTime[i] = (long) sum;
            }
        }

        private boolean checkPrecondition(BpfMapIterator iter) {
            if (iter == null) {
                mBpfTimesAvailable = false;
                return false;
            }
            if (mNumClusters > 0) {
                return true;
            }
            long[] coresOnClusters = mBpfReader.getDataDimensions();
            if (coresOnClusters == null || coresOnClusters.length < 1) {
                mBpfTimesAvailable = false;
                return false;
            }
            mNumClusters = coresOnClusters.length;
            mCoresOnClusters = new int[mNumClusters];
            int cores = 0;
            for (int i = 0; i < mNumClusters; i++) {
                mCoresOnClusters[i] = (int) coresOnClusters[i];
                cores += mCoresOnClusters[i];
            }
            mNumCores = cores;
            mBuffer = new long[cores + 1];
            mCurTime = new long[mNumClusters];
            mDeltaTime = new long[mNumClusters];
            return true;
        }

        private boolean checkPrecondition(ProcFileIterator iter) {
            if (iter == null || !iter.hasNextLine()) {
                // Error logged in KernelCpuProcStringReader.
+2 −0
Original line number Diff line number Diff line
@@ -199,6 +199,7 @@ cc_library_shared {
                "android_security_Scrypt.cpp",
                "com_android_internal_os_ClassLoaderFactory.cpp",
                "com_android_internal_os_FuseAppLoop.cpp",
                "com_android_internal_os_KernelCpuUidBpfMapReader.cpp",
                "com_android_internal_os_Zygote.cpp",
                "com_android_internal_os_ZygoteInit.cpp",
                "hwbinder/EphemeralStorage.cpp",
@@ -273,6 +274,7 @@ cc_library_shared {
                "libdl_android",
                "libstats_jni",
                "libstatslog",
                "libtimeinstate",
                "server_configurable_flags",
                "libstatspull",
            ],
+2 −0

File changed.

Preview size limit exceeded, changes collapsed.

+217 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading