首页 > 其他分享 >【framework】View添加过程

【framework】View添加过程

时间:2023-03-19 17:24:42浏览次数:47  
标签:... java Session WindowManager framework 添加 public View

1 前言

WMS启动流程 中介绍了 WindowManagerService 的启动流程,本文将介绍 View 的添加流程,按照进程分为以下2步:

  • 应用进程:介绍从 WindowManagerImpl(addView 方法)到 Session(addToDisplay 方法)的调用流程;
  • system_server 进程:介绍从 Session(addToDisplay 方法)到 SurfaceSession(构造方法)的调用流程;

​ 为区分不同进程,将应用进程、system_server 进程分别标识为浅蓝色、深蓝色。

2 View 添加过程

2.1 从 WindowManagerImpl 到 Session

​ 如图,浅蓝色的类是应用进程中执行的,深蓝色的类是在 system_server 进程中执行的,黄色的类是指 AIDL 文件生成的接口(用于跨进程)。

img

​ 注意事项:

  • WMS 在 system_server 进程中单例运行,WindowManagerGlobal 在应用进程中单例运行,但是应用进程一般有多个,而进程之间内存隔离,因此每个应用进程中有且仅一个 WindowManagerGlobal 对象,并且会与一个 Session 对象一一对应。
  • 一个窗口对应一个根 View,在添加根 View 时,会创建一个 ViewRootImpl、W、WindowState 对象与之一一对应。

(1)addView

​ /frameworks/base/core/java/android/view/WindowManagerImpl.java

public void addView(View view, ViewGroup.LayoutParams params) {
	applyDefaultToken(params);
	mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

(2)addView

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

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

	ViewRootImpl root;
	View panelParentView = null; //父窗口的根 View

	synchronized (mLock) {
		...
		//如果是子窗口,则通过 token 寻找父窗口的根 View
		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); //mViews = new ArrayList<View>(),存储了所有窗口的根 View
				}
			}
		}
		//每个窗口对应一个 ViewRootImpl 对象
		root = new ViewRootImpl(view.getContext(), display);
		view.setLayoutParams(wparams);
		//存留 view、root、params信息
		mViews.add(view);
		mRoots.add(root);
		mParams.add(wparams);
		try {
			root.setView(view, wparams, panelParentView);
		}
		...
	}
}

​ 可以看到,每个根 View,都与一个 LayoutParams 和一个 ViewRootImpl 一一对应。

(3)setView

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

​ 在 WindowManagerGlobal 的 addView() 方法中创建了 ViewRootImpl 对象,因此,先看看 ViewRootImpl 的构造方法。

public ViewRootImpl(Context context, Display display) {
	mContext = context;
    //IWindowSession 类型,单例对象,getWindowSession() 方法调用 WMS 的 openSession() 方法,new 一个 Session 对象
	mWindowSession = WindowManagerGlobal.getWindowSession(); 
	mDisplay = display;
	...
	mWindow = new W(this); //IWindow.Stub 的实现类
	...
    mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this, context); //View.AttachInfo 类型
    ...
	mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
    ...
}

​ 注意:在创建 ViewRootImpl 时,也创建了 W,进一步说明每个 根 View 都与一个 W 一一对应,即 mWindow.asBinder() 可以作为 根 View (或窗口)的身份标识。

​ 再看看 ViewRootImpl 的 setView 方法。

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
	synchronized (this) {
		if (mView == null) {
			mView = view;
            ...
			mWindowAttributes.copyFrom(attrs);
			...
			mAttachInfo.mRootView = view;
			...
			if (panelParentView != null) {
				mAttachInfo.mPanelParentWindowToken = panelParentView.getApplicationWindowToken();
			}
            ...
			if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
				mInputChannel = new InputChannel();
			}
			...
            //请求显示 View
            requestLayout();
            ...
			try {
				...
				res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), 
					mDisplay.getDisplayId(), mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, 
					mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel, mTempInsets);
				setFrame(mTmpFrame);
			}
			...
		}
	}
}

2.2 从 Session 到 SurfaceSession

img

​ 注意事项:每个应用进程对应一个 Session 对象和一个 SurfaceSession 对象, 每个窗口对应一个 WindowState 对象。

(1)Session 的创建过程

​ 在 ViewRootImpl 的构造方法中,调用了 WindowManagerGlobal 的 getWindowSession() 方法中获取了 Session 对象,因此,先看看 Session 对象的创建过程。

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

public static IWindowSession getWindowSession() {
	synchronized (WindowManagerGlobal.class) {
		if (sWindowSession == null) {
			try {
				...
				IWindowManager windowManager = getWindowManagerService(); //获取 WMS
				sWindowSession = windowManager.openSession(
						new IWindowSessionCallback.Stub() {
							@Override
							public void onAnimatorScaleChanged(float scale) {
								ValueAnimator.setDurationScale(scale);
							}
						});
			}
			...
		}
		return sWindowSession; //private static IWindowSession sWindowSession,单例对象
	}
}

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

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

​ /frameworks/base/services/core/java/com/android/server/wm/Session.java

public Session(WindowManagerService service, IWindowSessionCallback callback) {
	mService = service;
	mCallback = callback;
	mUid = Binder.getCallingUid();
	mPid = Binder.getCallingPid();
	...
	try {
		mCallback.asBinder().linkToDeath(this, 0);
	}
	...
}

(2)addToDisplay

​ /frameworks/base/services/core/java/com/android/server/wm/Session.java

public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, 
		int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, 
		DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, InsetsState outInsetsState) {
    //mService 为 WMS
	return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, outContentInsets, 
			outStableInsets, outOutsets, outDisplayCutout, outInputChannel, outInsetsState);
}

(3)addWindow

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

public int addWindow(Session session, IWindow client, int seq, LayoutParams attrs, int viewVisibility, 
		int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, 
		DisplayCutout.ParcelableWrapper, InputChannel outInputChannel, InsetsState outInsetsState) {
	...
	//检查权限,不通过则直接返回
	...
	WindowState parentWindow = null; //父窗口的 WindowState
	...
	final int type = attrs.type;
	synchronized (mGlobalLock) {
		//获取 DisplayContent,不存在就创建,按照以下顺序创建,不为空就返回:
		//mRoot.getWindowToken(attrs.token).getDisplayContent()
		//mRoot.getDisplayContent(displayId)
		//mRoot.createDisplayContent(mDisplayManager.getDisplay(displayId), null)
		final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
		...
		if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) { //待添加的窗口是 sub_win
			parentWindow = windowForClientLocked(null, attrs.token, false); //parentWindow = mWindowMap.get(attrs.token)
			...
		}
		...
		//过滤:1.type=sub_win、parentWindow=null; 2.type = sub_win = parentWindow 等
		...
		AppWindowToken atoken = null;
		final boolean hasParent = parentWindow != null;
		//获取 WindowToken(有父窗口,则获取父窗口的)
		WindowToken token = displayContent.getWindowToken(hasParent ? parentWindow.mAttrs.token : attrs.token);
		//获取窗口 type(有父窗口,则获取父窗口的)
		final int rootType = hasParent ? parentWindow.mAttrs.type : type;
		...
		if (token == null) { //如果 parentWindow != null, 则 token != null。因此,token = null,则 parentWindow = null,即此时的 token 和 rootType 是当前窗口的
			...
			//过滤:1.rootType=app_win; 2.rootType=ime_win; 3.rootType=wallpaper_win; rootType=toast_win 等,即不允许上述窗口的 token 为 null
			...
			final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
			...
			//前面没有过滤 sub_win,说明 sub_win 的 token 可以不用提前赋值,这里也会创建
			token = new WindowToken(this, binder, type, false, displayContent, session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);
		} else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) { //rootType=app_win
			atoken = token.asAppWindowToken(); //atoken 不能为空,否则会返回错误码
			...
		}
		...
		//过滤:1.rootType = ime_win != token.windowType; 2.rootType = wallpaper_win != oken.windowType 等
		...
		else if (type == TYPE_TOAST) {
			//若 token.windowType!=toast_win,可能会被过滤,即返回错误码
			...
		}
		...
		else if (token.asAppWindowToken() != null) { //AppWindowToken 是 WindowToken 的子类
			attrs.token = null;
			token = new WindowToken(this, client.asBinder(), type, false, displayContent, session.mCanAddInternalSystemWindow);
		}
		//创建 WindowState,说明每个根 View,都与一个 WindowState 一一对应
		final WindowState win = new WindowState(this, session, client, token, parentWindow, appOp[0], 
				seq, attrs, viewVisibility, session.mUid, session.mCanAddInternalSystemWindow);
		...
		final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
		displayPolicy.adjustWindowParamsLw(win, win.mAttrs, Binder.getCallingPid(), Binder.getCallingUid());
		win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
		//前面已排除一些异常可能,接下来的代码不会有异常情况
		res = displayPolicy.prepareAddWindowLw(win, attrs);
		...
		win.attach(); //mSessions.add(win.mSession)
		mWindowMap.put(client.asBinder(), win);
		...
		win.mToken.addWindow(win); //win.mToken.addChild(win, mWindowComparator)
		...
	}
	...
	return res;
}

