免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
深入淺出 詳解Android Surface系統(tǒng)(2)

JNI層

上面兩個類的JNI實現(xiàn)都在framework/base/core/jni/android_view_Surface.cpp中。

[---->SurfaceSession:: SurfaceSession()]

  1. public class SurfaceSession {  
  2.  
  3. /** Create a new connection with the surface flinger. */ 
  4.  
  5. public SurfaceSession() {  
  6.  
  7. init();  
  8.  

它的init函數對應為:

[--->SurfaceSession_init]

  1. static void SurfaceSession_init(JNIEnv* env, jobject clazz)  
  2.  
  3. {  
  4.  
  5. //SurfaceSession對應為SurfaceComposerClient  
  6.  
  7. sp client = new SurfaceComposerClient;  
  8.  
  9. client->incStrong(clazz);  
  10.  
  11. //Google常用做法,在JAVA對象中保存C++對象的指針。  
  12.  
  13. env->SetIntField(clazz, sso.client, (int)client.get());  
  14.  

Surface的init對應為:

[--->Surface_init]

  1. static void Surface_init(  
  2.  
  3. JNIEnv* env, jobject clazz,  
  4.  
  5. jobject session,  
  6.  
  7. jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jint flags)  
  8.  
  9. {  
  10.  
  11. SurfaceComposerClient* client =  
  12.  
  13. (SurfaceComposerClient*)env->GetIntField(session, sso.client);  
  14.  
  15. sp surface;  
  16.  
  17. if (jname == NULL) {  
  18.  
  19. //client是SurfaceComposerClient,返回的surface是一個SurfaceControl  
  20.  
  21. //真得很復雜!  
  22.  
  23. surface = client->createSurface(pid, dpy, w, h, format, flags);  
  24.  
  25. else {  
  26.  
  27. const jchar* str = env->GetStringCritical(jname, 0);  
  28.  
  29. const String8 name(str, env->GetStringLength(jname));  
  30.  
  31. env->ReleaseStringCritical(jname, str);  
  32.  
  33. surface = client->createSurface(pid, name, dpy, w, h, format, flags);  
  34.  
  35. }  
  36.  
  37. //把surfaceControl信息設置到Surface對象中  
  38.  
  39. setSurfaceControl(env, clazz, surface);  
  40.  

  1. static void setSurfaceControl(JNIEnv* env, jobject clazz,  
  2.  
  3. const sp& surface)  
  4.  
  5. {  
  6.  
  7. SurfaceControl* const p =  
  8.  
  9. (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);  
  10.  
  11. if (surface.get()) {  
  12.  
  13. surface->incStrong(clazz);  
  14.  
  15. }  
  16.  
  17. if (p) {  
  18.  
  19. p->decStrong(clazz);  
  20.  
  21. }  
  22.  
  23. env->SetIntField(clazz, so.surfaceControl, (int)surface.get());  
  24.  

[--->Surface_copyFrom]

  1. static void Surface_copyFrom(  
  2.  
  3. JNIEnv* env, jobject clazz, jobject other)  
  4.  
  5. {  
  6.  
  7. const sp& surface = getSurfaceControl(env, clazz);  
  8.  
  9. const sp& rhs = getSurfaceControl(env, other);  
  10.  
  11. if (!SurfaceControl::isSameSurface(surface, rhs)) {  
  12.  
  13. setSurfaceControl(env, clazz, rhs);  
  14.  
  15. //把本地那個surface的surfaceControl對象轉移到outSurface上  
  16.  
  17. }  
  18.  

這里僅僅是surfaceControl的轉移,但是并沒有看到Surface相關的信息。

那么Surface在哪里創(chuàng)建的呢?為了解釋這個問題,我使用了終極武器,aidl。

1 終極武器AIDL

aidl可以把XXX.aidl文件轉換成對應的java文件。我們剛才調用的是WindowSession的

relayOut函數。如下:

  1. sWindowSession.relayout(  
  2.  
  3. mWindow, params,  
  4.  
  5. (int) (mView.mMeasuredWidth * appScale + 0.5f),  
  6.  
  7. (int) (mView.mMeasuredHeight * appScale + 0.5f),  
  8.  
  9. viewVisibility, insetsPending, mWinFrame,  
  10.  
  11. mPendingContentInsets, mPendingVisibleInsets,  
  12.  
  13. mPendingConfiguration, mSurface); 

它的aidl文件在framework/base/core/java/android/view/IWindowSession.aidl中

  1. interface IWindowSession {  
  2.  
  3. int add(IWindow window, in WindowManager.LayoutParams attrs,  
  4.  
  5. in int viewVisibility, out Rect outContentInsets);  
  6.  
  7. void remove(IWindow window);  
  8.  
  9. //注意喔,這個outSurface前面的是out,表示輸出參數,這個類似于C++的引用。  
  10.  
  11. int relayout(IWindow window, in WindowManager.LayoutParams attrs,  
  12.  
  13. int requestedWidth, int requestedHeight, int viewVisibility,  
  14.  
  15. boolean insetsPending, out Rect outFrame, out Rect outContentInsets,  
  16.  
  17. out Rect outVisibleInsets, out Configuration outConfig,  
  18.  
  19. out Surface outSurface); 

剛才說了,JNI及其JAVA調用只是copyFrom了SurfaceControl對象到outSurface中,但是沒看到哪里創(chuàng)建Surface。這其中的奧秘就在aidl文件編譯后生成的java文件中。

你在命令行下可以輸入:

aidl -Id:\android-2.2-froyo-20100625-source\source\frameworks\base\core\java\ -Id:\android-2.2-froyo-20100625-source\source\frameworks\base\Graphics\java d:\android-2.2-froyo-20100625-source\source\frameworks\base\core\java\android\view\IWindowSession.aidl test.java

以生成test.java文件。-I參數指定include目錄,例如aidl有些參數是在別的java文件中指定的,那么這個-I就需要把這些目錄包含進來。

先看看ViewRoot這個客戶端生成的代碼是什么。

  1. public int relayout(  
  2.  
  3. android.view.IWindow window,  
  4.  
  5. android.view.WindowManager.LayoutParams attrs,  
  6.  
  7. int requestedWidth, int requestedHeight,  
  8.  
  9. int viewVisibility, boolean insetsPending,  
  10.  
  11. android.graphics.Rect outFrame,  
  12.  
  13. android.graphics.Rect outContentInsets,  
  14.  
  15. android.graphics.Rect outVisibleInsets,  
  16.  
  17. android.content.res.Configuration outConfig,  
  18.  
  19. android.view.Surface outSurface) ---->outSurface是第11個參數  
  20.  
  21. throws android.os.RemoteException  
  22.  
  23. {  
  24.  
  25. android.os.Parcel _data = android.os.Parcel.obtain();  
  26.  
  27. android.os.Parcel _reply = android.os.Parcel.obtain();  
  28.  
  29. int _result;  
  30.  
  31. try {  
  32.  
  33. _data.writeInterfaceToken(DESCRIPTOR);  
  34.  
  35. _data.writeStrongBinder((((window!=null))?(window.asBinder()):(null)));  
  36.  
  37. if ((attrs!=null)) {  
  38.  
  39. _data.writeInt(1);  
  40.  
  41. attrs.writeToParcel(_data, 0);  
  42.  
  43. }  
  44.  
  45. else {  
  46.  
  47. _data.writeInt(0);  
  48.  
  49. }  
  50.  
  51. _data.writeInt(requestedWidth);  
  52.  
  53. _data.writeInt(requestedHeight);  
  54.  
  55. _data.writeInt(viewVisibility);  
  56.  
  57. _data.writeInt(((insetsPending)?(1):(0)));  
  58.  
  59. //奇怪,outSurface的信息沒有寫到_data中。那.....  
  60.  
  61. mRemote.transact(Stub.TRANSACTION_relayout, _data, _reply, 0);  
  62.  
  63. _reply.readException();  
  64.  
  65. _result = _reply.readInt();  
  66.  
  67. if ((0!=_reply.readInt())) {  
  68.  
  69. outFrame.readFromParcel(_reply);  
  70.  
  71. }  
  72.  
  73. ....  
  74.  
  75. if ((0!=_reply.readInt())) {  
  76.  
  77. outSurface.readFromParcel(_reply); //從Parcel中讀取信息來填充outSurface  
  78.  
  79. }  
  80.  
  81. }  
  82.  
  83. finally {  
  84.  
  85. _reply.recycle();  
  86.  
  87. _data.recycle();  
  88.  
  89. }  
  90.  
  91. return _result;  
  92.  

真奇怪啊,Binder客戶端這頭竟然沒有把outSurface的信息發(fā)過去。我們趕緊看看服務端。

服務端這邊處理是在onTranscat函數中。

  1. @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException  
  2.  
  3. {  
  4.  
  5. switch (code)  
  6.  
  7. {  
  8.  
  9. case TRANSACTION_relayout:  
  10.  
  11. {  
  12.  
  13. data.enforceInterface(DESCRIPTOR);  
  14.  
  15. android.view.IWindow _arg0;  
  16.  
  17. android.view.Surface _arg10;  
  18.  
  19. //剛才說了,Surface信息并沒有傳過來,那么我們在relayOut中看到的outSurface是怎么  
  20.  
  21. //出來的呢?看下面這句,原來在服務端這邊竟然new了一個新的Surface!!!  
  22.  
  23. _arg10 = new android.view.Surface();  
  24.  
  25. int _result = this.relayout(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10);  
  26.  
  27. reply.writeNoException();  
  28.  
  29. reply.writeInt(_result);  
  30.  
  31. //_arg10是copyFrom了,那怎么傳到客戶端呢?  
  32.  
  33. if ((_arg10!=null)) {  
  34.  
  35. reply.writeInt(1);//調用Surface的writeToParcel,把信息加入reply  
  36.  
  37. _arg10.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);  
  38.  
  39. }  
  40.  
  41. return true;  
  42.  

太詭異了!竟然有這么多花花腸子。我相信如果沒有aidl的幫助,我無論如何也不會知道這其中的奧妙。

那好,我們的流程明白了。

◆客戶端雖然傳了一個surface,但其實沒傳遞給服務端

◆服務端調用writeToParcel,把信息寫到Parcel中,然后數據傳回客戶端

◆客戶端調用Surface的readFromParcel,獲得surface信息。

那就去看看writeToParcel吧。

[---->Surface_writeToParcel]

  1. static void Surface_writeToParcel(  
  2.  
  3. JNIEnv* env, jobject clazz, jobject argParcel, jint flags)  
  4.  
  5. {  
  6.  
  7. Parcel* parcel = (Parcel*)env->GetIntField(  
  8.  
  9. argParcel, no.native_parcel);  
  10.  
  11. const sp& control(getSurfaceControl(env, clazz));  
  12.  
  13. //還好,只是把數據序列化到Parcel中  
  14.  
  15. SurfaceControl::writeSurfaceToParcel(control, parcel);  
  16.  
  17. if (flags & PARCELABLE_WRITE_RETURN_VALUE) {  
  18.  
  19. setSurfaceControl(env, clazz, 0);  
  20.  
  21. }  
  22.  

那看看客戶端的Surface_readFromParcel吧。

[----->Surface_readFromParcel]

  1. static void Surface_readFromParcel(  
  2.  
  3. JNIEnv* env, jobject clazz, jobject argParcel)  
  4.  
  5. {  
  6.  
  7. Parcel* parcel = (Parcel*)env->GetIntField( argParcel, no.native_parcel);  
  8.  
  9. //客戶端這邊還沒有surface呢  
  10.  
  11. const sp& control(getSurface(env, clazz));  
  12.  
  13. //不過我們看到希望了,根據服務端那邊Parcel信息來構造一個新的surface  
  14.  
  15. sp rhs = new Surface(*parcel);  
  16.  
  17. if (!Surface::isSameSurface(control, rhs)) {  
  18.  
  19. setSurface(env, clazz, rhs); //把這個新surface賦給客戶端。終于我們有了surface!  
  20.  
  21. }  
  22.  

到此,我們終于七拐八繞的得到了surface,這其中經歷太多曲折了。下一節(jié),我們將精簡這其中復雜的操作,統(tǒng)一歸到Native層,以這樣為切入點來了解Surface的工作流程和原理。

好,反正你知道ViewRoot調用了relayout后,Surface就真正從WindowManagerService那得到了。繼續(xù)回到ViewRoot,其中還有一個重要地方是我們知道卻不了解的。

  1. private void performTraversals() {  
  2.  
  3. // cache mView since it is used so much below...  
  4.  
  5. final View host = mView;  
  6.  
  7. boolean initialized = false;  
  8.  
  9. boolean contentInsetsChanged = false;  
  10.  
  11. boolean visibleInsetsChanged;  
  12.  
  13. try {  
  14.  
  15. relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);  
  16.  
  17. // relayoutWindow完后,我們得到了一個無比寶貴的Surface  
  18.  
  19. //那我們畫界面的地方在哪里?就在這個函數中,離relayoutWindow不遠處。  
  20.  
  21. ....  
  22.  
  23. boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw();  
  24.  
  25. if (!cancelDraw && !newSurface) {  
  26.  
  27. mFullRedrawNeeded = false;  
  28.  
  29. draw(fullRedrawNeeded); //draw?draw什么呀?  
  30.  

[--->ViewRoot::draw()]

  1. private void draw(boolean fullRedrawNeeded) {  
  2.  
  3. Surface surface = mSurface; //嘿嘿,不擔心了,surface資源都齊全了  
  4.  
  5. if (surface == null || !surface.isValid()) {  
  6.  
  7. return;  
  8.  
  9. }  
  10.  
  11. if (mAttachInfo.mViewScrollChanged) {  
  12.  
  13. mAttachInfo.mViewScrollChanged = false;  
  14.  
  15. mAttachInfo.mTreeObserver.dispatchOnScrollChanged();  
  16.  
  17. }  
  18.  
  19. int yoff;  
  20.  
  21. final boolean scrolling = mScroller != null && mScroller.computeScrollOffset();  
  22.  
  23. if (scrolling) {  
  24.  
  25. yoff = mScroller.getCurrY();  
  26.  
  27. else {  
  28.  
  29. yoff = mScrollY;  
  30.  
  31. }  
  32.  
  33. if (mCurScrollY != yoff) {  
  34.  
  35. mCurScrollY = yoff;  
  36.  
  37. fullRedrawNeeded = true;  
  38.  
  39. }  
  40.  
  41. float appScale = mAttachInfo.mApplicationScale;  
  42.  
  43. boolean scalingRequired = mAttachInfo.mScalingRequired;  
  44.  
  45. Rect dirty = mDirty;  
  46.  
  47. if (mUseGL) { //我們不用OPENGL  
  48.  
  49. ...  
  50.  
  51. }  
  52.  
  53. Canvas canvas;  
  54.  
  55. try {  
  56.  
  57. int left = dirty.left;  
  58.  
  59. int top = dirty.top;  
  60.  
  61. int right = dirty.right;  
  62.  
  63. int bottom = dirty.bottom;  
  64.  
  65. //從Surface中鎖定一塊區(qū)域,這塊區(qū)域是我們認為的需要重繪的區(qū)域  
  66.  
  67. canvas = surface.lockCanvas(dirty);  
  68.  
  69. // TODO: Do this in native  
  70.  
  71. canvas.setDensity(mDensity);  
  72.  
  73. }  
  74.  
  75. try {  
  76.  
  77. if (!dirty.isEmpty() || mIsAnimating) {  
  78.  
  79. long startTime = 0L;  
  80.  
  81. try {  
  82.  
  83. canvas.translate(0, -yoff);  
  84.  
  85. if (mTranslator != null) {  
  86.  
  87. mTranslator.translateCanvas(canvas);  
  88.  
  89. }  
  90.  
  91. canvas.setScreenDensity(scalingRequired  
  92.  
  93. ? DisplayMetrics.DENSITY_DEVICE : 0);  
  94.  
  95. //mView就是之前的decoreView,  
  96.  
  97. mView.draw(canvas);  
  98.  
  99. }  
  100.  
  101. finally {  
  102.  
  103. //我們的圖畫完了,告訴surface釋放這塊區(qū)域  
  104.  
  105. surface.unlockCanvasAndPost(canvas);  
  106.  
  107. }  
  108.  
  109. if (scrolling) {  
  110.  
  111. mFullRedrawNeeded = true;  
  112.  
  113. scheduleTraversals();  
  114.  
  115. }  
  116.  

看起來,這個surface的用法很簡單嘛:

l lockSurface,得到一個畫布Canvas

l 調用View的draw,讓他們在這個Canvas上盡情繪圖才。另外,這個View會調用所有它的子View來畫圖,最終會進入到View的onDraw函數中,在這里我們可以做定制化的界面美化工作。當然,如果你想定制化整個系統(tǒng)畫圖的話,完全可以把performTranvsal看懂,然后再修改。

l unlockCanvasAndPost,告訴Surface釋放這塊畫布

當然,這幾個重要函數調用干了具體的活。這些重要函數,我們最終會精簡到Native層的。

2 總結

到這里,你應該知道了一個Activity中,調用setContentView后它如何從系統(tǒng)中獲取一塊Surface,以及它是如何使用這個Surface的了。不得不說,關于UI這塊,Android絕對是夠復雜的。難怪2.3把UI這塊代碼基本重寫一遍,希望能夠簡單精煉點。

【編輯推薦】

  1. Android開發(fā):自定義GridView/ListView數據源
  2. Android自定義標題欄:顯示網頁加載進度
  3. Android應用開發(fā)教程:兩個運行的Activity之間的通信
  4. Android學習筆記:Activity跳轉

【責任編輯:小野 TEL:(010)68476606】

內容導航
 第 1 頁:Activity是如何顯示的 第 2 頁:JNI層

本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Android深入淺出之Surface
[轉]Android IPC進程通信——Messager方式
Android中AIDL實現(xiàn)進程通信
理解 Android Binder 機制:Java層
Android Study - 關于AIDL的使用學習
使用AIDL(Android接口描述語言)設計和使用遠程接口
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服