ActivityManagerService之onStop()的调用流程,及为何会最迟会延迟10秒执行?

这篇文章通过追踪AMS源码(api28),走一遍执行onStop()的流程,先来一张流程图:

 

两个Activity之间切换后,上一个Activity切换到OnStop状态;或者调用finish()后,到Activity回收切换到最终的OnDestroy状态,AMS的机制是,等主线程空闲时,再通知AMS执行Activity的可见性切换(Onstop()),Activity的回收(OnDestroy()),目的是由于OnStop,OnDestroy这个两个状态的切换并不影响界面的显示和点击事件分发,属于低优先级的行为,不紧跟OnPause,OnResume这个两个状态切换之后执行,可以避免主线程处理过多操作,导致Activity的切换动画卡顿。在AMS端也存在保护机制,当app进程执行完handleResumeActivity()回调到AMS的completeResumeLocked()就会开启超时10秒的任务去通知执行Activity的可见性切换(Onstop()),Activity的回收(OnDestroy()),这样做的目标是避免app进程的主线程一直不空闲,导致这操作永远执行不到。

从源码开始追踪(省略无关的代码):

本次追踪分为四部分(1、当前目标activity切换ON_RESUME状态后,将上一个activity放到等待执行切换到ON_STOP状态的队列中;2、app进程端开始;3、AMS开始;4、AMS开始执行Activity切换onStop)

目录

1、AMS通知目标activity切换到ON_RESUME状态后,将上一个可见的activity放到切换到ON_STOP状态的等待处理队列中

1.1、ActivityRecord#completeResumeLocked

1.2、ActivityStackSupervisor#reportResumedActivityLocked

1.3、ActivityStackSupervisor#ensureActivitiesVisibleLocked

1.4、ActivityStack#ensureActivitiesVisibleLocked

1.5、ActivityStack#makeInvisible

1.6、ActivityStack#addToStopping

2、app进程执行完handleResumeActivity方法之后开始

2.1、Idler#queueIdle

2.2、ActivityManagerService#activityIdle

3、将需要切换到ON_STOP状态的activity加入队列后,AMS将发送一个超时10秒的任务,确保app端主线繁忙时,也是执行对应切换生命周期操作

3.1、ActivityStackSupervisor#scheduleIdleTimeoutLocked(即1.5中,对应那个方法)

4、AMS开始执行目标Activity切换onStop状态

4.1、ActivityStackSupervisor#activityIdleInternalLocked


1、AMS通知目标activity切换到ON_RESUME状态后,将上一个可见的activity放到切换到ON_STOP状态的等待处理队列中

1.1、ActivityRecord#completeResumeLocked

void completeResumeLocked() {
    
    ...
    
    // 执行切换到ON_RESUME状态后的操作
    mStackSupervisor.reportResumedActivityLocked(this);

    ...

}

1.2、ActivityStackSupervisor#reportResumedActivityLocked

boolean reportResumedActivityLocked(ActivityRecord r) {

    // 从等待切换到ON_STOP状态的队列中移除
    mStoppingActivities.remove(r);

    ...

    // 必须在目标activity切换到ON_RESUME状态流程完整后,才可以调整其他activity的可见状态(确定那 
    // 些activity需要进入ON_STOP状态)
    if (allResumedActivitiesComplete()) {
       
        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
        mWindowManager.executeAppTransition();
        return true;
    }

    return false;

}

1.3、ActivityStackSupervisor#ensureActivitiesVisibleLocked

void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
            boolean preserveWindows, boolean notifyClients) {
    getKeyguardController().beginActivityVisibilityUpdate();
    try {
    
        // 遍历一下所有的activity的可见状态
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx)           
        {
            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = display.getChildAt(stackNdx);
                stack.ensureActivitiesVisibleLocked(starting,configChanges,preserveWindows,
                            notifyClients);
            }
        }
    } finally {
        getKeyguardController().endActivityVisibilityUpdate();
    }
}

1.4、ActivityStack#ensureActivitiesVisibleLocked

final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
            boolean preserveWindows, boolean notifyClients) {
    
    ...

    // 顶层可见的activity    
    ActivityRecord top = topRunningActivityLocked();

    // 判断当前最顶层的activity是否是完全可见(即盖住下面全部的activity,不是半透明activity)
    final boolean stackShouldBeVisible = shouldBeVisible(starting);
    boolean behindFullscreenActivity = !stackShouldBeVisible;
    
    // 遍历一下所有的activity
    for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
        
        final TaskRecord task = mTaskHistory.get(taskNdx);
        final ArrayList<ActivityRecord> activities = task.mActivities;
        for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
            
            // 开始判断每个activity
            final ActivityRecord r = activities.get(activityNdx);
            
            // 如果已经finish的跳过不管
            if (r.finishing) {
                continue;
            }

            
            // 判断该activity是否可见
            final boolean visibleIgnoringKeyguard = r.shouldBeVisibleIgnoringKeyguard(
                            behindFullscreenActivity);
            r.visibleIgnoringKeyguard = visibleIgnoringKeyguard;
                
            final boolean reallyVisible = checkKeyguardVisibility(r,
                            visibleIgnoringKeyguard, isTop && isTopNotPinnedStack);
            
            // 如果该activity为可见状态
            if (reallyVisible) {
             
                // 如果该activity不存在
                if (r.app == null || r.app.thread == null) {
                    
                    // 需要重启该activity
                    if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
                                    resumeNextActivity, r)) {
                    ...
                    
                    }                    

                }
                // 如果该activity已经可见了
                else if (r.visible) {
                    
                    // 如果需要通知app端
                    if (r.mClientVisibilityDeferred && notifyClients) {
                        
                        // 通知一下对应的activity切换可见性
                        r.makeClientVisible();
                    }
                    
                }else{
                    
                    // 通知对应的activity切换可见性 
                    r.makeVisibleIfNeeded(starting, notifyClients);
                }            
   
            }
            // 如果该activity为不可见状态
            else{
                // 将该activity设置为不可见状态
                makeInvisible(r);

            }

            ...
            
        }

    }
    
}

1.5、ActivityStack#makeInvisible

private void makeInvisible(ActivityRecord r) {

    // 如果已经为不可见状态
    if (!r.visible) {
        return;
    }

    ...

    switch (r.getState()) {
        
        // 如果已经是停止,需要通知app端的activity切换到正确的可见状态
        case STOPPING:
        case STOPPED:
            if (r.app != null && r.app.thread != null) {
                if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
                                "Scheduling invisibility: " + r);
                mService.getLifecycleManager().scheduleTransaction(r.app.thread,         
                     r.appToken,WindowVisibilityItem.obtain(false /* showWindow */));
            }
            r.supportsEnterPipOnTaskSwitch = false;
                break;

        // 如果在一下这些状态,需要加到准备切换到ON_STOP的队列中
        case INITIALIZING:
        case RESUMED:
        case PAUSING:
        case PAUSED:
            addToStopping(r, true /* scheduleIdle */,canEnterPictureInPicture /*             
                  idleDelayed */);
            break;

        default:
            break;
     }
    

}

1.6、ActivityStack#addToStopping

 void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) {
    if (!mStackSupervisor.mStoppingActivities.contains(r)) {
        mStackSupervisor.mStoppingActivities.add(r);
    }

    ...

    // 超时10执行状态切换    
    mStackSupervisor.scheduleIdleTimeoutLocked(r);

}
    

2、app进程执行完handleResumeActivity方法之后开始

@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,String reason) {

    ...

    // 执行完,往主线程插入一个任务,等主线程空闲时执行
    Looper.myQueue().addIdleHandler(new Idler());
}

2.1、Idler#queueIdle

private class Idler implements MessageQueue.IdleHandler {
    @Override
    public final boolean queueIdle() {
    
    // 当前活跃的activity
    ActivityClientRecord a = mNewActivities;

    ...

    // 通知AMS开始执行操作
    am.activityIdle(a.token, a.createdConfig, stopProfiling);

    ...    

    }
}

2.2、ActivityManagerService#activityIdle

public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling){
    synchronized (this) {
     
        mStackSupervisor.activityIdleInternalLocked(token, false /* fromTimeout */,
                                false /* processPausingActivities */, config);    
   
    }
}

3、将需要切换到ON_STOP状态的activity加入队列后,AMS将发送一个超时10秒的任务,确保app端主线繁忙时,也是执行对应切换生命周期操作

3.1、ActivityStackSupervisor#scheduleIdleTimeoutLocked(即1.5中,对应那个方法)

void scheduleIdleTimeoutLocked(ActivityRecord next) {
    
    Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG, next);
    mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT/*10*/);
}

4、AMS开始执行目标Activity切换onStop状态

4.1、ActivityStackSupervisor#activityIdleInternalLocked

final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
                boolean processPausingActivities, Configuration config) {

   ...

   final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(r,
                true /* remove */, processPausingActivities);
   NS = stops != null ? stops.size() : 0;
   if ((NF = mFinishingActivities.size()) > 0) {
       finishes = new ArrayList<>(mFinishingActivities);
       mFinishingActivities.clear();
   }

   if (mStartingUsers.size() > 0) {
       startingUsers = new ArrayList<>(mStartingUsers);
       mStartingUsers.clear();
   }

   // 将在队列中的activity执行切换到ON_STOP生命周期
   for (int i = 0; i < NS; i++) {
       r = stops.get(i);
       final ActivityStack stack = r.getStack();
       if (stack != null) {
           // 如果该activity已经finish了,需要将它排进finish的队列中
           if (r.finishing) {
               stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY,                 
                      false,"activityIdleInternalLocked");
           } else {
               stack.stopActivityLocked(r);
           }
       }
   }

   // 将在队列中的activity执行切换到ON_DESTROY生命周期
   for (int i = 0; i < NF; i++) {
       r = finishes.get(i);
       final ActivityStack stack = r.getStack();
       if (stack != null) {
           activityRemoved |= stack.destroyActivityLocked(r, true, "finish-idle");
       }
   }

}

总结:通过本次的代码追踪,就是知道为啥OnStop和OnDestory不是跟在OnPause之后立马执行,而是延迟执行且最迟会延迟到10秒执行。如果内存不足,这个两个方法可能存在不执行的情况。故我们在使用activity生命周期回调做一些全局方法的调用,就需要处理调用时序问题和可能存在泄漏的问题。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值