Android進程與線程
當某個組件第一次運行的時候,Android啟動了一個進程。默認的,所有的組件和程序運行在這個進程和線程中。
也可以安排組件在其他的進程或者線程中運行
進程組件運行的進程由manifest file控制。組件的節(jié)點 — <activity>, <service>, <receiver>, 和 <provider> — 都包含一個 process 屬性。 這個屬性可以設置組件運行的進程:可以配置組件在一個獨立進程運行,或者多個組件在同一個進程運行。甚至可以多個程序在一個進程中運行——如果這些程序共享一個User ID并給定同樣的權(quán)限。<application> 節(jié)點也包含 process 屬性 ,用來設置程序中所有組件的默認進程。
所有的組件在此進程的主線程中實例化 ,系統(tǒng)對這些組件的調(diào)用從主線程中分離。并非每個對象都會從主線程中分離。一般來說,響應例如View.onKeyDown()用戶操作的方法和通知的方法也在主線程中運行。這就表示,組件被系統(tǒng)調(diào)用的時候不應該長時間運行或者阻塞操作(如網(wǎng)絡操作或者計算大量數(shù)據(jù)),因為這樣會阻塞進程中的其他組件 。可以把這類操作從主線程中分離。
當更加常用的進程無法獲取足夠內(nèi)存,Android可能會關閉不常用的進程。下次啟動程序的時候會重新啟動進程。
當決定哪個進程需要被關閉的時候, Android會考慮哪個對用戶更加有用。如Android會傾向于關閉一個長期不顯示在界面的進程來支持一個經(jīng)常顯示在界面的進程。是否關閉一個進程決定于組件在進程中的狀態(tài),參見后面的章節(jié)Component Lifecycles.
線程即使為組件分配了不同的進程,有時候也需要再分配線程。比如用戶界面需要很快對用戶進行響應,因此某些費時的操作,如網(wǎng)絡連接、下載或者非常占用服務器時間的操作應該放到其他線程。
線程通過java的標準對象Thread 創(chuàng)建. Android 提供了很多方便的管理線程的方法:— Looper 在線程中運行一個消息循環(huán); Handler 傳遞一個消息; HandlerThread 創(chuàng)建一個帶有消息循環(huán)的線程。
遠程調(diào)用Remote procedure callsAndroid有一個遠程調(diào)用(RPCs) 的輕量級機制— 通過這個機制,方法可以在本地調(diào)用,在遠程執(zhí)行(在其他進程執(zhí)行),還可以返回一個值。要實現(xiàn)這個需求,必須分解方法調(diào)用,并且所有要傳遞的數(shù)據(jù)必須是操作系統(tǒng)可以訪問的級別。從本地的進程和內(nèi)存地址傳送到遠程的進程和內(nèi)存地址并在遠程處理和返回。返回值必須向相反的方向傳遞。Android提供了做以上操作的代碼,所以開發(fā)者可以專注于實現(xiàn)RPC的接口。
一個RPC接口只能包含方法。所有的方法都是同步執(zhí)行的 (直到遠程方法返回,本地方法才結(jié)束阻塞),沒有返回值的時候也是如此。
簡單來說,這個機制是這樣的:使用IDL (interface definition language)定義你想要實現(xiàn)的接口, aidl 工具可以生成用于java的接口定義,本地和遠程都要使用這個定義 。它包含2個類,見下圖:
inner類包含了所有的管理遠程程序(符合IDL描述的接口)所需要的代碼。所有的inner類實現(xiàn)了IBinder 接口.其中一個在本地使用,可以不管它的代碼;另外一個叫做Stub繼承了 Binder 類。為了實現(xiàn)遠程調(diào)用,這個類包含RPC接口。開發(fā)者可以繼承Stub類來實現(xiàn)需要的方法 。
一般來說,遠程進程會被一個service管理(因為service可以通知操作系統(tǒng)這個進程的信息并和其他進程通信),它也會包含aidl 工具產(chǎn)生的接口文件,Stub類實現(xiàn)了遠處那個方法。服務的客戶端只需要aidl 工具產(chǎn)生的接口文件。
以下是如何連接服務和客戶端調(diào)用:
線程安全的方法在某些情況下,方法可能調(diào)用不止一個的線程,因此需要注意方法的線程安全。
對于可以遠程調(diào)用的方法,也要注意這點。當一個調(diào)用在Ibinder對象中的方法的程序啟動了和Ibinder對象相同的進程,方法就在 Ibinder的進程中執(zhí)行。但是,如果調(diào)用者發(fā)起另外一個進程,方法在另外一個線程中運行,這個線程在和IBinder對象在一個線程池中;它不會在進程的主線程中運行。例如,一個service從主線程被調(diào)用onBind() 方法,onBind() 返回的對象(如實現(xiàn)了RPC的Stub子類)中的方法會被從線程池中調(diào)用。因為一個服務可能有多個客戶端請求,不止一個線程池會在同一時間調(diào)用 IBinder的方法。因此IBinder必須線程安全。
簡單來說,一個content provider 可以接收其他進程的數(shù)據(jù)請求。即使ContentResolver和ContentProvider類沒有隱藏了管理交互的細節(jié),ContentProvider中響應這些請求的方法(query(), insert(), delete(), update(), and getType() )— 是在content provider的線程池中被調(diào)用的,而不是ContentProvider的本身進程。因為這些方法可能是同時從很多線程池運行的,所以這些方法必須要線程安全。
也可以安排組件在其他的進程或者線程中運行
進程組件運行的進程由manifest file控制。組件的節(jié)點 — <activity>, <service>, <receiver>, 和 <provider> — 都包含一個 process 屬性。 這個屬性可以設置組件運行的進程:可以配置組件在一個獨立進程運行,或者多個組件在同一個進程運行。甚至可以多個程序在一個進程中運行——如果這些程序共享一個User ID并給定同樣的權(quán)限。<application> 節(jié)點也包含 process 屬性 ,用來設置程序中所有組件的默認進程。
所有的組件在此進程的主線程中實例化 ,系統(tǒng)對這些組件的調(diào)用從主線程中分離。并非每個對象都會從主線程中分離。一般來說,響應例如View.onKeyDown()用戶操作的方法和通知的方法也在主線程中運行。這就表示,組件被系統(tǒng)調(diào)用的時候不應該長時間運行或者阻塞操作(如網(wǎng)絡操作或者計算大量數(shù)據(jù)),因為這樣會阻塞進程中的其他組件 。可以把這類操作從主線程中分離。
當更加常用的進程無法獲取足夠內(nèi)存,Android可能會關閉不常用的進程。下次啟動程序的時候會重新啟動進程。
當決定哪個進程需要被關閉的時候, Android會考慮哪個對用戶更加有用。如Android會傾向于關閉一個長期不顯示在界面的進程來支持一個經(jīng)常顯示在界面的進程。是否關閉一個進程決定于組件在進程中的狀態(tài),參見后面的章節(jié)Component Lifecycles.
線程即使為組件分配了不同的進程,有時候也需要再分配線程。比如用戶界面需要很快對用戶進行響應,因此某些費時的操作,如網(wǎng)絡連接、下載或者非常占用服務器時間的操作應該放到其他線程。
線程通過java的標準對象Thread 創(chuàng)建. Android 提供了很多方便的管理線程的方法:— Looper 在線程中運行一個消息循環(huán); Handler 傳遞一個消息; HandlerThread 創(chuàng)建一個帶有消息循環(huán)的線程。
遠程調(diào)用Remote procedure callsAndroid有一個遠程調(diào)用(RPCs) 的輕量級機制— 通過這個機制,方法可以在本地調(diào)用,在遠程執(zhí)行(在其他進程執(zhí)行),還可以返回一個值。要實現(xiàn)這個需求,必須分解方法調(diào)用,并且所有要傳遞的數(shù)據(jù)必須是操作系統(tǒng)可以訪問的級別。從本地的進程和內(nèi)存地址傳送到遠程的進程和內(nèi)存地址并在遠程處理和返回。返回值必須向相反的方向傳遞。Android提供了做以上操作的代碼,所以開發(fā)者可以專注于實現(xiàn)RPC的接口。
一個RPC接口只能包含方法。所有的方法都是同步執(zhí)行的 (直到遠程方法返回,本地方法才結(jié)束阻塞),沒有返回值的時候也是如此。
簡單來說,這個機制是這樣的:使用IDL (interface definition language)定義你想要實現(xiàn)的接口, aidl 工具可以生成用于java的接口定義,本地和遠程都要使用這個定義 。它包含2個類,見下圖:

inner類包含了所有的管理遠程程序(符合IDL描述的接口)所需要的代碼。所有的inner類實現(xiàn)了IBinder 接口.其中一個在本地使用,可以不管它的代碼;另外一個叫做Stub繼承了 Binder 類。為了實現(xiàn)遠程調(diào)用,這個類包含RPC接口。開發(fā)者可以繼承Stub類來實現(xiàn)需要的方法 。
一般來說,遠程進程會被一個service管理(因為service可以通知操作系統(tǒng)這個進程的信息并和其他進程通信),它也會包含aidl 工具產(chǎn)生的接口文件,Stub類實現(xiàn)了遠處那個方法。服務的客戶端只需要aidl 工具產(chǎn)生的接口文件。
以下是如何連接服務和客戶端調(diào)用:
- ·服務的客戶端(本地)會實現(xiàn)onServiceConnected() 和onServiceDisconnected() 方法,這樣,當客戶端連接或者斷開連接的時候可以獲取到通知。通過 bindService() 獲取到服務的連接。
- · 服務的 onBind() 方法中可以接收或者拒絕連接,取決它收到的intent (intent通過 bindService()方法連接到服務). 如果服務接收了連接,會返回一個Stub類的實例.
- · 如果服務接受了連接,Android會調(diào)用客戶端的onServiceConnected() 方法,并傳遞一個Ibinder對象(系統(tǒng)管理的Stub類的代理),通過這個代理,客戶端可以連接遠程的服務。
線程安全的方法在某些情況下,方法可能調(diào)用不止一個的線程,因此需要注意方法的線程安全。
對于可以遠程調(diào)用的方法,也要注意這點。當一個調(diào)用在Ibinder對象中的方法的程序啟動了和Ibinder對象相同的進程,方法就在 Ibinder的進程中執(zhí)行。但是,如果調(diào)用者發(fā)起另外一個進程,方法在另外一個線程中運行,這個線程在和IBinder對象在一個線程池中;它不會在進程的主線程中運行。例如,一個service從主線程被調(diào)用onBind() 方法,onBind() 返回的對象(如實現(xiàn)了RPC的Stub子類)中的方法會被從線程池中調(diào)用。因為一個服務可能有多個客戶端請求,不止一個線程池會在同一時間調(diào)用 IBinder的方法。因此IBinder必須線程安全。
簡單來說,一個content provider 可以接收其他進程的數(shù)據(jù)請求。即使ContentResolver和ContentProvider類沒有隱藏了管理交互的細節(jié),ContentProvider中響應這些請求的方法(query(), insert(), delete(), update(), and getType() )— 是在content provider的線程池中被調(diào)用的,而不是ContentProvider的本身進程。因為這些方法可能是同時從很多線程池運行的,所以這些方法必須要線程安全。
Android移植: wifi設計原理(源碼分析)
開機啟動service,適合鬧鐘程序
Android多媒體框架分析
Android的Media Framework 處于Libraries這一層,這層的Library不是用Java實現(xiàn),一般是C/C++實現(xiàn),它們通過Java的JNI方式調(diào)用。 多媒體架構(gòu):基于第三方PacketVideo公司的OpenCORE platform 來實現(xiàn),支持所有通用的音頻,視頻,靜態(tài)圖像格式。CODEC( 編解碼器 ) 使用 OpenMAX 1L interface 接口進行擴展,可以方便的支持hardware / software codec plug-ins。支持的格式包括: MPEG4 、H.264 、MP3 、AAC 、AMR 、JPG 、PNG 、GIF 等。 在實際開發(fā)中我們并不會過多的研究Open Core 的實現(xiàn),Android 提供了上層的Media API 給開發(fā)人員使用,分別是MediaPlayer 和MediaRecorder。 (1)The Android platform is capable of playing both audio and video media. It is also capable of playing media contained in the resources for an application, or a standalone file in the filesystem, or even streaming media over a data connection. Playback is achieved through the android.media.MediaPlayer class. (2)The Android platform can also record audio. Video recording capabilities are coming in the future. This is achieved through the android.media.MediaRecorder class. 分述: Media Player 提供的基本接口如下: Public Methods (1)static MediaPlayer create (Context context, Uri uri) Convenience method to create a MediaPlayer for a given Uri. (2)int getCurrentPosition () Gets the current playback position. (3)int getDuration () Gets the duration of the file. (4)int getVideoHeight () Returns the height of the video. (5)int getVideoWidth () Returns the width of the video. (6)boolean isPlaying () Checks whether the MediaPlayer is playing. (7)void pause () Pauses playback. (8)void prepare () Prepares the player for playback, synchronously. (9)void prepareAsync () Prepares the player for playback, asynchronously. (10)void release () Releases resources associated with this MediaPlayer object. (11)void reset () Resets the MediaPlayer to its uninitialized state. (12)void seekTo (int msec) Seeks to specified time position. (13) void setAudioStreamType (int streamtype) Sets the audio stream type for this MediaPlayer. (14)void setDataSource (String path) Sets the data source (file-path or http/rtsp URL) to use. (15)void setDisplay (SurfaceHolder sh) Sets the SurfaceHolder to use for displaying the video portion of the media. (16)void setVolume (float leftVolume, float rightVolume) Sets the volume on this player. (17)void start () Starts or resumes playback. (18)void stop () Stops playback after playback has been stopped or paused. 我們可以看出 MediaPlayer 類提供了一個多媒體播放器的基本操作,播放,暫停,停止,設置音量等等。 簡單的例子: Playing a File:
Playing a Raw Resource: MediaPlayer mp = MediaPlayer.create(context, R.raw.sound_file_1); mp.start(); 另Media Recorder 提供的基本接口如下: Public Method: (1)void prepare () Prepares the recorder to begin capturing and encoding data. (2)void release () Releases resources associated with this MediaRecorder object. (3)void reset () Restarts the MediaRecorder to its idle state. (4)void setAudioEncoder (int audio_encoder) Sets the audio encoder to be used for recording. (5)void setAudioSource (int audio_source) Sets the audio source to be used for recording. (6)void setOutputFile (String path) Sets the path of the output file to be produced. (7)void setOutputFormat (int output_format) Sets the format of the output file produced during recording. (8)void setPreviewDisplay (Surface sv) Sets a Surface to show a preview of recorded media (video). (9)void start () Begins capturing and encoding data to the file specified with setOutputFile(). (10)void stop () Stops recording. 簡單的例子: Example: MediaRecorder recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); recorder.setOutputFile(PATH_NAME); recorder.prepare(); recorder.start(); // Recording is now started ... recorder.stop(); recorder.reset(); // You can reuse the object by going back to setAudioSource() step recorder.release(); // Now the object cannot be reused 整體結(jié)構(gòu)的核心文件的位置如下: A,MediaPlayer JNI 代碼位置 /frameworks/base/media/jni B, MediaPlayer (Native) 代碼位置 /frameworks/base/media/libmedia C, MediaPlayerService (Server) 代碼位置 /frameworks/base/media/libmediaplayerservice D, MediaPlayerService Host Process 代碼位置 /frameworks/base/media/mediaserver/main_mediaserver.cpp E, PVPlayer 代碼位置 /external/opencore/android/ |
Android專用驅(qū)動和Binder
Android中有些驅(qū)動程序提供輔助操作系統(tǒng)的功能,這些驅(qū)動程序不是linux的標準驅(qū)動,它們一般并不操作實際的硬件,只是輔助系統(tǒng)的運行。主要要以下幾種:
Ashmem:匿名共享內(nèi)存驅(qū)動
Logger:輕量級的Log驅(qū)動
Binder:基于OpenBinder系統(tǒng)的驅(qū)動,為Android平臺提供IPC支持。
Android Power Management:電源管理模塊
Low Memory Killer:在缺少內(nèi)存的情況下殺死進程
Android PMEM:物理內(nèi)存驅(qū)動 Binder:Android的Binder驅(qū)動程序為用戶層提供了IPC支持,Android的運行整個依賴Binder驅(qū)動。Binder設備節(jié)點名稱:/dev/binder。用ls -l /dev/binder可查看設備屬性。主設備號為10(misc driver),次設備號動態(tài)生成。
Binder驅(qū)動程序在內(nèi)核的路徑如下:
\android_kernel_f301\include\linux\binder.h
\android_kernel_f301\drivers\misc\binder.c
Binder在Android用戶空間的調(diào)用主要表現(xiàn)在對libutil工具庫和service manager守護進程的支持。
\frameworks\base\cmds\servicemanager\Binder.c
\frameworks\base\cmds\servicemanager\Binder.h
\frameworks\base\libs\utils\Binder.cpp
\frameworks\base\libs\utils\Binder.h
Binder是Android中主要的使用的IPC方式,通常只需要按照模板定義相關的類即可,不需要直接調(diào)用Binder驅(qū)動程序的設備節(jié)點。
Ashmem:匿名共享內(nèi)存驅(qū)動
Logger:輕量級的Log驅(qū)動
Binder:基于OpenBinder系統(tǒng)的驅(qū)動,為Android平臺提供IPC支持。
Android Power Management:電源管理模塊
Low Memory Killer:在缺少內(nèi)存的情況下殺死進程
Android PMEM:物理內(nèi)存驅(qū)動 Binder:Android的Binder驅(qū)動程序為用戶層提供了IPC支持,Android的運行整個依賴Binder驅(qū)動。Binder設備節(jié)點名稱:/dev/binder。用ls -l /dev/binder可查看設備屬性。主設備號為10(misc driver),次設備號動態(tài)生成。
Binder驅(qū)動程序在內(nèi)核的路徑如下:
\android_kernel_f301\include\linux\binder.h
\android_kernel_f301\drivers\misc\binder.c
Binder在Android用戶空間的調(diào)用主要表現(xiàn)在對libutil工具庫和service manager守護進程的支持。
\frameworks\base\cmds\servicemanager\Binder.c
\frameworks\base\cmds\servicemanager\Binder.h
\frameworks\base\libs\utils\Binder.cpp
\frameworks\base\libs\utils\Binder.h
Binder是Android中主要的使用的IPC方式,通常只需要按照模板定義相關的類即可,不需要直接調(diào)用Binder驅(qū)動程序的設備節(jié)點。
Android.mk的用法和基礎
一個Android.mk file用來向編譯系統(tǒng)描述你的源代碼。具體來說:該文件是GNU Makefile的一小部分,會被編譯系統(tǒng)解析一次或多次。你可以在每一個Android.mk file中定義一個或多個模塊,你也可以在幾個模塊中使用同一個源代碼文件。編譯系統(tǒng)為你處理許多細節(jié)問題。例如,你不需要在你的Android.mk中列出頭文件和依賴文件。NDK編譯系統(tǒng)將會為你自動處理這些問題。這也意味著,在升級NDK后,你應該得到新的toolchain/platform支持,而且不需要改變你的Android.mk文件。 先看一個簡單的例子:一個簡單的"hello world",比如下面的文件: sources/helloworld/helloworld.c sources/helloworld/Android.mk 相應的Android.mk文件會象下面這樣: ---------- cut here ------------------ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := helloworld LOCAL_SRC_FILES := helloworld.c include $(BUILD_SHARED_LIBRARY) ---------- cut here ------------------ 我們來解釋一下這幾行代碼: LOCAL_PATH := $(call my-dir) 一個Android.mk file首先必須定義好LOCAL_PATH變量。它用于在開發(fā)樹中查找源文件。在這個例子中,宏函數(shù)’my-dir’, 由編譯系統(tǒng)提供,用于返回當前路徑(即包含Android.mk file文件的目錄)。 include $( CLEAR_VARS) CLEAR_VARS由編譯系統(tǒng)提供,指定讓GNU MAKEFILE為你清除許多LOCAL_XXX變量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。這是必要的,因為所有的編譯控制文件都在同一個GNU MAKE執(zhí)行環(huán)境中,所有的變量都是全局的。 LOCAL_MODULE := helloworld LOCAL_MODULE變量必須定義,以標識你在Android.mk文件中描述的每個模塊。名稱必須是唯一的,而且不包含任何空格。注意編譯系統(tǒng)會自動產(chǎn)生合適的前綴和后綴,換句話說,一個被命名為'foo'的共享庫模塊,將會生成'libfoo.so'文件。 LOCAL_SRC_FILES := helloworld.c LOCAL_SRC_FILES變量必須包含將要編譯打包進模塊中的C或C++源代碼文件。注意,你不用在這里列出頭文件和包含文件,因為編譯系統(tǒng)將會自動為你找出依賴型的文件;僅僅列出直接傳遞給編譯器的源代碼文件就好。 在Android中增加本地程序或者庫,這些程序和庫與其所載路徑?jīng)]有任何關系,只和它們的Android.mk文件有關系。Android.mk和普通的Makefile有所不同,它具有統(tǒng)一的寫法,主要包含一些系統(tǒng)公共的宏。 在一個Android.mk中可以生成多個可執(zhí)行程序、動態(tài)庫和靜態(tài)庫。 1,編譯應用程序的模板: #Test Exe LOCAL_PATH := $(call my-dir) #include $(CLEAR_VARS) LOCAL_SRC_FILES:= main.c LOCAL_MODULE:= test_exe #LOCAL_C_INCLUDES := #LOCAL_STATIC_LIBRARIES := #LOCAL_SHARED_LIBRARIES := include $(BUILD_EXECUTABLE) (菜鳥級別解釋::=是賦值的意思,$是引用某變量的值)LOCAL_SRC_FILES中加入源文件路徑,LOCAL_C_INCLUDES 中加入所需要包含的頭文件路徑,LOCAL_STATIC_LIBRARIES加入所需要鏈接的靜態(tài)庫(*.a)的名稱,LOCAL_SHARED_LIBRARIES中加入所需要鏈接的動態(tài)庫(*.so)的名稱,LOCAL_MODULE表示模塊最終的名稱,BUILD_EXECUTABLE表示以一個可執(zhí)行程序的方式進行編譯。 2,編譯靜態(tài)庫的模板: #Test Static Lib LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ helloworld.c LOCAL_MODULE:= libtest_static #LOCAL_C_INCLUDES := #LOCAL_STATIC_LIBRARIES := #LOCAL_SHARED_LIBRARIES := include $(BUILD_STATIC_LIBRARY) 一般的和上面相似,BUILD_STATIC_LIBRARY表示編譯一個靜態(tài)庫。 3,編譯動態(tài)庫的模板: #Test Shared Lib LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ helloworld.c LOCAL_MODULE:= libtest_shared TARGET_PRELINK_MODULES := false #LOCAL_C_INCLUDES := #LOCAL_STATIC_LIBRARIES := #LOCAL_SHARED_LIBRARIES := include $(BUILD_SHARED_LIBRARY) 一般的和上面相似,BUILD_SHARED_LIBRARY表示編譯一個靜態(tài)庫。 以上三者的生成結(jié)果分別在如下,generic依具體target會變: out/target/product/generic/obj/EXECUTABLE out/target/product/generic/obj/STATIC_LIBRARY out/target/product/generic/obj/SHARED_LIBRARY 每個模塊的目標文件夾分別為: 可執(zhí)行程序:XXX_intermediates 靜態(tài)庫: XXX_static_intermediates 動態(tài)庫: XXX_shared_intermediates 另外,在Android.mk文件中,還可以指定最后的目標安裝路徑,用LOCAL_MODULE_PATH和LOCAL_UNSTRIPPED_PATH來指定。不同的文件系統(tǒng)路徑用以下的宏進行選擇: TARGET_ROOT_OUT:表示根文件系統(tǒng)。 TARGET_OUT:表示system文件系統(tǒng)。 TARGET_OUT_DATA:表示data文件系統(tǒng)。 用法如: CAL_MODULE_PATH:=$(TARGET_ROOT_OUT) |