Android 系统设备启动标识及系统更新标识的JNI与原生获取方式
Android 系统设备启动标识及系统更新标识的JNI与原生获取方式
通过JNI方式获取
系统启动标识 boot_mark
文档中提供的获取参考为
static jstring getBoot(JNIEnv *env, jclass) {
FILE *fp = fopen("/proc/sys/kernel/random/boot_id", "r");
char boot[TID1_LEN];
if (fp == nullptr) {
//获取失败
} else {
unsigned char c;
int i = 0;
while (i < TID1_LEN) {
c = fgetc(fp);
boot[i] = c;
i = i + 1;
}
if (ferror(fp)) {
//获取失败
}
}
// fgets(t1,sizeof(t1),fp);
std::string sboot = boot;
return env->NewStringUTF(sboot.c_str());
}
实际测试中发现,虚拟机等部分设备会在NewStringUTF
方法中出现 NewstringUTF方法会在部分设备上报错 input is not valid Modified UTF-8: illegal start byte 0x**
错误,参照Android API广告反作弊需求 Native层获取 bootMark奔溃解析
中提到的方法修改后的代码为:
static jstring getBoot(JNIEnv *env, jclass) {
FILE *fp = fopen("/proc/sys/kernel/random/boot_id", "r");
char boot[TID1_LEN];
if (fp == nullptr) {
//获取失败
} else {
unsigned char c;
int i = 0;
while (i < TID1_LEN) {
c = fgetc(fp);
boot[i] = c;
i = i + 1;
}
if (ferror(fp)) {
//获取失败
}
}
// fgets(t1,sizeof(t1),fp);
//std::string sboot = boot;
//return env->NewStringUTF(sboot.c_str());
//替换下面的代码
jclass strClass = (env)->FindClass("java/lang/String");
jstring encoding = (env)->NewStringUTF("UTF-8");
jmethodID ctorID = (env)->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
//建立byte数组
jbyteArray bytes = (env)->NewByteArray((jsize) TID1_LEN);
//将char* 转换为byte数组
(env)->SetByteArrayRegion(bytes, 0, (jsize) TID1_LEN, (jbyte *) boot);
return (jstring) (env)->NewObject(strClass, ctorID, bytes, encoding);
}
获取系统更新标识 update_mark
直接使用参考代码:
static jstring getUpdate(JNIEnv *env, jclass) {
struct stat sb{};
int updates = 0;
int updatens = 0;
if (stat("/data/data", &sb) == -1) {
//获取失败
} else {
updatens = (int) sb.st_atim.tv_nsec;
updates = (int) sb.st_atim.tv_sec;
}
std::string idRes = std::to_string(updates) + "." + std::to_string(updatens);
return env->NewStringUTF(idRes.c_str());
}
通过原生获取
系统启动标识 boot_mark
获取启动标识要更方便一些
public static String getBootMark() {
String ret = "";
try {
File bootIdFile = new File("/proc/sys/kernel/random/boot_id");
if (bootIdFile.exists()) {
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(bootIdFile);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
ret = reader.readLine().trim();
try {
ret = ret.substring(0, 36);
} catch (Throwable ignore) {
}
} catch (IOException ignore) {
} finally {
if (inputStream != null) try {
inputStream.close();
} catch (IOException error) {
error.printStackTrace();
}
}
}
} catch (Throwable tr) {
tr.printStackTrace();
}
return ret;
}
获取系统更新标识 update_mark
由于StructStat#st_atim和StructTimespec是API level 27
新增的属性,所以27以下的设备只能获取到秒精度
private String getUpdateMark() {
try {
// 通过os获取StructStat
StructStat fstat = Os.stat("/data/data");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
// 27及以上新增StructTimespec,支持nsec
StructTimespec st_atim = fstat.st_atim;
return st_atim.tv_sec + "." + st_atim.tv_nsec;
} else {
// 27以下通过 Seconds part of time of last access 获取
return fstat.st_atime + "." + "0";
}
} catch (Throwable tr) {
tr.printStackTrace();
}
return "";
}
分类:
Android
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)