WindowManagerService之窗口的创建

本次源码基于Android11分析

相关源码:

/frameworks/base/core/java/android/app/ActivityThread.java
/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
/frameworks/base/core/java/android/view/WindowManagerImpl.java
/frameworks/base/core/java/android/view/WindowManagerGlobal.java
/frameworks/base/core/java/android/view/ViewRootImpl.java
/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
/frameworks/base/services/core/java/com/android/server/wm/Session.java
/frameworks/base/services/core/java/com/android/server/wm/WindowState.java

本文以startActvity()为启点分析Window窗口的创建过程。

窗口的创建过程

1. Activity的onCreate阶段

public final class ActivityThread extends ClientTransactionHandler {

  public Activity handleLaunchActivity(ActivityClientRecord r,
                                       PendingTransactionActions pendingActions, Intent customIntent) {

      // 1.WindowManagerGlobal的初始化
      WindowManagerGlobal.initialize();
      // 2.启动Activity
      final Activity a = performLaunchActivity(r, customIntent);
      //...
      return a;
  }

  private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
      try {
          //...
          // 执行activity.attach(),初始化如PhoneWindow等
          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, r.configCallback,
                  r.assistToken);
          //...
          // 1. 执行Activity.onCreate()方法
          if (r.isPersistable()) {
              mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
          } else {
              mInstrumentation.callActivityOnCreate(activity, r.state);
          }
          //...

      } catch (SuperNotCalledException e) {
          throw e;
      }
      //...
      return activity;
  }

}

启动Activity的时候会通过反射创建Activity的实例,并执行Activity的attach()方法对一些变量进行初始化,比如PhoneWindow变量。

public class Activity extends ContextThemeWrapper
      implements LayoutInflater.Factory2,
      Window.Callback, KeyEvent.Callback,
      OnCreateContextMenuListener, ComponentCallbacks2,
      Window.OnWindowDismissedCallback,
      AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {

  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, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
      attachBaseContext(context);
      mFragments.attachHost(null /*parent*/);

      //创建PhoneWindow
      mWindow = new PhoneWindow(this, window, activityConfigCallback);
      mWindow.setWindowControllerCallback(mWindowControllerCallback);
      mWindow.setCallback(this);
      mWindow.setOnWindowDismissedCallback(this);
      mWindow.getLayoutInflater().setPrivateFactory(this);
      //...
      mUiThread = Thread.currentThread(); //获取UI线程
      mMainThread = aThread;
      mInstrumentation = instr;
      mToken = token; //远程ActivityRecord的appToken的代理端
      mAssistToken = assistToken;
      mIdent = ident;
      mApplication = application; //所属的Appplication
      mIntent = intent;
      mReferrer = referrer;
      mComponent = intent.getComponent();
      mActivityInfo = info;
      mTitle = title;
      mParent = parent;
      // ...
      //设置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());
      }
      // 获取WindowManagerImpl对象
      mWindowManager = mWindow.getWindowManager();
      mCurrentConfig = config;

      mWindow.setColorMode(info.colorMode);
      mWindow.setPreferMinimalPostProcessing(
              (info.flags & ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING) != 0);

      setAutofillOptions(application.getAutofillOptions());
      setContentCaptureOptions(application.getContentCaptureOptions());
  }

}

Activity.attach()执行在onCreate()方法之前,会实例化一个PhoneWindow

2. Activity的onResume阶段

class ActivityThread {

  // Activity的onResume
  @Override
  public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
                                   String reason) {
      //执行到onResume方法()
      final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);

      final Activity a = r.activity;

      if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
          // ...
          mNumVisibleActivities++;
          if (r.activity.mVisibleFromClient) {
              // 添加视图
              r.activity.makeVisible();
          }
      }
      //...
  }
}

public class Activity extends ContextThemeWrapper
      implements LayoutInflater.Factory2,
      Window.Callback, KeyEvent.Callback,
      OnCreateContextMenuListener, ComponentCallbacks2,
      Window.OnWindowDismissedCallback,
      AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {

  void makeVisible() {
      if (!mWindowAdded) {
          ViewManager wm = getWindowManager();
          // 向WindowManagerImpl添加DecorView
          wm.addView(mDecor, getWindow().getAttributes());
          mWindowAdded = true;
      }
      mDecor.setVisibility(View.VISIBLE);
  }
}

public final class WindowManagerImpl implements WindowManager {

  public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
      applyDefaultToken(params);
      // 调用WMG.addView方法
      mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
              mContext.getUserId());
  }
}

public final class WindowManagerGlobal {

