WindowManagerService學習

一、WMS服務初始化過程

  • SystemServer中創建WMS

frameworks/base/services/java/com/android/server/SystemServer.java

private void startOtherServices() {
    ... ...
    WindowManagerService wm = null;
    wm = WindowManagerService.main(context, inputManager,
        mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
             !mFirstBoot, mOnlyCore, new PhoneWindowManager());
    ServiceManager.addService(Context.WINDOW_SERVICE, wm);
    ... ...
    wm.displayReady();
    ... ...
    wm.systemReady();

}
  • WindowManagerService.main

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

  public static WindowManagerService main(final Context context, final InputManagerService im,
            final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
            WindowManagerPolicy policy) {
        //WMS 運行在"android.display"線程
        //DisplayThread 從Android 5.0開始,所有跟系統前景相關的操作都集中到這個線程類中。這個線程只能由WindowManager,DisplayManager和InputManager用來實時顯示相關的快速操作。
        DisplayThread.getHandler().runWithScissors(() ->
                sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
                        onlyCore, policy), 0);
        return sInstance;
    }

frameworks/base/core/java/android/os/Handler.java

/**
* One example of where you might want to use this method is when you just
* set up a Handler thread and need to perform some initialization steps on
* it before continuing execution.
*/

  public final boolean runWithScissors(final Runnable r, long timeout) {
        if (r == null) {
            throw new IllegalArgumentException("runnable must not be null");
        }
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout must be non-negative");
        }
        //如果當前線程和handler所在線程是同一線程,直接執行run
        if (Looper.myLooper() == mLooper) {
            r.run();
            return true;
        }
        //否者把這個runnable 放在handler 所在線程執行,當前線程等待直到這個runnable 執行完后被喚醒
        BlockingRunnable br = new BlockingRunnable(r);
        return br.postAndWait(this, timeout);
    }
private static final class BlockingRunnable implements Runnable {
  @Override
  public void run() {
        try {
             mTask.run();
        } finally {
             synchronized (this) {
                   mDone = true;
                   notifyAll();
               }
          }
     }

   public boolean postAndWait(Handler handler, long timeout) {
            if (!handler.post(this)) {
                return false;
            }

            synchronized (this) {
                if (timeout > 0) {
                    ... ...
                } else {
                    while (!mDone) {
                        try {
                            wait();
                        } catch (InterruptedException ex) {
                        }
                    }
                }
            }
            return true;
        }
}
  • WindowManagerService 構造函數
private WindowManagerService(Context context, InputManagerService inputManager,
            boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
            WindowManagerPolicy policy) {
            ... ...
            初始化PhoneWindowManager
            initPolicy();
 }
   private void initPolicy() {
       //運行在android.ui 線程
       UiThread.getHandler().runWithScissors(new Runnable() {
           @Override
           public void run() {
               WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
               //mPolicy為PhoneWindowManager
               mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
           }
       }, 0);
   }

這里跟前面一樣使用Handler.runWithScissors, 由于WindowManagerService是在"android.display"線程中運行, 而mPolicy.init
在"android.ui"線程中運行,"android.display"線程等待mPolicy.init執行完再被喚醒。

  • wm.displayReady
public void displayReady() {
    for (Display display : mDisplays) {
        displayReady(display.getDisplayId());
    }

    synchronized(mWindowMap) {
        final DisplayContent displayContent = getDefaultDisplayContentLocked();
        if (mMaxUiWidth > 0) {
            displayContent.setMaxUiWidth(mMaxUiWidth);
        }
        readForcedDisplayPropertiesLocked(displayContent);
        mDisplayReady = true;
    }

    try {
        mActivityManager.updateConfiguration(null);
    } catch (RemoteException e) {
    }

    synchronized(mWindowMap) {
        mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_TOUCHSCREEN);
        configureDisplayPolicyLocked(getDefaultDisplayContentLocked());
    }

    try {
        mActivityManager.updateConfiguration(null);
    } catch (RemoteException e) {
    }

    updateCircularDisplayMaskIfNeeded();
}
  • wm.systemReady
