blob: 3bcc4b99c687cc4b1921283b4f54835c507fad6a [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.cts;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.AutoCloseInputStream;
import android.os.Parcelable;
import android.os.cts.ParcelFileDescriptorPeer.FutureCloseListener;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
import com.google.common.util.concurrent.AbstractFuture;
import junit.framework.ComparisonFailure;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.TimeUnit;
public class ParcelFileDescriptorTest extends AndroidTestCase {
private static final long DURATION = 100l;
public void testConstructorAndOpen() throws Exception {
ParcelFileDescriptor tempFile = makeParcelFileDescriptor(getContext());
ParcelFileDescriptor pfd = new ParcelFileDescriptor(tempFile);
AutoCloseInputStream in = new AutoCloseInputStream(pfd);
try {
// read the data that was wrote previously
assertEquals(0, in.read());
assertEquals(1, in.read());
assertEquals(2, in.read());
assertEquals(3, in.read());
} finally {
in.close();
}
}
private static class DoneSignal extends AbstractFuture<Void> {
public boolean set() {
return super.set(null);
}
@Override
public boolean setException(Throwable t) {
return super.setException(t);
}
}
public void testFromSocket() throws Throwable {
final int PORT = 12222;
final int DATA = 1;
final DoneSignal done = new DoneSignal();
final Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
ServerSocket ss;
ss = new ServerSocket(PORT);
Socket sSocket = ss.accept();
OutputStream out = sSocket.getOutputStream();
out.write(DATA);
Thread.sleep(DURATION);
out.close();
done.set();
} catch (Exception e) {
done.setException(e);
}
}
});
t.start();
Thread.sleep(DURATION);
Socket socket;
socket = new Socket(InetAddress.getLocalHost(), PORT);
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
AutoCloseInputStream in = new AutoCloseInputStream(pfd);
assertEquals(DATA, in.read());
in.close();
socket.close();
pfd.close();
done.get(5, TimeUnit.SECONDS);
}
public void testFromData() throws IOException {
assertNull(ParcelFileDescriptor.fromData(null, null));
byte[] data = new byte[] { 0 };
assertFileDescriptorContent(data, ParcelFileDescriptor.fromData(data, null));
data = new byte[] { 0, 1, 2, 3 };
assertFileDescriptorContent(data, ParcelFileDescriptor.fromData(data, null));
data = new byte[0];
assertFileDescriptorContent(data, ParcelFileDescriptor.fromData(data, null));
// Check that modifying the data does not modify the data in the FD
data = new byte[] { 0, 1, 2, 3 };
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromData(data, null);
data[1] = 42;
assertFileDescriptorContent(new byte[] { 0, 1, 2, 3 }, pfd);
}
private static void assertFileDescriptorContent(byte[] expected, ParcelFileDescriptor fd)
throws IOException {
assertInputStreamContent(expected, new ParcelFileDescriptor.AutoCloseInputStream(fd));
}
private static void assertInputStreamContent(byte[] expected, InputStream is)
throws IOException {
try {
byte[] observed = new byte[expected.length];
int count = is.read(observed);
assertEquals(expected.length, count);
assertEquals(-1, is.read());
MoreAsserts.assertEquals(expected, observed);
} finally {
is.close();
}
}
public void testFromDataSkip() throws IOException {
byte[] data = new byte[] { 40, 41, 42, 43, 44, 45, 46 };
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromData(data, null);
assertNotNull(pfd);
FileDescriptor fd = pfd.getFileDescriptor();
assertNotNull(fd);
assertTrue(fd.valid());
FileInputStream is = new FileInputStream(fd);
try {
assertEquals(1, is.skip(1));
assertEquals(41, is.read());
assertEquals(42, is.read());
assertEquals(2, is.skip(2));
assertEquals(45, is.read());
assertEquals(46, is.read());
assertEquals(-1, is.read());
} finally {
is.close();
}
}
public void testToString() {
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
assertNotNull(pfd.toString());
}
public void testWriteToParcel() throws Exception {
ParcelFileDescriptor pf = makeParcelFileDescriptor(getContext());
Parcel pl = Parcel.obtain();
pf.writeToParcel(pl, ParcelFileDescriptor.PARCELABLE_WRITE_RETURN_VALUE);
pl.setDataPosition(0);
ParcelFileDescriptor pfd = ParcelFileDescriptor.CREATOR.createFromParcel(pl);
AutoCloseInputStream in = new AutoCloseInputStream(pfd);
try {
// read the data that was wrote previously
assertEquals(0, in.read());
assertEquals(1, in.read());
assertEquals(2, in.read());
assertEquals(3, in.read());
} finally {
in.close();
}
}
public void testClose() throws Exception {
ParcelFileDescriptor pf = makeParcelFileDescriptor(getContext());
AutoCloseInputStream in1 = new AutoCloseInputStream(pf);
try {
assertEquals(0, in1.read());
} finally {
in1.close();
}
pf.close();
AutoCloseInputStream in2 = new AutoCloseInputStream(pf);
try {
assertEquals(0, in2.read());
fail("Failed to throw exception.");
} catch (Exception e) {
// expected
} finally {
in2.close();
}
}
public void testGetStatSize() throws Exception {
ParcelFileDescriptor pf = makeParcelFileDescriptor(getContext());
assertTrue(pf.getStatSize() >= 0);
}
public void testGetFileDescriptor() {
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
assertNotNull(pfd.getFileDescriptor());
ParcelFileDescriptor p = new ParcelFileDescriptor(pfd);
assertSame(pfd.getFileDescriptor(), p.getFileDescriptor());
}
public void testDescribeContents() {
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
assertTrue((Parcelable.CONTENTS_FILE_DESCRIPTOR & pfd.describeContents()) != 0);
}
private static void assertContains(String expected, String actual) {
if (actual.contains(expected)) return;
throw new ComparisonFailure("", expected, actual);
}
private static void write(ParcelFileDescriptor pfd, int oneByte) throws IOException{
new FileOutputStream(pfd.getFileDescriptor()).write(oneByte);
}
private static int read(ParcelFileDescriptor pfd) throws IOException {
return new FileInputStream(pfd.getFileDescriptor()).read();
}
public void testPipeNormal() throws Exception {
final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createReliablePipe();
final ParcelFileDescriptor red = pipe[0];
final ParcelFileDescriptor blue = pipe[1];
write(blue, 1);
assertEquals(1, read(red));
blue.close();
assertEquals(-1, read(red));
red.checkError();
}
public void testPipeError() throws Exception {
final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createReliablePipe();
final ParcelFileDescriptor red = pipe[0];
final ParcelFileDescriptor blue = pipe[1];
write(blue, 2);
blue.closeWithError("OMG MUFFINS");
// even though closed we should still drain pipe
assertEquals(2, read(red));
assertEquals(-1, read(red));
try {
red.checkError();
fail("expected throw!");
} catch (IOException e) {
assertContains("OMG MUFFINS", e.getMessage());
}
}
public void testFileNormal() throws Exception {
final Handler handler = new Handler(Looper.getMainLooper());
final FutureCloseListener listener = new FutureCloseListener();
final ParcelFileDescriptor file = ParcelFileDescriptor.open(
File.createTempFile("pfd", "bbq"), ParcelFileDescriptor.MODE_READ_WRITE, handler,
listener);
write(file, 7);
file.close();
// make sure we were notified
assertEquals(null, listener.get());
}
public void testFileError() throws Exception {
final Handler handler = new Handler(Looper.getMainLooper());
final FutureCloseListener listener = new FutureCloseListener();
final ParcelFileDescriptor file = ParcelFileDescriptor.open(
File.createTempFile("pfd", "bbq"), ParcelFileDescriptor.MODE_READ_WRITE, handler,
listener);
write(file, 8);
file.closeWithError("OMG BANANAS");
// make sure error came through
assertContains("OMG BANANAS", listener.get().getMessage());
}
public void testFileDetach() throws Exception {
final Handler handler = new Handler(Looper.getMainLooper());
final FutureCloseListener listener = new FutureCloseListener();
final ParcelFileDescriptor file = ParcelFileDescriptor.open(
File.createTempFile("pfd", "bbq"), ParcelFileDescriptor.MODE_READ_WRITE, handler,
listener);
file.detachFd();
// make sure detach came through
assertContains("DETACHED", listener.get().getMessage());
}
public void testSocketErrorAfterClose() throws Exception {
final ParcelFileDescriptor[] pair = ParcelFileDescriptor.createReliableSocketPair();
final ParcelFileDescriptor red = pair[0];
final ParcelFileDescriptor blue = pair[1];
// both sides throw their hands in the air
blue.closeWithError("BLUE RAWR");
red.closeWithError("RED RAWR");
// red noticed the blue error, but after that the comm pipe was dead so
// blue had no way of seeing the red error.
try {
red.checkError();
fail("expected throw!");
} catch (IOException e) {
assertContains("BLUE RAWR", e.getMessage());
}
// expected to not throw; no error
blue.checkError();
}
public void testSocketMultipleCheck() throws Exception {
final ParcelFileDescriptor[] pair = ParcelFileDescriptor.createReliableSocketPair();
final ParcelFileDescriptor red = pair[0];
final ParcelFileDescriptor blue = pair[1];
// allow checking before closed; they should all pass
blue.checkError();
blue.checkError();
blue.checkError();
// and verify we actually see it
red.closeWithError("RAWR RED");
try {
blue.checkError();
fail("expected throw!");
} catch (IOException e) {
assertContains("RAWR RED", e.getMessage());
}
}
// http://b/21578056
public void testFileNamesWithNonBmpChars() throws Exception {
final File file = File.createTempFile("treble_clef_\ud834\udd1e", ".tmp");
final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file,
ParcelFileDescriptor.MODE_READ_ONLY);
assertNotNull(pfd);
pfd.close();
}
static ParcelFileDescriptor makeParcelFileDescriptor(Context con) throws Exception {
final String fileName = "testParcelFileDescriptor";
FileOutputStream fout = null;
fout = con.openFileOutput(fileName, Context.MODE_WORLD_WRITEABLE);
try {
fout.write(new byte[] { 0x0, 0x1, 0x2, 0x3 });
} finally {
fout.close();
}
File dir = con.getFilesDir();
File file = new File(dir, fileName);
ParcelFileDescriptor pf = null;
pf = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
return pf;
}
}