Sharing shared Memory File descriptors across android app/processes using binder

1,808 views
Skip to first unread message

Sachin Gole

unread,
Feb 24, 2014, 6:36:43 AM2/24/14
to andro...@googlegroups.com
We have two processes which interacts through shared memory to read/write data. One process is application(client) and other process is background service which is separate application in this example it is ashmem producer service.
AshmemService :- This is background running service which is sticky, this provides API to create shared memory channel using android MemoryFile API. This service creates shared memory and get file descriptor and that fd is passed to client process through binder interface.
AshmemClient :- This is application which get shared memory channel file descriptor from AshmemService. This client app binds to service, once it is connected it calls aidl interface api to get fd. 
Channel creation works fine which creates shared memory , Now for testing purpose I am writing block of bytes from Client to shared memory. once writing is done then I am trying to same block in service to valid data received from app.

From Client app whenever I am trying to write block of 128 bytes, writes returns 0 so looks like I am not able to write in FD which is received through parcelable binder. Even I have verified that fd is valid through fd.valid() API.

pfd.getStatSize() returns -1. I think I am not getting correct fd from parcelable file descriptor.


The returned file descriptor is a dup of the original file descriptor: the object and fd is different, but operating on the same underlying file stream, with the same position, etc.
In Reverse case, which is in service where we have created shared memory if we try to write byte block then same block we can read in application that I have validated and it is working as expected.


 package com.example.service.ashmem;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;
import java.nio.ByteBuffer;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.util.Log;


public class ConnectionWriter implements Parcelable {
    public final static String TAG = "ConnectionWriter";

    protected FileOutputStream fos = null;
    protected FileDescriptor fd = null;
    protected int noofBlocks = 0;
    protected int blocksize = 0;
    protected int lastPosition;
    protected int chanId;

    public ConnectionWriter(MemoryFileChannel channel, int chanId) {

        this.fd = channel.getFileDescriptor();
        channel.getParcelFileDescriptor();
        this.chanId = chanId;
        this.blocksize = channel.getBlocksize();
        this.noofBlocks = channel.getNoofBlocks();
        Log.d(TAG, "ctor: chanId: " + chanId + " fd valid: " + fd.valid()+ " fd: "+fd);
    }

    public ConnectionWriter(Parcel in) {
        readFromParcel(in);
    }

    public static final Parcelable.Creator<ConnectionWriter> CREATOR = new
            Parcelable.Creator<ConnectionWriter>() {
                public ConnectionWriter createFromParcel(Parcel in) {
                    Log.d(TAG, "new ConnectionWriter");
                    return new ConnectionWriter(in);
                }

                @Override
                public ConnectionWriter[] newArray(int arg0) {
                    return null;
                }           
        };

    public boolean writeBlock(ByteBuffer data, int pos)
            throws IllegalArgumentException, IOException {
        FileChannel fc = fos.getChannel();


        Log.d(TAG, "ByteBuffer capacity : "+data.capacity());
        Log.d(TAG, "location to write : "+pos*blocksize);
        Log.d(TAG, "FileChannel : "+fc.isOpen() + fc.position() + fc.size());
        int len = fc.write(data);
        Log.d(TAG, "block write in ashmem : "+len + " fd: "+fd);
        return true;
    }

    public void writeToParcel(Parcel out, int arg1) {
        Log.d(TAG, "writeToParcel "+ "fd: "+fd + " fd valid"+ fd.valid());

        out.writeInt(blocksize);
        out.writeInt(noofBlocks);
        out.writeFileDescriptor(fd);
        out.writeInt(lastPosition);
        out.writeInt(chanId);
    }

    public void readFromParcel(Parcel in) {
        // Make sure to validate data since these are coming from an external process
        blocksize = in.readInt();
        noofBlocks = in.readInt();
        ParcelFileDescriptor pfd = in.readFileDescriptor();
        if (pfd != null) {
            fd = pfd.getFileDescriptor();
            Log.d(TAG, "readFromParcel "+ "fd: "+fd);
            fos = new FileOutputStream(fd);
            Log.v(TAG, "  fd is " + fd.valid());
            long stat = pfd.getStatSize();
            Log.d(TAG, "  fd stat " + stat);
        }
        lastPosition = in.readInt();
        chanId = in.readInt();
    }

    public int getId() {
        return chanId;
    }

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    public void close() {
        try {
            if (fos != null)
                fos.close();
        } catch (IOException ioe) {
        }
    }
}

Below are logs on adb logcat

ConnectionWriter(31694): new ConnectionWriter
ConnectionWriter(31694): readFromParcel fd: FileDescriptor[58]
ConnectionWriter(31694):   fd is true
ConnectionWriter(31694):   fd stat -1
ConnectionWriter(31694): ByteBuffer capacity : 128
ConnectionWriter(31694): location to write : 0
ConnectionWriter(31694): FileChannel : true00
ConnectionWriter(31694): block write in ashmem : 0 fd: FileDescriptor[58]

 am not sure but looks like I am not getting correct ParcelFileDescriptor. If anybody has any suggestion about sharing MemoryFile fd. please suggest.

pacha...@gmail.com

unread,
Feb 24, 2014, 9:36:10 PM2/24/14
to andro...@googlegroups.com
How do you know that the process you are writing to is still the service? That's not guaranteed... Why is a Content Provider not apropos?
Reply all
Reply to author
Forward
0 new messages