Android14 WMS-窗口添加流程(一)-Client端

      窗口布局在onCreate方法中通过setContentView(R.layout.xxx)加载,但窗口的显示并不是在wm_on_create_called中, 而是在wm_on_resume_called后,也就是说应用onResume时此窗口是不可见的,真正可见是当此window窗口的mDrawState变化状态从NO_SURFACE -> DRAW_PENDING -> COMMIT_DRAW_PENDING  -> HAS_DRAWN-> READY_TO_SHOW,然后才会将图层置为可见状态,这个在后面会讲解到。设置为可见的log如下:

05-25 10:56:31.956  1915  1973 V WindowManager: performShow on Window{f4647f5 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: mDrawState=READY_TO_SHOW readyForDisplay=true starting=false during animation: policyVis=true parentHidden=false tok.visibleRequested=true tok.visible=true animating=false tok animating=false Callers=com.android.server.wm.WindowState.performShowLocked:4372 com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked:256 com.android.server.wm.DisplayContent.lambda$new$8:1082 com.android.server.wm.DisplayContent.$r8$lambda$NJwM1ysKPNyOazqyI2QXlp2I4yA:0 
05-25 10:56:31.962  1915  1973 V WindowManager: Showing Window{f4647f5 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: mDrawState=READY_TO_SHOW readyForDisplay=true starting=false during animation: policyVis=true parentHidden=false tok.visibleRequested=true tok.visible=true animating=true tok animating=false Callers=com.android.server.wm.WindowState.performShowLocked:4387 com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked:256 com.android.server.wm.DisplayContent.lambda$new$8:1082 com.android.server.wm.DisplayContent.$r8$lambda$NJwM1ysKPNyOazqyI2QXlp2I4yA:0


1. ActivityThread#handleResumeActivity

Activity启动时一开始都是置为不可见INVISIBLE的,然后才置为可见VISIBLE。
ActivityThread.java - OpenGrok cross reference for /frameworks/base/core/java/android/app/ActivityThread.java

    @Overridepublic void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,boolean isForward, boolean shouldSendCompatFakeFocus, String reason) {// If we are getting ready to gc after going to the background, well// we are back active so skip it.unscheduleGcIdler();mSomeActivitiesChanged = true;// TODO Push resumeArgs into the activity for consideration// skip below steps for double-resume and r.mFinish = true case.
//这个是activity resume很重要的一步,会调用到activity本身的onResume方法,后面会做详细解释if (!performResumeActivity(r, finalStateRequest, reason)) {return;}
//如果mActivitiesToBeDestroyed集合包含此acitivity,则不往下执行resume操作。
//mActivitiesToBeDestroyed是即将 要销毁的activity集合if (mActivitiesToBeDestroyed.containsKey(r.token)) {// Although the activity is resumed, it is going to be destroyed. So the following// UI operations are unnecessary and also prevents exception because its token may// be gone that window manager cannot recognize it. All necessary cleanup actions// performed below will be done while handling destruction.return;}final Activity a = r.activity;if (localLOGV) {Slog.v(TAG, "Resume " + r + " started activity: " + a.mStartedActivity+ ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished);}
...
//如果这个window没有被add进window manager,并且这个activity没有执行finish操作,或者启动其他activity,则首先要将此window添加进window manager中。boolean willBeVisible = !a.mStartedActivity;if (!willBeVisible) {willBeVisible = ActivityClient.getInstance().willActivityBeVisible(a.getActivityToken());}
//这里代表这是首次启动这个activity
//如果window为空,并且不要执行finish,并且申请可见,则进入如下逻辑if (r.window == null && !a.mFinished && willBeVisible) {r.window = r.activity.getWindow();View decor = r.window.getDecorView();
//先将根布局设置为不可见decor.setVisibility(View.INVISIBLE);
//获取当前window manager对象ViewManager wm = a.getWindowManager();
//获取当前window属性WindowManager.LayoutParams l = r.window.getAttributes();a.mDecor = decor;
//将window type类型设置为普通APP类型l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;l.softInputMode |= forwardBit;if (r.mPreserveWindow) {a.mWindowAdded = true;r.mPreserveWindow = false;// Normally the ViewRoot sets up callbacks with the Activity// in addView->ViewRootImpl#setView. If we are instead reusing// the decor view we have to notify the view root that the// callbacks may have changed.
//获取ViewRootImplViewRootImpl impl = decor.getViewRootImpl();if (impl != null) {impl.notifyChildRebuilt();}}if (a.mVisibleFromClient) {if (!a.mWindowAdded) {a.mWindowAdded = true;
//如果此window没有被add进window manager过,则将此根view(decor)add进window manager中wm.addView(decor, l);} else {// The activity will get a callback for this {@link LayoutParams} change// earlier. However, at that time the decor will not be set (this is set// in this method), so no action will be taken. This call ensures the// callback occurs with the decor set.a.onWindowAttributesChanged(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) {//如果这个activity已经被add进window manager过了,并且在resume期间又起了其他activity,那么我们就不会将这个window设置为可见if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
//设置立即hide的flag为truer.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.
//这里代表这个activity已经被添加进window manager了,并非首次启动if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward);
//获取ViewRootImplViewRootImpl impl = r.window.getDecorView().getViewRootImpl();
//获取窗口属性WindowManager.LayoutParams l = impl != null? impl.mWindowAttributes : r.window.getAttributes();if ((l.softInputMode& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)!= forwardBit) {l.softInputMode = (l.softInputMode& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))| forwardBit;if (r.activity.mVisibleFromClient) {ViewManager wm = a.getWindowManager();View decor = r.window.getDecorView();wm.updateViewLayout(decor, l);}}r.activity.mVisibleFromServer = true;mNumVisibleActivities++;if (r.activity.mVisibleFromClient) {r.activity.makeVisible();}
...}

 这块大概的流程图如上所示,在执行handleResumeActivity的时候,会先去执行activity的onResume方法,然后再将当前的window add进window manager。

这块有个地方拓展下,就是窗口类型,普通apk启动的窗口类型都是TYPE_BASE_APPLICATION

            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

Android系统三大窗口类型

Android系统中共有三大窗口类型,分别是Application类型, 子窗口类型,以及系统窗口类型:

窗口类型Vlaue含义
以下窗口类型为普通APPLICAT窗口类型,范围1-99
FIRST_APPLICATION_WINDOW 1App的初始值
TYPE_BASE_APPLICATION1所有App的基础值
TYPE_APPLICATION2普通应用程序窗口
TYPE_APPLICATION_STARTING3starting窗口
TYPE_DRAWN_APPLICATION4等待绘制完成的窗口
LAST_APPLICATION_WINDOW 99App的最大值
以下窗口类型为子窗口类型,范围1000-1999
FIRST_SUB_WINDOW 1000子窗口的初始值
TYPE_APPLICATION_PANELFIRST_SUB_WINDOW 应用程序窗口顶部的面板。这些窗口出现在它们的附属窗口的顶部。
TYPE_APPLICATION_MEDIAFIRST_SUB_WINDOW +1media子窗口
TYPE_APPLICATION_SUB_PANELFIRST_SUB_WINDOW +2子窗口之上的子窗口

TYPE_APPLICATION_ATTACHED

_DIALOG

FIRST_SUB_WINDOW +3Dialog子窗口

TYPE_APPLICATION_MEDIA

_OVERLAY

FIRST_SUB_WINDOW +4media子窗口之上的子窗口

TYPE_APPLICATION_ABOVE_

SUB_PANEL

FIRST_SUB_WINDOW +5在SUB_PANEL之上的子窗口
LAST_SUB_WINDOW 1999子窗口的最大值
以下为系统窗口类型,范围2000-2999
FIRST_SYSTEM_WINDOW2000系统窗口的初始值
TYPE_STATUS_BARFIRST_SYSTEM_WINDOW系统状态栏窗口
TYPE_SEARCH_BARFIRST_SYSTEM_WINDOW+1搜索条窗口
TYPE_PHONEFIRST_SYSTEM_WINDOW+2通话窗口,位于状态栏之上
TYPE_SYSTEM_ALERTFIRST_SYSTEM_WINDOW+3Alert窗口,如电量不足提示,显示在APP之上窗口
TYPE_KEYGUARDFIRST_SYSTEM_WINDOW+4锁屏窗口
TYPE_TOASTFIRST_SYSTEM_WINDOW+5短暂的提示框窗口
TYPE_SYSTEM_OVERLAYFIRST_SYSTEM_WINDOW+6系统覆盖窗口,不能接受input焦点,否则会与屏保发生冲突
TYPE_PRIORITY_PHONEFIRST_SYSTEM_WINDOW+7电话优先窗口,如屏保状态下显示来电窗口
TYPE_SYSTEM_DIALOGFIRST_SYSTEM_WINDOW+8系统Dialog窗口
TYPE_KEYGUARD_DIALOGFIRST_SYSTEM_WINDOW+9keyguard Dialog窗口
TYPE_SYSTEM_ERRORFIRST_SYSTEM_WINDOW+10系统报错窗口
TYPE_INPUT_METHODFIRST_SYSTEM_WINDOW+11输入法窗口
TYPE_INPUT_METHOD_DIALOGFIRST_SYSTEM_WINDOW+12输入法Dialog窗口
TYPE_WALLPAPERFIRST_SYSTEM_WINDOW+13壁纸窗口
TYPE_STATUS_BAR_PANELFIRST_SYSTEM_WINDOW+14从状态栏滑出的面板在多用户系统中显示在所有用户的窗口上。

TYPE_SECURE_SYSTEM_OVERLAY

FIRST_SYSTEM_WINDOW+15@hide
TYPE_DRAGFIRST_SYSTEM_WINDOW+16@hide拖拽窗口

TYPE_STATUS_BAR_SUB_PANEL

FIRST_SYSTEM_WINDOW+17@hide,status bar之上的子窗口
TYPE_POINTERFIRST_SYSTEM_WINDOW+18@hide
TYPE_NAVIGATION_BARFIRST_SYSTEM_WINDOW+19@hide导航栏窗口
TYPE_VOLUME_OVERLAYFIRST_SYSTEM_WINDOW+20@hide系统音量条
TYPE_BOOT_PROGRESSFIRST_SYSTEM_WINDOW+21@hide启动时的进度条窗口
TYPE_INPUT_CONSUMERFIRST_SYSTEM_WINDOW+22@hide消耗input事件的窗口
TYPE_NAVIGATION_BAR_PANELFIRST_SYSTEM_WINDOW+24@hide
TYPE_DISPLAY_OVERLAYFIRST_SYSTEM_WINDOW+26@hide用于模拟第二个Display显示屏
TYPE_MAGNIFICATION_OVERLAYFIRST_SYSTEM_WINDOW+27@hide
TYPE_PRIVATE_PRESENTATIONFIRST_SYSTEM_WINDOW+30
TYPE_VOICE_INTERACTIONFIRST_SYSTEM_WINDOW+31@hide
TYPE_ACCESSIBILITY_OVERLAYFIRST_SYSTEM_WINDOW+32

TYPE_VOICE_INTERACTION_STARTING

FIRST_SYSTEM_WINDOW+33@hide
TYPE_DOCK_DIVIDERFIRST_SYSTEM_WINDOW+34@hide
TYPE_QS_DIALOGFIRST_SYSTEM_WINDOW+35@hide
TYPE_SCREENSHOTFIRST_SYSTEM_WINDOW+36@hide在锁屏之上,该层保留截图动画,区域选择和UI。
TYPE_PRESENTATIONFIRST_SYSTEM_WINDOW+37@hide用于在外部显示器上显示的窗口(多个屏幕情况下)
TYPE_APPLICATION_OVERLAYFIRST_SYSTEM_WINDOW+38

TYPE_ACCESSIBILITY_MAGNIFICATION

_OVERLAY

FIRST_SYSTEM_WINDOW+39@hide
TYPE_NOTIFICATION_SHADEFIRST_SYSTEM_WINDOW+40@hide
TYPE_STATUS_BAR_ADDITIONALFIRST_SYSTEM_WINDOW+41@hide
LAST_SYSTEM_WINDOW2999系统窗口的最大值

 1.1. ActivityThread#performResumeActivity

    @VisibleForTestingpublic boolean performResumeActivity(ActivityClientRecord r, boolean finalStateRequest,String reason) {if (localLOGV) {Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished);}
//如果activity将要finish,则直接return掉,不执行resume操作了if (r.activity.mFinished) {return false;}
//如果activity已经on_resume了,则不继续往下执行,returnif (r.getLifecycleState() == ON_RESUME) {if (!finalStateRequest) {final RuntimeException e = new IllegalStateException("Trying to resume activity which is already resumed");
...}return false;}
...
//执行activity的onResume操作r.activity.performResume(r.startsNotResumed, reason);r.state = null;r.persistentState = null;
//设置activity状态为on_resumer.setState(ON_RESUME);
//将会打印出event log---wm_on_top_resumed_gained_called相关信息reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming");} catch (Exception e) {if (!mInstrumentation.onException(r.activity, e)) {throw new RuntimeException("Unable to resume activity "+ r.intent.getComponent().toShortString() + ": " + e.toString(), e);}}return true;}

本小节介绍了activity启动过程中其他的知识,下文再继续接着讲怎么添加窗口流程的,下面接着1.1中的addView方法。

2. WindowManager#addView

wm的获取方法如下,可以看到最后是获得到了一个WindowManager对象,

    private WindowManager mWindowManager;public WindowManager getWindowManager() {return mWindowManager;}

那就来到了WindowManager中的addView方法

查看WindowManager中没有addView方法,但是ViewManager中有,那我们再看下谁实现了WindowManager呢

public interface WindowManager extends ViewManager {
-------------------------------------------------------------
public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

可找到是WindowManagerImpl中实现此addView方法,因为WindowManagerImpl继承了WindowManager:

/** @see WindowManager* @see WindowManagerGlobal* @hide*/
public final class WindowManagerImpl implements WindowManager {
...@Overridepublic void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {applyTokens(params);mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,mContext.getUserId());}

此方法又调用了 WindowManagerGlobal中的addView方法,并将view,窗口属性,要显示的屏幕,父window,以及user id传入

WindowManagerGlobal.java - OpenGrok cross reference for /frameworks/base/core/java/android/view/WindowManagerGlobal.java

    public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow, int userId) {if (view == null) {throw new IllegalArgumentException("view must not be null");}if (display == null) {throw new IllegalArgumentException("display must not be null");}if (!(params instanceof WindowManager.LayoutParams)) {throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");}
//获取窗口布局属性final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;if (parentWindow != null) {
//如果父窗口不为空,则调整当前父窗口下所有子窗口布局的属性parentWindow.adjustLayoutParamsForSubWindow(wparams);} else {// If there's no parent, then hardware acceleration for this view is// set from the application's hardware acceleration setting.final Context context = view.getContext();if (context != null&& (context.getApplicationInfo().flags& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;}}ViewRootImpl root;View panelParentView = null;synchronized (mLock) {// Start watching for system property changes.if (mSystemPropertyUpdater == null) {mSystemPropertyUpdater = new Runnable() {@Override public void run() {synchronized (mLock) {for (int i = mRoots.size() - 1; i >= 0; --i) {mRoots.get(i).loadSystemProperties();}}}};SystemProperties.addChangeCallback(mSystemPropertyUpdater);}int index = findViewLocked(view, false);if (index >= 0) {if (mDyingViews.contains(view)) {// Don't wait for MSG_DIE to make it's way through root's queue.mRoots.get(index).doDie();} else {throw new IllegalStateException("View " + view+ " has already been added to the window manager.");}// The previous removeView() had not completed executing. Now it has.}// If this is a panel window, then find the window it is being// attached to for future reference.
//如果是子窗口if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {final int count = mViews.size();for (int i = 0; i < count; i++) {if (mRoots.get(i).mWindow.asBinder() == wparams.token) {panelParentView = mViews.get(i);}}}IWindowSession windowlessSession = null;// If there is a parent set, but we can't find it, it may be coming// from a SurfaceControlViewHost hierarchy.
//如果token不为空并且不是子窗口if (wparams.token != null && panelParentView == null) {for (int i = 0; i < mWindowlessRoots.size(); i++) {ViewRootImpl maybeParent = mWindowlessRoots.get(i);if (maybeParent.getWindowToken() == wparams.token) {
//获取WindowSessionwindowlessSession = maybeParent.getWindowSession();break;}}}if (windowlessSession == null) {
//如果windowlessSession为空root = new ViewRootImpl(view.getContext(), display);} else {
//如果windowlessSession不为空,则在此处传入windowlessSessionroot = new ViewRootImpl(view.getContext(), display,windowlessSession, new WindowlessWindowLayout());}
//将窗口布局属性设置进viewview.setLayoutParams(wparams);
//将此view添加进mViewsmViews.add(view);
//将此root添加进MRootsmRoots.add(root);
//将此窗口布局属性添加进mParamsmParams.add(wparams);// do this last because it fires off messages to start doing thingstry {
//将view,窗口属性和子窗口,user id 设置进ViewRootImplroot.setView(view, wparams, panelParentView, userId);} catch (RuntimeException e) {final int viewIndex = (index >= 0) ? index : (mViews.size() - 1);// BadTokenException or InvalidDisplayException, clean up.if (viewIndex >= 0) {removeViewLocked(viewIndex, true);}throw e;}}}

3. ViewRootImpl#setView

然后就从WindowManagerGlobal走到了ViewRootImpl中

http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/view/ViewRootImpl.java#1214

    final IWindowSession mWindowSession;public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {setView(view, attrs, panelParentView, UserHandle.myUserId());}public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {synchronized (this) {
//这个mView和上一个方法中的可不一样,当窗口detach后,这个mView会被置为空if (mView == null) {mView = view;
...mWindowAttributes.copyFrom(attrs)
...// Schedule the first layout -before- adding to the window// manager, to make sure we do the relayout before receiving// any other events from the system.
//首先需要layoutrequestLayout();
...
//这个是很重要的一步res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(), userId,mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets, mTempControls, attachedFrame, compatScale);
...mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars;mInsetsController.onStateChanged(mTempInsets);mInsetsController.onControlsChanged(mTempControls.get());final InsetsState state = mInsetsController.getState();final Rect displayCutoutSafe = mTempRect;state.getDisplayCutoutSafe(displayCutoutSafe);final WindowConfiguration winConfig = getCompatWindowConfiguration();mWindowLayout.computeFrames(mWindowAttributes, state,displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,mInsetsController.getRequestedVisibleTypes(), 1f /* compactScale */, mTmpFrames);setFrame(mTmpFrames.frame, true /* withinRelayout */);
...}

接着往下走,就会讲到WindowSession.addToDisplayAsUser方法

4. WindowSession.addToDisplayAsUser

这里是涉及到AIDL通信,因为mWindowSession是final IWindowSession mWindowSession;

用到的AIDL文件如下:

frameworks/base/core/java/android/view/IWindowSession.aidl

http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/view/IWindowSession.aidl

 在Client端,WindowlessWindowManager实现了IWindowSession

public class WindowlessWindowManager implements IWindowSession {
    /*** IWindowSession implementation. Currently this class doesn't need to support for multi-user.*/@Overridepublic int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,int viewVisibility, int displayId, int userId, @InsetsType int requestedVisibleTypes,InputChannel outInputChannel, InsetsState outInsetsState,InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,float[] outSizeCompatScale) {return addToDisplay(window, attrs, viewVisibility, displayId, requestedVisibleTypes,outInputChannel, outInsetsState, outActiveControls, outAttachedFrame,outSizeCompatScale);}@Overridepublic int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,int viewVisibility, int displayId, @InsetsType int requestedVisibleTypes,InputChannel outInputChannel, InsetsState outInsetsState,InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,float[] outSizeCompatScale) {
// setParent方法作用如下
// Set a parent surface for our new SurfaceControl.
// 给我们的new SurfaceControl设置父surface
// Child surfaces are constrained to the onscreen region of their parent.
//子surfaces被限制在它们的父surface之上
// Furthermore they stack relatively in Z order, and inherit the transformation of the parent.
//此外这些stack按照Z值排序,并继承父级的transformation //window leash 图层创建final SurfaceControl leash = new SurfaceControl.Builder(mSurfaceSession).setName(attrs.getTitle().toString() + "Leash").setCallsite("WindowlessWindowManager.addToDisplay").setParent(getParentSurface(window, attrs)).build();
//window图层创建final SurfaceControl sc = new SurfaceControl.Builder(mSurfaceSession).setFormat(attrs.format).setBLASTLayer().setName(attrs.getTitle().toString()).setCallsite("WindowlessWindowManager.addToDisplay").setHidden(false).setParent(leash).build();
//在当前文件的最上面有State的定义,主要就是将入参赋值给State的全局变量final State state = new State(sc, attrs, displayId, window, leash, /* frame= */ new Rect());synchronized (this) {State parentState = mStateForWindow.get(attrs.token);if (parentState != null) {state.mAttachedFrame = parentState.mFrame;}// Give the first window the mFocusGrantToken since that's the token the host can use// to give focus to the embedded.if (mStateForWindow.isEmpty()) {state.mFocusGrantToken = mFocusGrantToken;} else {state.mFocusGrantToken = new Binder();}mStateForWindow.put(window.asBinder(), state);}if (state.mAttachedFrame == null) {outAttachedFrame.set(0, 0, -1, -1);} else {outAttachedFrame.set(state.mAttachedFrame);}outSizeCompatScale[0] = 1f;if (((attrs.inputFeatures &WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) {try {if (mRealWm instanceof IWindowSession.Stub) {mRealWm.grantInputChannel(displayId,new SurfaceControl(sc, "WindowlessWindowManager.addToDisplay"),window, mHostInputToken, attrs.flags, attrs.privateFlags,attrs.inputFeatures, attrs.type,attrs.token, state.mFocusGrantToken, attrs.getTitle().toString(), outInputChannel);} else {mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags, attrs.privateFlags, attrs.inputFeatures, attrs.type, attrs.token,state.mFocusGrantToken, attrs.getTitle().toString(), outInputChannel);}state.mInputChannelToken =outInputChannel != null ? outInputChannel.getToken() : null;} catch (RemoteException e) {Log.e(TAG, "Failed to grant input to surface: ", e);}}final int res = WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE |WindowManagerGlobal.ADD_FLAG_USE_BLAST;// Include whether the window is in touch mode.return isInTouchModeInternal(displayId) ? res | WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE: res;}

这里我们来看一下mRealWm的赋值过程

public class WindowlessWindowManager implements IWindowSession {...
//全局变量声明private final IWindowSession mRealWm;public WindowlessWindowManager(Configuration c, SurfaceControl rootSurface,IBinder hostInputToken) {mRootSurface = rootSurface;mConfiguration = new Configuration(c);
//赋值 mRealWm = WindowManagerGlobal.getWindowSession();mHostInputToken = hostInputToken;}

然后就走到了WindowManagerGlobal这里去获取WindowSession

WindowManagerGlobal.java - OpenGrok cross reference for /frameworks/base/core/java/android/view/WindowManagerGlobal.java

    @UnsupportedAppUsagepublic static IWindowSession getWindowSession() {synchronized (WindowManagerGlobal.class) {if (sWindowSession == null) {try {
// Emulate the legacy behavior.  The global instance of InputMethodManager
// was instantiated here.
// TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsageInputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
//第一步IWindowManager windowManager = getWindowManagerService();
//第二步sWindowSession = windowManager.openSession(new IWindowSessionCallback.Stub() {@Overridepublic void onAnimatorScaleChanged(float scale) {ValueAnimator.setDurationScale(scale);}});} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}return sWindowSession;}}

 在第一步中,通过getWindowManagerService方法获取了server端binder对象,即获取了WMS服务, 看代码是单例模式,可以看出来这个sWindowSession是一个单例,也就是一个应用的所有ViewRootImpl的WindowSession都是同一个,也就是一个应用只有一个WindowSession,用于与WMS进行通信。

    @UnsupportedAppUsagepublic static IWindowManager getWindowManagerService() {synchronized (WindowManagerGlobal.class) {if (sWindowManagerService == null) {
//获取server端binder对象,即获取WMS服务sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
...return sWindowManagerService;}}

在第二步中,则调用到了Server端服务WMS中的方法,这里也是单例模式的写法,sWindowManagerService 在Client端也只有一个对象。

WindowManagerService.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    @Override
    public IWindowSession openSession(IWindowSessionCallback callback) {return new Session(this, callback);}

然后在WMS中new了一个Session,Session实例化相关如下 

Session.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/Session.java

class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {final WindowManagerService mService;final IWindowSessionCallback mCallback;final int mUid;final int mPid;...
    public Session(WindowManagerService service, IWindowSessionCallback callback) {mService = service;mCallback = callback;mUid = Binder.getCallingUid();mPid = Binder.getCallingPid();
...

来看看WMS,其实也是继承了 IWindowSession.Stub

/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {

从上我们总结出:

一个应用只有一个WindowSession, 用于与WMS进行通信。

5. Session#grantInputChannel

接着讲上文中的 grantInputChannel方法

Session.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/Session.java

    @Overridepublic void grantInputChannel(int displayId, SurfaceControl surface,IWindow window, IBinder hostInputToken, int flags, int privateFlags, int type, int inputFeatures, IBinder windowToken, IBinder focusGrantToken, String inputHandleName,InputChannel outInputChannel) {
...
//这里会调用Server端的grantInputChannel方法mService.grantInputChannel(this, mUid, mPid, displayId, surface, window, hostInputToken, flags, mCanAddInternalSystemWindow ? privateFlags : 0,type, inputFeatures, windowToken, focusGrantToken, inputHandleName,outInputChannel);
...}

下面是一个关于以上流程的setting主页面启动流程

05-25 12:58:21.791  1909  2175 I wm_task_created: 441
05-25 12:58:21.795  1909  2175 I wm_task_moved: [441,441,0,1,2]
05-25 12:58:21.795  1909  2175 I wm_task_to_front: [0,441,0]
05-25 12:58:21.795  1909  2175 I wm_create_task: [0,441,441,0]
05-25 12:58:21.795  1909  2175 I wm_create_activity: [0,232997572,441,com.android.settings/.homepage.SettingsHomepageActivity,android.settings.SETTINGS,NULL,NULL,335544320]
05-25 12:58:21.795  1909  2175 I wm_task_moved: [441,441,0,1,2]
05-25 12:58:22.265  1909  3494 I wm_restart_activity: [0,232997572,441,com.android.settings/.homepage.SettingsHomepageActivity]
05-25 12:58:22.267  1909  3494 I wm_set_resumed_activity: [0,com.android.settings/.homepage.SettingsHomepageActivity,minimalResumeActivityLocked - onActivityStateChanged]
05-25 12:58:22.363  2518  2518 I wm_on_create_called: [232997572,com.android.settings.homepage.SettingsHomepageActivity,performCreate,66]
05-25 12:58:22.457  2518  2518 I wm_on_start_called: [232997572,com.android.settings.homepage.SettingsHomepageActivity,handleStartActivity,92]
05-25 12:58:22.460  2518  2518 V ActivityThread: Performing resume of ActivityRecord{a4a98fc token=android.os.BinderProxy@c7155ef {com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}} finished=false
05-25 12:58:22.460  2518  2518 I wm_on_resume_called: [232997572,com.android.settings.homepage.SettingsHomepageActivity,RESUME_ACTIVITY,0]
05-25 12:58:22.525  2518  2518 V ActivityThread: Resume ActivityRecord{a4a98fc token=android.os.BinderProxy@c7155ef {com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}} started activity: false, hideForNow: false, finished: false
05-25 12:58:22.545  1909  2175 V WindowManager: Attaching Window{a90e6ab u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity} token=ActivityRecord{de342c4 u0 com.android.settings/.homepage.SettingsHomepageActivity t441}
05-25 12:58:22.552  2518  2518 V ActivityThread: Resuming ActivityRecord{a4a98fc token=android.os.BinderProxy@c7155ef {com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}} with isForward=true
05-25 12:58:22.552  2518  2518 V ActivityThread: Scheduling idle handler for ActivityRecord{a4a98fc token=android.os.BinderProxy@c7155ef {com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}}
05-25 12:58:22.553  2518  2518 I wm_on_top_resumed_gained_called: [232997572,com.android.settings.homepage.SettingsHomepageActivity,topStateChangedWhenResumed]
05-25 12:58:22.769  1909  1971 I wm_activity_launch_time: [0,232997572,com.android.settings/.homepage.SettingsHomepageActivity,970]

6. WindowManagerService#grantInputChannel

这里就到了Server端,以上都是Client端。

由于本篇文章已经过长,故Server端的另起一篇文章分析。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/18085.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Raven2掠夺者2渡鸦2游戏预约注册教程 账号注册教程

《渡鸦2》是一款源自韩国的创新力作&#xff0c;作为《Raven》系列的最新续篇&#xff0c;这款游戏在MMORPG手游领域内再度扩展了其标志性的暗黑奇幻宇宙&#xff0c;融入了大量革新的游戏设计与丰富内容。定档于2024年5月29日开启公测的《渡鸦2》&#xff0c;正处在紧张刺激的…

blender复制uv贴图

1、新建两个猴头 2、点击其中一个进入uv编辑模式 3、在uv编辑中打开一个图像 4、新建一个材质球&#xff0c;将图像渲染到模型上 打开图像纹理 选择刚才打开的图像 切换到材质预览模式后&#xff0c;就可以看到贴图了 5、选择一个孤岛 6、然后选择拼排孤岛 可以看到该模型展开…

【全开源】JAVA人力资源招聘社会校招类型招聘系统校园招聘PC端

塑造企业高效招聘新体验 一、源码简介 招聘PC端源码&#xff0c;一款面向企业的招聘管理系统解决方案。它拥有完整的招聘流程管理功能&#xff0c;从职位发布到候选人管理&#xff0c;再到面试安排与结果反馈&#xff0c;所有环节都通过直观易用的界面进行展现&#xff0c;大…

Vivado打开之前项目仿真过的波形文件

第一步&#xff1a;顶部菜单 点击&#xff1a;Open Static Simulation 然后在弹出的窗口找到.sim结尾的文件夹&#xff0c;在里面找到wdb结尾的文件&#xff0c;点击ok 第二步&#xff1a;依次点击下方红圈 找到wcfg结尾的文件&#xff0c;点击ok即可

第十三届蓝桥杯国赛大学B组填空题(c++)

A.2022 动态规划 AC; #include<iostream> #define int long long using namespace std; int dp[2050][15]; //dp[i][j]:把数字i分解为j个不同的数的方法数 signed main(){dp[0][0]1;for(int i1;i<2022;i){for(int j1;j<10;j){//一种是已经分成j个数,这时只需每一个…

坦克飞机大战项目详解:从包结构到测试发布

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、项目初始化与包结构构建 代码案例&#xff1a; 二、资源文件与配置文件管理 代码案例…

MySQL简单测试和安装

MySQL 的特点 1、MySQL 性能卓越、服务稳定&#xff0c;很少出现异常宕机。 2、MySQL开放源代码且无版权制约&#xff0c;自主性及使用成本低。 3、MySQL历史悠久(版本众多)&#xff0c;用户使用活跃&#xff0c;遇到问题可以寻求帮助。 4、MySQL体积小(相对大型关系型数据库)…

linux安装mysql后,配置mysql,并连接navicate软件

Xshell连接登陆服务器 输入全局命令 mysql -u root -p 回车后&#xff0c;输入密码&#xff0c;不显示输入的密码 注意mysql服务状态&#xff0c;是否运行等 修改配置文件my.cnf&#xff0c;这里没找到就找my.ini&#xff0c;指定有一个是对的 find / -name my.cnf 接下…

【Web】浏览器指纹:追踪用户的新技术

目录 什么是浏览器指纹&#xff1f;浏览器指纹的原理浏览器指纹的应用使用JavaScript获取浏览器指纹总结 在这个数字化时代&#xff0c;用户隐私和网络安全成为了人们日益关注的话题。而浏览器指纹作为一种追踪用户的新技术&#xff0c;正逐渐受到人们的关注。本文将详细介绍浏…

26计算机操作系统408考研--操作系统处理机调度篇章(五)

文章目录 一、调度简介死锁一、调度简介 计算机系统中,处理器和内存资源会出现供不应求的情况,特别是多个I/O设备与主机交互,作业不断进入系统,或者是多个批处理作业在磁盘的后备队列中等待进入内存的情况。操作系统在管理有限的资源的同时,需要考虑如何选取进入内存的作…

IS-IS开销值和协议优先级

原理概述 IS-IS 协议为路由器的每个 IS-IS 接口定义并维护了一个 Level-1开销值和一个 Level-2开销值。开销值可以在接口上或者全局上手动配置&#xff0c;也可以使用 Auto-Cost 自动计算确定。开销值的优先顺序为&#xff1a;接口上手动配置的开销值&#xff0c;全局上手动配置…

热门项目朋友聚会喝酒热场小游戏小程序源码系统 带完整的安装代码包以及搭建教程

系统概述 朋友聚会喝酒热场小游戏小程序源码系统是一款专门为朋友聚会场景设计的互动娱乐工具。它旨在为用户提供一系列有趣的小游戏&#xff0c;帮助提升聚会的氛围和趣味性&#xff0c;让朋友们在轻松愉快的环境中度过美好时光。本系统采用先进的技术架构&#xff0c;具备高…

TensorRT部署模型基本步骤(C++)

TensorRT部署模型基本步骤&#xff08;C&#xff09; 文章目录 TensorRT部署模型基本步骤&#xff08;C&#xff09;前言一、onnx模型转engine1.基于C代码生成engine2.基于trtexec.exe命令行生成 二、读取本地模型三、创建推理引擎四、创建推理上下文五、创建GPU显存缓冲区六、…

惯性测量单元M-G370系列广泛用于工业系统各个领域

爱普生现已推出型号为M-G370系列的高稳定性、高精度及极小尺寸封装的惯性测量单元(IMU)&#xff0c;可广泛应用于工业系统的各个领域。 为了节省PCB的面积和产品空间&#xff0c;M-G370系列性测量单元设计精巧&#xff0c;且具有6个自由度:三轴角速率和三轴线性加速度&…

selenium学习笔记

什么是selenium 比较官方的解释 Selenium是一个自动化测试工具&#xff0c;用于在Web应用程序中模拟用户操作。它提供了一组API&#xff0c;可以通过编程方式控制浏览器&#xff0c;并模拟用户的交互行为&#xff0c;例如点击、输入文本和导航等。Selenium支持多种编程语言&a…

9.4 Go语言入门(运算符)

Go语言入门&#xff08;运算符&#xff09; 目录三、运算符1. 算术运算符2. 关系运算符3. 逻辑运算符4. 位运算符5. 赋值运算符6. 其他运算符7. 运算符优先级 目录 Go 语言&#xff08;Golang&#xff09;是一种静态类型、编译型语言&#xff0c;由 Google 开发&#xff0c;专注…

若依启动run-modules-system.bat报错问题解决方案

在启动run-modules-system.bat时遇到了一些问题,在网上搜索无果后,排查解决完毕 1.启动nacos时,报错如下 Error creating bean with name grpcClusterServer: Invocation of init method failed; nested exception is java.io.IOException: Failed to bind to address 0.0.0.0…

SQL实战 将学生信息进行 行转列输出

表countries 数据如下&#xff1a; namecontinentJaneAmericaPascalEuropeXiAsiaJackAmerica数据建表来源&#xff1a; SQL试题使得每个学生 按照姓名的字⺟顺序依次排列 在对应的⼤洲下⾯展示为如下的数据样式&#xff1a; namecontinentJane, JackAmericaXiAsiaPascalPasca…

Python开发 —— 对象type、object、class

1. "Python中一切皆为对象"的理解 在Python中&#xff0c;一切皆为对象的意思是指&#xff1a;无论是数字、字符串、函数、类、模块等任何数据类型&#xff0c;都可以被看做是一个对象。每个对象都具有自己的属性和方法&#xff0c;可以被操作和调用。 例如&#xff…

linux--实时性优化

linux--实时性优化 1 介绍2 实时性需求3 代表性实时系统4 嵌入式系统嵌入式软件系统结构处理器时钟节拍多任务机制任务调度方式任务调度算法时间片调度算法优先级调度算法基于优先级的时间片调度算法 5 cyclictest 测试工具命令说明命令分析参数含义 6 linux 实时性改进某版本上…