概述
Android WIFI 模块解析(2)
书接上文,这一章接着分析wifi
模块的Hal
层的调用逻辑.
public String setupInterfaceForClientMode(boolean lowPrioritySta,
@NonNull InterfaceCallback interfaceCallback) {
synchronized (mLock) {
//启动hal层.
if (!startHal()) {
Log.e(TAG, "Failed to start Hal");
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
return null;
}
//启动wpa_supplicant
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;
}
}
这是上一章中贴出的最后一个函数,本章我们重点分析startHal()
函数和startSupplicant()
函数.
startHal
调用过程
我们先追逐一下其代码过程
startHal
/** Helper method invoked to start supplicant if there were no ifaces */
private boolean startHal() {
synchronized (mLock) {
if (!mIfaceMgr.hasAnyIface()) {
//判断其是否当前的设备供应商Hal层是否可用
if (mWifiVendorHal.isVendorHalSupported()) {
//启动设备Hal
if (!mWifiVendorHal.startVendorHal()) {
Log.e(TAG, "Failed to start vendor HAL");
return false;
}
} else {
Log.i(TAG, "Vendor Hal not supported, ignoring start.");
}
}
return true;
}
}
WifiVendorHal
这个类注释是厂商hal层对HIDL
的支持,HIDL
的发音hide-l
.后文专门解释一下这个东西
/**
* Vendor HAL via HIDL
*/
public class WifiVendorHal {
...
/**
* Bring up the HIDL 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;
}
}
...
}
HalDeviceManager
/**
* Handles device management through the HAL (HIDL) interface.
*/
public class HalDeviceManager {
/**
* Attempts to start Wi-Fi (using HIDL). Returns the success (true) or failure (false) or
* the start operation. Will also dispatch any registered ManagerStatusCallback.onStart() on
* success.
*
* Note: direct call to HIDL.
*/
public boolean start() {
return startWifi();
}
private boolean startWifi() {
if (VDBG) Log.d(TAG, "startWifi");
synchronized (mLock) {
try {
if (mWifi == null) {
Log.w(TAG, "startWifi called but mWifi is null!?");
return false;
} else {
int triedCount = 0;
while (triedCount <= START_HAL_RETRY_TIMES) {
//在这里
WifiStatus status = mWifi.start();
if (status.code == WifiStatusCode.SUCCESS) {
initIWifiChipDebugListeners();
managerStatusListenerDispatch();
if (triedCount != 0) {
Log.d(TAG, "start IWifi succeeded after trying "
+ triedCount + " times");
}
return true;
} else if (status.code == WifiStatusCode.ERROR_NOT_AVAILABLE) {
// Should retry. Hal might still be stopping.
Log.e(TAG, "Cannot start IWifi: " + statusString(status)
+ ", Retrying...");
try {
Thread.sleep(START_HAL_RETRY_INTERVAL_MS);
} catch (InterruptedException ignore) {
// no-op
}
triedCount++;
} else {
// Should not retry on other failures.
Log.e(TAG, "Cannot start IWifi: " + statusString(status));
return false;
}
}
Log.e(TAG, "Cannot start IWifi after trying " + triedCount + " times");
return false;
}
} catch (RemoteException e) {
Log.e(TAG, "startWifi exception: " + e);
return false;
}
}
}
}
在这里我们看到mWifi
这个对象去调用了start()
函数通过hal
层去启动与内核通信.那么mWifi
这个对象在何时创建.
import android.hardware.wifi.V1_0.IWifi;
/**
* Wrapper function to access the HIDL services. Created to be mockable in unit-tests.
*/
protected IWifi getWifiServiceMockable() {
try {
return IWifi.getService();
} catch (RemoteException e) {
Log.e(TAG, "Exception getting IWifi service: " + e);
return null;
}
}
我们看下IWifi到底是何物
IWifi
package android.hardware.wifi@1.0;
import IWifiChip;
import IWifiEventCallback;
/**
* This is the root of the HAL module and is the interface returned when
* loading an implementation of the Wi-Fi HAL. There must be at most one
* module loaded in the system.
*/
interface IWifi {
/**
* Requests notifications of significant events for the HAL. Multiple calls to
* this must register multiple callbacks each of which must receive all
* events. |IWifiEventCallback| object registration must be independent of the
* state of the rest of the HAL and must persist though stops/starts. These
* objects must be deleted when the corresponding client process is dead.
*
* @param callback An instance of the |IWifiEventCallback| HIDL interface
* object.
* @return status WifiStatus of the operation.
* Possible status codes:
* |WifiStatusCode.SUCCESS|,
* |WifiStatusCode.UNKNOWN|
*/
@entry
@callflow(next={"*"})
registerEventCallback(IWifiEventCallback callback)
generates (WifiStatus status);
/**
* Get the current state of the HAL.
*
* @return started true if started, false otherwise.
*/
isStarted() generates (bool started);
/**
* Perform any setup that is required to make use of the module. If the module
* is already started then this must be a noop.
* Must trigger |IWifiEventCallback.onStart| on success.
*
* @return status WifiStatus of the operation.
* Possible status codes:
* |WifiStatusCode.SUCCESS|,
* |WifiStatusCode.NOT_AVAILABLE|,
* |WifiStatusCode.UNKNOWN|
*/
@entry
@callflow(next={"registerEventCallback", "start", "stop", "getChip"})
start() generates (WifiStatus status);
/**
* Tear down any state, ongoing commands, etc. If the module is already
* stopped then this must be a noop. If the HAL is already stopped or it
* succeeds then onStop must be called. After calling this all IWifiChip
* objects will be considered invalid.
* Must trigger |IWifiEventCallback.onStop| on success.
* Must trigger |IWifiEventCallback.onFailure| on failure.
*
* Calling stop then start is a valid way of resetting state in the HAL,
* driver, firmware.
*
* @return status WifiStatus of the operation.
* Possible status codes:
* |WifiStatusCode.SUCCESS|,
* |WifiStatusCode.NOT_STARTED|,
* |WifiStatusCode.UNKNOWN|
*/
@exit
@callflow(next={"registerEventCallback", "start", "stop"})
stop() generates (WifiStatus status);
...
};
WIFI HAL 总结
IWifi.hal
文件位于hardware/interfaces/wifi/1.0/
,这个取决于厂商使用的版本.前文在HalDeviceManager
使用IWifi.getService();
这样的方式来获取服务,那么我们就会很疑惑,服务注册在何处,代码在何方.
问题的关键呢就在这个hal
文件中,它通过BP文件会生成Java
和C++
的模板代码,在bp文件中有不同的配置项配置它的生成代码.也可以自己通过命令去生成代码.
hidl-gen
工具路径在代码路径下out/host/linux-x86/bin/
路径下.可以通过hidl-gen -help
命令查看对于参数.但是这个东西在android 10
有被google
抛弃,改用了AIDL
方式.所以对这块就没有更深入的探究下去.
关于HIDL的官方介绍
简单的贴一下编译后的C++
的注册代码
int main(int /*argc*/, char** argv) {
android::base::InitLogging(
argv, android::base::LogdLogger(android::base::SYSTEM));
LOG(INFO) << "Wifi Hal is booting up...";
configureRpcThreadpool(1, true /* callerWillJoin */);
// Setup hwbinder service 这个是1_2版本的注册代码,不是上文中的1_0的版本,但是注册的地吗几乎是一致的,作为参考查看
android::sp<android::hardware::wifi::V1_2::IWifi> service =
new android::hardware::wifi::V1_2::implementation::Wifi(
std::make_shared<WifiLegacyHal>(),
std::make_shared<WifiModeController>(),
std::make_shared<WifiFeatureFlags>());
CHECK_EQ(service->registerAsService(), android::NO_ERROR)
<< "Failed to register wifi HAL";
joinRpcThreadpool();
LOG(INFO) << "Wifi Hal is terminating...";
return 0;
}
在这一块的参考资料确实有点少,理解也不够深入,举个例子
/**
* Perform any setup that is required to make use of the module. If the module
* is already started then this must be a noop.
* Must trigger |IWifiEventCallback.onStart| on success.
*
* @return status WifiStatus of the operation.
* Possible status codes:
* |WifiStatusCode.SUCCESS|,
* |WifiStatusCode.NOT_AVAILABLE|,
* |WifiStatusCode.UNKNOWN|
*/
android.hardware.wifi.V1_0.WifiStatus start()
throws android.os.RemoteException;
上面是tart()
函数生成的JAvA
代码,下文是生成的C++的代码,没有搞清楚在C++
代码start
函数中的 _hidl_cb
参数从和而来,这个参数在后面的实际调用中也有用到.感兴趣的朋友,可以自己在深入的看下去,如果有答案了,有条件的话也告诉我一下.
/**
* Perform any setup that is required to make use of the module. If the module
* is already started then this must be a noop.
* Must trigger |IWifiEventCallback.onStart| on success.
*
* @return status WifiStatus of the operation.
* Possible status codes:
* |WifiStatusCode.SUCCESS|,
* |WifiStatusCode.NOT_AVAILABLE|,
* |WifiStatusCode.UNKNOWN|
*/
virtual ::android::hardware::Return<void> start(start_cb _hidl_cb) = 0;
startSupplicant
在成功的通过HAL层
代码启动wifi
设备之后,代码就可以去调用了startSupplicant()
函数,那么这个东西是干什么的,HAL层
对外提供了start
,stop
,getChipIds
,和注册回调函数等方案,其他并未提供,也就是说只有硬件相关的型号,和启动,暂停等关键函数,关于wifi
的链接维护等函数并未提供,startSupplicant
启动的就是wpa_sulicant
.
wpa_sulicant
wpa_sulicant
是一个开源项目,被google
经过修改加入到Android
系统当中.主要支持WPA,EAP,无线网卡和驱动.有兴趣致力于研究wifi
相关的朋友可以研究一下这个东西,本文浅尝辄止.
wpa_sulicant官网
一个很不错的讲解网站
调用过程
startSupplicant
/** Helper method invoked to start supplicant if there were no STA ifaces */
private boolean startSupplicant() {
synchronized (mLock) {
if (!mIfaceMgr.hasAnyStaIface()) {
//这里
if (!mWificondControl.enableSupplicant()) {
Log.e(TAG, "Failed to enable supplicant");
return false;
}
if (!waitForSupplicantConnection()) {
Log.e(TAG, "Failed to connect to supplicant");
return false;
}
if (!mSupplicantStaIfaceHal.registerDeathHandler(
new SupplicantDeathHandlerInternal())) {
Log.e(TAG, "Failed to register supplicant death handler");
return false;
}
}
return true;
}
}
/**
* Enable wpa_supplicant via wificond.
* @return Returns true on success.
*/
public boolean enableSupplicant() {
if (!retrieveWificondAndRegisterForDeath()) {
return false;
}
try {
//这里
return mWificond.enableSupplicant();
} catch (RemoteException e) {
Log.e(TAG, "Failed to enable supplicant due to remote exception");
}
return false;
}
可以看到最终启动wpa_supplicant
使用一个wificond
的一个对象.我们看下它是怎么获取的.
WifiInjector
private static final String WIFICOND_SERVICE_NAME = "wificond";
public IWificond makeWificond() {
// We depend on being able to refresh our binder in WifiStateMachine, so don't cache it.
IBinder binder = ServiceManager.getService(WIFICOND_SERVICE_NAME);
return IWificond.Stub.asInterface(binder);
}
也是通过binder
的形式进行通信,那么wificond
服务是何时注册到ServiceManager
中的呢.接着往下看
wificond
include $(CLEAR_VARS)
LOCAL_MODULE := wificond
LOCAL_CPPFLAGS := $(wificond_cpp_flags)
LOCAL_INIT_RC := wificond.rc
LOCAL_C_INCLUDES := $(wificond_includes)
LOCAL_SRC_FILES :=
main.cpp
LOCAL_SHARED_LIBRARIES :=
android.hardware.wifi.offload@1.0
libbinder
libbase
libcutils
libhidlbase
libhidltransport
libminijail
libutils
libwifi-system
libwifi-system-iface
LOCAL_STATIC_LIBRARIES :=
libwificond
include $(BUILD_EXECUTABLE)
这个是system/connectivity/wificond/android.mk
中的一段,大意就是编译一个Natvie C的可执行文件,module
为wificond
.
在对应的main.cpp
我们找到了注册服务的代码
int main(int argc, char** argv) {
...
RegisterServiceOrCrash(server.get());
event_dispatcher->Poll();
LOG(INFO) << "wificond is about to exit";
return 0;
}
void RegisterServiceOrCrash(const android::sp<android::IBinder>& service) {
android::sp<android::IServiceManager> sm = android::defaultServiceManager();
CHECK_EQ(sm != NULL, true) << "Could not obtain IServiceManager";
//这里addService到ServiceManager中
CHECK_EQ(sm->addService(android::String16(kServiceName), service),
android::NO_ERROR);
}
那么它是在什么时候执行这个main.cpp
呢,跟同事讨论这个问题时,猜测
- 在开机流程中有一段代码是会执行所有服务的
main()
函数.(未经确认,我还没有仔细的梳理过开机流程).
不过我在init.zygote
文件找到这样一段脚本文件
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
如果和推测一致呢就是在开机流程中已经执行了,在这里用restart
确保其一定被启动.负责无法理解要用 restart
去启动.好,解释了服务在何时注册,何时启动之后,我们接着往下看他是怎么启动wpa_supplicant
.
Status Server::enableSupplicant(bool* success) {
//这里,接着寻找 supplicant_manager_
*success = supplicant_manager_->StartSupplicant();
return Status::ok();
}
supplicant_manager
- 代码路径
frameworks/opt/net/wifi/libwifi_system/supplicant_manager.cpp
在这里呢就简单的分析一下它的启动代码
namespace {
const char kSupplicantInitProperty[] = "init.svc.wpa_supplicant";
const char kSupplicantServiceName[] = "wpa_supplicant";
} // namespace
bool SupplicantManager::StartSupplicant() {
char supp_status[PROPERTY_VALUE_MAX] = {'