Loading core/java/com/android/internal/os/RuntimeInit.java +41 −14 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.util.Slog; import com.android.internal.logging.AndroidConfig; import com.android.server.NetworkManagementSocketTagger; import dalvik.system.VMRuntime; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.TimeZone; Loading Loading @@ -228,8 +229,8 @@ public class RuntimeInit { * @param argv Argument vector for main() * @param classLoader the classLoader to load {@className} with */ private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws Zygote.MethodAndArgsCaller { private static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { Class<?> cl; try { Loading Loading @@ -263,7 +264,7 @@ public class RuntimeInit { * clears up all the stack frames that were required in setting * up the process. */ throw new Zygote.MethodAndArgsCaller(m, argv); return new MethodAndArgsCaller(m, argv); } public static final void main(String[] argv) { Loading @@ -286,8 +287,8 @@ public class RuntimeInit { if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!"); } protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws Zygote.MethodAndArgsCaller { protected static Runnable applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) { // If the application calls System.exit(), terminate the process // immediately without running any shutdown hooks. It is not possible to // shutdown an Android application gracefully. Among other things, the Loading @@ -300,20 +301,13 @@ public class RuntimeInit { VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); final Arguments args; try { args = new Arguments(argv); } catch (IllegalArgumentException ex) { Slog.e(TAG, ex.getMessage()); // let the process exit return; } final Arguments args = new Arguments(argv); // The end of of the RuntimeInit event (see #zygoteInit). Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); // Remaining arguments are passed to the start class's static main invokeStaticMain(args.startClass, args.startArgs, classLoader); return findStaticMain(args.startClass, args.startArgs, classLoader); } /** Loading Loading @@ -422,4 +416,37 @@ public class RuntimeInit { System.arraycopy(args, curArg, startArgs, 0, startArgs.length); } } /** * Helper class which holds a method and arguments and can call them. This is used as part of * a trampoline to get rid of the initial process setup stack frames. */ static class MethodAndArgsCaller implements Runnable { /** method to call */ private final Method mMethod; /** argument array */ private final String[] mArgs; public MethodAndArgsCaller(Method method, String[] args) { mMethod = method; mArgs = args; } public void run() { try { mMethod.invoke(null, new Object[] { mArgs }); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException(ex); } } } } core/java/com/android/internal/os/WebViewZygoteInit.java +14 −10 Original line number Diff line number Diff line Loading @@ -69,8 +69,7 @@ class WebViewZygoteInit { } @Override protected boolean handlePreloadPackage(String packagePath, String libsPath, String cacheKey) { protected void handlePreloadPackage(String packagePath, String libsPath, String cacheKey) { Log.i(TAG, "Beginning package preload"); // Ask ApplicationLoaders to create and cache a classloader for the WebView APK so that // our children will reuse the same classloader instead of creating their own. Loading Loading @@ -106,12 +105,10 @@ class WebViewZygoteInit { DataOutputStream socketOut = getSocketOutputStream(); socketOut.writeInt(preloadSucceeded ? 1 : 0); } catch (IOException ioe) { Log.e(TAG, "Error writing to command socket", ioe); return true; throw new IllegalStateException("Error writing to command socket", ioe); } Log.i(TAG, "Package preload done"); return false; } } Loading @@ -125,16 +122,23 @@ class WebViewZygoteInit { throw new RuntimeException("Failed to setpgid(0,0)", ex); } final Runnable caller; try { sServer.registerServerSocket("webview_zygote"); sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS)); sServer.closeServerSocket(); } catch (Zygote.MethodAndArgsCaller caller) { caller.run(); // The select loop returns early in the child process after a fork and // loops forever in the zygote. caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS)); } catch (RuntimeException e) { Log.e(TAG, "Fatal exception:", e); throw e; } finally { sServer.closeServerSocket(); } System.exit(0); // We're in the child process and have exited the select loop. Proceed to execute the // command. if (caller != null) { caller.run(); } } } core/java/com/android/internal/os/WrapperInit.java +27 −31 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.system.StructCapUserData; import android.system.StructCapUserHeader; import android.util.BootTimingsTraceLog; import android.util.Slog; import com.android.internal.os.Zygote.MethodAndArgsCaller; import dalvik.system.VMRuntime; import java.io.DataOutputStream; import java.io.FileDescriptor; Loading Loading @@ -61,7 +60,6 @@ public class WrapperInit { * @param args The command-line arguments. */ public static void main(String[] args) { try { // Parse our mandatory arguments. int fdNum = Integer.parseInt(args[0], 10); int targetSdkVersion = Integer.parseInt(args[1], 10); Loading @@ -88,10 +86,9 @@ public class WrapperInit { // Launch the application. String[] runtimeArgs = new String[args.length - 2]; System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length); WrapperInit.wrapperInit(targetSdkVersion, runtimeArgs); } catch (Zygote.MethodAndArgsCaller caller) { caller.run(); } Runnable r = wrapperInit(targetSdkVersion, runtimeArgs); r.run(); } /** Loading Loading @@ -142,8 +139,7 @@ public class WrapperInit { * @param targetSdkVersion target SDK version * @param argv arg strings */ private static void wrapperInit(int targetSdkVersion, String[] argv) throws Zygote.MethodAndArgsCaller { private static Runnable wrapperInit(int targetSdkVersion, String[] argv) { if (RuntimeInit.DEBUG) { Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from wrapper"); } Loading @@ -165,7 +161,7 @@ public class WrapperInit { // Perform the same initialization that would happen after the Zygote forks. Zygote.nativePreApplicationInit(); RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); } /** Loading core/java/com/android/internal/os/Zygote.java +0 −35 Original line number Diff line number Diff line Loading @@ -221,39 +221,4 @@ public final class Zygote { command.append(" '").append(arg.replace("'", "'\\''")).append("'"); } } /** * Helper exception class which holds a method and arguments and * can call them. This is used as part of a trampoline to get rid of * the initial process setup stack frames. */ public static class MethodAndArgsCaller extends Exception implements Runnable { /** method to call */ private final Method mMethod; /** argument array */ private final String[] mArgs; public MethodAndArgsCaller(Method method, String[] args) { mMethod = method; mArgs = args; } public void run() { try { mMethod.invoke(null, new Object[] { mArgs }); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException(ex); } } } } core/java/com/android/internal/os/ZygoteConnection.java +100 −145 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ import android.net.Credentials; import android.net.LocalSocket; import android.os.FactoryTest; import android.os.Process; import android.os.SELinux; import android.os.SystemProperties; import android.os.Trace; import android.system.ErrnoException; Loading @@ -42,14 +41,13 @@ import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import libcore.io.IoUtils; /** Loading @@ -73,6 +71,7 @@ class ZygoteConnection { private final BufferedReader mSocketReader; private final Credentials peer; private final String abiList; private boolean isEof; /** * Constructs instance from connected socket. Loading @@ -99,6 +98,8 @@ class ZygoteConnection { Log.e(TAG, "Cannot read peer credentials", ex); throw ex; } isEof = false; } /** Loading @@ -111,21 +112,14 @@ class ZygoteConnection { } /** * Reads one start command from the command socket. If successful, * a child is forked and a {@link Zygote.MethodAndArgsCaller} * exception is thrown in that child while in the parent process, * the method returns normally. On failure, the child is not * spawned and messages are printed to the log and stderr. Returns * a boolean status value indicating whether an end-of-file on the command * socket has been encountered. * Reads one start command from the command socket. If successful, a child is forked and a * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child * process. {@code null} is always returned in the parent process (the zygote). * * @return false if command socket should continue to be read from, or * true if an end-of-file has been encountered. * @throws Zygote.MethodAndArgsCaller trampoline to invoke main() * method in child process * If the client closes the socket, an {@code EOF} condition is set, which callers can test * for by calling {@code ZygoteConnection.isClosedByPeer}. */ boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller { Runnable processOneCommand(ZygoteServer zygoteServer) { String args[]; Arguments parsedArgs = null; FileDescriptor[] descriptors; Loading @@ -134,43 +128,36 @@ class ZygoteConnection { args = readArgumentList(); descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { Log.w(TAG, "IOException on command socket " + ex.getMessage()); closeSocket(); return true; throw new IllegalStateException("IOException on command socket", ex); } // readArgumentList returns null only when it has reached EOF with no available // data to read. This will only happen when the remote socket has disconnected. if (args == null) { // EOF reached. closeSocket(); return true; } /** the stderr of the most recent request, if avail */ PrintStream newStderr = null; if (descriptors != null && descriptors.length >= 3) { newStderr = new PrintStream( new FileOutputStream(descriptors[2])); isEof = true; return null; } int pid = -1; FileDescriptor childPipeFd = null; FileDescriptor serverPipeFd = null; try { parsedArgs = new Arguments(args); if (parsedArgs.abiListQuery) { return handleAbiListQuery(); handleAbiListQuery(); return null; } if (parsedArgs.preloadDefault) { return handlePreload(); handlePreload(); return null; } if (parsedArgs.preloadPackage != null) { return handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs, parsedArgs.preloadPackageCacheKey); handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs, parsedArgs.preloadPackageCacheKey); return null; } if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) { Loading @@ -194,11 +181,15 @@ class ZygoteConnection { int[] fdsToIgnore = null; if (parsedArgs.invokeWith != null) { try { FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC); childPipeFd = pipeFds[1]; serverPipeFd = pipeFds[0]; Os.fcntlInt(childPipeFd, F_SETFD, 0); fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()}; } catch (ErrnoException errnoEx) { throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx); } } /** Loading Loading @@ -233,31 +224,24 @@ class ZygoteConnection { parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet, parsedArgs.appDataDir); } catch (ErrnoException ex) { logAndPrintError(newStderr, "Exception creating pipe", ex); } catch (IllegalArgumentException ex) { logAndPrintError(newStderr, "Invalid zygote arguments", ex); } catch (ZygoteSecurityException ex) { logAndPrintError(newStderr, "Zygote security policy prevents request: ", ex); } try { if (pid == 0) { // in child zygoteServer.setForkChild(); zygoteServer.closeServerSocket(); IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); // should never get here, the child is expected to either // throw Zygote.MethodAndArgsCaller or exec(). return true; return handleChildProc(parsedArgs, descriptors, childPipeFd); } else { // in parent...pid of < 0 means failure // In the parent. A pid < 0 indicates a failure and will be handled in // handleParentProc. IoUtils.closeQuietly(childPipeFd); childPipeFd = null; return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); handleParentProc(pid, descriptors, serverPipeFd); return null; } } finally { IoUtils.closeQuietly(childPipeFd); Loading @@ -265,15 +249,13 @@ class ZygoteConnection { } } private boolean handleAbiListQuery() { private void handleAbiListQuery() { try { final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII); mSocketOutStream.writeInt(abiListBytes.length); mSocketOutStream.write(abiListBytes); return false; } catch (IOException ioe) { Log.e(TAG, "Error writing to command socket", ioe); return true; throw new IllegalStateException("Error writing to command socket", ioe); } } Loading @@ -283,7 +265,7 @@ class ZygoteConnection { * if no preload was initiated. The latter implies that the zygote is not configured to load * resources lazy or that the zygote has already handled a previous request to handlePreload. */ private boolean handlePreload() { private void handlePreload() { try { if (isPreloadComplete()) { mSocketOutStream.writeInt(1); Loading @@ -291,11 +273,8 @@ class ZygoteConnection { preload(); mSocketOutStream.writeInt(0); } return false; } catch (IOException ioe) { Log.e(TAG, "Error writing to command socket", ioe); return true; throw new IllegalStateException("Error writing to command socket", ioe); } } Loading @@ -311,7 +290,7 @@ class ZygoteConnection { return mSocketOutStream; } protected boolean handlePreloadPackage(String packagePath, String libsPath, String cacheKey) { protected void handlePreloadPackage(String packagePath, String libsPath, String cacheKey) { throw new RuntimeException("Zyogte does not support package preloading"); } Loading @@ -327,6 +306,10 @@ class ZygoteConnection { } } boolean isClosedByPeer() { return isEof; } /** * Handles argument parsing for args related to the zygote spawner. * Loading Loading @@ -757,15 +740,9 @@ class ZygoteConnection { * @param parsedArgs non-null; zygote args * @param descriptors null-ok; new file descriptors for stdio if available. * @param pipeFd null-ok; pipe for communication back to Zygote. * @param newStderr null-ok; stream to use for stderr until stdio * is reopened. * * @throws Zygote.MethodAndArgsCaller on success to * trampoline to code that invokes static main. */ private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws Zygote.MethodAndArgsCaller { private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd) { /** * By the time we get here, the native code has closed the two actual Zygote * socket connections, and substituted /dev/null in their place. The LocalSocket Loading @@ -782,7 +759,6 @@ class ZygoteConnection { for (FileDescriptor fd: descriptors) { IoUtils.closeQuietly(fd); } newStderr = System.err; } catch (ErrnoException ex) { Log.e(TAG, "Error reopening stdio", ex); } Loading @@ -799,9 +775,12 @@ class ZygoteConnection { parsedArgs.niceName, parsedArgs.targetSdkVersion, VMRuntime.getCurrentInstructionSet(), pipeFd, parsedArgs.remainingArgs); // Should not get here. throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned"); } else { ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */); return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */); } } Loading @@ -813,13 +792,8 @@ class ZygoteConnection { * @param descriptors null-ok; file descriptors for child's new stdio if * specified. * @param pipeFd null-ok; pipe for communication with child. * @param parsedArgs non-null; zygote args * @return true for "exit command loop" and false for "continue command * loop" */ private boolean handleParentProc(int pid, FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) { private void handleParentProc(int pid, FileDescriptor[] descriptors, FileDescriptor pipeFd) { if (pid > 0) { setChildPgid(pid); } Loading Loading @@ -911,11 +885,8 @@ class ZygoteConnection { mSocketOutStream.writeInt(pid); mSocketOutStream.writeBoolean(usingWrapper); } catch (IOException ex) { Log.e(TAG, "Error writing to command socket", ex); return true; throw new IllegalStateException("Error writing to command socket", ex); } return false; } private void setChildPgid(int pid) { Loading @@ -931,20 +902,4 @@ class ZygoteConnection { + "normal if peer is not in our session"); } } /** * Logs an error message and prints it to the specified stream, if * provided * * @param newStderr null-ok; a standard error stream * @param message non-null; error message * @param ex null-ok an exception */ private static void logAndPrintError (PrintStream newStderr, String message, Throwable ex) { Log.e(TAG, message, ex); if (newStderr != null) { newStderr.println(message + (ex == null ? "" : ex)); } } } Loading
core/java/com/android/internal/os/RuntimeInit.java +41 −14 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.util.Slog; import com.android.internal.logging.AndroidConfig; import com.android.server.NetworkManagementSocketTagger; import dalvik.system.VMRuntime; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.TimeZone; Loading Loading @@ -228,8 +229,8 @@ public class RuntimeInit { * @param argv Argument vector for main() * @param classLoader the classLoader to load {@className} with */ private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws Zygote.MethodAndArgsCaller { private static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { Class<?> cl; try { Loading Loading @@ -263,7 +264,7 @@ public class RuntimeInit { * clears up all the stack frames that were required in setting * up the process. */ throw new Zygote.MethodAndArgsCaller(m, argv); return new MethodAndArgsCaller(m, argv); } public static final void main(String[] argv) { Loading @@ -286,8 +287,8 @@ public class RuntimeInit { if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!"); } protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws Zygote.MethodAndArgsCaller { protected static Runnable applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) { // If the application calls System.exit(), terminate the process // immediately without running any shutdown hooks. It is not possible to // shutdown an Android application gracefully. Among other things, the Loading @@ -300,20 +301,13 @@ public class RuntimeInit { VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); final Arguments args; try { args = new Arguments(argv); } catch (IllegalArgumentException ex) { Slog.e(TAG, ex.getMessage()); // let the process exit return; } final Arguments args = new Arguments(argv); // The end of of the RuntimeInit event (see #zygoteInit). Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); // Remaining arguments are passed to the start class's static main invokeStaticMain(args.startClass, args.startArgs, classLoader); return findStaticMain(args.startClass, args.startArgs, classLoader); } /** Loading Loading @@ -422,4 +416,37 @@ public class RuntimeInit { System.arraycopy(args, curArg, startArgs, 0, startArgs.length); } } /** * Helper class which holds a method and arguments and can call them. This is used as part of * a trampoline to get rid of the initial process setup stack frames. */ static class MethodAndArgsCaller implements Runnable { /** method to call */ private final Method mMethod; /** argument array */ private final String[] mArgs; public MethodAndArgsCaller(Method method, String[] args) { mMethod = method; mArgs = args; } public void run() { try { mMethod.invoke(null, new Object[] { mArgs }); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException(ex); } } } }
core/java/com/android/internal/os/WebViewZygoteInit.java +14 −10 Original line number Diff line number Diff line Loading @@ -69,8 +69,7 @@ class WebViewZygoteInit { } @Override protected boolean handlePreloadPackage(String packagePath, String libsPath, String cacheKey) { protected void handlePreloadPackage(String packagePath, String libsPath, String cacheKey) { Log.i(TAG, "Beginning package preload"); // Ask ApplicationLoaders to create and cache a classloader for the WebView APK so that // our children will reuse the same classloader instead of creating their own. Loading Loading @@ -106,12 +105,10 @@ class WebViewZygoteInit { DataOutputStream socketOut = getSocketOutputStream(); socketOut.writeInt(preloadSucceeded ? 1 : 0); } catch (IOException ioe) { Log.e(TAG, "Error writing to command socket", ioe); return true; throw new IllegalStateException("Error writing to command socket", ioe); } Log.i(TAG, "Package preload done"); return false; } } Loading @@ -125,16 +122,23 @@ class WebViewZygoteInit { throw new RuntimeException("Failed to setpgid(0,0)", ex); } final Runnable caller; try { sServer.registerServerSocket("webview_zygote"); sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS)); sServer.closeServerSocket(); } catch (Zygote.MethodAndArgsCaller caller) { caller.run(); // The select loop returns early in the child process after a fork and // loops forever in the zygote. caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS)); } catch (RuntimeException e) { Log.e(TAG, "Fatal exception:", e); throw e; } finally { sServer.closeServerSocket(); } System.exit(0); // We're in the child process and have exited the select loop. Proceed to execute the // command. if (caller != null) { caller.run(); } } }
core/java/com/android/internal/os/WrapperInit.java +27 −31 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.system.StructCapUserData; import android.system.StructCapUserHeader; import android.util.BootTimingsTraceLog; import android.util.Slog; import com.android.internal.os.Zygote.MethodAndArgsCaller; import dalvik.system.VMRuntime; import java.io.DataOutputStream; import java.io.FileDescriptor; Loading Loading @@ -61,7 +60,6 @@ public class WrapperInit { * @param args The command-line arguments. */ public static void main(String[] args) { try { // Parse our mandatory arguments. int fdNum = Integer.parseInt(args[0], 10); int targetSdkVersion = Integer.parseInt(args[1], 10); Loading @@ -88,10 +86,9 @@ public class WrapperInit { // Launch the application. String[] runtimeArgs = new String[args.length - 2]; System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length); WrapperInit.wrapperInit(targetSdkVersion, runtimeArgs); } catch (Zygote.MethodAndArgsCaller caller) { caller.run(); } Runnable r = wrapperInit(targetSdkVersion, runtimeArgs); r.run(); } /** Loading Loading @@ -142,8 +139,7 @@ public class WrapperInit { * @param targetSdkVersion target SDK version * @param argv arg strings */ private static void wrapperInit(int targetSdkVersion, String[] argv) throws Zygote.MethodAndArgsCaller { private static Runnable wrapperInit(int targetSdkVersion, String[] argv) { if (RuntimeInit.DEBUG) { Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from wrapper"); } Loading @@ -165,7 +161,7 @@ public class WrapperInit { // Perform the same initialization that would happen after the Zygote forks. Zygote.nativePreApplicationInit(); RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); } /** Loading
core/java/com/android/internal/os/Zygote.java +0 −35 Original line number Diff line number Diff line Loading @@ -221,39 +221,4 @@ public final class Zygote { command.append(" '").append(arg.replace("'", "'\\''")).append("'"); } } /** * Helper exception class which holds a method and arguments and * can call them. This is used as part of a trampoline to get rid of * the initial process setup stack frames. */ public static class MethodAndArgsCaller extends Exception implements Runnable { /** method to call */ private final Method mMethod; /** argument array */ private final String[] mArgs; public MethodAndArgsCaller(Method method, String[] args) { mMethod = method; mArgs = args; } public void run() { try { mMethod.invoke(null, new Object[] { mArgs }); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException(ex); } } } }
core/java/com/android/internal/os/ZygoteConnection.java +100 −145 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ import android.net.Credentials; import android.net.LocalSocket; import android.os.FactoryTest; import android.os.Process; import android.os.SELinux; import android.os.SystemProperties; import android.os.Trace; import android.system.ErrnoException; Loading @@ -42,14 +41,13 @@ import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import libcore.io.IoUtils; /** Loading @@ -73,6 +71,7 @@ class ZygoteConnection { private final BufferedReader mSocketReader; private final Credentials peer; private final String abiList; private boolean isEof; /** * Constructs instance from connected socket. Loading @@ -99,6 +98,8 @@ class ZygoteConnection { Log.e(TAG, "Cannot read peer credentials", ex); throw ex; } isEof = false; } /** Loading @@ -111,21 +112,14 @@ class ZygoteConnection { } /** * Reads one start command from the command socket. If successful, * a child is forked and a {@link Zygote.MethodAndArgsCaller} * exception is thrown in that child while in the parent process, * the method returns normally. On failure, the child is not * spawned and messages are printed to the log and stderr. Returns * a boolean status value indicating whether an end-of-file on the command * socket has been encountered. * Reads one start command from the command socket. If successful, a child is forked and a * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child * process. {@code null} is always returned in the parent process (the zygote). * * @return false if command socket should continue to be read from, or * true if an end-of-file has been encountered. * @throws Zygote.MethodAndArgsCaller trampoline to invoke main() * method in child process * If the client closes the socket, an {@code EOF} condition is set, which callers can test * for by calling {@code ZygoteConnection.isClosedByPeer}. */ boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller { Runnable processOneCommand(ZygoteServer zygoteServer) { String args[]; Arguments parsedArgs = null; FileDescriptor[] descriptors; Loading @@ -134,43 +128,36 @@ class ZygoteConnection { args = readArgumentList(); descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { Log.w(TAG, "IOException on command socket " + ex.getMessage()); closeSocket(); return true; throw new IllegalStateException("IOException on command socket", ex); } // readArgumentList returns null only when it has reached EOF with no available // data to read. This will only happen when the remote socket has disconnected. if (args == null) { // EOF reached. closeSocket(); return true; } /** the stderr of the most recent request, if avail */ PrintStream newStderr = null; if (descriptors != null && descriptors.length >= 3) { newStderr = new PrintStream( new FileOutputStream(descriptors[2])); isEof = true; return null; } int pid = -1; FileDescriptor childPipeFd = null; FileDescriptor serverPipeFd = null; try { parsedArgs = new Arguments(args); if (parsedArgs.abiListQuery) { return handleAbiListQuery(); handleAbiListQuery(); return null; } if (parsedArgs.preloadDefault) { return handlePreload(); handlePreload(); return null; } if (parsedArgs.preloadPackage != null) { return handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs, parsedArgs.preloadPackageCacheKey); handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs, parsedArgs.preloadPackageCacheKey); return null; } if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) { Loading @@ -194,11 +181,15 @@ class ZygoteConnection { int[] fdsToIgnore = null; if (parsedArgs.invokeWith != null) { try { FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC); childPipeFd = pipeFds[1]; serverPipeFd = pipeFds[0]; Os.fcntlInt(childPipeFd, F_SETFD, 0); fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()}; } catch (ErrnoException errnoEx) { throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx); } } /** Loading Loading @@ -233,31 +224,24 @@ class ZygoteConnection { parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet, parsedArgs.appDataDir); } catch (ErrnoException ex) { logAndPrintError(newStderr, "Exception creating pipe", ex); } catch (IllegalArgumentException ex) { logAndPrintError(newStderr, "Invalid zygote arguments", ex); } catch (ZygoteSecurityException ex) { logAndPrintError(newStderr, "Zygote security policy prevents request: ", ex); } try { if (pid == 0) { // in child zygoteServer.setForkChild(); zygoteServer.closeServerSocket(); IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); // should never get here, the child is expected to either // throw Zygote.MethodAndArgsCaller or exec(). return true; return handleChildProc(parsedArgs, descriptors, childPipeFd); } else { // in parent...pid of < 0 means failure // In the parent. A pid < 0 indicates a failure and will be handled in // handleParentProc. IoUtils.closeQuietly(childPipeFd); childPipeFd = null; return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); handleParentProc(pid, descriptors, serverPipeFd); return null; } } finally { IoUtils.closeQuietly(childPipeFd); Loading @@ -265,15 +249,13 @@ class ZygoteConnection { } } private boolean handleAbiListQuery() { private void handleAbiListQuery() { try { final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII); mSocketOutStream.writeInt(abiListBytes.length); mSocketOutStream.write(abiListBytes); return false; } catch (IOException ioe) { Log.e(TAG, "Error writing to command socket", ioe); return true; throw new IllegalStateException("Error writing to command socket", ioe); } } Loading @@ -283,7 +265,7 @@ class ZygoteConnection { * if no preload was initiated. The latter implies that the zygote is not configured to load * resources lazy or that the zygote has already handled a previous request to handlePreload. */ private boolean handlePreload() { private void handlePreload() { try { if (isPreloadComplete()) { mSocketOutStream.writeInt(1); Loading @@ -291,11 +273,8 @@ class ZygoteConnection { preload(); mSocketOutStream.writeInt(0); } return false; } catch (IOException ioe) { Log.e(TAG, "Error writing to command socket", ioe); return true; throw new IllegalStateException("Error writing to command socket", ioe); } } Loading @@ -311,7 +290,7 @@ class ZygoteConnection { return mSocketOutStream; } protected boolean handlePreloadPackage(String packagePath, String libsPath, String cacheKey) { protected void handlePreloadPackage(String packagePath, String libsPath, String cacheKey) { throw new RuntimeException("Zyogte does not support package preloading"); } Loading @@ -327,6 +306,10 @@ class ZygoteConnection { } } boolean isClosedByPeer() { return isEof; } /** * Handles argument parsing for args related to the zygote spawner. * Loading Loading @@ -757,15 +740,9 @@ class ZygoteConnection { * @param parsedArgs non-null; zygote args * @param descriptors null-ok; new file descriptors for stdio if available. * @param pipeFd null-ok; pipe for communication back to Zygote. * @param newStderr null-ok; stream to use for stderr until stdio * is reopened. * * @throws Zygote.MethodAndArgsCaller on success to * trampoline to code that invokes static main. */ private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws Zygote.MethodAndArgsCaller { private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd) { /** * By the time we get here, the native code has closed the two actual Zygote * socket connections, and substituted /dev/null in their place. The LocalSocket Loading @@ -782,7 +759,6 @@ class ZygoteConnection { for (FileDescriptor fd: descriptors) { IoUtils.closeQuietly(fd); } newStderr = System.err; } catch (ErrnoException ex) { Log.e(TAG, "Error reopening stdio", ex); } Loading @@ -799,9 +775,12 @@ class ZygoteConnection { parsedArgs.niceName, parsedArgs.targetSdkVersion, VMRuntime.getCurrentInstructionSet(), pipeFd, parsedArgs.remainingArgs); // Should not get here. throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned"); } else { ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */); return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */); } } Loading @@ -813,13 +792,8 @@ class ZygoteConnection { * @param descriptors null-ok; file descriptors for child's new stdio if * specified. * @param pipeFd null-ok; pipe for communication with child. * @param parsedArgs non-null; zygote args * @return true for "exit command loop" and false for "continue command * loop" */ private boolean handleParentProc(int pid, FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) { private void handleParentProc(int pid, FileDescriptor[] descriptors, FileDescriptor pipeFd) { if (pid > 0) { setChildPgid(pid); } Loading Loading @@ -911,11 +885,8 @@ class ZygoteConnection { mSocketOutStream.writeInt(pid); mSocketOutStream.writeBoolean(usingWrapper); } catch (IOException ex) { Log.e(TAG, "Error writing to command socket", ex); return true; throw new IllegalStateException("Error writing to command socket", ex); } return false; } private void setChildPgid(int pid) { Loading @@ -931,20 +902,4 @@ class ZygoteConnection { + "normal if peer is not in our session"); } } /** * Logs an error message and prints it to the specified stream, if * provided * * @param newStderr null-ok; a standard error stream * @param message non-null; error message * @param ex null-ok an exception */ private static void logAndPrintError (PrintStream newStderr, String message, Throwable ex) { Log.e(TAG, message, ex); if (newStderr != null) { newStderr.println(message + (ex == null ? "" : ex)); } } }