​ 特别提醒:请重点关注 WindowToken、WindowState 的创建过程。

(4)构造方法

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

WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState parentWindow, int appOp, 
		int seq, WindowManager.LayoutParams a, int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) {
	this(service, s, c, token, parentWindow, appOp, seq, a, viewVisibility, ownerId,
			ownerCanAddInternalSystemWindow, new PowerManagerWrapper(){...});
}

WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState parentWindow, int appOp, 
		int seq, WindowManager.LayoutParams a, int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow,
		PowerManagerWrapper powerManagerWrapper) {
	super(service); //mWmService = service
	mSession = s;
	mClient = c;
	...
	mToken = token;
	mAppToken = mToken.asAppWindowToken();
	...
	mAttrs.copyFrom(a);
	...
	mPolicy = mWmService.mPolicy;
	mContext = mWmService.mContext;
	...
	if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) { //计算子窗口图层
		mBaseLayer = mPolicy.getWindowLayerLw(parentWindow) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
		mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
		...
		parentWindow.addChild(this, sWindowSubLayerComparator);
		...
	} else { //计算窗口图层
		mBaseLayer = mPolicy.getWindowLayerLw(this) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
		mSubLayer = 0;
		...
	}
	...
    mWinAnimator = new WindowStateAnimator(this);
    ...
}

(5)attach

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

void attach() {
	...
	mSession.windowAddedLocked(mAttrs.packageName);
}

(6)windowAddedLocked

​ /frameworks/base/services/core/java/com/android/server/wm/Session.java

void windowAddedLocked(String packageName) {
    //绑定应用进程包名
	mPackageName = packageName;
	...
	if (mSurfaceSession == null) {
		...
		mSurfaceSession = new SurfaceSession();
		...
		//将 Session 添加到 WMS 中
		mService.mSessions.add(this);
		...
	}
	mNumWindow++;
}

​ 说明: Session 和 SurfaceSession 都与应用进程一一对应,SurfaceSession 持有 SurfaceComposerClient,作为跟 SurfaceFlinger 通信的代理对象。

(7)SurfaceSession

​ /frameworks/base/core/java/android/view/SurfaceSession.java

public final class SurfaceSession {
	// SurfaceComposerClient
	private long mNativeClient;
	...

	public SurfaceSession() {
        //创建 SurfaceComposerClient
		mNativeClient = nativeCreate();
	}

    ...
}

​ 说明: SurfaceComposerClient 是 ISurfaceComposer 的代理类,SurfaceFlinger 是 ISurfaceComposer 的实现类,它们通过 Binder 实现跨进程通讯。

3 添加 View 的场景

