Activity 之stop过程
在之前学习了AMS如何与客户进程进行交互,从而实现启动应用进程并且创建application以及activity,调用activity生命周期进行界面显示的过程。那么当activity显示了之后,如何停止呢?现在就来学习一下,activity停止有很多种情况,例如从A启动B,那么A需要通知,又或者点击了Home键、返回键等,但是其实最终都是会经过startActivity()这一步。
Android内部提出了一种主动内存管理机制,即AMS会根据当前activity的状态,在系统内存不够用的时候杀死优先级较低的应用以释放内存空间。如何判断优先级的高低呢?就需要给不同的activity赋予不同的权值了,这个权值指的就是Activity的状态,包括正在运行、停止、销毁等,相应activity的几个回调(onPause()、onStop()、onDestroy()),不同的回调时机不同,例如当暂停和用户交互时,回调onPause(),当AMS希望把activity的权值改为stop状态时,回调onStop(),若要杀死activity,则回调onDestroy().
前面在执行handleResumeActivity()时,在最后添加了一个Idler对象;
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
....
Looper.myQueue().addIdleHandler(new Idler());
Idler内部是调用AMS的activityIdle(),经过一系列的调用,最终会来到ActivityStack的stopActivityLock(),代码如下:
final void stopActivityLocked(ActivityRecord r) {
/**
* 1.处理FLAG_ACTIVITY_NO_HISTORY标识,这个标识的作用是不要让该activity出现在
* mHistory中,如果该activity就要让它finish。比如A -> B -> C,如果B的启动标识包含了
* 该标识,那么要把B finish了,从C返回的是A,而不是B。
**/
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if (!r.finishing) {
if (!shouldSleepActivities()) {
if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"stop-no-history", false)) {
r.resumeKeyDispatchingLocked();
return;
}
}
}
}
if (r.app != null && r.app.thread != null) {
adjustFocusedActivityStack(r, "stopActivity");
r.resumeKeyDispatchingLocked();
try {
r.stopped = false;
r.setState(STOPPING, "stopActivityLocked");
/**
* 2.设置目标activity隐藏
**/
if (!r.visible) {
r.setVisible(false);
}
EventLogTags.writeAmStopActivity(
r.userId, System.identityHashCode(r), r.shortComponentName);
mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
StopActivityItem.obtain(r.visible, r.configChangeFlags));
if (shouldSleepOrShutDownActivities()) {
r.setSleeping(true);
}
/**
* 3.向目标进程的ActivityThread发送一个消息,通知它去停止指定的activity
**/
Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
mHandler.sendMessageDelayed(msg, STOP_TIMEOUT);
} catch (Exception e) {
r.stopped = true;
r.setState(STOPPED, "stopActivityLocked");
if (r.deferRelaunchUntilPaused) {
destroyActivityLocked(r, true, "stop-except");
}
}
}
}
执行完上面的过程之后,ActivityThread的handleStopActivity()将开始执行,代码如下:
public void handleStopActivity(IBinder token,...) {
final ActivityClientRecord r = mActivities.get(token);
r.activity.mConfigChangeFlags |= configChanges;
final StopInfo stopInfo = new StopInfo();
/**
* 1.调用performStopActivityInner(),这个方法内部主要做几件事情
* 1.1 调用performPauseActivityIfNeeded()回调activity的onPause(),activity在stop之前必须pause,同时将状态改为pause
* 1.2 判断info是否为空,不为空则回调onCreateDescription(),产生对该Activity的描述,AMS可能需要该描述进行一定的统计
* 1.3 回调Activity的onStop()方法
*
**/
performStopActivityInner(r, stopInfo, show, true /* saveState */, finalStateRequest,
reason);
/**
* 2.这里将该Activity的窗口即DecorView设置为隐藏
**/
updateVisibility(r, show);
/**
* 3.调用AMS的ActivityStop(),向AMS报告,自己已经停止了该Activity,AMS内部会调用trimApplication()进行一定的内存回收工作
**/
if (!r.isPreHoneycomb()) {
QueuedWork.waitToFinish();
}
stopInfo.setActivity(r);
stopInfo.setState(r.state);
stopInfo.setPersistentState(r.persistentState);
pendingActions.setStopInfo(stopInfo);
mSomeActivitiesChanged = true;
}
pause和stop的过程大致如图:
Android内存与Linux配合进行内存管理
android的内存管理分成两部分,第一部分是应用程序关闭后,后台进程没有真正提出,以便下次能够快速启动;第二部分是,当系统内存不够用时,AMS会主动根据一定的优先规则退出优先级较低的进程。何为内存不够用呢,这是属于Linux内核的内存管理控制的事情,AMS是无法预知的,应用程序和AMS运行在两个独立的虚拟机中,应用程序申请内存不会告知AMS,AMS无法感知应用程序申请内存的状况。那么Linux和AMS是如何联系到一起呢?以及AMS如何得知内存不够用呢?
看下这个详细的图:
Android的OOM killer进程会想Linux内核注册内存管理模块,AMS中会设置进程的oom_adj值,标识着该进程的优先级,当Linux内核发现内存不够时,就会通知OOM killer,然后OOM killer从AMS中获取各个进程的oom_adj值,将值大的进程有选择性的杀死,可见,AMS在这个内存回收和进程管理的角色更像是一个信息的提供着,真正进行回收的并非是AMS,它只是负责提供进程的信息,最后是由OOM killer去执行清理以及回收的工作。