public void systemReady() {
    mPolicy.systemReady();
    //TaskSnapshotController android O 新增, 當app token不可見時對當前task截圖并放在緩存中,系統應用可以得到代表當前task狀態的截圖,并在他們自己的進程中繪制
    //當這個task可見后,顯示starting window 時用這個截圖的內容,可以使應用轉換更加敏捷
    mTaskSnapshotController.systemReady();
}

WMS初始化過程涉及進程關系如下:
(圖片來源^^: http://gityuan.com/2017/01/08/windowmanger/

WMS_Thread.PNG

二、關于Token

AMS中的Token是Binder對象,用于跨進程標識同一個Activity對象。WMS中的WindowToken用來標識與一個Activity對應的所有窗口。

1. Token 定義和創建

/frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java

    static class Token extends IApplicationToken.Stub {
        private final WeakReference<ActivityRecord> weakActivity;

        Token(ActivityRecord activity) {
            weakActivity = new WeakReference<>(activity);
        }
        //獲取ActivityRecord 對象
        private static ActivityRecord tokenToActivityRecordLocked(Token token) {
            if (token == null) {
                return null;
            }
            ActivityRecord r = token.weakActivity.get();
            if (r == null || r.getStack() == null) {
                return null;
            }
            return r;
        }

    }
    ... ...

    ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,...{
        ... ...
        appToken = new Token(this, service);
    }

2. Token對象傳遞
  • (1)在啟動一個Activity時會調用 ActivityStack 的startActivityLocked,在這里面調用 addAppToken 將AMS的Token 對象傳遞給WMS,然后WMS 根據這個Token對象創建 AppWindowToken。
  • (2)接下來ASS調用scheduleLaunchActivity將token傳給應用端的ActivityThread,此時應用端得到token的代理對象。
  • (3)Activity Resume過程中,添加視圖時ViewRootImpl.setView會調用WMS.addWindow將應用端的token代理對象傳給WMS,此時WMS得到token的Binder對象。

/frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

    final void startActivityLocked(ActivityRecord r, boolean newTask, boolean keepCurTransition,
            ActivityOptions options) {
        ... ...
        if (!newTask) {
            // If starting in an existing task, find where that is...
            boolean startIt = true;
            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                task = mTaskHistory.get(taskNdx);
                if (task.getTopActivity() == null) {
                    // All activities in task are finishing.
                    continue;
                }
                if (task == r.task) {
                    // Here it is!  Now, if this is not yet visible to the
                    // user, then just add it without starting; it will
                    // get started when the user navigates back to it.
                    if (!startIt) {
                        task.addActivityToTop(r);
                        r.putInHistory();
                        addConfigOverride(r, task);
                        ... ...
                }
            }
        }
    void addConfigOverride(ActivityRecord r, TaskRecord task) {
        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
        // TODO: VI deal with activity
        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
                task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,
                task.mResizeMode, r.isAlwaysFocusable(), task.isHomeTask(),
                r.appInfo.targetSdkVersion, r.mRotationAnimationHint);
        r.taskConfigOverride = task.mOverrideConfig;
    }
  • AMS跨Binder調用應用進程的scheduleLaunchActivity()將Token傳遞給上層應用進程,這時候應用端得到的是Token 代理對象。
    final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
            ... ...
            //app.thread 是 IApplicationThread 對象,服務端為應用進程中的ApplicationThread 
            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                    new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
                    task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                    newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
           ... ...
    }
  • 應用端添加窗口調用的ViewRootImpl的setView,跨進程將token對象再傳給WMS服務,這時候應用端傳的是Token 代理對象,
    WMS服務端得到的卻是Token對象,這樣就跟之前AMS addAppToken時傳過來的Token是同一個對象了。

/frameworks/base/core/java/android/view/ViewRootImpl.java

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        ... ...
        //mWindowSession IWindowSession對象,服務端是WMS中的 Session,在addToDisplay調用WMS的addWindow
        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
            getHostVisibility(), mDisplay.getDisplayId(),
            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
            mAttachInfo.mOutsets, mInputChannel);
        ... ...
    }

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
            ... ...
            WindowToken token = mTokenMap.get(attrs.token);
            ... ...
    }

三、StartingWindow

  • 點擊應用圖標時,啟動應用Activity之前,WMS會先啟動一個窗口StartingWindow用于過度。
startingwindow.jpg
  • StartingWindow啟動流程
Startingwindow.png
  • StartingWindow關閉流程
StartingWindowEnd.png

四、Activity窗口創建流程

AMS.png
  1. 啟動一個Activity時調用startActivityLocked

/frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

    final void startActivityLocked(ActivityRecord r, boolean newTask, boolean keepCurTransition,
            ActivityOptions options) {
        TaskRecord rTask = r.task;
        final int taskId = rTask.taskId;
        // mLaunchTaskBehind tasks get placed at the back of the task stack.
        if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
            insertTaskAtTop(rTask, r);
            //(1)將要打開Activity所在的task移到頂部
            mWindowManager.moveTaskToTop(taskId);
        }
        TaskRecord task = null;
        if (!newTask) {
            // If starting in an existing task, find where that is...
            boolean startIt = true;
            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                ... ...
                if (task == r.task) {
                    if (!startIt) {
                        if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
                                + task, new RuntimeException("here").fillInStackTrace());
                        task.addActivityToTop(r);
                        r.putInHistory();
                        //(2)在這里調用addAppToken 創建AppWindowToken對象
                        addConfigOverride(r, task);
                        if (VALIDATE_TOKENS) {
                            validateAppTokensLocked();
                        }
                        ActivityOptions.abort(options);
                        return;
                    }
                    }
                    break;
                } else if (task.numFullscreen > 0) {
                    startIt = false;
                }
            }
        }

        ... ...
        if (!isHomeStack() || numActivities() > 0) {
            // We want to show the starting preview window if we are
            // switching to a new task, or the next activity's process is
            // not currently running.
            boolean showStartingIcon = newTask;
            ProcessRecord proc = r.app;
            if (proc == null) {
                proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
            }
            if (proc == null || proc.thread == null) {
                showStartingIcon = true;
            }
            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                    "Prepare open transition: starting " + r);
            if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
                mWindowManager.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
                mNoAnimActivities.add(r);
            } else {
                //(3)設置Activity切換動畫類型,發送一個APP_TRANSITION_TIMEOUT的5s超時消息。
                mWindowManager.prepareAppTransition(newTask
                        ? r.mLaunchTaskBehind
                                ? TRANSIT_TASK_OPEN_BEHIND
                                : TRANSIT_TASK_OPEN
                        : TRANSIT_ACTIVITY_OPEN, keepCurTransition);
                mNoAnimActivities.remove(r);
            }
            addConfigOverride(r, task);
            ... ...
            if (r.mLaunchTaskBehind) {
                //(4)設置Activity可見性,什么情況下mLaunchTaskBehind???
                mWindowManager.setAppVisibility(r.appToken, true);
                ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
            } else if (SHOW_APP_STARTING_PREVIEW && doShow) {
                ActivityRecord prev = r.task.topRunningActivityWithStartingWindowLocked();
                ... ...
                //(5)顯示StartingWindow
                r.showStartingWindow(prev, showStartingIcon);
            }
        } 
        ... ...
    }
  • 下面依次介紹WMS 中的(1)~(5)

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

(1) moveTaskToTop

    public void moveTaskToTop(int taskId) {
        final long origId = Binder.clearCallingIdentity();
        try {
            synchronized(mWindowMap) {
                Task task = mTaskIdToTask.get(taskId);
                if (task == null) {
                    // Normal behavior, addAppToken will be called next and task will be created.
                    return;
                }
                final TaskStack stack = task.mStack;
                final DisplayContent displayContent = task.getDisplayContent();
                //將該task所屬的棧 移至display的頂部
                displayContent.moveStack(stack, true);
                if (displayContent.isDefaultDisplay) {
                    final TaskStack homeStack = displayContent.getHomeStack();
                    if (homeStack != stack) {
                        // 將home移到display的底部                
                        displayContent.moveStack(homeStack, false);
                    }
                }
                //將task移到棧頂
                stack.moveTaskToTop(task);
                if (mAppTransition.isTransitionSet()) {
                    task.setSendingToBottom(false);
                }
                //更新窗口布局
                moveStackWindowsLocked(displayContent);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

(2) addAppToken

    @Override
    public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
            int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
            int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
            Rect taskBounds, Configuration config, int taskResizeMode, boolean alwaysFocusable,
            boolean homeTask, int targetSdkVersion, int rotationAnimationHint) {
        ... ...

        synchronized(mWindowMap) {
            AppWindowToken atoken = findAppWindowToken(token.asBinder());
            if (atoken != null) {
                Slog.w(TAG_WM, "Attempted to add existing app token: " + token);
                return;
            }
            //創建AppWindowToken
            atoken = new AppWindowToken(this, token, voiceInteraction);
            atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
            atoken.appFullscreen = fullscreen;
            atoken.showForAllUsers = showForAllUsers;
            atoken.targetSdk = targetSdkVersion;
            atoken.requestedOrientation = requestedOrientation;
            atoken.layoutConfigChanges = (configChanges &
                    (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
            atoken.mLaunchTaskBehind = launchTaskBehind;
            atoken.mAlwaysFocusable = alwaysFocusable;
            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
                    + " to stack=" + stackId + " task=" + taskId + " at " + addPos);
            atoken.mRotationAnimationHint = rotationAnimationHint;
            //找到或者創建所在task
            Task task = mTaskIdToTask.get(taskId);
            if (task == null) {
                task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, config);
            }
            task.addAppToken(addPos, atoken, taskResizeMode, homeTask);
            //將AppWindowToken對象添加到mTokenMap中
            mTokenMap.put(token.asBinder(), atoken);

            // Application tokens start out hidden.
            atoken.hidden = true;
            atoken.hiddenRequested = true;
        }
    }

(3) prepareAppTransition 設置Activity動畫的類型和超時處理,真正執行動畫要在Activity Resumed狀態時,WMS 的executeAppTransition中。

    boolean prepareAppTransitionLocked(int transit, boolean alwaysKeepCurrent) {
        if (!isTransitionSet() || mNextAppTransition == TRANSIT_NONE) {
            // Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0 時設為TRANSIT_NONE
            setAppTransition(transit);
        } else if (!alwaysKeepCurrent) {
            if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
                // newTask時將mNextAppTransition設為TRANSIT_TASK_OPEN
                setAppTransition(transit);
            } else if (transit == TRANSIT_ACTIVITY_OPEN
                    && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) {
                // 將mNextAppTransition設為TRANSIT_ACTIVITY_OPEN
                setAppTransition(transit);
            }
        }
        boolean prepared = prepare();
        if (isTransitionSet()) {
            //5秒后被執行,是用來強制前面所設置的Activity組件切換動畫要在5秒之內執行完成的,否則的話,WindowManagerService服務就會認為該切換動畫執行超時了。
            mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
            mService.mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, APP_TRANSITION_TIMEOUT_MS);
        }
        return prepared;
    }

(4)后面再說 ,(5)StartingWindow流程圖見第三部分

startActivityLocked 主要完成了以下工作:
(1).將activity所在task移到頂部
(2).創建WindowToken并加到 WindowToken列表中
(3).設置activity切換動畫的相關參數
(4).開啟startingWindow

  1. Activity 進入onCreate和onResume階段會調用到 ActivityStack.resumeTopActivityInnerLocked
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
 ... ... 
        //如果目標進程已存在onResume,否則onCreate
        if (next.app != null && next.app.thread != null) {
            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next
                    + " stopped=" + next.stopped + " visible=" + next.visible);

            // If the previous activity is translucent, force a visibility update of
            // the next activity, so that it's added to WM's opening app list, and
            // transition animation can be set up properly.
            // For example, pressing Home button with a translucent activity in focus.
            // Launcher is already visible in this case. If we don't add it to opening
            // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a
            // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation.
            final boolean lastActivityTranslucent = lastStack != null
                    && (!lastStack.mFullscreen
                    || (lastStack.mLastPausedActivity != null
                    && !lastStack.mLastPausedActivity.fullscreen));

            //如果目標activity不可見之前的activity是半透明的, 那么使窗口可見
            if (!next.visible || next.stopped || lastActivityTranslucent) {
                mWindowManager.setAppVisibility(next.appToken, true);
            }
            ... ...
            try {
                ... ...

                // Well the app will no longer be stopped.
                // Clear app token stopped state in window manager if needed.
                mWindowManager.notifyAppResumed(next.appToken, next.stopped, allowSavedSurface);

                EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
                        System.identityHashCode(next), next.task.taskId, next.shortComponentName);

                next.sleeping = false;
                mService.showUnsupportedZoomDialogIfNeededLocked(next);
                mService.showAskCompatModeDialogLocked(next);
                next.app.pendingUiClean = true;
                next.app.forceProcessStateUpTo(mService.mTopProcessState);
                next.clearOptionsLocked();
                //activity進入onResume
                next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
                        mService.isNextTransitionForward(), resumeAnimOptions);

                mStackSupervisor.checkReadyForSleepLocked();

                if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed " + next);
            } 

        } else {
            // Whoops, need to restart this activity!
            if (!next.hasBeenLaunched) {
                next.hasBeenLaunched = true;
            } else {
                if (SHOW_APP_STARTING_PREVIEW) {
                    next.showStartingWindow(null, true);
                }
                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
            }
            if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next);
            //activity 進入attach 和onCreate流程
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }

        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        return true;
    }

