歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android4.0 WindowManagerService的分析

Android4.0 WindowManagerService的分析

日期:2017/3/1 10:16:47   编辑:Linux編程

對於Activity,在ActivityThread.java在handleLaunchActivity會調用performLaunchActivity,而performLaunchActivity則調用Activity中的attach函數,實現創建window(實際是PhoneWindow):

Activity.java

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) {


//創建window

mWindow = PolicyManager.makeNewWindow(this);

mWindow.setCallback(this);

mWindow.getLayoutInflater().setPrivateFactory(this);

if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {

mWindow.setSoftInputMode(info.softInputMode);

}

if (info.uiOptions != 0) {

mWindow.setUiOptions(info.uiOptions);

}


//獲取WindowManager

mWindow.setWindowManager(null, mToken, mComponent.flattenToString(),

(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);

mWindowManager = mWindow.getWindowManager();

}


PolicyManager.java

public static Window makeNewWindow(Context context) {

//使用sPolicy來創建window

return sPolicy.makeNewWindow(context);

}

這裡的sPolicy定義是:private static final IPolicy sPolicy;

那麼,如何初始化?

private static final String POLICY_IMPL_CLASS_NAME =

"com.Android.internal.policy.impl.Policy";

static {

// 獲取Policy這個class並實例化

try {

Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);

sPolicy = (IPolicy)policyClass.newInstance();

}

}


再往下:

Policy.java

public class Policy implements IPolicy {

public Window makeNewWindow(Context context) {

/*可見,activity.attach中的PolicyManager.makeNewWindow(this)是新建一個PhoneWindow

*context則是Activity中實現的ContextImpl實例

*而PhoneWindow是window的子類,故而可以賦給window

*/

return new PhoneWindow(context);

}

……

}

由Policy的定義可知,Policy implement IPolicy,並且實現了它定義的接口。

/*至此,實現了創建一個PhoneWindow*/


接著Activity.attach往下:

//設置window的Callback,Activity是實現了Window.Callback的接口的

mWindow.setCallback(this);

mWindow.getLayoutInflater().setPrivateFactory(this);

//設置soft input mode

if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {

mWindow.setSoftInputMode(info.softInputMode);

}

if (info.uiOptions != 0) {

mWindow.setUiOptions(info.uiOptions);

}


我們回到最初,我們說過,在ActivityThread中會在performLaunchActivity之後判斷是否成功,並真正調用handleResumeActivity();


ActivityThread.java

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {

ActivityClientRecord r = performResumeActivity(token, clearHide);

//這個layoutParams是在ActivityClientRecord 這裡的。

WindowManager.LayoutParams l = r.window.getAttributes();

……

/*

*r是ActivityClientRecord,在performResumeActivity之前並沒有將window加入到r中

*那麼,activity如何創建並且是如何加入到這個activityClientRecord中的呢?

*/

if (r.window == null && !a.mFinished && willBeVisible) {

//在activity的attach函數中創建的activity的window賦給r.window

r.window = r.activity.getWindow();


//我們知道attach創建的是PhoneWindow,那PhoneWindow中DecorView如何創建的?

View decor = r.window.getDecorView();

decor.setVisibility(View.INVISIBLE);


//WindowManager是ViewManager的子類

ViewManager wm = a.getWindowManager();

WindowManager.LayoutParams l = r.window.getAttributes();


//將decor賦給Activity的mDecor

a.mDecor = decor;

//type的數值是1

l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

l.softInputMode |= forwardBit;


if (a.mVisibleFromClient) {

a.mWindowAdded = true;

//將主View(decorView)添加到WindowManager中

wm.addView(decor, l);

}

}


}

我們在Context的分析中已經分析過,WindowManager實際上初始化的是WindowManagerImpl,通過它來進行各種操作,我們轉到WindowManagerImpl.java分析addView


PhoneWindow.java

是這樣獲取DecorView的

public final View getDecorView() {

if (mDecor == null) {

installDecor();

}

return mDecor;

}


private void installDecor() {

if (mDecor == null) {

//創建DecorView,接著往下去看如何創建DecorView,DecorView是個什麼?

mDecor = generateDecor();

mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

mDecor.setIsRootNamespace(true);

}


if (mContentParent == null) {

//這個mContentParent是干什麼的?

mContentParent = generateLayout(mDecor);

}

}


private final class DecorView extends FrameLayout implements RootViewSurfaceTaker

{

public DecorView(Context context, int featureId) {

super(context);

mFeatureId = featureId;

}


/*

*DecorView中還實現了派發key event、key快捷方式等方法

*/

public boolean dispatchKeyEvent(KeyEvent event) {

……

}


public boolean dispatchKeyShortcutEvent(KeyEvent ev) {

……

}

}

由DecorView定義我們可以知道,DecorView是一個擴張的FrameLayout,它是所有當前的Activity中View的主View


WindowManagerImpl.java

public void addView(View view, ViewGroup.LayoutParams params, CompatibilityInfoHolder cih) {

addView(view, params, cih, false);

}


private void addView(View view, ViewGroup.LayoutParams params,

CompatibilityInfoHolder cih, boolean nest) {

//這說明將DecorView添加到WindowManager必須要滿足下面這個條件,否則會報異常

if (!(params instanceof WindowManager.LayoutParams)) {

throw new IllegalArgumentException(

"Params must be WindowManager.LayoutParams");

}


final WindowManager.LayoutParams wparams

= (WindowManager.LayoutParams)params;


ViewRootImpl root;

View panelParentView = null;


synchronized (this) {

//主要是查看要添加的View是否已經在mViews中了,若有就返回對應的index

int index = findViewLocked(view, false);

if (index >= 0) {

if (!nest) {

throw new IllegalStateException("View " + view

+ " has already been added to the window manager.");

}

//為什麼這樣,因為若添加了view到mViews,那麼mRoots也對應添加

root = mRoots[index];

root.mAddNesting++;

// Update layout parameters.

view.setLayoutParams(wparams);

root.setLayoutParams(wparams, true);

return;

}


root = new ViewRootImpl(view.getContext());

//第一次添加view到mView,mViews是還沒有分配空間的

if (mViews == null) {

index = 1;

mViews = new View[1];

mRoots = new ViewRootImpl[1];

mParams = new WindowManager.LayoutParams[1];

} else {

//這裡奇怪的是,為什麼將mViews、mRoots中內容先保存然後再拷貝一遍呢?

index = mViews.length + 1;

Object[] old = mViews;

mViews = new View[index];

System.arraycopy(old, 0, mViews, 0, index-1);

old = mRoots;

mRoots = new ViewRootImpl[index];

System.arraycopy(old, 0, mRoots, 0, index-1);

old = mParams;

mParams = new WindowManager.LayoutParams[index];

System.arraycopy(old, 0, mParams, 0, index-1);

}

index--;

//這裡就完成了添加View到WindowManager

mViews[index] = view;

mRoots[index] = root;

mParams[index] = wparams;

}

//這一步非常重要

root.setView(view, wparams, panelParentView);

}


ViewRootImpl.java

public ViewRootImpl(Context context) {

getWindowSession(context.getMainLooper());


//獲取當前activity的線程

mThread = Thread.currentThread();

//IWindow的代理,在ViewRootImpl中創建

//這裡強調一下,創建W時傳入this,代指ViewRootImpl的ContextImpl,而這個ContextImpl又是由

//WindowManagerImpl傳入的ContextImpl,再之後就是當前的調用者的ContextImpl傳遞給//ContextImpl.java的獲取Service時傳入的。這樣看來,在當前的上下文創建了一個實例,只要傳入它的//Context,那麼,都是可以通過Context找到這個當前調用者的

mWindow = new W(this);

}


public static IWindowSession getWindowSession(Looper mainLooper) {

synchronized (mStaticInit) {

if (!mInitialized) {

try {

//先獲取InputMethodManager,然後用它調用InputMethodManagerService

InputMethodManager imm = InputMethodManager.getInstance(mainLooper);


//獲取WindowManagerService中的Session,同時我們看到這裡用到了

//InputMethodManagerService的mClient和ControlledInputConnectionWrapper

sWindowSession = Display.getWindowManager().openSession(

imm.getClient(), imm.getInputContext());

mInitialized = true;

} catch (RemoteException e) {

}

}

//注意:sWindowSession是個全局變量

return sWindowSession;

}

}


WindowManagerService.java

這個sWindowSession是在WindowManagerService中實現的,是client調用WindowManagerService的接口。

每一個ViewRoot對應在WindowManagerService中有一個sWindowSession

同時我們注意,這裡傳入的client是InputMethodManager中的IInputMethodClient類型的mClient

public IWindowSession openSession(IInputMethodClient client,

IInputContext inputContext) {

……

//創建一個Session並返回

//在這個Session的構造函數中有如下操作:

//mService.mInputMethodManager.addClient(client, inputContext, mUid, mPid);

//將InputMethodManger中的mClient添加進去了

Session session = new Session(this, client, inputContext);


return session;

}

我們接著,WindowManagerImpl往下看,在setView的最後會調用ViewRoot.setView(),這個是連接client和

WindowManagerService的關鍵地方:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {

……

try {

mOrigWindowType = mWindowAttributes.type;

//這裡調用

res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,

getHostVisibility(), mAttachInfo.mContentInsets, mInputChannel);

} catch (RemoteException e) {

……

}

}


Session.java

public int add(IWindow window, int seq, WindowManager.LayoutParams attrs,

int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) {

//如此,將Client端提供給WindowManagerService的接口IWindow賦給WindowManagerService使用

return mService.addWindow(this, window, seq, attrs, viewVisibility, outContentInsets,

outInputChannel);

}


WindowManagerService.java

//主要是將PhoneWindow的回調函數IWindow傳遞給WindowManagerService

//outInputChannel是inputChannel

public int addWindow(Session session, IWindow client, int seq,

WindowManager.LayoutParams attrs, int viewVisibility,

Rect outContentInsets, InputChannel outInputChannel) {

WindowState win = null;


win = new WindowState(this, session, client, token,

attachedWindow, seq, attrs, viewVisibility);


……

win.attach();


if (outInputChannel != null && (attrs.inputFeatures

& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {

String name = win.makeInputChannelName();

InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);

win.setInputChannel(inputChannels[0]);

inputChannels[1].transferTo(outInputChannel);

mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);

}

}

在windowState.java中調用attach:

void attach() {

mSession.windowAddedLocked();

}

最後在Session.java中實現添加:

void windowAddedLocked() {

if (mSurfaceSession == null) {

mSurfaceSession = new SurfaceSession();

mService.mSessions.add(this);

}


mNumWindow++;

}


至此,正式建立activity的client和windowManagerService之間的聯系:

ViewRootImpl 通過IWindowSession 訪問 WindowManagerService

WindowManagerService通過IWindow訪問ViewRootImpl

Copyright © Linux教程網 All Rights Reserved