安卓StorageManagerService

在Android系统的存储管理体系中,StorageManagerService(简称SMS)是核心中枢组件,承担着设备存储全生命周期的管理职责。它作为连接应用层、Framework层与底层存储硬件的重要桥梁,统一管控设备的所有存储资源,包括内部存储、外部SD卡、USB存储设备等,为系统组件和应用提供标准化的存储操作接口,并实现存储安全、存储优化等高级特性。

StorageManagerService采用分层架构设计,各层级职责清晰:

1、应用API接口层 :以StorageManager类为核心,为应用提供存储访问的入口,封装了与StorageManagerService的跨进程通信逻辑。

2、Framework服务层 :StorageManagerService的核心实现层,负责存储管理的业务逻辑处理,与系统其他服务进行交互。

3、底层支撑层 :依赖Vold服务完成存储设备的底层操作,Vold服务通过NetlinkManager与内核进行通信,处理存储设备的硬件事件。


StorageManagerService属于系统服务,启动流程如下:

在SystemServer启动其他服务阶段(startOtherServices()),通过SystemServiceManager启动StorageManagerService。

复制代码
// frameworks/base/services/java/com/android/server/SystemServer.java
private static final String STORAGE_MANAGER_SERVICE_CLASS =
            "com.android.server.StorageManagerService$Lifecycle";
private void startOtherServices() {
    // 省略其他服务启动
    traceBeginAndSlog("StartStorageManagerService");
    try {
        // 启动StorageManagerService
        mSystemServiceManager.startService(STORAGE_MANAGER_SERVICE_CLASS);
        // 获取服务Binder引用
        IStorageManager storageManager = IStorageManager.Stub.asInterface(
                ServiceManager.getService("mount"));
    } catch (Throwable e) {
        reportWtf("starting StorageManagerService", e);
    }
    traceEnd();
}

1、onStart() :初始化StorageManagerService;发布Binder服务,将服务注册到ServiceManager中,服务名为"mount"。调用StorageManagerService.start启动,连接storaged和vold服务,获取binder对象,并注册IVoldListener监听。

复制代码
public void onStart() {
	mStorageManagerService = new StorageManagerService(getContext());
	publishBinderService("mount", mStorageManagerService);
	mStorageManagerService.start();
}

//StorageManagerService.java
private void start() {
	connectStoraged();
	connectVold();
}

storaged服务:‌**storaged 是 Android 系统中用于收集和发布存储相关指标的原生守护进程(daemon)**‌,自 Android 8(Oreo)起引入,主要用于监控存储设备的使用情况、健康状态及 I/O 性能。主要功能有:

  • 磁盘统计信息采集 ‌:定期读取 /sys/block/mmcblk0/stat(eMMC 设备)或 /sys/block/sda/stat(非 eMMC 设备)获取磁盘读写统计。
  • eMMC 生命周期监控 ‌:通过解析 /d/mmc0/mmc0:001/ext_csd 获取 eMMC 的剩余寿命和磨损情况。
  • 应用级 I/O 归因 ‌:遍历 /proc/uid_io/stats,记录每个 UID(应用)的前台/后台读写字节数、字符数、同步操作等,用于识别高 I/O 应用。
  • 错误报告支持 ‌:可通过 dumpsys 调用,在系统错误报告中包含详细的 I/O 使用数据。

vold服务在《安卓vold服务》一篇中已介绍,本文不加赘述。

2、StorageManagerService 构造初始化:创建各种处理器和控制器、初始化文件系统和维护记录、读取配置设置、注册广播接收器、添加内部存储卷。

复制代码
 // 创建并启动专用的HandlerThread用于处理存储管理任务
HandlerThread hthread = new HandlerThread(TAG);
hthread.start();

// 创建主服务处理器,关联到HandlerThread的Looper  包括volume挂载、volume卸载等处理
mHandler = new StorageManagerServiceHandler(hthread.getLooper());

// 创建OBB(Opaque Binary Blob)操作处理器,使用IO线程的Looper
mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());

// 初始化存储会话控制器
mStorageSessionController = new StorageSessionController(mContext);

// 创建安装器服务并启动
mInstaller = new Installer(mContext);
mInstaller.onStart();

// 初始化存储设置文件(原子文件操作,保证数据一致性)
mSettingsFile = new AtomicFile(
		new File(Environment.getDataSystemDirectory(), "storage.xml"), "storage-settings");

// 初始化写记录文件
mWriteRecordFile = new AtomicFile(
		new File(Environment.getDataSystemDirectory(), "storage-write-records"));
			
			
// 读取存储设置
synchronized (mLock) {
	readSettingsLocked();
}

