WebViewZygote.java revision f05f99b9106ab6dffcf71735f0f7c269ad23282e
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;
25f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Senntonimport android.util.AndroidRuntimeException;
26ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekimport android.util.Log;
27ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
2889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesekimport com.android.internal.annotations.GuardedBy;
2989cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek
303b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)import java.io.File;
31ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekimport java.io.IOException;
323b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)import java.util.ArrayList;
33ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekimport java.util.Arrays;
343b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)import java.util.List;
35ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekimport java.util.concurrent.TimeoutException;
36ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
37ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek/** @hide */
38ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekpublic class WebViewZygote {
39ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    private static final String LOGTAG = "WebViewZygote";
40ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
41ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    private static final String WEBVIEW_ZYGOTE_SERVICE_32 = "webview_zygote32";
42ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    private static final String WEBVIEW_ZYGOTE_SERVICE_64 = "webview_zygote64";
43ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
4489cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek    /**
4589cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek     * Lock object that protects all other static members.
4689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek     */
4789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek    private static final Object sLock = new Object();
4889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek
4989cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek    /**
5089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek     * Instance that maintains the socket connection to the zygote. This is null if the zygote
5189cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek     * is not running or is not connected.
5289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek     */
5389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek    @GuardedBy("sLock")
54ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    private static ZygoteProcess sZygote;
55ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
5689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek    /**
57f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton     * Variable that allows us to determine whether the WebView zygote Service has already been
58f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton     * started.
59f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton     */
60f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton    @GuardedBy("sLock")
61f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton    private static boolean sStartedService = false;
62f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton
63f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton    /**
6489cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek     * Information about the selected WebView package. This is set from #onWebViewProviderChanged().
6589cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek     */
6689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek    @GuardedBy("sLock")
67ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    private static PackageInfo sPackage;
68ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
6989cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek    /**
7089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek     * Flag for whether multi-process WebView is enabled. If this is false, the zygote
7189cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek     * will not be started.
7289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek     */
7389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek    @GuardedBy("sLock")
74ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    private static boolean sMultiprocessEnabled = false;
75ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
76ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    public static ZygoteProcess getProcess() {
7789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek        synchronized (sLock) {
78f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton            if (sZygote != null) return sZygote;
79f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton
80f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton            waitForServiceStartAndConnect();
8189cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            return sZygote;
8289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek        }
83ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    }
84ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
85ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    public static String getPackageName() {
8689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek        synchronized (sLock) {
8789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            return sPackage.packageName;
8889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek        }
89ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    }
90ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
91c5f86647b19d5cac4d9874ef84954fcf7a6d5fa9Robert Sesek    public static boolean isMultiprocessEnabled() {
9289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek        synchronized (sLock) {
9389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            return sMultiprocessEnabled && sPackage != null;
9489cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek        }
95c5f86647b19d5cac4d9874ef84954fcf7a6d5fa9Robert Sesek    }
96c5f86647b19d5cac4d9874ef84954fcf7a6d5fa9Robert Sesek
97ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    public static void setMultiprocessEnabled(boolean enabled) {
9889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek        synchronized (sLock) {
9989cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            sMultiprocessEnabled = enabled;
10089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek
10189cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            // When toggling between multi-process being on/off, start or stop the
10289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            // service. If it is enabled and the zygote is not yet started, bring up the service.
10389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            // Otherwise, bring down the service. The name may be null if the package
10489cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            // information has not yet been resolved.
10589cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            final String serviceName = getServiceNameLocked();
10689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            if (serviceName == null) return;
10789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek
108f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton            if (enabled) {
109f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton                if (!sStartedService) {
110f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton                    SystemService.start(serviceName);
111f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton                    sStartedService = true;
112f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton                }
11389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            } else {
11489cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek                SystemService.stop(serviceName);
115f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton                sStartedService = false;
11689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek                sZygote = null;
11789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            }
118ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        }
119ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    }
120ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
121ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    public static void onWebViewProviderChanged(PackageInfo packageInfo) {
12289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek        synchronized (sLock) {
12389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            sPackage = packageInfo;
124ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
12589cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            // If multi-process is not enabled, then do not start the zygote service.
12689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            if (!sMultiprocessEnabled) {
12789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek                return;
12889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            }
129ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
130f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton            final String serviceName = getServiceNameLocked();
13189cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            sZygote = null;
132ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
13389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            // The service may enter the RUNNING state before it opens the socket,
13489cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            // so connectToZygoteIfNeededLocked() may still fail.
13589cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            if (SystemService.isStopped(serviceName)) {
13689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek                SystemService.start(serviceName);
13789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            } else {
13889cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek                SystemService.restart(serviceName);
13989cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            }
140f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton            sStartedService = true;
141f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton        }
142f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton    }
14389cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek
144f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton    private static void waitForServiceStartAndConnect() {
145f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton        if (!sStartedService) {
146f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton            throw new AndroidRuntimeException("Tried waiting for the WebView Zygote Service to " +
147f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton                    "start running without first starting the service.");
148f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton        }
149f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton
150f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton        String serviceName;
151f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton        synchronized (sLock) {
152f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton            serviceName = getServiceNameLocked();
153f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton        }
154f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton        try {
155f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton            SystemService.waitForState(serviceName, SystemService.State.RUNNING, 5000);
156f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton        } catch (TimeoutException e) {
157f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton            Log.e(LOGTAG, "Timed out waiting for " + serviceName);
158f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton            return;
159f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton        }
16089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek
161f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton        synchronized (sLock) {
16289cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek            connectToZygoteIfNeededLocked();
163ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        }
164ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    }
165ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
16689cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek    @GuardedBy("sLock")
16789cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek    private static String getServiceNameLocked() {
168ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        if (sPackage == null)
169ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            return null;
170ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
171ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        if (Arrays.asList(Build.SUPPORTED_64_BIT_ABIS).contains(
172ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek                    sPackage.applicationInfo.primaryCpuAbi)) {
173ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            return WEBVIEW_ZYGOTE_SERVICE_64;
174ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        }
175ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
176ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        return WEBVIEW_ZYGOTE_SERVICE_32;
177ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    }
178ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
17989cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek    @GuardedBy("sLock")
18089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek    private static void connectToZygoteIfNeededLocked() {
181f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton        if (sZygote != null) {
182ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            return;
183f05f99b9106ab6dffcf71735f0f7c269ad23282eGustav Sennton        }
184ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
185ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        if (sPackage == null) {
186ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            Log.e(LOGTAG, "Cannot connect to zygote, no package specified");
187ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            return;
188ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        }
189ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
19089cc5205b3b54b85c584583760d07af7049e6e28Robert Sesek        final String serviceName = getServiceNameLocked();
191ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        if (!SystemService.isRunning(serviceName)) {
192ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            Log.e(LOGTAG, serviceName + " is not running");
193ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            return;
194ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        }
195ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
196ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        try {
197ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            sZygote = new ZygoteProcess("webview_zygote", null);
198ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
1993b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)            // All the work below is usually done by LoadedApk, but the zygote can't talk to
2003b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)            // PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so
2013b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)            // doesn't have an ActivityThread and can't use Binder.
2023b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)            // Instead, figure out the paths here, in the system server where we have access to
2033b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)            // the package manager. Reuse the logic from LoadedApk to determine the correct
2043b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)            // paths and pass them to the zygote as strings.
2053b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)            final List<String> zipPaths = new ArrayList<>(10);
2063b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)            final List<String> libPaths = new ArrayList<>(10);
207638d81009918eae44eec3261e235b78eae44331dDimitry Ivanov            LoadedApk.makePaths(null, false, sPackage.applicationInfo, zipPaths, libPaths);
2083b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)            final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
2093b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)            final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
2103b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)                    TextUtils.join(File.pathSeparator, zipPaths);
2113b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)
2123b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)            Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
2133b6ca99b1069e8f303727a00c1da7acabe017fd8Torne (Richard Coles)            sZygote.preloadPackageForAbi(zip, librarySearchPath, Build.SUPPORTED_ABIS[0]);
214ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        } catch (Exception e) {
215ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            Log.e(LOGTAG, "Error connecting to " + serviceName, e);
216ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            sZygote = null;
217ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        }
218ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    }
219ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek}
220