Android SurfaceFlinger——动画进程销毁(十七)

        在动画播放完成后,对动画相关资源释放的同时还需要销毁动画进程。这里我们就来分析一下动画进程的销毁流程。

一、动画进程销毁

        动画进程的销毁一般是在桌面进程准备显示的时候,而桌面准备显示是在桌面 Activity 的 Resume 生命周期,我们来看一下。

1、ActivityThread

源码位置:/frameworks/base/core/java/android/app/ActivityThread.java

@Override
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,boolean isForward, String reason) {……Looper.myQueue().addIdleHandler(new Idler());
}

        在执行完 Resume 之后,会在当前线程的消息队列(Looper)中添加一个空闲处理器( IdleHandler),让进程空闲执行,当消息队列中暂时没有待处理的消息时,系统会调用这个空闲处理器的回调方法,允许执行一些轻量级的任务或者进行资源清理等工作。

private class Idler implements MessageQueue.IdleHandler {@Overridepublic final boolean queueIdle() { 执行空闲时需要处理的逻辑ActivityClientRecord a = mNewActivities;boolean stopProfiling = false;……    if (a != null) {mNewActivities = null;final ActivityClient ac = ActivityClient.getInstance();ActivityClientRecord prev;// 处理Activity空闲逻辑do {if (a.activity != null && !a.activity.mFinished) {ac.activityIdle(a.token, a.createdConfig, stopProfiling);a.createdConfig = null;}prev = a;a = a.nextIdle;prev.nextIdle = null;} while (a != null);}if (stopProfiling) {// 停止性能分析器管理mProfiler.stopProfiling();}return false;}
}

        这里在 Activity 空闲时,通知系统该 Activity 已经进入空闲状态,并清除其创建时的配置信息。

2、ActivityClient

源码位置:/frameworks/base/core/java/android/app/ActivityClient.java

/** 报告活动恢复后主线程处于空闲状态*/
public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {try {getActivityClientController().activityIdle(token, config, stopProfiling);} catch (RemoteException e) {e.rethrowFromSystemServer();}
}private static IActivityClientController getActivityClientController() {final IActivityClientController controller = INTERFACE_SINGLETON.mKnownInstance;return controller != null ? controller : INTERFACE_SINGLETON.get();
}

3、ActivityClientController

源码位置:/frameworks/base/services/core/java/com/android/server/wm/ActivityClientController.java

private final ActivityTaskSupervisor mTaskSupervisor;@Override
public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {final long origId = Binder.clearCallingIdentity();try {synchronized (mGlobalLock) {Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityIdle");final ActivityRecord r = ActivityRecord.forTokenLocked(token);if (r == null) {return;}mTaskSupervisor.activityIdleInternal(r, false /* fromTimeout */, false /* processPausingActivities */, config);if (stopProfiling && r.hasProcess()) {r.app.clearProfilerIfNeeded();}}} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);Binder.restoreCallingIdentity(origId);}
}

        该函数位于 ActivityManagerService 相关服务类中,负责处理 Activity 进入空闲状态时的一系列操作。调用 ActivityTaskSupervisor 协调执行必要的生命周期管理、资源回收以及性能监控的清理工作。

4、ActivityTaskSupervisor 

源码位置:/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java

void activityIdleInternal(ActivityRecord r, boolean fromTimeout, boolean processPausingActivities, Configuration config) {if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + r);if (r != null) {mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);r.finishLaunchTickingLocked();if (fromTimeout) {// 结束Activity启动时的计时监控reportActivityLaunched(fromTimeout, r, INVALID_DELAY, -1 /* launchState */);}// 配置更新if (config != null) {r.setLastReportedGlobalConfiguration(config);}// 标记空闲状态r.idle = true;// 判断系统是否正在启动(isBooting())且所有活动都已空闲if ((mService.isBooting() && mRootWindowContainer.allResumedActivitiesIdle()) || fromTimeout) {// 检查并完成系统的启动流程checkFinishBootingLocked();}// 重启动作标志清除r.mRelaunchReason = RELAUNCH_REASON_NONE;}……// 后台应用的资源回收操作mService.mH.post(() -> mService.mAmInternal.trimApplications());
}

        该方法不仅标记了 Activity 的空闲状态,还执行了一系列系统维护操作,其中的checkFinishBootingLocked() 方法就会检测 BootAnimation 是否关闭。

checkFinishBootingLocked

final ActivityTaskManagerService mService;private void checkFinishBootingLocked() {// 获取当前启动状态final boolean booting = mService.isBooting();boolean enableScreen = false;// 设置启动状态为已完成mService.setBooting(false);if (!mService.isBooted()) {// 标记系统已启动mService.setBooted(true);// 标记启用屏幕enableScreen = true;}// 调度完成启动的后续操作if (booting || enableScreen) {mService.postFinishBooting(booting, enableScreen);}
}

        这里就是判断并设置全局标志位,最终调用到 ATMS 中的 postFinishBooting() 方法处理启动完成后的收尾工作。

5、ActivityTaskManagerService

源码位置:/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

final ActivityTaskManagerInternal mInternal;void postFinishBooting(boolean finishBooting, boolean enableScreen) {mH.post(() -> {if (finishBooting) {// 调用AMS中的对应方法,继续启动完成的收尾工作mAmInternal.finishBooting();}if (enableScreen) {// 启用屏幕mInternal.enableScreenAfterBoot(isBooted());}});
}

        我们接着看一下  enableScreenAfterBoot() 函数,调用自身对应方法。

enableScreenAfterBoot

WindowManagerService mWindowManager;@Override
public void enableScreenAfterBoot(boolean booted) {writeBootProgressEnableScreen(SystemClock.uptimeMillis());mWindowManager.enableScreenAfterBoot();synchronized (mGlobalLock) {updateEventDispatchingLocked(booted);}
}

        此时就会走到 WMS 中的 enableScreenAfterBoot() 方法。WMS 作为窗体管理服务,肯定有渲染相关的服务在里面。

6、WindowManagerService

源码位置:/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public void enableScreenAfterBoot() {synchronized (mGlobalLock) {……if (mSystemBooted) {return;}mSystemBooted = true;// 隐藏显示在屏幕上的启动消息或动画hideBootMessagesLocked();// 如果30秒后屏幕仍然没有出现,放弃并打开它mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30 * 1000);}// 通知策略服务系统已启动mPolicy.systemBooted();// 执行屏幕启用操作performEnableScreen();
}

        该方法主要用于在系统启动后启用屏幕显示。

performEnableScreen

private void performEnableScreen() {synchronized (mGlobalLock) {……try {IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");if (surfaceFlinger != null) {ProtoLog.i(WM_ERROR, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");Parcel data = Parcel.obtain();data.writeInterfaceToken("android.ui.ISurfaceComposer");surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHEDdata, null, 0);data.recycle();}} catch (RemoteException ex) {……}……}try {mActivityManager.bootAnimationComplete();} catch (RemoteException e) {}……
}

        关键是通信到 SurfaceFlinger 中,传入了 FIRST_CALL_TRANSACTION 命令,而这个命令实际上就是 BOOT_FINISHED。

ISurfaceComposer.h

源码位置:/frameworks/native/libs/gui/include/gui/ISurfaceComposer.h

BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION

        接下来我们看一下 SurfaceFlinger 中对于 BOOT_FINISHED 消息做了什么处理。这里使用的是 Binder 通信,实际的消息处理是在基类 ISurfaceComposer 中。

7、ISurfaceComposer.cpp

源码位置:/frameworks/native/libs/gui/ISurfaceComposer.cpp

case BOOT_FINISHED: {CHECK_INTERFACE(ISurfaceComposer, data, reply);bootFinished();return NO_ERROR;
}

        其实这里调用的就是 SurfaceFlinger 中的 bootFinished() 方法。 

8、SurfaceFlinger.cpp

源码位置:/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::bootFinished() {……// 等待启动属性设置线程结束if (mStartPropertySetThread->join() != NO_ERROR) {ALOGE("Join StartPropertySetThread failed!");}……// 链接WMS服务的死亡监听const String16 name("window");mWindowManager = defaultServiceManager()->getService(name);if (mWindowManager != 0) {mWindowManager->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));}// 停止启动动画// 这种方式比直接杀死进程更优雅,因为启动动画进程可以根据这个信号选择动画停止的位置。property_set("service.bootanim.exit", "1");// 记录停止启动动画的日志事件const int LOGTAG_SF_STOP_BOOTANIM = 60110;LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));……
}

        这里 SurfaceFlinger 绑定了对 WMS 的 Binder 死亡代理。不过关键还是设置了 service.bootanim.exit 这个全局属性。而这个属性刚好就是 BootAnimation 在 checkExit 方法中不断循环检测。

9、BootAnimation

源码位置: /frameworks/base/cmds/bootanimation/BootAnimation.cpp

void BootAnimation::checkExit() {// 检测是否应该结束启动动画过程char value[PROPERTY_VALUE_MAX];property_get(EXIT_PROP_NAME, value, "0");int exitnow = atoi(value);if (exitnow) {requestExit();}
}

        requestExit 其实就是退出该 BootAnimation 线程的 threadLoop 方法,这样整个 main 方法就不会阻塞住,就会一直运行整个 main 到底结束整个进程。

总结

        这里用一幅图总结系统启动动画的整个流程:

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

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

相关文章

美团校招机试 - 小美的平衡矩阵(20240309-T1)

题目来源 美团校招笔试真题_小美的平衡矩阵 题目描述 小美拿到了一个 n * n 的矩阵&#xff0c;其中每个元素是 0 或者 1。 小美认为一个矩形区域是完美的&#xff0c;当且仅当该区域内 0 的数量恰好等于 1 的数量。 现在&#xff0c;小美希望你回答有多少个 i * i 的完美…

redis哨兵模式(Redis Sentinel)

哨兵模式的背景 当主服务器宕机后&#xff0c;需要手动把一台从服务器切换为主服务器&#xff0c;这就需要人工干预&#xff0c;费事费力&#xff0c;还会造成一段时间内服务不可用。这不是一种推荐的方式。 为了解决单点故障和提高系统的可用性&#xff0c;需要一种自动化的监…

暑假本科生、研究生怎么学?来看详细的AI夏令营规划

Datawhale夏令营 发布&#xff1a;2024 AI 夏令营 学习规划 「学习内容详览」 01机器学习方向&#xff1a;2024/7/1~7/7 「Datawhale」邀请想入门人工智能领域并实践机器学习算法的学习者和我们一起来学习~ 详细学习规划如下&#xff1a; 02大模型技术方向&#xff1a;2024/7…

基于springboot、vue汽车租赁系统

设计技术&#xff1a; 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatisvue工具&#xff1a;IDEA、Maven、Navicat 主要功能&#xff1a; 用户进入系统可以查看首页、个人中心、车辆信息管理、租赁订单列表管理、还车记录管理等操作 管理…

串级PID控制算原理及法详解

文章目录 1. PID 2. 串级PID 3. 串级PID的物理量 4. C语言实现单极PID 5. C语言实现串极PID 6. 模拟仿真 1. PID PID是应用最广泛的闭环控制方法之一&#xff0c;是一种常用的反馈控制方法&#xff0c;对于每个PID控制器由三个部分组成&#xff1a;比例控制&#xff08;…

自然语言处理——英文文本预处理

高质量数据的重要性 数据的质量直接影响模型的性能和准确性。高质量的数据可以显著提升模型的学习效果&#xff0c;帮助模型更准确地识别模式、进行预测和决策。具体原因包括以下几点&#xff1a; 噪音减少&#xff1a;高质量的数据经过清理&#xff0c;减少了无关或错误信息…

Wp-scan一键扫描wordpress网页(KALI工具系列三十)

目录 1、KALI LINUX 简介 2、Wp-scan工具简介 3、信息收集 3.1 目标IP&#xff08;服务器) 3.2kali的IP 4、操作实例 4.1 基本扫描 4.2 扫描已知漏洞 4.3 扫描目标主题 4.4 列出用户 4.5 输出扫描文件 4.6 输出详细结果 5、总结 1、KALI LINUX 简介 Kali Linux 是一…

《梦醒蝶飞:释放Excel函数与公式的力量》6.1 DATE函数

6.1 DATE函数 第一节&#xff1a;DATE函数 1&#xff09;DATE函数概述 DATE函数是Excel中的一个内置函数&#xff0c;用于根据指定的年、月、日返回对应的日期序列号。这个函数非常有用&#xff0c;尤其是在处理日期数据时&#xff0c;它可以帮助你构建特定的日期&#xff0…

pycharm工具回退键调出

pycharm工具调出回退键。 View->Appearance->Toolbar,即可调出 调不出的可以使用快捷键&#xff1a;ctrlalt向左箭头 但是这个快捷键容易和电脑屏幕旋转冲突。可将电脑的快捷键关掉&#xff0c;即可。 ctrlalt向上箭头&#xff1a;将屏幕旋转到正常&#xff08;横向&am…

【面试干货】final、finalize 和 finally 的区别

【面试干货】final、finalize 和 finally 的区别 1、final1.1 修饰类1.2 修饰方法1.3 修饰变量 2、finally3、finalize4、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java编程语言中&#xff0c;final、finalize和finally都是关键…

汽车免拆诊断案例 | 2016 款吉利帝豪EV车无法加速

故障现象 一辆2016款吉利帝豪EV车&#xff0c;累计行驶里程约为28.4万km&#xff0c;车主反映车辆无法加速。 故障诊断 接车后路试&#xff0c;行驶约1 km&#xff0c;踩下加速踏板&#xff0c;无法加速&#xff0c;车速为20 km/h左右&#xff0c;同时组合仪表上的电机及控制…

设备驱动框架之LED

文章目录 前言一、什么是驱动框架二、使用步骤1.注册LED设备2.卸载LED设备3.内核中申请内存4.container_of5.platform_get_drvdata 和 platform_set_drvdata6.module_platform_driver 三、驱动示例总结 前言 为了尽量降低驱动开发者难度以及接口标准化&#xff0c;就出现了设备…

面试-Java线程池

1.利用Excutors创建不同的线程池满足不同场景的需求 分析&#xff1a; 如果并发的请求的数量非常多&#xff0c;但每个线程执行的时间非常短&#xff0c;这样就会频繁的创建和销毁线程。如此一来&#xff0c;会大大降低系统的效率。 可能出现&#xff0c;服务器在为每个线程创建…

利用powershell开展网络钓鱼

要确保人们打开我们的恶意文件并执行它们&#xff0c;我们只需让微软努力工作多年来赢得人们的信任&#xff0c;然后将一些危险的宏插入到幻灯片中。 本博文将介绍如何通过屏幕顶部的一个友好的警告提示&#xff0c;在用户启用宏后立即运行您的宏。 首先&#xff0c;我们需要打…

浏览器扩展V3开发系列之 chrome.commands 快捷键的用法和案例

【作者主页】&#xff1a;小鱼神1024 【擅长领域】&#xff1a;JS逆向、小程序逆向、AST还原、验证码突防、Python开发、浏览器插件开发、React前端开发、NestJS后端开发等等 chrome.commands API 允许开发者使用快捷键来执行特定的命令。 在使用 chrome.commands API 之前必须…

Vue 学习之 axios

目录 执行安装命令&#xff1a;npm install axios 使用的时候导入 axios以data&#xff0c;params&#xff0c;headers传参方式的区别 axios封装 是一个基于 promise 的 网络请求库&#xff0c;作用于浏览器和 node.js 中。使用Axios可以在前端项目中发送各种方式的HTTP请求…

如何查看websocket连接信息

Chrome 浏览器中查看 webSocket 连接信息_谷歌浏览器看不到 websocket-CSDN博客 Getting Started — Flask-SocketIO documentation 运作原理 | Socket.IO

VS Code准备JAVA环境

背景 由于IntelliJ IDEA是需要激活码的,简单的java demo测试,除了可以直接使用命令行java和javac进行执行, 推荐使用VS code, 其功能比较强大,扩展插件也比丰富,对阅读和书写代码都是比较友好的. JDK环境准备 Linux JDK可以使用Open JDK 11. sudo apt-get install openjdk-1…

UE引擎实现ShadowMap、体积光(C++)

前言 整体上参考了YivanLee大佬的这两篇文&#xff1a; 虚幻4渲染编程&#xff08;灯光篇&#xff09;【第一卷&#xff1a;各种ShadowMap】 虚幻4渲染编程&#xff08;灯光篇&#xff09;【第二卷&#xff1a;体积光】 正文 1、ShadowMap &#xff08;1&#xff09;创建工…

【浦语开源】深入探索:大模型全链路开源组件 InternLM Lagent,打造灵笔Demo实战指南

一、准备工作&#xff1a; 1、环境配置&#xff1a; pip、conda换源&#xff1a; pip临时换源&#xff1a; pip install -i https://mirrors.cernet.edu.cn/pypi/web/simple some-package# 这里的“https://mirrors.cernet.edu.cn/pypi/web/simple”是所换的源&#xff0c;…