歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android4.0 WindowManagerService的分析

對於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