当前位置: 移动技术网 > IT编程>开发语言>Java > Android81.从软件层固定wifi mac地址方法

Android81.从软件层固定wifi mac地址方法

2020年08月11日  | 移动技术网IT编程  | 我要评论
最近做一个Android8.1机器,客户懒惰得不想用工具写WIFI mac地址,又不希望每次重启WIFI mac地址都会变化,想要固定下来。网上搜索了一圈,没找到一个有效可行的方法,还是自己老实跟代码吧。 思路:找到系统是在哪里读写mac地址,然后将第一次开机随机生成的地址写入nvram,应该就能实现固定。 所以首先得找到系统怎么获取显示随机mac地址的: 首先知道设置里关于手机---状态信息里有WIFI MAC地址显示这个是在Status.java里具体实现...

最近做一个Android8.1机器,客户懒惰得不想用工具写WIFI mac地址,又不希望每次重启WIFI  mac地址都会变化,想要固定下来。网上搜索了一圈,没找到一个有效可行的方法,还是自己老实跟代码吧。

思路:找到系统是在哪里读写mac地址,然后将第一次开机随机生成的地址写入nvram,应该就能实现固定。

所以首先得找到系统怎么获取显示随机mac地址的:

首先知道设置里关于手机---状态信息里有WIFI  MAC地址显示这个是在Status.java里具体实现如下:

private void setWifiStatus() {
WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
boolean hasMacAddress = wifiInfo != null && wifiInfo.hasRealMacAddress();

//这里获取了一个WiFiInfo对象,然后getMacAddress.
String macAddress = hasMacAddress ? wifiInfo.getMacAddress() : null;
mWifiMacAddress.setSummary(!TextUtils.isEmpty(macAddress)
? mExt.customizeMacAddressString(macAddress, mUnavailable)
: mUnavailable);
}

查看WiFiInfo.java

/**
* Record the MAC address of the WLAN interface
* @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
* @hide
*/
public void setMacAddress(String macAddress) { //mac地址从设置方法传入的,搜索wifi模块setMacAddress方法
this.mMacAddress = macAddress;
}

public String getMacAddress() {
return mMacAddress;
}

找到是在WifiStateMachine.java中有设置,找到有好几个地方有设置,不过其他地方都是设置默认的一个地址,唯独这里:

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;

///可以看到是从WiFiNative里获取设置进去的。

mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
initializeWpsDetails();
sendSupplicantConnectionChangedBroadcast(true);
///M: ALPS03503585 Disable EAP-SIM AP if modem is not ready
MtkEapSimUtility.disableSimConfigWhenSimNotLoaded();
transitionTo(mSupplicantStartedState);

查看WifiNative.java:

public String getMacAddress() {
return mSupplicantStaIfaceHal.getMacAddress();
}

SupplicantStaIfaceHal.java

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;
}
}

Native 最终跟到的接口在:

vendor\mediatek\proprietary\hardware\interfaces\nvram\1.0\INvram.hal中分别定义了

interface INvram {
readFileByName(string filename, uint32_t size)
generates (string data);
writeFileByNamevec(string filename, uint32_t size, vec<uint8_t> data)
generates (int8_t retval);
};

读写的地址是  /vendor/nvdata/APCFG/APRDEB/WIFI   。

所以直接操作NVRam:

从NvRam读mac地址方法:

private String getMacAddrFromNvram() {
StringBuffer nvramBuf = new StringBuffer();
try {
int i = 0;
String buff = null;
INvram agent = INvram.getService();    //获取INvram的客户端对象
if (agent == null) {
Log.e(TAG+":"+"NvRam", "NvRAMAgent is null");
return "";            }
try {
buff = agent.readFileByName(MAC_ADDRESS_FILENAME, MAC_ADDRESS_OFFSET + MAC_ADDRESS_DIGITS);
} catch (Exception e) {
e.printStackTrace();
return "";
}
Log.i(TAG, "Raw data:" + buff);
if (buff.length() < 2 * (MAC_ADDRESS_OFFSET + MAC_ADDRESS_DIGITS)) {
return "";
}
// Remove the \0 special character.
int macLen = buff.length() - 1;
for (i = MAC_ADDRESS_OFFSET * 2; i < macLen; i += 2) {
if ((i + 2) < macLen) {
nvramBuf.append(buff.substring(i, i + 2));
nvramBuf.append(":");
} else {
nvramBuf.append(buff.substring(i));
}
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
return nvramBuf.toString();
}


向NvRam中写入wifi  mac地址:

private int updateWifiMacToNvram(String mac){//mac 00:08:22:11:06:06
try {
int i = 0;
INvram agent = INvram.getService();
byte[] macAddr = new byte[MAC_ADDRESS_DIGITS];
if (agent == null) {
Log.e(TAG+":"+"NvRam", "NvRAMAgent is null");
return 0;
}
//parse mac address firstly
StringTokenizer txtBuffer = new StringTokenizer(mac, ":");
while (txtBuffer.hasMoreTokens()) {
macAddr[i] = (byte) Integer.parseInt(txtBuffer.nextToken(), 16);
i++;
}
if(i != MAC_ADDRESS_DIGITS){
Log.e(TAG+":"+"NvRam", "Wrong length of macAddr:" + i);
return 0;
}
String buff = null;
try {
buff = agent.readFileByName(MAC_ADDRESS_FILENAME, MAC_ADDRESS_OFFSET + MAC_ADDRESS_DIGITS);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
byte[] buffArr = HexDump.hexStringToByteArray(buff.substring(0, buff.length() - 1));
for (i = 0; i < MAC_ADDRESS_DIGITS; i ++) {
buffArr[i + 4] = macAddr[i];
}
ArrayList<Byte> dataArray = new ArrayList<Byte>(MAC_ADDRESS_OFFSET + MAC_ADDRESS_DIGITS);
for (i = 0; i < MAC_ADDRESS_OFFSET + MAC_ADDRESS_DIGITS; i++) {
dataArray.add(i, new Byte(buffArr[i]));
}
int flag = 0;
try {
flag = agent.writeFileByNamevec(MAC_ADDRESS_FILENAME,MAC_ADDRESS_OFFSET + MAC_ADDRESS_DIGITS,dataArray);
Log.e(TAG+":"+"NvRam", "write mac to nvram compeleted flag=" + flag);
return flag;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}catch (Exception e) {
e.printStackTrace();
}
return 0;
}

还有一个随机生成有效mac地址的方法:

private String getRandomMacAddress(){
short[] mRandomMacAddr = new short[MAC_ADDRESS_DIGITS];
StringBuilder sb = new StringBuilder();
Random rand = new Random();
NumberFormat formatter = new DecimalFormat("00");
int end1 = rand.nextInt(100);
int end2 = rand.nextInt(100);
//int end3 = rand.nextInt(100);
String num1 = formatter.format(end1);
String num2 = formatter.format(end2);
//String num3 = formatter.format(end3);
sb.append("00:08:22:11:");
sb.append(num1).append(":").append(num2);
return sb.toString();

}

有这几个方法,可以将这些方法写到一个服务里, 找到一个开机会走到的地方,比如监听开机广播,我的是在systemui:

KeyguardUpdateMonitor.java中case MSG_BOOT_COMPLETED:中添加启动一个服务器类,在服务中判断即可。


然后读取当前的mac地址,如果是00:00:00:00:00:00则随机生成一个mac地址写入nvram即可。需要注意的是读到的mac地址00:00:00:00:00:00末尾会有一个\0,所以用equals方法去判断的时候需要注意。最好直接用contains比如:

if(mac.equals("") || mac.contains("00:00:00:00:00:00")){
wifimac = getRandomMacAddress();
Log.e(TAG+":"+"NvRam"," start write wifimac =" + wifimac);
mHandler.postDelayed(updateMacToNvRam, 1000);
}

另外方法中用到的常量,也贴出来:

private static final int MAC_ADDRESS_OFFSET = 4;
private static final int MAC_ADDRESS_DIGITS = 6;
private static final String MAC_ADDRESS_FILENAME = "/vendor/nvdata/APCFG/APRDEB/WIFI";

需要导入的方法:

import java.util.StringTokenizer;
import vendor.mediatek.hardware.nvram.V1_0.INvram;
import com.android.internal.util.HexDump;
import java.text.NumberFormat;
import java.util.Random;
import java.text.DecimalFormat;
import java.util.ArrayList;


亲测可用的方案,需注意第一次开机后,写入了,但要开关一下wifi才能在设置状态信息里看到mac地址。

本文地址:https://blog.csdn.net/u013560831/article/details/107917840

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网