如何从MTK平台机器的NVRAM中获取WIFI mac地址

简介: 在MTK的机器中,如果不用特定的工具烧写MAC地址,在开机后打开WIFI后会显示: “NVRAM WARNING: Err=0x10”  这就是没有烧写mac地址的原因,所以每次打开wifi,wifi的MAC地址都是一个随机产生的值,为什么会这样?  答案在: vendor/mediatek/p...

在MTK的机器中,如果不用特定的工具烧写MAC地址,在开机后打开WIFI后会显示: “NVRAM WARNING: Err=0x10”  这就是没有烧写mac地址的原因,所以每次打开wifi,wifi的MAC地址都是一个随机产生的值,为什么会这样?  
答案在: vendor/mediatek/proprietary/packages/apps/CdsInfo/src/com/mediatek/connnectivity/CdsWifiInfoActivity.java   

public class CdsWifiInfoActivity extends Activity {

    private static final String TAG = "CDSINFO/WifiInfo";

    private static final int MAC_ADDRESS_ID = 30;
    private static final int MAC_ADDRESS_DIGITS = 6;
    private static final int MAX_ADDRESS_VALUE = 0xff;
    private static final int INVALID_RSSI = -200;
//定义了MAC地址存储的文件的绝对路径
    private static final String MAC_ADDRESS_FILENAME = "/data/nvram/APCFG/APRDEB/WIFI";

    private static final String[] WIFI_SYSTEM_PROPERTY = new String[] {
        "net.hostname",
        "dhcp.wlan0.ipaddress",
        "net.dns1",
        "net.dns2",
。。。。。
以下是获取mac地址的方法:

//获取mac地址的方法
    private void getMacAddr() {


        try {
            IBinder binder = ServiceManager.getService("NvRAMAgent");
            NvRAMAgent agent = NvRAMAgent.Stub.asInterface(binder);

            mRandomMacAddr = new short[MAC_ADDRESS_DIGITS];

            if (mUserMode) {
                mMacAddrLabel.setVisibility(View.GONE);
                mMacAddrEdit.setVisibility(View.GONE);
                mMacAddBtn.setVisibility(View.GONE);
            } else {
                StringBuilder sb = new StringBuilder();
                Random rand = new Random();
                NumberFormat formatter = new DecimalFormat("00");
                int end1 = rand.nextInt(100);
                int end2 = rand.nextInt(100);
                String num1 = formatter.format(end1);
                String num2 = formatter.format(end2);
		//这几位是固定的值
                sb.append("00:08:22:11:");
                sb.append(num1).append(":").append(num2);

                mMacAddrLabel.setVisibility(View.VISIBLE);
                mMacAddrEdit.setVisibility(View.VISIBLE);
                mMacAddBtn.setVisibility(View.VISIBLE);
                System.out.println("string buffer:" + sb);
                mMacAddrEdit.setText(sb);
                MacAddressRandom = sb.toString();

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
更新mac地址的方法:

//更新mac地址
    private void updateMacAddr() {

        try {
            int i = 0;
            IBinder binder = ServiceManager.getService("NvRAMAgent");
            NvRAMAgent agent = NvRAMAgent.Stub.asInterface(binder);

            //parse mac address firstly
            StringTokenizer txtBuffer = new StringTokenizer(mMacAddrEdit.getText().toString(), ":");

            while (txtBuffer.hasMoreTokens()) {
                mRandomMacAddr[i] = (short) Integer.parseInt(txtBuffer.nextToken(), 16);
                System.out.println(i + ":" + mRandomMacAddr[i]);
                i++;
            }

            if (i != 6) {
                mToast.setText("The format of mac address is not correct");
                mToast.show();
                return;
            }

            byte[] buff = null;

            try {
                buff = agent.readFileByName(MAC_ADDRESS_FILENAME);
            } catch (Exception e) {
                e.printStackTrace();
            }
			
			//随机产生的buff[i+4]开始就是mac地址存储的位置
            for (i = 0; i < MAC_ADDRESS_DIGITS; i ++) {
                buff[i + 4] = (byte) mRandomMacAddr[i];
            }

            int flag = 0;

            try {
                flag = agent.writeFileByName(MAC_ADDRESS_FILENAME, buff);
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (flag > 0) {
                mToast.setText("Update successfully.\r\nPlease reboot this device");
                mToast.show();
            } else {
                mToast.setText("Update failed");
                mToast.show();
            }

        } catch (Exception e) {
            mToast.setText(e.getMessage() + ":" + e.getCause());
            mToast.show();
            e.printStackTrace();
        }
    }
从这个代码中可以分析得知,此时的Wifi MAC地址除了前面几位是固定值,而后面都是随机产生的。  但只有一个文件才是正确的WIFI MAC地址保存的值。如果没有烧写WIFI MAC地址,那么这个文件的第4到第9个字节是固定为0的,只有烧写了MAC地址,这6个字节才是有数据的。  通过代码分析,得知烧写mac地址后的文件是保存在: /data/nvram/APCFG/APRDEB/WIFI 这个文件中。
通过adb pull /data/nvram/APCFG/APRDEB/WIFI获取这个文件到我当前的系统,打开一看:    


是一堆乱码,那么如何正确打开查看呢?可以上百度去下一个WinHex打开,其实这个文件里面保存的是十六进制的数据。打开后可以看到:  


从这段数据中:,格式是这样的:04 01 00 00 CC 79 CF FF 35 54 44 。。偏移从0开始一直往后依次类推,分析代码得知:  
CC 79 CF FF 35 54 44就是通过特定工具刷写进去的WIFI MAC地址,如果不刷,那么这6个字节的数据默认为0。关于这个表,我们可以参考MTK的文档得知:

NVRAM在EMMC中是只读数据,一般存储在data分区中,所以格式化机器是会将NVRAM中的数据擦除的。


当然Nvram中不止存放wifi的MAC地址,也存放Gsensor校准的数据,这点以后我们再来写怎么获取。


下面就是NVRAM,WIFI的春初数值对应的。