13d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma/*
23d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma * Copyright (C) 2017 The Android Open Source Project
33d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma *
43d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma * Licensed under the Apache License, Version 2.0 (the "License");
53d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma * you may not use this file except in compliance with the License.
63d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma * You may obtain a copy of the License at
73d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma *
83d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma *      http://www.apache.org/licenses/LICENSE-2.0
93d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma *
103d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma * Unless required by applicable law or agreed to in writing, software
113d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma * distributed under the License is distributed on an "AS IS" BASIS,
123d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma * See the License for the specific language governing permissions and
143d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma * limitations under the License.
153d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma */
163d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma
173d422c37b7f2caf364febc556e17b43c40c56be6Mike Mapackage com.android.internal.os;
183d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma
193d422c37b7f2caf364febc556e17b43c40c56be6Mike Maimport android.annotation.Nullable;
203d422c37b7f2caf364febc556e17b43c40c56be6Mike Maimport android.util.Slog;
213d422c37b7f2caf364febc556e17b43c40c56be6Mike Maimport android.util.SparseArray;
223d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma
233d422c37b7f2caf364febc556e17b43c40c56be6Mike Maimport com.android.internal.annotations.VisibleForTesting;
243d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma
252ab014426647bbc8960fdb4dadfe480b9806676eMike Maimport java.nio.ByteBuffer;
262ab014426647bbc8960fdb4dadfe480b9806676eMike Maimport java.nio.IntBuffer;
27234d1828ca4a706676ad6f3fa0629959c74297c7Mike Maimport java.util.function.Consumer;
283d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma
293d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma/**
302ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * Reads binary proc file /proc/uid_cpupower/concurrent_policy_time and reports CPU cluster times
312ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * to BatteryStats to compute cluster power. See
322ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * {@link PowerProfile#getAveragePowerForCpuCluster(int)}.
332ab014426647bbc8960fdb4dadfe480b9806676eMike Ma *
342ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * concurrent_policy_time is an array of u32's in the following format:
352ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * [n, x0, ..., xn, uid0, time0a, time0b, ..., time0n,
362ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * uid1, time1a, time1b, ..., time1n,
372ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * uid2, time2a, time2b, ..., time2n, etc.]
382ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * where n is the number of policies
392ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * xi is the number cpus on a particular policy
402ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * Each uidX is followed by x0 time entries corresponding to the time UID X spent on cluster0
412ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * running concurrently with 0, 1, 2, ..., x0 - 1 other processes, then followed by x1, ..., xn
422ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * time entries.
432ab014426647bbc8960fdb4dadfe480b9806676eMike Ma *
443d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma * The file contains a monotonically increasing count of time for a single boot. This class
452ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * maintains the previous results of a call to {@link #readDelta} in order to provide a
462ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * proper delta.
472ab014426647bbc8960fdb4dadfe480b9806676eMike Ma *
482ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * This class uses a throttler to reject any {@link #readDelta} call within
492ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * {@link #mThrottleInterval}. This is different from the throttler in {@link KernelCpuProcReader},
502ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * which has a shorter throttle interval and returns cached result from last read when the request
512ab014426647bbc8960fdb4dadfe480b9806676eMike Ma * is throttled.
522ab014426647bbc8960fdb4dadfe480b9806676eMike Ma *
5369d8b3e0508de7e181f70a3322be626b1527ee0eMike Ma * This class is NOT thread-safe and NOT designed to be accessed by more than one caller since each
5469d8b3e0508de7e181f70a3322be626b1527ee0eMike Ma * caller has its own view of delta.
553d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma */
5669d8b3e0508de7e181f70a3322be626b1527ee0eMike Mapublic class KernelUidCpuClusterTimeReader extends
5769d8b3e0508de7e181f70a3322be626b1527ee0eMike Ma        KernelUidCpuTimeReaderBase<KernelUidCpuClusterTimeReader.Callback> {
5869d8b3e0508de7e181f70a3322be626b1527ee0eMike Ma    private static final String TAG = KernelUidCpuClusterTimeReader.class.getSimpleName();
592ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
602ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private final KernelCpuProcReader mProcReader;
612ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private SparseArray<double[]> mLastUidPolicyTimeMs = new SparseArray<>();
623d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma
632ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private int mNumClusters = -1;
642ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private int mNumCores;
652ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private int[] mNumCoresOnCluster;
662ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
672ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private double[] mCurTime; // Reuse to avoid GC.
682ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private long[] mDeltaTime; // Reuse to avoid GC.
69ec67661bdfe1814039f625575176678219acc7b1Chenjie Yu    private long[] mCurTimeRounded; // Reuse to avoid GC.
703d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma
7169d8b3e0508de7e181f70a3322be626b1527ee0eMike Ma    public interface Callback extends KernelUidCpuTimeReaderBase.Callback {
723d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma        /**
732ab014426647bbc8960fdb4dadfe480b9806676eMike Ma         * Notifies when new data is available.
742ab014426647bbc8960fdb4dadfe480b9806676eMike Ma         *
752ab014426647bbc8960fdb4dadfe480b9806676eMike Ma         * @param uid              uid int
762ab014426647bbc8960fdb4dadfe480b9806676eMike Ma         * @param cpuClusterTimeMs an array of times spent by this uid on corresponding clusters.
772ab014426647bbc8960fdb4dadfe480b9806676eMike Ma         *                         The array index is the cluster index.
783d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma         */
792ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        void onUidCpuPolicyTime(int uid, long[] cpuClusterTimeMs);
803d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma    }
813d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma
822ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    public KernelUidCpuClusterTimeReader() {
832ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mProcReader = KernelCpuProcReader.getClusterTimeReaderInstance();
843d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma    }
853d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma
862ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    @VisibleForTesting
872ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    public KernelUidCpuClusterTimeReader(KernelCpuProcReader procReader) {
882ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mProcReader = procReader;
893d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma    }
903d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma
9169d8b3e0508de7e181f70a3322be626b1527ee0eMike Ma    @Override
9269d8b3e0508de7e181f70a3322be626b1527ee0eMike Ma    protected void readDeltaImpl(@Nullable Callback cb) {
93234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma        readImpl((buf) -> {
94234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            int uid = buf.get();
95234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            double[] lastTimes = mLastUidPolicyTimeMs.get(uid);
96234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            if (lastTimes == null) {
97234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                lastTimes = new double[mNumClusters];
98234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                mLastUidPolicyTimeMs.put(uid, lastTimes);
99234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            }
100234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            if (!sumClusterTime(buf, mCurTime)) {
101234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                return;
102234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            }
103234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            boolean valid = true;
104234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            boolean notify = false;
105234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            for (int i = 0; i < mNumClusters; i++) {
106234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                mDeltaTime[i] = (long) (mCurTime[i] - lastTimes[i]);
107234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                if (mDeltaTime[i] < 0) {
108234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                    Slog.e(TAG, "Negative delta from cluster time proc: " + mDeltaTime[i]);
109234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                    valid = false;
110234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                }
111234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                notify |= mDeltaTime[i] > 0;
112234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            }
113234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            if (notify && valid) {
114234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                System.arraycopy(mCurTime, 0, lastTimes, 0, mNumClusters);
115234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                if (cb != null) {
116234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                    cb.onUidCpuPolicyTime(uid, mDeltaTime);
117234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                }
118234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            }
119234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma        });
120234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma    }
121234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma
122234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma    public void readAbsolute(Callback callback) {
123234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma        readImpl((buf) -> {
124234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            int uid = buf.get();
125234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            if (sumClusterTime(buf, mCurTime)) {
126234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                for (int i = 0; i < mNumClusters; i++) {
127234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                    mCurTimeRounded[i] = (long) mCurTime[i];
128234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                }
129234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                callback.onUidCpuPolicyTime(uid, mCurTimeRounded);
130234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            }
131234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma        });
132234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma    }
133234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma
134234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma    private boolean sumClusterTime(IntBuffer buffer, double[] clusterTime) {
135234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma        boolean valid = true;
136234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma        for (int i = 0; i < mNumClusters; i++) {
137234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            clusterTime[i] = 0;
138234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            for (int j = 1; j <= mNumCoresOnCluster[i]; j++) {
139234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                int time = buffer.get();
140234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                if (time < 0) {
141234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                    Slog.e(TAG, "Negative time from cluster time proc: " + time);
142234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                    valid = false;
143234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                }
144234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                clusterTime[i] += (double) time * 10 / j; // Unit is 10ms.
145234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma            }
146234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma        }
147234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma        return valid;
148234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma    }
149234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma
150234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma    /**
151234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma     * readImpl accepts a callback to process the uid entry. readDeltaImpl needs to store the last
152234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma     * seen results while processing the buffer, while readAbsolute returns the absolute value read
153234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma     * from the buffer without storing. So readImpl contains the common logic of the two, leaving
154234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma     * the difference to a processUid function.
155234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma     *
156234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma     * @param processUid the callback function to process the uid entry in the buffer.
157234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma     */
158234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma    private void readImpl(Consumer<IntBuffer> processUid) {
1592ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        synchronized (mProcReader) {
1602ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            ByteBuffer bytes = mProcReader.readBytes();
1612ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            if (bytes == null || bytes.remaining() <= 4) {
1622ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                // Error already logged in mProcReader.
1632ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                return;
1642ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            }
1652ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            if ((bytes.remaining() & 3) != 0) {
1662ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                Slog.wtf(TAG,
1672ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                        "Cannot parse cluster time proc bytes to int: " + bytes.remaining());
1682ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                return;
1692ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            }
1702ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            IntBuffer buf = bytes.asIntBuffer();
1712ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            final int numClusters = buf.get();
1722ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            if (numClusters <= 0) {
1732ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                Slog.wtf(TAG, "Cluster time format error: " + numClusters);
1742ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                return;
1752ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            }
1762ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            if (mNumClusters == -1) {
1772ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                mNumClusters = numClusters;
1782ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            }
1792ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            if (buf.remaining() < numClusters) {
1802ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                Slog.wtf(TAG, "Too few data left in the buffer: " + buf.remaining());
1813d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma                return;
1823d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma            }
1832ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            if (mNumCores <= 0) {
1842ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                if (!readCoreInfo(buf, numClusters)) {
1852ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                    return;
1862ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                }
1872ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            } else {
1882ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                buf.position(buf.position() + numClusters);
1892ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            }
1903d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma
1912ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            if (buf.remaining() % (mNumCores + 1) != 0) {
1922ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                Slog.wtf(TAG,
1932ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                        "Cluster time format error: " + buf.remaining() + " / " + (mNumCores
1942ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                                + 1));
1952ab014426647bbc8960fdb4dadfe480b9806676eMike Ma                return;
1963d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma            }
1972ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            int numUids = buf.remaining() / (mNumCores + 1);
1983d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma
1992ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            for (int i = 0; i < numUids; i++) {
200234d1828ca4a706676ad6f3fa0629959c74297c7Mike Ma                processUid.accept(buf);
20169d8b3e0508de7e181f70a3322be626b1527ee0eMike Ma            }
20269d8b3e0508de7e181f70a3322be626b1527ee0eMike Ma            if (DEBUG) {
20369d8b3e0508de7e181f70a3322be626b1527ee0eMike Ma                Slog.d(TAG, "Read uids: " + numUids);
2043d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma            }
2053d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma        }
2063d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma    }
2073d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma
2082ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    // Returns if it has read valid info.
2092ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    private boolean readCoreInfo(IntBuffer buf, int numClusters) {
2102ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        int numCores = 0;
2112ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        int[] numCoresOnCluster = new int[numClusters];
2122ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        for (int i = 0; i < numClusters; i++) {
2132ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            numCoresOnCluster[i] = buf.get();
2142ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            numCores += numCoresOnCluster[i];
2152ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        }
2162ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        if (numCores <= 0) {
2172ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            Slog.e(TAG, "Invalid # cores from cluster time proc file: " + numCores);
2182ab014426647bbc8960fdb4dadfe480b9806676eMike Ma            return false;
2192ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        }
2202ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mNumCores = numCores;
2212ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mNumCoresOnCluster = numCoresOnCluster;
2222ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mCurTime = new double[numClusters];
2232ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mDeltaTime = new long[numClusters];
224ec67661bdfe1814039f625575176678219acc7b1Chenjie Yu        mCurTimeRounded = new long[numClusters];
2252ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        return true;
2262ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    }
2272ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
2282ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    public void removeUid(int uid) {
2292ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mLastUidPolicyTimeMs.delete(uid);
2302ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    }
2312ab014426647bbc8960fdb4dadfe480b9806676eMike Ma
2322ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    public void removeUidsInRange(int startUid, int endUid) {
2332ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mLastUidPolicyTimeMs.put(startUid, null);
2342ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mLastUidPolicyTimeMs.put(endUid, null);
2352ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        final int firstIndex = mLastUidPolicyTimeMs.indexOfKey(startUid);
2362ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        final int lastIndex = mLastUidPolicyTimeMs.indexOfKey(endUid);
2372ab014426647bbc8960fdb4dadfe480b9806676eMike Ma        mLastUidPolicyTimeMs.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
2382ab014426647bbc8960fdb4dadfe480b9806676eMike Ma    }
2393d422c37b7f2caf364febc556e17b43c40c56be6Mike Ma}
240