1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.os; 18 19 import static android.system.OsConstants.AF_UNIX; 20 import static android.system.OsConstants.SOCK_STREAM; 21 22 import android.system.ErrnoException; 23 import android.system.Os; 24 import android.util.Log; 25 26 import libcore.io.IoBridge; 27 import libcore.io.IoUtils; 28 import libcore.io.Memory; 29 import libcore.io.Streams; 30 31 import java.io.FileDescriptor; 32 import java.io.IOException; 33 import java.io.OutputStream; 34 import java.nio.ByteOrder; 35 import java.util.Arrays; 36 37 /** 38 * Simple bridge that allows file access across process boundaries without 39 * returning the underlying {@link FileDescriptor}. This is useful when the 40 * server side needs to strongly assert that a client side is completely 41 * hands-off. 42 * 43 * @hide 44 * @deprecated replaced by {@link RevocableFileDescriptor} 45 */ 46 @Deprecated 47 public class FileBridge extends Thread { 48 private static final String TAG = "FileBridge"; 49 50 // TODO: consider extending to support bidirectional IO 51 52 private static final int MSG_LENGTH = 8; 53 54 /** CMD_WRITE [len] [data] */ 55 private static final int CMD_WRITE = 1; 56 /** CMD_FSYNC */ 57 private static final int CMD_FSYNC = 2; 58 /** CMD_CLOSE */ 59 private static final int CMD_CLOSE = 3; 60 61 private FileDescriptor mTarget; 62 63 private final FileDescriptor mServer = new FileDescriptor(); 64 private final FileDescriptor mClient = new FileDescriptor(); 65 66 private volatile boolean mClosed; 67 FileBridge()68 public FileBridge() { 69 try { 70 Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mServer, mClient); 71 } catch (ErrnoException e) { 72 throw new RuntimeException("Failed to create bridge"); 73 } 74 } 75 isClosed()76 public boolean isClosed() { 77 return mClosed; 78 } 79 forceClose()80 public void forceClose() { 81 IoUtils.closeQuietly(mTarget); 82 IoUtils.closeQuietly(mServer); 83 IoUtils.closeQuietly(mClient); 84 mClosed = true; 85 } 86 setTargetFile(FileDescriptor target)87 public void setTargetFile(FileDescriptor target) { 88 mTarget = target; 89 } 90 getClientSocket()91 public FileDescriptor getClientSocket() { 92 return mClient; 93 } 94 95 @Override run()96 public void run() { 97 final byte[] temp = new byte[8192]; 98 try { 99 while (IoBridge.read(mServer, temp, 0, MSG_LENGTH) == MSG_LENGTH) { 100 final int cmd = Memory.peekInt(temp, 0, ByteOrder.BIG_ENDIAN); 101 if (cmd == CMD_WRITE) { 102 // Shuttle data into local file 103 int len = Memory.peekInt(temp, 4, ByteOrder.BIG_ENDIAN); 104 while (len > 0) { 105 int n = IoBridge.read(mServer, temp, 0, Math.min(temp.length, len)); 106 if (n == -1) { 107 throw new IOException( 108 "Unexpected EOF; still expected " + len + " bytes"); 109 } 110 IoBridge.write(mTarget, temp, 0, n); 111 len -= n; 112 } 113 114 } else if (cmd == CMD_FSYNC) { 115 // Sync and echo back to confirm 116 Os.fsync(mTarget); 117 IoBridge.write(mServer, temp, 0, MSG_LENGTH); 118 119 } else if (cmd == CMD_CLOSE) { 120 // Close and echo back to confirm 121 Os.fsync(mTarget); 122 Os.close(mTarget); 123 mClosed = true; 124 IoBridge.write(mServer, temp, 0, MSG_LENGTH); 125 break; 126 } 127 } 128 129 } catch (ErrnoException | IOException e) { 130 Log.wtf(TAG, "Failed during bridge", e); 131 } finally { 132 forceClose(); 133 } 134 } 135 136 public static class FileBridgeOutputStream extends OutputStream { 137 private final ParcelFileDescriptor mClientPfd; 138 private final FileDescriptor mClient; 139 private final byte[] mTemp = new byte[MSG_LENGTH]; 140 FileBridgeOutputStream(ParcelFileDescriptor clientPfd)141 public FileBridgeOutputStream(ParcelFileDescriptor clientPfd) { 142 mClientPfd = clientPfd; 143 mClient = clientPfd.getFileDescriptor(); 144 } 145 FileBridgeOutputStream(FileDescriptor client)146 public FileBridgeOutputStream(FileDescriptor client) { 147 mClientPfd = null; 148 mClient = client; 149 } 150 151 @Override close()152 public void close() throws IOException { 153 try { 154 writeCommandAndBlock(CMD_CLOSE, "close()"); 155 } finally { 156 IoBridge.closeAndSignalBlockedThreads(mClient); 157 IoUtils.closeQuietly(mClientPfd); 158 } 159 } 160 fsync()161 public void fsync() throws IOException { 162 writeCommandAndBlock(CMD_FSYNC, "fsync()"); 163 } 164 writeCommandAndBlock(int cmd, String cmdString)165 private void writeCommandAndBlock(int cmd, String cmdString) throws IOException { 166 Memory.pokeInt(mTemp, 0, cmd, ByteOrder.BIG_ENDIAN); 167 IoBridge.write(mClient, mTemp, 0, MSG_LENGTH); 168 169 // Wait for server to ack 170 if (IoBridge.read(mClient, mTemp, 0, MSG_LENGTH) == MSG_LENGTH) { 171 if (Memory.peekInt(mTemp, 0, ByteOrder.BIG_ENDIAN) == cmd) { 172 return; 173 } 174 } 175 176 throw new IOException("Failed to execute " + cmdString + " across bridge"); 177 } 178 179 @Override write(byte[] buffer, int byteOffset, int byteCount)180 public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException { 181 Arrays.checkOffsetAndCount(buffer.length, byteOffset, byteCount); 182 Memory.pokeInt(mTemp, 0, CMD_WRITE, ByteOrder.BIG_ENDIAN); 183 Memory.pokeInt(mTemp, 4, byteCount, ByteOrder.BIG_ENDIAN); 184 IoBridge.write(mClient, mTemp, 0, MSG_LENGTH); 185 IoBridge.write(mClient, buffer, byteOffset, byteCount); 186 } 187 188 @Override write(int oneByte)189 public void write(int oneByte) throws IOException { 190 Streams.writeSingleByte(this, oneByte); 191 } 192 } 193 } 194