在动画播放完成后,对动画相关资源释放的同时还需要销毁动画进程。这里我们就来分析一下动画进程的销毁流程。
一、动画进程销毁
动画进程的销毁一般是在桌面进程准备显示的时候,而桌面准备显示是在桌面 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 {
@Override
public 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_FINISHED
data, 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 到底结束整个进程。
总结
这里用一幅图总结系统启动动画的整个流程: