安卓软件栈
framework 层
StorageManager
frameworks/base/core/java/android/os/storage/StorageManager.java
java libcore
有个 java.io.file 在门路:
libcore/ojluni/src/main/java/java/io/File.java
外面有文件相干操作:
public boolean createNewFile() throws IOException {SecurityManager security = System.getSecurityManager();
if (security != null) security.checkWrite(path);
if (isInvalid()) {throw new IOException("Invalid file path");
}
return fs.createFileExclusively(path);
}
/* -- File operations -- */
// Android-changed: Add method to intercept native method call; BlockGuard support.
public boolean createFileExclusively(String path) throws IOException {BlockGuard.getThreadPolicy().onWriteToDisk();
BlockGuard.getVmPolicy().onPathAccess(path);
return createFileExclusively0(path);
}
这里是 C 语言实现的给 java 调用的 createFileExclusively0 JNI 接口:
libcore/ojluni/src/main/native/UnixFileSystem_md.c:// Android-changed: Name changed because of added thread policy check
JNIEXPORT jboolean JNICALL
Java_java_io_UnixFileSystem_createFileExclusively0(JNIEnv *env, jclass cls,
jstring pathname)
{
jboolean rv = JNI_FALSE;
WITH_PLATFORM_STRING(env, pathname, path) {
FD fd;
/* The root directory always exists */
if (strcmp (path, "/")) {fd = handleOpen(path, O_RDWR | O_CREAT | O_EXCL, 0666);
if (fd < 0) {if (errno != EEXIST)
JNU_ThrowIOExceptionWithLastError(env, path);
} else {if (close(fd) == -1)
JNU_ThrowIOExceptionWithLastError(env, path);
rv = JNI_TRUE;
}
}
} END_PLATFORM_STRING(env, path);
return rv;
}
libcore/ojluni/src/main/native/io_util_md.c:FD
handleOpen(const char *path, int oflag, int mode) {
FD fd;
RESTARTABLE(open64(path, oflag, mode), fd);
if (fd != -1) {
struct stat64 buf64;
int result;
RESTARTABLE(fstat64(fd, &buf64), result);
if (result != -1) {if (S_ISDIR(buf64.st_mode)) {close(fd);
errno = EISDIR;
fd = -1;
}
} else {close(fd);
fd = -1;
}
}
return fd;
}
bionic/libc/include/bits/fortify/fcntl.h:__BIONIC_FORTIFY_INLINE
int open64(const char* const __pass_object_size pathname, int flags, mode_t modes)
__overloadable
__clang_warning_if(!__open_modes_useful(flags) && modes,
"'open64' " __open_useless_modes_warning) {return open(pathname, flags, modes);
}
__BIONIC_FORTIFY_INLINE
int open(const char* const __pass_object_size pathname, int flags, mode_t modes)
__overloadable
__clang_warning_if(!__open_modes_useful(flags) && modes,
"'open' " __open_useless_modes_warning) {return __open_real(pathname, flags, modes);
}
int __open_real(const char*, int, ...) __RENAME(open);
bionic/libc/include/sys/cdefs.h:#define __RENAME(x) __asm__(#x)
/**
* readObject is called to restore this filename.
* The original separator character is read. If it is different
* than the separator character on this system, then the old separator
* is replaced by the local separator.
*/
private synchronized void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{ObjectInputStream.GetField fields = s.readFields();
String pathField = (String)fields.get("path", null);
char sep = s.readChar(); // read the previous separator char
if (sep != separatorChar)
pathField = pathField.replace(sep, separatorChar);
String path = fs.normalize(pathField);
UNSAFE.putObject(this, PATH_OFFSET, path);
UNSAFE.putIntVolatile(this, PREFIX_LENGTH_OFFSET, fs.prefixLength(path));
}
另外一个类:
frameworks/base/core/java/android/content/ContextWrapper.java
frameworks/base/core/java/android/app/ContextImpl.java:@Override
public FileOutputStream openFileOutput(String name, int mode) throws FileNotFoundException {checkMode(mode);
final boolean append = (mode&MODE_APPEND) != 0;
File f = makeFilename(getFilesDir(), name);
try {FileOutputStream fos = new FileOutputStream(f, append);
setFilePermissionsFromMode(f.getPath(), mode, 0);
return fos;
} catch (FileNotFoundException e) { }
File parent = f.getParentFile();
parent.mkdir();
FileUtils.setPermissions(parent.getPath(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-1, -1);
FileOutputStream fos = new FileOutputStream(f, append);
setFilePermissionsFromMode(f.getPath(), mode, 0);
return fos;
}
According to this slide deck from 2016, Libcore is Google’s implementation of some core Java libraries such as java.net, java.util, java.icu (Unicode), java.math, java.reflect, and possibly more. Libcore also allows for POSIX system calls from Java.Libcore’s master branch can be found here. Most of Google’s implementation is found in folder luni , but libcore also mixes with Oracle code. For example, Oracle’s JNI implementation from OpenJDK is used in Android in folder ojluni. So libcore replaces some functionality from OpenJDK, but not all.
libc 库
源码地位:bionic/libc/stdio/stdio.cpp
例如 fopen:
FILE* fopen(const char* file, const char* mode) {
int mode_flags;
int flags = __sflags(mode, &mode_flags);
if (flags == 0) return nullptr;
int fd = open(file, mode_flags, DEFFILEMODE);
if (fd == -1) {return nullptr;}
FILE* fp = __FILE_init(__sfp(), fd, flags);
if (fp == nullptr) {
ErrnoRestorer errno_restorer;
close(fd);
return nullptr;
}
外面的 open 就会最终调用到 open 零碎调用。
libc 外面调用的零碎调用,依据这个文件里的零碎调用列表,会用 python 脚本生成头文件:
https://android.googlesource.com/platform/bionic/+/refs/heads/master/libc/SYSCALLS.TXT
# This file is used to automatically generate bionic's system call stubs.
#
# Each non-blank, non-comment line has the following format:
#
# return_type func_name[|alias_list][:syscall_name[:socketcall_id]]([parameter_list]) arch_list
#
# where:
# arch_list ::= "all" | arches
# arches ::= arch | arch "," arches
# arch ::= "arm" | "arm64" | "x86" | "x86_64" | "lp32" | "lp64"
#
# Note:
# - syscall_name corresponds to the name of the syscall, which may differ from
# the exported function name (example: the exit syscall is implemented by the _exit()
# function, which is not the same as the standard C exit() function which calls it)
#
# - alias_list is optional comma separated list of function aliases.
#
# - The call_id parameter, given that func_name and syscall_name have
# been provided, allows the user to specify dispatch style syscalls.
# For example, socket() syscall on i386 actually becomes:
# socketcall(__NR_socket, 1, *(rest of args on stack)).
#
# - Each parameter type is assumed to be stored in 32 bits.
#
# This file is processed by a python script named gensyscalls.py, run via
# genrules in Android.bp.
援用