EBADF(错误的文件数)QUOT;与ParcelFileDescriptor.createPipe()failes与&QUOT转移的InputStream到另一个服务(跨进程); [英] Transfer InputStream to another Service (across process boundaries) with ParcelFileDescriptor.createPipe() failes with "EBADF (Bad file number)"

查看:1182
本文介绍了EBADF(错误的文件数)QUOT;与ParcelFileDescriptor.createPipe()failes与&QUOT转移的InputStream到另一个服务(跨进程);的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从一个机器人服务送的InputStream内不同的进程中运行其他服务使用<一个href="http://developer.android.com/reference/android/os/ParcelFileDescriptor.html#createPipe%28%29"><$c$c>ParcelFileDescriptor.createPipe(),一个流来流复制线程和ParcelFileDescriptor,再presenting管道,这是考虑到其他的服务,粘结剂IPC方式的读取端。

I want to "send" an InputStream from one Android Service to another service running within a different process by using ParcelFileDescriptor.createPipe(), a stream-to-stream copy thread and a ParcelFileDescriptor, representing the read side of the pipe, which is given to the other service with means of Binder IPC.

我想给定的InputStream发送到接收服务:

I want to send a given InputStream to the receiving service:

public sendInputStream() {
    InputStream is = ...; // that's the stream for process/service B
    ParcelFileDescriptor pdf = ParcelFileDescriptorUtil.pipeFrom(is);
    inputStreamService.inputStream(pdf);
}

该ParcelFileDescriptorUtil是一个辅助类,采用了经典的 java.io 流来流复制主题:

public class ParcelFileDescriptorUtil {

    public static ParcelFileDescriptor pipeFrom(InputStream inputStream) throws IOException {
        ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
        ParcelFileDescriptor readSide = pipe[0];
        ParcelFileDescriptor writeSide = pipe[1];

        // start the transfer thread
        new TransferThread(inputStream, new ParcelFileDescriptor.AutoCloseOutputStream(writeSide)).start();

        return readSide;
    }

    static class TransferThread extends Thread {
        final InputStream mIn;
        final OutputStream mOut;

        TransferThread(InputStream in, OutputStream out) {
            super("ParcelFileDescriptor Transfer Thread");
            mIn = in;
            mOut = out;
            setDaemon(true);
        }

        @Override
        public void run() {
            byte[] buf = new byte[1024];
            int len;

            try {
                while ((len = mIn.read(buf)) > 0) {
                    mOut.write(buf, 0, len);
                }
                mOut.flush(); // just to be safe
            } catch (IOException e) {
                LOG.e("TransferThread", e);
            }
            finally {
                try {
                    mIn.close();
                } catch (IOException e) {
                }
                try {
                    mOut.close();
                } catch (IOException e) {
                }
            }
        }
    }
}

接收服务code(B法)

在接受服务的 .aidl

package org.exmaple;
interface IInputStreamService {
    void inputStream(in ParcelFileDescriptor pfd);
}

接收服务,称为进程A:

The receiving service, called by Process A:

public class InputStreamService extends Service {

@Override
public IBinder onBind(Intent intent) {
    return mBinder;
}

private final IInputStreamService.Stub mBinder = new IInputStreamService.Stub() {

    @Override
    public void inputStream(ParcelFileDescriptor pfd) throws RemoteException {

        InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
        OutputStream os = ...;
        int len;
        byte[] buf = new byte[1024];
        try {
            while ((len = is.read(buf)) > 0) {
                os.write(buf, 0, len);
            }
        } catch (IOException e) {
                        // this catches the exception shown below
        }
    }
};

in.read()的InputStream()总是抛出一个 IOException异常

java.io.IOException: read failed: EBADF (Bad file number)
    at libcore.io.IoBridge.read(IoBridge.java:442)
    at java.io.FileInputStream.read(FileInputStream.java:179)
    at java.io.InputStream.read(InputStream.java:163)

这似乎是EBADF错误号是由设置阅读()时,文件描述符被关闭。但我不知道是什么原因造成的,以及如何解决它。

It seems like the EBADF errno is set by read() when the file descriptor is closed. But I don't know what is causing it and how to fix it.

是的,我知道,一个ConentProvider也将是一个可能性。但应该不是也有我的方法工作吗?是否有任何其他方式来手一个InputStream流发送到不同的服务机器人?

And yes, I know that a ConentProvider would also be a possibility. But shouldn't it also work with my approach? Are there any other ways to hand an InputStream stream to a different service in Android?

在一个侧面说明:CommonsWare创建了一个类似<一个href="https://github.com/commonsguy/cw-omnibus/blob/master/ContentProvider/Pipe/src/com/commonsware/android/cp/pipe/PipeProvider.java">project使用ContentProvider的(SO问题相关的<一个href="http://stackoverflow.com/questions/12920429/anyone-have-mediaplayer-working-with-parcelfiledescriptor-and-createpipe">1, <一href="http://stackoverflow.com/questions/12894976/anyone-have-mediarecorder-working-with-parcelfiledescriptor-and-createpipe">2).这就是我得到了大部分的想法,我的做法从

On a side note: CommonsWare created a similar project using a ContentProvider (related SO questions 1, 2). It's where I got most of the ideas for my approach from

推荐答案

这似乎是原因是 ParcelFileDescriptor 作为服务方法的参数。如果服务的返回的的 ParcelFileDescriptor 它按预期工作。

It seems like the cause was the ParcelFileDescriptor being an argument of the service method. If the service does return the ParcelFileDescriptor it works as expected.

public sendInputStream() {
    InputStream is = ...; // that's the stream for process/service B
    ParcelFileDescriptor pfd = inputStreamService.inputStream();
    OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(pfd);

    int len;
    byte[] buf = new byte[1024];
    try {
        while ((len = is.read(buf)) > 0) {
            os.write(buf, 0, len);
    } catch (IOException e) {
    } finally {
        try { is.close(); } catch (IOException e1) {}
        try { os.close(); ] catch (IOException e1) {}
    }
}

接收服务code(B法)

在接受服务的 .aidl

package org.exmaple;
interface IInputStreamService {
    ParcelFileDescriptor inputStream();
}

接收服务,称为进程A:

The receiving service, called by Process A:

public class InputStreamService extends Service {

@Override
public IBinder onBind(Intent intent) {
    return mBinder;
}

private final IInputStreamService.Stub mBinder = new IInputStreamService.Stub() {

    @Override
    public void ParcelFileDescriptor inputStream() throws RemoteException {
                // one can read the contents of the Processes A's InputStream
                // from the following OutputStream
                OutputStream os = ...;
                ParcelFileDescriptor pfd = ParcelFileDescriptorUtil.pipeTo(os);
                return pfd;
    }
};

该ParcelFileDescriptorUtil是一个辅助类,采用了经典的 java.io。流来流复制线程。 现在我们必须使用 pipeTo()方法的。

The ParcelFileDescriptorUtil is a helper class, with a classic java.io. stream-to-stream copy Thread. Now we have to use the pipeTo() method.

public class ParcelFileDescriptorUtil {

    public static ParcelFileDescriptor pipeTo(OutputStream outputStream) throws IOException {
        ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
        ParcelFileDescriptor readSide = pipe[0];
        ParcelFileDescriptor writeSide = pipe[1];

        // start the transfer thread
        new TransferThread(new ParcelFileDescriptor.AutoCloseInputStream(readSide), outputStream).start();

        return writeSide;
    }

    static class TransferThread extends Thread {
        final InputStream mIn;
        final OutputStream mOut;

        TransferThread(InputStream in, OutputStream out) {
            super("ParcelFileDescriptor Transfer Thread");
            mIn = in;
            mOut = out;
            setDaemon(true);
        }

        @Override
        public void run() {
            byte[] buf = new byte[1024];
            int len;

            try {
                while ((len = mIn.read(buf)) > 0) {
                    mOut.write(buf, 0, len);
                }
                mOut.flush(); // just to be safe
            } catch (IOException e) {
                LOG.e("TransferThread", e);
            }
            finally {
                try {
                    mIn.close();
                } catch (IOException e) {
                }
                try {
                    mOut.close();
                } catch (IOException e) {
                }
            }
        }
    }
}

这可以让你跨越进程边界传递InputStreams,一个缺点是,有参与流来流拷贝一些CPU时间。

This allows you to transfer InputStreams across process boundaries, one drawback is that there is some CPU time involved in the stream-to-stream copies.

这篇关于EBADF(错误的文件数)QUOT;与ParcelFileDescriptor.createPipe()failes与&QUOT转移的InputStream到另一个服务(跨进程);的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