使用binder在android app / processes之间共享共享内存文件描述符

时间:2014-02-22 13:56:51

标签: java android android-ndk

我们有两个进程通过共享内存进行交互以读/写数据。一个过程是应用程序(客户端),其他过程是后台服务,在这个例子中是单独的应用程序,它是ashmem生产者服务。

  • AshmemService: - 这是后台运行服务,它是粘性的,这提供了使用android MemoryFile API创建共享内存通道的API。此服务创建共享内存并获取文件描述符,并通过绑定器接口将fd传递给客户端进程。

  • AshmemClient: - 这是从AshmemService获取共享内存通道文件描述符的应用程序。这个客户端应用程序绑定到服务,一旦连接它调用aidl接口api获取fd。 通道创建工作正常,创建共享内存。现在,为了测试目的,我正在从客户端写入字节块到共享内存。一旦完成写作,我就会尝试将相同的块用于从app收到的有效数据。

每当我尝试写入128字节的块时,从客户端应用程序,写入返回0,所以看起来我无法写入通过parcelable binder接收的FD。即使我已经验证了fd通过fd.valid()API有效。

pfd.getStatSize()返回-1。我想我没有从parcelable文件描述符中获得正确的fd。

http://developer.android.com/reference/android/os/Parcel.html

返回的文件描述符是原始文件描述符的副本:对象和fd不同,但是在相同的底层文件流上操作,具有相同的位置等。 在反向情况下,如果我们尝试写字节块然后在同一个块中创建共享内存,那么我们可以在已经验证的应用程序中读取并且它正在按预期工作。

    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) {
        }
    }
}

以下是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]

我不确定,但看起来我没有得到正确的ParcelFileDescriptor。如果有人有任何关于共享MemoryFile fd的建议。请建议。

0 个答案:

没有答案