美文网首页android之AMS学习攻克
Activity相关学习-启动(8)- activityIdle

Activity相关学习-启动(8)- activityIdle

作者: weiinter105 | 来源:发表于2019-01-18 19:35 被阅读0次

    前言

    前面说道,调用到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

    相关文章

      网友评论

        本文标题:Activity相关学习-启动(8)- activityIdle

        本文链接:https://www.haomeiwen.com/subject/cszudqtx.html