一 Settings界面
Settings包括了Android原生Settings界面的实现,部分厂商会基于Android-Settings架构定制自己的一些界面,例如XM-Settings、HW-Settings,都会包含在这部分,原生的Settings一般是一个apk文件,命名为Settings.apk,存放在手机/system/priv-app/Settings目录。这部分大多以界面的形式呈现,当我们无法定位到某个界面对于那部分代码时,可以使用如下命令:
adb logcat | grep -iEn "activity|fragment"
二 Wi-Fi打开
2.1 Wi-Fi相关进程
首先,我们打开一台手机设备,看看Wi-Fi打开之后会出现哪些进程:
XXXX:/ # ps -ef | grep -iEn "wifi|supplicant"
482:wifi 1458 1 0 18:19:07 ? 00:00:02 android.hardware.wifi-service
599:wifi 2493 1 0 18:19:11 ? 00:00:00 wificond
608:system 2510 1 0 18:19:11 ? 00:00:00 wifidisplayhalservice
689:wifi 4196 1 0 18:19:19 ? 00:00:00 wpa_supplicant -O/data/vendor/wifi/wpa/sockets -puse_p2p_group_interface=1 -dd -g@android:wpa_wlan0
可以看到有四个进程:
1.android.hardware.wifi-service
他是wifi hal服务,负责wifiservice和wpa_supplicant、hostapd之间的通信进程,它是一个由C++编码实现的守护进程,其源码路径一般都是在hardware/interfaces/wifi/aidl/default下边,一般会有一个rc文件来启动这个进程。
2.2.wificond
他是wifi的一个守护进程,主要实现wifi的扫描功能;其代码结构如下:
3.wifidisplayhalservice
Wi-Fi P2P的进程;
4.wpa_supplicant
Wi-Fi的守护进程;
2.2 Wi-Fi service启动
wifiService是在系统启动时被systemServer进程拉起来;SystemServer.java文件中包含了wifiService的拉起过程:
private static final String WIFI_SERVICE_CLASS =
"com.android.server.wifi.WifiService";
private static final String WIFI_SCANNING_SERVICE_CLASS =
"com.android.server.wifi.scanner.WifiScanningService";
//systemServer进程启动
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...
if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI)) {
// Wifi Service must be started first for wifi-related services.
t.traceBegin("StartWifi");
mSystemServiceManager.startServiceFromJar(
WIFI_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
t.traceEnd();
t.traceBegin("StartWifiScanning");
mSystemServiceManager.startServiceFromJar(
WIFI_SCANNING_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
t.traceEnd();
}
在wifiService被拉起来之后,会new一个wifi注册器WifiInjector和WifServiceImpl;
注意:onStart方法是在对象初始化时执行,目的是将wifiService服务注册到ServiceManager;
(1)Wi-Fi注射器的作用是将framework层Wi-Fi相关的服务全部拉起来,这个时候不同的服务在各自的构造函数中做一些初始化的动作。
(2)创建WifiServiceImpl对象,这个类相当关键,他是wifiService的大管家,所有用户端的请求都会被他分发给不同的服务去处理;在Android S/T/U版本中新增了两个类:
clientModeImpl:它的作用类似于老版本中的WifiStateMachine,主要处理连接、注网以及客户端请求的事件和回调处理。
ActiveModeWarden官方是这样解释的,大家在后续自己阅读源码过程中细细体会,里边应用了Android状态机
2.3 Wi-Fi启动流程
1.应用调用WifiManager.setWifiEnabled()
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
2.WifiManager通过AIDL机制调用WifiSericeImpl.setWifiEnabled()
/packages/modules/Wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
/**
* see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
* @param enable {@code true} to enable, {@code false} to disable.
* @return {@code true} if the enable/disable operation was
* started or is already in the queue.
*/
@Override
public synchronized boolean setWifiEnabled(String packageName, boolean enable) {
//权限检查,主要防止一些非法调用
if (enforceChangePermission(packageName) != MODE_ALLOWED) {
return false;
}
int callingUid = Binder.getCallingUid();
int callingPid = Binder.getCallingPid();
boolean isPrivileged = isPrivileged(callingPid, callingUid);
boolean isThirdParty = !isPrivileged
&& !isDeviceOrProfileOwner(callingUid, packageName)
&& !mWifiPermissionsUtil.isSystem(packageName, callingUid);
boolean isTargetSdkLessThanQ = mWifiPermissionsUtil.isTargetSdkLessThan(packageName,
Build.VERSION_CODES.Q, callingUid) && !isGuestUser();
mWifiPermissionsUtil.checkPackage(callingUid, packageName);
if (isThirdParty && !isTargetSdkLessThanQ) {
mLog.info("setWifiEnabled not allowed for uid=%").c(callingUid).flush();
return false;
}
// If Satellite mode is enabled, Wifi can not be turned on/off
if (mSettingsStore.isSatelliteModeOn()) {
mLog.info("setWifiEnabled not allowed as satellite mode is on.").flush();
return false;
}
// If Airplane mode is enabled, only privileged apps are allowed to toggle Wifi
if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) {
mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush();
return false;
}
// If SoftAp is enabled, only privileged apps are allowed to toggle wifi
if (!isPrivileged && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) {
mLog.err("setWifiEnabled with SoftAp enabled: only Settings can toggle wifi").flush();
return false;
}
// If user restriction is set, only DO/PO is allowed to toggle wifi
if (SdkLevel.isAtLeastT() && mUserManager.hasUserRestrictionForUser(
UserManager.DISALLOW_CHANGE_WIFI_STATE,
UserHandle.getUserHandleForUid(callingUid))
&& !isDeviceOrProfileOwner(callingUid, packageName)) {
mLog.err("setWifiEnabled with user restriction: only DO/PO can toggle wifi").flush();
return false;
}
// Show a user-confirmation dialog for legacy third-party apps targeting less than Q.
if (enable && isTargetSdkLessThanQ && isThirdParty
&& showDialogWhenThirdPartyAppsEnableWifi()) {
mLog.info("setWifiEnabled must show user confirmation dialog for uid=%").c(callingUid)
.flush();
mWifiThreadRunner.post(() -> {
if (mActiveModeWarden.getWifiState()
== WIFI_STATE_ENABLED) {
// Wi-Fi already enabled; don't need to show dialog.
return;
}
showWifiEnableRequestDialog(callingUid, callingPid, packageName);
});
return true;
}
// 如果以上全部通过,将调用真正的wifi打开动作
setWifiEnabledInternal(packageName, enable, callingUid, callingPid, isPrivileged);
return true;
private void setWifiEnabledInternal(String packageName, boolean enable,
int callingUid, int callingPid, boolean isPrivileged) {
mLog.info("setWifiEnabled package=% uid=% enable=% isPrivileged=%").c(packageName)
.c(callingUid).c(enable).c(isPrivileged).flush();
long ident = Binder.clearCallingIdentity();
try {
if (!mSettingsStore.handleWifiToggled(enable)) {
// Nothing to do if wifi cannot be toggled
return;
}
} finally {
Binder.restoreCallingIdentity(ident);
}
if (enable) {
// Clear out all outstanding wifi enable request dialogs.
mWifiThreadRunner.post(() -> {
for (int i = 0; i < mWifiEnableRequestDialogHandles.size(); i++) {
mWifiEnableRequestDialogHandles.valueAt(i).dismissDialog();
}
mWifiEnableRequestDialogHandles.clear();
});
}
if (mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)) {
if (enable) {
mWifiThreadRunner.post(
() -> mWifiConnectivityManager.setAutoJoinEnabledExternal(true, false));
mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_ON);
} else {
WifiInfo wifiInfo = mActiveModeWarden.getConnectionInfo();
mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_OFF,
wifiInfo == null ? -1 : wifiInfo.getNetworkId());
}
}
if (!enable) {
mWifiInjector.getInterfaceConflictManager().reset();
}
mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable);
mWifiMetrics.reportWifiStateChanged(enable, mWifiInjector.getWakeupController().isUsable(),
false);
mActiveModeWarden.wifiToggled(new WorkSource(callingUid, packageName));
mLastCallerInfoManager.put(WifiManager.API_WIFI_ENABLED, Process.myTid(),
callingUid, callingPid, packageName, enable);
}
3.开始进入到ActiveModeWarden类,调用wifiToggled方法;
/packages/modules/Wifi/service/java/com/android/server/wifi/ActiveModeWarden.java
mActiveModeWarden.wifiToggled(new WorkSource(callingUid, packageName));
/** Wifi has been toggled. */
public void wifiToggled(WorkSource requestorWs) {
mWifiController.sendMessage(WifiController.CMD_WIFI_TOGGLED, requestorWs);
}
这里发送了一个消息CMD_WIFI_TOGGLED,WifiController是一个内部类,在ActiveModeWarden构造函数中进行初始化,之后WifiController的构造函数中会调用WifiNative.initialize函数,其目的是初始化wifi hal服务。ActiveModeWarden服务也是在wifi server初始化过程中通过构造函数初始化。WifiController这里第一个接触状态机,其关系如下:
对于消息处理仍然采用之前的机制,父状态机优先处理,
private class IdleState extends RunnerState {
switch (message.what) {
case CMD_START:
// Always start in scan mode first.
RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj;
mClientInterfaceName = mWifiNative.setupInterfaceForClientInScanMode(
mWifiNativeInterfaceCallback, roleChangeInfo.requestorWs,
ConcreteClientModeManager.this);
if (TextUtils.isEmpty(mClientInterfaceName)) {
Log.e(getTag(), "Failed to create ClientInterface. Sit in Idle");
takeBugReportInterfaceFailureIfNeeded(
"Wi-Fi BugReport (scan STA interface failure):",
"Failed to create client interface in idle state");
mModeListener.onStartFailure(ConcreteClientModeManager.this);
break;
}
mWifiNative.setWifiNativeInterfaceEventCallback(
mWifiNativeInterfaceEventCallback);
if (roleChangeInfo.role instanceof ClientConnectivityRole) {
sendMessage(CMD_SWITCH_TO_CONNECT_MODE, roleChangeInfo);
transitionTo(mStartedState);
} else {
mScanRoleChangeInfoToSetOnTransition = roleChangeInfo;
transitionTo(mScanOnlyModeState);
}
break;
这里的关键是调用了WifiNative.setupInterfaceClientInScanMode方法;
public String setupInterfaceForClientInScanMode(
@NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs,
@NonNull ConcreteClientModeManager concreteClientModeManager) {
synchronized (mLock) {
//加载wlan驱动
if (!startHal()) {
Log.e(TAG, "Failed to start Hal");
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
return null;
}
//分配对应网口
Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_SCAN);
if (iface == null) {
Log.e(TAG, "Failed to allocate new STA iface");
return null;
}
iface.externalListener = interfaceCallback;
//创建wlan网口
iface.name = createStaIface(iface, requestorWs, concreteClientModeManager);
if (TextUtils.isEmpty(iface.name)) {
Log.e(TAG, "Failed to create iface in vendor HAL");
mIfaceMgr.removeIface(iface.id);
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
return null;
}
//创建STA接口
if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run,
new NormalScanEventCallback(iface.name),
new PnoScanEventCallback(iface.name))) {
Log.e(TAG, "Failed to setup iface in wificond=" + iface.name);
teardownInterface(iface.name);
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
return null;
}
registerInterfaceObserver();
//监听wlan网口up/down状态
iface.networkObserver = new NetworkObserverInternal(iface.id);
if (!registerNetworkObserver(iface.networkObserver)) {
Log.e(TAG, "Failed to register network observer for iface=" + iface.name);
teardownInterface(iface.name);
return null;
}
//监听wpa_supplicant状态
mWifiMonitor.startMonitoring(iface.name);
// Just to avoid any race conditions with interface state change callbacks,
// update the interface state before we exit.
onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
mWifiVendorHal.enableLinkLayerStats(iface.name);
Log.i(TAG, "Successfully setup " + iface);
iface.featureSet = getSupportedFeatureSetInternal(iface.name);
updateSupportedBandForStaInternal(iface);
mWifiVendorHal.enableStaChannelForPeerNetwork(mContext.getResources().getBoolean(
R.bool.config_wifiEnableStaIndoorChannelForPeerNetwork),
mContext.getResources().getBoolean(
R.bool.config_wifiEnableStaDfsChannelForPeerNetwork));
return iface.name;
}
}
其调用栈是:
wifi.cpp -->startInternal()
wifi.cpp–>initializeModeControllerAndLegacyHal()
WifiModeController.cpp–>initialize()
DriverTool.cpp–>LoadDiver()
/frameworks/opt/net/wifi/libwifi_hal/driver_tool.cpp
bool DriverTool::LoadDriver() {
return ::wifi_load_driver() == 0;
}
int wifi_load_driver() {
#ifdef WIFI_DRIVER_MODULE_PATH
if (is_wifi_driver_loaded()) {
return 0;
}
if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) return -1;
#endif
#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
if (is_wifi_driver_loaded()) {
return 0;
}
if (wifi_change_driver_state(WIFI_DRIVER_STATE_ON) < 0) {
#ifdef WIFI_DRIVER_MODULE_PATH
PLOG(WARNING) << "Driver unloading, err='fail to change driver state'";
if (rmmod(DRIVER_MODULE_NAME) == 0) {
PLOG(DEBUG) << "Driver unloaded";
} else {
// Set driver prop to "ok", expect HL to restart Wi-Fi.
PLOG(DEBUG) << "Driver unload failed! set driver prop to 'ok'.";
property_set(DRIVER_PROP_NAME, "ok");
}
#endif
return -1;
}
#endif
is_driver_loaded = true;
return 0;
}
这里有几个注意点
1.命令如何挂载wlan驱动
insmod 驱动路径
2.驱动挂载之后会更新一个系统属性
wlan.driver.status OK
3.wlan驱动挂载后会更新设备节点
/sys/class/net/wlan0
到此第一部分CMD_START消息处理完成;开始处理第二个消息,即消息CMD_SWITCH_TO_CONNECT_MODE;
5.处理消息CMD_SWITCH_TO_CONNECT_MODE,这个消息的主要作用就是启动wpa_supplicant守护进程;
注意在这里wifi开启状态被更新为Enabling状态;
framework与wpa_supplicant进程通信是通过AIDL机制,ISupplicant是一个hal服务,其目录结构如下:
asInterface 这个方法将触发wpa_supplicant进程,进入到wpa_supplicant的main函数中;
在一系列调用之后,完成switchClientInterfaceToConnectivityMode方法的调用,回到状态机ConnectModeState中,更新wifi状态为Enabled状态
6.ClientModeImpl开始准备L2、L3层服务启动
至此,wifi服务全部启动,如果触发连接,将会将客户端连接请求交给ClientModeImpl进行消息的处理和时间响应。