Android 4.2 SetContentView 流程分析(三)

来源:互联网 发布:seo网络推广软件 编辑:程序博客网 时间:2024/05/22 14:20

这一路分析下来, 开始进入 JNI layer 了.

[android_view_SurfaceSession.cpp]static jint nativeCreate(JNIEnv* env, jclass clazz) {    // new 一个 SurfaceComposerClient对象, 其功用后面会在分析.    sp<SurfaceComposerClient> client = new SurfaceComposerClient;               client->incStrong(clazz);    return reinterpret_cast<jint>(client);}

到此在做个结论,handleResumeActivity 函数利用WindowManagerImpl依照WindowManager.LayoutParams的属性来为DecoreView增加一个 view的纪录.

, 在addView 过程会有以下的流程:

1. 产生一个新的ViewRootImpl, 在ViewRootImpl的对象初始化中建立一个 DecoreView 和 WindowManagerService 之间的 Session.

2. 将先前设置好的View 加入DecoreView. 在加入过程有两个关键动作如下:

        a.  执行 performTraversals开始布局并且绘画显示画面.

        b.  SurfaceComposerClient 组件:  new一个 SurfaceComposerClient对象, 其功用跟 surfaceControl 有关.

针对以上第二点的流程的两个关键动作,我们继续分析.

a. 执行 performTraversals

[ViewRootImpl.java]private void performTraversals() {    // mView是前面经由setContentView的一个View,也就是DecoreView.    final View host = mView;     //...    //关键函数    relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);    //....     //...    //开始绘图.    performDraw();    //...}

performTraversals函数做蛮多杂事的, 我们只需要关心两个动作其中两个关键动作, relayoutWindow performDraw.

relayoutWindow 分析

[ViewRootImpl.java]private int relayoutWindow(WindowManager.LayoutParams params,                       int viewVisibility,                        boolean insetsPending) throws RemoteException {          //....         //由此可以看到藉由Session去呼叫WindowManagerService的         // relayoutWindow function.         int relayoutResult = sWindowSession.relayout(                mWindow, mSeq, params,                (int) (mView.getMeasuredWidth() * appScale + 0.5f),                (int) (mView.getMeasuredHeight() * appScale + 0.5f),                viewVisibility, insetsPending ?                  WindowManagerImpl.RELAYOUT_INSETS_PENDING : 0,                mWinFrame, mPendingContentInsets,                mPendingVisibleInsets,                mPendingConfiguration, mSurface);          //...         return relayoutResult;} [Session.java]public int relayout(IWindow window, int seq, WindowManager.LayoutParamsattrs,            int requestedWidth, int requestedHeight, int viewFlags,            int flags, Rect outFrame, Rect outContentInsets,            Rect outVisibleInsets, Configuration outConfig, SurfaceoutSurface) {        int res = mService.relayoutWindow(this, window, seq, attrs,                requestedWidth, requestedHeight, viewFlags, flags,                outFrame, outContentInsets, outVisibleInsets,                outConfig, outSurface);        return res;}
有此段程序代码,可以看到relayoutWindow函数会藉由Session去呼叫WindowManagerService的relayoutWindowfunction. 其中值得关注的是最后一个参数mSurface.这个mSurface是怎么来的.在定义ViewRootImpl 类别一开始就产生了一个没有带参数的Surface物件

[ViewRootImpl.java]private final Surface mSurface = new Surface(); [Surface.java]public Surface() {        checkHeadless();        mCloseGuard.open("release");}

接这就继续分析WindowManagerService的relayoutWindow function做了哪些事?

[WindowManagerService.java]public int relayoutWindow(Session session, IWindow client, int seq,            WindowManager.LayoutParams attrs, int requestedWidth,            int requestedHeight, int viewVisibility, int flags,            Rect outFrame, Rect outContentInsets,            Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {             //断开Binder机制,清除呼叫者的UID, PID,重新设定service的//UID, PID,使其可以Service呼叫自己的功能.            long origId = Binder.clearCallingIdentity();             synchronized(mWindowMap) {            //经由先前ViewRootImpl在setView时所建立的一个//WindowState Hashtable搭配指定的Client的IBinder去找出相//对应的WindowState.               WindowState win = windowForClientLocked(session, client,false);               if (win == null) {                return 0;               }               WindowStateAnimator winAnimator = win.mWinAnimator;               // do something               Surface surface = winAnimator.createSurfaceLocked();               if (surface != null) {                    //复制一份surface数据到outSurface.                    outSurface.copyFrom(surface);                                      } else {                    //归还之前为surface配置的内存.                    outSurface.release();               }            }           //恢复Binder机制,清除service的UID, PID,恢复呼叫者的UID,//PID.           Binder.restoreCallingIdentity(origId);         return (inTouchMode ? WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE : 0)                | (toBeDisplayed ? WindowManagerImpl.RELAYOUT_RES_FIRST_TIME : 0)                | (surfaceChanged ? WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED : 0)                | (animating ? WindowManagerImpl.RELAYOUT_RES_ANIMATING : 0);}
由此段程序代码带出两个关键, Surface surface = winAnimator.createSurfaceLocked();  和outSurface.copyFrom(surface); 就依序来分析这两个动作.

Surface surface = winAnimator.createSurfaceLocked();

[WindowStateAnimator.java]Surface createSurfaceLocked() {    if (mSurface == null) {        // …        mSurface = new Surface(                        mSession.mSurfaceSession,                        attrs.getTitle().toString(),                        w, h, format, flags);               // …    }    return mSurface;} [Surface.java]/** create a surface with a name @hide */public Surface(SurfaceSession session,            String name, int w, int h, int format, int flags)            throws OutOfResourcesException {        if (session == null) {            throw new IllegalArgumentException("session must not be null");        }        if (name == null) {            throw new IllegalArgumentException("name must not be null");        }         if ((flags & HIDDEN) == 0) {            // ...        }         checkHeadless();        mName = name;        nativeCreate(session, name, w, h, format, flags);        mCloseGuard.open("release");    }private native void nativeCreate(SurfaceSession session, String name,            int w, int h, int format, int flags)            throws OutOfResourcesException; [android_view_Surface.cpp]static void nativeCreate(JNIEnv* env, jobject surfaceObj, jobject sessionObj,        jstring nameStr, jint w, jint h, jint format, jint flags) {    ScopedUtfChars name(env, nameStr);    sp<SurfaceComposerClient>             client(android_view_SurfaceSession_getClient(env, sessionObj));     sp<SurfaceControl> surface = client->createSurface(            String8(name.c_str()), w, h, format, flags);    if (surface == NULL) {        jniThrowException(env, OutOfResourcesException, NULL);        return;    }     setSurfaceControl(env, surfaceObj, surface);}

由此可知, winAnimator.createSurfaceLocked所做的事就是在native层产生一个SurfaceControl 对象,在Java层产生一个带有surfaceSession参数的Surface参考对象.

outSurface.copyFrom(surface);

[Surface.java]public native void copyFrom(Surface o); [android_view_Surface.cpp]static void Surface_copyFrom(        JNIEnv* env, jobject clazz, jobject other){    if (clazz == other)        return;     if (other == NULL) {        doThrowNPE(env);        return;    }     /*     * This is used by the WindowManagerService just after constructing     * a Surface and is necessary for returning the Surface reference to     * the caller. At this point, we should only have a SurfaceControl.     */     const sp<SurfaceControl>& surface = getSurfaceControl(env, clazz);    const sp<SurfaceControl>& rhs = getSurfaceControl(env, other);    //将rhs对象指定给sutface指针对象.    if (!SurfaceControl::isSameSurface(surface, rhs)) {        // we reassign the surface only if it's a different one        // otherwise we would loose our client-side state.        setSurfaceControl(env, clazz, rhs);    }}

由以上的代码段,WindowManagerService的relayoutWindow可以做个以下总结:

1. 藉由mWindowMap里去得到目前Client (DecoreView)的WindowState对象.

2. 藉由此WindowState物件win来new一个带有SurfaceSession参数的Surface物件.用意是可以借着SurfaceComposerClient来新增一个SurfaceControl.

3. 利用Surface的copyfrom 函数把带有SurfaceSession参数的Surface对象复制一份到ViewRootImpl所产生的一个无参数建构出来的Surface对象.

结论又带出一个新的角色SurfaceComposerClient,其功用后面会分析.

 

performDraw分析

[ViewRootImpl.java]

private void performDraw() {    //检查目前的Screen是否开启且是否要画下一张画面.只要其中一个条    //件不满足,就不继续往下做处理.     // fullRedrawNeeded用来控制画面的大小.    final boolean fullRedrawNeeded = mFullRedrawNeeded;    mFullRedrawNeeded = false;     mIsDrawing = true;     try {       draw(fullRedrawNeeded);    } finally {       mIsDrawing = false;   }} private void draw(boolean fullRedrawNeeded) {       // mSurface 是ViewRootImpl所产生的一个无参数建构出来的Surface       //对象,经过relayoutWindow处理之后, 就变成一个带有       //surfaceSession参数的Surface对象,在native layer具有surface       //control物件.       Surface surface = mSurface;        //...             final Rect dirty = mDirty;        // ....       //设定画面的大小       if (fullRedrawNeeded) {            attachInfo.mIgnoreDirtyState = true;            dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight *                   appScale + 0.5f));        }                 if (!dirty.isEmpty() || mIsAnimating) {            //从android 4.1之后在绘制画面多了一个选择就是由HardWare            //renderer来处理.            if (attachInfo.mHardwareRenderer != null &&              attachInfo.mHardwareRenderer.isEnabled()) {                 //由Hardware renderer来画.            } else if (!drawSoftware(surface, attachInfo, yoff,                               scalingRequired, dirty)) {                return;            }        }         // ...} private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,            boolean scalingRequired, Rect dirty) {      //一旦有Hardware renderer的request而此时Hardware renderer的功      //能又未打开,系统将停止Software renderer处理动作.      if (attachInfo.mHardwareRenderer != null        && !attachInfo.mHardwareRenderer.isEnabled() &&        attachInfo.mHardwareRenderer.isRequested()) {            mFullRedrawNeeded = true;            scheduleTraversals();            return false;        }        //由Software renderer来画.      Canvas canvas;      // ...      canvas = mSurface.lockCanvas(dirty);     // ...     //这里的mView就是在一开始 handleResumeActivity函数中的第六个     //步骤, Window Manager (WindowManagerImpl)要处理addView所带     //入的ViewGroup (DecoreView)物件.     mView.draw(canvas);     // ...     surface.unlockCanvasAndPost(canvas);     return true;}
从以上的程序代码可以看到, Surface lock一块Canvas, 之前配置的View (DecoreView) 在利用这块Canvas来绘制UI组件.避免分析太分散,Surface的 lockCanvas, unlockCanvasAndPost和DecoreView的draw 函数分析放在最后分析.

b.SurfaceComposerClient 组件.

当ViewRootImpl去设置View(DecoreView)时,会先经由Session通知WindowMangerService去addWindow, 在addWindow中会去new SurfaceSession.SurfaceComposerClient就是由new SurfaceSession中产生的.由于SurfaceComposerClient衍生自RefBase类别, 所以都会用sp来取得对象指针.

[android_view_SurfaceSession.cpp]sp<SurfaceComposerClient> client = new SurfaceComposerClient;

通常利用sp来建构对象时,会先呼叫onFirstRef函数,才会呼叫相对应建构子.因此若想要看一下SurfaceComposerClient的初始实作, 需要从其onFirstRef函数下手,分析如下: 

[SurfaceComposerClient.cpp]void SurfaceComposerClient::onFirstRef() {    // ISurfaceComposer 是 surfaceFlinger的 binder界面,所以    //getComposerService会回传SurfaceFlinger的Binder Proxy:    //BpSurfaceComposer.    sp<ISurfaceComposer> sm(ComposerService::getComposerService());    if (sm != 0) {        sp<ISurfaceComposerClient> conn = sm->createConnection();        if (conn != 0) {            mClient = conn;            mStatus = NO_ERROR;        }    }}
既然getComposerService回传的是SurfaceFlinger的Binder Proxy,表示由得到的对象,其方法可以在SurfaceFlnger类别去找.所以sm->createConnection(), 其createConnection函数如下所示:

[SurfaceFlinger.cpp]sp<ISurfaceComposerClient> SurfaceFlinger::createConnection(){    sp<ISurfaceComposerClient> bclient;    sp<Client> client(new Client(this));    status_t err = client->initCheck();    if (err == NO_ERROR) {        bclient = client;    }    return bclient;}
createConnection 函数回传一个ISurfaceComposerClient指针对象, 其实作可以发现这个指针对象是一个Client的指针对象.接下来就来分析Client建构子和其方法initCheck.

[Client.cpp]Client::Client(const sp<SurfaceFlinger>& flinger)    : mFlinger(flinger), mNameGenerator(1){}status_t Client::initCheck() const {    //没做任何事,推测未来会有实作.    return NO_ERROR;} 

c. lockCanvas, unlockCanvasAndPost

现在就来分析,Surface的 lockCanvas, unlockCanvasAndPost.

[Surface.java]/** draw into a surface */public Canvas lockCanvas(Rect dirty) throws OutOfResourcesException, IllegalArgumentException {   return nativeLockCanvas (dirty);}private native Canvas nativeLockCanvas (Rect dirty); [android_view_Surface.cpp]static jobject nativeLockCanvas (JNIEnv* env, jobject clazz, jobject dirtyRect){    sp<Surface> surface(getSurface(env, surfaceObj));    if (!Surface::isValid(surface)) {        doThrowIAE(env);        return NULL;    }    //1. 取得Dirty区域的大小.    Region dirtyRegion;    if (dirtyRectObj) {        Rect dirty;        dirty.left = env->GetIntField(dirtyRectObj, gRectClassInfo.left);        dirty.top = env->GetIntField(dirtyRectObj, gRectClassInfo.top);        dirty.right = env->GetIntField(dirtyRectObj, gRectClassInfo.right);        dirty.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);        if (!dirty.isEmpty()) {            dirtyRegion.set(dirty);        }    } else {        dirtyRegion.set(Rect(0x3FFF, 0x3FFF));    }       //2. 利用获得的Dirty区域利用Surface对象的lock函数来设置     //SurfaceInfo.     Surface::SurfaceInfo info;      status_t err = surface->lock(&info, &dirtyRegion);     //3. 从Java layer取得SkCanvas object.     // mCanvas在Surface建构之前就已经存在了,请参考程序代码 Surface.java     jobject canvas = env->GetObjectField(clazz, so.canvas);     //...     SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas,                           no.native_canvas);    //4. 利用得到的SkCanvas来开始设定绘制区域.从Android 4.1开始绘制的    //类型有分SkBitmap内存管理跟 SkRegion内存管理.    //利用SurfaceInfo配置一块 2d skia的SkBitmap内存管理    SkBitmap bitmap;      ssize_t bpr = info.s * bytesPerPixel(info.format);    bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);    if (info.format == PIXEL_FORMAT_RGBX_8888) {        bitmap.setIsOpaque(true);    }    if (info.w > 0 && info.h > 0) {        //设定需要管理surface的buffer        bitmap.setPixels(info.bits);    } else {        // be safe with an empty bitmap.        bitmap.setPixels(NULL);    }    //SkCanvas设定此bitmap内存管理, 以便可以用这个内存管理在    //surface的buffer上作画.    nativeCanvas->setBitmapDevice(bitmap);        //配置一块 SkRegion内存管理    if (dirtyRegion.isRect()) { // very common case        const Rect b(dirtyRegion.getBounds());        clipReg.setRect(b.left, b.top, b.right, b.bottom);    } else {        size_t count;        Rect const* r = dirtyRegion.getArray(&count);        while (count) {            clipReg.op(r->left, r->top, r->right, r->bottom,                     SkRegion::kUnion_Op);            r++, count--;        }    }     nativeCanvas->clipRegion(clipReg);    //5. 储存SkCanvas在内存管理上的配置.    int saveCount = nativeCanvas->save();       //6. 利用JNI的函数将一些需要的值来设定Java对象的属性.        return canvas;} [Surface.cpp]status_t Surface::lock(SurfaceInfo* other, Region* inOutDirtyRegion) {     //...     //因为Surface类别衍生自 SurfaceTextureClient类别, 要呼叫父类别的     //函数需要父类别名子加上范围运算符.     status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds);     //...     return err;} [SurfaceTextureClient.cpp]status_t SurfaceTextureClient::lock(        ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds){   //0. already locked, retrun   if (!mConnectedToCpu) {        //        int err = SurfaceTextureClient::connect(NATIVE_WINDOW_API_CPU);        if (err) {            return err;        }        // we're intending to do software rendering from this point        setUsage(GRALLOC_USAGE_SW_READ_OFTEN |                    GRALLOC_USAGE_SW_WRITE_OFTEN);    }       ANativeWindowBuffer* out;    //检查目前在queue中的buffer使用状态.并取出未使用的buffer index.    int fenceFd = -1;    status_t err = dequeueBuffer(&out, &fenceFd);    // 1. 宣告一个GraphicBuffer型态指针变量指向(ANativeWindowBuffer)out    //内存.    sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));       //2. 依据backBuffer来设定需要更新的区域边界.    const Rect bounds(backBuffer->width, backBuffer->height);     Region newDirtyRegion;      if (inOutDirtyBounds) {            newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));            newDirtyRegion.andSelf(bounds);      } else {            newDirtyRegion.set(bounds);      }       //3. 检查是否有frontBuffer可以copy,以便显示到画面.      // mPostedBuffer跟之后要分析的 unlockCanvasAndPost处理有关.      const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);      const bool canCopyBack = (frontBuffer != 0 &&                backBuffer->width  == frontBuffer->width &&                backBuffer->height == frontBuffer->height &&                backBuffer->format == frontBuffer->format);       if (canCopyBack) {            // copy the area that is invalid and not repainted this round            const Region copyback(mDirtyRegion.subtract(newDirtyRegion));            if (!copyback.isEmpty())               //4. 避免整块memory做更新,因此只要藉由这方法来更新               //该更新的部分.                copyBlt(backBuffer, frontBuffer, copyback);        } else {            // if we can't copy-back anything, modify the user's dirty            // region to make sure they redraw the whole buffer            newDirtyRegion.set(bounds);            mDirtyRegion.clear();            Mutex::Autolock lock(mMutex);            for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {                mSlots[i].dirtyRegion.clear();            }        }     // ...     void* vaddr;     //5. 依照newDirtyRegion的边界在backBuffer上lock一块内存并传回     //起始地址vaddr给jni中所宣告出来的SkBitmap使用.     status_t res = backBuffer->lock(                    GRALLOC_USAGE_SW_READ_OFTEN |                    GRALLOC_USAGE_SW_WRITE_OFTEN,                    newDirtyRegion.bounds(), &vaddr);    //...    mLockedBuffer = backBuffer;     if (res != 0) {            err = INVALID_OPERATION;     } else {            mLockedBuffer = backBuffer;            outBuffer->width  = backBuffer->width;            outBuffer->height = backBuffer->height;            outBuffer->stride = backBuffer->stride;            outBuffer->format = backBuffer->format;            outBuffer->bits   = vaddr;     }      return err;}
在分析lockCanvas中有个dequeueBuffer的动作没有在这里分析,有兴趣再另起一个topic来分析.接下来继续分析unlockCanvasAndPost.

[Surface.java]public void unlockCanvasAndPost(Canvas canvas) {        nativeUnlockCanvasAndPost(canvas);}private native void nativeUnlockCanvasAndPost(Canvas canvas); [android_view_Surface.cpp]static void nativeUnlockCanvasAndPost(JNIEnv* env, jobject surfaceObj, jobject canvasObj) {      jobject ownCanvasObj = env->GetObjectField(surfaceObj,                                        gSurfaceClassInfo.mCanvas);    if (!env->IsSameObject(ownCanvasObj, canvasObj)) {        doThrowIAE(env);        return;    }        const sp<Surface>& surface(getSurface(env, clazz));   if (!Surface::isValid(surface)) {        return;   }     SkCanvas* nativeCanvas = reinterpret_cast<SkCanvas*>(            env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));    int saveCount = env->GetIntField(surfaceObj,                               gSurfaceClassInfo.mCanvasSaveCount);    nativeCanvas->restoreToCount(saveCount);    nativeCanvas->setBitmapDevice(SkBitmap());    env->SetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount, 0);     status_t err = surface->unlockAndPost();    if (err < 0) {        doThrowIAE(env);    }} [Surface.cpp]status_t Surface::unlockAndPost() {    //因为Surface类别衍生自 SurfaceTextureClient类别, 要呼叫父类别的    //函数需要父类别名子加上范围运算符.    return SurfaceTextureClient::unlockAndPost();} [SurfaceTextureClient.cpp]status_t SurfaceTextureClient::unlockAndPost(){  //...  //0. 将使用完的Buffer做unlock的动作.  status_t err = mLockedBuffer->unlock();  //...  //1. 将unlock的buffer index送进queue中.  err = queueBuffer(mLockedBuffer.get());  //...  //2. 将mLockedBuffer指针对象传给mPostedBuffer指针对象做为下一次  // lockCanvas的依据.  mPostedBuffer = mLockedBuffer;  mLockedBuffer = 0; }
关于View的Draw流程就不在这一次的分析中, 因为Surface中的Canvas和Bitmap对View的Draw流程来说只是个工具. 总结如下:

1. 在App开始要布局layout view都会由setContentView来设置整体画面.

   这时的角色有PhoneWindow, WindowManagerImpl, DecoreView

   其相互动作如下:

   a. getWindow 得到一个 mWindow, 这个 mWindow 就是一个  

     PhoneWindow 物件.

   b. 利用 PhoneWindow 对象设为 WindowManagerImpl的角色.

   c. PhoneWindow 物件设置一个 DecoreView 的子 view.

2. 当App从Create状态转到Resume状态时, 这时就会开始绘制画面.

   角色: DecoreView, WindowManagerImpl, ViewRootImpl,WindowManagerService,     

   SurfaceSession, WindowState, Surface, Canvas

   i. ViewRootImpl利用Binder机制将WindowManagerService 和 DecoreView建立一个session.

   ii. ViewRootImpl经由session请求WindowManagerService来增加一个WindowState,并作记录.

   iii. WindowManagerService在作windowstate时, 会建构一个SurfaceComposerClient物件.

   iv. 利用SurfaceComposerClient对象产生SurfaceControl对象.

    v. 利用Canvas设置两个Buffer, 分别为Front和Back.

    vi. 利用Surface对象的lockCanvas, unlockCanvasAndPost函数来处理绘制画面的流程.

原创粉丝点击