Implementation of Android method for transferring big data across processes

  • 2021-12-11 18:55:49
  • OfStack

Recently, the picture data should be transmitted from Service to Client, and the previous data was transmitted through aidl:

Create an Parcelable file

ImageData.java


public class ImageData implements Parcelable {
  private byte[] data;
  public byte[] getData() {
    return data;
  }

  public ImageData(byte[] dataIn) {
    this.data = dataIn;
  }

  public ImageData(Parcel in) {
    int arrayLength = in.readInt();
    if (arrayLength > 0) {
      data = new byte[arrayLength];
      in.readByteArray(data);
    }
  }

  @Override
  public void writeToParcel(Parcel dest, int flags) {
    if (data != null && data.length > 0) {
      dest.writeInt(data.length);
      dest.writeByteArray(data);
    } else {
      dest.writeInt(0);
    }
  }
  ...
}

test.aidl
interface test {
  void sendMessage(ImageData data);
}

Run error report:

android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(BinderProxy.java:514)
...

Cause

The main reason for DeadObjectException here is that buffer created by binder is occupied:

kernel/msm-4.4/drivers/android/binder_alloc.c
315 if (best_fit == NULL) {
...
341 pr_err("%d: binder_alloc_buf size %zd failed, no address space\n",
342 alloc- > pid, size);
343 pr_err("allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n",
344 total_alloc_size, allocated_buffers, largest_alloc_size,
345 total_free_size, free_buffers, largest_free_size);
346 eret = ERR_PTR(-ENOSPC);
347 goto error_unlock;
348 }

If the data is larger than free_buffers during transmission, DeadObjectException will be thrown

Solve

1.socket
socke transmission is not limited by size, but it is complicated to implement

2. Documentation
File transfer is simple but inefficient, and higher versions are restricted by Android system permissions

3. Data cutting
Cutting larger data into smaller data transmission is a scheme with both efficiency and complexity

Defining a data body:


public class SliceData implements Parcelable {
  private byte[] data;
  private int length;
  ...
}

Method of cutting data:


  public static byte[][] divideArray(byte[] source, int chunkSize) {
    int totalLength = source.length;
    int arraySize = (int) Math.ceil(totalLength / (double) chunkSize);
    byte[][] ret = new byte[arraySize][chunkSize];
    int start = 0;
    int parts = 0;
    for (int i = 0; i < arraySize; i++) {
      if (start + chunkSize > totalLength) {
        System.arraycopy(source, start, ret[i], 0, source.length - start);
      } else {
        System.arraycopy(source, start, ret[i], 0, chunkSize);
      }
      start += chunkSize;
      parts++;
    }
    return ret;
  }

Build and send SliceData in sequence:


byte[][] divideData = divideArray(testBytes, 64 * 1024);//64k
for (byte[] item : divideData) {
  mEmitter.onNext(new SliceData(length, item));
}

client Receive:


int chunkSize = bytes.length;
if(buffer == null) {
  buffer = new byte[length];
  index = 0;
}
if (index + chunkSize > bodyLength) {// Finally 1 Data blocks 
  System.arraycopy(bytes, 0, buffer, index, bodyLength - index);
  visualResultData.bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
  buffer = null;
  index = 0;
} else {
  System.arraycopy(bytes, 0, buffer, index, chunkSize);
  index += chunkSize;
}

4. Party 3
binder itself uses mmap, and you can use the framework that implements mmap, such as MMKV

5.Bitmap
If the transmitted data is Bitmap, the putBinder scheme of Bundle can also be used
Define binder:


class ImageBinder extends IRemoteGetBitmap.Stub {
  @Override
  public Bitmap getBitMap() throws RemoteException {
    return mBitmap;
  }
}

Send


Bundle bundle = new Bundle();
bundle.putBinder("bitmap", new ImageBinder());
intent.putExtras(bundle);

Receive:


ImageBinder imageBinder = (ImageBinder) bundle.getBinder("bitmap");
Bitmap bitmap = imageBinder.getBitmap();

Related articles: