Loading core/jni/android_util_Process.cpp +57 −26 Original line number Diff line number Diff line Loading @@ -28,7 +28,11 @@ #include <meminfo/sysmeminfo.h> #include <processgroup/processgroup.h> #include <processgroup/sched_policy.h> #include <android-base/unique_fd.h> #include <algorithm> #include <limits> #include <memory> #include <string> #include <vector> Loading Loading @@ -58,8 +62,18 @@ using namespace android; static const bool kDebugPolicy = false; static const bool kDebugProc = false; // When reading `proc` files, how many bytes to read at a time static const int kReadSize = 4096; // Stack reservation for reading small proc files. Most callers of // readProcFile() are reading files under this threshold, e.g., // /proc/pid/stat. /proc/pid/time_in_state ends up being about 520 // bytes, so use 1024 for the stack to provide a bit of slack. static const ssize_t kProcReadStackBufferSize = 1024; // The other files we read from proc tend to be a bit larger (e.g., // /proc/stat is about 3kB), so once we exhaust the stack buffer, // retry with a relatively large heap-allocated buffer. We double // this size and retry until the whole file fits. static const ssize_t kProcReadMinHeapBufferSize = 4096; #if GUARD_THREAD_PRIORITY Mutex gKeyCreateMutex; Loading Loading @@ -1004,9 +1018,9 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, jniThrowException(env, "java/lang/OutOfMemoryError", NULL); return JNI_FALSE; } int fd = open(file8, O_RDONLY | O_CLOEXEC); if (fd < 0) { ::android::base::unique_fd fd(open(file8, O_RDONLY | O_CLOEXEC)); if (!fd.ok()) { if (kDebugProc) { ALOGW("Unable to open process file: %s\n", file8); } Loading @@ -1015,34 +1029,51 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, } env->ReleaseStringUTFChars(file, file8); std::vector<char> fileBuffer(kReadSize); int numBytesRead = 0; while (true) { // Resize buffer to make space for contents. This might be more than we need, but once we've // read we resize back down fileBuffer.resize(numBytesRead + kReadSize, 0); // Read in contents int len = TEMP_FAILURE_RETRY(read(fd, fileBuffer.data() + numBytesRead, kReadSize)); numBytesRead += len; if (len < 0) { // If `len` is negative, an error occurred on read // Most proc files we read are small, so we only go through the // loop once and use the stack buffer. We allocate a buffer big // enough for the whole file. char readBufferStack[kProcReadStackBufferSize]; std::unique_ptr<char[]> readBufferHeap; char* readBuffer = &readBufferStack[0]; ssize_t readBufferSize = kProcReadStackBufferSize; ssize_t numberBytesRead; for (;;) { // By using pread, we can avoid an lseek to rewind the FD // before retry, saving a system call. numberBytesRead = pread(fd, readBuffer, readBufferSize, 0); if (numberBytesRead < 0 && errno == EINTR) { continue; } if (numberBytesRead < 0) { if (kDebugProc) { ALOGW("Unable to open process file: %s fd=%d\n", file8, fd); ALOGW("Unable to open process file: %s fd=%d\n", file8, fd.get()); } close(fd); return JNI_FALSE; } else if (len == 0) { // If nothing read, we're done } if (numberBytesRead < readBufferSize) { break; } if (readBufferSize > std::numeric_limits<ssize_t>::max() / 2) { if (kDebugProc) { ALOGW("Proc file too big: %s fd=%d\n", file8, fd.get()); } return JNI_FALSE; } readBufferSize = std::max(readBufferSize * 2, kProcReadMinHeapBufferSize); readBufferHeap.reset(); // Free address space before getting more. readBufferHeap = std::make_unique<char[]>(readBufferSize); if (!readBufferHeap) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); return JNI_FALSE; } readBuffer = readBufferHeap.get(); } // Resize back down to the amount we read fileBuffer.resize(numBytesRead); // Terminate buffer with null byte fileBuffer.push_back('\0'); close(fd); return android_os_Process_parseProcLineArray(env, clazz, fileBuffer.data(), 0, numBytesRead, // parseProcLineArray below modifies the buffer while parsing! return android_os_Process_parseProcLineArray( env, clazz, readBuffer, 0, numberBytesRead, format, outStrings, outLongs, outFloats); } Loading Loading
core/jni/android_util_Process.cpp +57 −26 Original line number Diff line number Diff line Loading @@ -28,7 +28,11 @@ #include <meminfo/sysmeminfo.h> #include <processgroup/processgroup.h> #include <processgroup/sched_policy.h> #include <android-base/unique_fd.h> #include <algorithm> #include <limits> #include <memory> #include <string> #include <vector> Loading Loading @@ -58,8 +62,18 @@ using namespace android; static const bool kDebugPolicy = false; static const bool kDebugProc = false; // When reading `proc` files, how many bytes to read at a time static const int kReadSize = 4096; // Stack reservation for reading small proc files. Most callers of // readProcFile() are reading files under this threshold, e.g., // /proc/pid/stat. /proc/pid/time_in_state ends up being about 520 // bytes, so use 1024 for the stack to provide a bit of slack. static const ssize_t kProcReadStackBufferSize = 1024; // The other files we read from proc tend to be a bit larger (e.g., // /proc/stat is about 3kB), so once we exhaust the stack buffer, // retry with a relatively large heap-allocated buffer. We double // this size and retry until the whole file fits. static const ssize_t kProcReadMinHeapBufferSize = 4096; #if GUARD_THREAD_PRIORITY Mutex gKeyCreateMutex; Loading Loading @@ -1004,9 +1018,9 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, jniThrowException(env, "java/lang/OutOfMemoryError", NULL); return JNI_FALSE; } int fd = open(file8, O_RDONLY | O_CLOEXEC); if (fd < 0) { ::android::base::unique_fd fd(open(file8, O_RDONLY | O_CLOEXEC)); if (!fd.ok()) { if (kDebugProc) { ALOGW("Unable to open process file: %s\n", file8); } Loading @@ -1015,34 +1029,51 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, } env->ReleaseStringUTFChars(file, file8); std::vector<char> fileBuffer(kReadSize); int numBytesRead = 0; while (true) { // Resize buffer to make space for contents. This might be more than we need, but once we've // read we resize back down fileBuffer.resize(numBytesRead + kReadSize, 0); // Read in contents int len = TEMP_FAILURE_RETRY(read(fd, fileBuffer.data() + numBytesRead, kReadSize)); numBytesRead += len; if (len < 0) { // If `len` is negative, an error occurred on read // Most proc files we read are small, so we only go through the // loop once and use the stack buffer. We allocate a buffer big // enough for the whole file. char readBufferStack[kProcReadStackBufferSize]; std::unique_ptr<char[]> readBufferHeap; char* readBuffer = &readBufferStack[0]; ssize_t readBufferSize = kProcReadStackBufferSize; ssize_t numberBytesRead; for (;;) { // By using pread, we can avoid an lseek to rewind the FD // before retry, saving a system call. numberBytesRead = pread(fd, readBuffer, readBufferSize, 0); if (numberBytesRead < 0 && errno == EINTR) { continue; } if (numberBytesRead < 0) { if (kDebugProc) { ALOGW("Unable to open process file: %s fd=%d\n", file8, fd); ALOGW("Unable to open process file: %s fd=%d\n", file8, fd.get()); } close(fd); return JNI_FALSE; } else if (len == 0) { // If nothing read, we're done } if (numberBytesRead < readBufferSize) { break; } if (readBufferSize > std::numeric_limits<ssize_t>::max() / 2) { if (kDebugProc) { ALOGW("Proc file too big: %s fd=%d\n", file8, fd.get()); } return JNI_FALSE; } readBufferSize = std::max(readBufferSize * 2, kProcReadMinHeapBufferSize); readBufferHeap.reset(); // Free address space before getting more. readBufferHeap = std::make_unique<char[]>(readBufferSize); if (!readBufferHeap) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); return JNI_FALSE; } readBuffer = readBufferHeap.get(); } // Resize back down to the amount we read fileBuffer.resize(numBytesRead); // Terminate buffer with null byte fileBuffer.push_back('\0'); close(fd); return android_os_Process_parseProcLineArray(env, clazz, fileBuffer.data(), 0, numBytesRead, // parseProcLineArray below modifies the buffer while parsing! return android_os_Process_parseProcLineArray( env, clazz, readBuffer, 0, numberBytesRead, format, outStrings, outLongs, outFloats); } Loading