From 3fbde346ad04a557d519239d8d4f88bc6c8a7333 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Wed, 12 Jul 2017 19:17:52 -0700 Subject: [PATCH] Zygote: Poll with timeout for pid Do not use a blocking readInt. Poll for available bytes with a timeout. (cherry picked from commit cbc421406193308667a38b0bebc16c4064a19e83) Bug: 63638768 Test: m Test: cts-tradefed run commandAndExit cts-dev -m CtsWrapWrapDebugTestCases Change-Id: Ib2131c00aa47dd10bb940d8678bbbfb5a0346ad5 --- .../android/internal/os/ZygoteConnection.java | 66 ++++++++++++++++--- 1 file 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 91429a6092885..941ded3af8fe5 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; @@ -807,17 +809,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