Home | History | Annotate | Download | only in webkit
      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 
     58     public static ZygoteProcess getProcess() {
     59         synchronized (sLock) {
     60             if (sZygote != null) return sZygote;
     61 
     62             connectToZygoteIfNeededLocked();
     63             return sZygote;
     64         }
     65     }
     66 
     67     public static String getPackageName() {
     68         synchronized (sLock) {
     69             return sPackage.packageName;
     70         }
     71     }
     72 
     73     public static boolean isMultiprocessEnabled() {
     74         synchronized (sLock) {
     75             return sMultiprocessEnabled && sPackage != null;
     76         }
     77     }
     78 
     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 
     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")
    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")
    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