本篇是接上一篇Android R WindowManagerService 添加window过程分析 (一), 分析addWindow part3 , 这部分的主要工作有:
下面依次来分析这些细节:
构造WindowState有很多重要参数:
下面看WindowState创建
// @WMS#addWindow
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid, userId,
session.mCanAddInternalSystemWindow);
WindowState 的构造方法如下,大致做了如下几件事:
如果存在父窗口, 添加到父窗口建立与其的联系
// @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, int showUserId,
boolean ownerCanAddInternalSystemWindow, PowerManagerWrapper powerManagerWrapper) {
super(service);
// 初始化成员
mSession = s;
mClient = c;
mAppOp = appOp;
mToken = token;
mActivityRecord = mToken.asActivityRecord(); // 如果token是应用类型的,此处返回一个ActivityRecord,否则为null
mOwnerUid = ownerId;
mShowUserId = showUserId;
mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
mWindowId = new WindowId(this);
mAttrs.copyFrom(a);
mLastSurfaceInsets.set(mAttrs.surfaceInsets);
mViewVisibility = viewVisibility;
mPolicy = mWmService.mPolicy;
mContext = mWmService.mContext;
DeathRecipient deathRecipient = new DeathRecipient();
mSeq = seq;
mPowerManagerWrapper = powerManagerWrapper;
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
if (DEBUG) {
Slog.v(TAG, "Window " + this + " client=" + c.asBinder()
+ " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
}
try { // 注册客户端IWindow的死亡监听
c.asBinder().linkToDeath(deathRecipient, 0);
} catch (RemoteException e) { // 发送异常表示客户端已经不存在了
// 清除相关成员变量
mDeathRecipient = null;
...
return;
}
mDeathRecipient = deathRecipient;
if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) { // 处理子窗口
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
// 计算层级值 , TYPE_LAYER_MULTIPLIER = 10000 , TYPE_LAYER_OFFSET = 1000
// mBaseLayer = 父窗口type对应的层级值 * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET
mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type); // 通过type获取一个子窗口的层级值
mIsChildWindow = true;
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 {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
// 此窗口type对应的层级值 * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET
mBaseLayer = mPolicy.getWindowLayerLw(this)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = 0;
mIsChildWindow = false;
mLayoutAttached = false;
mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
|| mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
}
mIsFloatingLayer = mIsImWindow || mIsWallpaper;
if (mActivityRecord != null && mActivityRecord.mShowForAllUsers) {
// Windows for apps that can show for all users should also show when the device is
// locked.
mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED;
}
mWinAnimator = new WindowStateAnimator(this); // 创建animator,用于此窗口的动画
mWinAnimator.mAlpha = a.alpha;
mRequestedWidth = 0;
mRequestedHeight = 0;
mLastRequestedWidth = 0;
mLastRequestedHeight = 0;
mLayer = 0;
mInputWindowHandle = new InputWindowHandle( // 创建InputWindowHandle, 用于接收input事件
mActivityRecord != null ? mActivityRecord.mInputApplicationHandle : null,
getDisplayId());
// Make sure we initial all fields before adding to parentWindow, to prevent exception
// during onDisplayChanged.
if (mIsChildWindow) { // 将此子window添加到父窗口
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", this, parentWindow);
parentWindow.addChild(this, sWindowSubLayerComparator);
}
// System process or invalid process cannot register to display config change.
mWpcForDisplayConfigChanges = (s.mPid == MY_PID || s.mPid < 0)
? null
: service.mAtmService.getProcessController(s.mPid, s.mUid);
}
下面看看是如何通过WindowState获取layer的:
// @frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java
/**
* Returns the layer assignment for the window state. Allows you to control how different
* kinds of windows are ordered on-screen.
*
* @param win The window state
* @return int An arbitrary integer used to order windows, with lower numbers below higher ones.
*/
default int getWindowLayerLw(WindowState win) {
// 获取WindowState对应的type. 然后获取
return getWindowLayerFromTypeLw(win.getBaseType(), win.canAddInternalSystemWindow());
}
// 通过window对应的type获取层级值
default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { // 应用类型的窗口
return APPLICATION_LAYER; // APPLICATION_LAYER = 2
}
// 对于某些系统type, 有对应的固定层级值
switch (type) {
case TYPE_WALLPAPER:
// wallpaper is at the bottom, though the window manager may move it.
return 1;
case TYPE_PRESENTATION:
case TYPE_PRIVATE_PRESENTATION:
return APPLICATION_LAYER;
case TYPE_DOCK_DIVIDER:
return APPLICATION_LAYER;
case TYPE_QS_DIALOG:
return APPLICATION_LAYER;
case TYPE_PHONE:
return 3;
case TYPE_SEARCH_BAR:
case TYPE_VOICE_INTERACTION_STARTING:
return 4;
case TYPE_VOICE_INTERACTION:
// voice interaction layer is almost immediately above apps.
return 5;
case TYPE_INPUT_CONSUMER:
return 6;
case TYPE_SYSTEM_DIALOG:
return 7;
case TYPE_TOAST:
// toasts and the plugged-in battery thing
return 8;
case TYPE_PRIORITY_PHONE:
// SIM errors and unlock. Not sure if this really should be in a high layer.
return 9;
case TYPE_SYSTEM_ALERT:
// like the ANR / app crashed dialogs
// Type is deprecated for non-system apps. For system apps, this type should be
// in a higher layer than TYPE_APPLICATION_OVERLAY.
return canAddInternalSystemWindow ? 13 : 10;
case TYPE_APPLICATION_OVERLAY:
case TYPE_TRUSTED_APPLICATION_OVERLAY:
return 12;
case TYPE_INPUT_METHOD:
// on-screen keyboards and other such input method user interfaces go here.
return 15;
case TYPE_INPUT_METHOD_DIALOG:
// on-screen keyboards and other such input method user interfaces go here.
return 16;
case TYPE_STATUS_BAR:
return 17;
case TYPE_STATUS_BAR_ADDITIONAL:
return 18;
case TYPE_NOTIFICATION_SHADE:
return 19;
case TYPE_STATUS_BAR_SUB_PANEL:
return 20;
case TYPE_KEYGUARD_DIALOG:
return 21;
case TYPE_VOLUME_OVERLAY:
// the on-screen volume indicator and controller shown when the user
// changes the device volume
return 22;
case TYPE_SYSTEM_OVERLAY:
// the on-screen volume indicator and controller shown when the user
// changes the device volume
return canAddInternalSystemWindow ? 23 : 11;
case TYPE_NAVIGATION_BAR:
// the navigation bar, if available, shows atop most things
return 24;
case TYPE_NAVIGATION_BAR_PANEL:
// some panels (e.g. search) need to show on top of the navigation bar
return 25;
case TYPE_SCREENSHOT:
// screenshot selection layer shouldn't go above system error, but it should cover
// navigation bars at the very least.
return 26;
case TYPE_SYSTEM_ERROR:
// system-level error dialogs
return canAddInternalSystemWindow ? 27 : 10;
case TYPE_MAGNIFICATION_OVERLAY:
// used to highlight the magnified portion of a display
return 28;
case TYPE_DISPLAY_OVERLAY:
// used to simulate secondary display devices
return 29;
case TYPE_DRAG:
// the drag layer: input for drag-and-drop is associated with this window,
// which sits above all other focusable windows
return 30;
case TYPE_ACCESSIBILITY_OVERLAY:
// overlay put by accessibility services to intercept user interaction
return 31;
case TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY:
return 32;
case TYPE_SECURE_SYSTEM_OVERLAY:
return 33;
case TYPE_BOOT_PROGRESS:
return 34;
case TYPE_POINTER:
// the (mouse) pointer layer
return 35;
default:
Slog.e("WindowManager", "Unknown window type: " + type);
return APPLICATION_LAYER;
}
}
对于子窗口的层级值:
// @frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java
/**
* Return how to Z-order sub-windows in relation to the window they are attached to.
* Return positive to have them ordered in front, negative for behind.
*
* @param type The sub-window type code.
*
* @return int Layer in relation to the attached window, where positive is
* above and negative is below.
*/
default int getSubWindowLayerFromTypeLw(int type) {
switch (type) {
case TYPE_APPLICATION_PANEL:
case TYPE_APPLICATION_ATTACHED_DIALOG:
return APPLICATION_PANEL_SUBLAYER;
case TYPE_APPLICATION_MEDIA:
return APPLICATION_MEDIA_SUBLAYER;
case TYPE_APPLICATION_MEDIA_OVERLAY:
return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
case TYPE_APPLICATION_SUB_PANEL:
return APPLICATION_SUB_PANEL_SUBLAYER;
case TYPE_APPLICATION_ABOVE_SUB_PANEL:
return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER;
}
Slog.e("WindowManager", "Unknown sub-window type: " + type);
return 0; // 默认值是0
}
这个方法是处理来自client的参数, 如处理input focus , 确保特定的type的window不能获取焦点, 以下type的窗口不能获取input focus
如下代码
// @frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
/**
* Sanitize the layout parameters coming from a client. Allows the policy
* to do things like ensure that windows of a specific type can't take
* input focus.
*
* @param attrs The window layout parameters to be modified. These values
* are modified in-place.
*/
public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
int callingPid, int callingUid) {
// 判断是不是PRIVATE_FLAG_IS_SCREEN_DECOR, 这个FLAG 表示装饰窗口 screen decoration similar to the nav bar and status bar
final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
if (mScreenDecorWindows.contains(win)) {
if (!isScreenDecor) {
// No longer has the flag set, so remove from the set.
mScreenDecorWindows.remove(win);
}
} else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
mScreenDecorWindows.add(win);
}
switch (attrs.type) {
case TYPE_SYSTEM_OVERLAY:
case TYPE_SECURE_SYSTEM_OVERLAY:
// These types of windows can't receive input events.
attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
break;
case TYPE_WALLPAPER:
// Dreams and wallpapers don't have an app window token and can thus not be
// letterboxed. Hence always let them extend under the cutout.
attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
break;
case TYPE_NOTIFICATION_SHADE:
// If the Keyguard is in a hidden state (occluded by another window), we force to
// remove the wallpaper and keyguard flag so that any change in-flight after setting
// the keyguard as occluded wouldn't set these flags again.
// See {@link #processKeyguardSetHiddenResultLw}.
if (mService.mPolicy.isKeyguardOccluded()) {
attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
}
break;
case TYPE_TOAST:
// While apps should use the dedicated toast APIs to add such windows
// it possible legacy apps to add the window directly. Therefore, we
// make windows added directly by the app behave as a toast as much
// as possible in terms of timeout and animation.
if (attrs.hideTimeoutMilliseconds < 0
|| attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
}
// Accessibility users may need longer timeout duration. This api compares
// original timeout with user's preference and return longer one. It returns
// original timeout if there's no preference.
attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
(int) attrs.hideTimeoutMilliseconds,
AccessibilityManager.FLAG_CONTENT_TEXT);
attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
// Toast can show with below conditions when the screen is locked.
if (canToastShowWhenLocked(callingPid)) {
attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
}
// Toasts can't be clickable
attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
break;
case TYPE_BASE_APPLICATION:
// A non-translucent main app window isn't allowed to fit insets, as it would create
// a hole on the display!
if (attrs.isFullscreen() && win.mActivityRecord != null
&& win.mActivityRecord.fillsParent()
&& (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
&& attrs.getFitInsetsTypes() != 0) {
throw new RuntimeException("Illegal attributes: Main activity window that isn't"
+ " translucent trying to fit insets: "
+ attrs.getFitInsetsTypes()
+ " attrs=" + attrs);
}
break;
}
}
每个Display有一个displayId,对应着一个DisplayContent, 每个DisplayContent会创建一个DisplayPolicy, 因此在DisplayPolicy中确保WindowState的唯一性.可以保证此window在display的唯一性
此方法会检查添加相关type的窗口所需要的权限, 另外对于以下特殊的type在每个display禁止重复添加:
代码如下
// @frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
/**
* Check if a window can be added to the system.
*
* Currently enforces that two window types are singletons per display:
*
* - {@link WindowManager.LayoutParams#TYPE_STATUS_BAR}
* - {@link WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}
* - {@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}
*
*
* @param attrs Information about the window to be added.
*
* @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,
* WindowManagerImpl.ADD_MULTIPLE_SINGLETON
*/
int validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid) {
if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
}
switch (attrs.type) {
case TYPE_STATUS_BAR:
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
if (mStatusBar != null) {
if (mStatusBar.isAlive()) {
return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
}
}
break;
case TYPE_NOTIFICATION_SHADE:
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
if (mNotificationShade != null) {
if (mNotificationShade.isAlive()) {
return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
}
}
break;
case TYPE_NAVIGATION_BAR:
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
if (mNavigationBar != null) {
if (mNavigationBar.isAlive()) {
return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
}
}
break;
case TYPE_NAVIGATION_BAR_PANEL:
// Check for permission if the caller is not the recents component.
if (!mService.mAtmInternal.isCallerRecents(callingUid)) {
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
}
break;
case TYPE_STATUS_BAR_ADDITIONAL:
case TYPE_STATUS_BAR_SUB_PANEL:
case TYPE_VOICE_INTERACTION_STARTING:
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
break;
case TYPE_TRUSTED_APPLICATION_OVERLAY:
mContext.enforcePermission(
android.Manifest.permission.INTERNAL_SYSTEM_WINDOW, callingPid, callingUid,
"DisplayPolicy");
break;
case TYPE_STATUS_BAR_PANEL:
return WindowManagerGlobal.ADD_INVALID_TYPE;
}
if (attrs.providesInsetsTypes != null) {
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
enforceSingleInsetsTypeCorrespondingToWindowType(attrs.providesInsetsTypes);
}
return ADD_OKAY;
}
在WMS的addWindow方法方法会根据客户端传递过来的参数判断是否创建input channel, 要创建需满足以下条件:
代码如下
// @WMS#addWindow
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
win.openInputChannel(outInputChannel);
}
这个方法用于创建输入事件的管道
// @frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void openInputChannel(InputChannel outInputChannel) {
if (mInputChannel != null) { // 不能为此WindowState重复创建input channel
throw new IllegalStateException("Window already has an input channel.");
}
String name = getName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); // 创建一个input channel 对
mInputChannel = inputChannels[0];
mClientChannel = inputChannels[1];
mWmService.mInputManager.registerInputChannel(mInputChannel); // 将0端的InputChannel注册到IMS
mInputWindowHandle.token = mInputChannel.getToken();
if (outInputChannel != null) {
mClientChannel.transferTo(outInputChannel);
mClientChannel.dispose();
mClientChannel = null;
} else {
// If the window died visible, we setup a dummy input channel, so that taps
// can still detected by input monitor channel, and we can relaunch the app.
// Create dummy event receiver that simply reports all events as handled.
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
}
mWmService.mInputToWindowMap.put(mInputWindowHandle.token, this);
},
这个方法首先通过openInputChannelPair 创建了一个socket pair , 然后通过registerInputChannel 将socketfd[0]注册到了IMS, 将socketfd[1]端通过transferTo转换到了outInputChannel, 之后这个outInputChannel返回给客户端, 这样就使得IMS与客户端建立了事件分发与反馈的通道.
在客户端的ViewRootImpl通过此channel创建一个WindowInputEventReceiver, 通过此receiver可以接收到来自IMS端分发的事件, 也可以向其反馈事件处理完毕. 这部分内容比较多,在另外一篇文章进行叙述
下面引用深入理解Android 卷3 一张图来描述这个通信过程
接下来看WindowState的attach方法
void attach() {
if (DEBUG) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
mSession.windowAddedLocked(mAttrs.packageName); // 调用session的windowAddedLocked方法
}
void windowAddedLocked(String packageName) {
mPackageName = packageName;
mRelayoutTag = "relayoutWindow: " + mPackageName;
if (mSurfaceSession == null) { // 没有SurfaceSession, 则创建一个
if (DEBUG) {
Slog.v(TAG_WM, "First window added to " + this + ", creating SurfaceSession");
}
mSurfaceSession = new SurfaceSession(); // 关键类, 用于与SurfaceFlinger通信
ProtoLog.i(WM_SHOW_TRANSACTIONS, " NEW SURFACE SESSION %s", mSurfaceSession);
mService.mSessions.add(this); // 将此session对象添加到
if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
mService.dispatchNewAnimatorScaleLocked(this);
}
}
mNumWindow++; // window 数量递增
}
首先看看源文件的描述, 它代表了与 SurfaceFlinger之间的一个连接, 通过它来创建一个或多个Surface , 然后在这些Surface上进行绘制, 最后将这些Surface效果混合显示到屏幕
/**
* An instance of this class represents a connection to the surface
* flinger, from which you can create one or more Surface instances that will
* be composited to the screen.
* {@hide}
*/
public final class SurfaceSession {
// Note: This field is accessed by native code.
@UnsupportedAppUsage
private long mNativeClient; // SurfaceComposerClient*
/** Create a new connection with the surface flinger. */
@UnsupportedAppUsage
public SurfaceSession() {
mNativeClient = nativeCreate(); // 通过native创建cpp SurfaceComposerClient对象
}
native方法对应的jni函数在android_view_SurfaceSession 中, 名称相同.
// @frameworks/base/core/jni/android_view_SurfaceSession.cpp
static jlong nativeCreate(JNIEnv* env, jclass clazz) {
SurfaceComposerClient* client = new SurfaceComposerClient(); // 创建SurfaceComposerClient
client->incStrong((void*)nativeCreate); // 调用一次 incStrong
return reinterpret_cast(client); // 返回此client的地址
}
SurfaceComposerClient继承自RefBase. 构造方法仅仅初始话了mStatus , 重点是 incStrong调用, 它会触发onFirstRef方法的调用
/// @frameworks/native/libs/gui/SurfaceComposerClient.cpp
SurfaceComposerClient::SurfaceComposerClient()
: mStatus(NO_INIT)
{
}
void SurfaceComposerClient::onFirstRef() {
sp sf(ComposerService::getComposerService()); // 获取 SurfaceFlinger
if (sf != nullptr && mStatus == NO_INIT) {
sp conn;
conn = sf->createConnection(); // 创建 connection
if (conn != nullptr) {
mClient = conn;
mStatus = NO_ERROR;
}
}
}
/// @frameworks/native/libs/gui/SurfaceComposerClient.cpp
/*static*/ sp ComposerService::getComposerService() {
ComposerService& instance = ComposerService::getInstance(); // 获取单例
Mutex::Autolock _l(instance.mLock);
if (instance.mComposerService == nullptr) {
ComposerService::getInstance().connectLocked(); // 连接ComposerService
assert(instance.mComposerService != nullptr);
ALOGD("ComposerService reconnected");
}
return instance.mComposerService;
}
构造方法自动连接sf
ComposerService::ComposerService()
: Singleton() {
Mutex::Autolock _l(mLock);
connectLocked();
}
connectLocked 实际上获取的是 SurfaceFlinger 服务 , 同时会注册sf的死亡监听
void ComposerService::connectLocked() {
const String16 name("SurfaceFlinger");
while (getService(name, &mComposerService) != NO_ERROR) {
usleep(250000);
}
assert(mComposerService != nullptr);
// Create the death listener.
class DeathObserver : public IBinder::DeathRecipient {
ComposerService& mComposerService;
virtual void binderDied(const wp& who) {
ALOGW("ComposerService remote (surfaceflinger) died [%p]",
who.unsafe_get());
mComposerService.composerServiceDied();
}
public:
explicit DeathObserver(ComposerService& mgr) : mComposerService(mgr) { }
};
mDeathObserver = new DeathObserver(*const_cast(this));
IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver);
}
// 从sm获取service
template
status_t getService(const String16& name, sp* outService)
{
const sp sm = defaultServiceManager();
if (sm != nullptr) {
*outService = interface_cast(sm->getService(name));
if ((*outService) != nullptr) return NO_ERROR;
}
return NAME_NOT_FOUND;
}
sp SurfaceFlinger::createConnection() {
const sp client = new Client(this); // 创建并返回一个 Client
return client->initCheck() == NO_ERROR ? client : nullptr;
}
Client 类继承自 BnSurfaceComposerClient , 按binder的通信架构来看, 它是属于通信的服务端, 返回给WMS的实际上是它的bp端. 通过此Client, WMS就可以与SurfaceFlinger进行通信了, 完成类似createSurface 的操作. 为什么要需要多添加一个Client, 直接与SurfaceFlinger交互不行吗? 理论上是可行的. 在我看来,使用Client有2个好处. 一是使用Client可以更好的管理和组织Session - SurfaceSession - Client 这样一对一的关系,使结构层次更清晰. 另外, 将任务首先交给Client处理, 可以减轻sf的工作压力.
class Client : public BnSurfaceComposerClient
{
public:
explicit Client(const sp& flinger);
~Client() = default;
status_t initCheck() const;
// protected by SurfaceFlinger::mStateLock
void attachLayer(const sp& handle, const sp& layer);
void detachLayer(const Layer* layer);
sp getLayerUser(const sp& handle) const;
private:
// ISurfaceComposerClient interface
virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags, const sp& parent,
LayerMetadata metadata, sp* handle,
sp* gbp,
uint32_t* outTransformHint = nullptr);
...
}
经过以上流程, 客服端对应了WMS唯一的Session, 而Session持有了独一份的SurfaceSession , SurfaceSession 进一步创建SurfaceComposerClient. 在SurfaceComposerClient中通过SurfaceFinger.createConnection创建与sf的连接,即Client. 通过此Client来完成layer/surface相关操作.
/** Mapping from an IWindow IBinder to the server's Window object. */
final HashMap mWindowMap = new HashMap<>();
WMS@addWindow{...
mWindowMap.put(client.asBinder(), win);
win.initAppOpsState();
//...
}
WindowState都保存到mWindowMap, 以客户端传递过来的IWindow为键, WindowState对象为值
这个方法主要处理窗口的显示状态. 成员mAppOpVisibility 默认为true. 成员mAppOp 是在WindowState的构造方法中赋值, 是在创建WindowState时传入的appOp[0]. 而这个appOp[0] 是在PhoneWindowManager#checkAddPermission 方法中初始化的. appOp[0] 有如下几种取值:
因此检查的操作主要是 OP_TOAST_WINDOW 和 OP_SYSTEM_ALERT_WINDOW . 若用户修改了相关应用显示这些窗口的权限, 将导致窗口不会显示出来.
void initAppOpsState() {
if (mAppOp == OP_NONE || !mAppOpVisibility) {
return;
}
// If the app op was MODE_DEFAULT we would have checked the permission
// and add the window only if the permission was granted. Therefore, if
// the mode is MODE_DEFAULT we want the op to succeed as the window is
// shown.
final int mode = mWmService.mAppOps.startOpNoThrow(mAppOp, getOwningUid(),
getOwningPackage(), true /* startIfModeDefault */, null /* featureId */,
"init-default-visibility"); // 检查操作是否被允许
if (mode != MODE_ALLOWED && mode != MODE_DEFAULT) {
setAppOpVisibilityLw(false); // 设置可见性为false
}
}
更新窗口的可见性
private void setAppOpVisibilityLw(boolean state) {
if (mAppOpVisibility != state) {
mAppOpVisibility = state; // 改变mAppOpVisibility
if (state) {
// If the policy visibility had last been to hide, then this
// will incorrectly show at this point since we lost that
// information. Not a big deal -- for the windows that have app
// ops modifies they should only be hidden by policy due to the
// lock screen, and the user won't be changing this if locked.
// Plus it will quickly be fixed the next time we do a layout.
showLw(true, true); // 显示
} else {
hideLw(true, true); // 隐藏
}
}
}
这篇主要设计到WindowState相关的部分, 包含但不限于创建WindowState, 调整窗口显示的参数, 检查窗口重复添加性, 窗口对应的InputChannel的创建, SurfaceSession的创建, 以及一些其他初始化操作. 这些准备为后面的窗口的管理,显示,动画,事件等打下了基础.
WindowState中几个比较重要的初始化操作:
本篇部分细节过长, 留待后续进行分析.