You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Android应用获取读取内部存储CPU温度文件的权限?

Android应用读取CPU温度文件权限问题解决

问题描述

尝试读取CPU温度文件/sys/devices/virtual/thermal/thermal_zone0/temp时遇到权限拒绝错误,日志如下:

2023-03-03 23:21:12.178  5266-5266  System.err              com.example.racestats                W  java.io.FileNotFoundException: /sys/devices/virtual/thermal/thermal_zone0/temp: open failed: EACCES (Permission denied)
2023-03-03 23:21:12.179  5266-5266  System.err              com.example.racestats                W      at libcore.io.IoBridge.open(IoBridge.java:574)
2023-03-03 23:21:12.179  5266-5266  System.err              com.example.racestats                W      at java.io.RandomAccessFile.<init>(RandomAccessFile.java:289)
2023-03-03 23:21:12.179  5266-5266  System.err              com.example.racestats                W      at java.io.RandomAccessFile.<init>(RandomAccessFile.java:152)
2023-03-03 23:21:12.179  5266-5266  System.err              com.example.racestats                W      at com.example.racestats.MainActivityKt.getCpuTemperature(MainActivity.kt:171)
2023-03-03 23:21:12.180  5266-5266  System.err              com.example.racestats                W      at com.example.racestats.MainActivityKt.cpuTemperature$lambda$0(MainActivity.kt:157)
2023-03-03 23:21:12.180  5266-5266  System.err              com.example.racestats                W      at com.example.racestats.MainActivityKt.$r8$lambda$vjQE1RADCplWY99vEEfe1Z4FocA(Unknown Source:0)
2023-03-03 23:21:12.180  5266-5266  System.err              com.example.racestats                W      at com.example.racestats.MainActivityKt$$ExternalSyntheticLambda0.onClick(Unknown Source:4)
2023-03-03 23:21:12.180  5266-5266  System.err              com.example.racestats                W      at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:175)
2023-03-03 23:21:12.180  5266-5266  System.err              com.example.racestats                W      at android.os.Handler.dispatchMessage(Handler.java:106)
2023-03-03 23:21:12.180  5266-5266  System.err              com.example.racestats                W      at android.os.Looper.loopOnce(Looper.java:201)
2023-03-03 23:21:12.180  5266-5266  System.err              com.example.racestats                W      at android.os.Looper.loop(Looper.java:288)
2023-03-03 23:21:12.180  5266-5266  System.err              com.example.racestats                W      at android.app.ActivityThread.main(ActivityThread.java:7872)
2023-03-03 23:21:12.180  5266-5266  System.err              com.example.racestats                W      at java.lang.reflect.Method.invoke(Native Method)
2023-03-03 23:21:12.180  5266-5266  System.err              com.example.racestats                W      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
2023-03-03 23:21:12.180  5266-5266  System.err              com.example.racestats                W      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
2023-03-03 23:21:12.181  5266-5266  System.err              com.example.racestats                W  Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
2023-03-03 23:21:12.181  5266-5266  System.err              com.example.racestats                W      at libcore.io.Linux.open(Native Method)
2023-03-03 23:21:12.181  5266-5266  System.err              com.example.racestats                W      at libcore.io.ForwardingOs.open(ForwardingOs.java:563)
2023-03-03 23:21:12.181  5266-5266  System.err              com.example.racestats                W      at libcore.io.BlockGuardOs.open(BlockGuardOs.java:274)
2023-03-03 23:21:12.181  5266-5266  System.err              com.example.racestats                W      at libcore.io.ForwardingOs.open(ForwardingOs.java:563)
2023-03-03 23:21:12.181  5266-5266  System.err              com.example.racestats                W      at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7758)
2023-03-03 23:21:12.181  5266-5266  System.err              com.example.racestats                W      at libcore.io.IoBridge.open(IoBridge.java:560)
2023-03-03 23:21:12.181  5266-5266  System.err              com.example.racestats                W      ... 14 more

当前Kotlin代码

/**
 * This function will set the CPU Temp in are UI and will handles all things associated with the CPU temp.
 */
fun cpuTemperature(activity: Activity, callback: (Float) -> Unit) {
    val permissionCheck = ContextCompat.checkSelfPermission(activity, Manifest.permission.MANAGE_EXTERNAL_STORAGE)

    if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.MANAGE_EXTERNAL_STORAGE)) {
            Toast.makeText(activity, "This permission is required to access the CPU temperature.", Toast.LENGTH_LONG).show()
        }

        val alertDialogBuilder = AlertDialog.Builder(activity)
        alertDialogBuilder.setTitle("Permission Request")
        alertDialogBuilder.setMessage("The app needs access to external storage to read the CPU temperature. Do you allow this permission?")
        alertDialogBuilder.setPositiveButton("Allow") { _, _ ->
            ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.READ_INTERNAL_STORAGE), 1)
            ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 1)
            getCpuTemperature(callback)
        }
        alertDialogBuilder.setNegativeButton("Deny") { dialog, _ ->
            dialog.dismiss()
            // set cpu temp to be invisible
        }
        alertDialogBuilder.show()
    } else {
        getCpuTemperature(callback)
    }
}

