(一百零五)Android O 获取mac地址流程分析

版权声明:本文为博主原创文章,未经授权禁止转载,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地址。



2.总结

猜你喜欢

转载自blog.csdn.net/sinat_20059415/article/details/83928170