• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            ++wythern++

            X presents Y for a better Z

            #

            [轉]android native層memory leak分析辦法

            原文在這里

              • adb shell setprop libc.debug.malloc 1
              • adb shell ps mediaserver
              • adb shell kill <mediaserver_pid>
            1. Call dumpMemoryAddresses(). (in MemoryLeakTrackUtil.cpp).
            2. $ adb pull /proc/<mediaserver_pid>/maps
            3. get the diff file of memory allocations
              • $ adb pull /data/000 .
              • $ adb pull /data/111 .
              • $ diff 000 111 >diff_0_1
            4. $ ./addr2func.py --root-dir=../ --maps-file=./maps diff_0_1

            posted @ 2012-07-12 19:51 wythern 閱讀(1546) | 評論 (0)編輯 收藏

            [轉】MediaScanner用法總結

            MediaScanner用法總結


            轉自這里以及這里


            -   掃描全部

             

            Java代碼  收藏代碼
            1. public void systemScan(){  
            2.         sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"  
            3.                 + Environment.getExternalStorageDirectory())));  
            4.     }  

             

             

            -  掃描某個文件  參數:填入該文件的路徑

             

            Java代碼  收藏代碼
            1. public void fileScan(String file){  
            2.         Uri data = Uri.parse("file://"+file);  
            3.           
            4.         sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data));  
            5.     }  

             

             

            - 掃描文件夾 參數:填入該文件夾路徑

             

            Java代碼  收藏代碼
            1. public void fileScan(String file){  
            2.         Uri data = Uri.parse("file://"+file);  
            3.           
            4.         sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data));  
            5.     }  
            6.       
            7.     public void folderScan(String path){  
            8.         File file = new File(path);  
            9.           
            10.         if(file.isDirectory()){  
            11.             File[] array = file.listFiles();  
            12.               
            13.             for(int i=0;i<array.length;i++){  
            14.                 File f = array[i];  
            15.                   
            16.                 if(f.isFile()){//FILE TYPE  
            17.                     String name = f.getName();  
            18.                       
            19.                     if(name.contains(".mp3")){  
            20.                         fileScan(f.getAbsolutePath());  
            21.                     }  
            22.                 }  
            23.                 else {//FOLDER TYPE  
            24.                     folderScan(f.getAbsolutePath());  
            25.                 }  
            26.             }  
            27.         }  
            28.     }  

             

             

             

             

            posted @ 2012-06-04 20:38 wythern 閱讀(396) | 評論 (0)編輯 收藏

            [轉]eclipse中幾種加入jar包方式的區別

            原文鏈接:
            http://yilin.iteye.com/blog/941062


                 Java中的Jar是如此的重要,以至于沒有他們,我們就不能做出如此藝術的程序:封裝、模塊化、復用等等(無ant、marven方式) 。

            今天,我就來整理一些有關項目中的jar包添加管理的方法以及常見問題的解決:

            1、jar導入到我們的web項目中的classpath下

                 1)這里呢,一種方法是,直接用MyEclipse里自帶的相關的項目jar包,右擊項目“MyEclipse”菜單,選擇對應的jar包就OK了,例 “Add Spring Capabilities”,并且可以設置Spring的一些配置信息,不錯的可視化操作;

                 2)添加外部的jar包到web項目的lib包下,右擊項目“Properties”-->“Java Build Path”-->“Libraries”選項卡(當然了,此操作下,不僅僅這一種添加jar包的方式);

                 3)自己手動拷貝jar文件到項目的lib包下,具體操作只要把要添加的jar文件拷貝到MyEclipse中的workspace下的lib包里就好了;

            至此,jar文件的添加就OK了,so easy!jar是加進去了,但這幾種有什么區別,以后如何管理呢,接下來看看第2點

             

            2、三種jar包添加方式,都行得通,很OK,那么要如何擇決呢

                 1)這種方式,jar文件直接鏈接到MyEclipse的文件下,并沒有拷貝到WEB-INF/lib目錄下,不得用項目的發布、移植,可能會出現jar找不到的情形;

                 2)選擇性比較的強,可以隨意的加jar包,只要在你本機存在就可以了,鏈接的也是jar文件的絕對路徑,缺點同1;

                 3)直接添加到WEB-INF/lib目錄下,移植性強,可操作性也強。

            總而言之,第3)種jar包導入方式,個人覺得還是不錯的了!

             

            3、顯示/隱藏項目里的jar文件

                 不同的開發人員,都有著他固有的習慣,有的人就覺得把jar包顯示在開發視圖里太礙眼,看起來不舒服,復雜。而有些人呢,他就想研究看看到底運用了哪些技 術,導了哪些jar包,并且通過點擊jar包里的class文件直接查看源碼(假設先前有導入源碼)。所以呢,這里就牽涉到了一個jar包的顯示與隱藏問 題了:在Package Explorer這個窗體中,右上角有個下拉小三角,點擊-->“Filters”-->“Name filter patterns(matching names will be hidden)”,在這一選項下填有*.jar,勾上復選框即表示這一類的文件不顯示,多個類型之間可用“,”分隔。

             

            4、在Eclipse工程的Java Build Path設置中,可以通過加入第三方的jar包,但是,我發現是有好幾種方法來完成這個操作的,有“Add jars”,“Add Externel jars”,“Add library”,“Add Classes Loader”等,這幾種方式有什么區別嗎?
            add jar是表示從你的工程里添加JAR,前提是你把jar已經放到自己的工程目錄里。
            add external jar表示這個jar的位置需要URI來定位,需要給出全路徑。
            add library 是一些已經定義好的jar的集合,因為它們經常是一起用,所以簡化了些操作,比如你做RCP開發的時候就會有個plugin library包含了運行工程所需要的基本插件。
            Add classes Loader -- 這個應該是 add class folder吧?這個跟添加jar是一個意思,就是告訴ClassLoader去哪找class

             

            5.當出現java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener類似這種找不到Listener的異常 時,要切記spring的jar包一定要放在工程的lib下這樣才能避免這個錯誤的發生。

            補充:雖說無論用什么方式導入包在本地運行都是一樣的,但實事上我運行時,有的只有Java Build Path才起作用,有的只有導入到lib下才行。Java Build Path導入包和把包復制到lib下是有區別的,它倆其實不會沖突,也沒有什么關系的,Java Build Path是我們編譯需要的包,在比如在import ***.***.***時如果沒用Java Build Path導入包的話類里面就有紅叉,說不識別這個類;導入到lib下是程序運行時需要的包,即便用Java Build Path導入過的包,沒放到lib下,運行項目時會出現ClassNotFoundException的異常。

            posted @ 2012-05-17 15:00 wythern 閱讀(11356) | 評論 (0)編輯 收藏

            【轉】Android 調試技術

            原文鏈接:
            http://www.bobbog.com/archives/19


            Android 調試技術

            by bob

            一、JAVA層單步調試

            參見“用eclipse單步調試Laucher
            參見“用eclipse編譯調試adnroid的Browser

            二、Native層單步調試

            參見“使用GDB 單步調試Android本地代碼

            三、JAVA層堆棧打印

            1. 在指定的函數內打印相關java調用

            Log.d(TAG,Log.getStackTraceString(new Throwable()));

            2. 普通JAVA進程堆棧

            ActivityManagerService.dumpStackTraces

            保存在系統設置dalvik.vm.stack-trace-file指定的文件data/anr/traces.txt中。可以包含多個進程堆棧信息。

            3. 內核進程堆棧

            dumpKernelStackTraces,該函數為私有函數,不可調用。
            代碼在frameworks/base/services/java/com/android/server/Watchdog.java
            保存在系統設置dalvik.vm.stack-trace-file指定的文件data/anr/traces.txt中。

            4. 出異常時打印當前堆棧

            Exception::printStackTrace()

            try {  ... } catch (RemoteException e) {   e.printStackTrace();   ... }

            5. 輸出指定進程的堆棧

            Process.sendSignal(pid, Process.SIGNAL_QUIT)

            保存在data/anr/traces.txt。
            這個只對java進程有效,由dalvikvm的SignalCatcher.c處理。

            四、Native層堆棧打印

            1. CallStack

            使用方式:

            #include <utils/CallStack.h> ... CallStack stack; stack.update(); stack.dump("");  // the parameter is prefix of dump

            在使用之前需要修改system/core/include/arch/linux-arm/AndroidConfig.h

            #define HAVE_DLADDR 1 #define HAVE_CXXABI 1

            并在文件frameworks/base/libs/utils/Android.mk中大約105行(LOCAL_SHARED_LIBRARIES)后添加

            ifeq ($(TARGET_OS),linux) LOCAL_SHARED_LIBRARIES += libdl endif

            重新編譯,push生成的libutils.so到/system/lib/目錄下,重啟設備。

            五、JAVA異常分析

            這個android會輸出信息到logcat。容易分析。

            六、Natvie異常分析

            native進程異常會導致
            debuggerd會輸出信息到logcat并保存到/data/tombstones。
            可以修改system/core/debuggerd/debuggerd.c中dump_stack_and_code的代碼滿足更深的調試信息需求。

            七、日志Log系統

            在java中使用

            import android.util.Log; ... Log.d(TAG,"log info");

            在Native代碼中使用

            #define LOG_TAG "YOUR_LOGTAG" ... #include <utils/Log.h> #define LOG_NDEBUG 0 ... LOGD("log info");

            或者

            Log.d(LOG_TAG,“log info”);

            使用adb logcat時可以只顯示特定類別的LOG,還可以通過參數 -v threadtime 顯示線程號及時間信息。
            普通標準輸出轉為Logcat

            #system/bin/logwrapper 進程名

            八、其他調試手段(命令行)

            1. 打印指定JAVA進程的堆棧到文件中

            #kill -3 pid

            這里的3就是3.5節的Process.SIGNAL_QUIT。
            輸出在data/anr/traces.txt文件中。
            這個只對java進程有效,由dalvikvm處理。

            2. 打印指定進程的堆棧到Logcat

            #kill -11 pid 或者 #kill -7 pid

            這個有時有效。其原理是利用了(六)節的機制。
            可以用adb logcat看堆棧調用輸出。

            3. 打印指定進程的系統調用

            #strace -f -p pid -o output

            主要輸出文件、SOCKET、鎖等系統操作的信息。
            -f表示跟蹤所有子進程.
            -o輸出log到指定文件,可不用。

            posted @ 2012-04-16 19:02 wythern 閱讀(5677) | 評論 (0)編輯 收藏

            編譯android出現"too many open files"的解決辦法

            # vi /etc/sysctl.conf
            Append a config directive as follows:
            fs.file-max = 100000

            # vi /etc/security/limits.conf
            Set httpd user soft and hard limits as follows:
            httpd soft nofile 4096
            httpd hard nofile 10240

            Save and close the file. To see limits, enter:
            # su - httpd
            $ ulimit -Hn
            $ ulimit -Sn

            PS:好像需要重啟才能生效


            參考資料
            http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/

            posted @ 2012-02-06 15:28 wythern 閱讀(2258) | 評論 (0)編輯 收藏

            [轉]Android SurfaceFlinger中的SharedClient -- 客戶端(Surface)和服務端(Layer)之間的顯示緩沖區管理

            原文:
            http://blog.csdn.net/droidphone/article/details/5972568


              SurfaceFlinger在系統啟動階段作為系統服務被加載。應用程序中的每個窗口,對應本地代碼中的Surface,而Surface又對應于 SurfaceFlinger中的各個Layer,SurfaceFlinger的主要作用是為這些Layer申請內存,根據應用程序的請求管理這些 Layer顯示、隱藏、重畫等操作,最終由SurfaceFlinger把所有的Layer組合到一起,顯示到顯示器上。當一個應用程序需要在一個 Surface上進行畫圖操作時,首先要拿到這個Surface在內存中的起始地址,而這塊內存是在SurfaceFlinger中分配的,因為 SurfaceFlinger和應用程序并不是運行在同一個進程中,如何在應用客戶端(Surface)和服務端(SurfaceFlinger - Layer)之間傳遞和同步顯示緩沖區?這正是本文要討論的內容。

            Surface的創建過程

            我們先看看Android如何創建一個Surface,下面的序列圖展示了整個創建過程。

                                                                          圖一   Surface的創建過程

            創建Surface的過程基本上分為兩步:

            1. 建立SurfaceSession

            第一步通常只執行一次,目的是創建一個SurfaceComposerClient的實例,JAVA層通過JNI調用本地代碼,本地代碼創建一個 SurfaceComposerClient的實例,SurfaceComposerClient通過ISurfaceComposer接口調用 SurfaceFlinger的createConnection,SurfaceFlinger返回一個ISurfaceFlingerClient接 口給SurfaceComposerClient,在createConnection的過程中,SurfaceFlinger創建了用于管理緩沖區切換 的SharedClient,關于SharedClient我們下面再介紹,最后,本地層把SurfaceComposerClient的實例返回給 JAVA層,完成SurfaceSession的建立。

             

            2. 利用SurfaceSession創建Surface

            JAVA層通過JNI調用本地代碼Surface_Init(),本地代碼首先取得第一步創建的SurfaceComposerClient實例, 通過SurfaceComposerClient,調用ISurfaceFlingerClient接口的createSurface方法,進入 SurfaceFlinger,SurfaceFlinger根據參數,創建不同類型的Layer,然后調用Layer的setBuffers()方法, 為該Layer創建了兩個緩沖區,然后返回該Layer的ISurface接口,SurfaceComposerClient使用這個ISurface接 口創建一個SurfaceControl實例,并把這個SurfaceControl返回給JAVA層。

             

            由此得到以下結果:

            • JAVA層的Surface實際上對應于本地層的SurfaceControl對象,以后本地代碼可以使用JAVA傳入的SurfaceControl對象,通過SurfaceControl的getSurface方法,獲得本地Surface對象;
            • Android為每個Surface分配了兩個圖形緩沖區,以便實現Page-Flip的動作;
            • 建立SurfaceSession時,SurfaceFlinger創建了用于管理兩個圖形緩沖區切換的SharedClient對 象,SurfaceComposerClient可以通過ISurfaceFlingerClient接口的getControlBlock()方法獲得 這個SharedClient對象,查看SurfaceComposerClient的成員函數_init:

             

            1. void SurfaceComposerClient::_init(  
            2.         const sp<ISurfaceComposer>& sm, const sp<ISurfaceFlingerClient>& conn)  
            3. {  
            4.     ......  
            5.     mClient = conn;  
            6.     if (mClient == 0) {  
            7.         mStatus = NO_INIT;  
            8.         return;  
            9.     }  
            10.   
            11.     mControlMemory = mClient->getControlBlock();  
            12.     mSignalServer = sm;  
            13.     mControl = static_cast<SharedClient *>(mControlMemory->getBase());  
            14. }  

            獲得Surface對應的顯示緩沖區

            雖然在SurfaceFlinger在創建Layer時已經為每個Layer申請了兩個緩沖區,但是此時在JAVA層并看不到這兩個緩沖 區,JAVA層要想在Surface上進行畫圖操作,必須要先把其中的一個緩沖區綁定到Canvas中,然后所有對該Canvas的畫圖操作最后都會畫到 該緩沖區內。下圖展現了綁定緩沖區的過程:

                                                                                        圖二  綁定緩沖區的過程

                開始在Surface畫圖前,Surface.java會先調用lockCanvas()來得到要進行畫圖操作的Canvas,lockCanvas會進 一步調用本地層的Surface_lockCanvas,本地代碼利用JAVA層傳入的SurfaceControl對象,通過getSurface() 取得本地層的Surface對象,接著調用該Surface對象的lock()方法,lock()返回了改Surface的信息,其中包括了可用緩沖區的 首地址vaddr,該vaddr在Android的2D圖形庫Skia中,創建了一個bitmap,然后通過Skia庫中Canvas的 API:Canvas.setBitmapDevice(bitmap),把該bitmap綁定到Canvas中,最后把這個Canvas返回給JAVA 層,這樣JAVA層就可以在該Canvas上進行畫圖操作,而這些畫圖操作最終都會畫在以vaddr為首地址的緩沖區中。

                再看看在Surface的lock()方法中做了什么:

            • dequeueBuffer(&backBuffer)獲取backBuffer
              • SharedBufferClient->dequeue()獲得當前空閑緩沖區的編號
              • 通過緩沖區編號獲得真正的GraphicBuffer:backBuffer
              • 如果還沒有對Layer中的buffer進行映射(Mapper),getBufferLocked通過ISurface接口重新重新映射
            • 獲取frontBuffer
            • 根據兩個Buffer的更新區域,把frontBuffer的內容拷貝到backBuffer中,這樣保證了兩個Buffer中顯示內容的同步
            • backBuffer->lock() 獲得backBuffer緩沖區的首地址vaddr
            • 通過info參數返回vaddr

            釋放Surface對應的顯示緩沖區

            畫圖完成后,要想把Surface的內容顯示到屏幕上,需要把Canvas中綁定的緩沖區釋放,并且把該緩沖區從變成可投遞(因為默認只有兩個 buffer,所以實際上就是變成了frontBuffer),SurfaceFlinger的工作線程會在適當的刷新時刻,把系統中所有的 frontBuffer混合在一起,然后通過OpenGL刷新到屏幕上。下圖展現了解除綁定緩沖區的過程:

                                                                             圖三  解除綁定緩沖區的過程

            • JAVA層調用unlockCanvasAndPost
            • 進入本地代碼:Surface_unlockCanvasAndPost
            • 本地代碼利用JAVA層傳入的SurfaceControl對象,通過getSurface()取得本地層的Surface對象
            • 綁定一個空的bitmap到Canvas中
            • 調用Surface的unlockAndPost方法
              • 調用GraphicBuffer的unlock(),解鎖緩沖區
              • 在queueBuffer()調用了SharedBufferClient的queue(),把該緩沖區更新為可投遞狀態

            SharedClient 和 SharedBufferStack

            從前面的討論可以看到,Canvas綁定緩沖區時,要通過SharedBufferClient的dequeue方法取得空閑的緩沖區,而解除綁定 并提交緩沖區投遞時,最后也要調用SharedBufferClient的queue方法通知SurfaceFlinger的工作線程。實際上,在 SurfaceFlinger里,每個Layer也會關聯一個SharedBufferServer,SurfaceFlinger的工作線程通過 SharedBufferServer管理著Layer的緩沖區,在SurfaceComposerClient建立連接的階 段,SurfaceFlinger就已經為該連接創建了一個SharedClient 對象,SharedClient 對象中包含了一個SharedBufferStack數組,數組的大小是31,每當創建一個Surface,就會占用數組中的一個 SharedBufferStack,然后SurfaceComposerClient端的Surface會創建一個 SharedBufferClient和該SharedBufferStack關聯,而SurfaceFlinger端的Layer也會創建 SharedBufferServer和SharedBufferStack關聯,實際上每對 SharedBufferClient/SharedBufferServer是控制著同一個SharedBufferStack對象,通過 SharedBufferStack,保證了負責對Surface的畫圖操作的應用端和負責刷新屏幕的服務端(SurfaceFlinger)可以使用不 同的緩沖區,并且讓他們之間知道對方何時鎖定/釋放緩沖區。

            SharedClient和SharedBufferStack的代碼和頭文件分別位于:

            /frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp

            /frameworks/base/include/private/surfaceflinger/SharedBufferStack.h

             

             

                                                                                   圖四    客戶端和服務端緩沖區管理

                 繼續研究SharedClient、SharedBufferStack、SharedBufferClient、SharedBufferServer的誕生過程。

                1. SharedClient

            •     在createConnection階段,SurfaceFlinger創建Client對象:
            1. sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()  
            2. {  
            3.     Mutex::Autolock _l(mStateLock);  
            4.     uint32_t token = mTokens.acquire();  
            5.   
            6.     sp<Client> client = new Client(token, this);  
            7.     if (client->ctrlblk == 0) {  
            8.         mTokens.release(token);  
            9.         return 0;  
            10.     }  
            11.     status_t err = mClientsMap.add(token, client);  
            12.     if (err < 0) {  
            13.         mTokens.release(token);  
            14.         return 0;  
            15.     }  
            16.     sp<BClient> bclient =  
            17.         new BClient(this, token, client->getControlBlockMemory());  
            18.     return bclient;  
            19. }  
            • 再進入Client的構造函數中,它分配了4K大小的共享內存,并在這塊內存上構建了SharedClient對象:
            1. Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)  
            2.     : ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)  
            3. {  
            4.     const int pgsize = getpagesize();  
            5.     const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));  
            6.   
            7.     mCblkHeap = new MemoryHeapBase(cblksize, 0,  
            8.             "SurfaceFlinger Client control-block");  
            9.   
            10.     ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());  
            11.     if (ctrlblk) { // construct the shared structure in-place.  
            12.         new(ctrlblk) SharedClient;  
            13.     }  
            14. }  
            • 回到createConnection中,通過Client的getControlBlockMemory()方法獲得共享內存塊的 IMemoryHeap接口,接著創建ISurfaceFlingerClient的子類BClient,BClient的成員變量mCblk保存了 IMemoryHeap接口指針;
            • 把BClient返回給SurfaceComposerClient,SurfaceComposerClient通過 ISurfaceFlingerClient接口的getControlBlock()方法獲得IMemoryHeap接口指針,同時保存在 SurfaceComposerClient的成員變量mControlMemory中;
            • 繼續通過IMemoryHeap接口的getBase ()方法獲取共享內存的首地址,轉換為SharedClient指針后保存在SurfaceComposerClient的成員變量mControl中;
            • 至此,SurfaceComposerClient的成員變量mControl和SurfaceFlinger::Client.ctrlblk指向了同一個內存塊,該內存塊上就是SharedClient對象。 

                2. SharedBufferStack、SharedBufferServer、SharedBufferClient

                SharedClient對象中有一個SharedBufferStack數組:

                SharedBufferStack surfaces[ NUM_LAYERS_MAX ];

                NUM_LAYERS_MAX 被定義為31,這樣保證了SharedClient對象的大小正好滿足4KB的要求。創建一個新的Surface時,進入SurfaceFlinger的 createSurface函數后,先取在createConnection階段創建的Client對象,通過Client在 0--NUM_LAYERS_MAX 之間取得一個尚未被使用的編號,這個編號實際上就是SharedBufferStack數組的索引:

            1. int32_t id = client->generateId(pid);  
              

             然后以Client對象和索引值以及其他參數,創建不同類型的Layer對象,一普通的Layer對象為例:

            1. layer = createNormalSurfaceLocked(client, d, id,  
            2.                         w, h, flags, format);  

            在createNormalSurfaceLocked中創建Layer對象:

            1. sp<Layer> layer = new Layer(this, display, client, id);  

            構造Layer時會先構造的父類LayerBaseClient,LayerBaseClient中創建了SharedBufferServer對 象,SharedBufferStack 數組的索引值和SharedClient被傳入SharedBufferServer對象中。

            1. LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,  
            2.         const sp<Client>& client, int32_t i)  
            3.     : LayerBase(flinger, display), lcblk(NULL), client(client), mIndex(i),  
            4.       mIdentity(uint32_t(android_atomic_inc(&sIdentity)))  
            5. {  
            6.     lcblk = new SharedBufferServer(  
            7.             client->ctrlblk, i, NUM_BUFFERS,  
            8.             mIdentity);  
            9. }  

             

                自此,Layer通過lcblk成員變量(SharedBufferServer)和SharedClient共享內存區建立了關聯,并且每個Layer對應于SharedBufferStack 數組中的一項。

                回到SurfaceFlinger的客戶端Surface.cpp中,Surface的構造函數如下:

            1. Surface::Surface(const sp<SurfaceControl>& surface)  
            2.     : mClient(surface->mClient), mSurface(surface->mSurface),  
            3.       mToken(surface->mToken), mIdentity(surface->mIdentity),  
            4.       mFormat(surface->mFormat), mFlags(surface->mFlags),  
            5.       mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL),  
            6.       mWidth(surface->mWidth), mHeight(surface->mHeight)  
            7. {  
            8.     mSharedBufferClient = new SharedBufferClient(  
            9.             mClient->mControl, mToken, 2, mIdentity);  
            10.   
            11.     init();  
            12. }  

            SharedBufferClient構造參數mClient->mControl就是共享內存塊中的SharedClient對象,mToken就是SharedBufferStack 數組索引值。

            到這里我們終于知道,Surface中的mSharedBufferClient成 員和Layer中的lcblk成員(SharedBufferServer),通過SharedClient中的同一個 SharedBufferStack,共同管理著Surface(Layer)中的兩個緩沖區。



            一并參考:

            http://wenku.baidu.com/view/0243844bc850ad02de8041e6.html

             

            posted @ 2011-11-05 20:47 wythern 閱讀(425) | 評論 (0)編輯 收藏

            [轉]git 合并多個commit

            [source]
            http://blog.csdn.net/lynnos/article/details/6287135


            $ git reset --soft HEAD^1 (多個就是N了)

            $ git commit --amend

            posted @ 2011-08-09 16:41 wythern 閱讀(1229) | 評論 (0)編輯 收藏

            [轉]在Emacs里面如何替換有換行符的字符串

            [Source] 
            http://zh-cn.w3support.net/index.php?db=so&id=613022

            1. M-x replace-string ; \n
               will replace ";" with 2 characters "\n".

            2. M-x replace-regex ; \n
               get a error msg: Invalid use of `\' in replacement text.
               in this mode use C-q C-j to insert a RET into the string you current edited for replace/replaced.

            The author also said that you could paste a RET into the string for instead the method above, but i have not tested that.




            posted @ 2011-07-01 10:54 wythern 閱讀(1898) | 評論 (0)編輯 收藏

            Android Services in init.rc


            碰上一個寫在init.rc里面的service不能自動啟動的問題,加上class好了。
            service yourservice /sbin/yourservice
               class core
               user adb
               group adb
            class <name>
               Specify a class name for the service.  All services in a
               named class may be started or stopped together.  A service
               is in the class "default" if one is not specified via the
               class option.

            看起來是因為
            All services in a named class may be started or stopped together.
            而如果default的class都沒有起來的話,這個service也就不會自動啟動了
            所以 class_start default. 還是有用的....


            Ref:
            [Android init language]
            http://www.netmite.com/android/mydroid/1.6/system/core/init/readme.txt

            posted @ 2011-06-29 15:37 wythern 閱讀(1045) | 評論 (0)編輯 收藏

            Usage of zero element array

            Source: http://stackoverflow.com/questions/4255193/declaring-zero-size-vector

            This is called a flexible array member, and in C99 is written as char bar[];, and in C89 was written as char bar[1];, and which some compilers would let you write as char bar[0];. Basically, you only use pointers to the structure, and allocate them all with an amount of extra space at the end:

            const size_t i = sizeof("Hello, world!");
            struct foo *p = malloc(offsetof(struct foo, bar) + i);
            memcpy(p->bar, "Hello, world!", i);
            // initialize other members of p
            printf("%s\n", p->bar);

            That way, p->bar stores a string whose size isn't limited by an array declaration, but which is still all done in the same allocation as the rest of the struct (rather than needing the member to be a char * and need two mallocs and two frees to set it up).

            好處:連續(虛擬)內存空間以及僅需一次的free操作。

            posted @ 2011-05-04 13:37 wythern 閱讀(182) | 評論 (0)編輯 收藏

            僅列出標題
            共6頁: 1 2 3 4 5 6 
            亚洲国产另类久久久精品小说| 久久国产精品波多野结衣AV| 亚洲精品无码专区久久久| 无码人妻久久一区二区三区| 免费观看久久精彩视频| 色综合久久天天综线观看| 亚洲中文字幕无码久久综合网| 青草影院天堂男人久久| 欧美国产成人久久精品| 国产成人精品久久| 亚洲国产精品无码久久一线| 久久婷婷色综合一区二区| 久久99精品国产麻豆| 无码8090精品久久一区 | 欧美日韩中文字幕久久久不卡 | 久久成人国产精品| 久久亚洲国产成人影院网站| 国产一级做a爰片久久毛片| 久久久久亚洲AV成人网人人网站| 国产精品成人久久久久三级午夜电影| 久久久久亚洲av成人网人人软件 | 国产精品日韩欧美久久综合| 亚洲av成人无码久久精品| 久久青青草原精品国产不卡| 久久综合久久综合九色| 久久国产精品77777| 少妇久久久久久被弄高潮| 香蕉久久夜色精品国产2020| 亚洲精品无码久久久| 久久精品国产99国产精品| 狠狠色综合网站久久久久久久| 久久精品毛片免费观看| 久久AV高清无码| 成人国内精品久久久久一区| 国内精品久久久久影院优| 久久精品www人人爽人人| 国内精品伊人久久久久AV影院| 激情伊人五月天久久综合| 久久久久久久97| 亚洲伊人久久大香线蕉苏妲己| 青青国产成人久久91网|