WindowManagerService之addWindow函数分析

addWindow函数分析
public int addWindow(Session session, IWindow client, int seq,
		WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
		Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
		InputChannel outInputChannel)
step 1, 权限检查
// step 1, 权限检查
int[] appOp = new int[1];
int res = mPolicy.checkAddPermission(attrs, appOp);
if (res != WindowManagerGlobal.ADD_OKAY) {
	return res;
}
step 2, 窗口类型检查
final int type = attrs.type;
// step 1 , 加锁, 直到addWindow函数结尾,才释放
synchronized(mWindowMap) {
	// 一个DisplayContent对应一个绘制屏幕
	// step 2, 显示相关判断
	final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
	if (displayContent == null) {
		Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
				+ displayId + ".  Aborting.");
		return WindowManagerGlobal.ADD_INVALID_DISPLAY;
	}

	// step 3, 是否已经添加对应的窗口, 去重判断
	if (mWindowMap.containsKey(client.asBinder())) {
		Slog.w(TAG_WM, "Window " + client + " is already added");
		return WindowManagerGlobal.ADD_DUPLICATE_ADD;
	}

	// step 4, 如果是子窗口类型,则父窗口一定要存在
	if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
		parentWindow = windowForClientLocked(null, attrs.token, false);
		if (parentWindow == null) {
			Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
				  + attrs.token + ".  Aborting.");
			return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
		}
		if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
				&& parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
			Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
					+ attrs.token + ".  Aborting.");
			return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
		}
	}
}
step 3, WindowToken检查

根据窗口类型找到对应的WindowToken, 如果不是特定的type,且token不存在,则返回。一个WindowToken对应一系列的WindowState, app窗口对应的token为AppWindowToken

AppWindowToken atoken = null;
final boolean hasParent = parentWindow != null;
// step 1, 根据窗口类型, 获取对应的窗口令牌(WindowToken)
WindowToken token = displayContent.getWindowToken(
		hasParent ? parentWindow.mAttrs.token : attrs.token);
final int rootType = hasParent ? parentWindow.mAttrs.type : type;
boolean addToastWindowRequiresToken = false;

// step 2, 某些系统窗口,可以由WMS创建WindowToken,且需要系统权限,否则需要有对应的WindowToken才能添加窗口
if (token == null) {
	// App 窗口,需要token为AppWindowToken
	if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
		Slog.w(TAG_WM, "Attempted to add application window with unknown token "
			  + attrs.token + ".  Aborting.");
		return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
	}
	// 输入法窗口,需要token存在
	if (rootType == TYPE_INPUT_METHOD) {
		Slog.w(TAG_WM, "Attempted to add input method window with unknown token "
			  + attrs.token + ".  Aborting.");
		return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
	}
	// 壁纸窗口, 需要token存在
	if (rootType == TYPE_WALLPAPER) {
		Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "
			  + attrs.token + ".  Aborting.");
		return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
	}

	final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
	// step 3 , 创建对应的token对象
	token = new WindowToken(this, binder, type, false, displayContent,
			session.mCanAddInternalSystemWindow);
} else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
	// app窗口,且对应的token类型为AppWindowToken
	atoken = token.asAppWindowToken();
	if (atoken == null) {
		Slog.w(TAG_WM, "Attempted to add window with non-application token "
			  + token + ".  Aborting.");
		return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
	} else if (atoken.removed) {
		Slog.w(TAG_WM, "Attempted to add window with exiting application token "
			  + token + ".  Aborting.");
		return WindowManagerGlobal.ADD_APP_EXITING;
	}
} else if (rootType == TYPE_INPUT_METHOD) {
	// 输入法窗口,窗口类型为为TYPE_INPUT_METHOD
	if (token.windowType != TYPE_INPUT_METHOD) {
		Slog.w(TAG_WM, "Attempted to add input method window with bad token "
				+ attrs.token + ".  Aborting.");
		  return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
	}
} else if (token.asAppWindowToken() != null) {
	Slog.w(TAG_WM, "Non-null appWindowToken for system window of rootType=" + rootType);
	// It is not valid to use an app token with other system types; we will
	// instead make a new token for it (as if null had been passed in for the token).
	attrs.token = null;
	token = new WindowToken(this, client.asBinder(), type, false, displayContent,
			session.mCanAddInternalSystemWindow);
}
step 4, WindowState对象创建
// step 1, 创建WindowState对象,用来保存窗口状态信息, 把token对象传给WindowState
final WindowState win = new WindowState(this, session, client, token, parentWindow,
		appOp[0], seq, attrs, viewVisibility, session.mUid,
		session.mCanAddInternalSystemWindow);

// step 2, 如果添加窗口的客户端死亡,则返回
if (win.mDeathRecipient == null) {
	// Client has apparently died, so there is no reason to
	// continue.
	Slog.w(TAG_WM, "Adding window client " + client.asBinder()
			+ " that is dead, aborting.");
	return WindowManagerGlobal.ADD_APP_EXITING;
}

// step 3 , 窗口对应的绘制屏幕不存在,直接返回
if (win.getDisplayContent() == null) {
	Slog.w(TAG_WM, "Adding window to Display that has been removed.");
	return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
step 5, 窗口调整和权限检查
// mPolicy 实现类为PhoneWindowManager
// step 1, 调整窗口属性, 更新一些flag
mPolicy.adjustWindowParamsLw(win.mAttrs);

// step 2, 权限检查, 根据窗口类型做相关处理
res = mPolicy.prepareAddWindowLw(win, attrs);
if (res != WindowManagerGlobal.ADD_OKAY) {
	return res;
}

step 6, 根据属性来确定是否需要创建接收输入事件通道
// step 1, 创建输入通道, 用来接收按键事件
final boolean openInputChannels = (outInputChannel != null
		&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if  (openInputChannels) {
	win.openInputChannel(outInputChannel);
}
step 7, 将WindowState记录在WMS相关变量中
// step 1, 绑定SurfaceSession
win.attach();
// step 2, 将WindowState添加到mWindowMap中
mWindowMap.put(client.asBinder(), win);
// step 3, AppOps权限检查此窗口是否有权限显示
if (win.mAppOp != AppOpsManager.OP_NONE) {
	int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(),
			win.getOwningPackage());
	if ((startOpResult != AppOpsManager.MODE_ALLOWED) &&
			(startOpResult != AppOpsManager.MODE_DEFAULT)) {
		// 将窗口设置为不可见
		win.setAppOpVisibilityLw(false);
	}
}

final AppWindowToken aToken = token.asAppWindowToken();
// step 4 , 窗口类型为启动窗口
if (type == TYPE_APPLICATION_STARTING && aToken != null) {
	aToken.startingWindow = win;
	if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + aToken
			+ " startingWindow=" + win);
}


// step 5, 将窗口添加到对应的token中
win.mToken.addWindow(win);
step 8, 输入法和壁纸相关处理
boolean imMayMove = true;

// step 1, 输入法和壁纸相关处理
if (type == TYPE_INPUT_METHOD) {
	win.mGivenInsetsPending = true;
	setInputMethodWindowLocked(win);
	imMayMove = false;
} else if (type == TYPE_INPUT_METHOD_DIALOG) {
	displayContent.computeImeTarget(true /* updateImeTarget */);
	imMayMove = false;
} else {
	if (type == TYPE_WALLPAPER) {
		displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
		displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
	} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
		displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
	} else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
		displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
	}
}

// step 2, 输入法窗口是否需要重新调整
win.applyAdjustForImeIfNeeded();

// DOCK相关
if (type == TYPE_DOCK_DIVIDER) {
	mRoot.getDisplayContent(displayId).getDockedDividerController().setWindow(win);
}
step 9, 更新窗口层级

更新窗口层级实现在DisplayContent的assignWindowLayers中,根据传入的参数是否需要layout,传入参数为false, 表示不需要重新layout,layout在client进程调用WMS的relayoutWindow时会进行layout

boolean focusChanged = false;
// step 1, 如果窗口能接收按键, 则更新Foucus窗口
if (win.canReceiveKeys()) {
	focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
			false /*updateInputWindows*/);
	if (focusChanged) {
		imMayMove = false;
	}
}

// step 2, 如果输入法移除,需要重新调整输入法窗口
if (imMayMove) {
	displayContent.computeImeTarget(true /* updateImeTarget */);
}

// step 3, 更新窗口层级, 不分配Surface(不显示)
displayContent.assignWindowLayers(false /* setLayoutNeeded */);

// step 4, foucus窗口改变, 更新获取按键事件窗口
if (focusChanged) {
	mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
}
// step 5, 更新输入法窗口参数
mInputMonitor.updateInputWindowsLw(false /*force*/);


assignWindowLayers
void DisplayContent::assignWindowLayers(boolean setLayoutNeeded) {
	// step 1, 分配窗口层级
	mLayersController.assignWindowLayers(this);
	if (setLayoutNeeded) {
		// step 2, 将mLayoutNeeded成员变量置为true
		setLayoutNeeded();
	}
}
final void WindowLayersController::assignWindowLayers(DisplayContent dc) {

	// step 1, 清空成员变量参数
	reset();

	// step 2, 遍历DisplayContent中的所有窗口
	dc.forAllWindows(mAssignWindowLayersConsumer, false /* traverseTopToBottom */);

	// step 3, 对特殊窗layer做调整
	adjustSpecialWindows();

	// step 4, 分屏相关处理
	if (mService.mAccessibilityController != null && mAnyLayerChanged
			&& dc.getDisplayId() == DEFAULT_DISPLAY) {
		mService.mAccessibilityController.onWindowLayersChangedLocked();
	}
}

WindowState中实现了sWindowSubLayerComparator比较器,但是WindowToken相同的窗口mBaseLayer相同。mBaseLayer是在创建WindowState的时候确定的。同一窗口类型,高优先级的窗口需要在mBaseLayer的基础上再加一个WINDOW_LAYER_MULTIPLIER,才不会互相踩到,子窗口根据mSubLayer来判断是显示在父窗口上面还是下面,大于0显示在父窗口上面,小于0显示在父窗口下面。getWindowLayerLw函数根据窗口类型返回对应的层级值, 最终实现为WindowManagerPolicy的getWindowLayerFromTypeLw

WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
	   WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
	   int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) {
	// 子窗口
	if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
	    // mBaseLayer和父窗口相同
		mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
				* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
		// 根据窗口类型再来确定mSubLayer的值
		mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
		mIsChildWindow = true;

		if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + parentWindow);
		parentWindow.addChild(this, sWindowSubLayerComparator);

		mLayoutAttached = mAttrs.type !=
				WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
		mIsImWindow = parentWindow.mAttrs.type == TYPE_INPUT_METHOD
				|| parentWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
		mIsWallpaper = parentWindow.mAttrs.type == TYPE_WALLPAPER;
	} else {
		// 确定mBaseLayer
		mBaseLayer = mPolicy.getWindowLayerLw(this)
				* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
		mSubLayer = 0;
	   
	}
   
}
private static final Comparator<WindowState> sWindowSubLayerComparator =
new Comparator<WindowState>() {
	@Override
	public int compare(WindowState w1, WindowState w2) {
		final int layer1 = w1.mSubLayer;
		final int layer2 = w2.mSubLayer;
		// 根据mSubLayer的大小确定是在父窗口前面还是后面
		if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0 )) {
			return -1;
		}
		return 1;
	};
};

private final Consumer<WindowState> mAssignWindowLayersConsumer = w -> {
	boolean layerChanged = false;

	int oldLayer = w.mLayer;

	// step 1, WindowToken下的WindowState的mBaseLayer相同, 向后遍历, 后面优先级高, 相同token的WindowState加一个偏移值
	if (w.mBaseLayer == mCurBaseLayer) {
		mCurLayer += WINDOW_LAYER_MULTIPLIER;
	} else {
		mCurBaseLayer = mCurLayer = w.mBaseLayer;
	}

	// step 2, 给动画分配layer值
	assignAnimLayer(w, mCurLayer);


	if (w.mLayer != oldLayer || w.mWinAnimator.mAnimLayer != oldLayer) {
		// 层级改变
		layerChanged = true;
		mAnyLayerChanged = true;
	}

	// step 3, mHighestApplicationLayer值调整
	if (w.mAppToken != null) {
		mHighestApplicationLayer = Math.max(mHighestApplicationLayer,
				w.mWinAnimator.mAnimLayer);
	}

	// step 4, mHighestLayerInImeTargetBaseLayer值调整
	if (mImeTarget != null && w.mBaseLayer == mImeTarget.mBaseLayer) {
		mHighestLayerInImeTargetBaseLayer = Math.max(mHighestLayerInImeTargetBaseLayer,
				w.mWinAnimator.mAnimLayer);
	}

	// step 5, mHighestDockedAffectedLayer调整
	if (w.getAppToken() != null && StackId.isResizeableByDockedStack(w.getStackId())) {
		mHighestDockedAffectedLayer = Math.max(mHighestDockedAffectedLayer,
				w.mWinAnimator.mAnimLayer);
	}

	// step 6, 收集特殊窗口, 将特殊类型的窗口添加到指定的列表里面
	collectSpecialWindows(w);

	if (layerChanged) {
		// 动画相关
		w.scheduleAnimationIfDimming();
	}
};
addWindow函数总结

step 1, 权限检查
step 2, 窗口类型检查
step 3, WindowToken检查
step 4, WindowState对象创建
step 5, 窗口层级处理

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值