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