AndroidV上读取proc/pressure/cpu失败

2024-06-12  本文已影响0人  欣兄

一、问题与调试

在做cpu负载问题的是,需要读取/proc/pressure/cpu/的数据,发现打开文件失败

#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;
    }  
......

\color {red}{报错 open failed (errno =13)}

#define EACCES 13 /* Permission denied */   意思就是没有权限

查看一下

进入 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 访问需要root权限, 那就修改

system/core/rootdir/init.rc
在init.rc文件中加入如下
chown system system /proc/pressure/cpu
chmod 0664 /proc/pressure/cpu

调试编译也简单,直接在system/core/rootdir/ mm,编译产生的文件在
target\product\XXXX\system\etc\init\hw\init.rc ,然后 push init.rc system/etc/init/hw 替换其中的init.rc
当然直接把机器中的init.rc pull 出来,然后修改push进去也可以。

二、jni的配置例子

接着整理一下jni的使用,不跨进程,system_server进程中的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层通过jni调用到cpp层 javaToNative的具体实现,。

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就是具体实现的方法名
    };

    int register_android_server_NameCppTemp(JNIEnv *env) {
        return jniRegisterNativeMethods(env, "com/android/server/am/NameJavaTemp", gMethods,NELEM(gMethods)); //NameJavaTemp就是java端的类名
    }
}

三、epoll机制例子

实现了 epoll机制 监听 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端的类名
}
}

四、所涉及的jni 相关信息
1、JNI编程中JNIEnv、jobject和jclass这三种基本类型

static int initM(JNIEnv* env, jobject clazz) {......}
上一篇下一篇

猜你喜欢

热点阅读