diff options
5 files changed, 63 insertions, 49 deletions
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 269e50e..5b1f563 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -270,13 +270,12 @@ public class Process { * @param targetSdkVersion The target SDK version for the app. * @param zygoteArgs Additional arguments to supply to the zygote process. * - * @return int If > 0 the pid of the new process; if 0 the process is - * being emulated by a thread + * @return An object that describes the result of the attempt to start the process. * @throws RuntimeException on fatal start failure * * {@hide} */ - public static final int start(final String processClass, + public static final ProcessStartResult start(final String processClass, final String niceName, int uid, int gid, int[] gids, int debugFlags, int targetSdkVersion, @@ -376,14 +375,11 @@ public class Process { * and returns the child's pid. Please note: the present implementation * replaces newlines in the argument list with spaces. * @param args argument list - * @return PID of new child process + * @return An object that describes the result of the attempt to start the process. * @throws ZygoteStartFailedEx if process start failed for any reason */ - private static int zygoteSendArgsAndGetPid(ArrayList<String> args) + private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args) throws ZygoteStartFailedEx { - - int pid; - openZygoteSocketIfNeeded(); try { @@ -394,7 +390,8 @@ public class Process { * b) a number of newline-separated argument strings equal to count * * After the zygote process reads these it will write the pid of - * the child or -1 on failure. + * the child or -1 on failure, followed by boolean to + * indicate whether a wrapper process was used. */ sZygoteWriter.write(Integer.toString(args.size())); @@ -414,11 +411,13 @@ public class Process { sZygoteWriter.flush(); // Should there be a timeout on this? - pid = sZygoteInputStream.readInt(); - - if (pid < 0) { + ProcessStartResult result = new ProcessStartResult(); + result.pid = sZygoteInputStream.readInt(); + if (result.pid < 0) { throw new ZygoteStartFailedEx("fork() failed"); } + result.usingWrapper = sZygoteInputStream.readBoolean(); + return result; } catch (IOException ex) { try { if (sZygoteSocket != null) { @@ -433,8 +432,6 @@ public class Process { throw new ZygoteStartFailedEx(ex); } - - return pid; } /** @@ -449,18 +446,16 @@ public class Process { * @param debugFlags Additional flags. * @param targetSdkVersion The target SDK version for the app. * @param extraArgs Additional arguments to supply to the zygote process. - * @return PID + * @return An object that describes the result of the attempt to start the process. * @throws ZygoteStartFailedEx if process start failed for any reason */ - private static int startViaZygote(final String processClass, + private static ProcessStartResult startViaZygote(final String processClass, final String niceName, final int uid, final int gid, final int[] gids, int debugFlags, int targetSdkVersion, String[] extraArgs) throws ZygoteStartFailedEx { - int pid; - synchronized(Process.class) { ArrayList<String> argsForZygote = new ArrayList<String>(); @@ -516,15 +511,9 @@ public class Process { argsForZygote.add(arg); } } - - pid = zygoteSendArgsAndGetPid(argsForZygote); - } - if (pid <= 0) { - throw new ZygoteStartFailedEx("zygote start failed:" + pid); + return zygoteSendArgsAndGetResult(argsForZygote); } - - return pid; } /** @@ -808,4 +797,21 @@ public class Process { * @hide */ public static final native long getPss(int pid); + + /** + * Specifies the outcome of having started a process. + * @hide + */ + public static final class ProcessStartResult { + /** + * The PID of the newly started process. + * Always >= 0. (If the start failed, an exception will have been thrown instead.) + */ + public int pid; + + /** + * True if the process was started with a wrapper attached. + */ + public boolean usingWrapper; + } } diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index a3b7795..9af7e96 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -900,6 +900,7 @@ class ZygoteConnection { } } + boolean usingWrapper = false; if (pipeFd != null && pid > 0) { DataInputStream is = new DataInputStream(new FileInputStream(pipeFd)); int innerPid = -1; @@ -924,6 +925,7 @@ class ZygoteConnection { if (parentPid > 0) { Log.i(TAG, "Wrapped process has pid " + innerPid); pid = innerPid; + usingWrapper = true; } else { Log.w(TAG, "Wrapped process reported a pid that is not a child of " + "the process that we forked: childPid=" + pid @@ -934,6 +936,7 @@ class ZygoteConnection { try { mSocketOutStream.writeInt(pid); + mSocketOutStream.writeBoolean(usingWrapper); } catch (IOException ex) { Log.e(TAG, "Error reading from command socket", ex); return true; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index d5e8730..8501163 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -208,6 +208,12 @@ public final class ActivityManagerService extends ActivityManagerNative // before we decide it's never going to come up for real. static final int PROC_START_TIMEOUT = 10*1000; + // How long we wait for a launched process to attach to the activity manager + // before we decide it's never going to come up for real, when the process was + // started with a wrapper for instrumentation (such as Valgrind) because it + // could take much longer than usual. + static final int PROC_START_TIMEOUT_WITH_WRAPPER = 300*1000; + // How long to wait after going idle before forcing apps to GC. static final int GC_TIMEOUT = 5*1000; @@ -1950,9 +1956,13 @@ public final class ActivityManagerService extends ActivityManagerNative if ("1".equals(SystemProperties.get("debug.assert"))) { debugFlags |= Zygote.DEBUG_ENABLE_ASSERT; } - int pid = Process.start("android.app.ActivityThread", + + // Start the process. It will either succeed and return a result containing + // the PID of the new process, or else throw a RuntimeException. + Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread", app.processName, uid, uid, gids, debugFlags, app.info.targetSdkVersion, null); + BatteryStatsImpl bs = app.batteryStats.getBatteryStats(); synchronized (bs) { if (bs.isOnBattery()) { @@ -1960,12 +1970,12 @@ public final class ActivityManagerService extends ActivityManagerNative } } - EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid, + EventLog.writeEvent(EventLogTags.AM_PROC_START, startResult.pid, uid, app.processName, hostingType, hostingNameStr != null ? hostingNameStr : ""); if (app.persistent) { - Watchdog.getInstance().processStarted(app.processName, pid); + Watchdog.getInstance().processStarted(app.processName, startResult.pid); } StringBuilder buf = mStringBuilder; @@ -1979,7 +1989,7 @@ public final class ActivityManagerService extends ActivityManagerNative buf.append(hostingNameStr); } buf.append(": pid="); - buf.append(pid); + buf.append(startResult.pid); buf.append(" uid="); buf.append(uid); buf.append(" gids={"); @@ -1992,21 +2002,15 @@ public final class ActivityManagerService extends ActivityManagerNative } buf.append("}"); Slog.i(TAG, buf.toString()); - if (pid > 0) { - app.pid = pid; - app.removed = false; - synchronized (mPidsSelfLocked) { - this.mPidsSelfLocked.put(pid, app); - Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG); - msg.obj = app; - mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT); - } - } else { - app.pid = 0; - RuntimeException e = new RuntimeException( - "Failure starting process " + app.processName - + ": returned pid=" + pid); - Slog.e(TAG, e.getMessage(), e); + app.pid = startResult.pid; + app.usingWrapper = startResult.usingWrapper; + app.removed = false; + synchronized (mPidsSelfLocked) { + this.mPidsSelfLocked.put(startResult.pid, app); + Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG); + msg.obj = app; + mHandler.sendMessageDelayed(msg, startResult.usingWrapper + ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT); } } catch (RuntimeException e) { // XXX do better error recovery. diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index 090e26b..73ffafb 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -658,12 +658,12 @@ final class ActivityRecord extends IApplicationToken.Stub { public long getKeyDispatchingTimeout() { synchronized(service) { ActivityRecord r = getWaitingHistoryRecordLocked(); - if (r == null || r.app == null - || r.app.instrumentationClass == null) { - return ActivityManagerService.KEY_DISPATCHING_TIMEOUT; + if (r != null && r.app != null + && (r.app.instrumentationClass != null || r.app.usingWrapper)) { + return ActivityManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT; } - - return ActivityManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT; + + return ActivityManagerService.KEY_DISPATCHING_TIMEOUT; } } diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 3968f66..da83e7d 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -78,6 +78,7 @@ class ProcessRecord { IInstrumentationWatcher instrumentationWatcher; // who is waiting Bundle instrumentationArguments;// as given to us ComponentName instrumentationResultClass;// copy of instrumentationClass + boolean usingWrapper; // Set to true when process was launched with a wrapper attached BroadcastRecord curReceiver;// receiver currently running in the app long lastWakeTime; // How long proc held wake lock at last check long lastCpuTime; // How long proc has run CPU at last check |