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

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

概述:SystemServiceManager收到unlock事件后,遍历service链表,执行各个service的onUserUnlocking。对于存储service,执行的是StorageManagerService$Lifecycle中的onUserUnlocking,在这个方法中,存储的StorageSessionController、vold、storaged模块进行各自初始化操作。

一、SystemServiceManager处理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方法。

二、存储模块处理unlock事件

2.1  StorageManagerService$Lifecycle::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后的逻辑,后面分段分析。

2.2  ⑤处代码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);
    }

2.3  ⑥处代码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到其他的目录。

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

2.4  ⑦处代码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为外部存储挂载目录的流程。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【javascript】闭包

通过定时器从第一个元素开始往后&#xff0c;每隔一秒输出arr数组中的一个元素。 <script>var arr [one, two, three];for(var i 0; i < arr.length; i) {setTimeout(function () {console.log(arr[i]);}, i * 1000);} </script> 但是运行过后&#xff0c;我…

【LLMs 入门实战 】第二式:MiniGPT4 模型学习与实战

2023年4月17日&#xff0c;多模态问答模型MiniGPT-4发布&#xff0c;实现了GPT-4里的宣传效果《MiniGPT-4: Enhancing Vision-language Understanding with Advanced Large Language Models》《MiniGPT-4&#xff1a;使用高级大语言模型增强视觉语言理解》 模型介绍模型架构微调…

ECCV2022 多目标跟踪(MOT)汇总

一、《Towards Grand Unification of Object Tracking》 作者: Bin Yan1⋆, Yi Jiang2,†, Peize Sun3, Dong Wang1,†,Zehuan Yuan2, Ping Luo3, and Huchuan Lu School of Information and Communication Engineering, Dalian University of Technology, China 2 ByteDance …

5.6.2 传输层编址--端口

5.6.2 传输层编址 传输层为应用进程提供了端到端的逻辑通信&#xff0c;两个主机之间的通信实际上是两个主机中的应用进程之间的相互通信&#xff0c;因此一个主机中可能有多个应用进程同时和另一个主机中多个应用进程进行通信&#xff0c;而网络层我们学习的网际协议能够保证…

动态规划:积木画

积木画 问题描述 小明最近迷上了积木画, 有这么两种类型的积木, 分别为 I I I 型&#xff08;大小为 2 个单位面积) 和 L L L 型 (大小为 3 个单位面积): 同时, 小明有一块面积大小为 2 N 2 \times N 2N 的画布, 画布由 2 N 2 \times N 2N 个 1 1 1 \times 1 11 区域…

【强化学习】——Q-learning算法为例入门Pytorch强化学习

&#x1f935;‍♂️ 个人主页&#xff1a;Lingxw_w的个人主页 ✍&#x1f3fb;作者简介&#xff1a;计算机研究生在读&#xff0c;研究方向复杂网络和数据挖掘&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;CSDN专家博主、人工智能领域优质创作者&#xf…

【30天熟悉Go语言】8 Go流程控制之循环结构for range、goto、break、continue

文章目录 一、前言二、for循环1、语法1&#xff09;和Java的for循环一样2&#xff09;和Java的while一样3&#xff09;和Java的for(;;)一样 2、for语句执行过程 三、for range1、语法1&#xff09;遍历key、value只遍历value 2&#xff09;遍历key 四、关键字1、break1&#xf…

【Java】如何优雅的关闭线程池

文章目录 背景一、线程中断 interrupt二、线程池的关闭 shutdown 方法2.1、第一步&#xff1a;advanceRunState(SHUTDOWN) 把线程池置为 SHUTDOWN2.2、第二步&#xff1a;interruptIdleWorkers() 把空闲的工作线程置为中断2.3、 第三步&#xff1a;onShutdown() 一个空实现&…

Java POI (1)—— 数据读写操作快速入门

一、Excel的版本区别&#xff08;03版和07版&#xff09; 所谓“03版” 和 “07版”&#xff0c;指的是 Microsoft Excel 版本号。这些版本号代表着不同的Excel 文件格式。2003版 Excel 使用的文件格式为 .xls&#xff0c;而2007版开始使用新的文件格式 .xlsx。 . xlsx 文件格式…

【Spring 】项目创建和使用

哈喽&#xff0c;哈喽&#xff0c;大家好~ 我是你们的老朋友&#xff1a;保护小周ღ 谈起Java 圈子里的框架&#xff0c;最年长最耀眼的莫过于 Spring 框架啦&#xff0c;如今已成为最流行、最广泛使用的Java开发框架之一。不知道大家有没有在使用 Spring 框架的时候思考过这…

VulnHub靶机渗透:SKYTOWER: 1

SKYTOWER: 1 靶机环境介绍nmap扫描端口扫描服务扫描漏洞扫描总结 80端口目录爆破 3128端口获取立足点获取立足点2提权总结 靶机环境介绍 https://www.vulnhub.com/entry/skytower-1,96/ 靶机IP&#xff1a;192.168.56.101 kali IP&#xff1a;192.168.56.102 nmap扫描 端口扫…

使用mpi并行技术实现wordcount算法

【问题描述】 编写程序统计一个英文文本文件中每个单词的出现次数&#xff08;词频统计&#xff09;&#xff0c;并将统计结果按单词字典序输出到屏幕上。 注&#xff1a;在此单词为仅由字母组成的字符序列。包含大写字母的单词应将大写字母转换为小写字母后统计。 【输入形…

ChatGPT使用的SSE技术是什么?

在现代web应用程序中&#xff0c;实时通信变得越来越重要。HTTP协议的传统请求/响应模式总是需要定期进行轮询以获得最新的数据&#xff0c;这种方式效率低下并且浪费资源。因此&#xff0c;出现了一些新的通信技术&#xff0c;如WebSocket和SSE。但是&#xff0c;GPT为什么选择…

分布式数据库架构

分布式数据库架构 1、MySQL常见架构设计 对于mysql架构&#xff0c;一定会使用到读写分离&#xff0c;在此基础上有五种常见架构设计&#xff1a;一主一从或多从、主主复制、级联复制、主主与级联复制结合。 1.1、主从复制 这种架构设计是使用的最多的。在读写分离的基础上…

JS 介绍 Babel 的使用及 presets plugins 的概念

一、Babel 是什么 Bebal 可以帮助我们将新 JS 语法编译为可执行且兼容旧浏览器版本的一款编译工具。 举个例子&#xff0c;ES6&#xff08;编译前&#xff09;&#xff1a; const fn () > {};ES5&#xff08;编译后&#xff09;&#xff1a; var fn function() {}二、B…

设计模式-抽象工厂模式

抽象工厂模式 1、抽象工厂模式简介2、具体实现 1、抽象工厂模式简介 抽象工厂模式(Abstract Factory Pattern)在工厂模式尚添加了一个创建不同工厂的抽象接口(抽象类或接口实现)&#xff0c;该接口可叫做超级工厂。在使用过程中&#xff0c;我们首先通过抽象接口创建不同的工厂…

【HTML界面设计(二)】说说模块、登录界面

记录很早之前写的前端界面&#xff08;具体时间有点久远&#xff09; 一、说说模板 采用 适配器&#xff08;Adapter&#xff09;原理 来设计这款说说模板&#xff0c;首先看一下完整效果 这是demo样图&#xff0c;需要通过业务需求进行修改的部分 这一部分&#xff0c;就是dem…

Redis系列--布隆过滤器(Bloom Filter)

一、前言 在实际开发中&#xff0c;会遇到很多要判断一个元素是否在某个集合中的业务场景&#xff0c;类似于垃圾邮件的识别&#xff0c;恶意ip地址的访问&#xff0c;缓存穿透等情况。类似于缓存穿透这种情况&#xff0c;有许多的解决方法&#xff0c;如&#xff1a;redis存储…

宏景eHR SQL注入漏洞复现(CNVD-2023-08743)

0x01 产品简介 宏景eHR人力资源管理软件是一款人力资源管理与数字化应用相融合&#xff0c;满足动态化、协同化、流程化、战略化需求的软件。 0x02 漏洞概述 宏景eHR 存在SQL注入漏洞&#xff0c;未经过身份认证的远程攻击者可利用此漏洞执行任意SQL指令&#xff0c;从而窃取数…

如何在大规模服务中迁移缓存

当您启动初始服务时&#xff0c;通常会过度设计以考虑大量流量。但是&#xff0c;当您的服务达到爆炸式增长阶段&#xff0c;或者如果您的服务请求和处理大量流量时&#xff0c;您将需要重新考虑您的架构以适应它。糟糕的系统设计导致难以扩展或无法满足处理大量流量的需求&…