news 2026/3/26 3:11:39

AOSP 客制化内功心法(五)让状态栏显示 CPU 温度 —— 从 Kernel 到 SystemUI 的数据流动艺术

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AOSP 客制化内功心法(五)让状态栏显示 CPU 温度 —— 从 Kernel 到 SystemUI 的数据流动艺术

🌡️ 引言:为什么“显示 CPU 温度”是绝佳学习案例?

  • 涉及层级最全:Kernel → HAL → SystemService → Framework → SystemUI
  • 数据流清晰:单向读取(非控制类),逻辑简单但完整
  • 贴近真实需求:性能监控、过热预警、调试工具等场景高频使用

更重要的是——

它完美展示了 AOSP 中“被动采集 + 主动推送 + UI 响应”的三段式数据流动模型

今天,我们就用“搭建一条体温监测流水线”的比喻,手把手打通这条链路!


🏗️ 整体架构:五层数据流水线

层级角色类比
Kernel体温传感器医院的红外测温仪
HAL数据采集员护士,定时读取体温
SystemService健康数据中心医生办公室,汇总数据
Framework对外窗口挂号台,提供查询接口
SystemUI显示屏病房门口的电子体温牌

✅ 我们的目标:让“电子体温牌”实时显示最新体温!


第一章:第 1 步 —— Kernel 提供“体温数据源”

大多数 Android 设备通过thermal sysfs暴露 CPU 温度:

# 查看 CPU 温度(单位:毫摄氏度) cat /sys/class/thermal/thermal_zone0/temp # 输出:42000 → 表示 42.0°C

💡 不同设备路径可能不同(如thermal_zone7),可通过:

adb shell ls /sys/class/thermal/thermal_zone*/type

找到类型为cpu-*CPU的 zone。

本教程假设路径为/sys/class/thermal/thermal_zone0/temp
无需修改 Kernel,直接读即可!


第二章:第 2 步 —— HAL 层:招聘“体温护士”

📜 步骤 1:定义护士岗位说明书(HIDL)

创建:hardware/interfaces/thermal/1.0/IThermal.hal

