读取miscdata分区的简要分析

读取miscdata分区的简要分析

一. 简单使用,使用AIDL的方式调用读写的方法

1. 添加aidl接口,注意保持包名类名的一致
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M5ZOAXRP-1623748847856)(./images/1623398799791.png)]

package com.sprd.engineermode;

interface IPhaseCheck {
    boolean writeOffsetString(int offset, in byte[] value);
    String readOffsetString(int offset, int length);
    boolean writeChargeSwitch(int value);
}

在AndroidManifest.xml声明Service

<service android:name=".PhaseCheckService">
            <intent-filter>
                <action android:name="com.sr.intent.action.PHASE_CHECK"/>
            </intent-filter>
        </service>

在Android.bp编译控制文件中引入src

srcs: ["src/**/*.java", "src/**/*.kt", "src/**/*.aidl"]

2. 绑定服务,调用方法

//导包
import com.sprd.engineermode.IPhaseCheck
class MainActivity : AppCompatActivity() {

    var phaseCheckService: IPhaseCheck? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
//绑定服务
 bindService(
            Intent("com.sr.intent.action.PHASE_CHECK").setPackage("com.sprd.engineermode"),
            object : ServiceConnection {
                override fun onServiceConnected(name: ComponentName, service: IBinder) {
                    phaseCheckService = IPhaseCheck.Stub.asInterface(service)
                }

                override fun onServiceDisconnected(name: ComponentName) {}
            },
            Context.BIND_AUTO_CREATE
        )
        
        var offset = 806 * 1024 + 1
        var dataLength = miscdata.text.length

        if (phaseCheckService != null) {
            miscdata.text = phaseCheckService!!.readOffsetString(offset, dataLength)
            println("miscdataValue === " + phaseCheckService!!.readOffsetString(offset, dataLength))
        }

//写miscdata
        btn_submit.setOnClickListener {
            if ("" != edt_offset.text.toString().trim()) {
                offset = edt_offset.text.toString().toInt() * 1024 + 1
            }
            val miscdataValue = miscdata_input.text.toString().toByteArray()
            dataLength = miscdata.text.length
            if (phaseCheckService != null) {
                phaseCheckService!!.writeOffsetString(offset, miscdataValue)
                miscdata.text = phaseCheckService!!.readOffsetString(offset, dataLength)
            }
        }
//读miscdata
        btn_getMiscdataValue.setOnClickListener {
            if ("" != edt_offset.text.toString().trim()) {
                offset = edt_offset.text.toString().toInt() * 1024 + 1
            }
            dataLength = if ("" != edt_lengthData.text.toString().trim()) {
                edt_lengthData.text.toString().toInt()
            } else {
                20
            }
            if (phaseCheckService != null) {
                miscdata.text = phaseCheckService!!.readOffsetString(offset, dataLength)
            }
        }
    }
}

完成以上操作就可以完成miscdata的读取操作了,接下来探究一下这个aidl的背后做了那些事情

二. Service中的具体实现(在EngineerMode此apk中)

1. 定义IPhaseCheck.aidl接口

package com.sprd.engineermode;

 interface IPhaseCheck {
     boolean writeOffsetString(int offset, in byte[] value);
     String readOffsetString(int offset, int length);
     boolean writeChargeSwitch(int value);
 }

2. 定义Service,实现方法

 public class PhaseCheckService extends Service {
     @Override
     public IBinder onBind(Intent intent) {
         return mBinder;
     }
 
     private IBinder mBinder = new IPhaseCheck.Stub() {
         @Override
         public boolean writeOffsetString(int offset, byte[] value) throws RemoteException {
             boolean isSuc = new PhaseCheckParse().writeOffsetString(offset, value);
             return isSuc;
         }
         @Override
         public String readOffsetString(int offset, int length) throws RemoteException {
             String result = new PhaseCheckParse().readOffsetString(offset, length);
             return result;
         }
         @Override
         public boolean writeChargeSwitch(int value) {
             boolean isSuc = new PhaseCheckParse().writeChargeSwitch(value);
             return isSuc;
         }
     };
 }

3. 以上Service的方法实现主要在PhaseCheckParse中,接下来看看PhaseCheckParse里面做了那些操作


 public class PhaseCheckParse {
     private static String TAG = "PhaseCheckParse";
 
     private static int BUF_SIZE = 4096;
     private byte[] stream = new byte[300];
     private AdaptBinder binder;
 
 //初始化binder
     public PhaseCheckParse() {
         if (!checkPhaseCheck()) {
             stream = null;
         }
 
         binder = new AdaptBinder();
         Log.e(TAG, "Get The service connect!");
     }
    
 static class AdaptBinder {
          private AdaptParcel mAdpt;
          private static final String SOCKET_NAME = "phasecheck_srv";
  
          AdaptBinder() {
              mAdpt = new AdaptParcel();
              mAdpt.data = new byte[BUF_SIZE];
              mAdpt.code = 0;
              mAdpt.dataSize = 0;
              mAdpt.replySize = 0;
          }
  
          synchronized void sendCmdAndRecResult(AdaptParcel adpt) {
              Log.d(TAG, "send cmd");
              byte[] buf = new byte[BUF_SIZE];
              int2byte(buf, 0, adpt.code);
              int2byte(buf, 4, adpt.dataSize);
              int2byte(buf, 8, adpt.replySize);
  
              System.arraycopy(adpt.data, 0, buf, 12, adpt.dataSize+adpt.replySize);
              Log.d(TAG, "code = "+adpt.code);
              Log.d(TAG, "dataSize = "+adpt.dataSize);
              Log.d(TAG, "replySize = "+adpt.replySize);
  
              if (!SocketUtils.sendCmd(SOCKET_NAME, buf, buf)) {
                  Log.e(TAG, "send command failed");
                  return;
              }
  
              adpt.code = byte2Int(buf, 0);
              adpt.dataSize = byte2Int(buf, 4);
              adpt.replySize = byte2Int(buf, 8);
  
              Log.d(TAG, "code = " + adpt.code);
              Log.d(TAG, "dataSize = " + adpt.dataSize);
              Log.d(TAG, "replySize =  "+ adpt.replySize);
  
              System.arraycopy(buf, 12, adpt.data, 0, adpt.dataSize+adpt.replySize);
          }
  
          private void convertParcel(AdaptParcel adpt, int code, Parcel data, Parcel reply) {
              data.setDataPosition(0);
              reply.setDataPosition(0);
  
              data.writeByteArrayInternal(adpt.data, 0, adpt.dataSize);
              reply.writeByteArrayInternal(adpt.data, adpt.dataSize, adpt.replySize);
  
              Log.e(TAG, "convertParcel: dataSize = "+data.dataSize()+", replySize = "+ reply.dataSize());
  
              data.setDataPosition(0);
              reply.setDataPosition(0);
          }
  
          private void convertAdaptParcel(int code, Parcel data, Parcel reply) {
              if(mAdpt == null){
                  Log.e(TAG, "convertAdaptParcel2: mAdpt == null!");
                  return;
              }
              mAdpt.code = code;
  
              data.setDataPosition(0);
              reply.setDataPosition(0);
  
              data.logArray();
              byte[] bData = new byte[data.dataSize()];
              data.readByteArray(bData);
              for(int i = 0; i < data.dataSize(); i++){
                  mAdpt.data[i] = bData[i];
              }
  
              byte[] bReply = new byte[reply.dataSize()];
              reply.readByteArray(bReply);
              for(int i = 0; i < reply.dataSize(); i++){
                  mAdpt.data[i+data.dataSize()] = bReply[i];
              }
              mAdpt.dataSize = data.dataSize();
              mAdpt.replySize = reply.dataSize();
              Log.e(TAG, "convertAdaptParcel2: dataSize = "+data.dataSize()+", replySize = "+ reply.dataSize());
  
              data.setDataPosition(0);
              reply.setDataPosition(0);
          }
  
        //此方法为进行具体操作的方法,传入code和数据调用相应的方法
  void transact(int code, Parcel data, Parcel reply, int flags) {
              Log.e(TAG, "transact start....");
              //填充数据
              convertAdaptParcel(code, data, reply);
              //发送指令
              sendCmdAndRecResult(mAdpt);
              //序列化返回数据
              convertParcel(mAdpt, code, data, reply);
  
              Log.e(TAG, "transact end....");
          }
      }
 
 
 private static class AdaptParcel {
          int code;
          int dataSize;
          int replySize;
          byte[] data;
      }
 
 /**
 *以上就是初始化的一些操作,实现方法中通过调用binder.transact(code,data,reply,flags)进行相关的操作
 * 填充数据
 * 1. convertAdaptParcel(code, data, reply);
 * 发送指令
 * 2. sendCmdAndRecResult(mAdpt);
 * 序列化返回数据
 * 3. convertParcel(mAdpt, code, data, reply);
 **/
 
 

  //两个主要的方法实现:读写操作
      public String readOffsetString(int offset, int length) {
          String value = "";
          try{
              Parcel data = new Parcel();
              Parcel reply = new Parcel();
              data.writeInt(offset);
              data.writeInt(length);
              binder.transact(TYPE_READ_OFFSET, data, reply, 0);
              value = reply.readString();
              Log.e(TAG, "readOffsetValue value = "+value);
              data.recycle();
              reply.recycle();
          }catch (Exception ex) {
              Log.e(TAG, "Exception " + ex.getMessage());
              ex.printStackTrace();
          }
          return value;
      }
  
      public boolean writeOffsetString(int offset, byte[] value) {
          try{
              Parcel data = new Parcel();
              Parcel reply = new Parcel();
              data.writeInt(offset);
              data.writeInt(value.length);
              for (int i = 0; i < value.length; i++) {
                  data.writeByte(value[i]);
              }
              binder.transact(TYPE_WRITE_OFFSET, data, reply, 0);
              data.recycle();
              return true;
          }catch (Exception ex) {
              Log.e(TAG, "Exception " + ex.getMessage());
              ex.printStackTrace();
              return false;
          }
      }

          synchronized void sendCmdAndRecResult(AdaptParcel adpt) {
              Log.d(TAG, "send cmd");
              byte[] buf = new byte[BUF_SIZE];
              int2byte(buf, 0, adpt.code);
              int2byte(buf, 4, adpt.dataSize);
              int2byte(buf, 8, adpt.replySize);
  
              System.arraycopy(adpt.data, 0, buf, 12, adpt.dataSize+adpt.replySize);
              Log.d(TAG, "code = "+adpt.code);
              Log.d(TAG, "dataSize = "+adpt.dataSize);
              Log.d(TAG, "replySize = "+adpt.replySize);
  
              if (!SocketUtils.sendCmd(SOCKET_NAME, buf, buf)) {
                  Log.e(TAG, "send command failed");
                  return;
              }
  
              adpt.code = byte2Int(buf, 0);
              adpt.dataSize = byte2Int(buf, 4);
              adpt.replySize = byte2Int(buf, 8);
  
              Log.d(TAG, "code = " + adpt.code);
              Log.d(TAG, "dataSize = " + adpt.dataSize);
              Log.d(TAG, "replySize =  "+ adpt.replySize);
  
              System.arraycopy(buf, 12, adpt.data, 0, adpt.dataSize+adpt.replySize);
          }
  
          private void convertParcel(AdaptParcel adpt, int code, Parcel data, Parcel reply) {
              data.setDataPosition(0);
              reply.setDataPosition(0);
  
              data.writeByteArrayInternal(adpt.data, 0, adpt.dataSize);
              reply.writeByteArrayInternal(adpt.data, adpt.dataSize, adpt.replySize);
  
              Log.e(TAG, "convertParcel: dataSize = "+data.dataSize()+", replySize = "+ reply.dataSize());
  
              data.setDataPosition(0);
              reply.setDataPosition(0);
          }
  
          private void convertAdaptParcel(int code, Parcel data, Parcel reply) {
              if(mAdpt == null){
                  Log.e(TAG, "convertAdaptParcel2: mAdpt == null!");
                  return;
              }
              mAdpt.code = code;
  
              data.setDataPosition(0);
              reply.setDataPosition(0);
  
              data.logArray();
              byte[] bData = new byte[data.dataSize()];
              data.readByteArray(bData);
              for(int i = 0; i < data.dataSize(); i++){
                  mAdpt.data[i] = bData[i];
              }
  
              byte[] bReply = new byte[reply.dataSize()];
              reply.readByteArray(bReply);
              for(int i = 0; i < reply.dataSize(); i++){
                  mAdpt.data[i+data.dataSize()] = bReply[i];
              }
              mAdpt.dataSize = data.dataSize();
              mAdpt.replySize = reply.dataSize();
              Log.e(TAG, "convertAdaptParcel2: dataSize = "+data.dataSize()+", replySize = "+ reply.dataSize());
  
              data.setDataPosition(0);
              reply.setDataPosition(0);
          }
  
         
      }
  
      private class Parcel {
          private int mDataSize;
          private int mPos;
          private byte[] mData;
  
          private Parcel() {
              mData = new byte[BUF_SIZE];
              mPos = 0;
              mDataSize = 0;
          }
  
          void writeByteArrayInternal(byte[] b, int offset, int len) {
              if (len == 0) {
                  return;
              }
              System.arraycopy(b, offset, mData, mPos, len);
              mPos += len;
              mDataSize += len;
          }
  
          void readByteArray(byte[] val) {
              System.arraycopy(mData, mPos, val, 0, val.length);
              mPos += val.length;
          }
  
          int dataSize() {
              return mDataSize;
          }
          
          
          public byte readByte() {
              byte b = mData[mPos];
              mPos += 1;
              return b;
          }
  
          public void writeByte(byte b) {
              Log.d(TAG, "ningbiao writeByte b="+b);
              mData[mPos] = b;
              mPos += 1;
              mDataSize += 1;
          }
          
  
          void writeInt(int i) {
              Log.d(TAG, "writeInt i="+i);
              mData[mPos+3] = (byte)(i >> 24 & 0xff);
              mData[mPos+2] = (byte)(i >> 16 & 0xff);
              mData[mPos+1] = (byte)(i >> 8 & 0xff);
              mData[mPos] = (byte)(i & 0xff);
              mPos += 4;
              mDataSize += 4;
          }
  
          int readInt() {
              int b0 = mData[mPos] & 0xFF;
              int b1 = mData[mPos + 1] & 0xFF;
              int b2 = mData[mPos + 2] & 0xFF;
              int b3 = mData[mPos + 3] & 0xFF;
              mPos += 4;
              return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
          }
  
          void setDataPosition(int i) {
              mPos = i;
          }
  
          String readString() {
              int nNum = readInt();
              byte[] b = new byte[nNum];
              Log.d(TAG, "readString num = "+nNum);
              readByteArray(b);
  
              return new String(b, StandardCharsets.UTF_8);
          }
  
          void recycle() {
              reset();
          }
  
          void reset() {
              mPos = 0;
              mDataSize = 0;
          }
      }
    }

