news 2026/1/3 3:40:25

【Android FrameWork】第三十六天:随机数EntropyMixer

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Android FrameWork】第三十六天:随机数EntropyMixer

Android EntropyService

在 Android 系统中,EntropyService(后更名为 EntropyMixer)是保障随机数安全性的核心服务之一。

它通过维护内核熵池(Entropy Pool),解决了系统启动初期随机数可预测的问题,为加密、安全认证等场景提供高质量随机数。

本文将从Framework 层(Java 实现)C++ 层(Native 依赖)深入解析其源码逻辑。

什么是熵池?

Linux 内核维护一个熵池(内存中的随机数据池),收集硬件中断、设备噪声等不可预测的“熵源”,生成/dev/random(阻塞式,熵不足时等待)和/dev/urandom(非阻塞式,熵不足时复用已有数据)设备文件。

但系统启动初期,熵池为空,直接生成的随机数易被预测。EntropyService 的核心作用:通过持久化熵数据、补充设备信息,确保熵池始终有足够的“随机性”。

Framework 层实现

1 服务注册:SystemServer 中启动

EntropyService 是 SystemServer 启动的核心服务之一,在SystemServer.javastartOtherServices()方法中注册:

// frameworks/base/services/java/com/android/server/SystemServer.javaServiceManager.addService("entropy",newEntropyMixer(context));

2 构造函数:核心逻辑入口

EntropyMixer的构造函数定义了服务的核心参数和初始化流程:

// frameworks/base/services/core/java/com/android/server/EntropyMixer.javapublicEntropyMixer(Contextcontext){// 默认参数:熵数据文件、随机设备、硬件随机设备this(context,getSystemDir()+"/entropy.dat","/dev/urandom","/dev/hw_random");}publicEntropyMixer(Contextcontext,StringentropyFile,StringrandomDevice,StringhwRandomDevice){this.randomDevice=randomDevice;// 对应 /dev/urandomthis.hwRandomDevice=hwRandomDevice;// 硬件随机源(如 /dev/hw_random)this.entropyFile=entropyFile;// 持久化熵数据的文件:/data/system/entropy.dat// 核心初始化流程loadInitialEntropy();// 1. 加载历史熵数据到熵池addDeviceSpecificEntropy();// 2. 补充设备信息到熵池addHwRandomEntropy();// 3. 补充硬件随机源到熵池writeEntropy();// 4. 持久化当前熵池数据scheduleEntropyWriter();// 5. 定时更新熵数据registerShutdownReceiver();// 6. 注册关机/重启广播,触发持久化}

3 核心方法解析

(1)loadInitialEntropy():加载历史熵数据

系统启动时,将/data/system/entropy.dat中的历史熵数据写入/dev/urandom,填充空熵池:

privatevoidloadInitialEntropy(){try{// 将文件数据写入随机设备RandomBlock.fromFile(entropyFile).toFile(randomDevice,false);Slog.i(TAG,"Loaded initial entropy from "+entropyFile);}catch(IOExceptione){Slog.w(TAG,"Failed to load initial entropy",e);}}
(2)addDeviceSpecificEntropy():补充设备信息

向熵池写入设备唯一信息(如序列号、硬件型号等),增加随机性:

privatevoidaddDeviceSpecificEntropy(){try(BufferedWriterout=newBufferedWriter(newOutputStreamWriter(newFileOutputStream(randomDevice)))){// 写入固定字符串、启动时间、设备属性等out.write("All Your Randomness Are Belong To Us\n");out.write(System.currentTimeMillis()+"\n");out.write(System.nanoTime()+"\n");out.write(SystemProperties.get("ro.serialno")+"\n");out.write(SystemProperties.get("ro.hardware")+"\n");// ... 其他设备属性out.flush();}catch(IOExceptione){Slog.w(TAG,"Failed to add device entropy",e);}}
(3)addHwRandomEntropy():补充硬件随机源

若设备支持硬件随机数生成器(如/dev/hw_random),将其数据写入熵池:

privatevoidaddHwRandomEntropy(){try{RandomBlock.fromFile(hwRandomDevice).toFile(randomDevice,false);Slog.i(TAG,"Added HW RNG output to entropy pool");}catch(FileNotFoundExceptionignored){// 无硬件随机源时忽略}catch(IOExceptione){Slog.w(TAG,"Failed to add HW RNG entropy",e);}}
(4)writeEntropy()scheduleEntropyWriter():持久化与定时更新
  • writeEntropy():读取/dev/urandom的数据,写入entropy.dat持久化;
  • scheduleEntropyWriter():通过 Handler 每 3 小时触发一次持久化:
privatevoidwriteEntropy(){try{RandomBlock.fromFile(randomDevice).toFile(entropyFile,true);Slog.i(TAG,"Wrote entropy to "+entropyFile);}catch(IOExceptione){Slog.w(TAG,"Failed to write entropy",e);}}privatevoidscheduleEntropyWriter(){mHandler.removeMessages(ENTROPY_WHAT);// 3小时后触发mHandler.sendEmptyMessageDelayed(ENTROPY_WHAT,3*60*60*1000);}privatefinalHandlermHandler=newHandler(){@OverridepublicvoidhandleMessage(Messagemsg){if(msg.what==ENTROPY_WHAT){addHwRandomEntropy();writeEntropy();scheduleEntropyWriter();// 循环定时}}};

C++ 层依赖

EntropyService 本身是 Java 实现,但依赖Linux 内核的随机数设备Native 层的文件操作(通过 JNI 调用)。

1 内核随机数设备:/dev/random/dev/urandom

这两个设备由 Linux 内核的random.c实现(位于kernel/drivers/char/random.c),核心逻辑:

  • 收集“熵源”(如中断时间、磁盘 I/O 延迟)到熵池;
  • 提供read()接口(/dev/random阻塞,/dev/urandom非阻塞);
  • EntropyService 本质是通过读写这些设备文件与内核熵池交互。

2 Native 层文件操作:RandomBlock 的底层实现

RandomBlock是 EntropyMixer 中封装的文件操作工具类,其底层通过JNI 调用 C++ 的文件读写函数(如open()read()write()),避免 Java I/O 的性能开销。

例如,RandomBlock.fromFile()的 Native 实现逻辑(简化):

// 伪代码:Native 层文件读取jbyteArrayRandomBlock_nativeRead(JNIEnv*env,jclass clazz,jstring path){constchar*cPath=env->GetStringUTFChars(path,nullptr);intfd=open(cPath,O_RDONLY);if(fd<0){/* 错误处理 */}charbuffer[4096];ssize_t n=read(fd,buffer,sizeof(buffer));close(fd);env->ReleaseStringUTFChars(path,cPath);jbyteArray result=env->NewByteArray(n);env->SetByteArrayRegion(result,0,n,(jbyte*)buffer);returnresult;}

3 硬件随机源的 Native 驱动

若设备支持/dev/hw_random,其驱动由硬件厂商用 C 实现(位于kernel/drivers/char/hw_random/),核心是向内核熵池注入硬件生成的随机数据:

// 硬件随机源驱动伪代码staticvoidhw_rng_fill_entropy(structhw_rng*rng){u8 buffer[256];intn=rng->read(rng,buffer,sizeof(buffer));// 硬件读取随机数if(n>0){add_entropy_to_pool(buffer,n);// 注入内核熵池}}

核心方法调用

以下是从系统启动服务运行/终止的全流程方法调用时序:

阶段1:系统启动 → EntropyMixer初始化

1. `SystemServer.startOtherServices()` ↓ 调用 2. `EntropyMixer.<init>(Context)` ↓ 构造函数内依次触发 3. `loadInitialEntropy()` (加载`entropy.dat`到熵池) ↓ 完成后 4. `addDeviceSpecificEntropy()` (补充设备信息到熵池) ↓ 完成后 5. `addHwRandomEntropy()` (补充硬件随机源到熵池) ↓ 完成后 6. `writeEntropy()` (首次持久化当前熵池到`entropy.dat`) ↓ 完成后 7. `scheduleEntropyWriter()` (启动3小时周期的定时任务) ↓ 完成后 8. `registerShutdownReceiver()` (注册关机/重启广播接收器)

阶段2:定时任务执行(每3小时)

1. `mHandler`接收`ENTROPY_WHAT`消息 ↓ 处理消息时触发 2. `addHwRandomEntropy()` (再次补充硬件随机源) ↓ 完成后 3. `writeEntropy()` (更新持久化的`entropy.dat`) ↓ 完成后 4. `scheduleEntropyWriter()` (重新调度下一次定时任务)

阶段3:系统关机/重启

1. 系统发送关机/重启广播 ↓ 广播接收器触发 2. `writeEntropy()` (最后一次持久化熵池数据)

从应用到内核熵池的全链路解析

当 Android 系统应用需要生成随机数(如加密密钥、安全令牌)时,并非直接“创造”随机数据,而是通过多层组件协作,最终从内核熵池获取高质量随机数。

应用层:随机数的“入口”API

Android 应用层生成随机数的常用方式有两种:Java 标准库 API 和 Android 系统 API,两者最终都会关联到内核熵池。

1 Java 标准库:java.security.SecureRandom

这是应用层最常用的安全随机数生成器,默认绑定系统熵池

// 应用层代码示例SecureRandomsecureRandom=newSecureRandom();byte[]randomBytes=newbyte[16];// 生成16字节(128位)随机数secureRandom.nextBytes(randomBytes);
2 Android 系统 API:android.os.Build.VERSION.SDK_INT >= 26新增的StrongBox

针对高安全场景(如密钥存储),Android 9+ 提供StrongBox,底层直接调用硬件/内核级随机源:

// 应用层代码示例(需硬件支持)KeyGeneratorkeyGen=KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,"AndroidKeyStore");keyGen.init(newKeyGenParameterSpec.Builder("my_key",KeyProperties.PURPOSE_ENCRYPT|KeyProperties.PURPOSE_DECRYPT).setIsStrongBoxBacked(true)// 强制使用StrongBox.build());SecretKeykey=keyGen.generateKey();// 密钥随机数来自StrongBox关联的熵池

Framework 层

应用层调用的随机数 API,会先进入 Android Framework 层的安全框架,完成策略校验、熵源绑定等逻辑。

1SecureRandom的 Framework 层实现

SecureRandom的实际逻辑由sun.security.provider.SecureRandom(JDK 底层)和 Android 定制的android.security.SecureRandom共同实现:

  • 第一步SecureRandom初始化时,会加载随机数算法(如SHA1PRNG);
  • 第二步:算法初始化需要“种子”(Seed),而种子默认从系统熵池获取(通过/dev/urandom)。

Framework 层对SecureRandom的增强:

// Android 定制的 SecureRandom 逻辑(简化)publicclassSecureRandomextendsjava.security.SecureRandom{@OverrideprotectedvoidengineSetSeed(byte[]seed){// 强制将种子补充到内核熵池,避免弱种子NativeCrypto.RAND_seed(seed);super.engineSetSeed(seed);}}
2 Framework 到 Native 层的过渡:JNI 调用

Framework 层的随机数逻辑,通过JNI(Java Native Interface)调用 Native 层的 OpenSSL/系统库,最终关联到内核设备文件。

例如,SecureRandomnextBytes()会触发 JNI 调用:

// Framework 层 SecureRandom 的 JNI 绑定privatenativevoidnextBytes(byte[]bytes);

对应的 Native 实现(位于libandroid_runtime.so):

// Native 层代码(简化)staticvoidSecureRandom_nextBytes(JNIEnv*env,jobject obj,jbyteArray bytes){jbyte*buf=env->GetByteArrayElements(bytes,nullptr);intlen=env->GetArrayLength(bytes);// 调用 OpenSSL 的 RAND_bytes,而 RAND_bytes 会读取 /dev/urandomif(RAND_bytes((unsignedchar*)buf,len)!=1){env->ThrowNew(env->FindClass("java/security/NoSuchAlgorithmException"),"RAND_bytes failed");}env->ReleaseByteArrayElements(bytes,buf,0);}

Native 层

Native 层通过系统库(如 OpenSSL、Bionic libc)直接操作内核提供的随机数设备文件(/dev/random//dev/urandom),是连接 Framework 与内核的关键层。

1 OpenSSL 的 RAND 模块

Android 系统中的 OpenSSL 被定制为默认从/dev/urandom获取随机数:

// OpenSSL RAND 模块的实现(简化)intRAND_bytes(unsignedchar*buf,intnum){intfd=open("/dev/urandom",O_RDONLY);if(fd<0)return0;ssize_t n=read(fd,buf,num);// 从内核熵池读数据close(fd);return(n==num)?1:0;}

2 Bionic libc 的getrandom()系统调用

Android 5.0+ 支持getrandom()系统调用(替代直接读写设备文件),它直接从内核熵池获取数据:

// Native 层使用 getrandom() 的示例#include<sys/random.h>ssize_tgetrandom(void*buf,size_t buflen,unsignedintflags);// 调用示例charrandom_buf[16];getrandom(random_buf,sizeof(random_buf),0);// 直接从内核熵池读

内核层

所有随机数的最终来源是Linux 内核的熵池,由kernel/drivers/char/random.c实现,负责收集“熵源”并生成随机数据。

1 熵池的构成

内核熵池是一个256字节的内存池,通过收集以下“不可预测”的熵源填充:

  • 硬件中断的时间差;
  • 磁盘/网络 I/O 的延迟;
  • 键盘输入、触摸屏操作的时间;
  • EntropyService(EntropyMixer)补充的持久化数据、设备信息、硬件随机源。

2/dev/urandom/dev/random的区别

  • /dev/urandom:非阻塞,当熵池不足时,复用已有数据并通过加密算法增强随机性(Android 应用默认使用);
  • /dev/random:阻塞,直到熵池有足够新熵源(仅用于极高安全场景)。

3 EntropyService 对内核熵池的作用

如前文所述,EntropyService 会在系统启动时加载历史熵数据补充设备/硬件熵源,确保内核熵池在启动初期就有足够的随机性,避免应用层获取弱随机数。

全链路总结

应用层代码 ↓ 调用 Framework 层(SecureRandom / StrongBox) ↓ JNI 调用 Native 层(OpenSSL / getrandom()) ↓ 系统调用 / 文件读写 内核层(/dev/urandom → 熵池) ↓ 读取熵池数据 返回随机数到应用层

总结

  1. 系统启动:EntropyMixer 从entropy.dat加载历史熵数据,填充内核熵池;
  2. 补充熵源:写入设备信息、硬件随机数据,增强随机性;
  3. 持久化:将当前熵池数据写入entropy.dat,并每 3 小时更新;
  4. 关机/重启:通过广播触发持久化,确保下次启动时有足够熵数据。

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

介观交通流仿真软件:VISSIM (介观模式)_(9).公交系统仿真

公交系统仿真 在城市交通中&#xff0c;公交系统是重要的组成部分&#xff0c;其运行效率直接影响城市的整体交通状况。介观交通流仿真软件VISSIM提供了丰富的功能来模拟公交系统的运行&#xff0c;包括公交线路的设置、公交车辆的动态行为、公交优先策略的实施等。本节将详细介…

作者头像 李华
网站建设 2025/12/28 12:28:59

django基于Python员工管理系统设计开发实现

背景与意义 技术背景 Django是一个基于Python的高级Web框架&#xff0c;采用MTV&#xff08;Model-Template-View&#xff09;设计模式&#xff0c;内置ORM、表单处理和用户认证等功能。Python因其简洁语法和丰富的库生态&#xff08;如Pandas、NumPy&#xff09;&#xff0c…

作者头像 李华
网站建设 2025/12/19 7:23:05

基于django协同过滤算法的音乐推荐播放器设计开发实现

背景与意义音乐推荐系统在数字化时代扮演着重要角色&#xff0c;用户面对海量音乐内容时&#xff0c;个性化推荐能有效提升体验。协同过滤算法作为推荐系统的核心技术之一&#xff0c;通过分析用户行为数据&#xff08;如播放记录、评分&#xff09;挖掘相似用户或物品的关联性…

作者头像 李华
网站建设 2025/12/25 1:35:40

智慧公路边坡灾害监测 山体滑坡监测数据集 地质灾害AI解决方案 滑坡和落石灾害识别 自然灾害监测图像数据集 改进yolo第10312期

滑坡数据集数据集核心信息表信息类别具体内容数据集类别目标监测&#xff1b;包含 1个核心标注类别&#xff1a;、landslide&#xff08;英文&#xff09;、滑坡&#xff08;中文&#xff09;数据数量总计 6709 张图像数据集格式种类计算机视觉任务通用格式&#xff08;支持实例…

作者头像 李华
网站建设 2025/12/22 3:14:29

7.3 模型评估方法论:训练集、验证集、测试集划分策略

7.3 模型评估方法论:训练集、验证集、测试集划分策略 模型评估是机器学习工作流程中的关键环节,其目的是客观、准确地估计一个模型在未知数据上的泛化性能。一个严谨的评估方法论的核心在于数据集的划分策略,其根本目标是模拟模型部署后面对全新数据时的表现,并防止因信息…

作者头像 李华