// 将存储管理内部服务添加到本地服务管理器
LocalServices.addService(StorageManagerInternal.class, mStorageManagerInternal);

// 注册用户相关的广播接收器(用户添加/移除)
final IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_ADDED);
userFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);

// 添加内部存储卷
synchronized (mLock) {
	addInternalVolumeLocked();
}

// 如果启用了看门狗监控,将当前服务添加到监控列表
if (WATCHDOG_ENABLE) {
	Watchdog.getInstance().addMonitor(this);
}

3、onBootPhase:在系统启动的不同阶段执行特定逻辑

复制代码
public void onBootPhase(int phase) {
	if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
        //核心系统服务已启动
		mStorageManagerService.servicesReady();
	} else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
        //ActivityManagerService 准备就绪
		mStorageManagerService.systemReady();
	} else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
        //系统启动完成,Home 应用已启动
		mStorageManagerService.bootCompleted();
	}
}

4、servicesReady():核心系统服务就绪后,获取包管理和AppOps等关键系统服务的接口实例 ;查询并保存三个重要内容提供者的应用信息: MediaStore(媒体存储)、 Downloads(下载管理)、 ExternalStorage(外部存储文档管理);记录这些系统组件的App ID和进程名,用于后续的存储访问权限控制。

复制代码
// 从本地服务管理器获取包管理内部服务实例
mPmInternal = LocalServices.getService(PackageManagerInternal.class);

// 获取包管理服务的远程接口
mIPackageManager = IPackageManager.Stub.asInterface(
		ServiceManager.getService("package"));

// 获取AppOps服务的远程接口,用于应用操作权限管理
mIAppOpsService = IAppOpsService.Stub.asInterface(
		ServiceManager.getService(Context.APP_OPS_SERVICE));

// 获取MediaStore内容提供者的信息(媒体存储服务)
ProviderInfo provider = getProviderInfo(MediaStore.AUTHORITY);
if (provider != null) {
	// 从应用UID中提取App ID(去除用户ID部分)
	mMediaStoreAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
	// 保存MediaStore提供者的进程名称
	sMediaStoreAuthorityProcessName = provider.applicationInfo.processName;
}

// 获取下载内容提供者的信息
provider = getProviderInfo(Downloads.Impl.AUTHORITY);
if (provider != null) {
	// 保存下载提供者的App ID
	mDownloadsAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
}

// 获取外部存储内容提供者的信息(文档存储服务)
provider = getProviderInfo(DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY);
if (provider != null) {
	// 保存外部存储提供者的App ID
	mExternalStorageAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
}

5、 systemReady():系统服务就绪后,调度智能维护任务、fstrim操作;刷新ZRAM设置, 调度ZRAM写回任务,将ZRAM中的冷数据写回到存储设备(如果支持)。

复制代码
// 准备智能空闲维护,如果准备成功则开始调度智能维护任务
if (prepareSmartIdleMaint()) {
	// 按照指定的智能维护周期调度智能空闲维护任务
	SmartStorageMaintIdler.scheduleSmartIdlePass(mContext, sSmartIdleMaintPeriod);
}

// 开始调度名义上每日执行的fstrim(文件系统整理)操作
// fstrim用于优化SSD性能,回收未使用的块
MountServiceIdler.scheduleIdlePass(mContext);

// 刷新ZRAM设置,确保系统启动时应用当前设置
refreshZramSettings();

String zramPropValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY);
// 检查ZRAM是否启用且系统配置支持ZRAM写回功能
if (!zramPropValue.equals("0")  // ZRAM未禁用("0"表示禁用)
		&& mContext.getResources().getBoolean(
			com.android.internal.R.bool.config_zramWriteback)) {  // 系统配置允许ZRAM写回
	// 调度ZRAM写回任务,将ZRAM中的冷数据写回到存储设备
	ZramWriteback.scheduleZramWriteback(mContext);
}

// 配置媒体文件转码功能
configureTranscoding();

6、bootCompleted():开机完成后,备份当前系统解锁用户信息、清空磁盘和卷的缓存数据、重启vold守护进程到初始状态、重新注册所有用户信息并恢复解锁状态、通知相关服务重置完成。

复制代码
// 获取用户管理器服务实例
final UserManager userManager = mContext.getSystemService(UserManager.class);
// 获取系统中所有用户的信息列表
final List<UserInfo> users = userManager.getUsers();

// 通知存储会话控制器执行重置操作
mStorageSessionController.onReset(mVold, () -> {
	// 重置完成后移除Handler中的所有回调和消息
	mHandler.removeCallbacksAndMessages(null);
});

// 创建系统已解锁用户数组的副本(防止排序改变原始顺序)
	systemUnlockedUsers = Arrays.copyOf(mSystemUnlockedUsers,
			mSystemUnlockedUsers.length);

// 清空磁盘和卷的缓存信息
mDisks.clear();
mVolumes.clear();

// 重新添加内部存储卷(系统基础卷)
addInternalVolumeLocked();
		
// 重置vold守护进程,清理现有的磁盘/卷信息,从干净状态重新开始
// 注意:已经解锁的用户存储将保持解锁状态,不受重置影响
//
// TODO(b/135341433): 当FUSE稳定后移除谨慎的日志记录
mVold.reset();  // 执行vold重置

// 通知vold所有已存在和已启动的用户信息
for (UserInfo user : users) {
	if (user.isCloneProfile()) {
		// 如果是克隆配置文件,传递用户组ID
		mVold.onUserAdded(user.id, user.serialNumber, user.profileGroupId);
	} else {
		// 普通用户,用户组ID设为-1
		mVold.onUserAdded(user.id, user.serialNumber, -1);
	}
}
        
// 通知vold所有系统已解锁的用户已启动
for (int userId : systemUnlockedUsers) {
	mVold.onUserStarted(userId);      // 通知vold用户启动
	mStoraged.onUserStarted(userId);  // 通知storaged用户启动
}

// 恢复系统解锁用户的存储状态
restoreSystemUnlockedUsers(userManager, users, systemUnlockedUsers);

// 更新安全锁屏状态给vold
mVold.onSecureKeyguardStateChanged(mSecureKeyguardShowing);

// 通知存储管理内部服务重置完成
mStorageManagerInternal.onReset(mVold);

与Vold服务交互 :StorageManagerService作为客户端,通过Binder机制与Vold服务进行通信,Vold服务负责处理存储设备的底层挂载、卸载等操作。

与StorageStatsService协作 :StorageStatsService负责存储统计数据的收集和计算,StorageManagerService通过调用其接口获取存储统计信息。

StorageStatsService核心功能:

  • 分区统计:计算内部存储、外部卷的总容量、已用空间、可用空间、缓存空间。 getTotalBytes() 、 getFreeBytes() 。
  • 应用统计:遍历 /data/data 、 /storage/emulated/0/Android/data ,统计每个应用的APK大小、数据大小、缓存大小、OBB文件大小、媒体占用。 queryStatsForPackage()
  • 订阅与实时更新:支持系统/设置订阅存储变化,定时扫描并回调,更新存储占用视图。
  • 垃圾文件扫描:识别残留APK、无效缓存、空目录、冗余媒体,为清理提供数据支撑。

与PackageManagerService交互 :在应用安装、卸载过程中,同步处理应用存储目录的创建、删除和权限配置。

与MediaStore协同 :管理媒体文件的索引和访问,确保媒体文件的存储和访问流程一致。


为了实现更灵活的权限管理,Android引入了FUSE(Filesystem in Userspace)文件系统:

  1. 用户空间实现 :FUSE的核心逻辑运行在用户空间,而非内核空间,使得存储权限控制可以更灵活地定制。
  2. 权限拦截 :在应用访问存储文件时,FUSE文件系统可以拦截访问请求,交由StorageManagerService进行权限验证,实现精细化的存储访问控制。

从Android 10开始,StorageManagerService是Scoped Storage(作用域存储)特性的核心实现者:

  1. 权限划分 :将存储访问权限划分为媒体文件访问、文档访问等不同维度,应用仅能访问自身沙盒目录和授权的外部文件。
  2. 权限验证 :在应用访问存储资源时,实时验证权限有效性,拦截未授权的访问请求。
  3. 权限动态调整 :支持应用在运行时申请存储权限,并处理权限授予或拒绝后的状态同步。
相关推荐
码王吴彦祖2 小时前
AI 逆向分析国航 AirChina FECU 参数来源并实现离线生成
android·java·javascript
LJianK12 小时前
进程、线程、多线程、异步
java·开发语言·jvm
黄林晴2 小时前
Compose 原生 FlexBox 正式上线,告别布局妥协
android
lKWO OMET2 小时前
图文详述:MySQL的下载、安装、配置、使用
android·mysql·adb
ch.ju2 小时前
Java程序设计(第3版)第二章——循环结构1
java
大黄烽2 小时前
IDEA中集成AI 工具CodeBuddy和Trae区别和选型
java·人工智能·intellij-idea
HalvmånEver2 小时前
MySQL表的约束(二)
java·数据库·mysql
hhkSUC8PD2 小时前
Laravel AI SDK 正式发布
android·人工智能·laravel
云烟成雨TD2 小时前
Spring AI Alibaba 1.x 系列【34】Human-in-the-Loop(人在回路)执行流程
java·人工智能·spring