Loading cmds/app_process/app_main.cpp +41 −30 Original line number Diff line number Diff line Loading @@ -149,10 +149,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 @@ -163,39 +160,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 { fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); return 10; } } cmds/runtime/main_runtime.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -497,7 +497,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 +14 −0 Original line number Diff line number Diff line Loading @@ -633,6 +633,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 core/java/com/android/internal/os/RuntimeInit.java +105 −38 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import dalvik.system.VMRuntime; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.LogManager; import java.util.TimeZone; Loading @@ -45,6 +44,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 @@ -89,14 +89,14 @@ public class RuntimeInit { } private static final void commonInit() { if (false) 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 (false) Slog.d(TAG, ">>>>> qwerty keyboard = " + hasQwerty); if (DEBUG) Slog.d(TAG, ">>>>> qwerty keyboard = " + hasQwerty); if (hasQwerty == 1) { System.setProperty("qwerty", "1"); } Loading Loading @@ -183,11 +183,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 @@ -225,6 +220,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 @@ -233,7 +235,7 @@ public class RuntimeInit { */ finishInit(); if (false) Slog.d(TAG, "Leaving RuntimeInit!"); if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!"); } public static final native void finishInit(); Loading @@ -245,7 +247,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 @@ -253,45 +254,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.out.close(); System.setOut(new AndroidPrintStream(Log.INFO, "System.out")); System.err.close(); 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 @@ -351,4 +367,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 +117 −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 libcore.io.IoUtils; import libcore.io.Libcore; 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 { 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(); IoUtils.closeQuietly(fd); } catch (IOException ex) { Slog.d(TAG, "Could not write pid of wrapped process to Zygote pipe.", ex); } } 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 ? pipeFd.getInt$() : 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 @@ -149,10 +149,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 @@ -163,39 +160,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 { fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); return 10; } }
cmds/runtime/main_runtime.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -497,7 +497,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 +14 −0 Original line number Diff line number Diff line Loading @@ -633,6 +633,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
core/java/com/android/internal/os/RuntimeInit.java +105 −38 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import dalvik.system.VMRuntime; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.LogManager; import java.util.TimeZone; Loading @@ -45,6 +44,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 @@ -89,14 +89,14 @@ public class RuntimeInit { } private static final void commonInit() { if (false) 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 (false) Slog.d(TAG, ">>>>> qwerty keyboard = " + hasQwerty); if (DEBUG) Slog.d(TAG, ">>>>> qwerty keyboard = " + hasQwerty); if (hasQwerty == 1) { System.setProperty("qwerty", "1"); } Loading Loading @@ -183,11 +183,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 @@ -225,6 +220,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 @@ -233,7 +235,7 @@ public class RuntimeInit { */ finishInit(); if (false) Slog.d(TAG, "Leaving RuntimeInit!"); if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!"); } public static final native void finishInit(); Loading @@ -245,7 +247,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 @@ -253,45 +254,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.out.close(); System.setOut(new AndroidPrintStream(Log.INFO, "System.out")); System.err.close(); 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 @@ -351,4 +367,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 +117 −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 libcore.io.IoUtils; import libcore.io.Libcore; 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 { 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(); IoUtils.closeQuietly(fd); } catch (IOException ex) { Slog.d(TAG, "Could not write pid of wrapped process to Zygote pipe.", ex); } } 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 ? pipeFd.getInt$() : 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()); } }