package com.android.internal.os;
import android.app.ApplicationLoaders;
import android.net.LocalSocket;
import android.net.LocalServerSocket;
import android.os.Build;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.WebViewFactory;
import android.webkit.WebViewFactoryProvider;
import android.webkit.WebViewLibraryLoader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
class WebViewZygoteInit {
public static final String TAG = "WebViewZygoteInit";
private static ZygoteServer sServer;
private static class WebViewZygoteServer extends ZygoteServer {
@Override
protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
throws IOException {
return new WebViewZygoteConnection(socket, abiList);
}
}
private static class WebViewZygoteConnection extends ZygoteConnection {
WebViewZygoteConnection(LocalSocket socket, String abiList) throws IOException {
super(socket, abiList);
}
@Override
protected void preload() {
}
@Override
protected boolean isPreloadComplete() {
return true;
}
@Override
protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
String cacheKey) {
Log.i(TAG, "Beginning package preload");
ClassLoader loader = ApplicationLoaders.getDefault().createAndCacheWebViewClassLoader(
packagePath, libsPath, cacheKey);
WebViewLibraryLoader.loadNativeLibrary(loader, libFileName);
String[] packageList = TextUtils.split(packagePath, File.pathSeparator);
for (String packageEntry : packageList) {
Zygote.nativeAllowFileAcrossFork(packageEntry);
}
boolean preloadSucceeded = false;
try {
Class<WebViewFactoryProvider> providerClass =
WebViewFactory.getWebViewProviderClass(loader);
Method preloadInZygote = providerClass.getMethod("preloadInZygote");
preloadInZygote.setAccessible(true);
if (preloadInZygote.getReturnType() != Boolean.TYPE) {
Log.e(TAG, "Unexpected return type: preloadInZygote must return boolean");
} else {
preloadSucceeded = (boolean) providerClass.getMethod("preloadInZygote")
.invoke(null);
if (!preloadSucceeded) {
Log.e(TAG, "preloadInZygote returned false");
}
}
} catch (ReflectiveOperationException 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");
}
}
public static void main(String argv[]) {
Log.i(TAG, "Starting WebViewZygoteInit");
String socketName = null;
for (String arg : argv) {
Log.i(TAG, arg);
if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
socketName = arg.substring(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG.length());
}
}
if (socketName == null) {
throw new RuntimeException("No " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + " specified");
}
try {
Os.prctl(OsConstants.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to set PR_SET_NO_NEW_PRIVS", ex);
}
sServer = new WebViewZygoteServer();
final Runnable caller;
try {
sServer.registerServerSocketAtAbstractName(socketName);
Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName);
caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS));
} catch (RuntimeException e) {
Log.e(TAG, "Fatal exception:", e);
throw e;
} finally {
sServer.closeServerSocket();
}
if (caller != null) {
caller.run();
}
}
}