<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 189,comments - 115,trackbacks - 0

    Android進程與線程

    當(dāng)某個組件第一次運行的時候,Android啟動了一個進程。默認的,所有的組件和程序運行在這個進程和線程中。 
    也可以安排組件在其他的進程或者線程中運行 
    進程組件運行的進程由manifest file控制。組件的節(jié)點 — <activity>, <service>, <receiver>, 和 <provider> — 都包含一個 process 屬性。 這個屬性可以設(shè)置組件運行的進程:可以配置組件在一個獨立進程運行,或者多個組件在同一個進程運行。甚至可以多個程序在一個進程中運行——如果這些程序共享一個User ID并給定同樣的權(quán)限。<application> 節(jié)點也包含 process 屬性 ,用來設(shè)置程序中所有組件的默認進程。 
    所有的組件在此進程的主線程中實例 ,系統(tǒng)對這些組件的調(diào)用從主線程中分離。并非每個對象都會從主線程中分離。一般來說,響應(yīng)例如View.onKeyDown()用戶操作的方法和通知的方法也在主線程中運行。這就表示,組件被系統(tǒng)調(diào)用的時候不應(yīng)該長時間運行或者阻塞操作(如網(wǎng)絡(luò)操作或者計算大量數(shù)據(jù)),因為這樣會阻塞進程中的其他組件 。可以把這類操作從主線程中分離。 
    當(dāng)更加常用的進程無法獲取足夠內(nèi)存,Android可能會關(guān)閉不常用的進程。下次啟動程序的時候會重新啟動進程。 
    當(dāng)決定哪個進程需要被關(guān)閉的時候, Android會考慮哪個對用戶更加有用。如Android會傾向于關(guān)閉一個長期不顯示在界面的進程來支持一個經(jīng)常顯示在界面的進程。是否關(guān)閉一個進程決定于組件在進程中的狀態(tài),參見后面的章節(jié)Component Lifecycles. 
    線程即使為組件分配了不同的進程,有時候也需要再分配線程。比如用戶界面需要很快對用戶進行響應(yīng),因此某些費時的操作,如網(wǎng)絡(luò)連接、下載或者非常占用服務(wù)器時間的操作應(yī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)了遠處那個方法。服務(wù)的客戶端只需要aidl 工具產(chǎn)生的接口文件。 
    以下是如何連接服務(wù)和客戶端調(diào)用: 
    • ·服務(wù)的客戶端(本地)會實現(xiàn)onServiceConnected() 和onServiceDisconnected() 方法,這樣,當(dāng)客戶端連接或者斷開連接的時候可以獲取到通知。通過 bindService() 獲取到服務(wù)的連接。
    • · 服務(wù)的 onBind() 方法中可以接收或者拒絕連接,取決它收到的intent (intent通過 bindService()方法連接到服務(wù)). 如果服務(wù)接收了連接,會返回一個Stub類的實例.
    • · 如果服務(wù)接受了連接,Android會調(diào)用客戶端的onServiceConnected() 方法,并傳遞一個Ibinder對象(系統(tǒng)管理的Stub類的代理),通過這個代理,客戶端可以連接遠程的服務(wù)。
    以上的描述省略很多RPC的機制。請參見Designing a Remote Interface Using AIDL 和 IBinder 類。 
    線程安全的方法在某些情況下,方法可能調(diào)用不止一個的線程,因此需要注意方法的線程安全。 
    對于可以遠程調(diào)用的方法,也要注意這點。當(dāng)一個調(diào)用在Ibinder對象中的方法的程序啟動了和Ibinder對象相同的進程,方法就在 Ibinder的進程中執(zhí)行。但是,如果調(diào)用者發(fā)起另外一個進程,方法在另外一個線程中運行,這個線程在和IBinder對象在一個線程池中;它不會在進程的主線程中運行。例如,一個service從主線程被調(diào)用onBind() 方法,onBind() 返回的對象(如實現(xiàn)了RPC的Stub子類)中的方法會被從線程池中調(diào)用。因為一個服務(wù)可能有多個客戶端請求,不止一個線程池會在同一時間調(diào)用 IBinder的方法。因此IBinder必須線程安全。 
    簡單來說,一個content provider 可以接收其他進程的數(shù)據(jù)請求。即使ContentResolver和ContentProvider類沒有隱藏了管理交互的細節(jié),ContentProvider中響應(yīng)這些請求的方法(query(), insert(), delete(), update(), and getType() )— 是在content provider的線程池中被調(diào)用的,而不是ContentProvider的本身進程。因為這些方法可能是同時從很多線程池運行的,所以這些方法必須要線程安全。

    Android移植: wifi設(shè)計原理(源碼分析)

    Android移植: wifi設(shè)計原理(源碼分析)

    相關(guān)搜索: Androidwifi源碼原理移植
    android_wifi.png 
    初始化
    在 SystemServer 啟動的時候,會生成一個 ConnectivityService 的實例,
                  try {
                        Log.i(TAG, "Starting Connectivity Service.");
                        ServiceManager.addService(Context.CONNECTIVITY_SERVICE, new
    ConnectivityService(context));
                  } catch (Throwable e) {
                        Log.e(TAG, "Failure starting Connectivity Service", e);
                  }
    ConnectivityService 的構(gòu)造函數(shù)會創(chuàng)建 WifiService,
              if (DBG) Log.v(TAG, "Starting Wifi Service.");
              mWifiStateTracker = new WifiStateTracker(context, handler);
              WifiService wifiService = new WifiService(context, mWifiStateTracker);
              ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
    WifiStateTracker 會創(chuàng)建 WifiMonitor 接收來自底層的事件,WifiService 和 WifiMonitor 是整
    個模塊的核心。WifiService 負責(zé)啟動關(guān)閉 wpa_supplicant、啟動關(guān)閉 WifiMonitor 監(jiān)視線程
    和把命令下發(fā)給 wpa_supplicant,而 WifiMonitor 則負責(zé)從 wpa_supplicant 接收事件通知。
    連接 AP
    1. 使能 WIFI
    WirelessSettings 在初始化的時候配置了由 WifiEnabler 來處理 Wifi 按鈕,
         private void initToggles() {
              mWifiEnabler = new WifiEnabler(
                           this,
                           (WifiManager) getSystemService(WIFI_SERVICE),
                           (CheckBoxPreference) findPreference(KEY_TOGGLE_WIFI));
    當(dāng)用戶按下 Wifi 按鈕后,               Android 會調(diào)用 WifiEnabler 的 onPreferenceChange,    再由 WifiEnabler
    調(diào)用 WifiManager 的 setWifiEnabled 接口函數(shù),通過 AIDL,實際調(diào)用的是 WifiService 的
    setWifiEnabled 函數(shù),WifiService 接著向自身發(fā)送一條 MESSAGE_ENABLE_WIFI 消息,在
    處理該消息的代碼中做真正的使能工作:首先裝載 WIFI 內(nèi)核模塊(該模塊的位置硬編碼為
    "/system/lib/modules/wlan.ko" ), 然 后 啟 動 wpa_supplicant ( 配 置 文 件 硬 編 碼 為
    "/data/misc/wifi/wpa_supplicant.conf") 再通過 WifiStateTracker 來啟動 WifiMonitor 中的監(jiān)視
                                               ,
    線程。
         private boolean setWifiEnabledBlocking(boolean enable) {
              final      int     eventualWifiState   =     enable    ?   WIFI_STATE_ENABLED     :
    WIFI_STATE_DISABLED;
              updateWifiState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING);
              if (enable) {
                    if (!WifiNative.loadDriver()) {
                           Log.e(TAG, "Failed to load Wi-Fi driver.");
                           updateWifiState(WIFI_STATE_UNKNOWN);
                           return false;
                    }
                    if (!WifiNative.startSupplicant()) {
                           WifiNative.unloadDriver();
                           Log.e(TAG, "Failed to start supplicant daemon.");
                           updateWifiState(WIFI_STATE_UNKNOWN);
                           return false;
                    }
                    mWifiStateTracker.startEventLoop();
              }
                 // Success!
                 persistWifiEnabled(enable);
                 updateWifiState(eventualWifiState);
                 return true;
          }
    當(dāng)使能成功后,會廣播發(fā)送 WIFI_STATE_CHANGED_ACTION 這個 Intent 通知外界 WIFI
    已 經(jīng) 成 功 使 能 了 。 WifiEnabler 創(chuàng) 建 的 時 候 就 會 向 Android 注 冊 接 收
    WIFI_STATE_CHANGED_ACTION,因此它會收到該 Intent,從而開始掃描。
              private void handleWifiStateChanged(int wifiState) {
                 if (wifiState == WIFI_STATE_ENABLED) {
                      loadConfiguredAccessPoints();
                      attemptScan();
                 }
    2. 查找 AP
    掃描的入口函數(shù)是 WifiService 的 startScan,它其實也就是往 wpa_supplicant 發(fā)送 SCAN 命
    令。
    static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz)
    {
          jboolean result;
          // Ignore any error from setting the scan mode.
          // The scan will still work.
          (void)doBooleanCommand("DRIVER SCAN-ACTIVE", "OK");
          result = doBooleanCommand("SCAN", "OK");
          (void)doBooleanCommand("DRIVER SCAN-PASSIVE", "OK");
          return result;
    }
    當(dāng) wpa_supplicant 處理完 SCAN 命令后,它會向控制通道發(fā)送事件通知掃描完成,從而
    wifi_wait_for_event 函數(shù)會接收到該事件,由此 WifiMonitor 中的 MonitorThread 會被執(zhí)行來
    出來這個事件,
                 void handleEvent(int event, String remainder) {
                            case SCAN_RESULTS:
                                 mWifiStateTracker.notifyScanResultsAvailable();
                                 break;
    WifiStateTracker 則接著廣播發(fā)送 SCAN_RESULTS_AVAILABLE_ACTION 這個 Intent
                      case EVENT_SCAN_RESULTS_AVAILABLE:
                            mContext.sendBroadcast(new
    Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
    WifiLayer 注冊了接收 SCAN_RESULTS_AVAILABLE_ACTION 這個 Intent,所以它的相關(guān)
    處理函數(shù) handleScanResultsAvailable 會被調(diào)用,在該函數(shù)中,先會去拿到 SCAN 的結(jié)果(最
    終是往 wpa_supplicant 發(fā)送 SCAN_RESULT 命令并讀取返回值來實現(xiàn)的)                             ,
                    List<ScanResult> list = mWifiManager.getScanResults();
    對每一個掃描返回的 AP,WifiLayer 會調(diào)用 WifiSettings 的 onAccessPointSetChanged 函數(shù),
    從而最終把該 AP 加到 GUI 顯示列表中。
         public void onAccessPointSetChanged(AccessPointState ap, boolean added) {
              AccessPointPreference pref = mAps.get(ap);
              if (added) {
                    if (pref == null) {
                          pref = new AccessPointPreference(this, ap);
                          mAps.put(ap, pref);
                    } else {
                          pref.setEnabled(true);
                    }
                    mApCategory.addPreference(pref);
              }
         }
    3. 配置 AP 參數(shù)
    當(dāng)用戶在 WifiSettings 界面上選擇了一個 AP 后,會顯示配置 AP 參數(shù)的一個對話框,
         public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference
    preference) {
              if (preference instanceof AccessPointPreference) {
                    AccessPointState             state           =         ((AccessPointPreference)
    preference).getAccessPointState();
                    showAccessPointDialog(state, AccessPointDialog.MODE_INFO);
              }
         }
    4. 連接
    當(dāng)用戶在 AcessPointDialog 中選擇好加密方式和輸入密鑰之后,再點擊連接按鈕,Android
    就會去連接這個 AP。
         private void handleConnect() {
              String password = getEnteredPassword();
              if (!TextUtils.isEmpty(password)) {
                    mState.setPassword(password);
              }
              mWifiLayer.connectToNetwork(mState);
         }
    WifiLayer 會先檢測這個 AP 是不是之前被配置過,這個是通過向 wpa_supplicant 發(fā)送
    LIST_NETWORK 命令并且比較返回值來實現(xiàn)的,
              // Need WifiConfiguration for the AP
              WifiConfiguration config = findConfiguredNetwork(state);
    如果 wpa_supplicant 沒有這個 AP 的配置信息,                     則會向 wpa_supplicant 發(fā)送 ADD_NETWORK
    命令來添加該 AP,
              if (config == null) {
                    // Connecting for the first time, need to create it
                    config                             =                     addConfiguration(state,
    ADD_CONFIGURATION_ENABLE|ADD_CONFIGURATION_SAVE);
              }
    ADD_NETWORK 命 令 會 返 回 一 個 ID , WifiLayer 再 用 這 個 返 回 的 ID 作 為 參 數(shù) 向
    wpa_supplicant 發(fā)送 ENABLE_NETWORK 命令,從而讓 wpa_supplicant 去連接該 AP。
              // Make sure that network is enabled, and disable others
              mReenableApsOnNetworkStateChange = true;
              if (!mWifiManager.enableNetwork(state.networkId, true)) {
                    Log.e(TAG, "Could not enable network ID " + state.networkId);
                    error(R.string.error_connecting);
                    return false;
              }
    5. 配置 IP 地址
    當(dāng) wpa_supplicant 成功連接上 AP 之后,它會向控制通道發(fā)送事件通知連接上 AP 了,從而
    wifi_wait_for_event 函數(shù)會接收到該事件,由此 WifiMonitor 中的 MonitorThread 會被執(zhí)行來
    出來這個事件,
              void handleEvent(int event, String remainder) {
                         case CONNECTED:
                               handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,
    remainder);
                               break;
    WifiMonitor 再調(diào)用 WifiStateTracker 的 notifyStateChange,WifiStateTracker 則接著會往自身
    發(fā)送 EVENT_DHCP_START 消息來啟動 DHCP 去獲取 IP 地址,
         private void handleConnectedState() {
              setPollTimer();
              mLastSignalLevel = -1;
              if (!mHaveIPAddress & !mObtainingIPAddress) {
                    mObtainingIPAddress = true;
                    mDhcpTarget.obtainMessage(EVENT_DHCP_START).sendToTarget();
              }
         }
    然后再廣播發(fā)送 NETWORK_STATE_CHANGED_ACTION 這個 Intent
                    case EVENT_NETWORK_STATE_CHANGED:
                         if (result.state != DetailedState.DISCONNECTED || !mDisconnectPending) {
                               intent                                 =                        new
    Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
                               intent.putExtra(WifiManager.EXTRA_NETWORK_INFO,
    mNetworkInfo);
                              if (result.BSSID != null)
                                    intent.putExtra(WifiManager.EXTRA_BSSID, result.BSSID);
                              mContext.sendStickyBroadcast(intent);
                         }
                         break;
    WifiLayer 注冊了接收 NETWORK_STATE_CHANGED_ACTION 這個 Intent,所以它的相關(guān)
    處理函數(shù) handleNetworkStateChanged 會被調(diào)用,
    當(dāng) DHCP 拿到 IP 地址之后,會再發(fā)送 EVENT_DHCP_SUCCEEDED 消息,
         private class DhcpHandler extends Handler {
              public void handleMessage(Message msg) {
                    switch (msg.what) {
                         case EVENT_DHCP_START:
                              if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {
                                    event = EVENT_DHCP_SUCCEEDED;
                                                          }
    WifiLayer 處 理 EVENT_DHCP_SUCCEEDED 消 息 , 會 再 次 廣 播 發(fā) 送
    NETWORK_STATE_CHANGED_ACTION 這個 Intent,這次帶上完整的 IP 地址信息。
                    case EVENT_DHCP_SUCCEEDED:
                         mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);
                         setDetailedState(DetailedState.CONNECTED);
                         intent                                 =                           new
    Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
                         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
                         mContext.sendStickyBroadcast(intent);
                         break;
    至此為止,整個連接過程完成。
    問題:
         目前的實現(xiàn)不支持 Ad-hoc 方式。

    開機啟動service,適合鬧鐘程序

    Android多媒體框架分析

    Android的Media Framework 處于Libraries這一層,這層的Library不是用Java實現(xiàn),一般是C/C++實現(xiàn),它們通過JavaJNI方式調(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 類提供了一個多媒體播放器的基本操作,播放,暫停,停止,設(shè)置音量等等。 
          簡單的例子: 

    Playing a File:


    MediaPlayer mp = new MediaPlayer();


    mp.setDataSource(PATH_TO_FILE);


    mp.prepare();


    mp.start();

    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設(shè)備節(jié)點名稱:/dev/binder。用ls -l /dev/binder可查看設(shè)備屬性。主設(shè)備號為10(misc driver),次設(shè)備號動態(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方式,通常只需要按照模板定義相關(guān)的類即可,不需要直接調(diào)用Binder驅(qū)動程序的設(shè)備節(jié)點。

    Android.mk的用法和基礎(chǔ)

    一個Android.mk file用來向編譯系統(tǒng)描述你的源代碼。具體來說:該文件是GNU Makefile的一小部分,會被編譯系統(tǒng)解析一次或多次。你可以在每一個Android.mk file中定義一個或多個模塊,你也可以在幾個模塊中使用同一個源代碼文件。編譯系統(tǒng)為你處理許多細節(jié)問題。例如,你不需要在你的Android.mk中列出頭文件和依賴文件。NDK編譯系統(tǒng)將會為你自動處理這些問題。這也意味著,在升級NDK后,你應(yīng)該得到新的toolchain/platform支持,而且不需要改變你的Android.mk文件。
          先看一個簡單的例子:一個簡單的"hello world",比如下面的文件:
    sources/helloworld/helloworld.c 
    sources/helloworld/Android.mk
    相應(yīng)的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)提供,用于返回當(dā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)]有任何關(guān)系,只和它們的Android.mk文件有關(guān)系。Android.mk和普通的Makefile有所不同,它具有統(tǒng)一的寫法,主要包含一些系統(tǒng)公共的宏。
         在一個Android.mk中可以生成多個可執(zhí)行程序、動態(tài)庫和靜態(tài)庫。
    1,編譯應(yīng)用程序的模板:
         #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)
    posted on 2010-08-30 14:02 MEYE 閱讀(1672) 評論(0)  編輯  收藏 所屬分類: Android3D
    主站蜘蛛池模板: 亚洲精品国产av成拍色拍| 亚洲成a人片毛片在线| 亚洲av福利无码无一区二区| 亚洲av鲁丝一区二区三区| 亚洲一级毛片免费看| 综合偷自拍亚洲乱中文字幕| 久久久久国色AV免费观看| 久久青草免费91线频观看不卡 | 亚洲永久网址在线观看| 另类图片亚洲校园小说区| 国产婷婷成人久久Av免费高清 | 国产在线观看免费视频软件| 亚洲成年人免费网站| 精品久久久久久久免费加勒比| 亚洲男人av香蕉爽爽爽爽| 久久亚洲精品中文字幕| 亚洲欧美日韩国产成人| 久久国产美女免费观看精品| 黄网站色在线视频免费观看| 一本久到久久亚洲综合| 亚洲欧洲日产国码久在线观看| 亚洲人成网亚洲欧洲无码| 久久不见久久见免费影院www日本 久久WWW免费人成—看片 | 免费人成视频在线播放| 久久伊人免费视频| 免费无码成人AV片在线在线播放| 亚洲色偷偷综合亚洲AV伊人| 亚洲综合网美国十次| 国产亚洲视频在线播放大全| 无码囯产精品一区二区免费| 日本一区二区三区日本免费| 亚洲成AV人片在线观看无| 亚洲欧美精品午睡沙发| 永久免费av无码入口国语片| 黄网址在线永久免费观看 | 一区二区三区福利视频免费观看| 国产精品免费小视频| 亚洲视频在线观看| 一个人看的www免费在线视频| 无码国产精品一区二区免费虚拟VR| 亚洲毛片不卡av在线播放一区|