android存储3--初始化.unlock事件的处理

news2024/11/14 13:43:36

android版本:android-11.0.0_r21
http://aospxref.com/android-11.0.0_r21

概述:收到unlock事件后,StorageSessionController、vold、storaged模块进行各自初始化操作。

一、StorageManagerService::onUnlockUser处理unlock事件

设备解锁后,loop线程处理unlock消息,最终会执行到存储的StorageManagerService$Lifecycle中的onUserUnlocking方法,整个流程如下:

loop() //android.os.Looper
|
|-->msg.target.dispatchMessage(msg) //android.os.Handler
   |
   |--mCallback.handleMessage(msg) //com.android.server.am.UserController
      |
      |--case USER_UNLOCK_MSG:
                mInjector.getSystemServiceManager().unlockUser(userId) //com.android.server.SystemServiceManager
                |
               ①|--onUser(UNLOCKING, userHandle) //com.android.server.SystemServiceManager
                  |
                 ②|--onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, userHandle) //com.android.server.SystemServiceManager 
                       |
                      ③|--onUser(t, onWhat, userHandle, UserHandle.USER_NULL) //com.android.server.SystemServiceManager
                          |
                          |--case UNLOCKING:
                                    service.onUserUnlocking(curUser) //com.android.server.SystemService
                                    |
                                    |--onUnlockUser(user.getUserInfo()) //com.android.server.SystemService
                                       |
                                       |--onUnlockUser(userInfo.id) //com.android.server.StorageManagerService$Lifecycle                         

1)loop线程处理Android消息队列中的消息和事件,从队列中获取事件,将unlock事件通知其他系统服务。

2)系统服务UserController管理用户和用户操作,接收到USER_UNLOCK_MSG消息后执行SystemServiceManager中的unlockUser方法。

3)unlockUser方法经过几次转换(①②③见下,只是做了参数转换。参数差异见下)。

SystemServiceManager::(final @UserIdInt int userHandle)
    --> onUser(@NonNull String onWhat, @UserIdInt int userHandle)  ①
        --> onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
                   @UserIdInt int userHandle)  ②
             ​​​​​​​-->onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
                   @UserIdInt int curUserId, @UserIdInt int prevUserId)  ③
(如果未写明方法所属class,默认所属class与前面相同,所以这些onUser方法都是SystemServiceManager类中实现的)

UserController收到USER_UNLOCK_MSG后的处理细节见其他文章。

最终③处的onUser会遍历mServices链表,执行各个service的 onUserUnlocking,简化后的代码如下:
http://aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/SystemServiceManager.java#onUser

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

private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
            @UserIdInt int curUserId, @UserIdInt int prevUserId) {

        final TargetUser curUser = new TargetUser(getUserInfo(curUserId));

        final int serviceLen = mServices.size();

        // 遍历系统服务,执行每个servie的onUserUnlocking方法
        for (int i = 0; i < serviceLen; i++) {
            final SystemService service = mServices.get(i);
            final String serviceName = service.getClass().getName();

            try {
                switch (onWhat) {
 
                    case UNLOCKING:
                        	service.onUserUnlocking(curUser);  // ④,存储的sevice是"StorageManagerService$Lifecycle"
                        break;
                     ……
                }
            } 
    }

《android存储2--初始化.存储service的启动》中“mount service”一节已经阐述了StorageManagerService$Lifecycle发布的流程,所以上面代码执行for循环时,SystemService service = mServices.get(i)将会获取到StorageManagerService$Lifecycle。在④处,service.onUserUnlocking(curUser)将会执行StorageManagerService$Lifecycle中的onUserUnlocking方法。

二、StorageManagerService中的onUserUnlocking

StorageManagerService中定义了静态内部类StorageManagerService$Lifecycle,这个内部类用来控制StorageManagerService的Lifecycle,代码见下:http://aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/StorageManagerService.java#246

public class StorageManagerService extends IStorageManager.Stub
        implements Watchdog.Monitor, ScreenObserver {

        public static class Lifecycle extends SystemService {
                protected StorageManagerService mStorageManagerService;

                @Override
                public void onUnlockUser(int userHandle) {
                    mStorageManagerService.onUnlockUser(userHandle);
                }
                ……
            }
}

从StorageManagerService$Lifecycle函数可知道:

  • Lifecycle继承自SystemService抽象类
  • ​​​​​​​子类Lifecycle覆写了父类SystemService的onUnlockUser方法,但没有覆写onUserUnlocking

上文④处service.onUserUnlocking(curUser)调用的是父类SystemService::onUserUnlocking方法(因为StorageManagerService$Lifecycle没有覆写onUserUnlocking),见下。

http://aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/SystemService.java#onUserUnlocking

// SystemService类中的实现

public void onUserUnlocking(@NonNull TargetUser user) {
    onUnlockUser(user.getUserInfo());
}

onUnlockUser(user.getUserInfo())执行SystemService::onUnlockUser(@NonNull UserInfo userInfo)方法(注意重载参数类型)。

http://aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/SystemService.java#onUnlockUser

// SystemService类中的实现

public void onUnlockUser(@NonNull UserInfo userInfo) {
    onUnlockUser(userInfo.id);
}

onUnlockUser(userInfo.id)执行的是被StorageManagerService$Lifecycle覆写后的方法:

http://aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/StorageManagerService.java#onUnlockUser

//StorageManagerService$Lifecycle类中的实现

@Override
public void onUnlockUser(int userHandle) {
    mStorageManagerService.onUnlockUser(userHandle);
}

mStorageManagerService.onUnlockUser代码:

http://aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/StorageManagerService.java#1162

//StorageManagerService类中的实现

1162      private void onUnlockUser(int userId) {
1163          Slog.d(TAG, "onUnlockUser " + userId);
1164  
1165          // We purposefully block here to make sure that user-specific
1166          // staging area is ready so it's ready for zygote-forked apps to
1167          // bind mount against.
1168          try {
1169              mStorageSessionController.onUnlockUser(userId); // ⑤
1170              mVold.onUserStarted(userId); // ⑥
1171              mStoraged.onUserStarted(userId); // ⑦
1172          } catch (Exception e) {
1173              Slog.wtf(TAG, e);
1174          }
1175  
1176          mHandler.obtainMessage(H_COMPLETE_UNLOCK_USER, userId).sendToTarget();
1177      }

http://aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/StorageManagerService.java#1162即StorageManagerService$Lifecycle中的onUserUnlocking方法最终执行到StorageManagerService::onUnlockUser方法。⑤⑥⑦是存储内部各模块处理unlock user后的逻辑,后面分段分析。

三、⑤处代码mStorageSessionController.onUnlockUser分析

StorageManagerService::onUnlockUser中,mStorageManagerService.onUnlockUser执行的是StorageSessionController::onUnlockUser:

// 初始化 mExternalStorageServiceComponent变量(ComponentName类型)
StorageManagerService::onUnlockUser
    --> StorageSessionController::initExternalStorageServiceComponent

mExternalStorageServiceComponent用于提供外部存储服务,初始化后mExternalStorageServiceComponent的信息如下:

mExternalStorageServiceComponent.getPackageName()
值为:com.android.providers.media.module

mExternalStorageServiceComponent.getClassName()
值为:com.android.providers.media.fuse.ExternalStorageServiceImpl

ComponentName
值为:com.android.providers.media.module/com.android.providers.media.fuse.ExternalStorageServiceImpl

⑤处代码很简单,就是初始化了mExternalStorageServiceComponent变量。

附上mExternalStorageServiceComponent是何时使用的:

StorageSessionController::getExternalStorageServiceComponentName获取mExternalStorageServiceComponent,即com.android.providers.media.module/com.android.providers.media.fuse.ExternalStorageServiceImpl。这个服务是在provider/media/fuse目录实现的:

http://aospxref.com/android-11.0.0_r21/xref/packages/providers/MediaProvider/src/com/android/providers/media/fuse/

mExternalStorageServiceComponent在mount emulated 存储时,用于连接ExternalStorageServiceImpl服务,流程如下:

StorageManagerService::mount
   --> mStorageSessionController.onVolumeMount(pfd, vol) // StorageSessionController::onVolumeMount
         // sessionId: emulated;0
         // deviceFd代表的文件:/dev/fuse
         // vol.getPath().getPath()对应upperPath,值为:/storage/emulated
         // vol.getInternalPath().getPath()对应lowerPath,值为:/data/media
         --> connection.startSession(sessionId, deviceFd, vol.getPath().getPath(),
                    vol.getInternalPath().getPath())  // StorageUserConnection::startSession
               // sessionId, upperPath, lowerPath封装进session
               --> session = new Session(sessionId, upperPath, lowerPath)
               --> mActiveConnection.startSession(session, pfd)  // StorageUserConnection$ActiveConnection::startSession
                      // fd代表的文件:/dev/fuse
                      -->  waitForAsync((service, callback) -> service.startSession(session.sessionId,
                        FLAG_SESSION_TYPE_FUSE | FLAG_SESSION_ATTRIBUTE_INDEXABLE,
                        fd, session.upperPath, session.lowerPath, callback))
                            --> serviceFuture = connectIfNeeded()
                                   //获取外部存储组件名称com.android.providers.media.module/com.android.providers.media.fuse.ExternalStorageServiceImpl
                                   --> name = mSessionController.getExternalStorageServiceComponentName()
                                   --> mContext.bindServiceAsUser(new Intent().setComponent(name),
                                mServiceConnection,
                                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
                                mHandlerThread.getThreadHandler(),
                                UserHandle.of(mUserId))) // ContextImpl::bindServiceAsUser
                                         --> bindServiceCommon(service, conn, flags, null, handler, null, user) // ContextImpl::bindServiceCommon
                                                 --> ActivityManager.getService().bindIsolatedService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver())

