SurfaceFlinger旋转流程分析

chipset: MSM8X25Q

codebase: Android4.1

本文主要对SF(SurfaceFilnger)处理旋转事件的流程做个简单分析。GPU和mdp都可以用来旋转,文中对两者穿插说明。

系统初始化会调用GraphicPlane::setDisplayHardware,此函数主要判断系统是否默认设置了rotation property值,如果有,则先保存下来。另外,SF是以transform其实就是以矩阵来作旋转计算的,计算方法以线性代数中的知识为依据:

[html] view plain copy print ?
  1. void GraphicPlane::setDisplayHardware(DisplayHardware *hw) 
  2.     mHw = hw
  3.  
  4.     // initialize the display orientation transform. 
  5.     // it's a constant that should come from the display driver. 
  6.     int displayOrientation = ISurfaceComposer::eOrientationDefault; 
  7.     char property[PROPERTY_VALUE_MAX]; 
  8.     /*读取property*/ 
  9.     if (property_get("ro.sf.hwrotation", property, NULL) > 0) { 
  10.         //displayOrientation 
  11.         switch (atoi(property)) { 
  12.         /*当然,你也可以仿照添加180°的旋转。*/ 
  13.         case 90: 
  14.             displayOrientation = ISurfaceComposer::eOrientation90; 
  15.             break; 
  16.         case 270: 
  17.             displayOrientation = ISurfaceComposer::eOrientation270; 
  18.             break; 
  19.         } 
  20.     } 
  21.  
  22.  
  23.     const float w = hw->getWidth(); 
  24.     const float h = hw->getHeight(); 
  25.     /*根据宽和高以及orientation生成一个transform*/ 
  26.     GraphicPlane::orientationToTransfrom(displayOrientation, w, h, 
  27.             &mDisplayTransform); 
  28.     /*90°或者270°时需要变换宽高。*/ 
  29.     if (displayOrientation & ISurfaceComposer::eOrientationSwapMask) { 
  30.         mDisplayWidth = h
  31.         mDisplayHeight = w
  32.     } else { 
  33.         mDisplayWidth = w
  34.         mDisplayHeight = h
  35.     } 
  36.  
  37.     /*保存当前全局旋转角度,意味着整个系统的显示都要根据整个值 
  38. 来得出最后是否要旋转。如果为90°或者270°,那就是横屏,如果 
  39. 是180°,画面就要反转180°。*/ 
  40.     setOrientation(ISurfaceComposer::eOrientationDefault); 
  41.  
  42. status_t GraphicPlane::setOrientation(int orientation) 
  43.     // If the rotation can be handled in hardware, this is where 
  44.     // the magic should happen. 
  45.  
  46.     const DisplayHardware& hw(displayHardware()); 
  47.     const float w = mDisplayWidth
  48.     const float h = mDisplayHeight
  49.     mWidth = int(w); 
  50.     mHeight = int(h); 
  51.  
  52.     Transform orientationTransform; 
  53.     GraphicPlane::orientationToTransfrom(orientation, w, h, 
  54.             &orientationTransform); 
  55.     if (orientation & ISurfaceComposer::eOrientationSwapMask) { 
  56.         mWidth = int(h); 
  57.         mHeight = int(w); 
  58.     } 
  59.  
  60.     mOrientation = orientation
  61.     /*将orientation和h/w计算和得出一个全局的transform,这里的 
  62. 相乘计算方法,就是利用矩阵来实现的。*/ 
  63.     mGlobalTransform = mDisplayTransform * orientationTransform; 
  64.     return NO_ERROR; 

由于整个系统一直默认旋转只是流程中一个坐标的特殊处理,不管系统上层是否请求旋转,如横屏游戏,sensor坐标变化,默认的旋转是一直会被处理的。

注意别把这两种旋转混淆了,默认旋转是一般情况下用户看到的显示效果,而上层apk

请求的旋转相对默认旋转是瞬间的。

         现在以上层发生旋转事件为例看下SF处理旋转的流程。

上层调用SurfaceFlinger::setTransactionState设置当前角度变化了:

[html] view plain copy print ?
  1. void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state, 
  2.         int orientation, uint32_t flags) { 
  3.     Mutex::Autolock _l(mStateLock); 
  4.  
  5. uint32_t transactionFlags = 0
  6.  
  7. /*当前坐标和要设置的坐标不相等表明要作旋转了!*/ 
  8.     if (mCurrentState.orientation != orientation) { 
  9.         if (uint32_t(orientation)<=eOrientation270 || orientation==42) { 
  10.             mCurrentState.orientation = orientation
  11.             transactionFlags |= eTransactionNeeded; 
  12.         } else if (orientation != eOrientationUnchanged) { 
  13.             ALOGW("setTransactionState: ignoring unrecognized orientation: %d", 
  14.                     orientation); 
  15.         } 
  16.     } 
  17.  
  18.     /*设置旋转标志,SF处理的时候会用到。*/ 
  19.     const size_t count = state.size(); 
  20.     for (size_t i=0 ; i<count ; i++) { 
  21.         const ComposerState& s(state[i]); 
  22.         sp<Client> client( static_cast<Client *>(s.client.get()) ); 
  23.         transactionFlags |= setClientStateLocked(client, s.state); 
  24.     } 
  25.  
  26.     if (transactionFlags) { 
  27.         // this triggers the transaction 
  28.         setTransactionFlags(transactionFlags); 
  29.  
  30. ~~snip 

SF收到消息后,调用SurfaceFlinger::onMessageReceived进行处理,核心的部分都在这里了。

[html] view plain copy print ?
  1. void SurfaceFlinger::onMessageReceived(int32_t what) 
  2.     ATRACE_CALL(); 
  3.     switch (what) { 
  4.         case MessageQueue::INVALIDATE: 
  5.         case MessageQueue::REFRESH: { 
  6. //        case MessageQueue::INVALIDATE: { 
  7.             // if we're in a global transaction, don't do anything. 
  8.             const uint32_t mask = eTransactionNeeded | eTraversalNeeded; 
  9.             uint32_t transactionFlags = peekTransactionFlags(mask); 
  10. /*处理事务*/ 
  11.             if (CC_UNLIKELY(transactionFlags)) { 
  12.                 handleTransaction(transactionFlags); 
  13.             } 
  14.  
  15.             const uint32_t mask1 = eDelayedTraversalNeeded
  16.             uint32_t transactionFlags1 = peekTransactionFlags(mask1); 
  17.             if (CC_UNLIKELY(transactionFlags1)) { 
  18.                 handleDelayedTransaction(transactionFlags); 
  19.             } 
  20.             /*计算可视区域*/ 
  21.             // post surfaces (if needed) 
  22.             handlePageFlip(); 
  23.  
  24. ~~snip 
  25.       case MessageQueue::REFRESH: { 
  26.  
  27. ~~snip 
  28.             /*处理几何坐标*/ 
  29.             if (CC_UNLIKELY(mHwWorkListDirty)) { 
  30.                 // build the h/w work list 
  31.                 handleWorkList(); 
  32.             } 
  33.              
  34.             /*render*/ 
  35.             if (CC_LIKELY(hw.canDraw())) { 
  36.                 // repaint the framebuffer (if needed) 
  37.                 handleRepaint(); 
  38.                 // inform the h/w that we're done compositing 
  39.                 hw.compositionComplete(); 
  40.                 postFramebuffer(); 
  41.             } else { 
  42.                 // pretend we did the post 
  43.                 hw.compositionComplete(); 
  44.             } 
  45.  
  46.         } break; 
  47.     } 

下面一一对这几个函数分析。

handleTransaction

[html] view plain copy print ?
  1. void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) 
  2. ~~snip 
  3.  
  4.     const uint32_t mask = eTransactionNeeded | eTraversalNeeded; 
  5.     transactionFlags = getTransactionFlags(mask); 
  6.     handleTransactionLocked(transactionFlags); 
  7. ~~snip 
  8.  
  9. void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) 
  10.     const LayerVector& currentLayers(mCurrentState.layersSortedByZ); 
  11.     const size_t count = currentLayers.size(); 
  12.  
  13.     /* 
  14.      * Traversal of the children 
  15.      * (perform the transaction for each of them if needed) 
  16.      */ 
  17.     /*判断是否有事务要处理。*/ 
  18.     const bool layersNeedTransaction = transactionFlags & eTraversalNeeded; 
  19.     if (layersNeedTransaction) { 
  20.         for (size_t i=0 ; i<count ; i++) { 
  21.             const sp<LayerBase>& layer = currentLayers[i]; 
  22.             uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); 
  23.             if (!trFlags) continue; 
  24.  
  25.             const uint32_t flags = layer->doTransaction(0); 
  26.             if (flags & Layer::eVisibleRegion) 
  27.                 mVisibleRegionsDirty = true
  28.         } 
  29.     } 
  30. ~~snip 
  31.  
  32. if (transactionFlags & eTransactionNeeded) { 
  33.         /*有旋转角度变化的事务。*/ 
  34.         if (mCurrentState.orientation != mDrawingState.orientation) { 
  35.             // the orientation has changed, recompute all visible regions 
  36.             // and invalidate everything. 
  37.  
  38.             const int dpy = 0
  39.             const int orientation = mCurrentState.orientation; 
  40.             // Currently unused: const uint32_t flags = mCurrentState.orientationFlags; 
  41.             GraphicPlane& plane(graphicPlane(dpy)); 
  42.             /*根据当前旋转的坐标,还有默认的旋转坐标,计算和得出最终全局transform。 
  43. 此函数前面分析过了。*/ 
  44.             plane.setOrientation(orientation); 
  45.             const Transform& planeTransform(plane.transform()); 
  46.  
  47.             // update the shared control block 
  48.             const DisplayHardware& hw(plane.displayHardware()); 
  49.             volatile display_cblk_t* dcblk = mServerCblk->displays + dpy; 
  50.             dcblk->orientation = orientation
  51.             dcblk->w = plane.getWidth(); 
  52.             dcblk->h = plane.getHeight(); 
  53.  
  54.             /*旋转过后当然要重新绘制显示画面了,设置标志。*/ 
  55.             mVisibleRegionsDirty = true
  56.             mDirtyRegion.set(hw.bounds()); 
  57.         } 
  58.  
  59. ~~snip 

可见handleTransaction主要设置全局的transform。

handlePageFlip

[html] view plain copy print ?
  1. void SurfaceFlinger::handlePageFlip() 
  2.     ATRACE_CALL(); 
  3.     const DisplayHardware& hw = graphicPlane(0).displayHardware(); 
  4.     const Region screenRegion(hw.bounds()); 
  5.  
  6.     const LayerVector& currentLayers(mDrawingState.layersSortedByZ); 
  7.     const bool visibleRegions = lockPageFlip(currentLayers); 
  8.  
  9.         if (visibleRegions || mVisibleRegionsDirty) { 
  10.             Region opaqueRegion; 
  11.             /*有旋转过,所以要重新计算可视区域*/ 
  12.             computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion); 
  13. ~~snip 
  14. ~~snip 
  15.  
  16.  
  17. void SurfaceFlinger::computeVisibleRegions( 
  18.     const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion) 
  19.     ATRACE_CALL(); 
  20.  
  21.     const GraphicPlane& plane(graphicPlane(0)); 
  22.     const Transform& planeTransform(plane.transform()); 
  23.     const DisplayHardware& hw(plane.displayHardware()); 
  24.     const Region screenRegion(hw.bounds()); 
  25.  
  26.     Region aboveOpaqueLayers; 
  27.     Region aboveCoveredLayers; 
  28.     Region dirty; 
  29.  
  30.     bool secureFrameBuffer = false
  31.  
  32.     size_t i = currentLayers.size(); 
  33.     while (i--) { 
  34.         const sp<LayerBase>& layer = currentLayers[i]; 
  35.         /*将全局的transform传进去,然后调用各个layer作计算。*/ 
  36.         layer->validateVisibility(planeTransform); 
  37.      
  38.       ~~snip 
  39.  
  40. void LayerBase::validateVisibility(const Transform& planeTransform) 
  41. const Layer::State& s(drawingState()); 
  42. /*全局transform和当前layer的transform相乘计算得到一个transform.*/ 
  43.     const Transform tr(planeTransform * s.transform); 
  44.     const bool transformed = tr.transformed(); 
  45.     const DisplayHardware& hw(graphicPlane(0).displayHardware()); 
  46.     const uint32_t hw_h = hw.getHeight(); 
  47.     const Rect& crop(s.active.crop); 
  48.  
  49.     Rect win(s.active.w, s.active.h); 
  50.     if (!crop.isEmpty()) { 
  51.         win.intersect(crop, &win); 
  52.     } 
  53.  
  54. mNumVertices = 4
  55. /* mVertices 相当重要,系统根据当前的transform还有当前layer的 
  56. 区域作计算,当然也包含了全局的transform信息在里面,计算出来的 
  57. 坐标保存到了mVertices 去。要注意,mVertices 只是给GPU用的,如果 
  58. 用mdp做旋转,SF后面的流程会对其做相应设置。*/ 
  59.     tr.transform(mVertices[0], win.left,  win.top); 
  60.     tr.transform(mVertices[1], win.left,  win.bottom); 
  61.     tr.transform(mVertices[2], win.right, win.bottom); 
  62.     tr.transform(mVertices[3], win.right, win.top); 
  63.     for (size_t i=0 ; i<4 ; i++) 
  64.         mVertices[i][1] = hw_h - mVertices[i][1]; 
  65.  
  66.     if (CC_UNLIKELY(transformed)) { 
  67.         // NOTE: here we could also punt if we have too many rectangles 
  68.         // in the transparent region 
  69.     /*根据transform对透明区域作处理。*/ 
  70.         if (tr.preserveRects()) { 
  71.             // transform the transparent region 
  72.             transparentRegionScreen = tr.transform(s.transparentRegion); 
  73.         } else { 
  74.             // transformation too complex, can't do the transparent region 
  75.             // optimization. 
  76.             transparentRegionScreen.clear(); 
  77.         } 
  78.     } else { 
  79.         transparentRegionScreen = s.transparentRegion; 
  80.     } 
  81.  
  82.     /*保存相应的一些信息到新的参数变量中,以便后面用到。*/ 
  83.     // cache a few things... 
  84.     mOrientation = tr.getOrientation(); 
  85.     mPlaneOrientation = planeTransform.getOrientation(); 
  86.     mTransform = tr
  87.     mTransformedBounds = tr.transform(win); 

可见,从handlePageFlip中,我们主要是得到了GPU要处理的坐标,保存到了mVertices数组中。

handleWorkList

[html] view plain copy print ?
  1. void SurfaceFlinger::handleWorkList() 
  2.     mHwWorkListDirty = false
  3.     HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer()); 
  4.     if (hwc.initCheck() == NO_ERROR) { 
  5.         const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ); 
  6.         const size_t count = currentLayers.size(); 
  7.         hwc.createWorkList(count); 
  8.         hwc_layer_t* const cur(hwc.getLayers()); 
  9.         for (size_t i=0 ; cur && i<count ; i++) { 
  10.             /*依次调用各个layer的setGeometry 。*/ 
  11.             currentLayers[i]->setGeometry(&cur[i]); 
  12.         } 
  13.     } 
  14.  
  15. void Layer::setGeometry(hwc_layer_t* hwcl) 
  16.     /*调用基类函数。*/ 
  17.     LayerBaseClient::setGeometry(hwcl); 
  18.  
  19.     hwcl->flags &= ~HWC_SKIP_LAYER; 
  20.  
  21.     /*不完全透明时需要GPU处理。*/ 
  22.     // we can't do alpha-fade with the hwc HAL 
  23.     const State& s(drawingState()); 
  24.     if (s.alpha < 0xFF) { 
  25.         hwcl->flags = HWC_SKIP_LAYER
  26.     } 
  27.  
  28.     /* 
  29.      * Transformations are applied in this order: 
  30.      * 1) buffer orientation/flip/mirror 
  31.      * 2) state transformation (window manager) 
  32.      * 3) layer orientation (screen orientation) 
  33.      * mTransform is already the composition of (2) and (3) 
  34.      * (NOTE: the matrices are multiplied in reverse order) 
  35.      */ 
  36.      
  37.     /*这里就是在根据要求的旋转信息得出最终的transform, 
  38. 然后赋值给hwcl,hwcl的信息最后会传给mdp处理。*/ 
  39.     const Transform bufferOrientation(mCurrentTransform); 
  40.     hwcl->sourceTransform = bufferOrientation.getOrientation(); 
  41.     const Transform tr(mTransform * bufferOrientation); 
  42.  
  43.     // this gives us only the "orientation" component of the transform 
  44.     const uint32_t finalTransform = tr.getOrientation(); 
  45.  
  46.     // we can only handle simple transformation 
  47.     if (finalTransform & Transform::ROT_INVALID) { 
  48.         hwcl->flags = HWC_SKIP_LAYER
  49.     } else { 
  50.         hwcl->transform = finalTransform
  51.     } 
  52.     /*得到layer区域相对坐标,绝对坐标在基类中计算得到。*/ 
  53. Rect crop = computeBufferCrop(); 
  54.     hwcl->sourceCrop.left   = crop.left; 
  55.     hwcl->sourceCrop.top    = crop.top; 
  56.     hwcl->sourceCrop.right  = crop.right; 
  57.     hwcl->sourceCrop.bottom = crop.bottom; 

由此看来handleWorkList主要是服务于mdp的,如果用GPU旋转的话可以不需要这些信息。

handleRepaint

[html] view plain copy print ?
  1. void SurfaceFlinger::handleRepaint() 
  2. ~~snip 
  3. setupHardwareComposer(); 
  4.     /*对各个layer作render*/ 
  5.     composeSurfaces(mDirtyRegion); 
  6.  
  7.     // update the swap region and clear the dirty region 
  8.     mSwapRegion.orSelf(mDirtyRegion); 
  9.     mDirtyRegion.clear(); 
  10.  
  11. void SurfaceFlinger::composeSurfaces(const Region& dirty) 
  12.     const DisplayHardware& hw(graphicPlane(0).displayHardware()); 
  13.     HWComposer& hwc(hw.getHwComposer()); 
  14.     hwc_layer_t* const cur(hwc.getLayers()); 
  15.  
  16.     const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER); 
  17.     if (!cur || fbLayerCount) { 
  18. ~~snip 
  19.         const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); 
  20.         const size_t count = layers.size(); 
  21.  
  22.         for (size_t i=0 ; i<count ; i++) { 
  23.             const sp<LayerBase>& layer(layers[i]); 
  24.             const Region clip(dirty.intersect(layer->visibleRegionScreen)); 
  25. ~~snip 
  26.         /*如果不是HWC_FRAMEBUFFER 类型的话不处理,也就是让mdp去做处理。*/ 
  27. #ifdef QCOMHW 
  28.                 if (cur && (cur[i].compositionType != HWC_FRAMEBUFFER)) 
  29.                     continue; 
  30. #endif 
  31.             /*依次调用各种layer的draw函数 */ 
  32.                 // render the layer 
  33.                 layer->draw(clip); 
  34.             } 
  35.         } 
  36.    ~~snip 
  37.  
  38. void LayerBase::draw(const Region& clip) const 
  39.     //Dont draw External-only layers 
  40.     if (isLayerExternalOnly(getLayer())) { 
  41.         return; 
  42.     } 
  43.     onDraw(clip); 
  44.  
  45. void Layer::onDraw(const Region& clip) const 
  46. ~~snip 
  47.     /*画图*/ 
  48.     drawWithOpenGL(clip); 
  49.  
  50.     glDisable(GL_TEXTURE_EXTERNAL_OES); 
  51.     glDisable(GL_TEXTURE_2D); 
  52.  
  53. void LayerBase::drawWithOpenGL(const Region& clip) const 
  54.     const DisplayHardware& hw(graphicPlane(0).displayHardware()); 
  55.     const uint32_t fbHeight = hw.getHeight(); 
  56.     const State& s(drawingState()); 
  57.  
  58. ~~snip 
  59.  
  60.     struct TexCoords { 
  61.         GLfloat u; 
  62.         GLfloat v; 
  63.     }; 
  64.  
  65.     Rect crop(s.active.w, s.active.h); 
  66.     if (!s.active.crop.isEmpty()) { 
  67.         crop = s.active.crop; 
  68.     } 
  69.     GLfloat left = GLfloat(crop.left) / GLfloat(s.active.w); 
  70.     GLfloat top = GLfloat(crop.top) / GLfloat(s.active.h); 
  71.     GLfloat right = GLfloat(crop.right) / GLfloat(s.active.w); 
  72.     GLfloat bottom = GLfloat(crop.bottom) / GLfloat(s.active.h); 
  73.     /*得到顶点坐标*/ 
  74.     TexCoords texCoords[4]; 
  75.     texCoords[0].u = left
  76.     texCoords[0].v = top
  77.     texCoords[1].u = left
  78.     texCoords[1].v = bottom
  79.     texCoords[2].u = right
  80.     texCoords[2].v = bottom
  81.     texCoords[3].u = right
  82.     texCoords[3].v = top
  83.     for (int i = 0; i < 4; i++) { 
  84.         texCoords[i].v = 1.0f - texCoords[i].v; 
  85.     } 
  86.  
  87.     /*OpenGL利用下面这些函数将根据纹理坐标和顶点坐标 
  88. 得到最后layer的显示区域以及内容。*/ 
  89.     glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
  90.     glVertexPointer(2, GL_FLOAT, 0, mVertices); 
  91.     glTexCoordPointer(2, GL_FLOAT, 0, texCoords); 
  92.     glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices); 
  93.  
  94.     glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
  95.     glDisable(GL_BLEND); 

所以,composeSurfaces是服务于GPU的。

虽然mdp已经旋转完成了,但是似乎还没有看到如何送给mdp啊?看看postFramebuffer.

  postFramebuffer

[html] view plain copy print ?
  1. void SurfaceFlinger::postFramebuffer() 
  2. ~~snip 
  3.  
  4.     const DisplayHardware& hw(graphicPlane(0).displayHardware()); 
  5.     const nsecs_t now = systemTime(); 
  6.     mDebugInSwapBuffers = now
  7.     hw.flip(mSwapRegion); 
  8. ~~snip 
  9. void DisplayHardware::flip(const Region& dirty) const 
  10. ~~snip 
  11.  
  12.     if (mHwc->initCheck() == NO_ERROR) { 
  13.         mHwc->commit(); 
  14.     } else { 
  15.         eglSwapBuffers(dpy, surface); 
  16.     } 
  17. ~~snip 
  18.  
  19. status_t HWComposer::commit() const { 
  20.     /*调用了HAL的set,看起来和硬件有关联了!*/ 
  21.     int err = mHwc->set(mHwc, mDpy, mSur, ((mSwapRectOn)?mListDirty:mList)); 
  22.     if (mSwapRectOn && mListDirty) { 
  23.         mListDirty->flags &= ~HWC_GEOMETRY_CHANGED; 
  24.     } else if ( mList) { 
  25.         mList->flags &= ~HWC_GEOMETRY_CHANGED; 
  26.     } 
  27.     return (status_t)err; 
  28. static int hwc_set(hwc_composer_device_t *dev, 
  29.                    hwc_display_t dpy, 
  30.                    hwc_surface_t sur, 
  31.                    hwc_layer_list_t* list) 
  32.     int ret = 0
  33.     hwc_context_t* ctx = (hwc_context_t*)(dev); 
  34.     if (LIKELY(list)) { 
  35.         VideoOverlay::draw(ctx, list); 
  36.         ExtOnly::draw(ctx, list); 
  37.         CopyBit::draw(ctx, list, (EGLDisplay)dpy, (EGLSurface)sur); 
  38.         /*调用到mdp的draw了!!!*/ 
  39.         MDPComp::draw(ctx, list); 
  40.         EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); 
  41.       ~~snip 
  42.     return ret; 

总的下来,流程还是比较清晰的,不过里面很多transform很容易把人给弄晕掉,可以加log看值跟踪下。


2013/02/17

你可能感兴趣的:(SurfaceFlinger旋转流程分析)