一蜓洪、問(wèn)題與調(diào)試
在做cpu負(fù)載問(wèn)題的是纤勒,需要讀取/proc/pressure/cpu/的數(shù)據(jù),發(fā)現(xiàn)打開(kāi)文件失敗
#define KERNEL_INFO_CPU "proc/pressure/cpu"
......
int fd = TEMP_FAILURE_RETRY(open(KERNEL_INFO_CPU, O_WRONLY | O_CLOEXEC));
if (fd < 0) {
ALOGE("open failed (errno=%d)", errno);
return -1;
}
......
#define EACCES 13 /* Permission denied */ 意思就是沒(méi)有權(quán)限
查看一下
進(jìn)入 proc/pressure/目錄下 ls -alh
-r--r--r-- 1 root root 0 2024-06-11 20:01 cpu
-rw-rw-r-- 1 system system 0 2024-06-11 19:42 io
-rw-rw-r-- 1 system system 0 2024-06-11 19:41 memory
可以看到 cpu 訪問(wèn)需要root權(quán)限隆檀, 那就修改
system/core/rootdir/init.rc
在init.rc文件中加入如下
chown system system /proc/pressure/cpu
chmod 0664 /proc/pressure/cpu
調(diào)試編譯也簡(jiǎn)單摇天,直接在system/core/rootdir/ mm,編譯產(chǎn)生的文件在
target\product\XXXX\system\etc\init\hw\init.rc 恐仑,然后 push init.rc system/etc/init/hw 替換其中的init.rc
當(dāng)然直接把機(jī)器中的init.rc pull 出來(lái)闸翅,然后修改push進(jìn)去也可以。
二菊霜、jni的配置例子
接著整理一下jni的使用坚冀,不跨進(jìn)程,system_server進(jìn)程中的jni使用鉴逞。
主要涉及的文件
java 文件
....../services/core/java/com/android/server/am/NameJavaTemp.java
cpp 文件
....../services/jni/NameCppTemp.cpp
....../ services/jni/onload.cpp
....../services/jni/Android.bp
1记某、java 文件
....../services/core/java/com/android/server/am/NameJavaTemp.java
public class NameJavaTemp {
public NameJavaTemp(){
init();
}
private void init(){
new Thread(){
@Override
public void run(){
javaToNative();
}
}.start();
}
private native void javaToNative();
public void nativeTojava(String str){}
}
2构捡、....../services/jni/Android.bp
......
srcs: [
"onload.cpp",
"com_android_server_am_NameCppTemp.cpp",
],
......
3液南、....../ services/jni/onload.cpp
namespace android {
......
int register_android_server_NameCppTemp(JNIEnv* env);
......
};
extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
......
register_android_server_NameCppTemp(env);
......
return JNI_VERSION_1_4;
}
4、
如下代碼就包括從Java層通過(guò)jni調(diào)用到cpp層 javaToNative的具體實(shí)現(xiàn)勾徽,滑凉。
NameCppTemp.cpp
......
namespace android{
static int initM(JNIEnv* env, jobject clazz) {
......
jclass cls = env->GetObjectClass(clazz);
jmethodID methodId = env->GetMethodID(cls, "nativeTojava", "(Ljava/lang/String;)V");
if (methodId == nullptr) {
// error
return -1;
}
jstring arg = env->NewStringUTF("1");
env->CallVoidMethod(clazz, methodId, arg);
}
static const JNINativeMethod gMethods[] = {
{ "javaToNative","()V",(void*) initM}, //javaToNative就是 java端聲明的native方法,initM就是具體實(shí)現(xiàn)的方法名
};
int register_android_server_NameCppTemp(JNIEnv *env) {
return jniRegisterNativeMethods(env, "com/android/server/am/NameJavaTemp", gMethods,NELEM(gMethods)); //NameJavaTemp就是java端的類(lèi)名
}
}
三、epoll機(jī)制例子
實(shí)現(xiàn)了 epoll機(jī)制 監(jiān)聽(tīng) proc/pressure/cpu的 閾值喘帚,
....../services/jni/NameCppTemp.cpp
#define KERNEL_INFO_CPU "proc/pressure/cpu"
#include <stdio.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <string>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <utils/misc.h>
#include <nativehelper/JNIHelp.h>
#include <errno.h>
#include <log/log.h>
#include "jni.h"
#include<iostream>
#include<fstream>
#include<string>
#define MAX_POLL_EVENT 256
namespace android{
static int epollfd = -1;
static JNIEnv* g_env;
static int initM(JNIEnv* env, jobject clazz) {
const char trig[] = "some 500000 1000000";
epollfd = epoll_create(MAX_POLL_EVENT);
if (epollfd == -1) {
ALOGE("epoll_create failed: %s", strerror(errno));
return -1;
}
int fd = TEMP_FAILURE_RETRY(open(KERNEL_INFO_CPU, O_WRONLY | O_CLOEXEC));
if (fd < 0) {
ALOGE("open failed (errno=%d)", errno);
return -1;
}
int res;
struct epoll_event epev;
epev.events = EPOLLPRI;
if (write(fd, trig, strlen(trig) + 1) < 0) {
ALOGD("/proc/pressure/cpu write error: %s\n", strerror(errno));
return -1;
}
res = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &epev);
if (res < 0) {
ALOGE("epoll_ctl for monitor failed; errno=%d", errno);
}
while(true) {
struct epoll_event events[20];
int eventCount = 0;
eventCount = epoll_wait(epollfd, events, 20, -1);
if (eventCount < 0) {
if (errno == EINTR) {
continue;
}
ALOGE("epoll_wait failed (errno=%d)", errno);
return -1;
}
//ALOGD("The eventCount %d", eventCount);
jclass cls = env->GetObjectClass(clazz);
jmethodID methodId = env->GetMethodID(cls, "nativeTojava", "(Ljava/lang/String;)V");
if (methodId == nullptr) {
// error
return -1;
}
jstring arg = env->NewStringUTF("1");
env->CallVoidMethod(clazz, methodId, arg);
//test
std::ifstream file("proc/pressure/cpu");
if (!file.is_open()) {
ALOGD("open file failure");
return -1;
}
std::string buf;
getline(file, buf);
ALOGD("ZZZZ %s", buf.c_str());
}
}
static const JNINativeMethod gMethods[] = {
{ "javaToNative","()V",(void*) initM}, //javaToNative就是 java端聲明的native方法
};
int register_android_server_NameCppTemp(JNIEnv *env) {
return jniRegisterNativeMethods(env, "com/android/server/am/NameJavaTemp", gMethods,NELEM(gMethods)); //NameJavaTemp就是java端的類(lèi)名
}
}
四畅姊、所涉及的jni 相關(guān)信息
1、JNI編程中JNIEnv吹由、jobject和jclass這三種基本類(lèi)型
JavaVm是虛擬機(jī)在jni層的代表若未,?個(gè)進(jìn)程只有?個(gè)JavaVm,所有線程共??個(gè)JavaVM倾鲫。
JNIEnv 是?個(gè)線程相關(guān)的結(jié)構(gòu)體粗合,它代表了java的運(yùn)?環(huán)境 萍嬉。每?個(gè)線程都會(huì)有?個(gè),不同的線程中
不能相互調(diào)?隙疚,每個(gè)JNIEnv都是線程專(zhuān)有的壤追。 jni中可以擁有很多個(gè)JNIEnv,可以使?它來(lái)進(jìn)?java層
和native層的調(diào)?供屉。JNIEnv 是?個(gè)指針大诸,指向?個(gè)線程相關(guān)的結(jié)構(gòu),線程相關(guān)結(jié)構(gòu)指向了JNI函數(shù)指針數(shù)組贯卦。這個(gè)數(shù)組??
定義了?量的JNI函數(shù)指針。在同?個(gè)線程中焙贷,多次調(diào)?JNI層?法撵割,傳?的JNIEnv都是相同的。
在java層定義的本地?法辙芍,可以在不同的線程中調(diào)?啡彬,因此是可以接受不同的JNIEnv。jobject:實(shí)例引?(C++的說(shuō)法:對(duì)象引?)(普通函數(shù))
jclass: 類(lèi)引? (靜態(tài)函數(shù))
static int initM(JNIEnv* env, jobject clazz) {......}