【Android FrameWork】第三十六天:随机数EntropyMixer
2026/5/16 1:54:45 网站建设 项目流程

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. 关机/重启:通过广播触发持久化,确保下次启动时有足够熵数据。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询