​ 看到这里,读者也许会疑惑,什么样的 View 会通过 WindowManager 的 addView() 走完上述流程?布局中的 TextView 组件的添加会走上述流程么?带着这些疑问,笔者列举了系统中 3 个 View的添加场景应用,分别是:Activity、Dialog、Toast 中 View 的添加,这些 View 一般命名为 mDecor(也有例外),它们一般是根 View。

(1)Activity

​ /frameworks/base/core/java/android/app/Activity.java

Activity extends ContextThemeWrapper implements ... {
    private WindowManager mWindowManager;
    private Window mWindow
    View mDecor = null;
	
	void makeVisible() {
		if (!mWindowAdded) {
			ViewManager wm = getWindowManager(); //mWindowManager
			//通过 WindowManager 添加 View
			wm.addView(mDecor, getWindow().getAttributes());
			...
		}
		...
    }
}

(2)Dialog.java

​ /frameworks/base/core/java/android/app/Dialog.java

public class Dialog implements DialogInterface ... {
	private final WindowManager mWindowManager;
	final Window mWindow;
    View mDecor;
	
	public void show() {
        ...
        mDecor = mWindow.getDecorView();
		...
        WindowManager.LayoutParams l = mWindow.getAttributes();
        ...
        //通过 WindowManager 添加 View
        mWindowManager.addView(mDecor, l);
        ...
    }
}

(3)Toast

​ /frameworks/base/core/java/android/widget/Toast.java

public class Toast {
	WindowManager mWM;
	View mView;
	
	public void handleShow(IBinder windowToken) {
		...
		if (mView != mNextView) {
			...
			mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
			...
			try {
                //通过 WindowManager 添加 View
				mWM.addView(mView, mParams);
				...
			}
			...
		}
	}
}

4 WindowManager

​ WindowManager 是 View 添加的起点,其具体实现是 WindowManagerImpl。在获取 WindowManager 对象时,一般使用如下代码:

//Context 的具体实现是 ContextImpl
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); //"window"

​ 下面跟踪一下上述代码。

img

​ /frameworks/base/core/java/android/app/ContextImpl.java

public Object getSystemService(String name) {
	return SystemServiceRegistry.getSystemService(this, name);
}

​ /frameworks/base/core/java/android/app/SystemServiceRegistry.java

final class SystemServiceRegistry {
	...
	//<serviceName, serviceFetcher>
    private static final Map<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS = new ArrayMap<String, ServiceFetcher<?>>();
	//服务缓存个数,每调用一次 registerService,服务个数+1,sServiceCacheSize 未被初始化,默认初值为 0
	private static int sServiceCacheSize;

	//在类被加载时,注册服务
    static {
		...
        registerService(Context.WINDOW_SERVICE, WindowManager.class,
                new CachedServiceFetcher<WindowManager>() {
            @Override
            public WindowManager createService(ContextImpl ctx) {
                return new WindowManagerImpl(ctx);
            }});
    }
	
	//创建缓存,在 ContextImpl 类初始化时调用:final Object[] mServiceCache = SystemServiceRegistry.createServiceCache()
	public static Object[] createServiceCache() {
        return new Object[sServiceCacheSize];
    }

    //获取服务
    public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }

    //注册服务
    private static <T> void registerService(String serviceName, Class<T> serviceClass, ServiceFetcher<T> serviceFetcher) {
        ...
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }
	...
}

​ 说明:CachedServiceFetcher 是 SystemServiceRegistry 的内部类,负责创建和缓存服务,每个服务对应一个缓存编号和 ServiceFetcher。在静态代码块里调用了 registerService() 方法,说明在 SystemServiceRegistry 类加载时就创建了一系列 ServiceFetcher,但是此时还没有创建服务,在第一次请求服务时才开始创建服务。

​ 注意:SystemServiceRegistry 类被应用进程加载,系统中可能同时存在多个应用进程,而应用之间内存隔离,因此,每个应用进程在加载 SystemServiceRegistry 类时,都创建了一系列 ServiceFetcher。

​ /frameworks/base/core/java/android/app/SystemServiceRegistry.CachedServiceFetcher.java

