summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author T.J. Mercier <tjmercier@google.com> 2024-07-24 22:55:23 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2024-07-24 22:55:23 +0000
commiteadf19f00ffeae7179107d41d131ea44997e5540 (patch)
treeb505a88ca97e8159a0d057725b83e4225acab1f1
parent694948c0770be004886299244f8e07da50150664 (diff)
parentc90540ca1aecb757f36623494373f0e5dec854c3 (diff)
Merge changes I95ebeb36,I37da934b,Ifa4a739c,I3d8e5c72,If6a14c4e into main am: c90540ca1a
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/3185048 Change-Id: I46f8c668f7ecbf3481450653ef6f54400b54eeb7 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--core/jni/android_util_Process.cpp99
1 files changed, 46 insertions, 53 deletions
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 1a1d83cb6fb6..4cc904153aac 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -33,6 +33,7 @@
#include <algorithm>
#include <array>
+#include <cstring>
#include <limits>
#include <memory>
#include <string>
@@ -50,7 +51,6 @@
#include <inttypes.h>
#include <pwd.h>
#include <signal.h>
-#include <string.h>
#include <sys/epoll.h>
#include <sys/errno.h>
#include <sys/pidfd.h>
@@ -73,13 +73,13 @@ static constexpr bool kDebugProc = false;
// 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 constexpr ssize_t kProcReadStackBufferSize = 1024;
+static constexpr size_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 constexpr ssize_t kProcReadMinHeapBufferSize = 4096;
+static constexpr size_t kProcReadMinHeapBufferSize = 4096;
#if GUARD_THREAD_PRIORITY
Mutex gKeyCreateMutex;
@@ -818,7 +818,6 @@ jintArray android_os_Process_getPids(JNIEnv* env, jobject clazz,
}
DIR* dirp = opendir(file8);
-
env->ReleaseStringUTFChars(file, file8);
if(dirp == NULL) {
@@ -851,6 +850,7 @@ jintArray android_os_Process_getPids(JNIEnv* env, jobject clazz,
jintArray newArray = env->NewIntArray(newCount);
if (newArray == NULL) {
closedir(dirp);
+ if (curData) env->ReleaseIntArrayElements(lastArray, curData, 0);
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return NULL;
}
@@ -1047,78 +1047,71 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz,
return JNI_FALSE;
}
- const char* file8 = env->GetStringUTFChars(file, NULL);
- if (file8 == NULL) {
+ auto releaser = [&](const char* jniStr) { env->ReleaseStringUTFChars(file, jniStr); };
+ std::unique_ptr<const char[], decltype(releaser)> file8(env->GetStringUTFChars(file, NULL),
+ releaser);
+ if (!file8) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return JNI_FALSE;
}
- ::android::base::unique_fd fd(open(file8, O_RDONLY | O_CLOEXEC));
+ ::android::base::unique_fd fd(open(file8.get(), O_RDONLY | O_CLOEXEC));
if (!fd.ok()) {
if (kDebugProc) {
- ALOGW("Unable to open process file: %s\n", file8);
+ ALOGW("Unable to open process file: %s\n", file8.get());
}
- env->ReleaseStringUTFChars(file, file8);
return JNI_FALSE;
}
- env->ReleaseStringUTFChars(file, file8);
// 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];
- std::unique_ptr<char[]> readBufferHeap;
- char* readBuffer = &readBufferStack[0];
- ssize_t readBufferSize = kProcReadStackBufferSize;
- ssize_t numberBytesRead;
+ // with the stack buffer first. We allocate a buffer big enough
+ // for most files.
+
+ char stackBuf[kProcReadStackBufferSize];
+ std::vector<char> heapBuf;
+ char* buf = stackBuf;
+
+ size_t remaining = sizeof(stackBuf);
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 =
- TEMP_FAILURE_RETRY(pread(fd, readBuffer + offset, requestedBufferSize, offset));
- if (numberBytesRead < 0) {
+ ssize_t numBytesRead;
+
+ do {
+ numBytesRead = TEMP_FAILURE_RETRY(pread(fd, buf + offset, remaining, offset));
+ if (numBytesRead < 0) {
if (kDebugProc) {
ALOGW("Unable to read process file err: %s file: %s fd=%d\n",
- strerror_r(errno, &readBufferStack[0], sizeof(readBufferStack)), file8,
- fd.get());
+ strerror_r(errno, stackBuf, sizeof(stackBuf)), file8.get(), fd.get());
}
return JNI_FALSE;
}
- if (numberBytesRead == 0) {
- // End of file.
- numberBytesRead = offset;
- break;
- }
- 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());
+
+ offset += numBytesRead;
+ remaining -= numBytesRead;
+
+ if (numBytesRead && !remaining) {
+ if (buf == stackBuf) {
+ heapBuf.resize(kProcReadMinHeapBufferSize);
+ static_assert(kProcReadMinHeapBufferSize > sizeof(stackBuf));
+ std::memcpy(heapBuf.data(), stackBuf, sizeof(stackBuf));
+ } else {
+ constexpr size_t MAX_READABLE_PROCFILE_SIZE = 64 << 20;
+ if (heapBuf.size() >= MAX_READABLE_PROCFILE_SIZE) {
+ if (kDebugProc) {
+ ALOGW("Proc file too big: %s fd=%d size=%zu\n",
+ file8.get(), fd.get(), heapBuf.size());
+ }
+ 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;
+ heapBuf.resize(2 * heapBuf.size());
}
- readBuffer = readBufferHeap.get();
- offset = 0;
+ buf = heapBuf.data();
+ remaining = heapBuf.size() - offset;
}
- }
+ } while (numBytesRead != 0);
// parseProcLineArray below modifies the buffer while parsing!
return android_os_Process_parseProcLineArray(
- env, clazz, readBuffer, 0, numberBytesRead,
- format, outStrings, outLongs, outFloats);
+ env, clazz, buf, 0, offset, format, outStrings, outLongs, outFloats);
}
void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz,