Android7.0 Activity的绘制加载流程

时间:2022-04-14 22:38:52

涉及类:

frameworks\base\core\java\android\app\Activity.java

frameworks\base\core\java\com\android\internal\policy\PhoneWindow.java

frameworks\base\core\java\com\android\internal\policy\DecorView.java

frameworks\base\core\java\android\view\WindowManagerImpl.java

frameworks\base\core\java\android\view\WindowManagerGlobal.java

frameworks\base\core\java\android\view\ViewRootImpl.java

 

.简述

当我们通过点击Launcher图标的方式去启动一个应用,如果该应用首次启动的话,系统会为其创建进程,并且启动它的首个界面,对于Activity的启动,在Activity的启动流程分析中也详细介绍过了,但是对于Activity启动之后,是如何展示给我们用户看的,对于它的绘制渲染过程,请看以下分析

.绘制加载流程

2.1. Activity.attach

[-> Activity.java]

    final void attach(Context context,ActivityThread aThread,

           Instrumentation instr, IBindertoken, int ident,

           Application application, Intentintent, ActivityInfo info,

           CharSequence title, Activityparent, String id,

           NonConfigurationInstances lastNonConfigurationInstances,

           Configuration config, Stringreferrer, IVoiceInteractor voiceInteractor,

           Window window) {

        attachBaseContext(context);

 

        mFragments.attachHost(null /*parent*/);

//为应用程序创建属于它的窗口对象

        mWindow = new PhoneWindow(this,window);

       mWindow.setWindowControllerCallback(this);

//将当前Activity对象传入窗口对象,设置回调,以便Activity能够响应窗口事件

        mWindow.setCallback(this);

       mWindow.setOnWindowDismissedCallback(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);

        }

        mUiThread = Thread.currentThread();

 

        mMainThread = aThread;

        mInstrumentation = instr;

        mToken = token;

        mIdent = ident;

        mApplication = application;

        mIntent = intent;

        mReferrer = referrer;

        mComponent = intent.getComponent();

        mActivityInfo = info;

        mTitle = title;

        mParent = parent;

        mEmbeddedID = id;

        mLastNonConfigurationInstances =lastNonConfigurationInstances;

        if (voiceInteractor != null) {

           if (lastNonConfigurationInstances!= null) {

               mVoiceInteractor =lastNonConfigurationInstances.voiceInteractor;

           } else {

               mVoiceInteractor = newVoiceInteractor(voiceInteractor, this, this,

                       Looper.myLooper());

           }

        }

//设置当前窗口的管理

        mWindow.setWindowManager(

               (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),

               mToken,mComponent.flattenToString(),

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

        if (mParent != null) {

           mWindow.setContainer(mParent.getWindow());

        }

        mWindowManager =mWindow.getWindowManager();

        mCurrentConfig = config;

    }

Activity的界面绘制皆依于这个方法,Activity的初始化过程,对于我们首次启动需要创建承载其运行的应用程序,它的窗口对象的创建也是在此过程中完成。

当我们编写自己的Activity的时候重写onCreate方法,在方法体内会写上setContentView方法

此时从代码中看得出来,我们所创建的window还有Activity的界面内容,都还是处于模糊状态,到这里不能真正明白什么是window什么是Activity的内容界面,以及他们之间的关系?

当我们执行Activity启动流程的时候,执行performLaunchActivity然后回调ActivityonCreate方法,进而执行setContentview

2.2. Activity. setContentView

[->Activity.java]

    public void setContentView(@LayoutRes intlayoutResID) {

       getWindow().setContentView(layoutResID);

        initWindowDecorActionBar();

    }

这里通过getWindow方法获取在attach方法中创建的PhoneWindow,并且调用其setContentView方法

2.3. PW. setContentView

[->PhoneWindow.java]

    @Override

    public void setContentView(int layoutResID){

        // Note: FEATURE_CONTENT_TRANSITIONSmay be set in the process of installing the window

        // decor, when theme attributes and thelike are crystalized. Do not check the feature

        // before this happens.

        if (mContentParent == null) {

           installDecor();

        } else if(!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

           mContentParent.removeAllViews();

        }

 

        if(hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

           final Scene newScene =Scene.getSceneForLayout(mContentParent, layoutResID,

                   getContext());

           transitionTo(newScene);

        } else {

           mLayoutInflater.inflate(layoutResID, mContentParent);

        }

        mContentParent.requestApplyInsets();

        final Callback cb = getCallback();

        if (cb != null &&!isDestroyed()) {

           cb.onContentChanged();

        }

        mContentParentExplicitlySet = true;

    }

这里我们首次启动该Activity,所以mContentParent==null,调用installDecor

2.3. PW. installDecor

[->PhoneWindow.java]

    private void installDecor() {

        mForceDecorInstall = false;

        if (mDecor == null) {

           mDecor = generateDecor(-1);

           mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

           mDecor.setIsRootNamespace(true);

           if (!mInvalidatePanelMenuPosted&& mInvalidatePanelMenuFeatures != 0) {

               mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);

           }

        } else {

           mDecor.setWindow(this);

        }

        if (mContentParent == null) {

           mContentParent = generateLayout(mDecor);

 

           // Set up decor part of UI toignore fitsSystemWindows if appropriate.

           mDecor.makeOptionalFitsSystemWindows();

 

           final DecorContentParentdecorContentParent = (DecorContentParent) mDecor.findViewById(

                   R.id.decor_content_parent);

 

           if (decorContentParent != null) {

               mDecorContentParent =decorContentParent;

               mDecorContentParent.setWindowCallback(getCallback());

               if(mDecorContentParent.getTitle() == null) {

                   mDecorContentParent.setWindowTitle(mTitle);

               }

 

               final int localFeatures =getLocalFeatures();

               for (int i = 0; i <FEATURE_MAX; i++) {

                   if ((localFeatures & (1<< i)) != 0) {

                       mDecorContentParent.initFeature(i);

                   }

               }

 

               mDecorContentParent.setUiOptions(mUiOptions);

 

               if ((mResourcesSetFlags &FLAG_RESOURCE_SET_ICON) != 0 ||

                       (mIconRes != 0&& !mDecorContentParent.hasIcon())) {

                   mDecorContentParent.setIcon(mIconRes);

               } else if ((mResourcesSetFlags& FLAG_RESOURCE_SET_ICON) == 0 &&

                       mIconRes == 0&& !mDecorContentParent.hasIcon()) {

                   mDecorContentParent.setIcon(

                           getContext().getPackageManager().getDefaultActivityIcon());

                   mResourcesSetFlags |=FLAG_RESOURCE_SET_ICON_FALLBACK;

               }

               if ((mResourcesSetFlags &FLAG_RESOURCE_SET_LOGO) != 0 ||

                       (mLogoRes != 0&& !mDecorContentParent.hasLogo())) {

                   mDecorContentParent.setLogo(mLogoRes);

               }

 

               // Invalidate if the panel menuhasn't been created before this.

               // Panel menu invalidation isdeferred avoiding application onCreateOptionsMenu

               // being called in the middleof onCreate or similar.

               // A pending invalidation willtypically be resolved before the posted message

               // would run normally in orderto satisfy instance state restoration.

               PanelFeatureState st =getPanelState(FEATURE_OPTIONS_PANEL, false);

               if (!isDestroyed() &&(st == null || st.menu == null) && !mIsStartingWindow) {

                   invalidatePanelMenu(FEATURE_ACTION_BAR);

               }

           } else {

               mTitleView = (TextView)findViewById(R.id.title);

               if (mTitleView != null) {

                   if ((getLocalFeatures()& (1 << FEATURE_NO_TITLE)) != 0) {

                       final ViewtitleContainer = findViewById(R.id.title_container);

                       if (titleContainer !=null) {

                           titleContainer.setVisibility(View.GONE);

                       } else {

                           mTitleView.setVisibility(View.GONE);

                       }

                       mContentParent.setForeground(null);

                   } else {

                       mTitleView.setText(mTitle);

                   }

               }

           }

 

           if (mDecor.getBackground() == null&& mBackgroundFallbackResource != 0) {

               mDecor.setBackgroundFallback(mBackgroundFallbackResource);

           }

 

           // Only inflate or create a newTransitionManager if the caller hasn't

           // already set a custom one.

           if(hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {

               if (mTransitionManager == null){

                   final int transitionRes =getWindowStyle().getResourceId(

                           R.styleable.Window_windowContentTransitionManager,

                           0);

                   if (transitionRes != 0) {

                       finalTransitionInflater inflater = TransitionInflater.from(getContext());

                       mTransitionManager =inflater.inflateTransitionManager(transitionRes,

                               mContentParent);

                   } else {

                       mTransitionManager =new TransitionManager();

                   }

               }

 

               mEnterTransition =getTransition(mEnterTransition, null,

                       R.styleable.Window_windowEnterTransition);

               mReturnTransition =getTransition(mReturnTransition, USE_DEFAULT_TRANSITION,

                       R.styleable.Window_windowReturnTransition);

               mExitTransition =getTransition(mExitTransition, null,

                       R.styleable.Window_windowExitTransition);

               mReenterTransition =getTransition(mReenterTransition, USE_DEFAULT_TRANSITION,

                       R.styleable.Window_windowReenterTransition);

               mSharedElementEnterTransition =getTransition(mSharedElementEnterTransition, null,

                       R.styleable.Window_windowSharedElementEnterTransition);

               mSharedElementReturnTransition= getTransition(mSharedElementReturnTransition,

                       USE_DEFAULT_TRANSITION,

                       R.styleable.Window_windowSharedElementReturnTransition);

               mSharedElementExitTransition =getTransition(mSharedElementExitTransition, null,

                       R.styleable.Window_windowSharedElementExitTransition);

               mSharedElementReenterTransition= getTransition(mSharedElementReenterTransition,

                       USE_DEFAULT_TRANSITION,

                       R.styleable.Window_windowSharedElementReenterTransition);

               if (mAllowEnterTransitionOverlap== null) {

                   mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(

                           R.styleable.Window_windowAllowEnterTransitionOverlap, true);

               }

               if (mAllowReturnTransitionOverlap== null) {

                   mAllowReturnTransitionOverlap = getWindowStyle().getBoolean(

                           R.styleable.Window_windowAllowReturnTransitionOverlap, true);

               }

               if(mBackgroundFadeDurationMillis < 0) {

                   mBackgroundFadeDurationMillis = getWindowStyle().getInteger(

                           R.styleable.Window_windowTransitionBackgroundFadeDuration,

                           DEFAULT_BACKGROUND_FADE_DURATION_MS);

               }

               if (mSharedElementsUseOverlay== null) {

                   mSharedElementsUseOverlay =getWindowStyle().getBoolean(

                           R.styleable.Window_windowSharedElementsUseOverlay, true);

               }

           }

        }

}

  • 调用generateDecor方法生成DecorView,对于这个Decorview,就是就是window中最*view,它包含了window中所有的view这里对于DecorView在补充中做了详细的解释
  • 调用generateLayout为mContentParent赋值