  @UnsupportedAppUsage
  private final ArrayList<View> mViews = new ArrayList<View>();
  @UnsupportedAppUsage
  private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
  @UnsupportedAppUsage
  private final ArrayList<WindowManager.LayoutParams> mParams =
          new ArrayList<WindowManager.LayoutParams>();

  public void addView(View view, ViewGroup.LayoutParams params,
                      Display display, Window parentWindow, int userId) {
      ...
      final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;

      ViewRootImpl root;
      View panelParentView = null;
      //1. 创建ViewRootImpl
      root = new ViewRootImpl(view.getContext(), display);
      view.setLayoutParams(wparams);
      mViews.add(view);
      mRoots.add(root);
      mParams.add(wparams);

      try {
          // 2. 调用ViewRoot的setView()方法
          root.setView(view, wparams, panelParentView, userId);
      } catch (RuntimeException e) {
          //...
      }
  }
}

调用Activity.makeVisible()方法添加窗口视图,继而调用WindowManagerImpl.addView()->WindowManagerGlobal.addView()方法,在WMG中首先创建了ViewRootImpl的实例,并调用了ViewRootImpl.setView()方法。

public final class ViewRootImpl implements ViewParent,
      View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {

  public final Context mContext;
  final IWindowSession mWindowSession;
  Display mDisplay;
  final DisplayManager mDisplayManager;
  final String mBasePackageName;
  final int[] mTmpLocation = new int[2];
  final TypedValue mTmpValue = new TypedValue();
  final Thread mThread;
  final WindowLeaked mLocation;
  public final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
  final W mWindow;
  final Choreographer mChoreographer;

  // 构造函数,获取IWindowSession对象
  public ViewRootImpl(Context context, Display display) {
      // 1. 调用WindowManagerGlobal.getWindowSession()方法获取IWindowSession
      this(context, display, WindowManagerGlobal.getWindowSession(),
              false /* useSfChoreographer */);
  }

  public ViewRootImpl(Context context, Display display, IWindowSession session,
                      boolean useSfChoreographer) {
      mContext = context;
      //获取IWindowSession的代理类
      mWindowSession = session;
      mDisplay = display;
      mThread = Thread.currentThread();
      // 创建W对象
      mWindow = new W(this);
      mChoreographer = useSfChoreographer
              ? Choreographer.getSfInstance() : Choreographer.getInstance();
      ...
  }

  public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
                      int userId) {
      synchronized (this) {
          if (mView == null) {
              mView = view;
              requestLayout();
              try {
                  // 1. 调用Session.addToDisplayAsUser()方法
                  res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
                          getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
                          mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                          mAttachInfo.mDisplayCutout, inputChannel,
                          mTempInsets, mTempControls);
                  setFrame(mTmpFrame);
              } catch (RemoteException e) {
                  throw new RuntimeException("Adding window failed", e);
              } finally {
              }
          }
      }
  }
}

在ViewRootImpl的构造函数会调用WindowManagerGlobal.getWindowSession()方法获取Session实例,在ViewRootImpl的setView()方法中,会调用Session.addToDisplayAsUser()方法。

public final class WindowManagerGlobal {

  public static IWindowSession getWindowSession() {
      synchronized (WindowManagerGlobal.class) {
          if (sWindowSession == null) {
              try {
                  InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
                  //获取WMS的代理类
                  IWindowManager windowManager = getWindowManagerService();
                  //经过Binder调用,最终调用WMS.openSession()方法
                  sWindowSession = windowManager.openSession(
                          new IWindowSessionCallback.Stub() {
                              @Override
                              public void onAnimatorScaleChanged(float scale) {
                                  ValueAnimator.setDurationScale(scale);
                              }
                          });
              } catch (RemoteException e) {
                  throw e.rethrowFromSystemServer();
              }
          }
          return sWindowSession;
      }
  }

}

public class WindowManagerService extends IWindowManager.Stub
      implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {

  @Override
  public IWindowSession openSession(IWindowSessionCallback callback) {
      // this为WindowManagerService对象
      return new Session(this, callback);
  }

}

WindowManagerGlobal.getWindowSession()方法通过WMS. openSession()方法创建一个Session对象并返回。

class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {

  final WindowManagerService mService;

  public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs,
                                int viewVisibility, int displayId, int userId, Rect outFrame,
                                Rect outContentInsets, Rect outStableInsets,
                                DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
                                InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
      // 1. 调用WindowManagerService的addWindow()方法
      return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
              outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
              outInsetsState, outActiveControls, userId);
  }
}

