1. 程式人生 > >Android框架理解之USB

Android框架理解之USB

目的是看一下android下的usblinux下的usb有什麼區別?如果現在就能回答,就不用往下看了。

我的理解是android下沒有usb

Android誕生的背景

乍一看這個話題與android框架似乎毫無關係,但是每一個新生事物的誕生必然取決於當時的環境,環境造就了這個新生事物,同時這個新生事物也應該承載著歷史所賦予他的責任,他也將因此擁有某種能力,來完成他的使命。

最近幾年手機的快速增長大家是有目共睹,手機已經擺脫了他最初的角色:打電話。他開始發簡訊、上網、打遊戲、看電影、聊天等等。基於手機的增值服務對手機軟體環境的需求越來越大。Android誕生前的手機作業系統是什麼樣子的?symbian

winCElinux以及mtk,還有其他廠商的一些手機平臺。當時的情況是手機廠家只管造出手機,沒人考慮還需要在手機上開發應用軟體,所以這些作業系統可以說基本上沒有給別人留出進一步開發應用程式的餘地、或者根本就沒想留。或者你會說linux是開源的,想怎麼開發就怎麼開發。能在linux下開發應用程式的有幾個,跟沒提供介面一樣,那個winCE還收費,更扯淡。所以說android誕生之前的手機作業系統市場是一個不懂服務、沒有服務的軍閥混戰時期。但是我們已經過了只求溫飽、不求娛樂的時期了,但是這些手機系統沒有跟上,他們沒有意識到服務的重要性、開放的重要性、與人方便的重要性。是iPhone,她搶先了一步,為廣大手機客戶創造了非凡的體驗效果,手機原來可以做到這種效果。但這並不夠,僅僅讓使用者擁有暫時的體驗是不夠的,要有持續不斷的新鮮體驗注入。蘋果公司針對iPhone
引入了一個新的模式appstore,讓廣大的手機軟體開發者不斷的為iPhone注入新鮮的血液,不斷的給iPhone手機使用者帶來新的體驗,手機軟體開發者也獲得了可觀的收入,這是一個雙贏的模式,是iPhone養活了手機軟體開發者,還是軟體開發者養活了iPhone,這已經說不清楚了。但是我們能看到的是使用者對手機應用的需求決定著手機系統的發展的方向。那麼市場需要什麼樣的手機系統(或者叫做手機軟體環境)?從手機廠商來說:要開源,不需要再買什麼手機開發平臺。從應用的角度來說:要讓應用軟體的開發變得簡單,讓廣大的軟體開發人員來一起養活這個系統。Linux是成熟的、開源的作業系統。Java一種開發應用最快捷的平臺,大量從事java
開發的軟體人員。是google,和iPhone幾乎同時被歷史所選中。Google,一個做網際網路搜尋的公司,輕易的切入了手機行業、移動網際網路行業。他將linuxjava結合在了一起,其實誰都能做到,但是卻沒有想到。誰會去做自己不賺錢,給別人提供方便、賺錢機會的事情:google可以做,大賺的機會應該在後面。Linuxjava的結合產生了什麼樣的效果?類似於剛才提到的在軍閥混戰的時期突然站出了一位眾望所歸的英雄。短短几個月就被大家認可。被無數的java開發人員追捧,終於有了用武之地,就跟找到了人生的方向、信仰一樣,大量的android團隊、網站紛紛出現,因為只要會java就可以做手機應用軟體賺錢。所以只要手機廠商推出了一款android手機,不用擔心沒有應用軟體,不用花錢去開發應用軟體,市場為他們開發了。

通過以上的總結,可以看出android最重要的是給java開發人員提供了應用軟體的開發環境。至此,我們終於引出了下一個話題:android是怎麼實現這個機制的?讓javalinux(一個C環境)融合在了一起。

瞭解一個新的事物,不一定要從應用者的角度、也不一定要從研發人員的角度,我們還可以從設計者的角度來考慮、從他誕生的環境來切入等等,並沒有固定的,只是在不同的階段可以考慮從不同的角度來切入。

二是JNI

上面我們只是說androidjava開發人員能夠方便的進行手機應用軟體開發了,更具體的說應該是更方便的在linux作業系統上以java語言進行應用軟體開發了。所以說android不是作業系統,是linux作業系統下的一個框架。一個可以使用java語言進行開發的框架,一個實現了通過java呼叫C或者C++(.so)進而linux作業系統的框架。這個框架是執行在linux系統上的一個程式,沒有這個框架,下面的linux系統已經完全能夠實現我們所需要的應用(和使用android達到一樣的效果),但是他不夠人性化。Linux強大的可移植性和java的平臺無關性,兩者的結合簡直就是perfect

