Loading cmds/app_process/app_main.cpp +41 −30 Original line number Diff line number Diff line Loading @@ -128,10 +128,7 @@ int main(int argc, const char* const argv[]) mArgLen--; AppRuntime runtime; const char *arg; const char *argv0; argv0 = argv[0]; const char* argv0 = argv[0]; // Process command line arguments // ignore argv[0] Loading @@ -142,39 +139,53 @@ int main(int argc, const char* const argv[]) int i = runtime.addVmArguments(argc, argv); // Next arg is parent directory if (i < argc) { runtime.mParentDir = argv[i++]; // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; const char* parentDir = NULL; const char* niceName = NULL; const char* className = NULL; while (i < argc) { const char* arg = argv[i++]; if (!parentDir) { parentDir = arg; } else if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = "zygote"; } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; } else if (strcmp(arg, "--application") == 0) { application = true; } else if (strncmp(arg, "--nice-name=", 12) == 0) { niceName = arg + 12; } else { className = arg; break; } } // Next arg is startup classname or "--zygote" if (i < argc) { arg = argv[i++]; if (0 == strcmp("--zygote", arg)) { bool startSystemServer = (i < argc) ? strcmp(argv[i], "--start-system-server") == 0 : false; setArgv0(argv0, "zygote"); set_process_name("zygote"); runtime.start("com.android.internal.os.ZygoteInit", startSystemServer); } else { set_process_name(argv0); if (niceName && *niceName) { setArgv0(argv0, niceName); set_process_name(niceName); } runtime.mClassName = arg; runtime.mParentDir = parentDir; if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : ""); } else if (className) { // Remainder of args get passed to startup class main() runtime.mClassName = className; runtime.mArgC = argc - i; runtime.mArgV = argv + i; LOGV("App process is starting with pid=%d, class=%s.\n", getpid(), runtime.getClassName()); runtime.start(); } runtime.start("com.android.internal.os.RuntimeInit", application ? "application" : "tool"); } else { LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); return 10; } } cmds/runtime/main_runtime.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -498,7 +498,7 @@ int main(int argc, char* const argv[]) #ifndef HAVE_ANDROID_OS QuickRuntime* runt = new QuickRuntime(); runt->start("com/android/server/SystemServer", false /* spontaneously fork system server from zygote */); "" /* spontaneously fork system server from zygote */); #endif } Loading core/java/android/os/Process.java +47 −28 Original line number Diff line number Diff line Loading @@ -257,13 +257,12 @@ public class Process { * @param enableDebugger True if debugging should be enabled for this process. * @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, Loading Loading @@ -294,8 +293,7 @@ public class Process { } else { new Thread(runnable).start(); } return 0; return new ProcessStartResult(); } } Loading @@ -303,7 +301,7 @@ public class Process { * Start a new process. Don't supply a custom nice name. * {@hide} */ public static final int start(String processClass, int uid, int gid, public static final ProcessStartResult start(String processClass, int uid, int gid, int[] gids, int debugFlags, String[] zygoteArgs) { return start(processClass, "", uid, gid, gids, debugFlags, zygoteArgs); Loading Loading @@ -418,14 +416,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 { Loading @@ -436,7 +431,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())); Loading @@ -456,11 +452,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) { Loading @@ -475,8 +473,6 @@ public class Process { throw new ZygoteStartFailedEx(ex); } return pid; } /** Loading @@ -490,18 +486,16 @@ public class Process { * new process should setgroup() to. * @param enableDebugger True if debugging should be enabled for this process. * @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, String[] extraArgs) throws ZygoteStartFailedEx { int pid; synchronized(Process.class) { ArrayList<String> argsForZygote = new ArrayList<String>(); Loading Loading @@ -554,14 +548,8 @@ public class Process { } } pid = zygoteSendArgsAndGetPid(argsForZygote); return zygoteSendArgsAndGetResult(argsForZygote); } if (pid <= 0) { throw new ZygoteStartFailedEx("zygote start failed:" + pid); } return pid; } /** Loading Loading @@ -615,6 +603,20 @@ public class Process { return (int) procStatusValues[0]; } /** * Returns the parent process id for a currently running process. * @param pid the process id * @return the parent process id of the process, or -1 if the process is not running. * @hide */ public static final int getParentPid(int pid) { String[] procStatusLabels = { "PPid:" }; long[] procStatusValues = new long[1]; procStatusValues[0] = -1; Process.readProcLines("/proc/" + pid + "/status", procStatusLabels, procStatusValues); return (int) procStatusValues[0]; } /** * Set the priority of a thread, based on Linux priorities. * Loading Loading @@ -826,4 +828,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; } } core/java/com/android/internal/os/RuntimeInit.java +105 −36 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import android.os.Debug; import android.os.IBinder; import android.os.Process; import android.os.SystemProperties; import android.util.Config; import android.util.Log; import android.util.Slog; Loading @@ -46,6 +45,7 @@ import org.apache.harmony.luni.internal.util.TimezoneGetter; */ public class RuntimeInit { private final static String TAG = "AndroidRuntime"; private final static boolean DEBUG = false; /** true if commonInit() has been called */ private static boolean initialized; Loading Loading @@ -90,14 +90,14 @@ public class RuntimeInit { } private static final void commonInit() { if (Config.LOGV) Slog.d(TAG, "Entered RuntimeInit!"); if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!"); /* set default handler; this applies to all threads in the VM */ Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler()); int hasQwerty = getQwertyKeyboard(); if (Config.LOGV) Slog.d(TAG, ">>>>> qwerty keyboard = " + hasQwerty); if (DEBUG) Slog.d(TAG, ">>>>> qwerty keyboard = " + hasQwerty); if (hasQwerty == 1) { System.setProperty("qwerty", "1"); } Loading Loading @@ -184,11 +184,6 @@ public class RuntimeInit { */ private static void invokeStaticMain(String className, String[] argv) throws ZygoteInit.MethodAndArgsCaller { // We want to be fairly aggressive about heap utilization, to avoid // holding on to a lot of memory that isn't needed. VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); Class<?> cl; try { Loading Loading @@ -226,6 +221,13 @@ public class RuntimeInit { } public static final void main(String[] argv) { if (argv.length == 2 && argv[1].equals("application")) { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application"); redirectLogStreams(); } else { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool"); } commonInit(); /* Loading @@ -234,7 +236,7 @@ public class RuntimeInit { */ finishInit(); if (Config.LOGV) Slog.d(TAG, "Leaving RuntimeInit!"); if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!"); } public static final native void finishInit(); Loading @@ -246,7 +248,6 @@ public class RuntimeInit { * * Current recognized args: * <ul> * <li> --nice-name=<i>nice name to appear in ps</i> * <li> <code> [--] <start class name> <args> * </ul> * Loading @@ -254,43 +255,60 @@ public class RuntimeInit { */ public static final void zygoteInit(String[] argv) throws ZygoteInit.MethodAndArgsCaller { // TODO: Doing this here works, but it seems kind of arbitrary. Find // a better place. The goal is to set it up for applications, but not // tools like am. System.setOut(new AndroidPrintStream(Log.INFO, "System.out")); System.setErr(new AndroidPrintStream(Log.WARN, "System.err")); if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote"); redirectLogStreams(); commonInit(); zygoteInitNative(); int curArg = 0; for ( /* curArg */ ; curArg < argv.length; curArg++) { String arg = argv[curArg]; if (arg.equals("--")) { curArg++; break; } else if (!arg.startsWith("--")) { break; } else if (arg.startsWith("--nice-name=")) { String niceName = arg.substring(arg.indexOf('=') + 1); Process.setArgV0(niceName); applicationInit(argv); } /** * The main function called when an application is started through a * wrapper process. * * When the wrapper starts, the runtime starts {@link RuntimeInit#main} * which calls {@link WrapperInit#main} which then calls this method. * So we don't need to call commonInit() here. * * @param argv arg strings */ public static void wrapperInit(String[] argv) throws ZygoteInit.MethodAndArgsCaller { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper"); applicationInit(argv); } if (curArg == argv.length) { Slog.e(TAG, "Missing classname argument to RuntimeInit!"); private static void applicationInit(String[] argv) throws ZygoteInit.MethodAndArgsCaller { // We want to be fairly aggressive about heap utilization, to avoid // holding on to a lot of memory that isn't needed. VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); final Arguments args; try { args = new Arguments(argv); } catch (IllegalArgumentException ex) { Slog.e(TAG, ex.getMessage()); // let the process exit return; } // Remaining arguments are passed to the start class's static main invokeStaticMain(args.startClass, args.startArgs); } String startClass = argv[curArg++]; String[] startArgs = new String[argv.length - curArg]; System.arraycopy(argv, curArg, startArgs, 0, startArgs.length); invokeStaticMain(startClass, startArgs); /** * Redirect System.out and System.err to the Android log. */ public static void redirectLogStreams() { System.out.close(); System.setOut(new AndroidPrintStream(Log.INFO, "System.out")); System.err.close(); System.setErr(new AndroidPrintStream(Log.WARN, "System.err")); } public static final native void zygoteInitNative(); Loading Loading @@ -353,4 +371,55 @@ public class RuntimeInit { // Register handlers for DDM messages. android.ddm.DdmRegister.registerHandlers(); } /** * Handles argument parsing for args related to the runtime. * * Current recognized args: * <ul> * <li> <code> [--] <start class name> <args> * </ul> */ static class Arguments { /** first non-option argument */ String startClass; /** all following arguments */ String[] startArgs; /** * Constructs instance and parses args * @param args runtime command-line args * @throws IllegalArgumentException */ Arguments(String args[]) throws IllegalArgumentException { parseArgs(args); } /** * Parses the commandline arguments intended for the Runtime. */ private void parseArgs(String args[]) throws IllegalArgumentException { int curArg = 0; for (; curArg < args.length; curArg++) { String arg = args[curArg]; if (arg.equals("--")) { curArg++; break; } else if (!arg.startsWith("--")) { break; } } if (curArg == args.length) { throw new IllegalArgumentException("Missing classname argument to RuntimeInit!"); } startClass = args[curArg++]; startArgs = new String[args.length - curArg]; System.arraycopy(args, curArg, startArgs, 0, startArgs.length); } } } core/java/com/android/internal/os/WrapperInit.java 0 → 100644 +120 −0 Original line number Diff line number Diff line /* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.os; import android.os.Process; import android.util.Slog; import java.io.DataOutputStream; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; import dalvik.system.Zygote; /** * Startup class for the wrapper process. * @hide */ public class WrapperInit { private final static String TAG = "AndroidRuntime"; /** * Class not instantiable. */ private WrapperInit() { } /** * The main function called when starting a runtime application through a * wrapper process instead of by forking Zygote. * * The first argument specifies the file descriptor for a pipe that should receive * the pid of this process, or 0 if none. The remaining arguments are passed to * the runtime. * * @param args The command-line arguments. */ public static void main(String[] args) { try { // Tell the Zygote what our actual PID is (since it only knows about the // wrapper that it directly forked). int fdNum = Integer.parseInt(args[0], 10); if (fdNum != 0) { try { FileDescriptor fd = ZygoteInit.createFileDescriptor(fdNum); DataOutputStream os = new DataOutputStream(new FileOutputStream(fd)); os.writeInt(Process.myPid()); os.close(); ZygoteInit.closeDescriptorQuietly(fd); } catch (IOException ex) { Slog.d(TAG, "Could not write pid of wrapped process to Zygote pipe.", ex); } } // Mimic Zygote preloading. ZygoteInit.preload(); // Launch the application. String[] runtimeArgs = new String[args.length - 1]; System.arraycopy(args, 1, runtimeArgs, 0, runtimeArgs.length); RuntimeInit.wrapperInit(runtimeArgs); } catch (ZygoteInit.MethodAndArgsCaller caller) { caller.run(); } } /** * Executes a runtime application with a wrapper command. * This method never returns. * * @param invokeWith The wrapper command. * @param niceName The nice name for the application, or null if none. * @param pipeFd The pipe to which the application's pid should be written, or null if none. * @param args Arguments for {@link RuntimeInit.main}. */ public static void execApplication(String invokeWith, String niceName, FileDescriptor pipeFd, String[] args) { StringBuilder command = new StringBuilder(invokeWith); command.append(" /system/bin/app_process /system/bin --application"); if (niceName != null) { command.append(" '--nice-name=").append(niceName).append("'"); } command.append(" com.android.internal.os.WrapperInit "); command.append(pipeFd != null ? ZygoteInit.getFDFromFileDescriptor(pipeFd) : 0); Zygote.appendQuotedShellArgs(command, args); Zygote.execShell(command.toString()); } /** * Executes a standalone application with a wrapper command. * This method never returns. * * @param invokeWith The wrapper command. * @param classPath The class path. * @param className The class name to invoke. * @param args Arguments for the main() method of the specified class. */ public static void execStandalone(String invokeWith, String classPath, String className, String[] args) { StringBuilder command = new StringBuilder(invokeWith); command.append(" /system/bin/dalvikvm -classpath '").append(classPath); command.append("' ").append(className); Zygote.appendQuotedShellArgs(command, args); Zygote.execShell(command.toString()); } } Loading
cmds/app_process/app_main.cpp +41 −30 Original line number Diff line number Diff line Loading @@ -128,10 +128,7 @@ int main(int argc, const char* const argv[]) mArgLen--; AppRuntime runtime; const char *arg; const char *argv0; argv0 = argv[0]; const char* argv0 = argv[0]; // Process command line arguments // ignore argv[0] Loading @@ -142,39 +139,53 @@ int main(int argc, const char* const argv[]) int i = runtime.addVmArguments(argc, argv); // Next arg is parent directory if (i < argc) { runtime.mParentDir = argv[i++]; // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; const char* parentDir = NULL; const char* niceName = NULL; const char* className = NULL; while (i < argc) { const char* arg = argv[i++]; if (!parentDir) { parentDir = arg; } else if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = "zygote"; } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; } else if (strcmp(arg, "--application") == 0) { application = true; } else if (strncmp(arg, "--nice-name=", 12) == 0) { niceName = arg + 12; } else { className = arg; break; } } // Next arg is startup classname or "--zygote" if (i < argc) { arg = argv[i++]; if (0 == strcmp("--zygote", arg)) { bool startSystemServer = (i < argc) ? strcmp(argv[i], "--start-system-server") == 0 : false; setArgv0(argv0, "zygote"); set_process_name("zygote"); runtime.start("com.android.internal.os.ZygoteInit", startSystemServer); } else { set_process_name(argv0); if (niceName && *niceName) { setArgv0(argv0, niceName); set_process_name(niceName); } runtime.mClassName = arg; runtime.mParentDir = parentDir; if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : ""); } else if (className) { // Remainder of args get passed to startup class main() runtime.mClassName = className; runtime.mArgC = argc - i; runtime.mArgV = argv + i; LOGV("App process is starting with pid=%d, class=%s.\n", getpid(), runtime.getClassName()); runtime.start(); } runtime.start("com.android.internal.os.RuntimeInit", application ? "application" : "tool"); } else { LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); return 10; } }
cmds/runtime/main_runtime.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -498,7 +498,7 @@ int main(int argc, char* const argv[]) #ifndef HAVE_ANDROID_OS QuickRuntime* runt = new QuickRuntime(); runt->start("com/android/server/SystemServer", false /* spontaneously fork system server from zygote */); "" /* spontaneously fork system server from zygote */); #endif } Loading
core/java/android/os/Process.java +47 −28 Original line number Diff line number Diff line Loading @@ -257,13 +257,12 @@ public class Process { * @param enableDebugger True if debugging should be enabled for this process. * @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, Loading Loading @@ -294,8 +293,7 @@ public class Process { } else { new Thread(runnable).start(); } return 0; return new ProcessStartResult(); } } Loading @@ -303,7 +301,7 @@ public class Process { * Start a new process. Don't supply a custom nice name. * {@hide} */ public static final int start(String processClass, int uid, int gid, public static final ProcessStartResult start(String processClass, int uid, int gid, int[] gids, int debugFlags, String[] zygoteArgs) { return start(processClass, "", uid, gid, gids, debugFlags, zygoteArgs); Loading Loading @@ -418,14 +416,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 { Loading @@ -436,7 +431,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())); Loading @@ -456,11 +452,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) { Loading @@ -475,8 +473,6 @@ public class Process { throw new ZygoteStartFailedEx(ex); } return pid; } /** Loading @@ -490,18 +486,16 @@ public class Process { * new process should setgroup() to. * @param enableDebugger True if debugging should be enabled for this process. * @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, String[] extraArgs) throws ZygoteStartFailedEx { int pid; synchronized(Process.class) { ArrayList<String> argsForZygote = new ArrayList<String>(); Loading Loading @@ -554,14 +548,8 @@ public class Process { } } pid = zygoteSendArgsAndGetPid(argsForZygote); return zygoteSendArgsAndGetResult(argsForZygote); } if (pid <= 0) { throw new ZygoteStartFailedEx("zygote start failed:" + pid); } return pid; } /** Loading Loading @@ -615,6 +603,20 @@ public class Process { return (int) procStatusValues[0]; } /** * Returns the parent process id for a currently running process. * @param pid the process id * @return the parent process id of the process, or -1 if the process is not running. * @hide */ public static final int getParentPid(int pid) { String[] procStatusLabels = { "PPid:" }; long[] procStatusValues = new long[1]; procStatusValues[0] = -1; Process.readProcLines("/proc/" + pid + "/status", procStatusLabels, procStatusValues); return (int) procStatusValues[0]; } /** * Set the priority of a thread, based on Linux priorities. * Loading Loading @@ -826,4 +828,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; } }
core/java/com/android/internal/os/RuntimeInit.java +105 −36 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import android.os.Debug; import android.os.IBinder; import android.os.Process; import android.os.SystemProperties; import android.util.Config; import android.util.Log; import android.util.Slog; Loading @@ -46,6 +45,7 @@ import org.apache.harmony.luni.internal.util.TimezoneGetter; */ public class RuntimeInit { private final static String TAG = "AndroidRuntime"; private final static boolean DEBUG = false; /** true if commonInit() has been called */ private static boolean initialized; Loading Loading @@ -90,14 +90,14 @@ public class RuntimeInit { } private static final void commonInit() { if (Config.LOGV) Slog.d(TAG, "Entered RuntimeInit!"); if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!"); /* set default handler; this applies to all threads in the VM */ Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler()); int hasQwerty = getQwertyKeyboard(); if (Config.LOGV) Slog.d(TAG, ">>>>> qwerty keyboard = " + hasQwerty); if (DEBUG) Slog.d(TAG, ">>>>> qwerty keyboard = " + hasQwerty); if (hasQwerty == 1) { System.setProperty("qwerty", "1"); } Loading Loading @@ -184,11 +184,6 @@ public class RuntimeInit { */ private static void invokeStaticMain(String className, String[] argv) throws ZygoteInit.MethodAndArgsCaller { // We want to be fairly aggressive about heap utilization, to avoid // holding on to a lot of memory that isn't needed. VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); Class<?> cl; try { Loading Loading @@ -226,6 +221,13 @@ public class RuntimeInit { } public static final void main(String[] argv) { if (argv.length == 2 && argv[1].equals("application")) { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application"); redirectLogStreams(); } else { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool"); } commonInit(); /* Loading @@ -234,7 +236,7 @@ public class RuntimeInit { */ finishInit(); if (Config.LOGV) Slog.d(TAG, "Leaving RuntimeInit!"); if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!"); } public static final native void finishInit(); Loading @@ -246,7 +248,6 @@ public class RuntimeInit { * * Current recognized args: * <ul> * <li> --nice-name=<i>nice name to appear in ps</i> * <li> <code> [--] <start class name> <args> * </ul> * Loading @@ -254,43 +255,60 @@ public class RuntimeInit { */ public static final void zygoteInit(String[] argv) throws ZygoteInit.MethodAndArgsCaller { // TODO: Doing this here works, but it seems kind of arbitrary. Find // a better place. The goal is to set it up for applications, but not // tools like am. System.setOut(new AndroidPrintStream(Log.INFO, "System.out")); System.setErr(new AndroidPrintStream(Log.WARN, "System.err")); if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote"); redirectLogStreams(); commonInit(); zygoteInitNative(); int curArg = 0; for ( /* curArg */ ; curArg < argv.length; curArg++) { String arg = argv[curArg]; if (arg.equals("--")) { curArg++; break; } else if (!arg.startsWith("--")) { break; } else if (arg.startsWith("--nice-name=")) { String niceName = arg.substring(arg.indexOf('=') + 1); Process.setArgV0(niceName); applicationInit(argv); } /** * The main function called when an application is started through a * wrapper process. * * When the wrapper starts, the runtime starts {@link RuntimeInit#main} * which calls {@link WrapperInit#main} which then calls this method. * So we don't need to call commonInit() here. * * @param argv arg strings */ public static void wrapperInit(String[] argv) throws ZygoteInit.MethodAndArgsCaller { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper"); applicationInit(argv); } if (curArg == argv.length) { Slog.e(TAG, "Missing classname argument to RuntimeInit!"); private static void applicationInit(String[] argv) throws ZygoteInit.MethodAndArgsCaller { // We want to be fairly aggressive about heap utilization, to avoid // holding on to a lot of memory that isn't needed. VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); final Arguments args; try { args = new Arguments(argv); } catch (IllegalArgumentException ex) { Slog.e(TAG, ex.getMessage()); // let the process exit return; } // Remaining arguments are passed to the start class's static main invokeStaticMain(args.startClass, args.startArgs); } String startClass = argv[curArg++]; String[] startArgs = new String[argv.length - curArg]; System.arraycopy(argv, curArg, startArgs, 0, startArgs.length); invokeStaticMain(startClass, startArgs); /** * Redirect System.out and System.err to the Android log. */ public static void redirectLogStreams() { System.out.close(); System.setOut(new AndroidPrintStream(Log.INFO, "System.out")); System.err.close(); System.setErr(new AndroidPrintStream(Log.WARN, "System.err")); } public static final native void zygoteInitNative(); Loading Loading @@ -353,4 +371,55 @@ public class RuntimeInit { // Register handlers for DDM messages. android.ddm.DdmRegister.registerHandlers(); } /** * Handles argument parsing for args related to the runtime. * * Current recognized args: * <ul> * <li> <code> [--] <start class name> <args> * </ul> */ static class Arguments { /** first non-option argument */ String startClass; /** all following arguments */ String[] startArgs; /** * Constructs instance and parses args * @param args runtime command-line args * @throws IllegalArgumentException */ Arguments(String args[]) throws IllegalArgumentException { parseArgs(args); } /** * Parses the commandline arguments intended for the Runtime. */ private void parseArgs(String args[]) throws IllegalArgumentException { int curArg = 0; for (; curArg < args.length; curArg++) { String arg = args[curArg]; if (arg.equals("--")) { curArg++; break; } else if (!arg.startsWith("--")) { break; } } if (curArg == args.length) { throw new IllegalArgumentException("Missing classname argument to RuntimeInit!"); } startClass = args[curArg++]; startArgs = new String[args.length - curArg]; System.arraycopy(args, curArg, startArgs, 0, startArgs.length); } } }
core/java/com/android/internal/os/WrapperInit.java 0 → 100644 +120 −0 Original line number Diff line number Diff line /* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.os; import android.os.Process; import android.util.Slog; import java.io.DataOutputStream; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; import dalvik.system.Zygote; /** * Startup class for the wrapper process. * @hide */ public class WrapperInit { private final static String TAG = "AndroidRuntime"; /** * Class not instantiable. */ private WrapperInit() { } /** * The main function called when starting a runtime application through a * wrapper process instead of by forking Zygote. * * The first argument specifies the file descriptor for a pipe that should receive * the pid of this process, or 0 if none. The remaining arguments are passed to * the runtime. * * @param args The command-line arguments. */ public static void main(String[] args) { try { // Tell the Zygote what our actual PID is (since it only knows about the // wrapper that it directly forked). int fdNum = Integer.parseInt(args[0], 10); if (fdNum != 0) { try { FileDescriptor fd = ZygoteInit.createFileDescriptor(fdNum); DataOutputStream os = new DataOutputStream(new FileOutputStream(fd)); os.writeInt(Process.myPid()); os.close(); ZygoteInit.closeDescriptorQuietly(fd); } catch (IOException ex) { Slog.d(TAG, "Could not write pid of wrapped process to Zygote pipe.", ex); } } // Mimic Zygote preloading. ZygoteInit.preload(); // Launch the application. String[] runtimeArgs = new String[args.length - 1]; System.arraycopy(args, 1, runtimeArgs, 0, runtimeArgs.length); RuntimeInit.wrapperInit(runtimeArgs); } catch (ZygoteInit.MethodAndArgsCaller caller) { caller.run(); } } /** * Executes a runtime application with a wrapper command. * This method never returns. * * @param invokeWith The wrapper command. * @param niceName The nice name for the application, or null if none. * @param pipeFd The pipe to which the application's pid should be written, or null if none. * @param args Arguments for {@link RuntimeInit.main}. */ public static void execApplication(String invokeWith, String niceName, FileDescriptor pipeFd, String[] args) { StringBuilder command = new StringBuilder(invokeWith); command.append(" /system/bin/app_process /system/bin --application"); if (niceName != null) { command.append(" '--nice-name=").append(niceName).append("'"); } command.append(" com.android.internal.os.WrapperInit "); command.append(pipeFd != null ? ZygoteInit.getFDFromFileDescriptor(pipeFd) : 0); Zygote.appendQuotedShellArgs(command, args); Zygote.execShell(command.toString()); } /** * Executes a standalone application with a wrapper command. * This method never returns. * * @param invokeWith The wrapper command. * @param classPath The class path. * @param className The class name to invoke. * @param args Arguments for the main() method of the specified class. */ public static void execStandalone(String invokeWith, String classPath, String className, String[] args) { StringBuilder command = new StringBuilder(invokeWith); command.append(" /system/bin/dalvikvm -classpath '").append(classPath); command.append("' ").append(className); Zygote.appendQuotedShellArgs(command, args); Zygote.execShell(command.toString()); } }