要操作NVRAM,必须具有系统app的权限。我在系统的里面找到读写MAC地址相关的实现,首先是读的方法
private String getMacAddrFromNvram() {
StringBuffer nvramBuf = new StringBuffer();
try {
int i = 0;
String buff = null;
INvram agent = INvram.getService();
if (agent == null) {
mToast.setText("No support MAC address writing due to NVRAM");
mToast.show();
Log.e(TAG, "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)) {
mToast.setText("The foramt of NVRAM is not correct");
mToast.show();
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));
}
}
Log.d(TAG, "buff:" + nvramBuf.toString());
} catch (Exception e) {
e.printStackTrace();
return "";
}
return nvramBuf.toString();
}
核心就是这个INvram,看一下相关的实现。
public interface INvram extends IBase {
...
static INvram asInterface(IHwBinder binder) {
if (binder == null) {
return null;
} else {
IHwInterface iface = binder.queryLocalInterface("[email protected]::INvram");
if (iface != null && iface instanceof INvram) {
return (INvram)iface;
} else {
INvram.Proxy proxy = new INvram.Proxy(binder);
try {
Iterator var3 = proxy.interfaceChain().iterator();
while(var3.hasNext()) {
String descriptor = (String)var3.next();
if (descriptor.equals("[email protected]::INvram")) {
return proxy;
}
}
} catch (RemoteException var5) {
}
return null;
}
}
}
static INvram castFrom(IHwInterface iface) {
return iface == null ? null : asInterface(iface.asBinder());
}
IHwBinder asBinder();
static INvram getService(String serviceName, boolean retry) throws RemoteException {
return asInterface(HwBinder.getService("[email protected]::INvram", serviceName, retry));
}
static INvram getService(boolean retry) throws RemoteException {
return getService("default", retry);
}
static INvram getService(String serviceName) throws RemoteException {
return asInterface(HwBinder.getService("[email protected]::INvram", serviceName));
}
static INvram getService() throws RemoteException {
return getService("default");
}
String readFileByName(String var1, int var2) throws RemoteException;
byte writeFileByNamevec(String var1, int var2, ArrayList var3) throws RemoteException;
...
}
一开始想通过反射来调用,非SDK接口,根本找不到这个类,
private String readFileByName(String name,int offSet){
try {
Class> INvram = Class.forName("vendor.mediatek.hardware.nvram.V1_0.INvram");
Method getService = INvram.getDeclaredMethod("getService");
Object object = getService.invoke(INvram);//通过getinstance方法实例化对象
Method getAuthor = INvram.getDeclaredMethod("readFileByName", String.class,int.class);//参数类型的class
getAuthor.setAccessible(true);
String mac =(String)getAuthor.invoke(object, name,offSet);
return mac;
}catch (Exception e){
Log.d(TAG, "readFileByName: Exception "+e.toString());
return "";
}
}
于是去out目录找到相应的jar包,把jar导进去就可以调用了。路径为out\soong.intermediates\vendor\mediatek\proprietary\hardware\interfaces\nvram\1.0\vendor.mediatek.hardware.nvram-V1.0-java\android_common\combined\vendor.mediatek.hardware.nvram-V1.0-java.jar。再去看一下写MAC的方法
private void updateMacAddr() {
try {
int i = 0;
INvram agent = INvram.getService();
byte[] macAddr = new byte[MAC_ADDRESS_DIGITS];
if (agent == null) {
mToast.setText("No support MAC address writing due to NVRAM");
mToast.show();
Log.e(TAG, "NvRAMAgent is null");
return;
}
//parse mac address firstly 例如输入的为00:08:22:E8:48:96
StringTokenizer txtBuffer = new StringTokenizer(
mMacAddrEdit.getText().toString(), ":");
//将byte型转化为16进制的int
while (txtBuffer.hasMoreTokens()) {
macAddr[i] = (byte) Integer.parseInt(txtBuffer.nextToken(), 16);
i++;
}
if (i != MAC_ADDRESS_DIGITS) {
Log.e(TAG, "Wrong length of macAddr:" + i);
mToast.setText("The format of mac address is not correct");
mToast.show();
return;
}
//这里是为了读取前面4个byte
String buff = null;
try {
buff = agent.readFileByName(
MAC_ADDRESS_FILENAME, MAC_ADDRESS_OFFSET + MAC_ADDRESS_DIGITS);
} catch (Exception e) {
e.printStackTrace();
return;
}
// 将16进制字符转化为byte数组
byte[] buffArr = HexDump.hexStringToByteArray(
buff.substring(0, buff.length() - 1));
//从第4个开始赋值
for (i = 0; i < MAC_ADDRESS_DIGITS; i ++) {
buffArr[i + 4] = macAddr[i];
}
ArrayList dataArray = new ArrayList(
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);
} catch (Exception e) {
e.printStackTrace();
mToast.setText(e.getMessage() + ":" + e.getCause());
mToast.show();
return;
}
mToast.setText("Update successfully.\r\nPlease reboot this device");
mToast.show();
} catch (Exception e) {
mToast.setText(e.getMessage() + ":" + e.getCause());
mToast.show();
e.printStackTrace();
}
}
来看一下hexStringToByteArray的实现
public static byte[] hexStringToByteArray(String hexString){
int length = hexString.length();
byte[] buffer = new byte[length / 2];
for (int i = 0 ; i < length ; i += 2)
{
buffer[i / 2] = (byte)((toByte(hexString.charAt(i)) << 4) | toByte(hexString.charAt(i+1)));
}
return buffer;
}
private static int toByte(char c){
if (c >= '0' && c <= '9') return (c - '0');
if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
throw new RuntimeException ("Invalid hex char '" + c + "'");
}