WebViewZygote.java revision 638d81009918eae44eec3261e235b78eae44331d
1ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek/* 2ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek * Copyright (C) 2016 The Android Open Source Project 3ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek * 4ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek * Licensed under the Apache License, Version 2.0 (the "License"); 5ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek * you may not use this file except in compliance with the License. 6ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek * You may obtain a copy of the License at 7ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek * 8ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek * http://www.apache.org/licenses/LICENSE-2.0 9ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek * 10ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek * Unless required by applicable law or agreed to in writing, software 11ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek * distributed under the License is distributed on an "AS IS" BASIS, 12ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek * See the License for the specific language governing permissions and 14ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek * limitations under the License. 15ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek */ 16ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 17ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekpackage android.webkit; 18ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 193b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)import android.app.LoadedApk; 20ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekimport android.content.pm.PackageInfo; 21ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekimport android.os.Build; 22ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekimport android.os.SystemService; 23ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekimport android.os.ZygoteProcess; 243b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)import android.text.TextUtils; 25ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekimport android.util.Log; 26ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 2789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesekimport com.android.internal.annotations.GuardedBy; 2889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek 293b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)import java.io.File; 30ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekimport java.io.IOException; 313b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)import java.util.ArrayList; 32ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekimport java.util.Arrays; 333b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)import java.util.List; 34ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekimport java.util.concurrent.TimeoutException; 35ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 36ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek/** @hide */ 37ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekpublic class WebViewZygote { 38ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek private static final String LOGTAG = "WebViewZygote"; 39ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 40ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek private static final String WEBVIEW_ZYGOTE_SERVICE_32 = "webview_zygote32"; 41ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek private static final String WEBVIEW_ZYGOTE_SERVICE_64 = "webview_zygote64"; 42ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 4389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek /** 4489cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek * Lock object that protects all other static members. 4589cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek */ 4689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek private static final Object sLock = new Object(); 4789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek 4889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek /** 4989cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek * Instance that maintains the socket connection to the zygote. This is null if the zygote 5089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek * is not running or is not connected. 5189cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek */ 5289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek @GuardedBy("sLock") 53ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek private static ZygoteProcess sZygote; 54ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 5589cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek /** 5689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek * Information about the selected WebView package. This is set from #onWebViewProviderChanged(). 5789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek */ 5889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek @GuardedBy("sLock") 59ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek private static PackageInfo sPackage; 60ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 6189cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek /** 6289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek * Flag for whether multi-process WebView is enabled. If this is false, the zygote 6389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek * will not be started. 6489cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek */ 6589cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek @GuardedBy("sLock") 66ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek private static boolean sMultiprocessEnabled = false; 67ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 68ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek public static ZygoteProcess getProcess() { 6989cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek synchronized (sLock) { 7089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek connectToZygoteIfNeededLocked(); 7189cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek return sZygote; 7289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek } 73ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek } 74ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 75ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek public static String getPackageName() { 7689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek synchronized (sLock) { 7789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek return sPackage.packageName; 7889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek } 79ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek } 80ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 81c5f86647b19d5cac4d9874ef84954fcf7a6d5fa9Robert Sesek public static boolean isMultiprocessEnabled() { 8289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek synchronized (sLock) { 8389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek return sMultiprocessEnabled && sPackage != null; 8489cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek } 85c5f86647b19d5cac4d9874ef84954fcf7a6d5fa9Robert Sesek } 86c5f86647b19d5cac4d9874ef84954fcf7a6d5fa9Robert Sesek 87ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek public static void setMultiprocessEnabled(boolean enabled) { 8889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek synchronized (sLock) { 8989cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek sMultiprocessEnabled = enabled; 9089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek 9189cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek // When toggling between multi-process being on/off, start or stop the 9289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek // service. If it is enabled and the zygote is not yet started, bring up the service. 9389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek // Otherwise, bring down the service. The name may be null if the package 9489cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek // information has not yet been resolved. 9589cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek final String serviceName = getServiceNameLocked(); 9689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek if (serviceName == null) return; 9789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek 9889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek if (enabled && sZygote == null) { 9989cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek SystemService.start(serviceName); 10089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek } else { 10189cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek SystemService.stop(serviceName); 10289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek sZygote = null; 10389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek } 104ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek } 105ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek } 106ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 107ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek public static void onWebViewProviderChanged(PackageInfo packageInfo) { 10889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek String serviceName; 10989cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek synchronized (sLock) { 11089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek sPackage = packageInfo; 111ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 11289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek // If multi-process is not enabled, then do not start the zygote service. 11389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek if (!sMultiprocessEnabled) { 11489cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek return; 11589cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek } 116ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 11789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek serviceName = getServiceNameLocked(); 11889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek sZygote = null; 119ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 12089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek // The service may enter the RUNNING state before it opens the socket, 12189cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek // so connectToZygoteIfNeededLocked() may still fail. 12289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek if (SystemService.isStopped(serviceName)) { 12389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek SystemService.start(serviceName); 12489cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek } else { 12589cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek SystemService.restart(serviceName); 12689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek } 12789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek 12889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek try { 12989cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek SystemService.waitForState(serviceName, SystemService.State.RUNNING, 5000); 13089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek } catch (TimeoutException e) { 13189cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek Log.e(LOGTAG, "Timed out waiting for " + serviceName); 13289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek return; 13389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek } 13489cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek 13589cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek connectToZygoteIfNeededLocked(); 136ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek } 137ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek } 138ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 13989cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek @GuardedBy("sLock") 14089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek private static String getServiceNameLocked() { 141ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek if (sPackage == null) 142ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek return null; 143ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 144ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek if (Arrays.asList(Build.SUPPORTED_64_BIT_ABIS).contains( 145ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek sPackage.applicationInfo.primaryCpuAbi)) { 146ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek return WEBVIEW_ZYGOTE_SERVICE_64; 147ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek } 148ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 149ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek return WEBVIEW_ZYGOTE_SERVICE_32; 150ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek } 151ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 15289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek @GuardedBy("sLock") 15389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek private static void connectToZygoteIfNeededLocked() { 154ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek if (sZygote != null) 155ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek return; 156ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 157ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek if (sPackage == null) { 158ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek Log.e(LOGTAG, "Cannot connect to zygote, no package specified"); 159ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek return; 160ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek } 161ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 16289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek final String serviceName = getServiceNameLocked(); 163ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek if (!SystemService.isRunning(serviceName)) { 164ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek Log.e(LOGTAG, serviceName + " is not running"); 165ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek return; 166ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek } 167ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 168ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek try { 169ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek sZygote = new ZygoteProcess("webview_zygote", null); 170ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek 1713b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) // All the work below is usually done by LoadedApk, but the zygote can't talk to 1723b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) // PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so 1733b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) // doesn't have an ActivityThread and can't use Binder. 1743b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) // Instead, figure out the paths here, in the system server where we have access to 1753b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) // the package manager. Reuse the logic from LoadedApk to determine the correct 1763b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) // paths and pass them to the zygote as strings. 1773b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) final List<String> zipPaths = new ArrayList<>(10); 1783b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) final List<String> libPaths = new ArrayList<>(10); 179638d81009918eae44eec3261e235b78eae44331dDimitry Ivanov LoadedApk.makePaths(null, false, sPackage.applicationInfo, zipPaths, libPaths); 1803b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths); 1813b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) : 1823b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) TextUtils.join(File.pathSeparator, zipPaths); 1833b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) 1843b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath); 1853b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles) sZygote.preloadPackageForAbi(zip, librarySearchPath, Build.SUPPORTED_ABIS[0]); 186ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek } catch (Exception e) { 187ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek Log.e(LOGTAG, "Error connecting to " + serviceName, e); 188ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek sZygote = null; 189ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek } 190ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek } 191ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek} 192