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.UserHandle; 24 import android.os.ZygoteProcess; 25 import android.text.TextUtils; 26 import android.util.Log; 27 28 import com.android.internal.annotations.GuardedBy; 29 import com.android.internal.os.Zygote; 30 31 /** @hide */ 32 public class WebViewZygote { 33 private static final String LOGTAG = "WebViewZygote"; 34 35 /** 36 * Lock object that protects all other static members. 37 */ 38 private static final Object sLock = new Object(); 39 40 /** 41 * Instance that maintains the socket connection to the zygote. This is {@code null} if the 42 * zygote is not running or is not connected. 43 */ 44 @GuardedBy("sLock") 45 private static ChildZygoteProcess sZygote; 46 47 /** 48 * Information about the selected WebView package. This is set from #onWebViewProviderChanged(). 49 */ 50 @GuardedBy("sLock") 51 private static PackageInfo sPackage; 52 getProcess()53 public static ZygoteProcess getProcess() { 54 synchronized (sLock) { 55 if (sZygote != null) return sZygote; 56 57 connectToZygoteIfNeededLocked(); 58 return sZygote; 59 } 60 } 61 getPackageName()62 public static String getPackageName() { 63 synchronized (sLock) { 64 return sPackage.packageName; 65 } 66 } 67 isMultiprocessEnabled()68 public static boolean isMultiprocessEnabled() { 69 synchronized (sLock) { 70 return sPackage != null; 71 } 72 } 73 onWebViewProviderChanged(PackageInfo packageInfo)74 static void onWebViewProviderChanged(PackageInfo packageInfo) { 75 synchronized (sLock) { 76 sPackage = packageInfo; 77 stopZygoteLocked(); 78 } 79 } 80 81 @GuardedBy("sLock") stopZygoteLocked()82 private static void stopZygoteLocked() { 83 if (sZygote != null) { 84 // Close the connection and kill the zygote process. This will not cause 85 // child processes to be killed by itself. But if this is called in response to 86 // setMultiprocessEnabled() or onWebViewProviderChanged(), the WebViewUpdater 87 // will kill all processes that depend on the WebView package. 88 sZygote.close(); 89 Process.killProcess(sZygote.getPid()); 90 sZygote = null; 91 } 92 } 93 94 @GuardedBy("sLock") connectToZygoteIfNeededLocked()95 private static void connectToZygoteIfNeededLocked() { 96 if (sZygote != null) { 97 return; 98 } 99 100 if (sPackage == null) { 101 Log.e(LOGTAG, "Cannot connect to zygote, no package specified"); 102 return; 103 } 104 105 try { 106 String abi = sPackage.applicationInfo.primaryCpuAbi; 107 int runtimeFlags = Zygote.getMemorySafetyRuntimeFlagsForSecondaryZygote( 108 sPackage.applicationInfo, null); 109 final int[] sharedAppGid = { 110 UserHandle.getSharedAppGid(UserHandle.getAppId(sPackage.applicationInfo.uid)) }; 111 sZygote = Process.ZYGOTE_PROCESS.startChildZygote( 112 "com.android.internal.os.WebViewZygoteInit", 113 "webview_zygote", 114 Process.WEBVIEW_ZYGOTE_UID, 115 Process.WEBVIEW_ZYGOTE_UID, 116 sharedAppGid, // Access to shared app GID for ART profiles 117 runtimeFlags, 118 "webview_zygote", // seInfo 119 abi, // abi 120 TextUtils.join(",", Build.SUPPORTED_ABIS), 121 null, // instructionSet 122 Process.FIRST_ISOLATED_UID, 123 Integer.MAX_VALUE); // TODO(b/123615476) deal with user-id ranges properly 124 ZygoteProcess.waitForConnectionToZygote(sZygote.getPrimarySocketAddress()); 125 sZygote.preloadApp(sPackage.applicationInfo, abi); 126 } catch (Exception e) { 127 Log.e(LOGTAG, "Error connecting to webview zygote", e); 128 stopZygoteLocked(); 129 } 130 } 131 } 132