[Android] FileInputStream跟踪

本文主要探讨了在Android环境中如何跟踪FileInputStream的Native实现。由于Java标准库与Android的实现存在差异,作者在分析过程中遇到了一些挑战。通过参考链接中的资料,对FileInputStream的读取操作进行了深入研究。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源起

    需要跟踪FileInputStream的Read的Nativie实现,开始走了弯路,Java工程下的FileInputStream实现与Android工程的实现不同。另外,http://blog.chinaunix.net/uid-26926660-id-3326678.html中分析的不错。

java.io.FileInputStream

   @Override public int read() throws IOException {
        return Streams.readSingleByte(this);
    }

    @Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
        return IoBridge.read(fd, buffer, byteOffset, byteCount);
    }

libcore.io.Streams

public static int readSingleByte(InputStream in) throws IOException {
    byte[] buffer = new byte[1];
    int result = in.read(buffer, 0, 1); // in.read() -> FileInputStream.read -> IoBridge.read
    return (result != -1) ? buffer[0] & 0xff : -1;
}
最终还是调用IoBridge.read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) 

libcore.io.ioBridge
https://android.googlesource.com/platform/libcore/+/796f0d5a4e7b83c3efc5e587b6766977dc20b0c3/luni/src/main/java/libcore/io/IoBridge.java

    public static int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {
        Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount); 检查数组是否越界
        if (byteCount == 0) {
            return 0;
        }
        try {
            int readCount = Libcore.os.read(fd, bytes, byteOffset, byteCount);
            if (readCount == 0) {
                return -1;
            }
            return readCount;
        } catch (ErrnoException errnoException) {
            if (errnoException.errno == EAGAIN) { // Linux中非阻塞线程里面执行阻塞工作,会有这样的错误码,该错误码是native实现
                // We return 0 rather than throw if we try to read from an empty non-blocking pipe.
                return 0;
            }
            throw errnoException.rethrowAsIOException();
        }
    }

Java.util.Arrays
https://android.googlesource.com/platform/libcore/+/2bad9bff258de6275bd3847e5e9f3169b0a93c61/luni/src/main/java/java/util/Arrays.java
public static void checkOffsetAndCount(int arrayLength, int offset, int count) {
     if ((offset | count) < 0 || offset > arrayLength || arrayLength - offset < count) {
         throw new ArrayIndexOutOfBoundsException(arrayLength, offset, count);
    }
}

OsConstants.java
https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/libcore/io/OsConstants.java

public static final int EAGAIN = placeholder();
private static native void initConstants();
// A hack to avoid these constants being inlined by javac...
private static int placeholder() { return 0; }
// ...because we want to initialize them at runtime.
static {
   initConstants();
}

libcore_io_OsConstants.cpp
https://android.googlesource.com/platform/libcore/+/2bad9bff258de6275bd3847e5e9f3169b0a93c61/luni/src/main/native/libcore_io_OsConstants.cpp
#define EAGAIN 11 /* Try again */

libcore.io.Libcore
http://grepcode.com/file/repo1.maven.org/maven2/org.robovm/robovm-rt/0.0.2/libcore/io/Libcore.java#Libcore

package libcore.io;

public final class Libcore {
    private Libcore() { }

    public static Os os = new BlockGuardOs(new Posix());
}

BlockGuardOs
android / platform/libcore / 2bad9bff258de6275bd3847e5e9f3169b0a93c61 / . / luni / src / main / java / libcore / io / BlockGuardOs.java

@Override public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException {
    BlockGuard.getThreadPolicy().onReadFromDisk(); // BlockGuard. getThreadPolicy()是一个单例
    return os.read(fd, bytes, byteOffset, byteCount); // 使用的是Posix中的read
}

Libcore.io.Posix
https://android.googlesource.com/platform/libcore/+/6c9b5377550a9649ed1532d1fcdfeba116c74ead/luni/src/main/java/libcore/io/Posix.java
    
public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException {
        // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
        return readBytes(fd, bytes, byteOffset, byteCount);
}
private native int readBytes(FileDescriptor fd, Object buffer, int offset, int byteCount) throws ErrnoException;

src/main/native/libcore_io_Posix.cpp
https://android.googlesource.com/platform/libcore/+/721ceca2a52a3c27aa751476c8562e1e68088e15/luni/src/main/native/libcore_io_Posix.cpp

#include <unistd.h>
#include "ScopeBytes.h"

static jint Posix_readBytes(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount) {
    ScopedBytesRW bytes(env, javaBytes); // ScopeBytes.h中有定义
    if (bytes.get() == NULL) {
        return -1;
    }
    int fd = jniGetFDFromFileDescriptor(env, javaFd);
    return throwIfMinusOne(env, "read", TEMP_FAILURE_RETRY(read(fd, bytes.get() + byteOffset, byteCount)));
}

1. ScopedBytesRW bytes(env, javaBytes); ScopeBytes.h中有定义
https://android.googlesource.com/platform/libnativehelper/+/3d9d2148155c2e0b3bf51cd548f58f93d1199a4e/include/nativehelper/ScopedBytes.h
2. throwIfMinusOne和TEMP_FAILURE_RETRY
3. read(fd, bytes.get() + byteOffset, byteCount)就是c的库函数

throwIfMinusOne

template <typename rc_t>
static rc_t throwIfMinusOne(JNIEnv* env, const char* name, rc_t rc) {
    if (rc == rc_t(-1)) {
        throwErrnoException(env, name);
    }
    return rc;
}

static void throwErrnoException(JNIEnv* env, const char* name) {
    int errnum = errno;

    jthrowable cause = NULL;
    if (env->ExceptionCheck()) {
        cause = env->ExceptionOccurred();
        env->ExceptionClear();
    }

    ScopedLocalRef<jstring> javaName(env, env->NewStringUTF(name));
    if (javaName.get() == NULL) {
        // Not really much we can do here. We're probably dead in the water,
        // but let's try to stumble on...
        env->ExceptionClear();
    }

    jobject exception;
    if (cause != NULL) {
        static jmethodID ctor = env->GetMethodID(JniConstants::errnoExceptionClass, "<init>",
                "(Ljava/lang/String;ILjava/lang/Throwable;)V");
        exception = env->NewObject(JniConstants::errnoExceptionClass, ctor,
                javaName.get(), errnum, cause);
    } else {
        static jmethodID ctor = env->GetMethodID(JniConstants::errnoExceptionClass, "<init>",
                "(Ljava/lang/String;I)V");
        exception = env->NewObject(JniConstants::errnoExceptionClass, ctor, javaName.get(), errnum);
    }
    env->Throw(reinterpret_cast<jthrowable>(exception));
}

TEMP_FAILURE_RETRY

unistd.h,http://sinf1252.info.ucl.ac.be/usr/include/unistd.h.html
# define TEMP_FAILURE_RETRY(expression) \
  (__extension__                                                              \
    ({ long int __result;                                                      \
       do __result = (long int) (expression);                                      \
       while (__result == -1L && errno == EINTR);                              \
       __result; }))
#endif

本文链接

    http://blog.youkuaiyun.com/xiaodongrush/article/details/10004997

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值