因发现Android 9.0 会在打开wifi的时候去默认关闭热点,所以我们看下打开wifi的流程,和在哪里去关闭的热点
1 设置打开wifi会调用
frameworks\base\wifi\java\android\net\wifi\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 {@link java.lang.SecurityException} if the caller is missing required permissions.
*/
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
2调用frameworks\opt\net\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)
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
return true;
}
} finally {
Binder.restoreCallingIdentity(ident);
}
if (mPermissionReviewRequired) {
final int wiFiEnabledState = getWifiEnabledState();
if (enable) {
if (wiFiEnabledState == WifiManager.WIFI_STATE_DISABLING
|| wiFiEnabledState == WifiManager.WIFI_STATE_DISABLED) {
if (startConsentUi(packageName, Binder.getCallingUid(),
WifiManager.ACTION_REQUEST_ENABLE)) {
return true;
}
}
} else if (wiFiEnabledState == WifiManager.WIFI_STATE_ENABLING
|| wiFiEnabledState == WifiManager.WIFI_STATE_ENABLED) {
if (startConsentUi(packageName, Binder.getCallingUid(),
WifiManager.ACTION_REQUEST_DISABLE)) {
return true;
}
}
}
mWifiController.sendMessage(CMD_WIFI_TOGGLED);
return true;
}
3,上面代码没有开关热点操作,接着流程经历了一些状态传递,这里就不贴代码了,可以自己去看看下面几个类或者找一篇分析wifi开启流程的文章,frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiController.java
接着来到frameworks\opt\net\wifi\service\java\com\android\server\wifi\ScanOnlyModeManager.java
private class IdleState extends State {
@Override
public void enter() {
Log.d(TAG, "entering IdleState");
mClientInterfaceName = null;
}
@Override
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_START:
mClientInterfaceName = mWifiNative.setupInterfaceForClientMode(true,
mWifiNativeInterfaceCallback);
if (TextUtils.isEmpty(mClientInterfaceName)) {
Log.e(TAG, "Failed to create ClientInterface. Sit in Idle");
updateWifiState(WifiManager.WIFI_STATE_UNKNOWN);
break;
}
// we have a new scanning interface, make sure scanner knows we aren't
// ready yet and clear out the ScanRequestProxy
sendScanAvailableBroadcast(false);
// explicitly disable scanning for hidden networks in case we were
// previously in client mode
mScanRequestProxy.enableScanningForHiddenNetworks(false);
mScanRequestProxy.clearScanResults();
transitionTo(mStartedState);
break;
default:
Log.d(TAG, "received an invalid message: " + message);
return NOT_HANDLED;
}
return HANDLED;
}
}
这里我们查看setupInterfaceForClientMode方法
frameworks\base\wifi\java\android\net\wifi\WifiManager.java
/**
* Setup an interface for Client mode operations.
*
* This method configures an interface in STA mode in all the native daemons
* (wificond, wpa_supplicant & vendor HAL).
*
* @param lowPrioritySta The requested STA has a low request priority (lower probability of
* getting created, higher probability of getting destroyed).
* @param interfaceCallback Associated callback for notifying status changes for the iface.
* @return Returns the name of the allocated interface, will be null on failure.
*/
public String setupInterfaceForClientMode(boolean lowPrioritySta,
@NonNull InterfaceCallback interfaceCallback) {
synchronized (mLock) {
if (!startHal()) {
Log.e(TAG, "Failed to start Hal");
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
return null;
}
if (!startSupplicant()) {
Log.e(TAG, "Failed to start supplicant");
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
return null;
}
Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA);
if (iface == null) {
Log.e(TAG, "Failed to allocate new STA iface");
return null;
}
iface.externalListener = interfaceCallback;
iface.name = createStaIface(iface, lowPrioritySta);
if (TextUtils.isEmpty(iface.name)) {
Log.e(TAG, "Failed to create STA iface in vendor HAL");
mIfaceMgr.removeIface(iface.id);
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
return null;
}
if (mWificondControl.setupInterfaceForClientMode(iface.name) == null) {
Log.e(TAG, "Failed to setup iface in wificond on " + iface);
teardownInterface(iface.name);
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
return null;
}
if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
Log.e(TAG, "Failed to setup iface in supplicant on " + iface);
teardownInterface(iface.name);
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
return null;
}
iface.networkObserver = new NetworkObserverInternal(iface.id);
if (!registerNetworkObserver(iface.networkObserver)) {
Log.e(TAG, "Failed to register network observer on " + iface);
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));
initializeNwParamsForClientInterface(iface.name);
Log.i(TAG, "Successfully setup " + iface);
return iface.name;
}
}
可以看到这是过去需要开启wifi的设备节点的地方,然后查看createStaIface方法
/**
* Helper function to handle creation of STA iface.
* For devices which do not the support the HAL, this will bypass HalDeviceManager &
* teardown any existing iface.
*/
private String createStaIface(@NonNull Iface iface, boolean lowPrioritySta) {
synchronized (mLock) {
if (mWifiVendorHal.isVendorHalSupported()) {
return mWifiVendorHal.createStaIface(lowPrioritySta,
new InterfaceDestoyedListenerInternal(iface.id));
} else {
Log.i(TAG, "Vendor Hal not supported, ignoring createStaIface.");
//通过打印LOG发现最终我这套代码是走到了这里
return handleIfaceCreationWhenVendorHalNotSupported(iface);
}
}
}
接着查看handleIfaceCreationWhenVendorHalNotSupported
// For devices that don't support the vendor HAL, we will not support any concurrency.
// So simulate the HalDeviceManager behavior by triggering the destroy listener for
// any active interface.
private String handleIfaceCreationWhenVendorHalNotSupported(@NonNull Iface newIface) {
synchronized (mLock) {
Iface existingIface = mIfaceMgr.removeExistingIface(newIface.id);
if (existingIface != null) {
onInterfaceDestroyed(existingIface);
Log.i(TAG, "Successfully torn down " + existingIface);
}
// Return the interface name directly from the system property.
return mPropertyService.getString("wifi.interface", "wlan0");
}
}
/** Helper method invoked to teardown iface and perform necessary cleanup */
private void onInterfaceDestroyed(@NonNull Iface iface) {
synchronized (mLock) {
if (iface.type == Iface.IFACE_TYPE_STA) {
onClientInterfaceDestroyed(iface);
} else if (iface.type == Iface.IFACE_TYPE_AP) {
onSoftApInterfaceDestroyed(iface);//这里最终执行了关闭热点
}
// Invoke the external callback.
iface.externalListener.onDestroyed(iface.name);
}
}
通过上述可以发现,我们只需要修改onInterfaceDestroyed handleIfaceCreationWhenVendorHalNotSupported createStaIface三个方法中的任何一个就可以让开wifi时不要不关闭热点,当然个人建议修改createStaIface方法