2.4. PW. generateDecor

[->PhoneWindow.java]

    protected DecorView generateDecor(intfeatureId) {

        // System process doesn't haveapplication context and in that case we need to directly use

        // the context we have. Otherwise wewant the application context, so we don't cling to the

       // activity.

        Context context;

        if (mUseDecorContext) {

           Context applicationContext =getContext().getApplicationContext();

           if (applicationContext == null) {

               context = getContext();

           } else {

               context = newDecorContext(applicationContext, getContext().getResources());

               if (mTheme != -1) {

                   context.setTheme(mTheme);

               }

           }

        } else {

           context = getContext();

        }

        return new DecorView(context,featureId, this, getAttributes());

    }

创建了一个DecorView

2.5. PW. generateLayout

[->PhoneWindow.java]

这里代码较多舍略

generateLayout的工作主要可分为:

  • 设置窗口的风格Feature,
  • 设置标题栏
  • 找到id为content的view并且返回赋值给mContentParent

当珍执行到这里的时候我们Activity的界面就算是绘制完成了,这里面有几个比较重要的变量,mWindow(Phonewindow)mDecor(DecorView)mContentParent(ViewGroup)

当系统为了显示Activity界面做足了准备之后,并且Activity的启动也到了handleResumeActivity这一步,这里就是要让Activity界面展示在手机的屏幕上,其中执行了这么一串代码r.activity.makeVisible(),进入流程2.6

2.6. Activity. makeVisible

[-> Activity.java]

    void makeVisible() {

        if (!mWindowAdded) {

           ViewManager wm =getWindowManager();

           wm.addView(mDecor,getWindow().getAttributes());

           mWindowAdded = true;

        }

        mDecor.setVisibility(View.VISIBLE);

    }

这里wm.addView调用的就是WindowManagerImpladdView

2.7. WMI.addView

[->WindowManagerImpl.java]

    public void addView(@NonNull View view,@NonNull ViewGroup.LayoutParams params) {

       android.util.SeempLog.record_vg_layout(383,params);

        applyDefaultToken(params);

        mGlobal.addView(view, params,mContext.getDisplay(), mParentWindow);

    }

mGlobal就是WindowManagerGlobal的对象

2.8. WMG. addView

[->WindowManagerGlobal.java]

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

           Display display, WindowparentWindow) {

//获取窗口的参数

        final WindowManager.LayoutParamswparams = (WindowManager.LayoutParams) params;

        if (parentWindow != null) {

           parentWindow.adjustLayoutParamsForSubWindow(wparams);

        } else {

           //获取上下文

           final Context context =view.getContext();

           if (context != null

                   &&(context.getApplicationInfo().flags

                           &ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {

               wparams.flags |=WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;

           }

        }

 

        ViewRootImpl root;

        View panelParentView = null;

 

        synchronized (mLock) {

           // Start watching for systemproperty changes.

           if (mSystemPropertyUpdater == null){

               mSystemPropertyUpdater = newRunnable() {

                   @Override public void run(){

                        synchronized (mLock) {

                           for (int i =mRoots.size() - 1; i >= 0; --i) {

                               mRoots.get(i).loadSystemProperties();

                           }

                       }

                   }

               };

               SystemProperties.addChangeCallback(mSystemPropertyUpdater);

           }

 

           int index = findViewLocked(view,false);

           if (index >= 0) {

               if (mDyingViews.contains(view)){

                   // Don't wait for MSG_DIEto make it's way through root's queue.

                   mRoots.get(index).doDie();

               } else {

                   throw newIllegalStateException("View " + view

                           + " hasalready been added to the window manager.");

               }

               // The previous removeView()had not completed executing. Now it has.

           }

 

           // If this is a panel window, thenfind the window it is being

           // attached to for futurereference.

           if (wparams.type >=WindowManager.LayoutParams.FIRST_SUB_WINDOW &&

                   wparams.type <=WindowManager.LayoutParams.LAST_SUB_WINDOW) {

               final int count =mViews.size();

               for (int i = 0; i < count;i++) {

                   if(mRoots.get(i).mWindow.asBinder() == wparams.token) {

                       panelParentView =mViews.get(i);

                   }

               }

           }

 

           root = newViewRootImpl(view.getContext(), display);

 

           view.setLayoutParams(wparams);

 

           mViews.add(view);

           mRoots.add(root);

           mParams.add(wparams);

        }

 

        // do this last because it fires offmessages to start doing things

        try {

           root.setView(view, wparams,panelParentView);

        } catch (RuntimeException e) {

           // BadTokenException orInvalidDisplayException, clean up.

           synchronized (mLock) {

               final int index =findViewLocked(view, false);

               if (index >= 0) {

                   removeViewLocked(index,true);

               }

           }

           throw e;

        }

    }

这里需要强调的是每一个App对应一个WMG,是App中全局的窗口管理模块,我们在Activity启动流程2.19中的AT.handleLaunchActivity中进行了初始化,其中WMG中有三个比较重要的数组对象(这三个对象随WMG初始化初始化):

  • ArrayList<View> mViews = new ArrayList<View>();这个负责保存mDecor
  • ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();这个用来保存ViewRootImpl用来关联View和ViewManager
  • ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();这个用来用来保存布局的属性

WMGaddview方法还创建了一个相当重要的成员就是ViewRootImpl

2.8.1 VRI. ViewRootImpl

[->ViewRootImpl.java]

    public ViewRootImpl(Context context,Display display) {

        mContext = context;

        mWindowSession =WindowManagerGlobal.getWindowSession();

        mDisplay = display;

        mBasePackageName =context.getBasePackageName();

        mThread = Thread.currentThread();

        mLocation = new WindowLeaked(null);

        mLocation.fillInStackTrace();

        mWidth = -1;

        mHeight = -1;

        mDirty = new Rect();

        mTempRect = new Rect();

        mVisRect = new Rect();

        mWinFrame = new Rect();//当前窗口的位置以及尺寸的描述,

        mWindow = new W(this);// 继承于IWindow.Stub的W对象;

        mTargetSdkVersion =context.getApplicationInfo().targetSdkVersion;

        mViewVisibility = View.GONE;

        mTransparentRegion = new Region();

        mPreviousTransparentRegion = new Region();

        mFirst = true; // true for the firsttime the view is added

        mAdded = false;

        mAttachInfo = newView.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);

        mAccessibilityManager =AccessibilityManager.getInstance(context);

       mAccessibilityInteractionConnectionManager =

           newAccessibilityInteractionConnectionManager();

       mAccessibilityManager.addAccessibilityStateChangeListener(

               mAccessibilityInteractionConnectionManager);

        mHighContrastTextManager = newHighContrastTextManager();

       mAccessibilityManager.addHighTextContrastStateChangeListener(

               mHighContrastTextManager);

        mViewConfiguration =ViewConfiguration.get(context);

        mDensity =context.getResources().getDisplayMetrics().densityDpi;

        mNoncompatDensity =context.getResources().getDisplayMetrics().noncompatDensityDpi;

        mFallbackEventHandler = new PhoneFallbackEventHandler(context);

        mChoreographer = Choreographer.getInstance();//绘制相关的对象

        mDisplayManager =(DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);

        loadSystemProperties();

    }

  • 通过WMG获取一个mWindowSession,这个是用来与WMS通信的的代理
  • mThread = Thread.currentThread();这里保存当前线程到VRI中,个人认为就是UI主线程

2.9. VRI. setView

[->ViewRootImpl.java]

VRI中就属setView和构造方法最重要,构造函数负责初始化所需要的各个成员,setView则负责创建窗口,建立输入事件接收的通道,并且请求WMS进行View绘制工作

  • 保存View
  • 创建InputChannel
  • 调用requestLayout
  • 调用mWindowSession.addToDisplay,就是最终调用的就是WMS的addWindow方法

2.9.1 WMS. addWindow

[-> WindowManagerService.java]

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

          WindowManager.LayoutParams attrs,int viewVisibility, int displayId,

          Rect outContentInsets, RectoutStableInsets, Rect outOutsets,

          InputChannel outInputChannel) {

    ...

    //创建WindowState

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

               attachedWindow, appOp[0], seq,attrs, viewVisibility, displayContent);

               

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

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

         //根据WindowState的HashCode以及title来生成InputChannel名称

        String name =win.makeInputChannelName();

       

        //创建一对InputChannel

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

        //将socket服务端保存到WindowState的mInputChannel

        win.setInputChannel(inputChannels[0]);

       

        //socket客户端传递给outInputChannel

       inputChannels[1].transferTo(outInputChannel);

        //利用socket服务端作为参数

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

    }

    ...

    boolean focusChanged = false;

    if (win.canReceiveKeys()) {

        //新添加window能接收按下操作,则更新聚焦窗口。

        focusChanged =updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,

               false /*updateInputWindows*/);

    }

    ...

   

    if (focusChanged) {

       mInputMonitor.setInputFocusLw(mCurrentFocus, false/*updateInputWindows*/);

    }

    //设置当前聚焦窗口

    mInputMonitor.updateInputWindowsLw(false/*force*/);

}

inputChannels数组:

  • inputChannels[0]所对应的InputChannel名称的后缀为(server);
  • inputChannels[1]所对应的InputChannel名称的后缀为(client)

其中:

  • 服务端inputChannels[0]保存到WindowState的mInputChannel;
  • 客户端inputChannels[1]传递给outInputChannel,最终传递给ViewRootImpl的mInputChannel;

2.9.2 InputChannel.openInputChannelPair

[-> InputChannel.java]

    public static InputChannel[]openInputChannelPair(String name) {

        if (name == null) {

           throw newIllegalArgumentException("name must not be null");

        }

 

        if (DEBUG) {

           Slog.d(TAG, "Opening inputchannel pair '" + name + "'");

        }

        returnnativeOpenInputChannelPair(name);

    }

[->android_view_InputChannel.cpp]

staticjobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,

        jclass clazz, jstring nameObj) {

    const char* nameChars =env->GetStringUTFChars(nameObj, NULL);

    String8 name(nameChars);

    env->ReleaseStringUTFChars(nameObj,nameChars);

 

    sp<InputChannel> serverChannel;

    sp<InputChannel> clientChannel;

    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

 

    if (result) {

        String8 message;

        message.appendFormat("Could notopen input channel pair. status=%d", result);

        jniThrowRuntimeException(env,message.string());

        return NULL;

    }

 

    jobjectArray channelPair =env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);

    if (env->ExceptionCheck()) {

        return NULL;

    }

 

    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,

         new NativeInputChannel(serverChannel));//将Native的InputChannel转化换成java层

    if (env->ExceptionCheck()) {

        return NULL;

    }

 

    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,

           newNativeInputChannel(clientChannel));

    if (env->ExceptionCheck()) {

        return NULL;

    }

 

    env->SetObjectArrayElement(channelPair,0, serverChannelObj);

    env->SetObjectArrayElement(channelPair,1, clientChannelObj);

    return channelPair;

}

这里需要说明的是gInputChannelClassInfo,在android_view_InputChannel.cpp已经说明jclass clazz= FindClassOrDie(env, "android/view/InputChannel");意思就是java的类,所以这里

  • gInputChannelClassInfo.mPtr InputChannel的成员变量mPtr
  • gInputChannelClassInfo.clazz指Java层的InputChannel类
  • gInputChannelClassInfo.ctor constructor的缩写指Java层的InputChannel构造方法

因此这里所创建的channelPair数组就是java层的数组

我们再来看看status_t result =InputChannel::openInputChannelPair(name, serverChannel, clientChannel);做了什么事情

[-> InputTransport.cpp]

status_tInputChannel::openInputChannelPair(const String8& name,

        sp<InputChannel>&outServerChannel, sp<InputChannel>& outClientChannel) {

    int sockets[2];

   

    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0,sockets)) {

        ...

        return result;

    }

 

    int bufferSize = SOCKET_BUFFER_SIZE;

    setsockopt(sockets[0], SOL_SOCKET,SO_SNDBUF, &bufferSize, sizeof(bufferSize));

    setsockopt(sockets[0], SOL_SOCKET,SO_RCVBUF, &bufferSize, sizeof(bufferSize));

    setsockopt(sockets[1], SOL_SOCKET,SO_SNDBUF, &bufferSize, sizeof(bufferSize));

    setsockopt(sockets[1], SOL_SOCKET,SO_RCVBUF, &bufferSize, sizeof(bufferSize));

 

    String8 serverChannelName = name;

    serverChannelName.append("(server)");

   

    outServerChannel = newInputChannel(serverChannelName, sockets[0]);

 

    String8 clientChannelName = name;

    clientChannelName.append("(client)");

   

    outClientChannel = newInputChannel(clientChannelName, sockets[1]);

    return OK;

}

到这里还是很混乱,我们理一下,InputChannel是为了能够接受Input事件用的,当我们通过调用InputChannel.openInputChannelPair,创建了一对InputChannel,当然这是调用的Native方法创建的,从代码中看InputTransport.cpp这里的openInputChannelPair算是真正创建InputChannel的地方了。因此到这里一对NativeInputChannel对象完了

  • sockets[0]所对应的InputChannel名称的后缀为(server);
  • sockets[1]所对应的InputChannel名称的后缀为(client)

回到WMS. addWindow方法中

//将socket服务端保存到WindowState的mInputChannel

        win.setInputChannel(inputChannels[0]);

       

        //socket客户端传递给outInputChannel

       inputChannels[1].transferTo(outInputChannel);

        //利用socket服务端作为参数

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

经过一系列的调用之后,我们创建好了InputChannel,然后将server端保存到SystemServerWindowStatemInputChannel中去,然后让InputDispatcher监听服务端,便于时间分发,将客户端放到Ui线程的VRI中创建的mInputChannel中去,然后Ui线程就从这个客户端中获取Input事件

2.10. VRI. requestLayout

[->ViewRootImpl.java]

这里就是涉及到Activity界面的详细的绘制,这里会检查线程,如果不是UI线程则报错,然后通过mChoreographer异步处理界面绘制操作,所以说界面的详细的绘制过程在子线程中执行的,计算组件大小,计算位置,绘制组件……..

.总结

本文大致的介绍了Activity的绘制过程,因为实际运用中,ActivityInput事件交互较多,所以侧重分析了Activity怎么能够接受到用户的按键事件的,主要通过InputChannel,对于他是怎么通过InputChannel接受事件的,还需要继续分析Android中的Input系统。

 

3.1. 何为DecorView

这里引用源码中的解释This is thetop-level view of the window, containing the window décor

3.2. 为何用DecorView

3.3. 如何用DecorView