Android 获取系统内存页大小:sysconf(_SC_PAGESIZE) 与 JNI 实现

最近一个应用准备上架 Google Play,其中某个 SDK 未适配 16KB 内存页大小的设备,因此需要根据设备的内存页大小进行功能屏蔽。具体做法:获取当前设备的内存页大小,若为 16KB,则禁用该 SDK 的相关功能。

先写个工具类,用于获取当前设备的内存页大小。

PageSizeHelper 定义native方法,代码贴出来如下:

java 复制代码
package com.example.nativedemo;

public class PageSizeHelper {
    static {
        System.loadLibrary("page_size_jni");   // should is same with lib name in CMakeLists.txt
    }

    public static native long getPageSize();
}

再这个java文件目录执行 javac -h . PageSizeHelper.java 命令生成头文件:

可以看到生成了头文件和class文件:

其中,com_example_nativedemo_PageSizeHelper.h 文件内容如下:

cpp 复制代码
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_nativedemo_PageSizeHelper */

#ifndef _Included_com_example_nativedemo_PageSizeHelper
#define _Included_com_example_nativedemo_PageSizeHelper
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_nativedemo_PageSizeHelper
 * Method:    getPageSize
 * Signature: ()J
 */
JNIEXPORT jlong JNICALL Java_com_example_nativedemo_PageSizeHelper_getPageSize
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

class文件没用,可以删了。

再右击main目录, 按照下面步骤创建jni目录:

创建好jni目录如下:

再把头文件移动到该jni目录。

再在jni目录里创建c++文件实现其功能, page_size_jni.cpp内容如下:

cpp 复制代码
#include <jni.h>
#include <unistd.h>
#include "com_example_nativedemo_PageSizeHelper.h"

extern "C"
JNIEXPORT jlong JNICALL JNICALL Java_com_example_nativedemo_PageSizeHelper_getPageSize
        (JNIEnv * env, jclass cls) {
    // sysconf(_SC_PAGESIZE) 返回 long,直接转为 jlong
    long pageSize = sysconf(_SC_PAGESIZE);
    return (jlong) pageSize;
}

其中sysconf是一个c语言库函数,获取系统当前的各项配置信息或限制值, 使用它需要包含<unistd.h> 头文件。

Jni目录创建CMakeLists.txt,步骤:

CMakeLists.txt 内容如下:

bash 复制代码
cmake_minimum_required(VERSION 3.4.1)
project("zx_native") # 项目名称 可以随意修改

# 添加一个共享库,名称必须与 System.loadLibrary() 中一致
add_library(
        page_size_jni        # 库名, System.loadLibrary("page_size_jni") 就是加载的这个库
        SHARED               # 动态库
        page_size_jni.cpp    # 源文件
)

# 可选:如果需要查找 log 库等,可以添加
# find_library(log-lib log)
# target_link_libraries(page_size_jni ${log-lib})

修改app/build.gradle.kts :

app/build.gradle.kts完整内容如下:

Groovy 复制代码
plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.compose)
}

android {
    namespace = "com.example.nativedemo"
    compileSdk = 36

    defaultConfig {
        applicationId = "com.example.nativedemo"
        minSdk = 29
        targetSdk = 36
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

        ndk {
            abiFilters.addAll(listOf("arm64-v8a", "armeabi-v7a"))
        }

        externalNativeBuild {
            cmake {
                cppFlags("-std=c++17")
            }
        }

        ndkVersion = "30.0.14904198"
    }

    externalNativeBuild {
        cmake {
            path = file("src/main/jni/CMakeLists.txt")
        }
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    buildFeatures {
        viewBinding = true
    }
}

dependencies {
    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.appcompat)
    implementation(libs.androidx.material)

    // Compose 可以保留
    implementation(libs.androidx.lifecycle.runtime.ktx)
    implementation(libs.androidx.activity.compose)
    implementation(platform(libs.androidx.compose.bom))
    implementation(libs.androidx.compose.ui)
    implementation(libs.androidx.compose.ui.graphics)
    implementation(libs.androidx.compose.ui.tooling.preview)
    implementation(libs.androidx.compose.material3)

    // MVI核心依赖
    implementation(libs.androidx.lifecycle.viewmodel.ktx)
    implementation(libs.kotlinx.coroutines.android)
    implementation(libs.androidx.recyclerview)
    implementation(libs.androidx.swiperefreshlayout)

    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.junit)
    androidTestImplementation(libs.androidx.espresso.core)
}

同步报错:

下载ndk:

下载完再同步就ok了。

在MainActivity测试下:

运行:

ok. 获取到了,看下对不对,用adb命令再看下PAGESIZE值:

ok. 获取到了。

相关推荐
天空之城--3 小时前
Android Koin 完全指南:从原理到实践
android
zhangphil4 小时前
Android main thread主线程Choreographer doFrame发生FullSuspendCheck
android
TimeFine8 小时前
智能眼镜开发:获取真实的音频路由
android
pengyu8 小时前
【Kotlin 协程修仙录 · 渡劫境 · 中阶】 | 造化神兵:自定义 CoroutineDispatcher 与调度器的终极定制
android·kotlin
pengyu8 小时前
【Kotlin 协程修仙录 · 渡劫境 · 初阶】 | 飞升雷劫:CPS 变换与挂起函数字节码终极透视
android·kotlin
TimeFine9 小时前
智能眼镜开发:眼镜Touch后收音与触发播放系统音乐的矛盾处理
android
TimeFine9 小时前
智能眼镜开发:眼镜侧收集音频
android
又见情义9 小时前
Android 系统设置从平板版迁移至TV版实践
android
杉氧12 小时前
打破边界(一):实战编写 Android/iOS 原生模块 (Native Modules)
android·react native·前端框架