Android4.1.2java
設置中開關:android
packages/apps/Settings/src/com/android/settings/TetherSettings.java
安全
|----private void startTethering()
網絡
| |----mWifiApEnabler.setSoftapEnabled(true);
app
packages/apps/Settings/src/com/android/settings/wifi/WifiApEnabler.java
框架
|----public void setSoftapEnabled(boolean enable)less
| |----mWifiManager.setWifiApEnabled(null, enable)socket
框架:ide
frameworks/base/wifi/java/android/net/wifi/WifiManager.java
函數
|----public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled)
| |----mService.setWifiApEnabled(wifiConfig, enabled);
IWifiManager.aidl
|----void setWifiApEnabled(in WifiConfiguration wifiConfig, boolean enable);
frameworks/base/services/java/com/android/server/WifiService.java
|----public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled)
| |----mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);
frameworks/base/wifi/java/android/net/wifi/WifiStateMachine.java
|----public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable)
| |----sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));
| |----sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
WifiStateMachine 繼承於StateMachine, 而在WifiStateMachine中未有對sendMessage方法的複寫,因此實現是使用父類的實現:
/**
* Enqueue a message to this state machine.
*/
public final void sendMessage(int what) {
// mSmHandler can be null if the state machine has quit.
if (mSmHandler == null) return;
mSmHandler.sendMessage(obtainMessage(what));
}
/**
* Enqueue a message to this state machine.
*/
public final void sendMessage(int what, Object obj) {
// mSmHandler can be null if the state machine has quit.
if (mSmHandler == null) return;
mSmHandler.sendMessage(obtainMessage(what,obj));
}
/**
* Enqueue a message to this state machine.
*/
public final void sendMessage(Message msg) {
// mSmHandler can be null if the state machine has quit.
if (mSmHandler == null) return;
mSmHandler.sendMessage(msg);
}
可見,mSmHandler的定義是類SmHandler, 繼承於Handler, SmHandler對handleMessage進行了複寫,因此對於消息的接收處理應該是在SmHandler的handleMessage中:
/**
* Handle messages sent to the state machine by calling
* the current state's processMessage. It also handles
* the enter/exit calls and placing any deferred messages
* back onto the queue when transitioning to a new state.
*/
@Override
public final void handleMessage(Message msg) {
if (mDbg) Log.d(TAG, "handleMessage: E msg.what=" + msg.what);
/** Save the current message */
mMsg = msg;
if (mIsConstructionCompleted) { //正常的操做
/** Normal path */
processMsg(msg);
} else if (!mIsConstructionCompleted &&
(mMsg.what == SM_INIT_CMD) && (mMsg.obj == mSmHandlerObj)) { //初始化操做
/** Initial one time path. */
mIsConstructionCompleted = true;
invokeEnterMethods(0);
} else {
throw new RuntimeException("StateMachine.handleMessage: " +
"The start method not called, received msg: " + msg);
}
performTransitions(); //應用改變
if (mDbg) Log.d(TAG, "handleMessage: X");
}
processMsg(msg):
/**
* Process the message. If the current state doesn't handle
* it, call the states parent and so on. If it is never handled then
* call the state machines unhandledMessage method.
*/
private final void processMsg(Message msg) {
StateInfo curStateInfo = mStateStack[mStateStackTopIndex]; //獲取當前狀態
if (mDbg) {
Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
}
while (!curStateInfo.state.processMessage(msg)) { //判斷該消息是否處理
/**
* Not processed
*/
curStateInfo = curStateInfo.parentStateInfo;
if (curStateInfo == null) {
/**
* No parents left so it's not handled
*/
mSm.unhandledMessage(msg);
if (isQuit(msg)) {
transitionTo(mQuittingState); //設置狀態
}
break;
}
if (mDbg) {
Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
}
}
在WifiStateMachine中有不少狀態,截取幾個來看:
/* Loading the driver */
private State mDriverUnloadedState = new DriverUnloadedState();
/* Driver load/unload failed */
private State mDriverFailedState = new DriverFailedState();
/* Driver loading */
private State mDriverLoadingState = new DriverLoadingState();
/* Driver loaded */
private State mDriverLoadedState = new DriverLoadedState();
以上4個都是關於Wifi驅動加載與卸載的相關狀態,每個都有複寫本身的processMessage方法,好比DriverUnloadedState():
@Override
public boolean processMessage(Message message) {
if (DBG) log(getName() + message.toString() + "\n");
switch (message.what) {
case CMD_LOAD_DRIVER:
transitionTo(mDriverLoadingState);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
這說明,在狀態是「Wifi驅動已經成功卸載」時,系統只響應(handle)CMD_LOAD_DRIVER的消息,也就是驅動加載命令,其餘一律無論。很符合邏輯吧。
假設,在打開Wifi熱點的時候,驅動就是卸載的(默認狀態),那麼 sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));事後會來到這裏,也就會將新的狀態mDriverLoadingState加入狀態棧。隨後返回HANDLED,另外一種NOT_HANDLED就 不作討論了。那麼如今的流程變成了processMsg(msg) --> transitionTo(mDriverLoadingState) --> performTransitions(),因此在分析performTransitions()以前要先看看transitionTo(實如今父類 StateMachine中):
/** @see StateMachine#transitionTo(IState) */
private final void transitionTo(IState destState) {
mDestState = (State) destState;
if (mDbg) Log.d(TAG, "transitionTo: destState=" + mDestState.getName());
}
因爲State是IState的子類,因此這樣的參數傳遞進去沒有問題,mDestState目標狀態變成了mDriverLoadingState,而後是performTransitions()(仍是在父類StateMachine中):
/**
* Do any transitions
*/
private void performTransitions() {
/**
* If transitionTo has been called, exit and then enter
* the appropriate states. We loop on this to allow
* enter and exit methods to use transitionTo.
*/
State destState = null;
while (mDestState != null) { //即transitionTo設置的新狀態 mDriverLoadingState
if (mDbg) Log.d(TAG, "handleMessage: new destination call exit");
/**
* Save mDestState locally and set to null
* to know if enter/exit use transitionTo.
*/
destState = mDestState;
mDestState = null;
/**
* Determine the states to exit and enter and return the
* common ancestor state of the enter/exit states. Then
* invoke the exit methods then the enter methods.
*/
StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState); //將狀態裝入臨時隊列
invokeExitMethods(commonStateInfo); //將該狀態以前的全部狀態所有退出
int stateStackEnteringIndex = moveTempStateStackToStateStack(); //把臨時隊列合併至標準隊列,而且返回界限值stateStaclEnteringIndex
invokeEnterMethods(stateStackEnteringIndex); //遍歷執行自界限值到隊列頂部的全部狀態的enter方法,以下圖所示:
/*
|-------------|
High| stack_x | mStateStackTopIndex
|-------------|
| ..... |
|-------------|
| stack_y | stateStackEnteringIndex 以上都是從Temp臨時隊列合併來的
|-------------|
| ..... |
|-------------|
Low | stack_1 |
|-------------|
*/
/**
* Since we have transitioned to a new state we need to have
* any deferred messages moved to the front of the message queue
* so they will be processed before any other messages in the
* message queue.
*/ moveDeferredMessageAtFrontOfQueue(); //將全部延遲消息再次發送到隊列頂部,隨後清除延遲消息隊列。 }
/**
* After processing all transitions check and
* see if the last transition was to quit or halt.
*/
if (destState != null) { //如下檢查狀態是不是需求退出或掛起的,是則進行相應處理
if (destState == mQuittingState) {
cleanupAfterQuitting();
} else if (destState == mHaltingState) {
/**
* Call halting() if we've transitioned to the halting
* state. All subsequent messages will be processed in
* in the halting state which invokes haltedProcessMessage(msg);
*/
mSm.halting();
}
}
}
看了好多子函數,有點暈暈的。看得出來這個performTransitions()是對全部狀態進行處理的關鍵節點,可能同一時間會受到不少 Message,而這些Message所攜帶的不一樣狀態會被加入到一個臨時隊列中,而後會將標準隊列頂端到此狀態以前的全部狀態都退出(也就是觸發 exit()),並設置爲非活躍,而後剔除。以後會將臨時隊列合併入標準隊列,取得一個界限值,從界限值到隊列頂端依次激活(觸發enter())。其實 在sendMessage的同時,還有一種消息處理方式就是deferMessage,是對消息的延遲發送,最終會將消息加入到一個延遲消息隊列 mDeferredMessages中,每次的performTransitions()都會對延遲消息隊列進行從新發送而且清空它的隊列。最後,還會檢 測一下是否有特殊的狀態須要處理,如退出和掛起。
WifiStateMachine.java
應該關注一下mDriverLoadingState了,前邊看到這是一個DriverLoadingState(),enter()的主要內容是一個工做線程:
new Thread(new Runnable() {
public void run() {
mWakeLock.acquire(); //整個過程須要wakelock保護
//enabling state
switch(message.arg1) {
case WIFI_STATE_ENABLING: //打開WIFI
setWifiState(WIFI_STATE_ENABLING);
break;
case WIFI_AP_STATE_ENABLING: //打開WIFI AP
setWifiApState(WIFI_AP_STATE_ENABLING);
break;
}
if(mWifiNative.loadDriver()) { // 加載Wifi驅動,WifiNative.java --> core/jni /android_net_wifi_Wifi.cpp --> hardware/libhardware_legacy/wifi.c 就是 insmod xxx.ko,也許帶參數blablabla
if (DBG) log("Driver load successful");
sendMessage(CMD_LOAD_DRIVER_SUCCESS);
} else {
loge("Failed to load driver!");
switch(message.arg1) {
case WIFI_STATE_ENABLING:
setWifiState(WIFI_STATE_UNKNOWN);
break;
case WIFI_AP_STATE_ENABLING:
setWifiApState(WIFI_AP_STATE_FAILED);
break;
}
sendMessage(CMD_LOAD_DRIVER_FAILURE);
}
mWakeLock.release();
}
}).start();
}
而這裏能夠快速的複習一下前邊的流程,加載成功後會sendMessage(CMD_LOAD_DRIVER_SUCCESS),失敗了就會發送 CMD_LOAD_DRIVER_FAILURE。當前的狀態就是mDriverLoadingState,因此是DriverLoadingState 的processMessage來處理這兩個消息了:
@Override
public boolean processMessage(Message message) {
if (DBG) log(getName() + message.toString() + "\n");
switch (message.what) {
case CMD_LOAD_DRIVER_SUCCESS:
transitionTo(mDriverLoadedState);
break;
case CMD_LOAD_DRIVER_FAILURE:
transitionTo(mDriverFailedState);
break;
case CMD_LOAD_DRIVER:
case CMD_UNLOAD_DRIVER:
case CMD_START_SUPPLICANT:
case CMD_STOP_SUPPLICANT:
case CMD_START_AP:
case CMD_STOP_AP:
case CMD_START_DRIVER:
case CMD_STOP_DRIVER:
case CMD_SET_SCAN_MODE:
case CMD_SET_SCAN_TYPE:
case CMD_SET_COUNTRY_CODE:
case CMD_SET_FREQUENCY_BAND:
case CMD_START_PACKET_FILTERING:
case CMD_STOP_PACKET_FILTERING:
deferMessage(message);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
因而可知,加載成功後狀態就變爲mDriverLoadedState,失敗了狀態就是mDriverFailedState。回到DriverLoadingState的enter,setWifiApState:
private void setWifiApState(int wifiApState) {
final int previousWifiApState = mWifiApState.get();
try {
if (wifiApState == WIFI_AP_STATE_ENABLED) { //WIFI AP已經打開,則電池狀態開始記錄Wifi相關
mBatteryStats.noteWifiOn();
} else if (wifiApState == WIFI_AP_STATE_DISABLED) { //WIFI AP已經關閉,則電池狀態對WIFI的記錄關閉
mBatteryStats.noteWifiOff();
}
} catch (RemoteException e) {
loge("Failed to note battery stats in wifi");
}
// Update state
mWifiApState.set(wifiApState); //設置WIFI AP的狀態,原子狀態
if (DBG) log("setWifiApState: " + syncGetWifiApStateByName());
//將狀態消息發送至WifiManager進行進一步處理。終於脫離了狀態機,回到WifiManager了。
final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
mContext.sendStickyBroadcast(intent);
}
PS:經過sendBroadcast中發出的intent在Reciever註冊後才能正確收到,未註冊的時候不能被接收,即便後面再次註冊上也沒法接受到。而sendStickyBroadcast發出的Intent當Reciever註冊後就能收到Intent,即便註冊發生在廣播以後。也就是說sendStickyBroadcast安全性更高,可以保證廣播不會丟失,而sendBroadcast有必定危險。
好 的,分析了這麼久,只是有一條sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0)),發送出狀態廣播給別人獲取,在系統中一個很好的例子是桌面電源控件對這個狀態進行接收,能夠直觀的理解爲當ing的狀態時某按鈕是不可用的。
而後纔是真正的開啓動做:
sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
假設加載成功,當前狀態變成了mDriverLoadedState,那麼去DriverLoadedState的processMessage尋找這個Message的處理方法:
case CMD_START_AP:
transitionTo(mSoftApStartingState);
break;
新的狀態,mSoftApStartingState:
/* Soft ap is starting up */
private State mSoftApStartingState = new SoftApStartingState();
@Override
public void enter() {
if (DBG) log(getName() + "\n");
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
final Message message = getCurrentMessage();
if (message.what == CMD_START_AP) { //若是進入這個狀態而不是打開AP,那麼就直接拋出runtime異常,通常來講就是重啓了。又一次驗證了:不以結婚爲目的的談戀愛都是耍流氓。
final WifiConfiguration config = (WifiConfiguration) message.obj;
if (config == null) {
mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
} else {
mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
startSoftApWithConfig(config);
}
} else {
throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
}
}
OK, config爲NULL,又是一個Message:
mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
在WifiStateMachine構造的時候對mWifiApConfigChannel設置了handler:
mWifiApConfigChannel.connectSync(mContext, getHandler(), wifiApConfigStore.getMessenger());
CMD_REQUEST_AP_CONFIG的消息處理是在WifiApConfigStore中處理的:
class DefaultState extends State {
public boolean processMessage(Message message) {
switch (message.what) {
case WifiStateMachine.CMD_SET_AP_CONFIG:
case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED:
Log.e(TAG, "Unexpected message: " + message);
break;
case WifiStateMachine.CMD_REQUEST_AP_CONFIG:
mReplyChannel.replyToMessage(message,
WifiStateMachine.CMD_RESPONSE_AP_CONFIG, mWifiApConfig);
break;
default:
Log.e(TAG, "Failed to handle " + message);
break;
}
return HANDLED;
}
}
當前WIFI狀態機狀態爲SoftApStartingState,因此回覆消息在這裏處理:
@Override
public boolean processMessage(Message message) {
if (DBG) log(getName() + message.toString() + "\n");
switch(message.what) {
case CMD_LOAD_DRIVER:
case CMD_UNLOAD_DRIVER:
case CMD_START_SUPPLICANT:
case CMD_STOP_SUPPLICANT:
case CMD_START_AP:
case CMD_STOP_AP:
case CMD_START_DRIVER:
case CMD_STOP_DRIVER:
case CMD_SET_SCAN_MODE:
case CMD_SET_SCAN_TYPE:
case CMD_SET_COUNTRY_CODE:
case CMD_SET_FREQUENCY_BAND:
case CMD_START_PACKET_FILTERING:
case CMD_STOP_PACKET_FILTERING:
case CMD_TETHER_STATE_CHANGE:
deferMessage(message);
break;
case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
WifiConfiguration config = (WifiConfiguration) message.obj; //設置文件就是WifiApConfigStore中的mWifiApConfig
if (config != null) {
startSoftApWithConfig(config); //若是配置文件存在就繼續開啓AP
} else {
loge("Softap config is null!"); //若是配置文件爲空則開啓失敗,發送個消息CMD_START_AP_FAILURE,仍是在本狀態中處理
sendMessage(CMD_START_AP_FAILURE);
}
break;
case CMD_START_AP_SUCCESS:
setWifiApState(WIFI_AP_STATE_ENABLED);
transitionTo(mSoftApStartedState);
break;
case CMD_START_AP_FAILURE:
// initiate driver unload
sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0)); //卸載驅動,並更改狀態爲AP開啓失敗
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
這裏的配置文件是經過WifiManager的setWifiApConfiguration接口生成的:
frameworks/base/wifi/java/android/net/wifi/WifiManager.java
/**
* Sets the Wi-Fi AP Configuration.
* @return {@code true} if the operation succeeded, {@code false} otherwise
*
* @hide Dont open yet
*/
public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
try {
mService.setWifiApConfiguration(wifiConfig);
return true;
} catch (RemoteException e) {
return false;
}
}
mService爲IWifiManager,該接口定義以下:
void setWifiApConfiguration(in WifiConfiguration wifiConfig);
而實現爲WifiService
public class WifiService extends IWifiManager.Stub
/**
* see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
* @param wifiConfig WifiConfiguration details for soft access point
*/
public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
enforceChangePermission();
if (wifiConfig == null)
return;
mWifiStateMachine.setWifiApConfiguration(wifiConfig);
}
真是的實現有拋給了WifiStateMachine:
public void setWifiApConfiguration(WifiConfiguration config) {
mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
}
消息交給WifiApConfigStore處理,而
WifiApConfigStore(Context context, Handler target) {
super(TAG, target.getLooper());
mContext = context;
addState(mDefaultState);
addState(mInactiveState, mDefaultState);
addState(mActiveState, mDefaultState);
setInitialState(mInactiveState);
}
WifiApConfigStore在構造的時候分mDefaultState分配了兩個子狀態mInactiveState, mActiveState, 初始化狀態爲mInactiveState。
class InactiveState extends State {
public boolean processMessage(Message message) {
switch (message.what) {
case WifiStateMachine.CMD_SET_AP_CONFIG:
mWifiApConfig = (WifiConfiguration) message.obj;
transitionTo(mActiveState); //觸發ActiveState.enter()
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
}
class ActiveState extends State {
public void enter() {
new Thread(new Runnable() {
public void run() {
writeApConfiguration(mWifiApConfig);
sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED);
}
}).start();
}
writeApConfiguration實現:
private void writeApConfiguration(final WifiConfiguration config) {
DataOutputStream out = null;
try {
out = new DataOutputStream(new BufferedOutputStream(
new FileOutputStream(AP_CONFIG_FILE)));
out.writeInt(AP_CONFIG_FILE_VERSION);
out.writeUTF(config.SSID);
int authType = config.getAuthType();
out.writeInt(authType);
if(authType != KeyMgmt.NONE) {
out.writeUTF(config.preSharedKey);
}
} catch (IOException e) {
Log.e(TAG, "Error writing hotspot configuration" + e);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {}
}
}
}
默認文件路徑即爲/misc/wifi/softap.conf,寫好配置文件後發送WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED,本身發本身收了:
public boolean processMessage(Message message) {
switch (message.what) {
//TODO: have feedback to the user when we do this
//to indicate the write is currently in progress
case WifiStateMachine.CMD_SET_AP_CONFIG:
deferMessage(message);
break;
case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED: //修改完後切換狀態到InactiveState
transitionTo(mInactiveState);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
這樣配置文件就配置完了,結果是保存在mWifiConfig中的。
frameworks/base/wifi/java/android/net/wifi/WifiStateMachine.java startSoftApWithConfig
/* Current design is to not set the config on a running hostapd but instead
* stop and start tethering when user changes config on a running access point
*
* TODO: Add control channel setup through hostapd that allows changing config
* on a running daemon
*/
private void startSoftApWithConfig(final WifiConfiguration config) {
// start hostapd on a seperate thread
new Thread(new Runnable() {
public void run() {
try {
mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
} catch (Exception e) {
loge("Exception in softap start " + e);
try {
mNwService.stopAccessPoint(mInterfaceName);
mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
} catch (Exception e1) {
loge("Exception in softap re-start " + e1);
sendMessage(CMD_START_AP_FAILURE);
return;
}
}
if (DBG) log("Soft AP start successful");
sendMessage(CMD_START_AP_SUCCESS);
}
}).start();
}
邏輯就是嘗試開啓,若是發生錯誤就嘗試重啓,若是再錯誤就認可失敗,發送失敗狀態,若是沒錯誤就發送成功的消息。關鍵在mNwService的startAccessPoint方法中。
config, mInterfaceName, SOFTAP_IFACE
這三個參數:config爲傳遞下來的配置文件,SOFTAP_IFACE爲字符串wl0.1,mInterfaceName爲WifiStateMachine構造時傳遞下來的參數,而這個構造動做由WifiService構造的時候發起:
WifiService(Context context) {
mContext = context;
mInterfaceName = SystemProperties.get("wifi.interface", "wlan0");
mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName);
mWifiStateMachine.enableRssiPolling(true);
...
}
可見,這個mInterfaceName由prop wifi.interface控制,如咱們常常能在build.prop中看到wifi.interface=eth0/wlan0等,若是沒有會默認給wlan0。
接下來看startAccessPoint的實現(frameworks/base/services/java/com/android/server/NetworkManagementService.java):
@Override
public void startAccessPoint(
WifiConfiguration wifiConfig, String wlanIface, String softapIface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
Resources resources = mContext.getResources();
if (resources.getBoolean(com.android.internal.R.bool.config_wifiApFirmwareReload))
wifiFirmwareReload(wlanIface, "AP");
if (resources.getBoolean(com.android.internal.R.bool.config_wifiApStartInterface))
mConnector.execute("softap", "start", wlanIface);
if (wifiConfig == null) {
mConnector.execute("softap", "set", wlanIface, softapIface);
} else {
mConnector.execute("softap", "set", wlanIface, softapIface, wifiConfig.SSID,
getSecurityType(wifiConfig), wifiConfig.preSharedKey);
}
mConnector.execute("softap", "startap");
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
config_wifiApFirmwareReload、config_wifiApStartInterface都是能夠用戶自定義的xml配置接口,默認在frameworks/base/core/res/res/values/config.xml中,默認如:
<!-- Boolean indicating whether Softap requires reloading AP firmware -->
<bool name="config_wifiApFirmwareReload">true</bool>
<!-- Boolean indicating whether the start command should be called on the wireless interface
when starting the SoftAp -->
<bool name="config_wifiApStartInterface">false</bool>
想關聯的幾個函數有:
private static String getSecurityType(WifiConfiguration wifiConfig) { //獲取網絡安全類型
switch (wifiConfig.getAuthType()) {
case KeyMgmt.WPA_PSK:
return "wpa-psk";
case KeyMgmt.WPA2_PSK:
return "wpa2-psk";
default:
return "open";
}
}
/* @param mode can be "AP", "STA" or "P2P" */
@Override
public void wifiFirmwareReload(String wlanIface, String mode) { //根據不一樣模式裝在不一樣的固件(若是有須要的話)
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
mConnector.execute("softap", "fwreload", wlanIface, mode);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
經過以上不難看出,最終都是經過mConnector.execute來執行命令。
/**
* Constructs a new NetworkManagementService instance
*
* @param context Binder context for this service
*/
private NetworkManagementService(Context context) {
mContext = context;
if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
return;
}
mConnector = new NativeDaemonConnector(
new NetdCallbackReceiver(), "netd", 10, NETD_TAG, 160);
mThread = new Thread(mConnector, NETD_TAG);
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
}
mConnector是在構造時生成的NativeDaemonConnector對象,查看一下NativeDaemonConnector的構造過程 (frameworks/base/services/java/com/android/server /NativeDaemonConnector.java):
NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
int responseQueueSize, String logTag, int maxLogSize) {
mCallbacks = callbacks;
mSocket = socket;
mResponseQueue = new ResponseQueue(responseQueueSize);
mSequenceNumber = new AtomicInteger(0);
TAG = logTag != null ? logTag : "NativeDaemonConnector";
mLocalLog = new LocalLog(maxLogSize);
}
1.分別在handleMessage和listenToSocket的時候調用回調對象的onEvent和onDaemonConnected方法。而 監聽socket的服務被建立後就已經開出一個線程始終監聽了。在這裏爲new NetdCallbackReceiver();
2.mSocket也就是在NetworkManagementService中始終監聽的那個local socket。在這裏爲netd(/dev/socket/netd);
3.mResponseQueue是新建了一個命令隊列ResponseQueue,傳遞金的參數responseQueuesize就是這個隊列的容量上限。這個子類算上構造在內總共4個方法:
a.構造
b.添加命令
c.移除命令
d.打印隊列信息
4.mSequeueceNumber做爲指令執行計數器,是個原子量, 防止線程操做混亂;
5.日誌標籤
6.日誌容量
構造完成後,會new出一個線程,這個線程的工做就是調用listenToSocket。最後會使用看門狗來保護這個服務。
回到主線,默認狀況下,並有有效的配置文件,打開WIFI AP須要執行兩條命令:
mConnector.execute("softap", "fwreload", wlanIface, mode);
mConnector.execute("softap", "set", wlanIface, softapIface, wifiConfig.SSID,
getSecurityType(wifiConfig), wifiConfig.preSharedKey);
逐個分析一下:
wlanIface就是prop指定的wifi.interface,默認爲wlan0,mode爲"AP",共計四個參數。
這兩條命令都會最終執行到這裏:
public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args)
throws NativeDaemonConnectorException {
final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();
final int sequenceNumber = mSequenceNumber.incrementAndGet(); //命令計數器加一併返回
final StringBuilder cmdBuilder =
new StringBuilder(Integer.toString(sequenceNumber)).append(' ');
final long startTime = SystemClock.elapsedRealtime(); //返回的是自從系統啓動到當前的時間
makeCommand(cmdBuilder, cmd, args); //將全部參數整合成一條命令,放置在cmdBuilder中
final String logCmd = cmdBuilder.toString(); /* includes cmdNum, cmd, args */
log("SND -> {" + logCmd + "}");
cmdBuilder.append('\0'); //給字符串來個尾巴,而後化做真正的字符串sentCmd
final String sentCmd = cmdBuilder.toString(); /* logCmd + \0 */
synchronized (mDaemonLock) {
if (mOutputStream == null) { //mOutputStraem是netd的輸出通道
throw new NativeDaemonConnectorException("missing output stream");
} else {
try {
mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8)); //將命令發送出去 netd socket
} catch (IOException e) {
throw new NativeDaemonConnectorException("problem sending command", e);
}
}
}
NativeDaemonEvent event = null;
do {
event = mResponseQueue.remove(sequenceNumber, timeout, sentCmd); //從命令隊列中刪除已經發送出去的命令
if (event == null) {
loge("timed-out waiting for response to " + logCmd);
throw new NativeDaemonFailureException(logCmd, event);
}
log("RMV <- {" + event + "}");
events.add(event);
} while (event.isClassContinue());
final long endTime = SystemClock.elapsedRealtime();
if (endTime - startTime > WARN_EXECUTE_DELAY_MS) {
loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)");
}
if (event.isClassClientError()) {
throw new NativeDaemonArgumentException(logCmd, event);
}
if (event.isClassServerError()) {
throw new NativeDaemonFailureException(logCmd, event);
}
return events.toArray(new NativeDaemonEvent[events.size()]);
}
如今看來,全部命令都是經過netd socket發送出去。可是這個socket是誰來接收呢?
system/netd
[to be continued...]