Android11 Wifi Mac地址设置随机或者固定分析

Android11 Wifi Mac地址设置随机或者固定分析

本文对Android11 wifi MAC地址设置是否随机问题进行分析。

文章目录

  • Android11 Wifi Mac地址设置随机或者固定分析
    • 一、前言
    • 二、Android11 修改wifi MAC地址是否随机的关键代码
    • 三、Android11 修改wifi MAC应用端可以操作的事情
      • 1、App中获取Wifi MAC地址代码
      • 2、App代码中设置 Wifi MAC是否随机
      • 四、Android11 修改wifi MAC地址是否随机的分析过程
        • 1、从WifiManager 更新wifi配置信息开始分析:
        • 2、MAC获取过程分析
        • 五、Android11 wifi MAC地址是分析总结

          一、前言

          Android 8.0 开始,设备开始支持Wifi 随机MAC,说是为了安全。

          很多手上也能看到Wifi 默认使用的是随机MAC地址。

          但是有些情况下,需要固定MAC,比如有些OTA升级用的是Wifi MAC地址,这时候就要MAC固定。

          所以有必要对设备 Wifi MAC地址进行研究。

          网上搜索了一下,只有下面这个需要csdn 付费的文章:

          https://blog.csdn.net/baidu_41666295/article/details/123014817

          上面文章主要修改在下面两个文件:

          frameworks/base/core/res/res/values/config.xml
          packages/apps/Settings/src/com/android/settings/wifi/WifiConfigController.java
          

          网上这个文章是Android10 的,文件位置和主要逻辑可能在其他版本有一定是变化。

          从目前接触的framework 网络部分代码来看,

          从Android9到10 ,Android11 到12代码变化挺大,代码位置和逻辑封装都有变化。

          所以掌握其中的原理,才能正常进行处理。

          下面从Android11 的代码,进行Wifi MAC地址是否随机变化的分析。

          二、Android11 修改wifi MAC地址是否随机的关键代码

          其实大部分情况就修改一个属性就行

          frameworks\opt\net\wifi\service\res\values\config.xml

          //WiFi MAC 是否随机设置  true //AP (一般是投屏) MAC 是否随机设置  false //AP (一般是热点) MAC 是否随机设置  true

          config_wifi_connected_mac_randomization_supported 属性值修改为 false ,就是不随机变化了!

          有些方案中是,有overlay 属性的,就需要在对应位置配置。

          当然也是可以在代码中添加打印查看了属性配置情况。

          具体分析在后面。

          三、Android11 修改wifi MAC应用端可以操作的事情

          1、App中获取Wifi MAC地址代码

           public String getWifiMacAddress() {
                  WifiManager mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
                  if (mWifiManager.isWifiEnabled()) {
                      WifiInfo mWifiInfo = mWifiManager.getConnectionInfo();
                      return mWifiInfo.getMacAddress();
                  }
                  return "Unavailable";
              }
          

          2、App代码中设置 Wifi MAC是否随机

           //设置mac是否随机
              public void updateNetworkRamon(boolean isRandom) {
                  WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
                  WifiInfo wifiInfo = wifiManager.getConnectionInfo();
                  String curWifiName = wifiInfo.getSSID(); //当前连接的wifi 名称
                  List configuredNetworks = wifiManager.getConfiguredNetworks();
                  for (WifiConfiguration wifiConfiguration : configuredNetworks) {
                      if (curWifiName.equals(wifiConfiguration.SSID)) {
                          String randomizedMacAddress = wifiConfiguration.getRandomizedMacAddress().toString();
                          int macRandomSetting = wifiConfiguration.macRandomizationSetting;
          				//修改mac是否随机
                          wifiConfiguration.macRandomizationSetting = isRandom
                                  ? WifiConfiguration.RANDOMIZATION_PERSISTENT //persistent 持续的,表示一直随机的MAC
                                  : WifiConfiguration.RANDOMIZATION_NONE; //不随机,表示固定的MAC
                          //update 配置信息
                          wifiManager.updateNetwork(wifiConfiguration);
                          wifiManager.disconnect();
                      }
                  }
              }
          

          系统虽然暴露了设置是否随机的接口方法,但是设置不一定有用!

          为啥没用?因为Wifi 配置管理的代码会优先判断配置属性,决定是否MAC地址随机,所以设置的值不一定起到作用。

          //下面这个地址包含了wifi配置信息的管理,比如MAC 地址的重新定义
          frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiConfigManager.java
          代码判断配置属性:R.bool.config_wifi_connected_mac_randomization_supported 
          如果ture,MAC地址默认随机,这时候通过接口设置MAC是否随机是有作用。
          如果false,MAC地址为固定的设备地址,通过接口设置MAC是否随机无作用。
          代码后续分析。
          

          从 wifiConfiguration 源码看,里面有设置随机MAC地址的方法,是hide的,应用无法调用,只能系统内部调用。

          wifiConfiguration.setRandomizedMacAddress( MacAddress.fromString("11:22:33:44:55:66"));
          

          但是也可以看出随机MAC 在系统内部是可以控制的。如果要定制成某个MAC地址是可以实现的。

          wifiConfiguration 就相当于一个Bean对象,扫描到的wifi列表,每个都有对应的wifiConfiguration 对象。

          Android11 中所有的wifi列表配置属性都是保存在文件:

          wifi信息保存位置:
          /data/misc/apexdata/com.android.wifi/WifiConfigStore.xml
          热点信息保存位置:
          /data/misc/apexdata/com.android.wifi/WifiConfigStoreSoftAp.xml
          

          四、Android11 修改wifi MAC地址是否随机的分析过程

          1、从WifiManager 更新wifi配置信息开始分析:

          frameworks\base\wifi\java\android\net\wifi\WifiManager.java

          WifiManager.updateNetwork(wifiConfiguration);

           public int updateNetwork(WifiConfiguration config) {
                  if (config == null || config.networkId < 0) {
                      return -1;
                  }
                  return addOrUpdateNetwork(config);
              }
              private int addOrUpdateNetwork(WifiConfiguration config) {
                  try {
                      return mService.addOrUpdateNetwork(config, mContext.getOpPackageName());
                  } catch (RemoteException e) {
                      throw e.rethrowFromSystemServer();
                  }
              }
          

          frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiServiceImpl.java

           public int addOrUpdateNetwork(WifiConfiguration config, String packageName) {
            ...
                  Log.i("addOrUpdateNetwork", " uid = " + Binder.getCallingUid()
                          + " SSID " + config.SSID
                          + " nid=" + config.networkId);
                  return mWifiThreadRunner.call(
                      () -> mWifiConfigManager.addOrUpdateNetwork(config, callingUid, packageName)
                              .getNetworkId(),
                          WifiConfiguration.INVALID_NETWORK_ID);
              }
          

          frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiConfigManager.java

           public NetworkUpdateResult addOrUpdateNetwork(WifiConfiguration config, int uid,
             @Nullable String packageName) {
            
                  WifiConfiguration existingConfig = getInternalConfiguredNetwork(config);
          ...
                  NetworkUpdateResult result = addOrUpdateNetworkInternal(config, uid, packageName);
                  if (!result.isSuccess()) {
                      Log.e(TAG, "Failed to add/update network " + config.getPrintableSsid());
                      return result;
                  }
                  WifiConfiguration newConfig = getInternalConfiguredNetwork(result.getNetworkId());
                  sendConfiguredNetworkChangedBroadcast(
                          result.isNewNetwork()
                                  ? WifiManager.CHANGE_REASON_ADDED
                                  : WifiManager.CHANGE_REASON_CONFIG_CHANGE);
                  // Unless the added network is ephemeral or Passpoint, persist the network update/addition.
                  if (!config.ephemeral && !config.isPasspoint()) {
                      saveToStore(true);//保存配置文件到本地
                  }
          		//更新数据到之前的所有监听
          		for (OnNetworkUpdateListener listener : mListeners) {
                      if (result.isNewNetwork()) {
                          listener.onNetworkAdded(
                                  createExternalWifiConfiguration(newConfig, true, Process.WIFI_UID));//有修改配置的地方
                      } else {
                          listener.onNetworkUpdated(
                                  createExternalWifiConfiguration(newConfig, true, Process.WIFI_UID),
                                  createExternalWifiConfiguration(existingConfig, true, Process.WIFI_UID));
                      }
                  }
                  return result;
              }
          	//返回提供给外部的wifi配置对象
              private WifiConfiguration createExternalWifiConfiguration(
                      WifiConfiguration configuration, boolean maskPasswords, int targetUid) {
                  WifiConfiguration network = new WifiConfiguration(configuration);
                  if (maskPasswords) {
                      maskPasswordsInWifiConfiguration(network);
                  }
                  if (targetUid != Process.WIFI_UID && targetUid != Process.SYSTEM_UID
                          && targetUid != configuration.creatorUid) {
                      maskRandomizedMacAddressInWifiConfiguration(network);
                  }
          		//重点:这里可以看到如果不是随机MAC,也就是设置false的情况,无法设置什么参数,最后MAC都是固定的
                  if (!isMacRandomizationSupported()) {
                      network.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE; //固定MAC
                  }
                  return network;
              }		
          	//判断wifi是否设置随机MAC
              private boolean isMacRandomizationSupported() {
                  return mContext.getResources().getBoolean(
                          R.bool.config_wifi_connected_mac_randomization_supported);
              }
          

          从上面代码可以看到设置 config_wifi_connected_mac_randomization_supported 属性,可以控制是否随机MAC的情况。

          R.bool.config_wifi_connected_mac_randomization_supported

          如果ture,MAC地址默认随机,这时候通过接口设置MAC是否随机是有作用。

          如果false,MAC地址为固定的设备地址,通过接口设置MAC是否随机无作用。

          这里每个wifi都有对应的WifiConfiguration 对象,

          如果要动态设置全局的Wifi MAC都随机或者固定,可以在 createExternalWifiConfiguration 方法中,添加prop属性,强制修改即可。

          另外上面addOrUpdateNetwork代码看,配置的属性是先保存到本地,之后再进行重新复制的,

          所以本地保存的配置文件,会与系统上的状态不一致。

          2、MAC获取过程分析

           WifiInfo mWifiInfo = mWifiManager.getConnectionInfo();
           mWifiInfo.getMacAddress();
          

          WifiManager.getConnectionInfo() --> WifiServiceImpl.getConnectionInfo()

           public WifiInfo getConnectionInfo(String callingPackage, String callingFeatureId) {
                  enforceAccessPermission();
                  int uid = Binder.getCallingUid();
                  if (mVerboseLoggingEnabled) {
                      mLog.info("getConnectionInfo uid=%").c(uid).flush();
                  }
                  long ident = Binder.clearCallingIdentity();
                  try {
                      WifiInfo result = mClientModeImpl.syncRequestConnectionInfo();
           
                      if (hideDefaultMacAddress) {
                          result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
                      }
          ...
                      return result;
                  } finally {
                      Binder.restoreCallingIdentity(ident);
                  }
              }
          

          frameworks\opt\net\wifi\service\java\com\android\server\wifi\ClientModeImpl.java

          //内部类,连接状态机,构造方法中监听
              class ConnectModeState extends State {
                  @Override
                  public void enter() { //wifi首次连接的情况
                      Log.d(TAG, "entering ConnectModeState: ifaceName = " + mInterfaceName);
                      mOperationalMode = CONNECT_MODE;
                      setupClientMode();
           ...
                  }
          		@Override
                  public boolean processMessage(Message message) {//保存、连接等处理
          		}
          	}
              /**
               * Helper method to start other services and get state ready for client mode
               */
              private void setupClientMode() {
                  Log.d(TAG, "setupClientMode() ifacename = " + mInterfaceName);
          ...
          		//如果MAC随机,就先设置MAC
                  if (isConnectedMacRandomizationEnabled()) {
                      mWifiNative.setMacAddress(mInterfaceName, MacAddressUtils.createRandomUnicastAddress()); //获取一个随机MAC地址,每次都是一个随机数
                  }
          		//获取刚才设置的MAC地址,设置到wifi对象中,所以随机MAC属性设置了的情况,获取到的是随机MAC,
          		//未设置的情况,获取的是节点的MAC,是设备的固定MAC
                  mWifiInfo.setMacAddress(mWifiNative.getMacAddress(mInterfaceName));
          ...
              }
          	//通过配置属性判断是否MAC随机
              public boolean isConnectedMacRandomizationEnabled() {
                  return mContext.getResources().getBoolean(
                          R.bool.config_wifi_connected_mac_randomization_supported);
              }
          

          上代码可以看到,wifi 配置获取到后会判断MAC地址是否随机,如果随机随把随机MAC设置到WifiInfo 对象中。

          五、Android11 wifi MAC地址是分析总结

          wifi 的MAC 地址是可以随机显示或者固定,可以根据需求进行开发设计。

          修改:frameworks\opt\net\wifi\service\res\values\config.xml 的

          config_wifi_connected_mac_randomization_supported 属性值修改为 false ,Wifi MAC地址不随机变化了!

          如果要固定wifi MAC地址进行定制设计,可以在 WifiConfigManager.java中进行。

          ps:无论是wifi MAC还是有线MAC/设备MAC都是6位的用冒号隔开的字符串类似: 02:ad:36:01:09:74