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

Commit 951e7254 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge changes Ie5fa2605,Ia092e896 am: 140049bc

Change-Id: I20fd969e2124c228506e11540bdea04676684530
parents 9e8e0a54 140049bc
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -53,6 +53,8 @@ public class KernelSingleUidTimeReader {
    private int mReadErrorCounter;
    @GuardedBy("this")
    private boolean mSingleUidCpuTimesAvailable = true;
    @GuardedBy("this")
    private boolean mBpfTimesAvailable = true;
    // We use the freq count obtained from /proc/uid_time_in_state to decide how many longs
    // to read from each /proc/uid/<uid>/time_in_state. On the first read, verify if this is
    // correct and if not, set {@link #mSingleUidCpuTimesAvailable} to false. This flag will
@@ -62,6 +64,8 @@ public class KernelSingleUidTimeReader {

    private final Injector mInjector;

    private static final native boolean canReadBpfTimes();

    KernelSingleUidTimeReader(int cpuFreqsCount) {
        this(cpuFreqsCount, new Injector());
    }
@@ -83,6 +87,18 @@ public class KernelSingleUidTimeReader {
            if (!mSingleUidCpuTimesAvailable) {
                return null;
            }
            if (mBpfTimesAvailable) {
                final long[] cpuTimesMs = mInjector.readBpfData(uid);
                if (cpuTimesMs.length == 0) {
                    mBpfTimesAvailable = false;
                } else if (!mCpuFreqsCountVerified && cpuTimesMs.length != mCpuFreqsCount) {
                    mSingleUidCpuTimesAvailable = false;
                    return null;
                } else {
                    mCpuFreqsCountVerified = true;
                    return computeDelta(uid, cpuTimesMs);
                }
            }
            // Read total cpu times from the proc file.
            final String procFile = new StringBuilder(PROC_FILE_DIR)
                    .append(uid)
@@ -230,6 +246,8 @@ public class KernelSingleUidTimeReader {
        public byte[] readData(String procFile) throws IOException {
            return Files.readAllBytes(Paths.get(procFile));
        }

        public native long[] readBpfData(int uid);
    }

    @VisibleForTesting
+1 −0
Original line number Diff line number Diff line
@@ -208,6 +208,7 @@ cc_library_shared {
        "com_android_internal_os_ClassLoaderFactory.cpp",
        "com_android_internal_os_FuseAppLoop.cpp",
        "com_android_internal_os_KernelCpuUidBpfMapReader.cpp",
        "com_android_internal_os_KernelSingleUidTimeReader.cpp",
        "com_android_internal_os_Zygote.cpp",
        "com_android_internal_os_ZygoteInit.cpp",
        "com_android_internal_util_VirtualRefBasePtr.cpp",
+2 −0
Original line number Diff line number Diff line
@@ -231,6 +231,7 @@ extern int register_com_android_internal_os_AtomicDirectory(JNIEnv *env);
extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
extern int register_com_android_internal_os_KernelCpuUidBpfMapReader(JNIEnv *env);
extern int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env);
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
@@ -1642,6 +1643,7 @@ static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_com_android_internal_os_AtomicDirectory),
    REG_JNI(register_com_android_internal_os_FuseAppLoop),
    REG_JNI(register_com_android_internal_os_KernelCpuUidBpfMapReader),
    REG_JNI(register_com_android_internal_os_KernelSingleUidTimeReader),
};

/*
+54 −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.
 */

#include "core_jni_helpers.h"

#include <cputimeinstate.h>

namespace android {

static constexpr uint64_t NSEC_PER_MSEC = 1000000;

static jlongArray copyVecsToArray(JNIEnv *env, std::vector<std::vector<uint64_t>> &vec) {
    jsize s = 0;
    for (const auto &subVec : vec) s += subVec.size();
    jlongArray ar = env->NewLongArray(s);
    jsize start = 0;
    for (auto &subVec : vec) {
        for (uint32_t i = 0; i < subVec.size(); ++i) subVec[i] /= NSEC_PER_MSEC;
        env->SetLongArrayRegion(ar, start, subVec.size(),
                                reinterpret_cast<const jlong*>(subVec.data()));
        start += subVec.size();
    }
    return ar;
}

static jlongArray getUidCpuFreqTimeMs(JNIEnv *env, jclass, jint uid) {
    auto out = android::bpf::getUidCpuFreqTimes(uid);
    if (!out) return env->NewLongArray(0);
    return copyVecsToArray(env, out.value());
}

static const JNINativeMethod g_single_methods[] = {
    {"readBpfData", "(I)[J", (void *)getUidCpuFreqTimeMs},
};

int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env) {
    return RegisterMethodsOrDie(env, "com/android/internal/os/KernelSingleUidTimeReader$Injector",
                                g_single_methods, NELEM(g_single_methods));
}

}
+24 −1
Original line number Diff line number Diff line
@@ -31,20 +31,33 @@ import com.android.internal.os.KernelSingleUidTimeReader.Injector;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.Collection;

@SmallTest
@RunWith(AndroidJUnit4.class)
@RunWith(Parameterized.class)
public class KernelSingleUidTimeReaderTest {
    private final static int TEST_UID = 2222;
    private final static int TEST_FREQ_COUNT = 5;

    private KernelSingleUidTimeReader mReader;
    private TestInjector mInjector;
    protected boolean mUseBpf;

    @Parameters(name="useBpf={0}")
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] { {true}, {false} });
    }

    public KernelSingleUidTimeReaderTest(boolean useBpf) {
        mUseBpf = useBpf;
    }

    @Before
    public void setUp() {
@@ -273,6 +286,7 @@ public class KernelSingleUidTimeReaderTest {

    class TestInjector extends Injector {
        private byte[] mData;
        private long[] mBpfData;
        private boolean mThrowExcpetion;

        @Override
@@ -284,6 +298,14 @@ public class KernelSingleUidTimeReaderTest {
            }
        }

        @Override
        public long[] readBpfData(int uid) {
            if (!mUseBpf || mBpfData == null) {
                return new long[0];
            }
            return mBpfData;
        }

        public void setData(long[] cpuTimes) {
            final ByteBuffer buffer = ByteBuffer.allocate(cpuTimes.length * Long.BYTES);
            buffer.order(ByteOrder.nativeOrder());
@@ -291,6 +313,7 @@ public class KernelSingleUidTimeReaderTest {
                buffer.putLong(time / 10);
            }
            mData = buffer.array();
            mBpfData = cpuTimes.clone();
        }

        public void letReadDataThrowException(boolean throwException) {