复习并记录下android wifi相关知识,因为下载的是androidp 的source code,因此codebase就用androidP的版本,复习整个android wifi的flow,我大概会分为以下几个部分来讲解
1 android wifi enable flow
2 androi wifi scanning flow
3 android wifi user connect flow
4 android wifi auto connect flow
5 android network type swtich flow
.....
暂时想写的有上面这些,后续想到了再补充
今天这篇来写一下android wifi enable flow
android 发展到现在,wifi flow 从android N开始实际上已经开始了有了很多的变化,可以说整个架构都已经和原来的不一样了。上层与wpa_supplicant 之间 IPC也在将unix socket (android domain socket) 替换成hidl 方式。更有scan get_scan_result这些都是直接建立netlink socket 与kernel 通信而不通过wpa_supplicant。
首先先看下Wifiservice的注册,以及开机自动检测wifi的开启或关闭流程如下:
一般获取WifiManager有两种方式,
1 mWifiManager = mWifiManager = new WifiManager(mContext, mWifiService, mLooper.getLooper());
2 WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE )
第一种比较好理解,就是new一个WifiManager的实例,而第二种实际上也是new 一个WifiManager的实例,只不过是
这个new 实例的过程是在framework层做的,而不是在app层做的.以下讲解下这个流程,先上图,再解析source code
SystemServiceRegistry
registerService(Context.WIFI_SERVICE, WifiManager.class,
new CachedServiceFetcher<WifiManager>() {
@Override
public WifiManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_SERVICE);
IWifiManager service = IWifiManager.Stub.asInterface(b);
return new WifiManager(ctx.getOuterContext(), service,
ConnectivityThread.getInstanceLooper());
}});
而registerService,实际上就是把该类与名称对应存入map中
/**
* Statically registers a system service with the context.
* This method must be called during static initialization only.
*/
private static <T> void registerService(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
使用如下接口获取WifiManger实例mContext.getSystemService(Context.WIFI_SERVICE )则是从map表中查找
Context.java
public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);
==>
ContextWrapper.java
@Override
public Object getSystemService(String name) {
return mBase.getSystemService(name);
}
==>
ConttextImpl.java
1738 @Override
1739 public Object getSystemService(String name) {
1740 return SystemServiceRegistry.getSystemService(this, name);
1741 }
==>SystemServiceRegistry
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
则是用service name在之前注册的map里查找类WifiManger
UI上面打开wifi的flow 如下
app层会调用到WifiManager的接口
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
通过binder 继而call到 WifiServiceImpl.java
public synchronized boolean setWifiEnabled(String packageName, boolean enable)
throws RemoteException {
if (enforceChangePermission(packageName) != MODE_ALLOWED) {
return false;
}
//打印出uid和apk名称,便于debug
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;
}
//权限检测,详细可参照另一篇文章
//https://blog.csdn.net/lpboss/article/details/86610726
/*
* 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_STAT