blob: 3a1c4576ab3e68073ca30b001571d385bf9ef8c3 [file] [log] [blame]
Robert Sesekded20982016-08-15 13:59:13 -04001/*
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 android.webkit;
18
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010019import android.app.LoadedApk;
Torne (Richard Coles)4fd8aa52017-09-19 15:21:29 -040020import android.content.pm.ApplicationInfo;
Robert Sesekded20982016-08-15 13:59:13 -040021import android.content.pm.PackageInfo;
Torne (Richard Coles)e0624042018-03-13 17:48:52 -040022import android.os.AsyncTask;
Robert Sesekded20982016-08-15 13:59:13 -040023import android.os.Build;
Robert Sesek602d1322018-01-17 18:48:18 -050024import android.os.ChildZygoteProcess;
25import android.os.Process;
Robert Sesekded20982016-08-15 13:59:13 -040026import android.os.ZygoteProcess;
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010027import android.text.TextUtils;
Robert Sesekded20982016-08-15 13:59:13 -040028import android.util.Log;
29
Robert Sesek89cc5202016-12-16 12:06:44 -050030import com.android.internal.annotations.GuardedBy;
31
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010032import java.io.File;
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010033import java.util.ArrayList;
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010034import java.util.List;
Robert Sesekded20982016-08-15 13:59:13 -040035
36/** @hide */
37public class WebViewZygote {
38 private static final String LOGTAG = "WebViewZygote";
39
Robert Sesek89cc5202016-12-16 12:06:44 -050040 /**
41 * Lock object that protects all other static members.
42 */
43 private static final Object sLock = new Object();
44
45 /**
Nate Fischer0a6140d2017-09-05 12:37:49 -070046 * Instance that maintains the socket connection to the zygote. This is {@code null} if the
47 * zygote is not running or is not connected.
Robert Sesek89cc5202016-12-16 12:06:44 -050048 */
49 @GuardedBy("sLock")
Robert Sesek602d1322018-01-17 18:48:18 -050050 private static ChildZygoteProcess sZygote;
Gustav Senntonf05f99b2017-03-22 19:30:33 +000051
52 /**
Robert Sesek89cc5202016-12-16 12:06:44 -050053 * Information about the selected WebView package. This is set from #onWebViewProviderChanged().
54 */
55 @GuardedBy("sLock")
Robert Sesekded20982016-08-15 13:59:13 -040056 private static PackageInfo sPackage;
57
Robert Sesek89cc5202016-12-16 12:06:44 -050058 /**
Torne (Richard Coles)4fd8aa52017-09-19 15:21:29 -040059 * Original ApplicationInfo for the selected WebView package before stub fixup. This is set from
Torne (Richard Coles)04526702017-01-13 14:19:39 +000060 * #onWebViewProviderChanged().
61 */
62 @GuardedBy("sLock")
Torne (Richard Coles)4fd8aa52017-09-19 15:21:29 -040063 private static ApplicationInfo sPackageOriginalAppInfo;
Torne (Richard Coles)04526702017-01-13 14:19:39 +000064
65 /**
Nate Fischer0a6140d2017-09-05 12:37:49 -070066 * Flag for whether multi-process WebView is enabled. If this is {@code false}, the zygote
Robert Sesek89cc5202016-12-16 12:06:44 -050067 * will not be started.
68 */
69 @GuardedBy("sLock")
Robert Sesekded20982016-08-15 13:59:13 -040070 private static boolean sMultiprocessEnabled = false;
71
72 public static ZygoteProcess getProcess() {
Robert Sesek89cc5202016-12-16 12:06:44 -050073 synchronized (sLock) {
Gustav Senntonf05f99b2017-03-22 19:30:33 +000074 if (sZygote != null) return sZygote;
75
Robert Sesek602d1322018-01-17 18:48:18 -050076 connectToZygoteIfNeededLocked();
Robert Sesek89cc5202016-12-16 12:06:44 -050077 return sZygote;
78 }
Robert Sesekded20982016-08-15 13:59:13 -040079 }
80
81 public static String getPackageName() {
Robert Sesek89cc5202016-12-16 12:06:44 -050082 synchronized (sLock) {
83 return sPackage.packageName;
84 }
Robert Sesekded20982016-08-15 13:59:13 -040085 }
86
Robert Sesekc5f86642016-11-04 10:20:38 -040087 public static boolean isMultiprocessEnabled() {
Robert Sesek89cc5202016-12-16 12:06:44 -050088 synchronized (sLock) {
89 return sMultiprocessEnabled && sPackage != null;
90 }
Robert Sesekc5f86642016-11-04 10:20:38 -040091 }
92
Robert Sesekded20982016-08-15 13:59:13 -040093 public static void setMultiprocessEnabled(boolean enabled) {
Robert Sesek89cc5202016-12-16 12:06:44 -050094 synchronized (sLock) {
95 sMultiprocessEnabled = enabled;
Robert Sesekded20982016-08-15 13:59:13 -040096
Torne (Richard Coles)e0624042018-03-13 17:48:52 -040097 // When toggling between multi-process being on/off, start or stop the
98 // zygote. If it is enabled and the zygote is not yet started, launch it.
99 // Otherwise, kill it. The name may be null if the package information has
100 // not yet been resolved.
101 if (enabled) {
102 // Run on a background thread as this waits for the zygote to start and we don't
103 // want to block the caller on this. It's okay if this is delayed as anyone trying
104 // to use the zygote will call it first anyway.
105 AsyncTask.THREAD_POOL_EXECUTOR.execute(WebViewZygote::getProcess);
106 } else {
107 // No need to run this in the background, it's very brief.
Robert Sesek602d1322018-01-17 18:48:18 -0500108 stopZygoteLocked();
Robert Sesek89cc5202016-12-16 12:06:44 -0500109 }
Robert Sesekded20982016-08-15 13:59:13 -0400110 }
111 }
112
Torne (Richard Coles)4fd8aa52017-09-19 15:21:29 -0400113 public static void onWebViewProviderChanged(PackageInfo packageInfo,
114 ApplicationInfo originalAppInfo) {
Robert Sesek89cc5202016-12-16 12:06:44 -0500115 synchronized (sLock) {
116 sPackage = packageInfo;
Torne (Richard Coles)4fd8aa52017-09-19 15:21:29 -0400117 sPackageOriginalAppInfo = originalAppInfo;
Robert Sesekded20982016-08-15 13:59:13 -0400118
Robert Sesek89cc5202016-12-16 12:06:44 -0500119 // If multi-process is not enabled, then do not start the zygote service.
120 if (!sMultiprocessEnabled) {
121 return;
122 }
123
Robert Sesek602d1322018-01-17 18:48:18 -0500124 stopZygoteLocked();
Robert Sesekded20982016-08-15 13:59:13 -0400125 }
Robert Sesekded20982016-08-15 13:59:13 -0400126 }
127
Robert Sesek89cc5202016-12-16 12:06:44 -0500128 @GuardedBy("sLock")
Robert Sesek602d1322018-01-17 18:48:18 -0500129 private static void stopZygoteLocked() {
130 if (sZygote != null) {
131 // Close the connection and kill the zygote process. This will not cause
132 // child processes to be killed by itself. But if this is called in response to
133 // setMultiprocessEnabled() or onWebViewProviderChanged(), the WebViewUpdater
134 // will kill all processes that depend on the WebView package.
135 sZygote.close();
136 Process.killProcess(sZygote.getPid());
137 sZygote = null;
Robert Sesekded20982016-08-15 13:59:13 -0400138 }
Robert Sesekded20982016-08-15 13:59:13 -0400139 }
140
Robert Sesek89cc5202016-12-16 12:06:44 -0500141 @GuardedBy("sLock")
142 private static void connectToZygoteIfNeededLocked() {
Gustav Senntonf05f99b2017-03-22 19:30:33 +0000143 if (sZygote != null) {
Robert Sesekded20982016-08-15 13:59:13 -0400144 return;
Gustav Senntonf05f99b2017-03-22 19:30:33 +0000145 }
Robert Sesekded20982016-08-15 13:59:13 -0400146
147 if (sPackage == null) {
148 Log.e(LOGTAG, "Cannot connect to zygote, no package specified");
149 return;
150 }
151
Robert Sesekded20982016-08-15 13:59:13 -0400152 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800153 sZygote = Process.ZYGOTE_PROCESS.startChildZygote(
Robert Sesek602d1322018-01-17 18:48:18 -0500154 "com.android.internal.os.WebViewZygoteInit",
155 "webview_zygote",
156 Process.WEBVIEW_ZYGOTE_UID,
157 Process.WEBVIEW_ZYGOTE_UID,
158 null, // gids
159 0, // runtimeFlags
160 "webview_zygote", // seInfo
161 sPackage.applicationInfo.primaryCpuAbi, // abi
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100162 TextUtils.join(",", Build.SUPPORTED_ABIS),
Martijn Coenen86f08a52019-01-03 16:23:01 +0100163 null, // instructionSet
164 Process.FIRST_ISOLATED_UID,
165 Process.LAST_ISOLATED_UID);
Robert Sesekded20982016-08-15 13:59:13 -0400166
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +0100167 // All the work below is usually done by LoadedApk, but the zygote can't talk to
168 // PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so
169 // doesn't have an ActivityThread and can't use Binder.
170 // Instead, figure out the paths here, in the system server where we have access to
171 // the package manager. Reuse the logic from LoadedApk to determine the correct
172 // paths and pass them to the zygote as strings.
173 final List<String> zipPaths = new ArrayList<>(10);
174 final List<String> libPaths = new ArrayList<>(10);
Dimitry Ivanov638d8102017-02-22 15:39:42 -0800175 LoadedApk.makePaths(null, false, sPackage.applicationInfo, zipPaths, libPaths);
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +0100176 final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
177 final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
178 TextUtils.join(File.pathSeparator, zipPaths);
Robert Sesekded20982016-08-15 13:59:13 -0400179
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500180 String libFileName = WebViewFactory.getWebViewLibrary(sPackage.applicationInfo);
181
Torne (Richard Coles)4fd8aa52017-09-19 15:21:29 -0400182 // In the case where the ApplicationInfo has been modified by the stub WebView,
183 // we need to use the original ApplicationInfo to determine what the original classpath
184 // would have been to use as a cache key.
185 LoadedApk.makePaths(null, false, sPackageOriginalAppInfo, zipPaths, null);
186 final String cacheKey = (zipPaths.size() == 1) ? zipPaths.get(0) :
187 TextUtils.join(File.pathSeparator, zipPaths);
188
Robert Sesek602d1322018-01-17 18:48:18 -0500189 ZygoteProcess.waitForConnectionToZygote(sZygote.getPrimarySocketAddress());
Gustav Sennton833813c2017-04-24 14:23:39 +0100190
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +0100191 Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500192 sZygote.preloadPackageForAbi(zip, librarySearchPath, libFileName, cacheKey,
Torne (Richard Coles)04526702017-01-13 14:19:39 +0000193 Build.SUPPORTED_ABIS[0]);
Robert Sesekded20982016-08-15 13:59:13 -0400194 } catch (Exception e) {
Robert Sesek602d1322018-01-17 18:48:18 -0500195 Log.e(LOGTAG, "Error connecting to webview zygote", e);
196 stopZygoteLocked();
Robert Sesekded20982016-08-15 13:59:13 -0400197 }
198 }
Robert Sesekded20982016-08-15 13:59:13 -0400199}