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

Commit bae484ad authored by Narayan Kamath's avatar Narayan Kamath
Browse files

Zygote: Fix race condition on package preloads.



Before this change, ZygoteProcess.preloadPackageForAbi returned
as soon as the command was written to the zygote socket and not
after the preload completed. This meant that there was a small
window of time before the server side of the socket polled its FDs
where a second command could be written to the zygote socket. This
would lead to only one of the commands being processed and the
other being dropped. The client side of that socket would then wait
forever for a response and bring down the system once the watchdog
timeout was hit.

Example failure case :
--------------
system_server:send command(preloadPackage)
system_server:send command(fork)
zygote:poll & process command(preloadPackage)  // the fork command is dropped.

Example of normal operation :
------------------
system_server:send command(preloadPackage)
zygote:poll & process command(preloadPackage)
system_server:send command(fork)
zygote:poll & process command(fork)

This change makes preloadPackageForAbi synchronous, which ensures
that each POLLIN event corresponds to precisely one command.

Bug: 62886909
Bug: 13618569
Test: Manual
Contributed-By: default avatar <yuqianyu@huawei.com>

(cherry-picked from commit 24a3306c)

Change-Id: I83faf974c9a70a6ab18323f692c1981784e4c56a
parent 5c5f1f64
Loading
Loading
Loading
Loading
+4 −2
Original line number Original line Diff line number Diff line
@@ -488,7 +488,7 @@ public class ZygoteProcess {
     * Instructs the zygote to pre-load the classes and native libraries at the given paths
     * 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.
     * 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 {
                                        String abi) throws ZygoteStartFailedEx, IOException {
        synchronized(mLock) {
        synchronized(mLock) {
            ZygoteState state = openZygoteSocketIfNeeded(abi);
            ZygoteState state = openZygoteSocketIfNeeded(abi);
@@ -508,6 +508,8 @@ public class ZygoteProcess {
            state.writer.newLine();
            state.writer.newLine();


            state.writer.flush();
            state.writer.flush();

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


+13 −1
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ import android.util.Log;
import android.webkit.WebViewFactory;
import android.webkit.WebViewFactory;
import android.webkit.WebViewFactoryProvider;
import android.webkit.WebViewFactoryProvider;


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

            try {
                DataOutputStream socketOut = getSocketOutputStream();
                socketOut.writeInt(preloadSucceeded ? 1 : 0);
            } catch (IOException ioe) {
                Log.e(TAG, "Error writing to command socket", ioe);
                return true;
            }

            Log.i(TAG, "Package preload done");
            Log.i(TAG, "Package preload done");
            return false;
            return false;
        }
        }
+4 −0
Original line number Original line Diff line number Diff line
@@ -314,6 +314,10 @@ class ZygoteConnection {
        return ZygoteInit.isPreloadComplete();
        return ZygoteInit.isPreloadComplete();
    }
    }


    protected DataOutputStream getSocketOutputStream() {
        return mSocketOutStream;
    }

    protected boolean handlePreloadPackage(String packagePath, String libsPath, String cacheKey) {
    protected boolean handlePreloadPackage(String packagePath, String libsPath, String cacheKey) {
        throw new RuntimeException("Zyogte does not support package preloading");
        throw new RuntimeException("Zyogte does not support package preloading");
    }
    }