news 2026/4/15 22:20:21

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/4/16 9:23:01

MDK AC5,AC6,GCC以及IAR在const局部变量存储位置的异同

这个是在RTX5全家桶源码升级时遇到的&#xff0c;给大家分享下&#xff0c;基本上已经升级完毕测试完毕了&#xff0c;且支持MDK6&#xff0c;这几天录制视频分享直接说结论 1、一般情况下&#xff0c;const修饰后基本都是存到Flash里面的&#xff0c;全局变量或者静态局部变量…

作者头像 李华
网站建设 2026/4/16 9:24:59

C#之App.Config文件操作

C#之App.Config文件操作/// <summary>/// 操作配置文件(App.config)/// </summary>public class CommonConfig{/// <summary>/// 输入Key的值&#xff0c;返回配置的值/// </summary>/// <param name"KeyName"></param>/// <…

作者头像 李华
网站建设 2026/4/16 9:25:07

项目管理中最大的浪费是什么?

项目管理里最大的浪费&#xff1f;不是人不够&#xff0c;也不是钱不够&#xff0c;是信息流断了。你想想&#xff0c;需求在Word里&#xff0c;任务在Jira里&#xff0c;测试用例在另一个Excel里&#xff0c;代码在Git里。任何一个地方改了点东西&#xff0c;其他所有地方都得…

作者头像 李华
网站建设 2026/4/16 9:19:42

企业自动化升级必看:Agentic AI如何重构软件工程与业务效率?

传统自动化VS Agentic AI&#xff1a;企业该押注稳定&#xff0c;还是拥抱智能革命&#xff1f;Agentic AI爆火&#xff1a;传统自动化会被淘汰吗&#xff1f;企业战略选型指南企业自动化升级必看&#xff1a;Agentic AI如何重构软件工程与业务效率&#xff1f;从被动执行到主动…

作者头像 李华
网站建设 2026/4/16 9:21:26

DeepSeek+Ollama+AnythingLLM:打造你的专属AI知识管家,一键收藏!

本文详细介绍了使用DeepSeek、Ollama和AnythingLLM搭建本地AI知识库的完整流程&#xff0c;包括软件安装、模型配置、文档上传和使用方法。文章强调了本地部署保护隐私的优势&#xff0c;并针对不同文档类型和嵌入模型配置提供了实用建议。通过这套方案&#xff0c;用户可在电脑…

作者头像 李华
网站建设 2026/4/16 10:16:59

2025最新rag综述——RAG工业界大规模落地

在这篇 2025 年最新的 RAG 综述中&#xff0c;研究者系统梳理了过去一年的技术进展&#xff0c;提出了新的分析视角&#xff0c;并探讨了未来的发展趋势。本系列文章对其进行了解读和日常案例挖掘。 在这篇文章里&#xff0c;我们结合吴恩达最新 RAG 教程&#xff0c;聚焦一个更…

作者头像 李华