最后ViewRootImpl.setView()方法通过WindowManagerService.addWindow()去处理

2.1 WMS.addView添加窗口

  public int addWindow(Session session, IWindow client, int seq,
                       LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
                       Rect outContentInsets, Rect outStableInsets,
                       DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
                       InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
                       int requestUserId) {
      int[] appOp = new int[1];

      // 1. 权限检查,调用phoneWindow.checkAddPermission()方法中
      int res = mPolicy.checkAddPermission(attrs.type, isRoundedCornerOverlay, attrs.packageName,
              appOp);
      if (res != WindowManagerGlobal.ADD_OKAY) {
          return res; // 检查不通过返回
      }
      ...
      synchronized (mGlobalLock) {
          if (!mDisplayReady) {
              throw new IllegalStateException("Display has not been initialialized");
          }

          // 2. 通过displayId来查找对应的DisplayContent
          final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);

          // DisplayContent为null则返回
          if (displayContent == null) {
              ProtoLog.w(WM_ERROR, "Attempted to add window to a display that does "
                      + "not exist: %d. Aborting.", displayId);
              return WindowManagerGlobal.ADD_INVALID_DISPLAY;
          }
          //...

          if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
              //  通过attrs.token获取到父窗口
              parentWindow = windowForClientLocked(null, attrs.token, false);
              // 父窗口为空则返回
              if (parentWindow == null) {
                  ProtoLog.w(WM_ERROR, "Attempted to add window with token that is not a window: "
                          + "%s.  Aborting.", attrs.token);
                  return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
              }
              if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
                      && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
                  ProtoLog.w(WM_ERROR, "Attempted to add window with token that is a sub-window: "
                          + "%s.  Aborting.", attrs.token);
                  return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
              }
          }

          if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
              ProtoLog.w(WM_ERROR,
                      "Attempted to add private presentation window to a non-private display.  "
                              + "Aborting.");
              return WindowManagerGlobal.ADD_PERMISSION_DENIED;
          }

          //...

          ActivityRecord activity = null;
          final boolean hasParent = parentWindow != null;
          // 3. 通过displayContent拿到WindowToken
          WindowToken token = displayContent.getWindowToken(
                  hasParent ? parentWindow.mAttrs.token : attrs.token);
          // 拿到父窗口的type
          final int rootType = hasParent ? parentWindow.mAttrs.type : type;

          boolean addToastWindowRequiresToken = false;

          if (token == null) {
              // 4. 有父窗口用父窗口的windowToken,没有则new一个
              if (hasParent) {
                  // Use existing parent window token for child windows.
                  token = parentWindow.mToken;
              } else {
                  final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
                  token = new WindowToken(this, binder, type, false, displayContent,
                          session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);
              }
          } else if (rootType >= FIRST_APPLICATION_WINDOW
                  && rootType <= LAST_APPLICATION_WINDOW) {
              // 获取ActivityRecord
              activity = token.asActivityRecord();
          }
          //....

          // 5. 创建WindowState对象,包含窗口的状态信息
          final WindowState win = new WindowState(this, session, client, token, parentWindow,
                  appOp[0], seq, attrs, viewVisibility, session.mUid, userId,
                  session.mCanAddInternalSystemWindow);
          // 6. 判断请求添加窗口的客户端是否死亡
          if (win.mDeathRecipient == null) {
              ProtoLog.w(WM_ERROR, "Adding window client %s"
                      + " that is dead, aborting.", client.asBinder());
              return WindowManagerGlobal.ADD_APP_EXITING;
          }
          if (win.getDisplayContent() == null) {
              ProtoLog.w(WM_ERROR, "Adding window to Display that has been removed.");
              return WindowManagerGlobal.ADD_INVALID_DISPLAY;
          }

          final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
          // 根据窗口的type对窗口的LayoutParams的一些成员变量进行修改
          displayPolicy.adjustWindowParamsLw(win, win.mAttrs, callingPid, callingUid);
          // 准备将窗口添加到系统中
          res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
          if (res != WindowManagerGlobal.ADD_OKAY) {
              return res;
          }
          //...

          // 7. 执行windowState.attach()方法
          win.attach();
          // 8. 将WindowState加入到mWindowMap
          mWindowMap.put(client.asBinder(), win);
          // 9. 将WindowState加入到相应的WindowToken
          win.mToken.addWindow(win);
          return res;
      }
  }

addWindow()方法很长,大体上可以分为首先做一些权限的判断,然后拿到WindowToken,之后对token进行一些判断,再创建WindowState,并执行WindowState.attach()方法,并把WindowState加入到对应的WindowToken。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容