安卓软件栈
framework层
StorageManager
frameworks/base/core/java/android/os/storage/StorageManager.java
java libcore
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.
有个java.io.file在路径:
libcore/ojluni/src/main/java/java/io/File.java
framework层是调用上面的这个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)
看这两个文件:
libcore\luni\src\main\native\libcore_io_Posix.cpp
libcore\luni\src\main\native\libcore_io_Linux.cpp
另外一个类:
frameworks/base/core/java/android/content/ContextWrapper.java:
public class ContextWrapper extends Context {
@UnsupportedAppUsage
Context mBase;
public ContextWrapper(Context base) {
mBase = base;
}
@Override
public FileInputStream openFileInput(String name)
throws FileNotFoundException {
return mBase.openFileInput(name);
}
frameworks/base/core/java/android/app/ContextImpl.java:
@Override
public FileInputStream openFileInput(String name)
throws FileNotFoundException {
File f = makeFilename(getFilesDir(), name);
return new FileInputStream(f);
}
这个对象FileInputStream:
public FileInputStream(String name)
throws FileNotFoundException
Creates a FileInputStream by opening a connection to an actual file, the file named by the path name name in the file system. A new FileDescriptor object is created to represent this file connection.
其中的几个方法:
public int read() 从输入流读一个字节的数据
throws IOException
Reads a byte of data from this input stream. This method blocks if no input is yet available.
public int read(byte[] b)
throws IOException
Reads up to b.length bytes of data from this input stream into an array of bytes. This method blocks until some input is available.
/**
* Reads up to <code>len</code> bytes of data from this input stream
* into an array of bytes. If <code>len</code> is not zero, the method
* blocks until some input is available; otherwise, no
* bytes are read and <code>0</code> is returned.
*
* @param b the buffer into which the data is read.
* @param off the start offset in the destination array <code>b</code>
* @param len the maximum number of bytes read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the file has been reached.
* @exception NullPointerException If <code>b</code> is <code>null</code>.
* @exception IndexOutOfBoundsException If <code>off</code> is negative,
* <code>len</code> is negative, or <code>len</code> is greater than
* <code>b.length - off</code>
* @exception IOException if an I/O error occurs.
*/
public int read(byte b[], int off, int len) throws IOException {
// Android-added: close() check before I/O.
if (closed && len > 0) {
throw new IOException("Stream Closed");
}
// Android-added: Tracking of unbuffered I/O.
tracker.trackIo(len, IoTracker.Mode.READ);
// Android-changed: Use IoBridge instead of calling native method.
return IoBridge.read(fd, b, off, len);
}
libcore/ojluni/src/main/native/io_util.c:
jint
readBytes(JNIEnv *env, jobject this, jbyteArray bytes,
jint off, jint len, jfieldID fid)
{
jint nread;
char stackBuf[BUF_SIZE];
char *buf = NULL;
FD fd;
if (IS_NULL(bytes)) {
JNU_ThrowNullPointerException(env, NULL);
return -1;
}
if (outOfBounds(env, off, len, bytes)) {
JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", NULL);
return -1;
}
if (len == 0) {
return 0;
} else if (len > BUF_SIZE) {
buf = malloc(len);
if (buf == NULL) {
JNU_ThrowOutOfMemoryError(env, NULL);
return 0;
}
} else {
buf = stackBuf;
}
fd = GET_FD(this, fid);
if (fd == -1) {
JNU_ThrowIOException(env, "Stream Closed");
nread = -1;
} else {
nread = (jint)IO_Read(fd, buf, len);
if (nread > 0) {
(*env)->SetByteArrayRegion(env, bytes, off, nread, (jbyte *)buf);
} else if (nread == JVM_IO_ERR) {
JNU_ThrowIOExceptionWithLastError(env, "Read error");
} else if (nread == JVM_IO_INTR) {
JNU_ThrowByName(env, "java/io/InterruptedIOException", NULL);
} else { /* EOF */
nread = -1;
}
}
if (buf != stackBuf) {
free(buf);
}
return nread;
}
libcore/ojluni/src/main/native/io_util_md.h:
#define IO_Read JVM_Read
art/openjdkjvm/OpenjdkJvm.cc:
/* posix read() */
JNIEXPORT jint JVM_Read(jint fd, char* buf, jint nbytes) {
return TEMP_FAILURE_RETRY(read(fd, buf, nbytes));
}
libc库
源码位置:bionic/libc/stdio/stdio.cpp
上层不一定调用fopen,可能直接调open系统调用。
例如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.
引用
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。