Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 89c94f67 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes Id931d441,I83faf974

* changes:
  Zygote: Improve logging and error handling during connections.
  Zygote: Fix race condition on package preloads.
parents fee4546f ac0b4be1
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -463,7 +463,7 @@ public class ZygoteProcess {
     * Instructs the zygote to pre-load the classes and native libraries at the given paths
     * for the specified abi. Not all zygotes support this function.
     */
    public void preloadPackageForAbi(String packagePath, String libsPath, String cacheKey,
    public boolean preloadPackageForAbi(String packagePath, String libsPath, String cacheKey,
                                        String abi) throws ZygoteStartFailedEx, IOException {
        synchronized(mLock) {
            ZygoteState state = openZygoteSocketIfNeeded(abi);
@@ -483,6 +483,8 @@ public class ZygoteProcess {
            state.writer.newLine();

            state.writer.flush();

            return (state.inputStream.readInt() == 0);
        }
    }

+41 −14
Original line number Diff line number Diff line
@@ -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;
@@ -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 {
@@ -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) {
@@ -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
@@ -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);
    }

    /**
@@ -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);
            }
        }
    }
}
+25 −9
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.util.Log;
import android.webkit.WebViewFactory;
import android.webkit.WebViewFactoryProvider;

import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
@@ -68,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.
@@ -87,19 +87,28 @@ class WebViewZygoteInit {
            // Once we have the classloader, look up the WebViewFactoryProvider implementation and
            // call preloadInZygote() on it to give it the opportunity to preload the native library
            // and perform any other initialisation work that should be shared among the children.
            boolean preloadSucceeded = false;
            try {
                Class<WebViewFactoryProvider> providerClass =
                        WebViewFactory.getWebViewProviderClass(loader);
                Object result = providerClass.getMethod("preloadInZygote").invoke(null);
                if (!((Boolean)result).booleanValue()) {
                preloadSucceeded = ((Boolean) result).booleanValue();
                if (!preloadSucceeded) {
                    Log.e(TAG, "preloadInZygote returned false");
                }
            } catch (ClassNotFoundException | NoSuchMethodException | SecurityException |
                     IllegalAccessException | InvocationTargetException e) {
                Log.e(TAG, "Exception while preloading package", e);
            }

            try {
                DataOutputStream socketOut = getSocketOutputStream();
                socketOut.writeInt(preloadSucceeded ? 1 : 0);
            } catch (IOException ioe) {
                throw new IllegalStateException("Error writing to command socket", ioe);
            }

            Log.i(TAG, "Package preload done");
            return false;
        }
    }

@@ -113,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();
        }
    }
}
+27 −31
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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();
    }

    /**
@@ -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");
        }
@@ -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);
    }

    /**
+0 −35
Original line number Diff line number Diff line
@@ -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);
            }
        }
    }
}
Loading