MediaProvider::openFile --> openFileCommon --> openFileAndEnforcePathPermissionsHelper中:

// MediaProvider.java  openFileAndEnforcePathPermissionsHelper函数

 // 通过ExternalStorageServiceImpl.getFuseDaemon获取daemon
 daemon = getFuseDaemonForFile(file);

 boolean shouldOpenWithFuse = daemon != null
           && daemon.shouldOpenWithFuse(filePath, true /* forRead */, 
 lowerFsFd.getFd());

 if (SystemProperties.getBoolean(PROP_FUSE, false) && shouldOpenWithFuse) {
        // 走fuse流程
        pfd = FileUtils.openSafely(getFuseFile(file), modeBits);
        try {
               lowerFsFd.close();
         } 
   } else {
         // 绕过fuse,直接走底层文件系统
         Log.i(TAG, "Using lower FS for " + filePath);
    }

四、⑥处代码mVold.onUserStarted(userId)分析

StorageManagerService::onUnlockUser中,mVold.onUserStarted(userId)是核心代码,比较复杂。这篇文章简单说一下mVold.onUserStarted功能,它主要是为外部存储创建、挂载相关目录,以主用户0为例,挂载视图如下:

注意,①②③④处在代码中bind mount挂载的分别是:
①:/mnt/runtime/full/emulated  on  /mnt/pass_through/0/emulated
②:/mnt/runtime/default/emulated/0/Android/data  on  /mnt/user/0/emulated/0/Android/data
③:/mnt/runtime/default/emulated/0/Android/obb  on  /mnt/user/0/emulated/0/Android/obb
④:/mnt/runtime/write/emulated/0/Android/obb  on  /mnt/installer/0/emulated/0/Android/obb
但mount命令看到的却是/data/media目录被bindmount到其他的目录。

流程在下一篇文章中讲解。

五、⑦处代码mStoraged.onUserStarted(userId)分析

StorageManagerService::onUnlockUser中,mStoraged.onUserStarted(userId)功能比较简单,为storaged加载/data/misc_ce/0/storaged.proto文件

storaged周期地将统计结果写入/data/misc_ce/0/storaged.proto(默认1小时更新一次,见DEFAULT_PERIODIC_CHORES_INTERVAL_FLUSH_PROTO宏),这个文件按照system/core/storaged/storaged.proto格式编码。执行storaged -p命令时从/data/misc_ce/0/storaged.proto读取数据输出到终端上。示例如下:

cp15:/data/misc_ce/0/storaged # ls
storaged.proto
cp15:/data/misc_ce/0/storaged # storaged -p

I/O perf history (KB/s) :  most_recent  <---------  least_recent
last 24 hours : 66468 33941 44126 35316 45839 37312
last 7 days   : 0 0 0 0 0 0 0
last 52 weeks : 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
cp15:/data/misc_ce/0/storaged #

下一篇文章分析mVold.onUserStarted为外部存储挂载目录的流程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/674316.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

openlayers瓦片的使用

OpenLayers是一个用于WebGIS客户端的地图开发库&#xff0c;支持多种地图。在使用瓦片时&#xff0c;先将自己需要的瓦片下载&#xff0c;下载好的瓦片会分层&#xff0c;越高的层级瓦片的数量余额多。 使用时可以引入 ol.js 文件&#xff0c;和 ol.css 文件&#xff0c;或者使…

机器学习 | 实验五:LDA

LDA的思想&#xff1a;“投影后类内方差最小&#xff0c;类间方差最大”。即数据在低维度上进行投影&#xff0c;投影后希望每一种类别数据的投影点尽可能的接近&#xff0c;而不同类别的数据的类别中心之间的距离尽可能的大。 假设我们有两类数据分别为红色和蓝色&#xff0c;…

关于socket编程中FD_XXX以及select函数的理解

文章目录 01 | 宏接口定义02 | 使用方法03 | 服务端代码示例 学习socket编程的时候看到很多FD开头的宏定义和函数&#xff0c;这里记录一下这些宏定义和函数的含义及处理流程 01 | 宏接口定义 fd_set fd_set 是一种表示文件描述符的集合类型&#xff0c;在socket编程中&#xf…

计算机网络——自顶向下方法(第三章学习记录)

本章学习运输层 运输层位于应用层和网络层之间&#xff0c;是分层的网络体系的重要部分&#xff0c;该层为运行在不同主机上的应用进程提供直接的通信服务起着至关重要的作用。 运输层协议为运行在不同主机上的应用进程之间提供了逻辑通信(logic communication)功能。从应用程…

CSS3-补充-伪元素

伪元素 作用&#xff1a;在网页中创建非主体内容&#xff0c;开发中常用CSS创建标签&#xff0c;比如装饰性的不重要的小图 区别&#xff1a; 1 元素&#xff1a;HTML 设置的标签 2 伪元素&#xff1a;由 CSS 模拟出的标签效果 …

EMC学习笔记(七)阻抗控制(一)

阻抗控制&#xff08;一&#xff09; 1.特征阻抗的物理意义1.1 输入阻抗1.2 特征阻抗1.3 偶模阻抗、奇模阻抗、差分阻抗 2.生产工艺对阻抗控制的影响 1.特征阻抗的物理意义 1.1 输入阻抗 在集总电路中&#xff0c;输入阻抗是经常使用的一个术语 &#xff0c;它的物理意义是: …

FreeRTOS实时操作系统(六)列表与列表项

系列文章目录 文章目录 系列文章目录简要概念列表列表项迷你列表项 相关API函数初始化列表列表项初始化列表项插入&#xff08;升序&#xff09;末尾列表项插入列表项删除 实战实验 简要概念 列表是 FreeRTOS 中的一个数据结构&#xff0c;概念上和链表有点类似&#xff0c;列…

ubuntu环境下测试硬盘读写速度

在Ubuntu下&#xff0c;可以使用hdparm、dd和fio等工具来测试硬盘的读写速度。 开始之前&#xff0c;先使用sudo fdisk -l命令来列出系统中所有的硬盘和分区&#xff1a; 1.使用hdparm测试硬盘读取速度&#xff1a; 安装hdparm&#xff1a; sudo apt-get install hdparm 通…

C++17中utf-8 character literal的使用