static abstract interface ServiceFetcher<T> {
	T getService(ContextImpl ctx);
}

//服务拾取器(每个 service 对应一个 cacheIndex 和 serviceFetcher)
static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {	
	private final int mCacheIndex; //服务编号

	CachedServiceFetcher() {
		mCacheIndex = sServiceCacheSize++;
	}

	public final T getService(ContextImpl ctx) {
        //获取服务缓存数组,mServiceCache 属性在定义时就被初始化:mServiceCache = SystemServiceRegistry.createServiceCache()
		final Object[] cache = ctx.mServiceCache; 
		...
		for (;;) {
			...
			synchronized (cache) {
				T service = (T) cache[mCacheIndex];
				if (service != null || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) {
					return service; //服务已存在,无需创建
				}
				...
			}

			if (doInitialize) {
				T service = null;
				...
				try {
					//创建服务
					service = createService(ctx);
					...
				}
				...
                } finally {
					synchronized (cache) {
						//缓存服务,保证服务在同一应用进程中以单例存在
						cache[mCacheIndex] = service;
						...
					}
				}
				return service;
			}
			...
		}
	}

	public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException;
}

​ 每个 ContextImpl 对象在初始化时创建了一个用于缓存服务的数组,每个服务在第一次请求时才被创建并缓存,因此,每个 Context 中都可能存在一个单例的 WindowManager 对象。

​ 声明:本文转自【framework】View添加过程

标签:...,java,Session,WindowManager,framework,添加,public,View
From: https://www.cnblogs.com/zhyan8/p/17233662.html

相关文章

  • 【framework】Activity启动流程
    1前言ATMS启动流程介绍了ActivityTaskManagerService(ATMS)的启动和初始化流程,本文将介绍Activity的启动流程。由于Activity启动流程复杂,本文按进程将其拆分为3......
  • 【framework】AMS启动流程
    1前言​AMS即ActivityManagerService,负责Activy、Service、Broadcast、ContentProvider四大组件的生命周期管理。本文主要介绍AMS的启动流程和初始化过程。AMS......
  • 【framework】ATMS启动流程
    1前言​ATMS即ActivityTaskManagerService,用于管理Activity及其容器(任务、堆栈、显示等)。ATMS在Android10中才出现,由原来的AMS(ActivityManagerService)分离......
  • 【framework】IMS启动流程
    1前言​IMS是InputManagerService的简称,主要负责输入事件管理。1.1基本概念输入设备:屏幕、电源/音量、键鼠、充电口、蓝牙、wifi等设备节点:当输入设备可用......
  • 【framework】应用进程启动流程
    1前言Activity启动流程中介绍了从点击桌面上应用快捷方式到Activity的onCreate()方法调用流程,本将介绍应用进程的启动流程。由于应用进程启动流程复杂,本文按进......
  • 【framework】InputChannel创建流程
    1前言IMS启动流程中介绍了IMS在Java层和Native层的初始化流程,以及创建NativeInputManager、InputManager、InputReader、InputDispatcher、EventHub等对象......
  • 【framework】surfaceflinger启动流程
    1前言​surfaceflinger的作用是合成来自WMS的Surface数据,并发送到显示设备。​SurfaceFlinger服务不同于AMS、WMS、IMP、PMS、DMS等服务,主要区别如下:......
  • 添加购物车动画
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"/><metahttp-equiv="X-UA-Compatible"content="IE=edge"/><metaname="viewport"co......
  • 【Android开发】基本组件-ListView(重要)
    1.ListView的样子打开任意一款Android手机的“设置”选项,你所看到的效果就是ListView的效果。类似下图:2.详细剖析ListViewListView界面的每一行就是ListView的一个“条目”......
  • 【Android开发】用户界面设计-开发自定义的View
    效果图:Android中,所有的UI界面都是由View类和ViewGroup类及其子类组合而成的。View是所有UI组件的基类(父类),为ViewGroup类是容纳这些UI组件的容器,其本身也是View的子类。关......