AndroidV上读取proc/pressure/cpu失败

一、问题与调试

在做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这三种基本类型

  • JavaVm是虚拟机在jni层的代表,⼀个进程只有⼀个JavaVm,所有线程共⽤⼀个JavaVM。

  • JNIEnv 是⼀个线程相关的结构体,它代表了java的运⾏环境 。每⼀个线程都会有⼀个,不同的线程中
    不能相互调⽤,每个JNIEnv都是线程专有的。 jni中可以拥有很多个JNIEnv,可以使⽤它来进⾏java层
    和native层的调⽤。

  • JNIEnv 是⼀个指针,指向⼀个线程相关的结构,线程相关结构指向了JNI函数指针数组。这个数组⾥⾯
    定义了⼤量的JNI函数指针。

  • 在同⼀个线程中,多次调⽤JNI层⽅法,传⼊的JNIEnv都是相同的。
    在java层定义的本地⽅法,可以在不同的线程中调⽤,因此是可以接受不同的JNIEnv。

  • jobject:实例引⽤(C++的说法:对象引⽤)(普通函数)

  • jclass: 类引⽤ (静态函数)

static int initM(JNIEnv* env, jobject clazz) {......}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,271评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,725评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,252评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,634评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,549评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,985评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,471评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,128评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,257评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,233评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,235评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,940评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,528评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,623评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,858评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,245评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,790评论 2 339

推荐阅读更多精彩内容