概述
记一次rk平台热点打开流程追踪记录
问题描述
rk平台偶现热点打开失败,错误日志如下:
I/android.hardware.wifi@1.0-service: Starting legacy HAL
E/android.hardware.wifi@1.0-service: Could not set interface flags for wlan0 (Operation not permitted)
E/android.hardware.wifi@1.0-service: Failed to set WiFi interface up
E/android.hardware.wifi@1.0-service: Failed to start legacy HAL: UNKNOWN
E/HalDevMgr: executeChipReconfiguration: configureChip error: 9 (unknown)
E/WifiVendorHal: Failed to create AP iface
E/WifiNative: Failed to create AP iface in vendor HAL
E/SoftApManager: setup failure when creating ap interface.
V/WifiManager: SoftApCallbackProxy: onStateChanged: state=14, failureReason=0
E/WifiController: SoftAP start failed
故借此机会准备从Java层开始学习热点的打开流程
开始
1.首先,我们要打开热点,调用是ConnectivityManager中的如下方法:
public void startTethering(int type, boolean showProvisioningUi,
final OnStartTetheringCallback callback, Handler handler) {
Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
ResultReceiver wrappedCallback = new ResultReceiver(handler) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode == TETHER_ERROR_NO_ERROR) {
callback.onTetheringStarted();
} else {
callback.onTetheringFailed();
}
}
};
try {
String pkgName = mContext.getOpPackageName();
Log.i(TAG, "startTethering caller:" + pkgName);
mService.startTethering(type, wrappedCallback, showProvisioningUi, pkgName);
} catch (RemoteException e) {
Log.e(TAG, "Exception trying to start tethering.", e);
wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null);
}
}
此方法有四个参数:
type:热点类型,有三种TETHERING_WIFI、TETHERING_USB、TETHERING_BLUETOOTH(一般我们用到的个人热点就是TETHERING_WIFI)
showProvisioningUi:当设置为true是,将展示一个类似使用帮助的页面(需要厂商自己实现)
callback:热点打开结果的回调
handler:可以指定执行上面回调函数的线程
2.找到ConnectivityService的startTethering方法
@Override
public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
String callerPkg) {
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
if (!isTetheringSupported()) {
receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
return;
}
mTethering.startTethering(type, receiver, showProvisioningUi);
}
显示权限检查,注释已经写的很明白了,之后判断是否支持热点,之后就调到了Tethering中的startTethering方法
public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
if (!isTetherProvisioningRequired()) {//当没有定义热点UI时就会直接打开热点
enableTetheringInternal(type, true, receiver);
return;
}
if (showProvisioningUi) {
runUiTetherProvisioningAndEnable(type, receiver);
} else {
runSilentTetherProvisioningAndEnable(type, receiver);
}
}
接下来看enableTetheringInternal方法
/**
* Enables or disables tethering for the given type. This should only be called once
* provisioning has succeeded or is not necessary. It will also schedule provisioning rechecks
* for the specified interface.
*/
private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
boolean isProvisioningRequired = enable && isTetherProvisioningRequired();
int result;
switch (type) {
case TETHERING_WIFI:
result = setWifiTethering(enable);
if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
scheduleProvisioningRechecks(type);
}
sendTetherResult(receiver, result);
break;
case TETHERING_USB:
result = setUsbTethering(enable);
if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
scheduleProvisioningRechecks(type);
}
sendTetherResult(receiver, result);
break;
case TETHERING_BLUETOOTH:
setBluetoothTethering(enable, receiver);
break;
default:
Log.w(TAG, "Invalid tether type.");
sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
}
}
主要看TETHERING_WIFI
private int setWifiTethering(final boolean enable) {
int rval = TETHER_ERROR_MASTER_ERROR;
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mPublicSync) {
mWifiTetherRequested = enable;
final WifiManager mgr = getWifiManager();
if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
(!enable && mgr.stopSoftAp())) {
rval = TETHER_ERROR_NO_ERROR;
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
return rval;
}
3.找到startSoftAp的实现,在WifiServiceImpl.java中
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
/**
* see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
* @param wifiConfig SSID, security and channel details as part of WifiConfiguration
* @return {@code true} if softap start was triggered
* @throws SecurityException if the caller does not have permission to start softap
*/
@Override
public boolean startSoftAp(WifiConfiguration wifiConfig) {
// NETWORK_STACK is a signature only permission.
enforceNetworkStackPermission();
mLog.info("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
synchronized (mLocalOnlyHotspotRequests) {
// If a tethering request comes in while we have LOHS running (or requested), call stop
// for softap mode and restart softap with the tethering config.
if (!mLocalOnlyHotspotRequests.isEmpty()) {
stopSoftApInternal();
}
return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED);
}
}
/**
* Internal method to start softap mode. Callers of this method should have already checked
* proper permissions beyond the NetworkStack permission.
*/
private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
mLog.trace("startSoftApInternal uid=% mode=%")
.c(Binder.getCallingUid()).c(mode).flush();
// null wifiConfig is a meaningful input for CMD_SET_AP
if (wifiConfig == null || WifiApConfigStore.validateApWifiConfiguration(wifiConfig)) {
SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig);
return true;
}
Slog.e(TAG, "Invalid WifiConfiguration");
return false;
}
4.接着到WifiController.java这是个状态机,真正操作打开热点是在WifiStateMachinePrime.java中:
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachinePrime.java
/**
* Method to enable soft ap for wifi hotspot.
*
* The supplied SoftApModeConfiguration includes the target softap WifiConfiguration (or null if
* the persisted config is to be used) and the target operating mode (ex,
* {@link WifiManager.IFACE_IP_MODE_TETHERED} {@link WifiManager.IFACE_IP_MODE_LOCAL_ONLY}).
*
* @param wifiConfig SoftApModeConfiguration for the hostapd softap
*/
public void enterSoftAPMode(@NonNull SoftApModeConfiguration wifiConfig) {
mHandler.post(() -> {
startSoftAp(wifiConfig);
});
}
private void startSoftAp(SoftApModeConfiguration softapConfig) {
Log.d(TAG, "Starting SoftApModeManager");
WifiConfiguration config = softapConfig.getWifiConfiguration();
if (config != null && config.SSID != null) {
Log.d(TAG, "Passing config to SoftApManager! " + config);
} else {
config = null;
}
SoftApCallbackImpl callback = new SoftApCallbackImpl();
ActiveModeManager manager = mWifiInjector.makeSoftApManager(callback, softapConfig);
callback.setActiveModeManager(manager);
manager.start();
mActiveModeManagers.add(manager);
updateBatteryStatsWifiState(true);
}
5.找到SoftApManager.java的start()方法:
frameworks/opt/net/wifi/service/java/com/android/server/wifi/SoftApManager.java
/**
* Start soft AP with the supplied config.
*/
public void start() {
mStateMachine.sendMessage(SoftApStateMachine.CMD_START, mApConfig);
}
又一个状态机
private class IdleState extends State {
@Override
public void enter() {
mApInterfaceName = null;
mIfaceIsUp = false;
}
@Override
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_START:
Log.e(TAG, "CMD_START.");
mApInterfaceName = mWifiNative.setupInterfaceForSoftApMode(
mWifiNativeInterfaceCallback);
if (TextUtils.isEmpty(mApInterfaceName)) {
Log.e(TAG, "setup failure when creating ap interface.");
updateApState(WifiManager.WIFI_AP_STATE_FAILED,
WifiManager.WIFI_AP_STATE_DISABLED,
WifiManager.SAP_START_FAILURE_GENERAL);
mWifiMetrics.incrementSoftApStartResult(
false, WifiManager.SAP_START_FAILURE_GENERAL);
break;
}
updateApState(WifiManager.WIFI_AP_STATE_ENABLING,
WifiManager.WIFI_AP_STATE_DISABLED, 0);
int result = startSoftAp((WifiConfiguration) message.obj);
if (result != SUCCESS) {
int failureReason = WifiManager.SAP_START_FAILURE_GENERAL;
if (result == ERROR_NO_CHANNEL) {
failureReason = WifiManager.SAP_START_FAILURE_NO_CHANNEL;
}
updateApState(WifiManager.WIFI_AP_STATE_FAILED,
WifiManager.WIFI_AP_STATE_ENABLING,
failureReason);
stopSoftAp();
mWifiMetrics.incrementSoftApStartResult(false, failureReason);
break;
}
transitionTo(mStartedState);
break;
default:
// Ignore all other commands.
break;
}
return HANDLED;
}
}
6.setupInterfaceForSoftApMode方法,此处就比较重要了,需要逐条分析:
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
/**
* Setup an interface for Soft AP mode operations.
*
* This method configures an interface in AP mode in all the native daemons
* (wificond, wpa_supplicant & vendor HAL).
*
* @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 setupInterfaceForSoftApMode(@NonNull InterfaceCallback interfaceCallback) {
Log.e(TAG,"setupInterfaceForSoftApMode");
synchronized (mLock) {
if (!startHal()) {
Log.e(TAG, "Failed to start Hal");
mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
return null;
}
Log.e(TAG, "liyang Hal start success");
Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_AP);
if (iface == null) {
Log.e(TAG, "Failed to allocate new AP iface");
return null;
}
iface.externalListener = interfaceCallback;
iface.name = createApIface(iface);
if (TextUtils.isEmpty(iface.name)) {
Log.e(TAG, "Failed to create AP iface in vendor HAL");
mIfaceMgr.removeIface(iface.id);
mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
return null;
}
if (mWificondControl.setupInterfaceForSoftApMode(iface.name) == null) {
Log.e(TAG, "Failed to setup iface in wificond on " + iface);
teardownInterface(iface.name);
mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToWificond();
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;
}
// Just to avoid any race conditions with interface state change callbacks,
// update the interface state before we exit.
onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
Log.i(TAG, "Successfully setup " + iface);
return iface.name;
}
}
7先看startHal()方法:
/** Helper method invoked to start supplicant if there were no ifaces */
private boolean startHal() {
synchronized (mLock) {
if (!mIfaceMgr.hasAnyIface()) {
if (mWifiVendorHal.isVendorHalSupported()) {
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;
}
}
首次进来,还未调用 allocateIface 方法,所以 mIfaceMgr.hasAnyIface() 为 false,
同时mWifiVendorHal.isVendorHalSupported()也必然为true,接着就到了WifiVendorHal.java中:
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiVendorHal.java
/**
* Bring up the HIDL Vendor HAL and configure for AP (Access Point) mode
*
* @return true for success
*/
public boolean startVendorHalAp() {
synchronized (sLock) {
if (!startVendorHal()) {
return false;
}
if (TextUtils.isEmpty(createApIface(null))) {
stopVendorHal();
return false;
}
return true;
}
}
/**
* 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;
}
}
frameworks/opt/net/wifi/service/java/com/android/server/wifi/HalDeviceManager.java
/**
* 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() 开始就到了native层
hardware/interfaces/wifi/1.2/default/wifi.cpp
Return<void> Wifi::start(start_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
&Wifi::startInternal, hidl_status_cb);
}
WifiStatus Wifi::startInternal() {
if (run_state_ == RunState::STARTED) {
return createWifiStatus(WifiStatusCode::SUCCESS);
} else if (run_state_ == RunState::STOPPING) {
return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
"HAL is stopping");
}
WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
if (wifi_status.code == WifiStatusCode::SUCCESS) {
// Create the chip instance once the HAL is started.
chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_,
feature_flags_);
run_state_ = RunState::STARTED;
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onStart().isOk()) {
LOG(ERROR) << "Failed to invoke onStart callback";
};
}
LOG(INFO) << "Wifi HAL started";
} else {
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onFailure(wifi_status).isOk()) {
LOG(ERROR) << "Failed to invoke onFailure callback";
}
}
LOG(ERROR) << "Wifi HAL start failed";
}
return wifi_status;
}
WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
if (!mode_controller_->initialize()) {
LOG(ERROR) << "Failed to initialize firmware mode controller";
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
legacy_hal::wifi_error legacy_status = legacy_hal_->initialize();
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to initialize legacy HAL: "
<< legacyErrorToString(legacy_status);
return createWifiStatusFromLegacyError(legacy_status);
}
return createWifiStatus(WifiStatusCode::SUCCESS);
}
hardware/interfaces/wifi/1.2/default/wifi_mode_controller.cpp
bool WifiModeController::initialize() {
if (!driver_tool_->LoadDriver()) {
LOG(ERROR) << "Failed to load WiFi driver";
return false;
}
return true;
}
framework/opt/net/wifi/lbwifi_hal/driver_tool.cpp
bool DriverTool::LoadDriver() {
return ::wifi_load_driver() == 0;
}
frameworks/opt/net/wifi/libwifi_hal/wifi_hal_common.cpp
int wifi_load_driver() {
#ifdef WIFI_DRIVER_MODULE_PATH
char* wifi_ko_path = NULL ;
char* wifi_ko_arg =NULL;
int i = 0;
int count = 100;
if (is_wifi_driver_loaded()) {
return 0;
}
if (wifi_type[0] == 0) {
check_wifi_chip_type_string(wifi_type);
save_wifi_chip_type(wifi_type);
}
for (i=0; i< (int)(sizeof(module_list) / sizeof(module_list[0])); i++) {
if (!strcmp(wifi_type , module_list[i].wifi_name)) {
wifi_ko_path = module_list[i].wifi_module_path;
wifi_ko_arg = module_list[i].wifi_module_arg;
PLOG(ERROR) << "matched ko file path " << wifi_ko_path;
break;
}
}
if (wifi_ko_path == NULL) {
PLOG(ERROR) << "falied to find wifi driver for type=" << wifi_type;
return -1;
}
if (strstr(wifi_ko_path, MVL_DRIVER_MODULE_NAME)) {
insmod(MLAN_DRIVER_MODULE_PATH, "");
}
if (insmod(wifi_ko_path, wifi_ko_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) return -1;
#endif
while (count-- > 0) {
if (is_wifi_driver_loaded()) {
property_set(DRIVER_PROP_NAME, "ok");
return 0;
}
usleep(200000);
}
property_set(DRIVER_PROP_NAME, "timeout");
return -1;
}
这里面就开始加载wlan0模块,并通过检测/proc/net/dev节点中是否存在wlan0判断是否加载完成,具体模块的初始化在:
kernel/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c
dhd_module_init(void)
{
int err;
int retry = 0;
printf("%s: in %sn", __FUNCTION__, dhd_version);
DHD_PERIM_RADIO_INIT();
if (firmware_path[0] != '