package android.hardware.thermal@1.0; interface IThermal { // 获取 CPU 温度(单位:摄氏度) getCpuTemperature() generates (float temperature); }

🛠️ 步骤 2:实现护士工作(C++)

hardware/interfaces/thermal/1.0/default/Thermal.cpp

#include <fstream> #include <string> #include <android-base/strings.h> Return<float> Thermal::getCpuTemperature() { std::ifstream tempFile("/sys/class/thermal/thermal_zone0/temp"); std::string line; if (std::getline(tempFile, line)) { // 转换:42000 → 42.0 int milliTemp = std::stoi(line); return static_cast<float>(milliTemp) / 1000.0f; } return -1.0f; // 错误值 }

✅ 护士只做一件事:读文件 → 转换单位 → 返回结果


🚪 步骤 3:让护士上岗(启动服务)

android.hardware.thermal@1.0-service.rc

service vendor.thermal-hal /vendor/bin/hw/android.hardware.thermal@1.0-service class hal user system

编译后,系统开机自动运行,护士就位!


第三章:第 3 步 —— SystemService:建立“健康数据中心”

🏢 创建 ThermalService(医生办公室)

frameworks/base/services/core/java/com/android/server/ThermalService.java

public class ThermalService extends IThermalService.Stub { private IThermal mHal; public ThermalService() { try { mHal = IThermal.getService(); // 找到护士 } catch (Exception e) { Slog.e("ThermalService", "找不到体温护士", e); } } @Override public float getCpuTemperature() { if (mHal != null) { try { return mHal.getCpuTemperature(); // 问护士要数据 } catch (Exception e) { Slog.e("ThermalService", "获取体温失败", e); } } return -1.0f; } }

📋 在 SystemServer 中注册

SystemServer.java

ThermalService thermal = new ThermalService(); ServiceManager.addService("thermal", thermal); // 登记进通讯录 Slog.i(TAG, "Thermal Service started");

✅ 现在,任何系统组件都能通过ServiceManager.getService("thermal")查询体温!


第四章:第 4 步 —— Framework:设立“挂号窗口”

📖 定义对外接口(AIDL)

frameworks/base/core/java/android/os/IThermalService.aidl

interface IThermalService { float getCpuTemperature(); }

👩‍💼 在 ContextImpl 中注册窗口

ContextImpl.java

registerService(Context.THERMAL_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { IBinder b = ServiceManager.getService("thermal"); return IThermalService.Stub.asInterface(b); } });

🏷️ 声明服务常量

Context.java

public static final String THERMAL_SERVICE = "thermal";

✅ 现在,App 或 SystemUI 可以通过getSystemService(Context.THERMAL_SERVICE)获取窗口!


第五章:第 5 步 —— SystemUI:安装“电子体温牌”(状态栏)

这才是最精彩的部分!如何把数据画到状态栏?

🔧 步骤 1:创建温度监控器(TemperatureController)

frameworks/base/packages/SystemUI/src/com/android/systemui/thermal/TemperatureController.java

public class TemperatureController { private final IThermalService mService; private float mCurrentTemp = -1; private final List<Callback> mCallbacks = new ArrayList<>(); public TemperatureController(Context context) { mService = IThermalService.Stub.asInterface( ServiceManager.getService(Context.THERMAL_SERVICE) ); startMonitoring(); // 启动定时轮询 } private void startMonitoring() { Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { try { float temp = mService.getCpuTemperature(); if (temp != mCurrentTemp) { mCurrentTemp = temp; notifyChange(); // 通知 UI 更新 } } catch (Exception e) { Log.w("TemperatureController", "读取温度失败", e); } }, 0, 2, TimeUnit.SECONDS); // 每 2 秒查一次 } public void addCallback(Callback cb) { mCallbacks.add(cb); } private void notifyChange() { for (Callback cb : mCallbacks) cb.onTemperatureChanged(mCurrentTemp); } public interface Callback { void onTemperatureChanged(float celsius); } }

💡 为什么用轮询而不是监听?
因为 Kernel不会主动通知温度变化!只能定期查。


🖼️ 步骤 2:创建状态栏图标(TemperatureIcon)

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/TemperatureIcon.java

public class TemperatureIcon extends StatusBarIconView { private TextView mTextView; public TemperatureIcon(Context context) { super(context, null, 0); mTextView = new TextView(context); mTextView.setTextSize(12); mTextView.setTextColor(Color.WHITE); addView(mTextView); } public void updateTemperature(float celsius) { if (celsius > 0) { mTextView.setText(String.format("CPU: %.0f°C", celsius)); setVisibility(VISIBLE); } else { setVisibility(GONE); } } }

🔌 步骤 3:把图标插入状态栏

修改StatusBar.java(简化版):

// 在 makeStatusBarView() 中 TemperatureIcon tempIcon = new TemperatureIcon(mContext); statusBar.addView(tempIcon); // 绑定控制器 TemperatureController controller = Dependency.get(TemperatureController.class); controller.addCallback(temp -> tempIcon.updateTemperature(temp));

✅ 注意:实际需通过Dependency注入或SysUIComponent初始化,此处简化。


第六章:权限与 SELinux(别让安全机制拦住你!)

🔒 1. 添加系统权限(可选)

若仅 SystemUI 使用,无需额外权限。
若 App 也要用,需在AndroidManifest.xml声明:

<uses-permission android:name="android.permission.ACCESS_THERMAL_DATA" />

并在platform.xml授权。

🔐 2. SELinux 放行 HAL 访问 sysfs

device/<vendor>/sepolicy/vendor/file_contexts

/sys/class/thermal/thermal_zone[0-9]+/temp u:object_r:sysfs_thermal:s0

thermal_hal.te

allow thermal_hal sysfs_thermal:file read;

✅ 否则 HAL 会因权限拒绝而返回 -1!


第七章:编译、刷机、验证

🛠️ 编译命令

source build/envsetup.sh lunch aosp_arm64-userdebug make -j$(nproc) SystemUI services thermal-hal

🔍 验证步骤

  1. 启动模拟器或真机
  2. 查看日志:
    adb logcat | grep -E "(Thermal|Temperature)"
  3. 观察状态栏右上角是否出现CPU: 42°C
  4. adb shell cat /sys/class/thermal/.../temp对比数值

💡 若模拟器无 thermal 数据,可用脚本模拟:

echo 50000 > /sys/class/thermal/thermal_zone0/temp

第八章:优化建议(从能用到好用)

问题优化方案
轮询耗电改用inotify监听 sysfs 文件变化(需 native 支持)
温度跳变加滑动平均滤波(如取最近 3 次平均值)
高温告警当 > 60°C 时变红闪烁
多核支持读取所有thermal_zone*取最高值

总结:数据流动的三大艺术

  1. 采集艺术(Kernel → HAL)
    → 用 sysfs 暴露硬件数据,HAL 封装读取逻辑。

  2. 服务艺术(HAL → SystemService → Framework)
    → 通过 HIDL + Binder 构建安全、跨进程的数据通道。

  3. 呈现艺术(Framework → SystemUI)
    → 用 Controller + Callback 解耦数据与 UI,实现响应式更新。

✅ 这套模式不仅适用于温度,还可用于:

  • 电池健康度
  • 网络信号强度
  • 自定义传感器数据
  • 系统负载(CPU 使用率)

🌈 结语:你已掌握 AOSP 数据流动的“任督二脉”

从前,你看到 SystemUI 里全是onXXX()updateState(),觉得“没人调用”。
现在,你知道:

每一个回调,都是数据流经的驿站;
每一个监听,都是系统在等待下一次心跳。

当你能在状态栏显示 CPU 温度,
你就真正理解了:
AOSP 不是代码的堆砌,而是数据的生命之河。


下一篇预告
《AOSP 客制化内功心法(六):
从零实现“勿扰模式快捷开关”——深入 Settings 与 Notification Manager 的联动机制》

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/23 2:54:24

CUDA安装后无法识别?教你正确配置Miniconda中的PyTorch环境

CUDA安装后无法识别&#xff1f;教你正确配置Miniconda中的PyTorch环境 在深度学习项目开发中&#xff0c;你是否曾遇到这样的尴尬场景&#xff1a;明明已经装好了NVIDIA驱动和CUDA Toolkit&#xff0c;系统里nvidia-smi也能正常输出&#xff0c;但一运行Python代码&#xff0c…

作者头像 李华
网站建设 2026/3/25 11:35:59

Python安装完成后未生效?Miniconda-Python3.10刷新PATH路径方法

Python安装完成后未生效&#xff1f;Miniconda-Python3.10刷新PATH路径方法 在人工智能和数据科学项目中&#xff0c;一个常见的“低级但致命”的问题往往是&#xff1a;明明已经安装了 Miniconda 和 Python 3.10&#xff0c;可终端里敲 python 还是提示“命令未找到”。这种看…

作者头像 李华
网站建设 2026/3/25 3:17:44

HTML语义化标签应用:Miniconda-Python3.10提升SEO友好度

HTML语义化标签与Miniconda-Python3.10&#xff1a;构建可复现、高可见的技术内容体系 在人工智能和数据科学项目日益复杂化的今天&#xff0c;一个常被忽视的问题浮出水面&#xff1a;我们能否确保别人不仅“能运行代码”&#xff0c;还能“轻松找到并理解它”&#xff1f;这…

作者头像 李华
网站建设 2026/3/13 10:01:41

Anaconda下载缓慢?改用Miniconda-Python3.10镜像极速体验

Miniconda-Python3.10 镜像&#xff1a;告别 Anaconda 下载慢&#xff0c;开启轻量高效开发 在数据科学和人工智能项目中&#xff0c;你是否曾经历过这样的场景&#xff1a;深夜赶工搭建实验环境&#xff0c;打开浏览器点击 Anaconda 安装包下载链接&#xff0c;进度条却以“每…

作者头像 李华
网站建设 2026/3/24 12:09:46

[HNCTF 2022 WEEK3]CM2

得到文件看起来是一个安装程序粗略的查看一下没什么东西&#xff0c;应该就是正常的安装执行安装主程序随便输测试一下IDA 分析主函数里没找到相关信息查找字符串引用一下上面有两条获取输入的函数&#xff0c;分别赋给 v2&#xff0c;v3有一条判断 v2 ! admin查看验证 v3 的函…

作者头像 李华
网站建设 2026/3/18 11:38:16

Anaconda图形界面劣势:Miniconda命令行更适合服务器部署

Anaconda图形界面劣势&#xff1a;Miniconda命令行更适合服务器部署 在高性能计算集群、云服务器或远程科研环境中&#xff0c;你是否遇到过这样的场景&#xff1f;团队成员提交的训练脚本因为“包版本不一致”而失败&#xff1b;新同事花了整整两天才配好能跑通代码的环境&…

作者头像 李华