1 /* 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 17 package android.webkit; 18 19 import android.content.pm.PackageInfo; 20 import android.os.Build; 21 import android.os.ChildZygoteProcess; 22 import android.os.Process; 23 import android.os.ZygoteProcess; 24 import android.text.TextUtils; 25 import android.util.Log; 26 27 import com.android.internal.annotations.GuardedBy; 28 29 /** @hide */ 30 public class WebViewZygote { 31 private static final String LOGTAG = "WebViewZygote"; 32 33 /** 34 * Lock object that protects all other static members. 35 */ 36 private static final Object sLock = new Object(); 37 38 /** 39 * Instance that maintains the socket connection to the zygote. This is {@code null} if the 40 * zygote is not running or is not connected. 41 */ 42 @GuardedBy("sLock") 43 private static ChildZygoteProcess sZygote; 44 45 /** 46 * Information about the selected WebView package. This is set from #onWebViewProviderChanged(). 47 */ 48 @GuardedBy("sLock") 49 private static PackageInfo sPackage; 50 51 /** 52 * Flag for whether multi-process WebView is enabled. If this is {@code false}, the zygote 53 * will not be started. 54 */ 55 @GuardedBy("sLock") 56 private static boolean sMultiprocessEnabled = false; 57 getProcess()58 public static ZygoteProcess getProcess() { 59 synchronized (sLock) { 60 if (sZygote != null) return sZygote; 61 62 connectToZygoteIfNeededLocked(); 63 return sZygote; 64 } 65 } 66 getPackageName()67 public static String getPackageName() { 68 synchronized (sLock) { 69 return sPackage.packageName; 70 } 71 } 72 isMultiprocessEnabled()73 public static boolean isMultiprocessEnabled() { 74 synchronized (sLock) { 75 return sMultiprocessEnabled && sPackage != null; 76 } 77 } 78 setMultiprocessEnabled(boolean enabled)79 public static void setMultiprocessEnabled(boolean enabled) { 80 synchronized (sLock) { 81 sMultiprocessEnabled = enabled; 82 83 // When multi-process is disabled, kill the zygote. When it is enabled, 84 // the zygote will be started when it is first needed in getProcess(). 85 if (!enabled) { 86 stopZygoteLocked(); 87 } 88 } 89 } 90 onWebViewProviderChanged(PackageInfo packageInfo)91 static void onWebViewProviderChanged(PackageInfo packageInfo) { 92 synchronized (sLock) { 93 sPackage = packageInfo; 94 95 // If multi-process is not enabled, then do not start the zygote service. 96 if (!sMultiprocessEnabled) { 97 return; 98 } 99 100 stopZygoteLocked(); 101 } 102 } 103 104 @GuardedBy("sLock") stopZygoteLocked()105 private static void stopZygoteLocked() { 106 if (sZygote != null) { 107 // Close the connection and kill the zygote process. This will not cause 108 // child processes to be killed by itself. But if this is called in response to 109 // setMultiprocessEnabled() or onWebViewProviderChanged(), the WebViewUpdater 110 // will kill all processes that depend on the WebView package. 111 sZygote.close(); 112 Process.killProcess(sZygote.getPid()); 113 sZygote = null; 114 } 115 } 116 117 @GuardedBy("sLock") connectToZygoteIfNeededLocked()118 private static void connectToZygoteIfNeededLocked() { 119 if (sZygote != null) { 120 return; 121 } 122 123 if (sPackage == null) { 124 Log.e(LOGTAG, "Cannot connect to zygote, no package specified"); 125 return; 126 } 127 128 try { 129 String abi = sPackage.applicationInfo.primaryCpuAbi; 130 sZygote = Process.ZYGOTE_PROCESS.startChildZygote( 131 "com.android.internal.os.WebViewZygoteInit", 132 "webview_zygote", 133 Process.WEBVIEW_ZYGOTE_UID, 134 Process.WEBVIEW_ZYGOTE_UID, 135 null, // gids 136 0, // runtimeFlags 137 "webview_zygote", // seInfo 138 abi, // abi 139 TextUtils.join(",", Build.SUPPORTED_ABIS), 140 null, // instructionSet 141 Process.FIRST_ISOLATED_UID, 142 Integer.MAX_VALUE); // TODO(b/123615476) deal with user-id ranges properly 143 ZygoteProcess.waitForConnectionToZygote(sZygote.getPrimarySocketAddress()); 144 sZygote.preloadApp(sPackage.applicationInfo, abi); 145 } catch (Exception e) { 146 Log.e(LOGTAG, "Error connecting to webview zygote", e); 147 stopZygoteLocked(); 148 } 149 } 150 } 151