Merge changes Ie5fa2605,Ia092e896 am: 140049bce8 am: 951e7254cb
Change-Id: Ia8a485bccd46b2dd6946a2fb9e338f3565266c41
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user