当前位置: 代码迷 >> Android >> android的应用层代码毕竟层代码的流程
  详细解决方案

android的应用层代码毕竟层代码的流程

热度:84   发布时间:2016-05-01 19:59:07.0
android的应用层代码到底层代码的流程
求助:
应用层的文件浏览器里使用的是java的FILE file;  file.listFiles()函数来列出目录下的所有文件,那怎么来看这个函数不断向底层调用的过程呢?
比方说像网上很多牛人分析的发短信的流程一样,一个函数调用一个函数,最后一直到驱动层。
我就想知道这种文件浏览的过程是怎么样的。

这个说起来流程蛮多,反正大概就是:
1. android的java实现是在libcore/luni中,file.listFiles()在libcore/luni/src/main/java/java/io/File.java中,
  public File[] listFiles() {
        return filenamesToFiles(list());
    }
这里的list()是各个file的信息集合,方法如下:
    public String[] list() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkRead(path);
        }
        if (path.isEmpty()) {
            return null;
        }
        return listImpl(absolutePath);
    }
这里看到调用到listImpl方法,这是个native方法:private static native String[] listImpl(String path);在libcore/luni/src/main/native/java_io_File.cpp中:

static jobjectArray File_listImpl(JNIEnv* env, jclass, jstring javaPath) {
    // Read the directory entries into an intermediate form.
    DirEntries files;
    if (!readDirectory(env, javaPath, files)) {
        return NULL;
    }
    // Translate the intermediate form into a Java String[].
    jobjectArray result = env->NewObjectArray(files.size(), JniConstants::stringClass, NULL);
    for (int i = 0; files.size() != 0; files.pop_front(), ++i) {
        ScopedLocalRef<jstring> javaFilename(env, env->NewStringUTF(files.front()));
        if (env->ExceptionCheck()) {
            return NULL;
        }
        env->SetObjectArrayElement(result, i, javaFilename.get());
        if (env->ExceptionCheck()) {
            return NULL;
        }
    }
    return result;
}
这里调用到readDirectory方法,实现如下:
static bool readDirectory(JNIEnv* env, jstring javaPath, DirEntries& entries) {
    ScopedUtfChars path(env, javaPath);
    if (path.c_str() == NULL) {
        return false;
    }

    ScopedReaddir dir(path.c_str());
    if (dir.isBad()) {
        return false;
    }
    const char* filename;
    while ((filename = dir.next()) != NULL) {
        if (strcmp(filename, ".") != 0 && strcmp(filename, "..") != 0) {
            if (!entries.push_front(filename)) {
                jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
                return false;
            }
        }
    }
    return true;
}

最后可以看到使用ScopedReaddir dir(path.c_str());来读取dir信息.
ScopedReaddir是个class,其构造函数如下:
ScopedReaddir(const char* path) {
        mDirStream = opendir(path);
        mIsBad = (mDirStream == NULL);
    }
可以看到,最后是调用了linux文件操作方法opendir,这个在dirent.h中能找到
实现在libc里面(android的glibc实现是在bionic/libc下)的unistd/opendir.c中找到
DIR*  opendir( const char*  dirpath )
{
    DIR*  dir = malloc(sizeof(DIR));

    if (!dir)
        goto Exit;

    dir->_DIR_fd = open(dirpath, O_RDONLY|O_DIRECTORY);
    if (dir->_DIR_fd < 0)
    {
        free(dir);
        dir = NULL;
    }
    else
    {
        dir->_DIR_avail = 0;
        dir->_DIR_next  = NULL;
        pthread_mutex_init( &dir->_DIR_lock, NULL );
    }
Exit:
    return dir;
}
这个open最终又会调用到内核的open函数,然后继续调用内核相关方法,找不到了
又找了下:反正要调用到系统调用open,这些显然用汇编写的,比如arch-arm/systcalls/_open.S
.type __open, #function
    .globl __open
    .align 4
    .fnstart

__open:
    .save   {r4, r7}
    stmfd   sp!, {r4, r7}
    ldr     r7, =__NR_open
    swi     #0
    ldmfd   sp!, {r4, r7}
    movs    r0, r0
    bxpl    lr
    b       __set_syscall_errno
    .fnend

这就是系统调用的open方法的实现,我这是一头雾水了哈哈。
  相关解决方案