http://tech.sina.com.cn/s/2010-01-14/19281215405.shtml
開機過程中無線模組的初始化過程;如果sim卡鎖開啟,或者pin被鎖住的時候,會要求輸入pin或者puk,但是這個解鎖動作必須在系統初始化完成以後才能進行。(圖形系統都還沒有初始化怎麼輸入密碼阿?)當系統初始化完成以後會調用 wm.systemReady()來通知大家。這時候該做什麼就做什麼。
開機過程中無線模組的初始化過程:
rild 調用參考實現 Reference-ril.c (hardware\ril\reference-ril) 中的函數:
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
static void *mainLoop(void *param)
ret = at_open(fd, onUnsolicited);
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
在 initializeCallback 函數中對貓進行了初始化。
static void initializeCallback(void *param)
{
ATResponse *p_response = NULL;
int err;
setRadioState (RADIO_STATE_OFF);
at_handshake();
/* note: we don't check errors here. Everything important will
be handled in onATTimeout and onATReaderClosed */
/* atchannel is tolerant of echo but it must */
/* have verbose result codes */
at_send_command("ATE0Q0V1", NULL);
/* No auto-answer */
at_send_command("ATS0=0", NULL);
/* Extended errors */
at_send_command("AT+CMEE=1", NULL);
/* Network registration events */
err = at_send_command("AT+CREG=2", &p_response);
/* some handsets -- in tethered mode -- don't support CREG=2 */
if (err < 0 || p_response->success == 0) {
at_send_command("AT+CREG=1", NULL);
}
at_response_free(p_response);
/* GPRS registration events */
at_send_command("AT+CGREG=1", NULL);
/* Call Waiting notifications */
at_send_command("AT+CCWA=1", NULL);
/* Alternating voice/data off */
at_send_command("AT+CMOD=0", NULL);
/* Not muted */
at_send_command("AT+CMUT=0", NULL);
/* +CSSU unsolicited supp service notifications */
at_send_command("AT+CSSN=0,1", NULL);
/* no connected line identification */
at_send_command("AT+COLP=0", NULL);
/* HEX character set */
at_send_command("AT+CSCS=\"HEX\"", NULL);
/* USSD unsolicited */
at_send_command("AT+CUSD=1", NULL);
/* Enable +CGEV GPRS event notifications, but don't buffer */
at_send_command("AT+CGEREP=1,0", NULL);
/* SMS PDU mode */
at_send_command("AT+CMGF=0", NULL);
#ifdef USE_TI_COMMANDS
at_send_command("AT%CPI=3", NULL);
/* TI specific -- notifications when SMS is ready (currently ignored) */
at_send_command("AT%CSTAT=1", NULL);
#endif /* USE_TI_COMMANDS */
/* assume radio is off on error */
if (isRadioOn() > 0) {
setRadioState (RADIO_STATE_SIM_NOT_READY);
}
}
預設狀況下假設射頻模組是好的,
通過 setRadioState (RADIO_STATE_SIM_NOT_READY) 來觸發對無線模組的初始化。
通過 static void onRadioPowerOn() 對無線模組初始化。
首先通過 pollSIMState(NULL); 輪詢 sim卡狀態 。
static void pollSIMState (void *param)
{
ATResponse *p_response;
int ret;
if (sState != RADIO_STATE_SIM_NOT_READY) {
// no longer valid to poll
return;
}
switch(getSIMStatus()) {
case RIL_SIM_ABSENT:
case RIL_SIM_PIN:
case RIL_SIM_PUK:
case RIL_SIM_NETWORK_PERSONALIZATION:
default:
setRadioState(RADIO_STATE_SIM_LOCKED_OR_ABSENT);
return;
case RIL_SIM_NOT_READY:
RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL);
return;
case RIL_SIM_READY:
setRadioState(RADIO_STATE_SIM_READY);
return;
}
}
讀取sim卡狀態的函數是:getSIMStatus()
err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
它向貓發送了at命令 AT+CPIN? 來查詢無線模組的狀態,如果無線模組還沒有就緒,那麼他隔1秒鐘繼續調用
sim卡狀態輪詢函數 pollSIMState,直到獲得sim卡狀態。
當sim卡狀態為就緒,那麼通過 setRadioState(RADIO_STATE_SIM_READY) 設定變數 sState 為:
RADIO_STATE_SIM_READY,這時候會調用函數 static void onSIMReady()來進一步初始化無線模組。
發送的at命令有:
at_send_command_singleline("AT+CSMS=1", "+CSMS:", NULL);
at_send_command("AT+CNMI=1,2,2,1,1", NULL);
如果sim卡鎖開啟,或者pin被鎖住的時候,會要求輸入pin或者puk,但是這個解鎖動作必須在系統初始化完成以後才能
進行。(圖形系統都還沒有初始化怎麼輸入密碼阿?)當系統初始化完成以後會調用 wm.systemReady()來通知大家。
這時候該做什麼就做什麼。
wm.systemReady()的調用會觸發解鎖介面。具體流程如下:
因為有: WindowManagerService wm = null;所以 wm.systemReady()
調用的是 WindowManagerService 中的函數:
public void systemReady() {
mPolicy.systemReady();
}
WindowManagerService 中有:
final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
PolicyManager.makeNewWindowManager 調用的是檔案 PolicyManager.java 中的函數:
public static WindowManagerPolicy makeNewWindowManager() {
return sPolicy.makeNewWindowManager();
}
sPolicy.makeNewWindowManager 調用的是檔案 Policy.java 中的函數:
public PhoneWindowManager makeNewWindowManager() {
return new PhoneWindowManager();
}
因為 PhoneWindowManager 繼承自 WindowManagerPolicy
所以 mPolicy.systemReady() 最終調用的是檔案 PhoneWindowManager.java 中的函數:
public void systemReady()
mKeyguardMediator.onSystemReady();
doKeyguard();
showLocked();
Message msg = mHandler.obtainMessage(SHOW);
mHandler.sendMessage(msg);
發送 SHOW 的訊息。
檔案 KeyguardViewMediator.java 中的訊息處理函數:
public void handleMessage(Message msg) 對 SHOW 訊息進行了處理。
如果 msg.what 等於 SHOW 那麼執行:
handleShow();
private void handleShow()
...
mCallback.onKeyguardShow();
mKeyguardViewManager.show();
mShowing = true;
mKeyguardViewManager.show() 調用的是檔案 KeyguardViewManager.java 中的函數:
public synchronized void show()
...
mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor, this);
...
mKeyguardViewProperties.createKeyguardView 調用的是檔案 LockPatternKeyguardViewProperties.java
中的函數:
public KeyguardViewBase createKeyguardView(Context context,
KeyguardUpdateMonitor updateMonitor,
KeyguardWindowController controller) {
return new LockPatternKeyguardView(context, updateMonitor,
mLockPatternUtils, controller);
}
new LockPatternKeyguardView 調用了類 LockPatternKeyguardView 的建構函式:
public LockPatternKeyguardView(
Context context,
KeyguardUpdateMonitor updateMonitor,
LockPatternUtils lockPatternUtils,
KeyguardWindowController controller)
...
mLockScreen = createLockScreen();
addView(mLockScreen);
final UnlockMode unlockMode = getUnlockMode();
mUnlockScreen = createUnlockScreenFor(unlockMode);
mUnlockScreenMode = unlockMode;
addView(mUnlockScreen);
updateScreen(mMode);
執行上面的程式然後彈出解鎖介面,getUnlockMode 獲得鎖類型,通常有三種:
enum UnlockMode {
Pattern, //圖案鎖
SimPin, //輸入pin或者puk
Account //帳號鎖
}
通過上面的過程我們可以知道,在系統初始化階段啟動rild的時候,rild與貓進行了通訊,並對貓進行初始化。
儲存了網路的一系列狀態。
=========
待機狀態下,飛航模式切換流程分析:
飛航模式切換比較複雜,它狀態改變時涉及到極大模組狀態切換:
GSM模組,藍芽模組,wifi模組。
飛航模式的enabler層會發送廣播訊息:ACTION_AIRPLANE_MODE_CHANGED
private void setAirplaneModeOn(boolean enabling) {
mCheckBoxPref.setEnabled(false);
mCheckBoxPref.setSummary(enabling ? R.string.airplane_mode_turning_on
: R.string.airplane_mode_turning_off);
// Change the system setting
Settings.System.putInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
enabling ? 1 : 0);
// Post the intent
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", enabling);
mContext.sendBroadcast(intent);
}
因為GSM ,藍芽,wifi模組分別註冊了對 ACTION_AIRPLANE_MODE_CHANGED 訊息的監測,所以收到
該訊息後,模組會進行切換。
BluetoothDeviceService.java
開啟藍芽:enable(false);
關閉藍芽:disable(false);
PhoneApp.java (packages\apps\phone\src\com\android\phone)
設定GSM模組狀態 phone.setRadioPower(enabled);
WifiService.java
設定 wifi 狀態 setWifiEnabledBlocking(wifiEnabled, false, Process.myUid());
===
GSM模組切換過程分析:
phone.setRadioPower(enabled)調用的是:
檔案 GSMPhone.java 中的的函數:
public void setRadioPower(boolean power)
mSST.setRadioPower(power);
因為有 ServiceStateTracker mSST;
mSST.setRadioPower 調用的是檔案 ServiceStateTracker.java 中的函數:
public void setRadioPower(boolean power)
mDesiredPowerState = power;
setPowerStateToDesired();
cm.setRadioPower(true, null);
或者
cm.setRadioPower(false, null);
因為有:
CommandsInterface cm;
public final class RIL extends BaseCommands implements CommandsInterface
所以 cm.setRadioPower 調用的是檔案 RIL.java 中的函數:
public void setRadioPower(boolean on, Message result)
RILRequest rr = RILRequest.obtain(RIL_REQUEST_RADIO_POWER, result);
rr.mp.writeInt(1);
...
send(rr)
通過 send 向 rild 發送 RIL_REQUEST_RADIO_POWER 請求來開啟或者關閉GSM模組。
rild 資料接收流程:
收到 RIL_REQUEST_RADIO_POWER 執行:
requestRadioPower(data, datalen, t);
然後根據條件往無線模組發送模組開啟和關閉請求
主要的at命令有:
err = at_send_command("AT+CFUN=0", &p_response);
err = at_send_command("AT+CFUN=1", &p_response);
===
藍芽模組切換過程分析:
enable(false);
藍芽開啟調用檔案 BluetoothDeviceService.java 中的函數:
public synchronized boolean enable(boolean saveSetting)
setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_ON);
mEnableThread = new EnableThread(saveSetting);
mEnableThread.start();
----
disable(false)
藍芽關閉調用檔案 中的函數:
public synchronized boolean disable(boolean saveSetting)
setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF);
===
wifi模組切換過程分析:
廣播 wifi 狀態改變的訊息:WIFI_STATE_CHANGED_ACTION
setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);
更新 wifi 狀態:
private void updateWifiState()
如果需要使能開啟 wifi 那麼會發送:
sendEnableMessage(true, false, mLastEnableUid);
sendStartMessage(strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI);
訊息迴圈中處理命令訊息:
public void handleMessage(Message msg)
如果使能wifi:setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2);
開啟wifi: mWifiStateTracker.setScanOnlyMode(msg.arg1 != 0);
setWifiEnabledBlocking(false, msg.arg1 == 1, msg.arg2);
斷開 mWifiStateTracker.disconnectAndStop();
開啟過程步驟:
1> 裝載 wifi 驅動: WifiNative.loadDriver()
2> 啟動後退 daemo supplicant: WifiNative.startSupplicant()
關閉過程步驟:
1> 停止後退 daemo supplicant:WifiNative.stopSupplicant()
2> 卸載 wifi 驅動: WifiNative.unloadDriver()
如果 wifi 狀態預設為開啟那麼 WifiService 服務的建構函式:
WifiService(Context context, WifiStateTracker tracker)
boolean wifiEnabled = getPersistedWifiEnabled();
setWifiEnabledBlocking(wifiEnabled, false, Process.myUid());
會開啟wifi模組。
wordend 相關閱讀:
Android教程-解決WiFi串連不穩定
從零開始建立一個Android主畫面Widget
Android 妙招解決App Widget使用者互動