fun getCpuTemperature(callback: (Float) -> Unit) {
    return try {
        val reader = RandomAccessFile("/sys/devices/virtual/thermal/thermal_zone0/temp", "r")
        val line: String = reader.readLine()
        if (line != null) {
            val temp = line.toFloat()
            println(temp / 1000.0f)
            callback(temp / 1000.0f)
        } else {
            println(51.0f)
            callback(51.0f)
        }
    } catch (e: Exception) {
        println("about to look for temp")
        e.printStackTrace()
        println("Temp is below")
        println(0.0f)
        callback(0.0f)
    }
}

当前AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:requestLegacyExternalStorage="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.RaceStats"

        tools:targetApi="31">

        <activity
            android:name=".TopSpeed"
            android:exported="false">
            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>

</manifest>

核心问题分析

  1. 权限方向错误:你申请的READ_EXTERNAL_STORAGE、MANAGE_EXTERNAL_STORAGE是针对外部存储(SD卡、公共存储目录)的权限,而/sys/devices/virtual/thermal属于系统虚拟文件系统,和外部存储完全无关,所以这些权限对读取该文件没有任何作用。另外,READ_INTERNAL_STORAGE并非Android官方定义的权限,添加它也没有意义。

  2. 系统权限限制:非Root的普通Android设备中,/sys下的大部分文件仅允许root用户或system组进程读取,第三方APP的UID不在允许范围内,直接读取会触发EACCES权限拒绝。

可行解决方案

方案一:使用官方ThermalManager API(推荐,API 31+)

Android 12(API 31)及以上提供了ThermalManager系统服务,可以安全获取设备温度数据,无需直接访问/sys文件:

修正后的Kotlin代码

fun getCpuTemperature(activity: Activity, callback: (Float) -> Unit) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        val thermalManager = activity.getSystemService(Context.THERMAL_SERVICE) as ThermalManager
        val thermalZones = thermalManager.thermalZones
        // 遍历热区,找到CPU相关的温度
        for (zone in thermalZones) {
            if (zone.type.contains("cpu", ignoreCase = true) || zone.name.contains("cpu", ignoreCase = true)) {
                val tempCelsius = zone.temperature / 1000.0f
                callback(tempCelsius)
                return
            }
        }
        // 未找到CPU热区时返回默认值
        callback(0.0f)
    } else {
        // 处理低版本系统,尝试兼容方式
        handleLegacyCpuTemp(callback)
    }
}

// 低版本系统兼容方法(部分设备可能可用)
private fun handleLegacyCpuTemp(callback: (Float) -> Unit) {
    val possiblePaths = arrayOf(
        "/sys/devices/virtual/thermal/thermal_zone0/temp",
        "/sys/class/thermal/thermal_zone0/temp",
        "/sys/devices/platform/soc/soc:qcom,mdss_fb.19200000.mdss_fb/thermal/temp"
    )
    for (path in possiblePaths) {
        try {
            val reader = RandomAccessFile(path, "r")
            val line = reader.readLine()?.trim()
            reader.close()
            if (!line.isNullOrEmpty()) {
                val temp = line.toFloat()
                callback(temp / 1000.0f)
                return
            }
        } catch (e: Exception) {
            // 路径不可读,尝试下一个
            continue
        }
    }
    // 所有路径都失败
    callback(0.0f)
}

修正后的Manifest

移除无用权限,仅保留必要配置:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.RaceStats"
        tools:targetApi="31">

        <activity
            android:name=".TopSpeed"
            android:exported="false">
            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>

</manifest>

方案二:Root设备(仅测试用)

如果你的应用仅面向Root用户,可以在获取Root权限后执行命令读取文件:

fun getRootCpuTemperature(callback: (Float) -> Unit) {
    try {
        val process = Runtime.getRuntime().exec("su -c cat /sys/devices/virtual/thermal/thermal_zone0/temp")
        val reader = BufferedReader(InputStreamReader(process.inputStream))
        val line = reader.readLine()?.trim()
        reader.close()
        process.waitFor()
        if (!line.isNullOrEmpty()) {
            val temp = line.toFloat()
            callback(temp / 1000.0f)
            return
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
    callback(0.0f)
}

注意:这种方式无法上架Google Play,且仅适用于Root设备。

方案三:依赖厂商适配

部分厂商会开放部分热区文件的读取权限,你可以尝试遍历多个可能的热区路径(如thermal_zone1、thermal_zone2等),但这种方式兼容性差,无法保证所有设备可用。

关键注意事项

  • 不要申请无关权限,避免用户困惑和Play Store审核问题。
  • 官方API是唯一稳定的获取温度方式,优先使用ThermalManager。
  • 低版本系统的兼容方案无法保证所有设备可用,需做好异常处理。

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 00:27:07