前言
前面说道,调用到addToStopping,将activity添加到mStoppingActivities队列之后,会发送一个IDLE_NOW_MSG消息;其handler与AMS的MainHandler共用一个looper,消息执行时会调用activityIdleInternal
ActivityStackSupervisorHandler#handleMessage
4761 case IDLE_TIMEOUT_MSG: {
4762 if (DEBUG_IDLE) Slog.d(TAG_IDLE,
4763 "handleMessage: IDLE_TIMEOUT_MSG: r=" + msg.obj);
4764 // We don't at this point know if the activity is fullscreen,
4765 // so we need to be conservative and assume it isn't.
4766 activityIdleInternal((ActivityRecord) msg.obj,
4767 true /* processPausingActivities */);
4768 } break;
ActivityStackSupervisorHandler初始化过程
614 public ActivityStackSupervisor(ActivityManagerService service, Looper looper) {
615 mService = service;
616 mLooper = looper;
617 mHandler = new ActivityStackSupervisorHandler(looper);
618 }
ActivityManagerService#createStackSupervisor
3259 protected ActivityStackSupervisor createStackSupervisor() {
3260 final ActivityStackSupervisor supervisor = new ActivityStackSupervisor(this, mHandler.getLooper());
3261 supervisor.initialize();
3262 return supervisor;
3263 }
与ActivityManagerService中的MainHandler共用一个线程looper
ActivityStackSupervisorHandler.png
ActivityStackSupervisor$ActivityStackSupervisorHandler#activityIdleInternal
case IDLE_NOW_MSG: {
if (DEBUG_IDLE) Slog.d(TAG_IDLE, "handleMessage: IDLE_NOW_MSG: r=" + msg.obj);
activityIdleInternal((ActivityRecord) msg.obj,
false /* processPausingActivities */);
} break
处理IDLE_NOW_MSG消息时processPausingActivities为false,IDLE_TIMEOUT_MSG时processPausingActivities为true
首先看下mStoppingActivities和mActivitiesWaitingForVisibleActivity队列的意义和赋值位置
当下面的Activity paused之后,根据流程再次调用resumeTopActivityInnerLocked
在这里将已经paused的Activity添加到mActivitiesWaitingForVisibleActivity队列
if (prev != null && prev != next) {
if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(prev)
&& next != null && !next.nowVisible) {
mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(prev);
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Resuming top, waiting visible to hide: " + prev);
}else{
...
}
}
在makeInvisible中调用addToStopping将已经resumed的Activity加入到mStoppingActivities队列中
private void makeInvisible(ActivityRecord r) {
if (!r.visible) { //当本来已经visible为false时,直接返回就行了
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + r);
return;
}
// Now for any activities that aren't visible to the user, make sure they no longer are
// keeping the screen frozen.
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.getState());
try {
final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState(
"makeInvisible", true /* beforeStopping */);
// Defer telling the client it is hidden if it can enter Pip and isn't current paused,
// stopped or stopping. This gives it a chance to enter Pip in onPause().
// TODO: There is still a question surrounding activities in multi-window mode that want
// to enter Pip after they are paused, but are still visible. I they should be okay to
// enter Pip in those cases, but not "auto-Pip" which is what this condition covers and
// the current contract for "auto-Pip" is that the app should enter it before onPause
// returns. Just need to confirm this reasoning makes sense.
final boolean deferHidingClient = canEnterPictureInPicture
&& !r.isState(STOPPING, STOPPED, PAUSED);
r.setDeferHidingClient(deferHidingClient);
r.setVisible(false);
switch (r.getState()) {
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 */));
}
// Reset the flag indicating that an app can enter picture-in-picture once the
// activity is hidden
r.supportsEnterPipOnTaskSwitch = false;
break;
case INITIALIZING:
case RESUMED:
case PAUSING:
case PAUSED:
addToStopping(r, true /* scheduleIdle */,
canEnterPictureInPicture /* idleDelayed */); //且当下层Activity的state为上面几个时,调用addToStopping
break;
default:
break;
}
} catch (Exception e) {
// Just skip on any failure; we'll make it visible when it next restarts.
Slog.w(TAG, "Exception thrown making hidden: " + r.intent.getComponent(), e);
}
}
本地调试时发现在ActivityManagerService中接收到IDLE_NOW_MSG准备处理时,调用到activityIdleInternal时,线程会先切换到android.display线程,然后在android.display线程中会处理消息,回调到ActivityRecord中的onWindowsVisible,在其中将mActivitiesWaitingForVisibleActivity队列中的paused Activity移除
AppWindowContainerController#mOnWindowsVisible
private final Runnable mOnWindowsVisible = () -> {
if (mListener == null) {
return;
}
if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
+ AppWindowContainerController.this.mToken);
mListener.onWindowsVisible();
};
ActivityRecord#onWindowsVisible
@Override
public void onWindowsVisible() {
synchronized (service) {
mStackSupervisor.reportActivityVisibleLocked(this);
if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
if (!nowVisible) {
nowVisible = true;
launching = false;
lastVisibleTime = SystemClock.uptimeMillis();
if (idle || mStackSupervisor.isStoppingNoHistoryActivity()) {
// If this activity was already idle or there is an activity that must be
// stopped immediately after visible, then we now need to make sure we perform
// the full stop of any activities that are waiting to do so. This is because
// we won't do that while they are still waiting for this one to become visible.
final int size = mStackSupervisor.mActivitiesWaitingForVisibleActivity.size();
if (size > 0) {
for (int i = 0; i < size; i++) {
final ActivityRecord r =
mStackSupervisor.mActivitiesWaitingForVisibleActivity.get(i);
if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r);
}
mStackSupervisor.mActivitiesWaitingForVisibleActivity.clear();
mStackSupervisor.scheduleIdleLocked();
}
} else {
// Instead of doing the full stop routine here, let's just hide any activities
// we now can, and let them stop when the normal idle happens.
mStackSupervisor.processStoppingActivitiesLocked(null /* idleActivity */,
false /* remove */, true /* processPausingActivities */);
}
service.scheduleAppGcsLocked();
}
}
}
ActivityStackSupervisor#processStoppingActivitiesLocked
final ArrayList<ActivityRecord> processStoppingActivitiesLocked(ActivityRecord idleActivity,
boolean remove, boolean processPausingActivities) {
ArrayList<ActivityRecord> stops = null;
final boolean nowVisible = allResumedActivitiesVisible();
for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) {
ActivityRecord s = mStoppingActivities.get(activityNdx);
boolean waitingVisible = mActivitiesWaitingForVisibleActivity.contains(s);
if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
+ " waitingVisible=" + waitingVisible + " finishing=" + s.finishing);
if (waitingVisible && nowVisible) {
mActivitiesWaitingForVisibleActivity.remove(s); //android.display处调用的是上半段,将Activity从mActivitiesWaitingForVisibleActivity中移除
waitingVisible = false;
if (s.finishing) {
// If this activity is finishing, it is sitting on top of
// everyone else but we now know it is no longer needed...
// so get rid of it. Otherwise, we need to go through the
// normal flow and hide it once we determine that it is
// hidden by the activities in front of it.
if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
s.setVisibility(false);
}
}
if (remove) { //activityIdleInternalLocked调用到这里
final ActivityStack stack = s.getStack();
final boolean shouldSleepOrShutDown = stack != null
? stack.shouldSleepOrShutDownActivities()
: mService.isSleepingOrShuttingDownLocked();
if (!waitingVisible || shouldSleepOrShutDown) {
if (!processPausingActivities && s.isState(PAUSING)) {
// Defer processing pausing activities in this iteration and reschedule
// a delayed idle to reprocess it again
removeTimeoutsForActivityLocked(idleActivity);
scheduleIdleTimeoutLocked(idleActivity);
continue;
}
if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
if (stops == null) {
stops = new ArrayList<>();
}
stops.add(s);
mStoppingActivities.remove(activityNdx);
}
}
}
return stops;
}
android.display线程中调用processStoppingActivitiesLocked.png
这部分就与显示,WMS密切相关了,后面再学习
然后app端处于idle状态,binder call调用activityIdleInternalLocked,在其中将mStoppingActivities的Activity移出队列,并对其调用stopActivityLocked或者finishCurrentActivityLocked
binder线程调用processStoppingActivitiesLocked.png这种情况应该是ActivityThread调用handleResumeActivity之后通过binder call调用activityIdleInternalLocked->processStoppingActivitiesLocked,返回stops队列
然后回到ActivityManager线程,继续处理IDLE_NOW_MSG消息,但此时貌似已经没什么可以做的了,只是走一遍流程
ActivityManager线程调用processStoppingActivitiesLocked.png
这种情况应该是执行了IDLE_NOW_MSG(或IDLE_TIMEOUT_MSG timeout机制)的消息执行到activityIdleInternalLocked->processStoppingActivitiesLocked,返回stops队列
mActivitiesWaitingForVisibleActivity与mStoppingActivities
这时我们回来看mActivitiesWaitingForVisibleActivity的意义
353 /** List of activities that are waiting for a new activity to become visible before completing
354 * whatever operation they are supposed to do. */
355 // TODO: Remove mActivitiesWaitingForVisibleActivity list and just remove activity from
356 // mStoppingActivities when something else comes up.
目前理解:mActivitiesWaitingForVisibleActivity这个里面存放的是当new Activity启动时需要隐藏的Activity;从mActivitiesWaitingForVisibleActivity移除之后再执行activityIdleInternalLocked的processStoppingActivitiesLocked,将其从mStoppingActivities中移出来,做相应的操作
// Checked.
@GuardedBy("mService")
final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
boolean processPausingActivities, Configuration config) {
if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + token);
ArrayList<ActivityRecord> finishes = null;
ArrayList<UserState> startingUsers = null;
int NS = 0;
int NF = 0;
boolean booting = false;
boolean activityRemoved = false;
ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r != null) {
if (DEBUG_IDLE) Slog.d(TAG_IDLE, "activityIdleInternalLocked: Callers="
+ Debug.getCallers(4));
mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
r.finishLaunchTickingLocked();
if (fromTimeout) {
reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
}
// This is a hack to semi-deal with a race condition
// in the client where it can be constructed with a
// newer configuration from when we asked it to launch.
// We'll update with whatever configuration it now says
// it used to launch.
if (config != null) {
r.setLastReportedGlobalConfiguration(config);
}
// We are now idle. If someone is waiting for a thumbnail from
// us, we can now deliver.
r.idle = true;
//Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
if (isFocusedStack(r.getStack()) || fromTimeout) {
booting = checkFinishBootingLocked();
}
}
if (allResumedActivitiesIdle()) {
if (r != null) {
mService.scheduleAppGcsLocked(); //此时resumedActivity为idle状态,做gc操作
}
if (mLaunchingActivity.isHeld()) {
mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
if (VALIDATE_WAKE_LOCK_CALLER &&
Binder.getCallingUid() != Process.myUid()) {
throw new IllegalStateException("Calling must be system uid");
}
mLaunchingActivity.release();
}
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
// Atomically retrieve all of the other things to do.
final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(r,
true /* remove */, processPausingActivities);
//处理mStoppingActivities和mActivitiesWaitingForVisibleActivity队列
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();
}
// Stop any activities that are scheduled to do so but have been
// waiting for the next one to start.
for (int i = 0; i < NS; i++) {
r = stops.get(i);
final ActivityStack stack = r.getStack();
if (stack != null) {
if (r.finishing) {
stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false,
"activityIdleInternalLocked");
} else {
stack.stopActivityLocked(r);
}
}
}
// Finish any activities that are scheduled to do so but have been
// waiting for the next one to start.
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"); //finishes队列(mFinishingActivities)中的Activity做destroyActivityLocked操作
}
}
if (!booting) {
// Complete user switch
if (startingUsers != null) {
for (int i = 0; i < startingUsers.size(); i++) {
mService.mUserController.finishUserSwitch(startingUsers.get(i));
}
}
}
mService.trimApplications();
//dump();
//mWindowManager.dump();
if (activityRemoved) {
resumeFocusedStackTopActivityLocked();
}
return r;
}
stopActivity
首先看一下stopActivity的相关流程
ActivityStack#stopActivityLocked
final void stopActivityLocked(ActivityRecord r) {
if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + r);
r.launching = false;
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if (!r.finishing) {
if (!shouldSleepActivities()) {
if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r);
if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"stop-no-history", false)) {
// If {@link requestFinishActivityLocked} returns {@code true},
// {@link adjustFocusedActivityStack} would have been already called.
r.resumeKeyDispatchingLocked();
return;
}
} else {
if (DEBUG_STATES) Slog.d(TAG_STATES, "Not finishing noHistory " + r
+ " on stop because we're just sleeping");
}
}
}
if (r.app != null && r.app.thread != null) {
adjustFocusedActivityStack(r, "stopActivity"); //保证focus stack正确
r.resumeKeyDispatchingLocked();
try {
r.stopped = false;
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to STOPPING: " + r + " (stop requested)");
r.setState(STOPPING, "stopActivityLocked");
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Stopping visible=" + r.visible + " for " + r);
if (mActivityTrigger != null) {
mActivityTrigger.activityStopTrigger(r.intent, r.info, r.appInfo);
}
if (mActivityPluginDelegate != null) {
mActivityPluginDelegate.activitySuspendNotification
(r.appInfo.packageName, r.fullscreen, false);
}
if (!r.visible) {
r.setVisible(false);
}
EventLogTags.writeAmStopActivity(
r.userId, System.identityHashCode(r), r.shortComponentName); //event log
mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
StopActivityItem.obtain(r.visible, r.configChangeFlags));//执行StopActivityItem的excute
if (shouldSleepOrShutDownActivities()) {
r.setSleeping(true);
}
Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
mHandler.sendMessageDelayed(msg, STOP_TIMEOUT); //防止超时
} catch (Exception e) {
// Maybe just ignore exceptions here... if the process
// has crashed, our death notification will clean things
// up.
//process被kill的情况
Slog.w(TAG, "Exception thrown during pause", e);
// Just in case, assume it to be stopped.
r.stopped = true;
if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + r);
r.setState(STOPPED, "stopActivityLocked");
if (r.deferRelaunchUntilPaused) {
destroyActivityLocked(r, true, "stop-except");
}
}
}
}
StopActivityItem#excute
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
client.handleStopActivity(token, mShowWindow, mConfigChanges, pendingActions,
true /* finalStateRequest */, "STOP_ACTIVITY_ITEM");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
ActivityThread#handleStopActivity
@Override
public void handleStopActivity(IBinder token, boolean show, int configChanges,
PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {
final ActivityClientRecord r = mActivities.get(token);
r.activity.mConfigChangeFlags |= configChanges;
final StopInfo stopInfo = new StopInfo();
performStopActivityInner(r, stopInfo, show, true /* saveState */, finalStateRequest,
reason);
if (localLOGV) Slog.v(
TAG, "Finishing stop of " + r + ": show=" + show
+ " win=" + r.window);
updateVisibility(r, show);
// Make sure any pending writes are now committed.
if (!r.isPreHoneycomb()) {
QueuedWork.waitToFinish();
}
stopInfo.setActivity(r);
stopInfo.setState(r.state);
stopInfo.setPersistentState(r.persistentState);
pendingActions.setStopInfo(stopInfo);
mSomeActivitiesChanged = true;
}
ActivityThread#performStopActivityInner
/**
* Core implementation of stopping an activity. Note this is a little
* tricky because the server's meaning of stop is slightly different
* than our client -- for the server, stop means to save state and give
* it the result when it is done, but the window may still be visible.
* For the client, we want to call onStop()/onStart() to indicate when
* the activity's UI visibility changes.
* @param r Target activity client record.
* @param info Action that will report activity stop to server.
* @param keepShown Flag indicating whether the activity is still shown.
* @param saveState Flag indicating whether the activity state should be saved.
* @param finalStateRequest Flag indicating if this call is handling final lifecycle state
* request for a transaction.
* @param reason Reason for performing this operation.
*/
private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown,
boolean saveState, boolean finalStateRequest, String reason) {
if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
if (r != null) {
if (!keepShown && r.stopped) {
if (r.activity.mFinished) {
// If we are finishing, we won't call onResume() in certain
// cases. So here we likewise don't want to call onStop()
// if the activity isn't resumed.
return;
}
if (!finalStateRequest) {
final RuntimeException e = new RuntimeException(
"Performing stop of activity that is already stopped: "
+ r.intent.getComponent().toShortString());
Slog.e(TAG, e.getMessage(), e);
Slog.e(TAG, r.getStateString());
}
}
// One must first be paused before stopped...
performPauseActivityIfNeeded(r, reason);
if (info != null) {
try {
// First create a thumbnail for the activity...
// For now, don't create the thumbnail here; we are
// doing that by doing a screen snapshot.
info.setDescription(r.activity.onCreateDescription());
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to save state of activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
}
if (!keepShown) {
callActivityOnStop(r, saveState, reason);
}
}
}
ActivityThread#callActivityOnStop
/**
* Calls {@link Activity#onStop()} and {@link Activity#onSaveInstanceState(Bundle)}, and updates
* the client record's state.
* All calls to stop an activity must be done through this method to make sure that
* {@link Activity#onSaveInstanceState(Bundle)} is also executed in the same call.
*/
private void callActivityOnStop(ActivityClientRecord r, boolean saveState, String reason) {
// Before P onSaveInstanceState was called before onStop, starting with P it's
// called after. Before Honeycomb state was always saved before onPause.
final boolean shouldSaveState = saveState && !r.activity.mFinished && r.state == null
&& !r.isPreHoneycomb();
final boolean isPreP = r.isPreP();
if (shouldSaveState && isPreP) {
callActivityOnSaveInstanceState(r);
}
try {
r.activity.performStop(false /*preserveWindow*/, reason);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to stop activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
r.setState(ON_STOP);
if (shouldSaveState && !isPreP) {
callActivityOnSaveInstanceState(r);
}
}
activityIdleInternal相关的流程大致讲完了,还有一部分与finish Activity相关;在下面的章节再讲
startActivity.png
网友评论