上層應用和UIjava來完成,底層的硬體有C/C++來完成。如果底層的硬體有改動,只需要改動lib(.so)kernel層就可以了(我覺得叫做linux系統層更好)。層是一個很好的概念,層代表著獨立、自由。每一層的首要任務是負責自己層的事情,但是層與層之間需要溝通。Java層在實現某種功能時,如果需要呼叫底層的C元件,那麼就會使用JNI介面。JNIJava Native Interface的縮寫,譯為Java本地介面。它允許Java程式碼和其他語言編寫的程式碼進行互動。在android中提供JNI的方式,讓Java程式可以呼叫C語言程式。android中很多Java類都具有native介面,這些介面由本地實現,然後註冊到系統中。

JNI程式碼放在以下的路徑中:frameworks/base/core/jni/,這個路徑中的內容被編譯成庫 libandroid_runtime.so

Java轉化為位元組碼之後就需要虛擬機器來執行了。Dalvik virtual machine。在java執行的過程中,如果java類需要使用C++函式,那麼虛擬機器就會載入這個C函式。虛擬機器可以讓javaC之間通過標準的JNI相互呼叫。System.loadLibrary(*.so)這個動作就是java程式要求虛擬機器載入C函式,載入之後java類和.so庫就一起運行了。

下面是一個jni 例子。

關於jni如何使用,這裡就沒有必要介紹了,他只是用來連線JavaC++的一個簡單的機制,結合著java虛擬機器共同完成了javaC++的互動。

到了這裡我們可以考慮一下,JNI這個機制在android作用,他的作用也間接的反映出android的框架。作用就是連線java類和lib(.so C++),那麼也就是說android就是兩層:一層是java,另外一層是C++,通過JNI將兩層連線起來。當我們還不瞭解一件事物的時候,最好把他先想的簡單一點,之後再慢慢細分。

那麼為什麼android的框架模型中卻是4層呢?google在這點上我覺得有點不厚道。

1

底層的kernel層不屬於googleandroid,當然屬於linus torvalds還是google,已經不重要了,重要的是誤導了我對android的理解,以為android是一個作業系統,其實他不是。Kernel層的叫法我也不認同,我覺得應該叫做linux系統層。Android為什麼這麼叫?

三挾天子以令諸侯

       linuxandroid綁架了!android本來是執行在linux系統下的一個應用開發框架,但是他的光環已經掩蓋了linux系統,更可怕的是android正在逐步的修改linux系統,作業系統成了傀儡。Google嫁了女兒帶回來一個兒子(linux),這個被linus torvalds養了20年的兒子,給人做了上門女婿,並且在不斷的被洗腦、改造著。而linus torvalds和廣大的linux愛好者還要不斷的給linux提供生活補助。並且這個女兒好像也不是google的,好像是sun的。收養了一個看似普通的女兒,經過打扮,找了一個上門女婿(一個並未施展才華的小夥),組成了一個新的家庭:google稱其為android1+1 遠遠打大於了 2

       Google正在不遺餘力的包裝著這個新的組合,包裝都是有欺騙性的。但是做為即將在android環境下開發的人員來說,不能被他的宣傳廣告所迷惑,掌握了他的真實脈絡,才能進行開發、移植。