一个形如42的值被称作字面值常量(literal),这样的值一望而知。每个字面值常量都对应一种数据类型&#xff0c;字面值常量的形式和值决定了它的数据类型。 由单引号括起来的一个字符称为char型字面值&#xff0c;双引号括起来的零个或多个字符则构成字符串型字面值。 字符串字面…

9.QT 三目运算符

上面引出两个新的概念&#xff1a; 左值&#xff1a;能被赋值的就是左值。 右值&#xff1a;不能被赋值的就是右值。

基於ranger,kerberos,hadoop ha 配置hvie多用戶

基於ranger&#xff0c;kerberos&#xff0c;hadoop ha 配置hvie多用戶 hive多用戶權限管理一、hive的管理員用戶二、hive配置普通用戶1.添加用戶2.配置kerberos2.1 创建主体2.2 生成keytab文件2.3 修改keytab文件所有者(可做可不做) 3. 配置windows hive多用戶權限管理 一、h…

English Learning - L3 综合练习 8 TED-Living Beyond the Limits 2023.06.21 周三

English Learning - L3 综合练习 8 TED-Living Beyond the Limits 2023.06.21 周三 句 1句 2扩展 句 3句 4句 5句 6句 7扩展 random 句 8扩展 句 9句 10句 11句 12句 13句 14句 15句 16句 17句 18句 19句 20句 21句 22句 23 句 1 Four months later I was back up on a snowbo…

SVN使用步骤

1.基本操作 2.提交之间看一下变更内容 3.显示日志 是查看所有提交的记录4.撤销和恢复操作 撤销本地修改 或者点击提交的时候 还原 把修改的撤销掉 第二种情况,内容已经提交上去了点击提交日志 进行操作 只是撤销了本地 接着还需要继续提交到服务端 第三种情况 我们需要恢…

Linux系统之安装showdoc文档工具

Linux系统之部署showdoc文档工具 一、showdoc介绍1.1 showdoc简介1.2 showdoc功能 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本3.3 检查本地yum仓库状态 四、安装httpd服务4.1 安装httpd4.2 启动httpd服务…

用Visual C++写出你第一个Windows程序

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天来看看如何用Visual C写出你第一个Windows程序。 与其看很多Windows的书&#xff0c;不如先自己动手写一个Windows程序。由于Windows程序的特有机制&#xff0c;不建议去写那种简单的HELLO WORLD&#x…

iOS 制作私有库framework + 图片资源的使用

1. 库的分类 开源库&#xff1a;公开源代码&#xff0c;能看到具体实现** 闭源库**&#xff1a;不公开源代码&#xff0c;是经过编译后的二进制文件&#xff0c;看不到具体实现&#xff1b;其中包括&#xff1a;静态库和动态库 2. 开源库的制作 我了解的开源库的制作&#xff0…

Python基础篇(一):如何使用PyCharm创建第一个Python项目(包含tools)

如何使用PyCharm创建第一个Python项目 前言1.创建Python项目2. 创建第一个python文件3. 编写运行第一个python程序4. 关于此工具的相关使用 前言 环境版本Python3.11.4PyCharm2023.1.2OSwindows10 PyCharm是一款由JetBrains开发的强大的Python集成开发环境&#xff08;IDE&am…

单个springboot整合rabbitmq

一、rabbitmq的搭建 centos7搭建rabbitmq:centos7安装rabbitmq_java-zh的博客-CSDN博客 二、在什么情况下选择rabbitMQ 常见的四种MQ比较 特 性ActiveMQRabbitMQRocketMQKafka语言JavaErlangJavaScala单机吞吐万万十万十万时效性msusmsms(以内)可用性高&#xff08;主从架构…

模拟电路系列分享-复杂阻容电路的频响

目录 概要 整体架构流程 技术名词解释 技术细节 1.基本变形 2.单元串联的粗略计算 3.推广结论 小结 概要 在基本单元电路的基础上&#xff0c;熟悉一些常见的变形电路&#xff0c;学会判断是高通还是低通&#xff0c;快速计算出截止频率是多少&#xff0c;对求解复杂电路的频率…

TypeScript ~ 掌握基本类型 ①

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; TypeScript ~ TS &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &…