上一篇文章,在解析初始化GraphicBuffer中,遇到一個ion驅動,對圖元進行管理。首先看看ion是怎麼使用的:
我們按照這個流程分析ion的源碼。
如果對ion使用感興趣,可以去這篇文章下面看 https://blog.csdn.net/hexiaolong2009/article/details/102596744
本文基於Android的linux內核版本3.1.8
遇到什麼問題歡迎來本文討論 https://www.jianshu.com/p/5fe57566691f
什麼是ion?如果是音視頻,Camera的工程師會對這個驅動比較熟悉。最早的GPU和其他驅動協作申請一塊內存進行繪制是使用比較粗暴的共享內存。在Android系統中使用的是匿名內存。最早由三星實現了一個Display和Camera共享內存的問題,曾經在Linux社區掀起過一段時間。之後各路大牛不斷的改進之下,就成為了dma_buf驅動。並在 Linux-3.3 主線版本合入主線。現在已經廣泛的運用到各大多媒體開發中。
首先介紹dma_buf的2個角色,importer和exporter。importer是dma_buf驅動中的圖元消費者,exporter是dma_buf驅動中的圖元生產者。
這里借用大佬的圖片:
ion是基於dma_buf設計完成的。經過閱讀源碼,其實不少思路和Android的匿名內存有點相似。閱讀本文之前就算不知道dma_buf的設計思想也沒關系,我不會仔細到每一行,我會注重其在gralloc服務中的申請流程,看看ion是如何管理共享內存,為什麼要拋棄ashmem。
我們先來看看ion的file_operation:
只有一個open和ioctl函數。但是沒有mmap映射。因此mmap映射的時候一定其他對象在工作。
我們關注顯卡英偉達的初始化模塊。
文件:/ drivers / staging / android / ion / tegra / tegra_ion.c
mole_platform_driver實際上就是我之前經常提到過的mole_init的一個宏,多了一個register注冊到對應名字的平台中的步驟。在這裡面注冊了一個probe方法指針,probe指向的tegra_ion_probe是載入內核模塊注冊的時候調用。
先來看看對應的結構體:
再來看看對應ion內的堆結構體:
完成的事情如下幾個步驟:
我們不關注debug模式。其實整個就是我們分析了很多次的方法。把這個對象注冊miscdevice中。等到insmod就會把整個整個內核模塊從dev_t的map中關聯出來。
我們來看看這個驅動結構體:
文件:/ drivers / staging / android / ion / ion_heap.c
這里有四個不同堆會申請出來,我們主要來看看默認的ION_HEAP_TYPE_SYSTEM對應的heap流程。
其實真正象徵ion的內存堆是下面這個結構體
不管原來的那個heap,會新建3個ion_system_heap,分別order為8,4,0,大於4為大內存。意思就是這個heap中持有一個ion_page_pool 頁資源池子,裡面只有對應order的2的次冪,內存塊。其實就和夥伴系統有點相似。
還會設置flag為ION_HEAP_FLAG_DEFER_FREE,這個標志位後面會用到。
文件:/ drivers / staging / android / ion / ion_page_pool.c
在pool中分為2個鏈表一個是high_items,另一個是low_items。他們之間的區分在此時就是以2為底4的次冪為分界線。
文件:/ drivers / staging / android / ion / ion.c
因為打開了標志位ION_HEAP_FLAG_DEFER_FREE和heap存在shrink方法。因此會初始化兩個回收函數。
文件:/ drivers / staging / android / ion / ion_heap.c
此時會創建一個內核線程,調用ion_heap_deferred_free內核不斷的循環處理。不過由於這個線程設置的是SCHED_IDLE,這是最低等級的時間片輪轉搶占。和Handler那個adle一樣的處理規則,就是閑時處理。
在這個循環中,不斷的循環銷毀處理heap的free_list裡面已經沒有用的ion_buffer緩沖對象。
文件:/ drivers / staging / android / ion / ion_system_heap.c
注冊了heap的銷毀內存的方法。當系統需要銷毀頁的時候,就會調用通過register_shrinker注冊進來的函數。
文件:/ drivers / staging / android / ion / ion_page_pool.c
整個流程很簡單,其實就是遍歷循環需要銷毀的頁面數量,接著如果是8的次冪就是移除high_items中的page緩存。4和0則銷毀low_items中的page緩存。至於為什麼是2的次冪其實很簡單,為了銷毀和申請簡單。__free_pages能夠整頁的銷毀。
文件:/ drivers / staging / android / ion / ion.c
主要就是初始化ion_client各個參數,最後把ion_client插入到ion_device的clients。來看看ion_client結構體:
核心還是調用ion_alloc申請一個ion緩沖區的句柄。最後把數據拷貝會用戶空間。
這個實際上就是找到最小能承載的大小,去申請內存。如果8kb申請內存,就會拆分積分在0-4kb,4kb-16kb,16kb-128kb區間找。剛好dma也是在128kb之內才能申請。超過這個數字就禁止申請。8kb就會拆成2個4kb保存在第一個pool中。
最後所有的申請的page都添加到pages集合中。
文件:/ drivers / staging / android / ion / ion_page_pool.c
能看到此時會從 ion_page_pool沖取出對應大小區域的空閑頁返回上層,如果最早的時候沒有則會調用ion_page_pool_alloc_pages申請一個新的page。由於引用最終來自ion_page_pool中,因此之後申請之後還是在ion_page_pool中。
這里的處理就是為了避免DMA直接內存造成的緩存差異(一般的申請,默認會帶一個DMA標志位)。換句話說,是否打開cache其實就是,關閉了則使用pool的cache,打開了則不使用pool緩存,只依賴DMA的緩存。
我們可以看另一個dma的heap,它是怎麼做到dma內存的一致性.
文件: drivers / staging / android / ion / ion_cma_heap.c
能看到它為了能辦到dma緩存的一致性,使用了dma_alloc_coherent創建了一個所有強制同步的地址,也就是沒有DMA緩存的地址。
這里出現了幾個新的結構體,sg_table和scatterlist
文件:/ lib / scatterlist.c
這裡面實際上做的事情就是一件:初始化sg_table.
sg_table中有一個核心的對象scatterlist鏈表。如果pages申請的對象數量<PAGE_SIZE/sizeof(scatterlist),每一項sg_table只有一個scatterlist。但是超出這個數字就會增加一個scatterlist。
用公式來說:
換句話說,每一次生成scatterlist的鏈表就會直接盡可能占滿一頁,讓內存更好管理。
返回了sg_table。
初始化ion_handle,並且記錄對應的ion_client是當前打開文件的進程,並且設置ion_buffer到handle中。使得句柄能夠和buffer關聯起來。
每當ion_buffer需要銷毀,
❷ 如何查看Android源碼
當我們在eclipse中開發android程序的時候,往往需要看源代碼(可能是出於好奇,可能是讀源碼習慣),那麼如何查看Android源代碼呢?
比如下面這種情況
假設我們想參看Activity類的源代碼,按著Ctrl鍵,左擊它,現實的結果卻看不到代碼的,提示的信息便是「找不到Activity.class文件」。
此時點擊下面的按鈕,「Change Attached Source…」,選擇android源代碼所在位置,便彈出圖三的對話框。
第一種是選擇工作目錄,即已經存在的android應用程序源代碼。
第二種分兩種方式
(1)選擇External File…按鈕,添加Jar格式文件或者zip格式文件路徑;
(2)選擇External Floder…按鈕,添加文件夾所在路徑。
下面問題就來了,源代碼在哪裡?不能憑空產生阿。
可以通過Android SDK Manager進行源代碼下載;(推薦該種方法),如圖四
勾選Source for Android SDK,進行下載即可。
此外也可通過其他途徑下載,網上有很多共享的資源。
這里選擇第二種方式的(2)方法,選擇源碼所在目錄(即圖四下載源代碼目錄所在路徑),如圖五
點擊「OK」按鈕,此時,Activity文件便能夠查看源代碼了,如圖六。
這樣就大功告成了!!!
❸ 求android源碼下載地址,就像學學源碼的原理
Google剛剛公布,穩定版的Android源代碼已經公布,任何人都可以免費下載。Google希望通過公布源代碼,電信運營商和手機製造商,乃至一般開發者們進一步深刻了解和利用Android系統,從而有益於該平台下的的發展。
看來T-Mobile G1不一定打得過iPhone,那麼Android呢?
現在源代碼公布在http://source.android.com/,SDK網站是http://code.google.com/android/
❹ android源碼里有哪些比較好的演算法或框架推薦
Android中對於圖形界面以及多媒體的相關操作比較容易實現。而且對於大多數
手機
用戶來說,他們主要也就是根據這些方面的功能來對系統那個進行修改。我們可以通過本文介紹的Android多媒體框架的源碼解讀,來具體分析一下這方面的基本知識。
Android多媒體框架的代碼在以下目錄中:external/opencore/。這個目錄是Android多媒體框架的根目錄,其中包含的子目錄如下所示:
* android:這裡面是一個上層的庫,它基於PVPlayer和PVAuthor的SDK實現了一個為Android使用的Player和Author。
* baselibs:包含數據結構和線程安全等內容的底層庫
* codecs_v2:這是一個內容較多的庫,主要包含編解碼的實現,以及一個OpenMAX的實現
* engines:包含PVPlayer和PVAuthor引擎的實現
* extern_libs_v2:包含了khronos的OpenMAX的頭文件
* fileformats:文件格式的據具體解析(parser)類
* nodes:編解碼和文件解析的各個node類。
* oscl:操作系統兼容庫
* pvmi: 輸入輸出控制的抽象介面
* protocols:主要是與網路相關的RTSP、RTP、HTTP等協議的相關內容
* pvcommon:pvcommon庫文件的Android.mk文件,沒有源文件。
* pvplayer:pvplayer庫文件的Android.mk文件,沒有源文件。
* pvauthor:pvauthor庫文件的Android.mk文件,沒有源文件。
* tools_v2:編譯工具以及一些可注冊的模塊。
Splitter的定義與初始化
以wav的splitter為例,在fileformats目錄下有解析wav文件格式的pvwavfileparser.cpp文件,在nodes目錄下有pvmf_wavffparser_factory.cpp,pvmf_wavffparser_node.h, pvmf_wavffparser_port.h等文件。
我們由底往上看,vwavfileparser.cpp中的PV_Wav_Parser類有InitWavParser(),GetPCMData(),RetrieveFileInfo()等解析wav格式的成員函數,此類應該就是最終的解析類。我們搜索PV_Wav_Parser類被用到的地方可知,在PVMFWAVFFParserNode類中有PV_Wav_Parser的一個指針成員變數。
再搜索可知,PVMFWAVFFParserNode類是通過PVMFWAVFFParserNodeFactory的CreatePVMFWAVFFParserNode()成員函數生成的。而CreatePVMFWAVFFParserNode()函數是在PVPlayerNodeRegistry::PVPlayerNodeRegistry()類構造函數中通過PVPlayerNodeInfo類被注冊到Oscl_Vector<PVPlayerNodeInfo, OsclMemAllocator> 的vector中,在這個構造函數中,AMR,mp3等node也是同樣被注冊的。
由上可知,Android多媒體框架中對splitter的管理也是與ffmpeg等類似,都是在框架的初始化時注冊的,只不過Opencore注冊的是每個splitter的factory函數。
綜述一下splitter的定義與初始化過程:
每個splitter都在fileformats目錄下有個對應的子目錄,其下有各自的解析類。
每個splitter都在nodes目錄下有關對應的子目錄,其下有各自的統一介面的node類和node factory類。
播放引擎PVPlayerEngine類中有PVPlayerNodeRegistry iPlayerNodeRegistry成員變數。
在PVPlayerNodeRegistry的構造函數中,將 AMR, AAC, MP3等splitter的輸入與輸出類型標示和node factory類中的create node與release delete介面通過PVPlayerNodeInfo類push到Oscl_Vector<PVPlayerNodeInfo, OsclMemAllocator> iType成員變數中。
當前Splitter的匹配過程
PVMFStatus PVPlayerNodeRegistry::QueryRegistry(PVMFFormatType& aInputType, PVMFFormatType& aOutputType, Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids)函數的功能是根據輸入類型和輸出類型,在已注冊的node vector中尋找是否有匹配的node,有的話傳回其唯一識別標識PVUuid。
從QueryRegistry這個函數至底向上搜索可得到,在android中splitter的匹配過程如下:
android_media_MediaPlayer.cpp之中定義了一個JNINativeMethod(java本地調用方法)類型的數組gMethods,供java代碼中調用MultiPlayer類的setDataSource成員函數時找到對應的c++函數
1.{"setDataSource", "(Ljava/lang/String;)V", (void *)
android_media_MediaPlayer_setDataSource},
2.static void android_media_MediaPlayer_setDataSource
(JNIEnv *env, jobject thiz, jstring path)
此函數中先得到當前的MediaPlayer實例,然後調用其setDataSource函數,傳入路徑
3.status_t MediaPlayer::setDataSource(const char *url)
此函數通過調getMediaPlayerService()先得到當前的MediaPlayerService, const sp<IMediaPlayerService>& service(getMediaPlayerService());
然後新建一個IMediaPlayer變數, sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length));
在sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)中
調status_t MediaPlayerService::Client::setDataSource(const char *url)函數,Client是MediaPlayerService的一個內部類。
在MediaPlayerService::Client::setDataSource中,調sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
生成一個繼承自MediaPlayerBase的PVPlayer實例。
❺ 怎樣著手研究 Android 源代碼
一、源碼里的工程需要導入所有的Android源碼,不可以單獨作為一個Android工程導入到Eclipse里。
二、使用git和repo下載Android的源代碼,參考如下步驟
以下操作都是在Ubuntu10.04LTS下完成:
1)安裝git
sudo apt-get install git-core
2)安裝curl
sudo apt-get install git-core curl
3)安裝Repo,為了方便直接下載repo到用戶根目錄中。通過curl下載repo
curl http://android.git.kernel.org/repo >~/repo
4)給repo可執行的許可權
chmod a+x ~/repo
5)新建一個目錄,然後進入該目錄。通過repo將當前Android上所有源代碼下載。
首先初始化本地,
~/repo init -u git://android.git.kernel.org/platform/manifest.git
看到repo initialized in /android的提示後,則證明初始化完畢。成功後會在~/android下生成.repo文件夾
執行
repo sync
則自動開始下載源代碼。git支持斷點續傳,如果中斷了下次可繼續。
單獨下載內核,用這個
git clone git://android.git.kernel.org/kernel/linux-2.6.git
如果想拿某個branch而不是主線上的代碼,我們需要用-b參數制定branch名字,比如:
repo init -u git://android.git.kernel.org/platform/manifest.git -b froyo
另一種情況是,我們只需要某一個project的代碼,比如kernel/common,就不需要repo了,直接用Git即可。
git clone git://android.git.kernel.org/kernel/common.git
❻ 如何獲取android源代碼
當前的Android代碼託管在兩個方:https://github.com/android 和https://android.googlesource.com之前在 android.git.kernel.org上也有託管,不過現在重定向到了https://android.googlesource.com好在都支持git訪問。
google提供的repo工具實際上是一個內部操作git工具來簡化操作Android源碼的Python腳本。經過嘗試,直接使用git工具在ubuntu下可以實現cloneAndroid源碼。下面介紹一下方法:
1.獲取當前的在github上託管的Androidgitrepositories:
github頁面為:https://github.com/android/following。不過這個頁面不支持通過wget"https://github.com/android/following"或者curl"https://github.com/android/following"的方式訪問,錯誤信息如下:
這個時候需能做的只能是"tryagain"了。
需要說明的是"不要試圖同時並發執行多個gitclone命令",這樣會導致大量出現上面貼圖中的錯誤,另外,整個clone過程中耗時最多的gitrepository如下:
kernel_common.gitkernel_msm.gitplatform_frameworks_base.gitplatform_prebuilt.git其中platform_prebuilt.git是google提供的預編譯好的二進制文件,包含:各種庫文件,jar包,可執行程序等等,如果只是閱讀Android源代碼,這個gitrepository可以不用clone.