• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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