版权声明:本文为博主原创文章,未经授权禁止转载,O(∩_∩)O谢谢 https://blog.csdn.net/sinat_20059415/article/details/83928170
1.流程分析
1.1 WifiInfoPreferenceController
public void updateWifiInfo() {
if (mWifiMacAddressPref != null) {
final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
final String macAddress = wifiInfo == null ? null : wifiInfo.getMacAddress();
mWifiMacAddressPref.setSummary(!TextUtils.isEmpty(macAddress)
? macAddress
: mContext.getString(R.string.status_unavailable));
}
...
}
1.2 WifiManager
/**
* Return dynamic information about the current Wi-Fi connection, if any is active.
* <p>
* In the connected state, access to the SSID and BSSID requires
* the same permissions as {@link #getScanResults}. If such access is not allowed,
* {@link WifiInfo#getSSID} will return {@code "<unknown ssid>"} and
* {@link WifiInfo#getBSSID} will return {@code "02:00:00:00:00:00"}.
*
* @return the Wi-Fi information, contained in {@link WifiInfo}.
*/
public WifiInfo getConnectionInfo() {
try {
return mService.getConnectionInfo(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
1.3 WifiServiceImpl
/**
* See {@link android.net.wifi.WifiManager#getConnectionInfo()}
* @return the Wi-Fi information, contained in {@link WifiInfo}.
*/
@Override
public WifiInfo getConnectionInfo(String callingPackage) {
enforceAccessPermission();
mLog.info("getConnectionInfo uid=%").c(Binder.getCallingUid()).flush();
/*
* Make sure we have the latest information, by sending
* a status request to the supplicant.
*/
return mWifiStateMachine.syncRequestConnectionInfo(callingPackage);
}
1.4 WifiStateMachine
/**
* Get status information for the current connection, if any.
*
* @return a {@link WifiInfo} object containing information about the current connection
*/
public WifiInfo syncRequestConnectionInfo(String callingPackage) {
int uid = Binder.getCallingUid();
WifiInfo result = new WifiInfo(mWifiInfo);
if (uid == Process.myUid()) return result;
boolean hideBssidAndSsid = true;
result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
IPackageManager packageManager = AppGlobals.getPackageManager();
try {
if (packageManager.checkUidPermission(Manifest.permission.LOCAL_MAC_ADDRESS,
uid) == PackageManager.PERMISSION_GRANTED) {
result.setMacAddress(mWifiInfo.getMacAddress());
}
final WifiConfiguration currentWifiConfiguration = getCurrentWifiConfiguration();
if (mWifiPermissionsUtil.canAccessFullConnectionInfo(
currentWifiConfiguration,
callingPackage,
uid,
Build.VERSION_CODES.O)) {
hideBssidAndSsid = false;
}
} catch (RemoteException e) {
Log.e(TAG, "Error checking receiver permission", e);
} catch (SecurityException e) {
Log.e(TAG, "Security exception checking receiver permission", e);
}
if (hideBssidAndSsid) {
result.setBSSID(WifiInfo.DEFAULT_MAC_ADDRESS);
result.setSSID(WifiSsid.createFromHex(null));
}
return result;
}
如果当前进程有Manifest.permission.LOCAL_MAC_ADDRESS权限,则可以获取到当前WifiStateMachine缓存在WifiInfo里的mac地址。
那mac地址是如何缓存的呢?
class SupplicantStartingState extends State {
private void initializeWpsDetails() {
...
}
@Override
public boolean processMessage(Message message) {
logStateAndMessage(message, this);
switch(message.what) {
case WifiMonitor.SUP_CONNECTION_EVENT:
if (mVerboseLoggingEnabled) log("Supplicant connection established");
mSupplicantRestartCount = 0;
/* Reset the supplicant state to indicate the supplicant
* state is not known at this time */
mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
/* Initialize data structures */
mLastBssid = null;
mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
mLastSignalLevel = -1;
mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
...
break;
在supplicant启动后收到SUP_CONNECTION_EVENT连接完成的消息后从WifiNative中获取的。
1.5 WifiNative
/**
* Makes a callback to HIDL to getMacAddress from supplicant
*
* @return string containing the MAC address, or null on a failed call
*/
public String getMacAddress() {
return mSupplicantStaIfaceHal.getMacAddress();
}
1.6 SupplicantStaIfaceHal
/**
* Makes a callback to HIDL to getMacAddress from supplicant
*
* @return string containing the MAC address, or null on a failed call
*/
public String getMacAddress() {
synchronized (mLock) {
final String methodStr = "getMacAddress";
if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
Mutable<String> gotMac = new Mutable<>();
try {
mISupplicantStaIface.getMacAddress((SupplicantStatus status,
byte[/* 6 */] macAddr) -> {
if (checkStatusAndLogFailure(status, methodStr)) {
gotMac.value = NativeUtil.macAddressFromByteArray(macAddr);
}
});
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
}
return gotMac.value;
}
}
1.7 sta_iface.cpp
Return<void> StaIface::getMacAddress(getMacAddress_cb _hidl_cb)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::getMacAddressInternal, _hidl_cb);
}
std::pair<SupplicantStatus, std::array<uint8_t, 6>>
StaIface::getMacAddressInternal()
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
std::vector<char> cmd(
kGetMacAddress, kGetMacAddress + sizeof(kGetMacAddress));
char driver_cmd_reply_buf[4096] = {};
int ret = wpa_drv_driver_cmd(
wpa_s, cmd.data(), driver_cmd_reply_buf,
sizeof(driver_cmd_reply_buf));
// Reply is of the format: "Macaddr = XX:XX:XX:XX:XX:XX"
std::string reply_str = driver_cmd_reply_buf;
if (ret < 0 || reply_str.empty() ||
reply_str.find("=") == std::string::npos) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
// Remove all whitespace first and then split using the delimiter "=".
reply_str.erase(
remove_if(reply_str.begin(), reply_str.end(), isspace),
reply_str.end());
std::string mac_addr_str =
reply_str.substr(reply_str.find("=") + 1, reply_str.size());
std::array<uint8_t, 6> mac_addr;
if (hwaddr_aton(mac_addr_str.c_str(), mac_addr.data())) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""}, mac_addr};
}
1.8 driver_i.h
#ifdef ANDROID
static inline int wpa_drv_driver_cmd(struct wpa_supplicant *wpa_s,
char *cmd, char *buf, size_t buf_len)
{
if (!wpa_s->driver->driver_cmd)
return -1;
return wpa_s->driver->driver_cmd(wpa_s->drv_priv, cmd, buf, buf_len);
}
#endif /* ANDROID */
1.9 driver_cmd_nl80211.c
jiatai@jiatai:~/expand/aosp/aosp/external/wpa_supplicant_8$ grep "wpa_driver_nl80211_driver_cmd" ./ -nr
./src/drivers/driver_nl80211.c:10432: .driver_cmd = wpa_driver_nl80211_driver_cmd,
./src/drivers/driver_nl80211.h:277:extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
./device/google/cuttlefish_common/guest/libs/wpa_supplicant_8_lib/driver_cmd_nl80211.c
int wpa_driver_nl80211_driver_cmd(
void* priv, char* cmd, char* buf, size_t buf_len) {
struct i802_bss* bss = priv;
struct wpa_driver_nl80211_data* drv = bss->drv;
struct ifreq ifr;
android_wifi_priv_cmd priv_cmd;
int ret = 0;
D("%s: called", __FUNCTION__);
if (os_strcasecmp(cmd, "STOP") == 0) {
linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
} else if (os_strcasecmp(cmd, "START") == 0) {
linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
} else if (os_strcasecmp(cmd, "MACADDR") == 0) {
u8 macaddr[ETH_ALEN] = {};
ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr);
if (!ret)
ret = os_snprintf(
buf, buf_len, "Macaddr = " MACSTR "\n", MAC2STR(macaddr));
} else if (os_strcasecmp(cmd, "RELOAD") == 0) {
wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
} else { // Use private command
return 0;
}
return ret;
}
1.10 linux_ioctl.c
int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
{
struct ifreq ifr;
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(sock, SIOCGIFHWADDR, &ifr)) {
wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s",
ifname, strerror(errno));
return -1;
}
if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x",
ifname, ifr.ifr_hwaddr.sa_family);
return -1;
}
os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
return 0;
}
通过ioctl下发SIOCGIFHWADDR命令获取mac地址。