稍微解析一下这两个方法
例如存入一个String A,ASCII码为65,一个int为4byte一个byte为8bit,存储的机器码为反码,有32位即为000…01000001
然后做一个移位操作与上一个0xff,0xff默认为int型0x000000ff,& 0xff操作即为高位清零,截取第25-32bit位保存到mData[mPos+3],就是用四个byte位表示一个int
然后读取就是一个反序列化的操作

void writeInt(int i) {
              Log.d(TAG, "writeInt i="+i);
              mData[mPos+3] = (byte)(i >> 24 & 0xff);
              mData[mPos+2] = (byte)(i >> 16 & 0xff);
              mData[mPos+1] = (byte)(i >> 8 & 0xff);
              mData[mPos] = (byte)(i & 0xff);
              mPos += 4;
              mDataSize += 4;
          }
  
          int readInt() {
              int b0 = mData[mPos] & 0xFF;
              int b1 = mData[mPos + 1] & 0xFF;
              int b2 = mData[mPos + 2] & 0xFF;
              int b3 = mData[mPos + 3] & 0xFF;
              mPos += 4;
              return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
          }

接下来看看sendCmdAndRecResult(mAdpt)中的主要操作,主要是执行了sendCmd()方法

  1. 建立socket连接
  2. ops.write(cmd); ops.flush();传入cmd
  3. int count = ins.read(result);返回result
public static boolean sendCmd(String socketName, byte[] cmd, byte[] result ) {
          Log.d(TAG, socketName + " send byte cmd");
  
          LocalSocket socketClient = new LocalSocket();
          LocalSocketAddress mSocketAddress =
              new LocalSocketAddress(socketName, Namespace.ABSTRACT);
  
          try {
              socketClient.connect(mSocketAddress);
          } catch (IOException e) {
              Log.e(TAG, "connect to " + socketName + " failed", e);
              try {
                  socketClient.close();
              } catch (IOException ignored) {
              }
              return false;
          }
  
          Watchdog wd = null;
          try (OutputStream ops = socketClient.getOutputStream();
              InputStream ins = socketClient.getInputStream()){
              Log.i(TAG, "connect " + socketName + " success");
  
              ops.write(cmd);
              ops.flush();
              Log.d(TAG, "write cmd and flush done");
  
              wd = new Watchdog(socketName, "byte command");
              wd.setTimeoutCallback(SocketUtils::timeout, socketClient);
              wd.wantEat();
              int count = ins.read(result);
              wd.feedFood();
  
              Log.d(TAG, "result read done, count=" + count);
          } catch (IOException e) {
              e.printStackTrace();
              return false;
          } finally {
              if (wd != null) {
                  wd.feedFood();
              }
              try {
                  socketClient.close();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
  
          Log.d(TAG,  "cmd over and result len: " + result.length);
          return true;
}

再来找找建立socket通信后面的服务端,做了那些操作

  1. 启动服务,加入Service管理,通过binder机制来进行处理
  2. 建立连接,进行通信
  int main(int arg, char** argv)
  {
      ENG_LOG("phasecheck_sprd Nativeserver - main() begin\n");
  #ifdef CHANNEL_SOCKET
      phConnect();
  #else
      ProcessState::initWithDriver("/dev/vndbinder");
      ALOGE("phasecheck_sprd Nativeserver - main() begin /dev/vndbinder\n");
      sp<ProcessState> proc(ProcessState::self());
      sp<IServiceManager> sm = defaultServiceManager();
      //LOGI("ServiceManager: %p\n", sm.get());
      ENG_LOG("phasecheck_sprd new server - serviceManager: %p\n", sm.get());
      //int ret = NativeService::Instance();
      int ret = defaultServiceManager()->addService(
                  String16("phasechecknative"), new NativeService());
      ENG_LOG("phasecheck_sprd new ..server - NativeService::Instance return %d\n", ret);
      ProcessState::self()->startThreadPool();
      IPCThreadState::self()->joinThreadPool();
  #endif
      return 0;
  }

phConnect();

//creat services socket, bind, listen...
service_fd = socket_local_server(PHASECHECK_SERVICE,ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);

connect_fd = accept(service_fd, (struct sockaddr *)&client_address, &client_len)
...
//对数据进行处理
ns.onTransact(code, data, &reply, 0);
...
close(connect_fd);
...
close(service_fd);
...

onTransact():

 int NativeService::onTransact(uint32_t code,
                                     Parcel& data,
                                     Parcel* reply,
                                     uint32_t flags)
      {
          ENG_LOG("phasecheck_sprd nativeservice onTransact code:%d",code);
    //对相应的code码进行相应的处理
          switch(code)
          {
             
 case TYPE_WRITE_OFFSET:
              {
                  //write offset value
                  jint offset = data.readInt32();
                  jint write_count = data.readInt32();
                  char *value = (char *)malloc(write_count);
                  data.read(value,write_count);
                  ALOGD("phasecheck_sprd nativeservice write offset=%d,write_count=%d",offset, write_count);
                  int ret = eng_writeOffset(offset, write_count, value);
                  ALOGD("phasecheck_sprd nativeservice write ret=%d",ret);
                  free(value);
                  return NO_ERROR;
              }
          case TYPE_READ_OFFSET:
              {
                  //read byte array with offset
                  jint offset = data.readInt32();
                  jint read_count = data.readInt32();
                  char *value = (char *)malloc(read_count);
                  ALOGD("phasecheck_sprd nativeservice read offset=%d,read_count=%d",offset,read_count);
                  int ret = eng_readOffset(offset, read_count, value);
                  ALOGD("phasecheck_sprd nativeservice read offset is 0x%x, ret = %d", value, ret);
                  reply->write(value, ret);
                  free(value);
                  return NO_ERROR;
              }
        }
    }

再来看看获取对应code后的具体实现,主要就是以下两个方法:
主要就是读写设备文件节点

 jint eng_writeOffset(int offset, int write_count, char* value)
      {
          int len;
          ENG_LOG("eng_writeOffset: offset = %d, write_count = %d", offset, write_count);
          char buf[PROPERTY_VALUE_MAX];
          len = property_get(PHASE_CHECK_MISCDATA_PATH, buf, "");
          char* phasecheckPath = strcat(buf, PHASE_CHECK_MISCDATA);
          ENG_LOG("phasecheck_sprd : phasecheck Path:%s\n", phasecheckPath);
  
          int fd = open(phasecheckPath,O_RDWR);
          if (fd >= 0)
          {
              ENG_LOG("%s open Ok phasecheckPath = %s \n",__FUNCTION__ , phasecheckPath);
              int ret = lseek(fd, offset, SEEK_SET);
              if (ret < 0){
                  close(fd);
                  ENG_LOG("%s lseek fail phasecheckPath = %s \n",__FUNCTION__ , phasecheckPath);
                  return -1;
              }
              len = write(fd, value, write_count);
              ENG_LOG("write: %d", len);
              fsync(fd);
              close(fd);
              if (len <= 0){
                  ENG_LOG("%s read fail phasecheckPath = %s \n",__FUNCTION__ , phasecheckPath);
                  return -1;
              }
          } else {
              ENG_LOG("%s open fail phasecheckPath = %s \n",__FUNCTION__ , phasecheckPath);
              return -1;
          }
  
          return len;
      }
  
      int eng_readOffset(int offset,int read_count, char *value)
      {
          int len = 0;
          ENG_LOG("eng_readOffset: offset = %d, read_count= %d", offset, read_count);
          char buf[PROPERTY_VALUE_MAX];
          len = property_get(PHASE_CHECK_MISCDATA_PATH, buf, "");
          char* phasecheckPath = strcat(buf, PHASE_CHECK_MISCDATA);
          int fd = open(phasecheckPath,O_RDWR);
          if (fd >= 0)
          {
              ENG_LOG("%s open Ok phasecheckPath = %s \n",__FUNCTION__ , phasecheckPath);
              //lseek(fd, offset, SEEK_SET);
              int ret = lseek(fd, offset, SEEK_SET);
              if (ret < 0){
                  close(fd);
                  ENG_LOG("%s lseek fail phasecheckPath = %s \n",__FUNCTION__ , phasecheckPath);
                  return -1;
              }
              len = read(fd, value, read_count);
              ENG_LOG("read: %d", len);
              close(fd);
              if (len <= 0){
                  ENG_LOG("%s read fail phasecheckPath = %s \n",__FUNCTION__ , phasecheckPath);
                  return -1;
              }
          } else {
              ENG_LOG("%s open fail phasecheckPath = %s \n",__FUNCTION__ , phasecheckPath);
              return -1;
          }
          return len;
      }
三. 总结

以上就是对miscdata分区数据读写的一个简要分析了

  1. 以一个C/S结构的思想进行一个解读,主要就是对文件系统的读取操作
  2. 通过AIDL对其进行简单的使用
  3. 使用socket进行通信(有待完善)
  4. 使用binder对服务进行一个注册管理(有待完善)
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值