前言
此博客讲解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 = 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);
}
}
// 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);
}
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中。
这里在啰嗦一下为什么会检查这个类。因为在调用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 = (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;
}
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));
}
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
本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
来源:https://www.cnblogs.com/guanxinjing/p/16869583.html |