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

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

Merge "Stop tracking user specific uid cpu time on user stop"

parents 417f209a e6e723d5
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -118,6 +118,23 @@ public class SparseLongArray implements Cloneable {
        }
    }

    /**
     * @hide
     * Remove a range of mappings as a batch.
     *
     * @param index Index to begin at
     * @param size Number of mappings to remove
     *
     * <p>For indices outside of the range <code>0...size()-1</code>,
     * the behavior is undefined.</p>
     */
    public void removeAtRange(int index, int size) {
        size = Math.min(size, mSize - index);
        System.arraycopy(mKeys, index + size, mKeys, index, mSize - (index + size));
        System.arraycopy(mValues, index + size, mValues, index, mSize - (index + size));
        mSize -= size;
    }

    /**
     * Removes the mapping at the given index.
     */
+50 −10
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.WorkSource;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
@@ -75,7 +75,7 @@ import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
import com.android.server.NetworkManagementSocketTagger;

import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -194,6 +194,17 @@ public class BatteryStatsImpl extends BatteryStats {
        public String getSubsystemLowPowerStats();
    }

    public static abstract class UserInfoProvider {
        private int[] userIds;
        protected abstract @Nullable int[] getUserIds();
        private final void refreshUserIds() {
            userIds = getUserIds();
        }
        private final boolean exists(int userId) {
            return userIds != null ? ArrayUtils.contains(userIds, userId) : true;
        }
    }

    private final PlatformIdleStateCallback mPlatformIdleStateCallback;

    final class MyHandler extends Handler {
@@ -262,6 +273,7 @@ public class BatteryStatsImpl extends BatteryStats {

    public final MyHandler mHandler;
    private ExternalStatsSync mExternalSync = null;
    private UserInfoProvider mUserInfoProvider = null;

    private BatteryCallback mCallback;

@@ -649,6 +661,7 @@ public class BatteryStatsImpl extends BatteryStats {
        mDailyFile = null;
        mHandler = null;
        mPlatformIdleStateCallback = null;
        mUserInfoProvider = null;
        clearHistoryLocked();
    }

@@ -8588,16 +8601,14 @@ public class BatteryStatsImpl extends BatteryStats {
        return mCpuFreqs;
    }

    public BatteryStatsImpl(File systemDir, Handler handler) {
        this(new SystemClocks(), systemDir, handler, null);
    public BatteryStatsImpl(File systemDir, Handler handler, PlatformIdleStateCallback cb,
            UserInfoProvider userInfoProvider) {
        this(new SystemClocks(), systemDir, handler, cb, userInfoProvider);
    }

    public BatteryStatsImpl(File systemDir, Handler handler, PlatformIdleStateCallback cb) {
        this(new SystemClocks(), systemDir, handler, cb);
    }

    public BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
            PlatformIdleStateCallback cb) {
    private BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
            PlatformIdleStateCallback cb,
            UserInfoProvider userInfoProvider) {
        init(clocks);

        if (systemDir != null) {
@@ -8684,6 +8695,7 @@ public class BatteryStatsImpl extends BatteryStats {
        clearHistoryLocked();
        updateDailyDeadlineLocked();
        mPlatformIdleStateCallback = cb;
        mUserInfoProvider = userInfoProvider;
    }

    public BatteryStatsImpl(Parcel p) {
@@ -10172,6 +10184,7 @@ public class BatteryStatsImpl extends BatteryStats {
        // we read, we get a delta. If we are to distribute the cpu time, then do so. Otherwise
        // we just ignore the data.
        final long startTimeMs = mClocks.uptimeMillis();
        mUserInfoProvider.refreshUserIds();
        mKernelUidCpuTimeReader.readDelta(!mOnBatteryInternal ? null :
                new KernelUidCpuTimeReader.Callback() {
                    @Override
@@ -10185,6 +10198,11 @@ public class BatteryStatsImpl extends BatteryStats {
                                    + " no mapping to owning uid: " + uid);
                            return;
                        }
                        if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
                            Slog.d(TAG, "Got readings for an invalid user's uid " + uid);
                            mKernelUidCpuTimeReader.removeUid(uid);
                            return;
                        }
                        final Uid u = getUidStatsLocked(uid);

                        // Accumulate the total system and user time.
@@ -10357,6 +10375,11 @@ public class BatteryStatsImpl extends BatteryStats {
                                    + " no mapping to owning uid: " + uid);
                            return;
                        }
                        if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
                            Slog.d(TAG, "Got readings for an invalid user's uid " + uid);
                            mKernelUidCpuFreqTimeReader.removeUid(uid);
                            return;
                        }
                        final Uid u = getUidStatsLocked(uid);
                        if (u.mCpuFreqTimeMs == null) {
                            u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase);
@@ -11018,6 +11041,23 @@ public class BatteryStatsImpl extends BatteryStats {
        return u;
    }

    public void onCleanupUserLocked(int userId) {
        final int firstUidForUser = UserHandle.getUid(userId, 0);
        final int lastUidForUser = UserHandle.getUid(userId, UserHandle.PER_USER_RANGE - 1);
        mKernelUidCpuFreqTimeReader.removeUidsInRange(firstUidForUser, lastUidForUser);
        mKernelUidCpuTimeReader.removeUidsInRange(firstUidForUser, lastUidForUser);
    }

    public void onUserRemovedLocked(int userId) {
        final int firstUidForUser = UserHandle.getUid(userId, 0);
        final int lastUidForUser = UserHandle.getUid(userId, UserHandle.PER_USER_RANGE - 1);
        mUidStats.put(firstUidForUser, null);
        mUidStats.put(lastUidForUser, null);
        final int firstIndex = mUidStats.indexOfKey(firstUidForUser);
        final int lastIndex = mUidStats.indexOfKey(lastUidForUser);
        mUidStats.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
    }

    /**
     * Remove the statistics object for a particular uid.
     */
+11 −0
Original line number Diff line number Diff line
@@ -76,6 +76,17 @@ public class KernelUidCpuFreqTimeReader {
        mLastUidCpuFreqTimeMs.delete(uid);
    }

    public void removeUidsInRange(int startUid, int endUid) {
        if (endUid < startUid) {
            return;
        }
        mLastUidCpuFreqTimeMs.put(startUid, null);
        mLastUidCpuFreqTimeMs.put(endUid, null);
        final int firstIndex = mLastUidCpuFreqTimeMs.indexOfKey(startUid);
        final int lastIndex = mLastUidCpuFreqTimeMs.indexOfKey(endUid);
        mLastUidCpuFreqTimeMs.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
    }

    @VisibleForTesting
    public void readDelta(BufferedReader reader, @Nullable Callback callback) throws IOException {
        String line = reader.readLine();
+29 −4
Original line number Diff line number Diff line
@@ -130,17 +130,42 @@ public class KernelUidCpuTimeReader {
     * @param uid The UID to remove.
     */
    public void removeUid(int uid) {
        int index = mLastUserTimeUs.indexOfKey(uid);
        final int index = mLastSystemTimeUs.indexOfKey(uid);
        if (index >= 0) {
            mLastUserTimeUs.removeAt(index);
            mLastSystemTimeUs.removeAt(index);
            mLastUserTimeUs.removeAt(index);
        }
        removeUidsFromKernelModule(uid, uid);
    }

    /**
     * Removes UIDs in a given range from the kernel module and internal accounting data.
     * @param startUid the first uid to remove
     * @param endUid the last uid to remove
     */
    public void removeUidsInRange(int startUid, int endUid) {
        if (endUid < startUid) {
            return;
        }
        mLastSystemTimeUs.put(startUid, 0);
        mLastUserTimeUs.put(startUid, 0);
        mLastSystemTimeUs.put(endUid, 0);
        mLastUserTimeUs.put(endUid, 0);
        final int startIndex = mLastSystemTimeUs.indexOfKey(startUid);
        final int endIndex = mLastSystemTimeUs.indexOfKey(endUid);
        mLastSystemTimeUs.removeAtRange(startIndex, endIndex - startIndex + 1);
        mLastUserTimeUs.removeAtRange(startIndex, endIndex - startIndex + 1);
        removeUidsFromKernelModule(startUid, endUid);
    }

    private void removeUidsFromKernelModule(int startUid, int endUid) {
        Slog.d(TAG, "Removing uids " + startUid + "-" + endUid);
        try (FileWriter writer = new FileWriter(sRemoveUidProcFile)) {
            writer.write(Integer.toString(uid) + "-" + Integer.toString(uid));
            writer.write(startUid + "-" + endUid);
            writer.flush();
        } catch (IOException e) {
            Slog.e(TAG, "failed to remove uid from uid_cputime module", e);
            Slog.e(TAG, "failed to remove uids " + startUid + " - " + endUid
                    + " from uid_cputime module", e);
        }
    }
}
+156 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2007 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 android.util;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import android.support.annotation.NonNull;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.Random;

/**
 * Internal tests for {@link SparseLongArray}.
 */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SparseLongArrayTest {

    private static final int TEST_SIZE = 1000;

    private SparseLongArray mSparseLongArray;
    private int[] mKeys;
    private long[] mValues;
    private Random mRandom;

    private static boolean isSame(@NonNull SparseLongArray array1,
            @NonNull SparseLongArray array2) {
        if (array1.size() != array2.size()) {
            return false;
        }
        for (int i = 0; i < array1.size(); i++) {
            if (array1.keyAt(i) != array2.keyAt(i) || array1.valueAt(i) != array2.valueAt(i)) {
                return false;
            }
        }
        return true;
    }

    private void assertRemoved(int startIndex, int endIndex) {
        for (int i = 0; i < TEST_SIZE; i++) {
            if (i >= startIndex && i <= endIndex) {
                assertEquals("Entry not removed", Long.MIN_VALUE,
                        mSparseLongArray.get(mKeys[i], Long.MIN_VALUE));
            } else {
                assertEquals("Untouched entry corrupted", mValues[i],
                        mSparseLongArray.get(mKeys[i]));
            }
        }
    }

    /**
     * Generates a sorted array of distinct and random keys
     *
     * @param size the number of keys to return in the array. Should be < (2^31)/1000.
     * @return the array of keys
     */
    private int[] generateRandomKeys(int size) {
        final int[] keys = new int[size];
        keys[0] = -1 * mRandom.nextInt(size * 500);
        for (int i = 1; i < size; i++) {
            keys[i] = keys[i - 1] + 1 + mRandom.nextInt(1000);
            assertTrue(keys[i] > keys[i - 1]);
        }
        return keys;
    }

    @Before
    public void setUp() {
        mSparseLongArray = new SparseLongArray();
        mRandom = new Random(12345);
        mKeys = generateRandomKeys(TEST_SIZE);
        mValues = new long[TEST_SIZE];
        for (int i = 0; i < TEST_SIZE; i++) {
            mValues[i] = i + 1;
            mSparseLongArray.put(mKeys[i], mValues[i]);
        }
    }

    @Test
    public void testRemoveAtRange_removeHead() {
        mSparseLongArray.removeAtRange(0, 100);
        assertEquals(TEST_SIZE - 100, mSparseLongArray.size());
        assertRemoved(0, 99);
    }

    @Test
    public void testRemoveAtRange_removeTail() {
        mSparseLongArray.removeAtRange(TEST_SIZE - 200, 200);
        assertEquals(TEST_SIZE - 200, mSparseLongArray.size());
        assertRemoved(TEST_SIZE - 200, TEST_SIZE - 1);
    }

    @Test
    public void testRemoveAtRange_removeOverflow() {
        mSparseLongArray.removeAtRange(TEST_SIZE - 100, 200);
        assertEquals(TEST_SIZE - 100, mSparseLongArray.size());
        assertRemoved(TEST_SIZE - 100, TEST_SIZE - 1);
    }

    @Test
    public void testRemoveAtRange_removeEverything() {
        mSparseLongArray.removeAtRange(0, TEST_SIZE);
        assertEquals(0, mSparseLongArray.size());
        assertRemoved(0, TEST_SIZE - 1);
    }

    @Test
    public void testRemoveAtRange_removeMiddle() {
        mSparseLongArray.removeAtRange(200, 200);
        assertEquals(TEST_SIZE - 200, mSparseLongArray.size());
        assertRemoved(200, 399);
    }

    @Test
    public void testRemoveAtRange_removeSingle() {
        mSparseLongArray.removeAtRange(300, 1);
        assertEquals(TEST_SIZE - 1, mSparseLongArray.size());
        assertRemoved(300, 300);
    }

    @Test
    public void testRemoveAtRange_compareRemoveAt() {
        final SparseLongArray sparseLongArray2 = mSparseLongArray.clone();
        assertTrue(isSame(mSparseLongArray, sparseLongArray2));

        final int startIndex = 101;
        final int endIndex = 200;
        mSparseLongArray.removeAtRange(startIndex, endIndex - startIndex + 1);
        for (int i = endIndex; i >= startIndex; i--) {
            sparseLongArray2.removeAt(i);
        }
        assertEquals(TEST_SIZE - (endIndex - startIndex + 1), mSparseLongArray.size());
        assertRemoved(startIndex, endIndex);
        assertTrue(isSame(sparseLongArray2, mSparseLongArray));
    }
}
Loading