第一次啟動進入onCreate流程,跨進程調用應用端ActivityThread.handleLaunchActivity

    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        ... ... 
        WindowManagerGlobal.initialize();

        Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
            ... ... 
        }
    }

WindowManagerGlobal 用于應用端和WMS通信,服務端是Session,WindowManagerGlobal.initialize() 直接調用getWindowManagerService

    public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
                try {
                    sWindowManagerService = getWindowManagerService();
                    ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowManagerService;
        }
    }

得到WMS 服務代理對象

再回到ActivityThread.handleLaunchActivity 函數,調用performLaunchActivity

/android/frameworks/base/core/java/android/app/ActivityThread.java

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");

        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            //創建LoadedApk對象
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
        //創建ComponentName 對象
        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }

        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }

        Activity activity = null;
        try {
            //反射創建Activity對象
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
            //創建Application 對象
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (r.overrideConfig != null) {
                    config.updateFrom(r.overrideConfig);
                }
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                Window window = null;
                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                //調用activity.attach
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                activity.mCalled = false;
                //這里回調Activity.onCreate
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ... ...
                if (!r.activity.mFinished) {
                    activity.mCalled = false;
                    //回調Activity.onPostCreate,onPostCreate Activity view 初始化完畢后調用,可以用來得到Activity中view的高寬等
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state,
                                r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state);
                    }
                }
            }

        return activity;
    }

performLaunchActivity 函數中主要創建了LoadedApk、ComponentName、Activity對象,
并回調onCreate 和 onResume.

  • Activity.attach
    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
        //創建PhoneWindow 對象,繼承Window ,成員變量W,作為服務端 和WMS 通信
        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
        if (info.uiOptions != 0) {
            mWindow.setUiOptions(info.uiOptions);
        }
        mUiThread = Thread.currentThread();//得到ui 主線程

        mMainThread = aThread; //獲取ActivityThread 對象
        mInstrumentation = instr;
        mToken = token;
        mIdent = ident;
        mApplication = application;
        mIntent = intent;
        mReferrer = referrer;
        mComponent = intent.getComponent();
        mActivityInfo = info;
        mTitle = title;
        mParent = parent;
        mEmbeddedID = id;
        mLastNonConfigurationInstances = lastNonConfigurationInstances;
        if (voiceInteractor != null) {
            if (lastNonConfigurationInstances != null) {
                mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
            } else {
                mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
                        Looper.myLooper());
            }
        }
        //獲得WindowManagerImpl對象
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    }

attach 函數中主要初始化各種變量:

  • PhoneWindow
  • ActivityThread
  • mUiThread
  • mToken
  • Window的WindowManagerImpl

再回到ActivityThread.handleLaunchActivity 函數,調用ActivityThread.handleResumeActivity

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        ... ...
        //回調onResume
        r = performResumeActivity(token, clearHide, reason);

        ... ...
            if (r.window == null && !a.mFinished && willBeVisible) {
                ... ...
                if (a.mVisibleFromClient && !a.mWindowAdded) {
                    a.mWindowAdded = true;
                    //添加DecorView
                    wm.addView(decor, l);
                }

            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
            } else if (!willBeVisible) {
                if (localLOGV) Slog.v(
                    TAG, "Launch " + r + " mStartedActivity set");
                r.hideForNow = true;
            }

            // Get rid of anything left hanging around.
            cleanUpPendingRemoveWindows(r, false /* force */);

            // The window is now visible if it has been added, we are not
            // simply finishing, and we are not starting another activity.
            if (!r.activity.mFinished && willBeVisible
                    && r.activity.mDecor != null && !r.hideForNow) {
                ... ...
                //添加視圖
                if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();
                }
            }

            ... ...

            // Tell the activity manager we have resumed.
            if (reallyResume) {
                try {
                    ActivityManagerNative.getDefault().activityResumed(token);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }

        } 
        ... ...
    }

  1. performResumeActivity回調onResume
  2. 添加DecorView
  3. r.activity.makeVisible()添加視圖
  4. ActivityManagerNative.getDefault().activityResumed 通知AMS activty已經resumed
  • Activity.makeVisible
    void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }

調用WindowManagerImpl 的 addView方法,然后再調用WindowManagerGlobal.addView

  • WindowManagerGlobal.addView

/frameworks/base/core/java/android/view/WindowManagerGlobal.java

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        ... ...

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            .. ...
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }

        // do this last because it fires off messages to start doing things
        try {
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            ... ...
    }

/frameworks/base/core/java/android/view/ViewRootImpl.java

    public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();// WMS 的Session對象的代理端
        mDisplay = display;
        mBasePackageName = context.getBasePackageName();
        mThread = Thread.currentThread();
        ... ...
        mWindow = new W(this);//W是服務端用于跟WMS 的WindowState 通信
        ... ...
        mChoreographer = Choreographer.getInstance();
    }

初始化mWindowSession 和 mWindow,建立應用和WMS之間的通信。

session.PNG
  • WindowManagerGlobal.getWindowSession

/frameworks/base/core/java/android/view/WindowManagerGlobal.java

    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    //sWindowSession 靜態變量,一個應用進程中所有ViewRootImpl 對象中mWindowSession 都引用相同對象,用于和WMS通信
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }

跨進程調用WMS的openSession

    @Override
    public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
            IInputContext inputContext) {
        if (client == null) throw new IllegalArgumentException("null client");
        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
        Session session = new Session(this, callback, client, inputContext);
        return session;
    }

應用端得到Session的代理對象

  • 回到WindowManagerGlobal.addView中的ViewRootImpl.setView
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        ... ... 
            try {

                res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                    getHostVisibility(), mDisplay.getDisplayId(),
                    mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                    mAttachInfo.mOutsets, mInputChannel);
            } 
        ... ... 
                   
    }
  • Session.addToDisplay直接調用WMS的addWindow
    /android/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
            ... ...
            //創建WindowState 對象
            WindowState win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
            ... ...
            //調整窗口屬性,例如截圖窗口不能獲得焦點
            mPolicy.adjustWindowParamsLw(win.mAttrs);
            ... ...
            win.attach();
            //以IWindow 代理對象作為key值
            mWindowMap.put(client.asBinder(), win);
            ... ...

            boolean focusChanged = false;
            if (win.canReceiveKeys()) {
                //如果能接受key事件,更新窗口焦點
                focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
                        false /*updateInputWindows*/);
                if (focusChanged) {
                    imMayMove = false;
                }
            }

    }

/frameworks/base/services/core/java/com/android/server/wm/WindowState.java

    WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
           WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
           int viewVisibility, final DisplayContent displayContent) {
        mService = service;
        mSession = s;//Session Binder 對象的服務端
        mClient = c;//W Binder 對象的客戶端
        mAppOp = appOp;
        mToken = token;
        mOwnerUid = s.mUid;
        ... ...
        mContext = mService.mContext;
        //應用死掉后回調DeathRecipient
        DeathRecipient deathRecipient = new DeathRecipient();
        mSeq = seq;
        mEnforceSizeCompat = (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
        if (WindowManagerService.localLOGV) Slog.v(
            TAG, "Window " + this + " client=" + c.asBinder()
            + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
        try {
            //c在應用進程
            c.asBinder().linkToDeath(deathRecipient, 0);
        } 

     }

    void attach() {
        if (WindowManagerService.localLOGV) Slog.v(
            TAG, "Attaching " + this + " token=" + mToken
            + ", list=" + mToken.windows);
        mSession.windowAddedLocked();
    }
    void windowAddedLocked() {
        if (mSurfaceSession == null) {
            if (WindowManagerService.localLOGV) Slog.v(
                TAG_WM, "First window added to " + this + ", creating SurfaceSession");
            mSurfaceSession = new SurfaceSession();
            if (SHOW_TRANSACTIONS) Slog.i(
                    TAG_WM, "  NEW SURFACE SESSION " + mSurfaceSession);
            //將當前Session對象添加到WMS Sessions 列表中
            mService.mSessions.add(this);
            if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
                mService.dispatchNewAnimatorScaleLocked(this);
            }
        }
        mNumWindow++;
    }
  • WMS.updateFocusedWindowLocked
    boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
        //計算當前獲得focus的窗口
        WindowState newFocus = computeFocusedWindowLocked();
        ... ...

            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);

            if (imWindowChanged && oldFocus != mInputMethodWindow) {
                // Focus of the input method window changed. Perform layout if needed.
                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
                    mWindowPlacerLocked.performLayoutLockedInner(displayContent, true /*initial*/,
                            updateInputWindows);
                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
                    // Client will do the layout, but we need to assign layers
                    // for handleNewWindowLocked() below.
                    mLayersController.assignLayersLocked(displayContent.getWindowList());
                }
            }

            if ((focusChanged & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
                // The change in focus caused us to need to do a layout.  Okay.
                displayContent.layoutNeeded = true;
                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
                    //焦點改變重新計算窗口大小
                    mWindowPlacerLocked.performLayoutLockedInner(displayContent, true /*initial*/,
                            updateInputWindows);
                }
            }
       }

/android/frameworks/base/services/core/java/com/android/server/wm/WindowSurfacePlacer.java

   final void performLayoutLockedInner(final DisplayContent displayContent,
           boolean initial, boolean updateInputWindows) {
       ... ...
       //設置屏幕大小
       mService.mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mService.mRotation,
               mService.mCurConfiguration.uiMode);
        ... ...

        for (i = topAttached; i >= 0; i--) {
            final WindowState win = windows.get(i);

            if (win.mLayoutAttached) {
                ... ...
                    win.mLayoutNeeded = false;
                    win.prelayout();
                    //計算各層窗口大小
                    mService.mPolicy.layoutWindowLw(win, win.mAttachedWindow);
                    win.mLayoutSeq = seq;
                }
            } else if (win.mAttrs.type == TYPE_DREAM) {
                attachedBehindDream = behindDream;
            }
        }
        ... ...
        //執行清理工作
        mService.mPolicy.finishLayoutLw();
        mService.mH.sendEmptyMessage(UPDATE_DOCKED_STACK_DIVIDER);
    }
  • 總結

Activity窗口啟動流程

  1. 調用startActivity進入Activity生命周期之前主要完成了以下工作:

(1).將activity所在task移到頂部

(2).創建WindowToken并加到 WindowToken列表中

(3).設置activity切換動畫的相關參數

(4).開啟startingWindow

  1. 進入Activity的attach、onCreate、onResume

(1) 創建LoadedApk、ComponentName、Activity對象

(2) 在attach 函數中初始化變量:PhoneWindow, ActivityThread, mUiThread, mToken, Window的WindowManagerImpl

(3) 執行performResumeActivity,回調onResume,添加DecorView, r.activity.makeVisible()添加視圖

(4)創建 ViewRootImpl對象,ViewRootImpl中創建IWindow的服務端對象和IWindowSession的代理對象,用于應用和WMS之前通信,一個應用進程中所有ViewRootImpl 對象中的IWindowSession代理對象都引用相同對象。

(5)最后調用WMS.addWindow 計算和添加窗口。

五、主要類關系圖

all.PNG

參考博客

  1. http://gityuan.com/2017/01/08/windowmanger/
  2. http://blog.csdn.net/guoqifa29/article/details/46819377
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,844評論 2 372

推薦閱讀更多精彩內容