blob: 955fef0542fdfdb7846790244ddc8cbd1e783c07 [file] [log] [blame]
Tobias Sargeantb9679dc2016-01-19 16:34:54 +00001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.os;
18
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010019import android.app.ApplicationLoaders;
Robert Sesekded20982016-08-15 13:59:13 -040020import android.net.LocalSocket;
21import android.os.Build;
22import android.system.ErrnoException;
23import android.system.Os;
Robert Sesek602d1322018-01-17 18:48:18 -050024import android.system.OsConstants;
Robert Sesekded20982016-08-15 13:59:13 -040025import android.text.TextUtils;
26import android.util.Log;
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010027import android.webkit.WebViewFactory;
Tao Bai755eded2017-01-09 18:35:44 -080028import android.webkit.WebViewFactoryProvider;
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -050029import android.webkit.WebViewLibraryLoader;
Robert Sesekded20982016-08-15 13:59:13 -040030
Narayan Kamath24a33062017-07-03 14:12:26 +010031import java.io.DataOutputStream;
Torne (Richard Coles)04526702017-01-13 14:19:39 +000032import java.io.File;
Robert Sesekded20982016-08-15 13:59:13 -040033import java.io.IOException;
Narayan Kamath6f6e8942017-07-06 12:38:55 +010034import java.lang.reflect.Method;
Robert Sesekded20982016-08-15 13:59:13 -040035
Tobias Sargeantb9679dc2016-01-19 16:34:54 +000036/**
37 * Startup class for the WebView zygote process.
38 *
39 * See {@link ZygoteInit} for generic zygote startup documentation.
40 *
41 * @hide
42 */
43class WebViewZygoteInit {
44 public static final String TAG = "WebViewZygoteInit";
45
Robert Sesekded20982016-08-15 13:59:13 -040046 private static ZygoteServer sServer;
47
48 private static class WebViewZygoteServer extends ZygoteServer {
49 @Override
50 protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
51 throws IOException {
52 return new WebViewZygoteConnection(socket, abiList);
53 }
54 }
55
56 private static class WebViewZygoteConnection extends ZygoteConnection {
57 WebViewZygoteConnection(LocalSocket socket, String abiList) throws IOException {
58 super(socket, abiList);
59 }
60
61 @Override
Narayan Kamath669afcc2017-02-06 20:24:08 +000062 protected void preload() {
63 // Nothing to preload by default.
64 }
65
66 @Override
67 protected boolean isPreloadComplete() {
68 // Webview zygotes don't preload any classes or resources or defaults, all of their
69 // preloading is package specific.
70 return true;
Torne (Richard Coles)bb658932017-01-05 16:11:06 +000071 }
72
73 @Override
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -050074 protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
75 String cacheKey) {
Torne (Richard Coles)deeb6ad2017-04-18 17:16:36 -040076 Log.i(TAG, "Beginning package preload");
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010077 // Ask ApplicationLoaders to create and cache a classloader for the WebView APK so that
78 // our children will reuse the same classloader instead of creating their own.
79 // This enables us to preload Java and native code in the webview zygote process and
80 // have the preloaded versions actually be used post-fork.
81 ClassLoader loader = ApplicationLoaders.getDefault().createAndCacheWebViewClassLoader(
Torne (Richard Coles)04526702017-01-13 14:19:39 +000082 packagePath, libsPath, cacheKey);
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010083
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -050084 // Load the native library using WebViewLibraryLoader to share the RELRO data with other
85 // processes.
86 WebViewLibraryLoader.loadNativeLibrary(loader, libFileName);
87
Robert Sesek061ee302016-12-02 17:27:50 -050088 // Add the APK to the Zygote's list of allowed files for children.
Torne (Richard Coles)04526702017-01-13 14:19:39 +000089 String[] packageList = TextUtils.split(packagePath, File.pathSeparator);
90 for (String packageEntry : packageList) {
91 Zygote.nativeAllowFileAcrossFork(packageEntry);
92 }
Robert Sesek061ee302016-12-02 17:27:50 -050093
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010094 // Once we have the classloader, look up the WebViewFactoryProvider implementation and
95 // call preloadInZygote() on it to give it the opportunity to preload the native library
96 // and perform any other initialisation work that should be shared among the children.
Narayan Kamath24a33062017-07-03 14:12:26 +010097 boolean preloadSucceeded = false;
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010098 try {
Tao Bai755eded2017-01-09 18:35:44 -080099 Class<WebViewFactoryProvider> providerClass =
100 WebViewFactory.getWebViewProviderClass(loader);
Narayan Kamath6f6e8942017-07-06 12:38:55 +0100101 Method preloadInZygote = providerClass.getMethod("preloadInZygote");
102 preloadInZygote.setAccessible(true);
103 if (preloadInZygote.getReturnType() != Boolean.TYPE) {
104 Log.e(TAG, "Unexpected return type: preloadInZygote must return boolean");
105 } else {
106 preloadSucceeded = (boolean) providerClass.getMethod("preloadInZygote")
107 .invoke(null);
108 if (!preloadSucceeded) {
109 Log.e(TAG, "preloadInZygote returned false");
110 }
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +0100111 }
Narayan Kamath6f6e8942017-07-06 12:38:55 +0100112 } catch (ReflectiveOperationException e) {
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +0100113 Log.e(TAG, "Exception while preloading package", e);
114 }
Narayan Kamath24a33062017-07-03 14:12:26 +0100115
116 try {
117 DataOutputStream socketOut = getSocketOutputStream();
118 socketOut.writeInt(preloadSucceeded ? 1 : 0);
119 } catch (IOException ioe) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100120 throw new IllegalStateException("Error writing to command socket", ioe);
Narayan Kamath24a33062017-07-03 14:12:26 +0100121 }
122
Torne (Richard Coles)deeb6ad2017-04-18 17:16:36 -0400123 Log.i(TAG, "Package preload done");
Robert Sesekded20982016-08-15 13:59:13 -0400124 }
125 }
126
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000127 public static void main(String argv[]) {
Robert Sesek602d1322018-01-17 18:48:18 -0500128 Log.i(TAG, "Starting WebViewZygoteInit");
Robert Sesekded20982016-08-15 13:59:13 -0400129
Robert Sesek602d1322018-01-17 18:48:18 -0500130 String socketName = null;
131 for (String arg : argv) {
132 Log.i(TAG, arg);
133 if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
134 socketName = arg.substring(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG.length());
135 }
Robert Sesekded20982016-08-15 13:59:13 -0400136 }
Robert Sesek602d1322018-01-17 18:48:18 -0500137 if (socketName == null) {
138 throw new RuntimeException("No " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + " specified");
139 }
140
141 try {
142 Os.prctl(OsConstants.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
143 } catch (ErrnoException ex) {
144 throw new RuntimeException("Failed to set PR_SET_NO_NEW_PRIVS", ex);
145 }
146
147 sServer = new WebViewZygoteServer();
Robert Sesekded20982016-08-15 13:59:13 -0400148
Narayan Kamathbf99d062017-07-05 14:45:38 +0100149 final Runnable caller;
Robert Sesekded20982016-08-15 13:59:13 -0400150 try {
Robert Sesek602d1322018-01-17 18:48:18 -0500151 sServer.registerServerSocketAtAbstractName(socketName);
152
153 // Add the abstract socket to the FD whitelist so that the native zygote code
154 // can properly detach it after forking.
155 Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName);
156
Narayan Kamathbf99d062017-07-05 14:45:38 +0100157 // The select loop returns early in the child process after a fork and
158 // loops forever in the zygote.
159 caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS));
Robert Sesekded20982016-08-15 13:59:13 -0400160 } catch (RuntimeException e) {
161 Log.e(TAG, "Fatal exception:", e);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100162 throw e;
163 } finally {
164 sServer.closeServerSocket();
Robert Sesekded20982016-08-15 13:59:13 -0400165 }
166
Narayan Kamathbf99d062017-07-05 14:45:38 +0100167 // We're in the child process and have exited the select loop. Proceed to execute the
168 // command.
169 if (caller != null) {
170 caller.run();
171 }
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000172 }
173}