blob: ab985d4de7524073ce72261d7c61271994f1c595 [file] [log] [blame]
package com.android.networkstack.tethering.companionproxy.io;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.OsConstants;
import android.system.StructPollfd;
import com.android.networkstack.tethering.companionproxy.util.Assertions;
import java.io.FileDescriptor;
import java.io.InterruptedIOException;
import java.io.IOException;
/**
* Implements OsAccess for Android OS at runtime.
*
* @hide
*/
public final class AndroidOsAccess extends OsAccess {
@Override
public long monotonicTimeMillis() {
return System.nanoTime() / 1000000;
}
@Override
public FileDescriptor getInnerFileDescriptor(ParcelFileDescriptor fd) {
return fd.getFileDescriptor();
}
@Override
public String getFileDebugName(ParcelFileDescriptor fd) {
if (fd == null) {
return "null";
}
try {
return Integer.toString(fd.getFd());
} catch (IllegalStateException e) {
return "closed";
}
}
@Override
public void close(ParcelFileDescriptor fd) {
try {
// Android version of close() works correctly.
// Tests use a different implementation.
fd.close();
} catch (IOException e) {
// ignore
}
}
@Override
public int read(FileDescriptor fd, byte[] buffer, int pos, int len)
throws IOException {
Assertions.throwsIfOutOfBounds(buffer.length, pos, len);
if (len == 0) {
return 0;
}
try {
int readCount = android.system.Os.read(fd, buffer, pos, len);
if (readCount == 0) {
// Java convention uses -1 to indicate end of stream.
return -1;
}
return readCount;
} catch (ErrnoException e) {
if (e.errno == OsConstants.EAGAIN) {
return 0;
}
throw e.rethrowAsIOException();
}
}
@Override
public int write(FileDescriptor fd, byte[] buffer, int pos, int len)
throws IOException {
Assertions.throwsIfOutOfBounds(buffer.length, pos, len);
if (len == 0) {
return 0;
}
try {
return android.system.Os.write(fd, buffer, pos, len);
} catch (ErrnoException e) {
if (e.errno == OsConstants.EAGAIN) {
return 0;
}
throw e.rethrowAsIOException();
}
}
@Override
public void setNonBlocking(FileDescriptor fd) throws IOException {
try {
int flags = android.system.Os.fcntlInt(fd, OsConstants.F_GETFL, 0);
if (flags < 0) {
throw new ErrnoException("Unable to get FD flags", OsConstants.EINVAL);
}
flags = flags | OsConstants.O_NONBLOCK | OsConstants.FD_CLOEXEC;
if (android.system.Os.fcntlInt(fd, OsConstants.F_SETFL, flags) != 0) {
throw new ErrnoException("Unable to set FD flags", OsConstants.EINVAL);
}
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
}
}
@Override
public ParcelFileDescriptor[] pipe() throws IOException {
FileDescriptor[] fds = null;
try {
fds = android.system.Os.pipe();
if (fds == null) {
throw new IOException("Os.pipe() returned null");
}
ParcelFileDescriptor[] result = new ParcelFileDescriptor[2];
result[0] = ParcelFileDescriptor.dup(fds[0]);
result[1] = ParcelFileDescriptor.dup(fds[1]);
return result;
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
} finally {
if (fds != null) {
close(fds[0]);
close(fds[1]);
}
}
}
private static void close(FileDescriptor fd) {
if (fd != null) {
try {
android.system.Os.close(fd);
} catch (ErrnoException e) {
// ignore
}
}
}
@Override
public int poll(StructPollfd[] fds, int timeoutMs) throws IOException {
try {
return android.system.Os.poll(fds, timeoutMs);
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
}
}
@Override
public short getPollInMask() {
return (short) OsConstants.POLLIN;
}
@Override
public short getPollOutMask() {
return (short) OsConstants.POLLOUT;
}
}