165 lines
5.5 KiB
Java
165 lines
5.5 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2016 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package android.webkit;
|
||
|
|
||
|
import static android.webkit.Flags.updateServiceV2;
|
||
|
|
||
|
import android.content.pm.PackageInfo;
|
||
|
import android.os.Build;
|
||
|
import android.os.ChildZygoteProcess;
|
||
|
import android.os.Process;
|
||
|
import android.os.ZygoteProcess;
|
||
|
import android.text.TextUtils;
|
||
|
import android.util.Log;
|
||
|
|
||
|
import com.android.internal.annotations.GuardedBy;
|
||
|
import com.android.internal.os.Zygote;
|
||
|
|
||
|
/** @hide */
|
||
|
public class WebViewZygote {
|
||
|
private static final String LOGTAG = "WebViewZygote";
|
||
|
|
||
|
/**
|
||
|
* Lock object that protects all other static members.
|
||
|
*/
|
||
|
private static final Object sLock = new Object();
|
||
|
|
||
|
/**
|
||
|
* Instance that maintains the socket connection to the zygote. This is {@code null} if the
|
||
|
* zygote is not running or is not connected.
|
||
|
*/
|
||
|
@GuardedBy("sLock")
|
||
|
private static ChildZygoteProcess sZygote;
|
||
|
|
||
|
/**
|
||
|
* Information about the selected WebView package. This is set from #onWebViewProviderChanged().
|
||
|
*/
|
||
|
@GuardedBy("sLock")
|
||
|
private static PackageInfo sPackage;
|
||
|
|
||
|
/**
|
||
|
* Flag for whether multi-process WebView is enabled. If this is {@code false}, the zygote will
|
||
|
* not be started. Should be removed entirely after we remove the updateServiceV2 flag.
|
||
|
*/
|
||
|
@GuardedBy("sLock")
|
||
|
private static boolean sMultiprocessEnabled = false;
|
||
|
|
||
|
public static ZygoteProcess getProcess() {
|
||
|
synchronized (sLock) {
|
||
|
if (sZygote != null) return sZygote;
|
||
|
|
||
|
connectToZygoteIfNeededLocked();
|
||
|
return sZygote;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static String getPackageName() {
|
||
|
synchronized (sLock) {
|
||
|
return sPackage.packageName;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static boolean isMultiprocessEnabled() {
|
||
|
synchronized (sLock) {
|
||
|
if (updateServiceV2()) {
|
||
|
return sPackage != null;
|
||
|
} else {
|
||
|
return sMultiprocessEnabled && sPackage != null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static void setMultiprocessEnabled(boolean enabled) {
|
||
|
if (updateServiceV2()) {
|
||
|
throw new IllegalStateException(
|
||
|
"setMultiprocessEnabled shouldn't be called if update_service_v2 flag is set.");
|
||
|
}
|
||
|
synchronized (sLock) {
|
||
|
sMultiprocessEnabled = enabled;
|
||
|
|
||
|
// When multi-process is disabled, kill the zygote. When it is enabled,
|
||
|
// the zygote will be started when it is first needed in getProcess().
|
||
|
if (!enabled) {
|
||
|
stopZygoteLocked();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void onWebViewProviderChanged(PackageInfo packageInfo) {
|
||
|
synchronized (sLock) {
|
||
|
sPackage = packageInfo;
|
||
|
|
||
|
// If multi-process is not enabled, then do not start the zygote service.
|
||
|
// Only check sMultiprocessEnabled if updateServiceV2 is not enabled.
|
||
|
if (!updateServiceV2() && !sMultiprocessEnabled) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
stopZygoteLocked();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@GuardedBy("sLock")
|
||
|
private static void stopZygoteLocked() {
|
||
|
if (sZygote != null) {
|
||
|
// Close the connection and kill the zygote process. This will not cause
|
||
|
// child processes to be killed by itself. But if this is called in response to
|
||
|
// setMultiprocessEnabled() or onWebViewProviderChanged(), the WebViewUpdater
|
||
|
// will kill all processes that depend on the WebView package.
|
||
|
sZygote.close();
|
||
|
Process.killProcess(sZygote.getPid());
|
||
|
sZygote = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@GuardedBy("sLock")
|
||
|
private static void connectToZygoteIfNeededLocked() {
|
||
|
if (sZygote != null) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (sPackage == null) {
|
||
|
Log.e(LOGTAG, "Cannot connect to zygote, no package specified");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
String abi = sPackage.applicationInfo.primaryCpuAbi;
|
||
|
int runtimeFlags = Zygote.getMemorySafetyRuntimeFlagsForSecondaryZygote(
|
||
|
sPackage.applicationInfo, null);
|
||
|
sZygote = Process.ZYGOTE_PROCESS.startChildZygote(
|
||
|
"com.android.internal.os.WebViewZygoteInit",
|
||
|
"webview_zygote",
|
||
|
Process.WEBVIEW_ZYGOTE_UID,
|
||
|
Process.WEBVIEW_ZYGOTE_UID,
|
||
|
null, // gids
|
||
|
runtimeFlags,
|
||
|
"webview_zygote", // seInfo
|
||
|
abi, // abi
|
||
|
TextUtils.join(",", Build.SUPPORTED_ABIS),
|
||
|
null, // instructionSet
|
||
|
Process.FIRST_ISOLATED_UID,
|
||
|
Integer.MAX_VALUE); // TODO(b/123615476) deal with user-id ranges properly
|
||
|
ZygoteProcess.waitForConnectionToZygote(sZygote.getPrimarySocketAddress());
|
||
|
sZygote.preloadApp(sPackage.applicationInfo, abi);
|
||
|
} catch (Exception e) {
|
||
|
Log.e(LOGTAG, "Error connecting to webview zygote", e);
|
||
|
stopZygoteLocked();
|
||
|
}
|
||
|
}
|
||
|
}
|