Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / Android4.0 WindowManagerService的分析

对于Activity,在ActivityThread.java在handleLaunchActivity会调用performLaunchActivity,而performLaunchActivity则调用Activity中的attach函数,实现创建window(实际是PhoneWindow):Activity.javafinal 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) {
//创建windowmWindow = 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.javapublic 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.javapublic 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 modeif (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {       mWindow.setSoftInputMode(info.softInputMode);}if (info.uiOptions != 0) {   mWindow.setUiOptions(info.uiOptions);}
我们回到最初,我们说过,在ActivityThread中会在performLaunchActivity之后判断是否成功,并真正调用handleResumeActivity();
ActivityThread.javafinal 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.javapublic 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中了,若有就返回对应的indexint 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.javapublic 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和ControlledInputConnectionWrappersWindowSession = 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类型的mClientpublic 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.javapublic 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是inputChannelpublic 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 访问 WindowManagerServiceWindowManagerService通过IWindow访问ViewRootImpl