blob: 2d6f44352ba7d5ac4967e3a80771a194168b1ad5 [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;
Robert Sesekded20982016-08-15 13:59:13 -040020import android.content.pm.PackageInfo;
21import android.os.Build;
22import android.os.SystemService;
23import android.os.ZygoteProcess;
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010024import android.text.TextUtils;
Robert Sesekded20982016-08-15 13:59:13 -040025import android.util.Log;
26
Robert Sesek89cc5202016-12-16 12:06:44 -050027import com.android.internal.annotations.GuardedBy;
28
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010029import java.io.File;
Robert Sesekded20982016-08-15 13:59:13 -040030import java.io.IOException;
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010031import java.util.ArrayList;
Robert Sesekded20982016-08-15 13:59:13 -040032import java.util.Arrays;
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010033import java.util.List;
Robert Sesekded20982016-08-15 13:59:13 -040034import java.util.concurrent.TimeoutException;
35
36/** @hide */
37public class WebViewZygote {
38 private static final String LOGTAG = "WebViewZygote";
39
40 private static final String WEBVIEW_ZYGOTE_SERVICE_32 = "webview_zygote32";
41 private static final String WEBVIEW_ZYGOTE_SERVICE_64 = "webview_zygote64";
42
Robert Sesek89cc5202016-12-16 12:06:44 -050043 /**
44 * Lock object that protects all other static members.
45 */
46 private static final Object sLock = new Object();
47
48 /**
49 * Instance that maintains the socket connection to the zygote. This is null if the zygote
50 * is not running or is not connected.
51 */
52 @GuardedBy("sLock")
Robert Sesekded20982016-08-15 13:59:13 -040053 private static ZygoteProcess sZygote;
54
Robert Sesek89cc5202016-12-16 12:06:44 -050055 /**
56 * Information about the selected WebView package. This is set from #onWebViewProviderChanged().
57 */
58 @GuardedBy("sLock")
Robert Sesekded20982016-08-15 13:59:13 -040059 private static PackageInfo sPackage;
60
Robert Sesek89cc5202016-12-16 12:06:44 -050061 /**
62 * Flag for whether multi-process WebView is enabled. If this is false, the zygote
63 * will not be started.
64 */
65 @GuardedBy("sLock")
Robert Sesekded20982016-08-15 13:59:13 -040066 private static boolean sMultiprocessEnabled = false;
67
68 public static ZygoteProcess getProcess() {
Robert Sesek89cc5202016-12-16 12:06:44 -050069 synchronized (sLock) {
70 connectToZygoteIfNeededLocked();
71 return sZygote;
72 }
Robert Sesekded20982016-08-15 13:59:13 -040073 }
74
75 public static String getPackageName() {
Robert Sesek89cc5202016-12-16 12:06:44 -050076 synchronized (sLock) {
77 return sPackage.packageName;
78 }
Robert Sesekded20982016-08-15 13:59:13 -040079 }
80
Robert Sesekc5f86642016-11-04 10:20:38 -040081 public static boolean isMultiprocessEnabled() {
Robert Sesek89cc5202016-12-16 12:06:44 -050082 synchronized (sLock) {
83 return sMultiprocessEnabled && sPackage != null;
84 }
Robert Sesekc5f86642016-11-04 10:20:38 -040085 }
86
Robert Sesekded20982016-08-15 13:59:13 -040087 public static void setMultiprocessEnabled(boolean enabled) {
Robert Sesek89cc5202016-12-16 12:06:44 -050088 synchronized (sLock) {
89 sMultiprocessEnabled = enabled;
Robert Sesekded20982016-08-15 13:59:13 -040090
Robert Sesek89cc5202016-12-16 12:06:44 -050091 // When toggling between multi-process being on/off, start or stop the
92 // service. If it is enabled and the zygote is not yet started, bring up the service.
93 // Otherwise, bring down the service. The name may be null if the package
94 // information has not yet been resolved.
95 final String serviceName = getServiceNameLocked();
96 if (serviceName == null) return;
Robert Sesekded20982016-08-15 13:59:13 -040097
Robert Sesek89cc5202016-12-16 12:06:44 -050098 if (enabled && sZygote == null) {
99 SystemService.start(serviceName);
100 } else {
101 SystemService.stop(serviceName);
102 sZygote = null;
103 }
Robert Sesekded20982016-08-15 13:59:13 -0400104 }
105 }
106
107 public static void onWebViewProviderChanged(PackageInfo packageInfo) {
Robert Sesek89cc5202016-12-16 12:06:44 -0500108 String serviceName;
109 synchronized (sLock) {
110 sPackage = packageInfo;
Robert Sesekded20982016-08-15 13:59:13 -0400111
Robert Sesek89cc5202016-12-16 12:06:44 -0500112 // If multi-process is not enabled, then do not start the zygote service.
113 if (!sMultiprocessEnabled) {
114 return;
115 }
116
117 serviceName = getServiceNameLocked();
118 sZygote = null;
119
120 // The service may enter the RUNNING state before it opens the socket,
121 // so connectToZygoteIfNeededLocked() may still fail.
122 if (SystemService.isStopped(serviceName)) {
123 SystemService.start(serviceName);
124 } else {
125 SystemService.restart(serviceName);
126 }
127
128 try {
129 SystemService.waitForState(serviceName, SystemService.State.RUNNING, 5000);
130 } catch (TimeoutException e) {
131 Log.e(LOGTAG, "Timed out waiting for " + serviceName);
132 return;
133 }
134
135 connectToZygoteIfNeededLocked();
Robert Sesekded20982016-08-15 13:59:13 -0400136 }
Robert Sesekded20982016-08-15 13:59:13 -0400137 }
138
Robert Sesek89cc5202016-12-16 12:06:44 -0500139 @GuardedBy("sLock")
140 private static String getServiceNameLocked() {
Robert Sesekded20982016-08-15 13:59:13 -0400141 if (sPackage == null)
142 return null;
143
144 if (Arrays.asList(Build.SUPPORTED_64_BIT_ABIS).contains(
145 sPackage.applicationInfo.primaryCpuAbi)) {
146 return WEBVIEW_ZYGOTE_SERVICE_64;
147 }
148
149 return WEBVIEW_ZYGOTE_SERVICE_32;
150 }
151
Robert Sesek89cc5202016-12-16 12:06:44 -0500152 @GuardedBy("sLock")
153 private static void connectToZygoteIfNeededLocked() {
Robert Sesekded20982016-08-15 13:59:13 -0400154 if (sZygote != null)
155 return;
156
157 if (sPackage == null) {
158 Log.e(LOGTAG, "Cannot connect to zygote, no package specified");
159 return;
160 }
161
Robert Sesek89cc5202016-12-16 12:06:44 -0500162 final String serviceName = getServiceNameLocked();
Robert Sesekded20982016-08-15 13:59:13 -0400163 if (!SystemService.isRunning(serviceName)) {
164 Log.e(LOGTAG, serviceName + " is not running");
165 return;
166 }
167
168 try {
169 sZygote = new ZygoteProcess("webview_zygote", null);
170
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +0100171 // All the work below is usually done by LoadedApk, but the zygote can't talk to
172 // PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so
173 // doesn't have an ActivityThread and can't use Binder.
174 // Instead, figure out the paths here, in the system server where we have access to
175 // the package manager. Reuse the logic from LoadedApk to determine the correct
176 // paths and pass them to the zygote as strings.
177 final List<String> zipPaths = new ArrayList<>(10);
178 final List<String> libPaths = new ArrayList<>(10);
179 LoadedApk.makePaths(null, sPackage.applicationInfo, zipPaths, libPaths);
180 final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
181 final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
182 TextUtils.join(File.pathSeparator, zipPaths);
Robert Sesekded20982016-08-15 13:59:13 -0400183
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +0100184 Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
185 sZygote.preloadPackageForAbi(zip, librarySearchPath, Build.SUPPORTED_ABIS[0]);
Robert Sesekded20982016-08-15 13:59:13 -0400186 } catch (Exception e) {
187 Log.e(LOGTAG, "Error connecting to " + serviceName, e);
188 sZygote = null;
189 }
190 }
191}