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