一 前言
android框架层的函数调用是出了名的绕,开发者可能因为各种原因比如避免冲突、条件判断、函数封装等等各种各样需要考虑的因素而使得框架层的方法调用显得比较长,所以看源码的时候先看大体流程,有需要再深入某些重要的细节。不然一入源码深似海,会淹没在茫茫源码中。繁杂的东西,自己只要不凌乱,找好线索,进行总结,便会简单。
二 图示调用流程
三 代码具体流程
1 应用层
1.1 packages/apps/settings/WifiSettings.java
在onStart()创建一个WifiEnabler对象,实现wifi开关功能。
@Override
public void onStart() {
super.onStart();
// On/off switch is hidden for Setup Wizard (returns null)
mWifiEnabler = createWifiEnabler();
if (mIsRestricted) {
restrictUi();
return;
}
onWifiStateChanged(mWifiManager.getWifiState());
}
private WifiEnabler createWifiEnabler() {
final SettingsActivity activity = (SettingsActivity) getActivity();
return new WifiEnabler(activity, new SwitchBarController(activity.getSwitchBar()),
mMetricsFeatureProvider);
}
1.2 packages/apps/settings/WifiEnabler.java
开启Wifi开关变会有下面的操作。
@Override
public boolean onSwitchToggled(boolean isChecked) {
//Do nothing if called as a result of a state machine event
if (mStateMachineEvent) {
return true;
}
// Show toast message if Wi-Fi is not allowed in airplane mode
if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
// Reset switch to off. No infinite check/listener loop.
mSwitchWidget.setChecked(false);
return false;
}
if (isChecked) {
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_ON);
} else {
// Log if user was connected at the time of switching off.
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_OFF,
mConnected.get());
}
if (!mWifiManager.setWifiEnabled(isChecked)) {
// Error
mSwitchWidget.setEnabled(true);
Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
}
return true;
}
点击开关会调用mWifiManager.setWifiEnabled。
2 java 框架层
2.1 frameworks/base/wifi/java/android/net/wifi/WifiManager.java
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
2.2 frameworks/base/wifi/java/android/net/wifi/IWifiManager.aidl
boolean setWifiEnabled(String packageName, boolean enable);
2.3 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiSeviceImpl.java
@Override
public synchronized boolean setWifiEnabled(String packageName, boolean enable)throws RemoteException {
if (enforceChangePermission(packageName) != MODE_ALLOWED) { return false;
}
Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid() + ", package=" + packageName);
mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName).c(Binder.getCallingUid()).c(enable).flush();
boolean isFromSettings = checkNetworkSettingsPermission(
Binder.getCallingPid(), Binder.getCallingUid());
// If Airplane mode is enabled, only Settings is allowed to toggle Wifi
if (mSettingsStore.isAirplaneModeOn() && !isFromSettings) {
mLog.info("setWifiEnabled in Airplane mode: only Settings can enable wifi").flush();
return false;
}
// If SoftAp is enabled, only Settings is allowed to toggle wifi
boolean apEnabled = mWifiApState == WifiManager.WIFI_AP_STATE_ENABLED;
if (apEnabled && !isFromSettings) {
mLog.info("setWifiEnabled SoftAp not disabled: only Settings can enable wifi").flush();
return false;
}
/*
* Caller might not have WRITE_SECURE_SETTINGS,
* only CHANGE_WIFI_STATE is enforced
*/
long ident = Binder.clearCallingIdentity();
try {
if (! mSettingsStore.handleWifiToggled(enable)) {
// Nothing to do if wifi cannot be toggled