前言
此博客讲解Android8之后的版本为准,Android8.0以前,是通过AIDL的方式去获取一个名为【NvRAMAgent】的服务。 到了Android8.0之后,NVRAM的读写方式已经变更,不再通过AIDL去获取NVRAM服务,然后进行读写。而是通过HIDL的方式去获取服务来进行读写。
另外请注意,此博客讲解的是如何使用Android studio上编译的apk工程读写Nvram中的SN与WiFi的Mac地址。如果是系统工程apk请拉到博客最下面。
了解文件位置
在开始实现具体操作流程之前先了解下在系统工程目录里新的NVRAM是怎么生成的。HIDL的是需要依靠系统编译成so与jar形成接口来调用的,类似于AIDL与JNI的组合使用。另外这里只需要了解,并不需要修改这些文件与代码。因为我们需要得到经过系统编译后的so与jar文件,将其导入到后续我们的apk项目里。
hal文件
路径:
vendor/mediatek/proprietary/hardware/interfaces/nvram/1.0/INvram.hal
代码:
/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package vendor.mediatek.hardware.nvram@1.0; /* * Purpose: * Nvram hidl interface is used by java layer to access nvram file * Note: * Support nvram file list in nvram@1.0 was listed as below * Please update nvram interface and versoin if new nvram file need to be supported * /vendor/nvdata/APCFG/APRDEB/BT_Addr /vendor/nvdata/APCFG/APRDCL/AUXADC /vendor/nvdata/media/CAMERA_Para /vendor/nvdata/media/CAMERA_3A /vendor/nvdata/media/CAMERA_SHADING /vendor/nvdata/media/CAMERA_DEFECT /vendor/nvdata/media/CAMERA_SENSOR /vendor/nvdata/media/CAMERA_LENS /vendor/nvdata/APCFG/APRDCL/UART /vendor/nvdata/APCFG/APRDCL/FACTORY /vendor/nvdata/APCFG/APRDCL/BWCS /vendor/nvdata/APCFG/APRDCL/HWMON_ACC /vendor/nvdata/APCFG/APRDCL/HWMON_GYRO /vendor/nvdata/media/Voice_Recognize_Param /vendor/nvdata/media/Audio_AudEnh_Control_Opt /vendor/nvdata/media/Audio_VOIP_Param /vendor/nvdata/APCFG/APRDCL/HWMON_PS /vendor/nvdata/APCFG/APRDCL/MD_Type /vendor/nvdata/APCFG/APRDCL/EXT_MD_Type /vendor/nvdata/APCFG/APRDCL/SDIO /vendor/nvdata/media/CAMERA_VERSION /vendor/nvdata/media/CAMERA_FEATURE /vendor/nvdata/media/CAMERA_GEOMETRY /vendor/nvdata/APCFG/APRDCL/MD_SBP /vendor/nvdata/media/CAMERA_SHADING2 /vendor/nvdata/media/CAMERA_PLINE /vendor/nvdata/media/CAMERA_AF /vendor/nvdata/media/CAMERA_FLASH_CALIBRATION /vendor/nvdata/media/Audio_Sph /vendor/nvdata/APCFG/APRDEB/GPS /vendor/nvdata/media/Audio_CompFlt /vendor/nvdata/media/Audio_Effect /vendor/nvdata/APCFG/APRDEB/WIFI /vendor/nvdata/APCFG/APRDEB/WIFI_CUSTOM /vendor/nvdata/media/Audio_Sph_Med /vendor/nvdata/media/Audio_Vol_custom /vendor/nvdata/media/Sph_Dual_Mic /vendor/nvdata/media/Audio_Wb_Sph /vendor/nvdata/APCFG/APRDEB/PRODUCT_INFO /vendor/nvdata/media/Headphone_CompFlt /vendor/nvdata/media/Audio_gain_table /vendor/nvdata/media/Audio_ver1_Vol_custom /vendor/nvdata/media/Audio_Hd_Record_Param /vendor/nvdata/media/Audio_Hd_Record_Scene_Table /vendor/nvdata/media/Audio_Buffer_DC_Calibration_Param /vendor/nvdata/media/VibSpk_CompFlt /vendor/nvdata/media/MusicDRC_CompFlt /vendor/nvdata/media/RingToneDRC_CompFlt /vendor/nvdata/media/Audio_MAGI_CONFERENCE /vendor/nvdata/media/Audio_HAC_Param */ 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); };
.h文件
路径
vendor/mediatek/proprietary/external/libnvram/nvram_hidl/1.0/NvRam.h
代码:
#ifndef VENDOR_MEDIATEK_HARDWARE_NVRAM_V1_0_NVRAM_H #define VENDOR_MEDIATEK_HARDWARE_NVRAM_V1_0_NVRAM_H #include <vendor/mediatek/hardware/nvram/1.0/INvram.h> #include <hidl/MQDescriptor.h> #include <hidl/Status.h> namespace vendor { namespace mediatek { namespace hardware { namespace nvram { namespace V1_0 { namespace implementation { using ::android::hidl::base::V1_0::DebugInfo; using ::android::hidl::base::V1_0::IBase; using ::vendor::mediatek::hardware::nvram::V1_0::INvram; using ::android::hardware::hidl_array; using ::android::hardware::hidl_memory; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; using ::android::sp; struct Nvram : public INvram { // Methods from ::vendor::mediatek::hardware::nvram::V1_0::INvram follow. Return<void> readFileByName(const hidl_string& filename, uint32_t size, readFileByName_cb _hidl_cb) override; Return<int8_t> writeFileByNamevec(const hidl_string& filename, uint32_t size, const hidl_vec<uint8_t>& data) override; // Methods from ::android::hidl::base::V1_0::IBase follow. }; extern "C" INvram* HIDL_FETCH_INvram(const char* name); } // namespace implementation } // namespace V1_0 } // namespace nvram } // namespace hardware } // namespace mediatek } // namespace vendor #endif // VENDOR_MEDIATEK_HARDWARE_NVRAM_V1_0_NVRAM_H
.cpp文件
路径
vendor/mediatek/proprietary/external/libnvram/nvram_hidl/1.0/NvRam.cpp
代码:
#include "Nvram.h" #include <android-base/logging.h> #include <log/log.h> #include "libnvram.h" #include "libnvram_log.h" using std::string; #define NVRAM_LOG(...) \ do { \ ALOGD(__VA_ARGS__); \ } while (0) namespace vendor { namespace mediatek { namespace hardware { namespace nvram { namespace V1_0 { namespace implementation { void covertVector2Array(std::vector<uint8_t> in, char* out) { int size = in.size(); for(int i = 0; i < size; i++) { out[i] = in.at(i); } } void covertArray2Vector(const char* in, int len, std::vector<uint8_t>& out) { out.clear(); for(int i = 0; i < len; i++) { out.push_back(in[i]); } } // Methods from ::vendor::mediatek::hardware::nvram::V1_0::INvram follow. Return<void> Nvram::readFileByName(const hidl_string& filename, uint32_t size, readFileByName_cb _hidl_cb) { // TODO implement int pRecSize=0,pRecNum=0; bool IsRead=1; char *buff=NULL; int file_lid = -1; string result; int i = 0; char *nvramstr = (char*)malloc(2*size+1); char *nvramptr = nvramstr; char *cstr=new char[filename.size()+1]; if (nvramstr==NULL || size==0 || cstr==NULL) { NVRAM_LOG("nvramstr==NULL\n"); if(nvramstr!=NULL) free(nvramstr); if(cstr!=NULL) delete[] cstr; return Void(); } snprintf(cstr, filename.size()+1,"%s", filename.c_str()); file_lid = NVM_GetLIDByName(cstr); if(file_lid < 0) { NVRAM_LOG("Get LID by name fail! %s\n",cstr); free(nvramstr); delete[] cstr; return Void(); } F_ID fd=NVM_GetFileDesc(file_lid,&pRecSize,&pRecNum,IsRead); if (fd.iFileDesc==-1) { LOG(ERROR) << "open file Error!"; free(nvramstr); delete[] cstr; return Void(); } LOG(ERROR) << "RecNum is "<<pRecNum; //size=pRecSize*pRecNum; buff=(char *)malloc(size); if(buff == NULL) { NVRAM_LOG("Malloc Error!\n"); if(!NVM_CloseFileDesc(fd)) NVRAM_LOG("close File error!\n"); free(nvramstr); delete[] cstr; return Void(); } if((ssize_t)size == read(fd.iFileDesc,buff,(ssize_t)size)) { if(NVM_CloseFileDesc(fd)) { NVRAM_LOG("Read Done!Size is %d\n",size); //return buff; } else { NVRAM_LOG("Close file error!\n"); free(buff); free(nvramstr); delete[] cstr; return Void(); } } else { NVRAM_LOG("read File error!\n"); if(!NVM_CloseFileDesc(fd)) NVRAM_LOG("close File error!\n"); free(buff); free(nvramstr); delete[] cstr; return Void(); } NVRAM_LOG("nvramstr buff[0]%x, buff[1]%x, buff[2]%x, buff[3]%x, buff[4]%x, buff[5]%x, buff[6]%x, buff[7]%x, buff[8]%x \n", buff[0],buff[1],buff[2],buff[3],buff[4],buff[5],buff[6],buff[7],buff[8]); for(i=0; i<(int)size; i++) { nvramptr += sprintf(nvramptr, "%02X",buff[i]); } sprintf(nvramptr,"\n"); *(nvramptr+1)='\0'; NVRAM_LOG("nvramstr %s\n",nvramstr); _hidl_cb(nvramstr); free(buff); delete[] cstr; return Void(); } Return<int8_t> Nvram::writeFileByNamevec(const hidl_string& filename, uint32_t size, const hidl_vec<uint8_t>& data) { // TODO implement char *cstr_filename=new char[filename.size()+1]; char *cstr_data=new char[data.size()+1]; if (cstr_data==NULL || size==0 || cstr_filename==NULL) { NVRAM_LOG("cstr_data==NULL\n"); if(cstr_data!=NULL) delete[] cstr_data; if(cstr_filename!=NULL) delete[] cstr_filename; return int8_t {}; } snprintf(cstr_filename, filename.size()+1,"%s", filename.c_str()); covertVector2Array(data, cstr_data); int pRecSize=0,pRecNum=0,looptimes=0; bool IsRead=0; int file_lid = -1; file_lid = NVM_GetLIDByName(cstr_filename); if(file_lid < 0) { NVRAM_LOG("Get LID by name fail!\n"); delete[] cstr_data; delete[] cstr_filename; return int8_t {}; } F_ID fd=NVM_GetFileDesc(file_lid,&pRecSize,&pRecNum,IsRead); if (fd.iFileDesc==-1) { NVRAM_LOG("open file Error!\n"); delete[] cstr_data; delete[] cstr_filename; return int8_t {}; } #if 0 if(size != pRecSize) { NVRAM_LOG("Input size (%d) and RecSize (%d) not match!\n",size,pRecSize); if(!NVM_CloseFileDesc(fd)) NVRAM_LOG("close File error!\n"); //return 0; return int8_t {}; } #endif // GetFileDesc should return right pos and this would cause pro_info multi lids issue. #if 0 if(0 != lseek(fd.iFileDesc,0,SEEK_SET)){ NVRAM_LOG("lseek error!\n"); if(!NVM_CloseFileDesc(fd)) NVRAM_LOG("close File error!\n"); return 0; } #endif looptimes = pRecNum; NVRAM_LOG("RecNum is :%d\n",pRecNum); while(looptimes--) { if((ssize_t)size != write(fd.iFileDesc,cstr_data,(ssize_t)size)) { NVRAM_LOG("write file error!\n"); if(!NVM_CloseFileDesc(fd)) NVRAM_LOG("close File error!\n"); delete[] cstr_data; delete[] cstr_filename; return int8_t {}; } } if(NVM_CloseFileDesc(fd)) { NVRAM_LOG("Write file Done!\n"); delete[] cstr_data; delete[] cstr_filename; return int8_t {}; } else { NVRAM_LOG("close File error!\n"); delete[] cstr_data; delete[] cstr_filename; return int8_t {}; } //return int8_t {}; } // Methods from ::android::hidl::base::V1_0::IBase follow. INvram* HIDL_FETCH_INvram(const char* /* name */) { return new Nvram(); } } // namespace implementation } // namespace V1_0 } // namespace nvram } // namespace hardware } // namespace mediatek } // namespace vendor
经过系统编译后输出的so文件路径与jar文件路径
so路径
out\target\product\A8385_JS04\obj\SHARED_LIBRARIES\vendor.mediatek.hardware.nvram@1.0.vendor_intermediates
jar路径
out\target\common\obj\JAVA_LIBRARIES\vendor.mediatek.hardware.nvram-V1.0-java_intermediates
其中classes.jar就包含了INvram这个类,这里可以用反编译工具解包后查看
如图:
读写Nvram中SN号的操作流程
这里是Android studio上编译的工程
第一步 导入系统编译Nvram的so与jar
在build里添加
android { compileSdk 28 defaultConfig { applicationId "com.xxx.xxxx" minSdk 26 targetSdk 28 versionCode 11 versionName "1.10" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } //添加 sourceSets { main { jniLibs.srcDirs = ["libs"] } } //略... } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar'])//添加 implementation files('libs\\classes.jar')//添加 }
第二步 项目必须是系统权限与系统签名
怎么实现请参考博客:https://www.cnblogs.com/guanxinjing/p/11410915.html
第三步 项目必须架包framework
怎么实现请参考博客:https://www.cnblogs.com/guanxinjing/p/16613716.html
这里说一下为什么需要架framework,因为Android studio在编译的时候会检查到代码里没有IHwInterface这个类并且抛出编译异常,而这个类在framework中。
android.os.IHwInterface;
这里在啰嗦一下为什么会检查这个类。因为在调用INvram.getService()方法的时候,INvram的基类是IBase
而IBase继承了IHwInterface
第四步 修改系统工程里的代码,删除Nv写入保护的代码
系统工程修改文件路径
vendor\mediatek\proprietary\bootable\bootloader\lk\platform\mt6765\write_protect.c
修改代码位置
如果不删除写入保护set_write_protect,会出现在写入NV的时候如下报错
第五步 使用下面工具类读写SN号,或者Nv里的其他数据
import android.util.Log; import com.android.internal.util.HexDump; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import vendor.mediatek.hardware.nvram.V1_0.INvram; /** * * /vendor/nvdata/APCFG/APRDEB/BT_Addr * /vendor/nvdata/APCFG/APRDCL/AUXADC * /vendor/nvdata/media/CAMERA_Para * /vendor/nvdata/media/CAMERA_3A * /vendor/nvdata/media/CAMERA_SHADING * /vendor/nvdata/media/CAMERA_DEFECT * /vendor/nvdata/media/CAMERA_SENSOR * /vendor/nvdata/media/CAMERA_LENS * /vendor/nvdata/APCFG/APRDCL/UART * /vendor/nvdata/APCFG/APRDCL/FACTORY * /vendor/nvdata/APCFG/APRDCL/BWCS * /vendor/nvdata/APCFG/APRDCL/HWMON_ACC * /vendor/nvdata/APCFG/APRDCL/HWMON_GYRO * /vendor/nvdata/media/Voice_Recognize_Param * /vendor/nvdata/media/Audio_AudEnh_Control_Opt * /vendor/nvdata/media/Audio_VOIP_Param * /vendor/nvdata/APCFG/APRDCL/HWMON_PS * /vendor/nvdata/APCFG/APRDCL/MD_Type * /vendor/nvdata/APCFG/APRDCL/EXT_MD_Type * /vendor/nvdata/APCFG/APRDCL/SDIO * /vendor/nvdata/media/CAMERA_VERSION * /vendor/nvdata/media/CAMERA_FEATURE * /vendor/nvdata/media/CAMERA_GEOMETRY * /vendor/nvdata/APCFG/APRDCL/MD_SBP * /vendor/nvdata/media/CAMERA_SHADING2 * /vendor/nvdata/media/CAMERA_PLINE * /vendor/nvdata/media/CAMERA_AF * /vendor/nvdata/media/CAMERA_FLASH_CALIBRATION * /vendor/nvdata/media/Audio_Sph * /vendor/nvdata/APCFG/APRDEB/GPS * /vendor/nvdata/media/Audio_CompFlt * /vendor/nvdata/media/Audio_Effect * /vendor/nvdata/APCFG/APRDEB/WIFI * /vendor/nvdata/APCFG/APRDEB/WIFI_CUSTOM * /vendor/nvdata/media/Audio_Sph_Med * /vendor/nvdata/media/Audio_Vol_custom * /vendor/nvdata/media/Sph_Dual_Mic * /vendor/nvdata/media/Audio_Wb_Sph * /vendor/nvdata/APCFG/APRDEB/PRODUCT_INFO * /vendor/nvdata/media/Headphone_CompFlt * /vendor/nvdata/media/Audio_gain_table * /vendor/nvdata/media/Audio_ver1_Vol_custom * /vendor/nvdata/media/Audio_Hd_Record_Param * /vendor/nvdata/media/Audio_Hd_Record_Scene_Table * /vendor/nvdata/media/Audio_Buffer_DC_Calibration_Param * /vendor/nvdata/media/VibSpk_CompFlt * /vendor/nvdata/media/MusicDRC_CompFlt * /vendor/nvdata/media/RingToneDRC_CompFlt * /vendor/nvdata/media/Audio_MAGI_CONFERENCE * /vendor/nvdata/media/Audio_HAC_Param */ public class SNParamUtils { public static final String PRODUCT_INFO_FILENAME = "/vendor/nvdata/APCFG/APRDEB/PRODUCT_INFO"; private static final int SN_LENGTH = 32; public static void writeSn(String sn) { char sn_chars[] = sn.toCharArray(); byte sn_bytes[] = getBytes(sn_chars); try { INvram agent = INvram.getService(); if (agent != null) { ArrayList<Byte> dataArray = new ArrayList<>(); for (byte b : sn_bytes) { dataArray.add(new Byte(b)); } int ret_1 = agent.writeFileByNamevec(PRODUCT_INFO_FILENAME, SN_LENGTH, dataArray); if (ret_1 == 0) { Log.e("zh", "writeSn success " + ret_1); } else { Log.e("zh", "writeSn failed" + ret_1); } } else { Log.e("zh", "writeSn: agent null"); } } catch (Exception e) { Log.e("zh", "writeSn exception:" + e.getLocalizedMessage()); e.printStackTrace(); } } public static String readSn() { int targets = 0; try { String buff = null; INvram agent = INvram.getService(); if (agent != null) { buff = agent.readFileByName(PRODUCT_INFO_FILENAME, SN_LENGTH); Log.e("zh", "buff: " + buff ); } byte[] buffArr = HexDump.hexStringToByteArray(buff.substring(0, buff.length() - 1)); targets = (buffArr[0] & 0xff) | ((buffArr[1] << 8) & 0xff00) | ((buffArr[2] << 24) >>> 8) | (buffArr[3] << 24); Log.e("zh", "readSn: chars=>" + Arrays.toString(getChars(buffArr)) + ", targets == " + targets); Log.e("zh", "readSn: bytes=>" + Arrays.toString((buffArr)) + ", targets == " + targets); return String.valueOf(getChars(buffArr)); } catch (Exception e) { Log.e("zh", "readSn exception:" + e.getLocalizedMessage()); e.printStackTrace(); } return "123456789"; } private static char[] getChars(byte[] bytes) { Charset cs = Charset.forName("UTF-8"); ByteBuffer bb = ByteBuffer.allocate(bytes.length); bb.put(bytes); bb.flip(); CharBuffer cb = cs.decode(bb); return cb.array(); } private static byte[] getBytes(char[] chars) { Charset cs = Charset.forName("UTF-8"); CharBuffer cb = CharBuffer.allocate(chars.length); cb.put(chars); cb.flip(); ByteBuffer bb = cs.encode(cb); return bb.array(); } }
假如你是系统工程编译apk
可以在apk工程的android.mk里直接导入,不需要以上的第一步到第三步,但是依然需要第四步与第五步
LOCAL_STATIC_JAVA_LIBRARIES := vendor.mediatek.hardware.nvram-V1.0-java
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_CERTIFICATE := platform # Add static library for nvram # LOCAL_STATIC_JAVA_LIBRARIES := vendor.mediatek.hardware.nvram-V1.1-java-static LOCAL_STATIC_JAVA_LIBRARIES := vendor.mediatek.hardware.nvram-V1.0-java LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := JNvRAM_V11 LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE)
MTK平台如何用Build.getSerial()方法读取写入的SN号
这里直接复制MTK论坛那边的开发回复(下面提是MTK的写号工具SN Write,但是我们这个写NV的方法同样适用):
在/vendor/mediatek/proprietary/bootable/bootloader/lk/app/mt_boot/mt_boot.c
中,将 #define SERIAL_NUM_FROM_BARCODE 宏定义打开
这时SN Write工具写Barcode即可,其他无需修改。
这是最简单的方式,相当于serial no取Barcode空间的值。
在NV中读写WiFi的Mac地址
请注意!在Android10版本以后,WiFi已经默认使用随机mac地址,意思是说,哪怕你写到了NV中,在WifiManager中也不会读取到,这需要你手动设置或者修改代码将,下面的选项从随机Mac地址修改成固定设备的Mac地址。如下图位置:
代码部分:
其他流程与上面一样,这里直接提供读写代码。
import android.app.Application;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.util.Log;
import com.android.internal.util.HexDump;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.StringTokenizer;
import vendor.mediatek.hardware.nvram.V1_0.INvram;
public class MacParamUtils {
public static final String MAC_ADDRESS_FILENAME = "/vendor/nvdata/APCFG/APRDEB/WIFI";
private static final int MAC_ADDRESS_OFFSET = 4;
private static final int MAC_ADDRESS_DIGITS = 6;
/**
* 通过WifiManager获取WiFi Mac地址
*/
public static String getMACAddress(Application application) {
try {
WifiManager wifiManager = (WifiManager)application.getSystemService(Context.WIFI_SERVICE);
Method getFactoryMacAddresses = wifiManager.getClass().getMethod("getFactoryMacAddresses");
String[] macAddresses = (String[]) getFactoryMacAddresses.invoke(wifiManager);
String macAddress = "";
if (macAddresses.length > 0) {
macAddress = macAddresses[0];
}
return macAddress;
} catch (Exception e) {
return null;
}
}
/**
* 直接从NV中读取Mac地址
* @return
*/
public static String getWifiMacFromNvram() {
StringBuffer nvramBuf = new StringBuffer();
try {
int i = 0;
String buff = null;
INvram agent = INvram.getService();
if (agent == null) {
Log.e("zh", "NvRAMAgent is null");
return ""; }
try {
buff = agent.readFileByName(MAC_ADDRESS_FILENAME, MAC_ADDRESS_OFFSET + MAC_ADDRESS_DIGITS);
} catch (Exception e) {
e.printStackTrace();
return "";
}
Log.e("zh", "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();
}
/**
* 更新WiFi Mac地址到NV中
* @param mac
* @return
*/
public static int updateWifiMacToNvram(String mac){
try {
int i = 0;
INvram agent = INvram.getService();
byte[] macAddr = new byte[MAC_ADDRESS_DIGITS];
if (agent == null) {
Log.e("zh", "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("zh", "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);
return flag;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}catch (Exception e) {
e.printStackTrace();
}
return 0;
}
private static char[] getChars(byte[] bytes) {
Charset cs = Charset.forName("UTF-8");
ByteBuffer bb = ByteBuffer.allocate(bytes.length);
bb.put(bytes);
bb.flip();
CharBuffer cb = cs.decode(bb);
return cb.array();
}
private static byte[] getBytes(char[] chars) {
Charset cs = Charset.forName("UTF-8");
CharBuffer cb = CharBuffer.allocate(chars.length);
cb.put(chars);
cb.flip();
ByteBuffer bb = cs.encode(cb);
return bb.array();
}
}
End
本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/16869583.html