Flo*_*low 12 android ipc pipe android-service android-binder
我想通过使用ParcelFileDescriptor.createPipe()一个流到流的复制线程和一个ParcelFileDescriptor,将一个Android服务从一个Android服务"发送"到一个不同进程中运行的另一个服务,该表示管道的读取端,它被提供给另一个服务借助Binder IPC.
我想将一个给定的InputStream发送到接收服务:
public sendInputStream() {
InputStream is = ...; // that's the stream for process/service B
ParcelFileDescriptor pdf = ParcelFileDescriptorUtil.pipeFrom(is);
inputStreamService.inputStream(pdf);
}
Run Code Online (Sandbox Code Playgroud)
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) {
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
接收服务.aidl:
package org.exmaple;
interface IInputStreamService {
void inputStream(in ParcelFileDescriptor pfd);
}
Run Code Online (Sandbox Code Playgroud)
进程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
}
}
};
Run Code Online (Sandbox Code Playgroud)
但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)
Run Code Online (Sandbox Code Playgroud)
看起来EBADF错误是read()在文件描述符关闭时设置的.但我不知道是什么导致它以及如何解决它.
是的,我知道ConentProvider也是可能的.但它不应该与我的方法一起工作吗?有没有其他方法可以将InputStream流传递给Android中的其他服务?
在一个侧面说明:CommonsWare创造了一个类似的使用ContentProvider的项目(相关SO问题1,2).这是我从我的方法中获得大部分想法的地方
Flo*_*low 11
似乎原因是ParcelFileDescriptor作为服务方法的参数.如果服务确实返回,ParcelFileDescriptor它按预期工作.
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) {}
}
}
Run Code Online (Sandbox Code Playgroud)
接收服务.aidl:
package org.exmaple;
interface IInputStreamService {
ParcelFileDescriptor inputStream();
}
Run Code Online (Sandbox Code Playgroud)
进程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;
}
};
Run Code Online (Sandbox Code Playgroud)
ParcelFileDescriptorUtil是一个辅助类,具有经典的java.io.流到流复制线程.现在我们必须使用该pipeTo()方法.
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) {
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这允许您跨进程边界传输InputStream,一个缺点是流到流副本中涉及一些CPU时间.
| 归档时间: |
|
| 查看次数: |
8031 次 |
| 最近记录: |