diff options
| author | 2024-07-12 14:52:13 -0700 | |
|---|---|---|
| committer | 2024-07-14 20:26:09 +0000 | |
| commit | 7c5b6d11532b2904c19fccaacd709b79b80b4f20 (patch) | |
| tree | b988869c5e0d94961ae676a3c71cf086fdbb5dfb | |
| parent | 8a83c38bc1fea791b09cd23eb677452dc34f763b (diff) | |
Keep reading until end-of-file in reading procfs
As the pread(2) says "it is not an error for a successful call
to transfer fewer bytes than requested". The only way to verify
we're hitting the end-of-file is to keep reading from the file
until it returns 0. Here we're following this rule, in order to
make sure we read the whole procfs file to avoid the parser
errors. The drawback is that, now for every procfs read, it'll
have to hit the pread() at least twice. But if it has reached to
the end-of-file, the last read should return within microseconds.
Bug: 351917521
Flag: EXEMPT bugfix
Test: dumpsys cpuinfo
Change-Id: If6a14c4e8f4f1821628f1efb984f8064d4969a8c
Merged-In: If6a14c4e8f4f1821628f1efb984f8064d4969a8c
| -rw-r--r-- | core/jni/android_util_Process.cpp | 52 |
1 files changed, 31 insertions, 21 deletions
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index d2e58bb62c46..d7a0b0408e99 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -1063,8 +1063,8 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, } env->ReleaseStringUTFChars(file, file8); - // 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 + // Most proc files we read are small, so we go through the loop + // with the stack buffer firstly. We allocate a buffer big // enough for the whole file. char readBufferStack[kProcReadStackBufferSize]; @@ -1072,37 +1072,47 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, char* readBuffer = &readBufferStack[0]; ssize_t readBufferSize = kProcReadStackBufferSize; ssize_t numberBytesRead; + off_t offset = 0; for (;;) { + ssize_t requestedBufferSize = readBufferSize - offset; // 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; - } + numberBytesRead = + TEMP_FAILURE_RETRY(pread(fd, readBuffer + offset, requestedBufferSize, offset)); if (numberBytesRead < 0) { if (kDebugProc) { - ALOGW("Unable to open process file: %s fd=%d\n", file8, fd.get()); + ALOGW("Unable to read process file err: %s file: %s fd=%d\n", + strerror_r(errno, &readBufferStack[0], sizeof(readBufferStack)), file8, + fd.get()); } return JNI_FALSE; } - if (numberBytesRead < readBufferSize) { + if (numberBytesRead == 0) { + // End of file. + numberBytesRead = offset; break; } - if (readBufferSize > std::numeric_limits<ssize_t>::max() / 2) { - if (kDebugProc) { - ALOGW("Proc file too big: %s fd=%d\n", file8, fd.get()); + if (numberBytesRead < requestedBufferSize) { + // Read less bytes than requested, it's not an error per pread(2). + offset += numberBytesRead; + } else { + // Buffer is fully used, try to grow it. + 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; } - 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; + 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(); + offset = 0; } - readBuffer = readBufferHeap.get(); } // parseProcLineArray below modifies the buffer while parsing! |