經過上面的感性認識,我們要回歸理性的分析。最底層kernel(大家都這麼叫),入鄉隨俗,不僅包括核心本身,各種驅動、檔案系統也盡在其中。對硬體的所有基本操作都在這一層,這一層有誰來維護,總之不是google,但是google卻可以在裡邊加入自己的元素:android元素,其實沒有說google這樣做不好的意思,相反很贊成,Google根據這套框架所執行的環境對linux 核心進行不斷的改造,可謂是為嵌入式量身打造。其上一層是lib庫層,為什麼會誕生這一層?我覺得他是為java層而生。Java層的應用程式在試圖操作kernel底層的裝置時,發現很費勁,所以設計者可能考慮需要在java應用層和kernel層之間插入一層:lib層。這一層將裝置驅動層和java應用層聯絡了起來。所以如果我們要讓我們的某個裝置在android的環境下使用起來(如果android當前的框架中無法支援這個裝置),就需要在開發完驅動後,再在lib層用C++寫一組JNI介面函式,供java層呼叫。這個機制並不複雜,這個開發工作是否複雜取決於你要將這個裝置呈現給java開發者的功能,如果只想做個helloworld,能複雜的了麼?所以寫到這我有一個想法(等待以後的驗證)android開發的難易取決於我們以後要實現的某種功能,而這個功能與android環境、linux系統沒有多大關係(可能有點關係,畢竟在人家的地盤)Lib層之上是所謂的framework層,我覺得從我們公司的性質來看,更傾向於將framework層和app層統稱為java層。這兩層都是java程式,一層是jar包,就是一些封裝好的API函式,一層是使用這些API,對於我們做晶片、做驅動、做方案來說,這兩層就是一層。我們只要理解一個宗旨就可以了:android誕生的目的就是讓java開發人員能夠方便的使用java語言操作各種硬體資源,進行應用程式的開發,所以在framework這一層的jar包僅僅是為app層使用的,僅僅是一個純軟體及別的層面,這一層和lib層相呼應。或者這樣來劃分:jni之上的frameworkapp叫做軟體層(或應用層),之下的libkernel叫做硬體層(或系統層)。軟體層的framework間接的反應著硬體的操作方法和功能,稱其為軟體層中的硬體反映層。Lib層就成為硬體層中的軟體供給層。

軟體中的軟體、軟體中的硬體、硬體中的軟體、硬體中的硬體,簡單理解就兩層;軟體層和硬體層。每一層的開發都基於下一層提供的功能介面。

記得當時有同事討論在android這個環境下能否直接使用C語言開發。中華人民共和國是有共產黨領導的,既然選擇了在這裡生活,你就應該堅持四項基本原則、擁護黨的領導,不要老是想著國外那些情況,動不動就罷工、遊行什麼的。在這裡就要按照我們國家的制度辦事,遊行可以,不過要按照中國的遊行法來做。享受著android帶來的開發便捷,還想著以前的linux,用什麼C語言來開發應用程式,枉費google的一片心血。所以我覺得不是不可以,但要看android的臉色和氣度。我覺得應該是可能的,android雖然強大,綁架了linux系統,但是linux畢竟是一個作業系統,是可以直接執行程式的。這個基於linux系統執行的程式和android是同級別的[m1]

2

http://www.you01.com/dzly/dzswf/2010072932.swf

四從系統裝載過程再認識android

       androidkernel是單獨編譯,單獨載入的。可以說是這個真相,觸發了這篇文章。

在編譯android 之後,會生成幾個image 檔案,這些檔案是:

   1 ramdisk.img    :   一個分割槽影像檔案,它會在kernel 啟動的時候,以只讀的方式被 mount,這個檔案中只是包含了 /init 以及一些配置檔案,這個ramdisk 被用來呼叫init,以及把真正的root file system mount 起來

   2 system.img:是包含了整個系統,android frameworkapplication 等等,會被掛接到 "/" 上,包含了系統中所有的二進位制檔案

  3 userdata.img:將會被掛接到 /data 下,包含了所有應用相關的配置檔案,以及使用者相關的資料

ramdisk.img is a small partition image that is mounted read-only by the kernel at boot time. It only contains /init and a few config files. It is used to start init which will mount the rest of the system images properly and run the init procedure. A Ramdisk is a standard Linux feature.

system.img is a partition image that will be mounted as / and thus contains all system binaries

userdata.img is a partition image that can be mounted as /data and thus contains all application-specific and user-specific data.

Ramdiskkernelandroid的橋樑,linux啟動後掛在ramdisk,然後再ramdisk裡邊有啟動android的指令碼。

Linux核心啟動完成後,會啟動第一個程序:init程序,它是一個由核心啟動的使用者級程序。核心啟動後,就通過啟動一個使用者級程式init的方式,完成引導程序。init始終是第一個程序。

       Init程序一起來就根據init.rc指令碼檔案建立了幾個基本的服務:

  •  servicemanamger
  •  zygote

………………

init.rc這個腳本里的內容就是android需要維護的,裡邊應當有啟動android的過程。這方面的內容將有zhicheng來講解。

從這個linux-----àandroid的啟動過程,是不是再一次感覺到了層的重要性,層與層之間相互獨立,層與層之間又提供了某種開發的介面,允許對方的侵入。同時從這個啟動過程也能夠知道我們的工作需要落實在哪一層上(根據我們的需求)

五以特定應用為主線縱向貫穿各層

經過上面的理解,對android應該是有了一定的理解的。理解的目的是要用,如何把這個框架使用起來。我們是做SOC的,還得給他們做解決方案,以前只做驅動就可以了,但是既然在andoird下混了,就要按照android的規則出牌,我們得給人提供jar包、lib庫。我們得有服務精神,讓廣大的java應用開發人員在我們的解決方案上,遊刃有餘的開發應用程式,我們的獎金得依靠他們。

那麼針對某種應用我們都需要幹什麼呢?需求驅動著一切(底層反應著一切),軟體開發人員需要什麼,我們就提供什麼,所以我們從app層的某個特定的功能應用開始。

以向sd卡中寫入一個檔案為例:

下面這段程式碼是從網上找的,用於向sd卡中寫入一個檔案的片段。

    if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){                      File sdCardDir = Environment.getExternalStorageDirectory();//獲取SDCard目錄,2.2的時候為:/mnt/sdcart  2.1的時候為:/sdcard,所以使用靜態方法得到路徑會好一點。

                File saveFile = new File(sdCardDir, "abc.txt");      

                FileOutputStream outStream = new FileOutputStream(saveFile);      

                outStream.write("你好".getBytes());      

                outStream.close();      

            }   

對於一個應用程式來說,必須要知道自己要向哪個目錄中寫入檔案。如果想往sd卡中寫,就需要知道sd卡對應的目錄:Environment.getExternalStorageDirectory();這句話是用來獲取sd卡的儲存目錄,將目錄存放到sdCardDir,比如是/sdcard

那麼些這個檔案的過程是什麼?outStream.write("你好".getBytes());到底幹了什麼?

進入FileOutputStream.java,可以看到write的具體實現:

    public void write(byte[] buffer, int offset, int count) throws IOException {

        if (buffer == null) {

            throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$

        }

        if ((count | offset) < 0 || count > buffer.length - offset) {

            throw new IndexOutOfBoundsException(Msg.getString("K002f"));

        }

        if (count == 0) {

            return;

        }

        openCheck();

        fileSystem.write(fd.descriptor, buffer, offset, count);

}

然後呼叫到了fileSystem.writefd.descriptor中含有路徑資訊。

這個write會像一個linux中所謂的scsi裝置中寫入資料,經過一層層傳到sd的驅動層。這個sd裝置應該會在/dev目錄下有一個裝置節點,最終會通過這個裝置節點,呼叫到這個裝置的write驅動函式,實現最終的寫入動作。

當然從fileSystem這個物件的write到裝置驅動的write,中間走過了2層,一個是framework、一個是lib層。(這兩個write已經不是同一個write了,第一個writefileSystem這個物件呈現給app層的,而第二個write的功能也許沒那麼豐富,這都取決於設計者)

kernel層之上,應該能夠找到open這個裝置的地方。如open(“/dev/sd”)

六你看到題目中的USB了麼?

初衷是看看android中的usb是什麼樣子的,但是都快講完了usb也沒有出現。通過上面的sd的檔案操作,在android的框架中看到sd卡的驅動了麼?我沒有看到,希望永遠不要看到,因為他不應該在android的框架裡出現,應該出現在kernel(linux系統)USB

sd的角色是一樣的。所以也不應該出現在android的框架中、程式碼中。

七未濟的話題

通篇都是在說android只是一個框架、如何撿了便宜,其實這是不客觀的,這麼多人將android認為是一個作業系統,是有它的道理的。Android做了很多東西,並不是簡單的一堆jar包。他在linux系統之上衍生出了一個新的準系統,實現著程式的管理、通訊、儲存等功能。如activityintentservicecontent provider等,這些工作不是一個簡單的程式所能做的,java人員享受的開發之快捷是建立在android所提供的強大功能之上,稱其為android系統並不為過。Android不僅是一個系統,也是一種新的商業模式,一種企業文化的體現。

這些理解並不一定正確,不過是一個開始,還有很多工作需要我們去做。

所以這裡一共涉及到兩個大環境:一個是我們以前的linux環境,一個是android環境。

如果我們不提供解決方案,只提供驅動,只要關注linux環境中的驅動部分就可以。如果提供解決方案,假設已經有了針對硬體的驅動(linux層的驅動),那麼還需要在lib層加入一層C++的程式碼,向上提供操作驅動層的介面。同時還要在framework層針對我們裝置的功能封裝出相應的類和接口出來,並實現該類或介面的方法,提供給app層應用。App層我們不會用到,但是需要了解或讓客戶提需求,因為只有瞭解客戶要怎麼用這個裝置,才能封裝出好的類和介面。不過android系統的東西只要會用、有個瞭解就差不多了。