summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java66
1 files changed, 57 insertions, 9 deletions
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 2013ac09d8e2..1ccf31133e00 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -18,6 +18,7 @@ package com.android.internal.os;
import static android.system.OsConstants.F_SETFD;
import static android.system.OsConstants.O_CLOEXEC;
+import static android.system.OsConstants.POLLIN;
import static android.system.OsConstants.STDERR_FILENO;
import static android.system.OsConstants.STDIN_FILENO;
import static android.system.OsConstants.STDOUT_FILENO;
@@ -31,13 +32,14 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.system.ErrnoException;
import android.system.Os;
+import android.system.StructPollfd;
import android.util.Log;
import dalvik.system.VMRuntime;
import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileDescriptor;
-import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -852,17 +854,63 @@ class ZygoteConnection {
boolean usingWrapper = false;
if (pipeFd != null && pid > 0) {
- DataInputStream is = new DataInputStream(new FileInputStream(pipeFd));
int innerPid = -1;
try {
- innerPid = is.readInt();
- } catch (IOException ex) {
- Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
- } finally {
- try {
- is.close();
- } catch (IOException ex) {
+ // Do a busy loop here. We can't guarantee that a failure (and thus an exception
+ // bail) happens in a timely manner.
+ //
+ // We'll wait up to five seconds. This should give enough time for the fork to go
+ // through, but not to trigger the watchdog in the system server.
+ final int SLEEP_IN_MS = 5000;
+ final int BYTES_REQUIRED = 4; // Bytes in an int.
+
+ StructPollfd fds[] = new StructPollfd[] {
+ new StructPollfd()
+ };
+
+ byte data[] = new byte[BYTES_REQUIRED];
+
+ int remainingSleepTime = SLEEP_IN_MS;
+ int dataIndex = 0;
+ long startTime = System.nanoTime();
+
+ while (dataIndex < data.length && remainingSleepTime > 0) {
+ fds[0].fd = pipeFd;
+ fds[0].events = (short) POLLIN;
+ fds[0].revents = 0;
+ fds[0].userData = null;
+
+ int res = android.system.Os.poll(fds, remainingSleepTime);
+ long endTime = System.nanoTime();
+ remainingSleepTime = SLEEP_IN_MS - (int)((endTime - startTime) / 1000000l);
+
+ if (res > 0) {
+ if ((fds[0].revents & POLLIN) != 0) {
+ // Only read one byte, so as not to block.
+ int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1);
+ if (readBytes < 0) {
+ throw new RuntimeException("Some error");
+ }
+ dataIndex += readBytes;
+ } else {
+ // Error case. revents should contain one of the error bits.
+ break;
+ }
+ } else if (res == 0) {
+ Log.w(TAG, "Timed out waiting for child.");
+ }
+ }
+
+ if (dataIndex == data.length) {
+ DataInputStream is = new DataInputStream(new ByteArrayInputStream(data));
+ innerPid = is.readInt();
}
+
+ if (innerPid == -1) {
+ Log.w(TAG, "Error reading pid from wrapped process, child may have died");
+ }
+ } catch (Exception ex) {
+ Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
}
// Ensure that the pid reported by the wrapped process is either the