Android U Wi-Fi 打开流程
WifiManager 它属于WiFi模块对外的接口。所以settings、systemUI都是从这里调用相关WiFi的接口来实现显示相关功能。
下面setWifiEnabled()函数就是开打开关闭WiFi的对外接口,传递Boolean参数即可。调用此方法的应用必须要有android.Manifest.permission#CHANGE_WIFI_STATE相关权限。
//WifiManager.java
/**
* Enable or disable Wi-Fi.
* <p>
* Applications must have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}
* permission to toggle wifi.
*
* @param enabled {@code true} to enable, {@code false} to disable.
* @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
* either already in the requested state, or in progress toward the requested state.
* @throws SecurityException if the caller is missing required permissions.
*
* @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
* enable/disable Wi-Fi.
* <b>Compatibility Note:</b> For applications targeting
* {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
* {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#P}
* or below), they can continue to use this API.
* <p>
* Deprecation Exemptions:
* <ul>
* <li>Device Owner (DO), Profile Owner (PO) and system apps.
* </ul>
*
* Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, DO/COPE may set
* a user restriction (DISALLOW_CHANGE_WIFI_STATE) to only allow DO/PO to use this API.
*/
@Deprecated
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
得知通过aidl 调用的是WifiServiceImpl具体实现。
//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;
}
//走到了这里
setWifiEnabledInternal(packageName, enable, callingUid, callingPid, isPrivileged);
return true;
}
@AnyThread
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 {
//判断飞行模式下是否可以切换WIFI
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);
}
//ActiveModeWarden.java
//这里便是发送广播的地方了,那谁来处理CMD_WIFI_TOGGLED呢?那肯定是DisabledState状态的时候来处理呀。
/** Wifi has been toggled. */
public void wifiToggled(WorkSource requestorWs) {
mWifiController.sendMessage(WifiController.CMD_WIFI_TOGGLED, requestorWs);
}
//这里是WifiController创建状态机的地方
WifiController() {
super(TAG, mLooper);
final int threshold = mContext.getResources().getInteger(
R.integer.config_wifiConfigurationWifiRunnerThresholdInMs);
DefaultState defaultState = new DefaultState(threshold);
mEnabledState = new EnabledState(threshold);
mDisabledState = new DisabledState(threshold);
addState(defaultState); {
addState(mDisabledState, defaultState);
addState(mEnabledState, defaultState);
}
setLogRecSize(100);
setLogOnlyTransitions(false);
}
//接收到CMD_WIFI_TOGGLED消息
....
@Override
public boolean processMessageFiltered(Message msg) {
switch (msg.what) {
case CMD_WIFI_TOGGLED:
case CMD_SCAN_ALWAYS_MODE_CHANGED:
handleStaToggleChangeInDisabledState((WorkSource) msg.obj);
break;
....
//transitionTo(mEnabledState);切换状态机到mEnabledState
private void handleStaToggleChangeInDisabledState(WorkSource requestorWs) {
if (shouldEnableSta()) {
//看看这里面干了什么
startPrimaryOrScanOnlyClientModeManager(requestorWs);
transitionTo(mEnabledState);
}
}
/**
* Method to enable a new primary client mode manager.
*/
private boolean startPrimaryOrScanOnlyClientModeManager(WorkSource requestorWs) {
ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager();
if (role == ROLE_CLIENT_PRIMARY) {
//走到了这里
return startPrimaryClientModeManager(requestorWs);
} else if (role == ROLE_CLIENT_SCAN_ONLY) {
return startScanOnlyClientModeManager(requestorWs);
} else {
return false;
}
}
/**
* Method to enable a new primary client mode manager in connect mode.
*/
private boolean startPrimaryClientModeManager(WorkSource requestorWs) {
if (hasPrimaryOrScanOnlyModeManager()) {
Log.e(TAG, "Unexpected state - primary CMM should not be started when a primary "
+ "or scan only CMM is already present.");
if (!mIsMultiplePrimaryBugreportTaken) {
mIsMultiplePrimaryBugreportTaken = true;
mWifiDiagnostics.takeBugReport("Wi-Fi ActiveModeWarden bugreport",
"Trying to start primary mode manager when one already exists.");
}
return false;
}
Log.d(TAG, "Starting primary ClientModeManager in connect mode");
//创建ClientModeManage对象
ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
new ClientListener(), requestorWs, ROLE_CLIENT_PRIMARY, mVerboseLoggingEnabled);
//加入到ConcreteClientModeManager列表集合中
mClientModeManagers.add(manager);
mLastPrimaryClientModeManagerRequestorWs = requestorWs;
return true;
}
//这里可以看到在WifiInjector里面new ClientModeManager。
ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
new ClientListener(), requestorWs, ROLE_CLIENT_PRIMARY, mVerboseLoggingEnabled);
看看ClientModeManager的构造函数
//WifiInjector.java
/**
* Create a ClientModeManager
*
* @param listener listener for ClientModeManager state changes
* @return a new instance of ClientModeManager
*/
public ConcreteClientModeManager makeClientModeManager(
@NonNull ClientModeManager.Listener<ConcreteClientModeManager> listener,
@NonNull WorkSource requestorWs,
@NonNull ActiveModeManager.ClientRole role,
boolean verboseLoggingEnabled) {
return new ConcreteClientModeManager(
mContext, mWifiHandlerThread.getLooper(), mClock,
mWifiNative, listener, mWifiMetrics, mWakeupController,
this, mSelfRecovery, mWifiGlobals, mDefaultClientModeManager,
mClock.getElapsedSinceBootMillis(), requestorWs, role, mBroadcastQueue,
verboseLoggingEnabled);
}
//调用构造函数发送ClientModeStateMachine.CMD_START广播
ConcreteClientModeManager.java
ConcreteClientModeManager(
Context context, @NonNull Looper looper, Clock clock,
WifiNative wifiNative, @NonNull Listener<ConcreteClientModeManager> listener,
WifiMetrics wifiMetrics,
WakeupController wakeupController, WifiInjector wifiInjector,
SelfRecovery selfRecovery, WifiGlobals wifiGlobals,
DefaultClientModeManager defaultClientModeManager, long id,
@NonNull WorkSource requestorWs, @NonNull ClientRole role,
@NonNull ClientModeManagerBroadcastQueue broadcastQueue,
boolean verboseLoggingEnabled) {
mContext = context;
mClock = clock;
mWifiNative = wifiNative;
mModeListener = listener;
mWifiMetrics = wifiMetrics;
mWakeupController = wakeupController;
mWifiInjector = wifiInjector;
mStateMachine = new ClientModeStateMachine(looper);
mDeferStopHandler = new DeferStopHandler(looper);
mSelfRecovery = selfRecovery;
mWifiGlobals = wifiGlobals;
mDefaultClientModeManager = defaultClientModeManager;
mId = id;
mTargetRoleChangeInfo = new RoleChangeInfo(role, requestorWs, listener);
mBroadcastQueue = broadcastQueue;
enableVerboseLogging(verboseLoggingEnabled);
//send CMD_STATRT
mStateMachine.sendMessage(ClientModeStateMachine.CMD_START, mTargetRoleChangeInfo);
}
ClientModeStateMachine.CMD_START广播IdleState处理
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.java
/**
* Setup an interface for client mode (for scan) operations.
*
* This method configures an interface in STA mode in the native daemons
* (wificond, vendor HAL).
*
* @param interfaceCallback Associated callback for notifying status changes for the iface.
* @param requestorWs Requestor worksource.
* @param concreteClientModeManager ConcreteClientModeManager requesting the interface.
* @return Returns the name of the allocated interface, will be null on failure.
*/
public String setupInterfaceForClientInScanMode(
@NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs,
@NonNull ConcreteClientModeManager concreteClientModeManager) {
synchronized (mLock) {
//这里调用startHal()
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;
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;
}
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();
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;
}
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;
}
}
/** Helper method invoked to start supplicant if there were no ifaces */
private boolean startHal() {
synchronized (mLock) {
if (!mIfaceMgr.hasAnyIface()) {
if (mWifiVendorHal.isVendorHalSupported()) {
//开启vendor Hal
if (!mWifiVendorHal.startVendorHal()) {
Log.e(TAG, "Failed to start vendor HAL");
return false;
}
if (SdkLevel.isAtLeastS()) {
mWifiVendorHal.setCoexUnsafeChannels(
mCachedCoexUnsafeChannels, mCachedCoexRestrictions);
}
} else {
Log.i(TAG, "Vendor Hal not supported, ignoring start.");
}
}
registerWificondListenerIfNecessary();
return true;
}
}
//调用供应商的hal
//WifiVendorHal.java
/**
* Bring up the Vendor HAL.
* @return true on success, false otherwise.
*/
public boolean startVendorHal() {
synchronized (sLock) {
if (!mHalDeviceManager.start()) {//判断调用是否成功
mLog.err("Failed to start vendor HAL").flush();
return false;
}
mLog.info("Vendor Hal started successfully").flush();
return true;
}
}
//调用startWifi()
//HalDeviceManager.java
/**
* Attempts to start Wi-Fi. Returns the success (true) or failure (false) or
* the start operation. Will also dispatch any registered ManagerStatusCallback.onStart() on
* success.
*/
public boolean start() {
return startWifi();
}
private boolean startWifi() {
if (VDBG) Log.d(TAG, "startWifi");
//进行初始化
initializeInternal();
synchronized (mLock) {
int triedCount = 0;
while (triedCount <= START_HAL_RETRY_TIMES) {
//调用WifiHal.start()
int status = mWifiHal.start();
if (status == WifiHal.WIFI_STATUS_SUCCESS) {
managerStatusListenerDispatch();
if (triedCount != 0) {
Log.d(TAG, "start IWifi succeeded after trying "
+ triedCount + " times");
}
WifiChipInfo[] wifiChipInfos = getAllChipInfo();
if (wifiChipInfos == null) {
Log.e(TAG, "Started wifi but could not get current chip info.");
}
return true;
} else if (status == WifiHal.WIFI_STATUS_ERROR_NOT_AVAILABLE) {
// Should retry. Hal might still be stopping. the registered event
// callback will not be cleared.
Log.e(TAG, "Cannot start wifi because unavailable. Retrying...");
try {
Thread.sleep(START_HAL_RETRY_INTERVAL_MS);
} catch (InterruptedException ignore) {
// no-op
}
triedCount++;
} else {
// Should not retry on other failures.
// Will be handled in the onFailure event.
Log.e(TAG, "Cannot start IWifi. Status: " + status);
return false;
}
}
Log.e(TAG, "Cannot start IWifi after trying " + triedCount + " times");
return false;
}
}
//启动实际加载WiFi动作的调用,涉及HIDL机制调用
//WifiHal.java
/**
* See comments for {@link IWifiHal#start()}
*/
public @WifiStatusCode int start() {
return validateAndCall("start", WIFI_STATUS_ERROR_UNKNOWN,
() -> mWifiHal.start());
}