Merge "Reparent the webview_zygote to be a child of the main app_process zygote." am: 1c81aa6375
am: 486190f87b
Change-Id: I683dbbf730bfd02e43cb67bfcaa0df56d69c9796
This commit is contained in:
@@ -1,51 +0,0 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := webview_zygote
|
||||
|
||||
LOCAL_SRC_FILES := webview_zygote.cpp
|
||||
|
||||
LOCAL_CFLAGS := -Wall -Werror
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libandroid_runtime \
|
||||
libbinder \
|
||||
liblog \
|
||||
libcutils \
|
||||
libutils
|
||||
|
||||
LOCAL_LDFLAGS_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
|
||||
LOCAL_LDFLAGS_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
|
||||
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
|
||||
|
||||
LOCAL_INIT_RC := webview_zygote32.rc
|
||||
|
||||
# Always include the 32-bit version of webview_zygote. If the target is 64-bit,
|
||||
# also include the 64-bit webview_zygote.
|
||||
ifeq ($(TARGET_SUPPORTS_64_BIT_APPS),true)
|
||||
LOCAL_INIT_RC += webview_zygote64.rc
|
||||
endif
|
||||
|
||||
LOCAL_MULTILIB := both
|
||||
|
||||
LOCAL_MODULE_STEM_32 := webview_zygote32
|
||||
LOCAL_MODULE_STEM_64 := webview_zygote64
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#define LOG_TAG "WebViewZygote"
|
||||
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#include <android_runtime/AndroidRuntime.h>
|
||||
#include <binder/IPCThreadState.h>
|
||||
#include <binder/ProcessState.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class WebViewRuntime : public AndroidRuntime {
|
||||
public:
|
||||
WebViewRuntime(char* argBlockStart, size_t argBlockSize)
|
||||
: AndroidRuntime(argBlockStart, argBlockSize) {}
|
||||
|
||||
~WebViewRuntime() override {}
|
||||
|
||||
void onStarted() override {
|
||||
// Nothing to do since this is a zygote server.
|
||||
}
|
||||
|
||||
void onVmCreated(JNIEnv*) override {
|
||||
// Nothing to do when the VM is created in the zygote.
|
||||
}
|
||||
|
||||
void onZygoteInit() override {
|
||||
// Called after a new process is forked.
|
||||
sp<ProcessState> proc = ProcessState::self();
|
||||
proc->startThreadPool();
|
||||
}
|
||||
|
||||
void onExit(int code) override {
|
||||
IPCThreadState::self()->stopProcess();
|
||||
AndroidRuntime::onExit(code);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
int main(int argc, char* const argv[]) {
|
||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
|
||||
LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
|
||||
return 12;
|
||||
}
|
||||
|
||||
size_t argBlockSize = 0;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
argBlockSize += strlen(argv[i]) + 1;
|
||||
}
|
||||
|
||||
android::WebViewRuntime runtime(argv[0], argBlockSize);
|
||||
runtime.addOption("-Xzygote");
|
||||
|
||||
android::Vector<android::String8> args;
|
||||
runtime.start("com.android.internal.os.WebViewZygoteInit", args, /*zygote=*/ true);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
service webview_zygote32 /system/bin/webview_zygote32
|
||||
user webview_zygote
|
||||
socket webview_zygote stream 660 webview_zygote system
|
||||
|
||||
on property:init.svc.zygote=stopped
|
||||
stop webview_zygote32
|
||||
@@ -1,22 +0,0 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
service webview_zygote64 /system/bin/webview_zygote64
|
||||
user webview_zygote
|
||||
socket webview_zygote stream 660 webview_zygote system
|
||||
|
||||
on property:init.svc.zygote=stopped
|
||||
stop webview_zygote64
|
||||
@@ -20,29 +20,22 @@ import android.app.LoadedApk;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.os.Build;
|
||||
import android.os.SystemService;
|
||||
import android.os.ChildZygoteProcess;
|
||||
import android.os.Process;
|
||||
import android.os.ZygoteProcess;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AndroidRuntimeException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/** @hide */
|
||||
public class WebViewZygote {
|
||||
private static final String LOGTAG = "WebViewZygote";
|
||||
|
||||
private static final String WEBVIEW_ZYGOTE_SERVICE_32 = "webview_zygote32";
|
||||
private static final String WEBVIEW_ZYGOTE_SERVICE_64 = "webview_zygote64";
|
||||
private static final String WEBVIEW_ZYGOTE_SOCKET = "webview_zygote";
|
||||
|
||||
/**
|
||||
* Lock object that protects all other static members.
|
||||
*/
|
||||
@@ -53,14 +46,7 @@ public class WebViewZygote {
|
||||
* is not running or is not connected.
|
||||
*/
|
||||
@GuardedBy("sLock")
|
||||
private static ZygoteProcess sZygote;
|
||||
|
||||
/**
|
||||
* Variable that allows us to determine whether the WebView zygote Service has already been
|
||||
* started.
|
||||
*/
|
||||
@GuardedBy("sLock")
|
||||
private static boolean sStartedService = false;
|
||||
private static ChildZygoteProcess sZygote;
|
||||
|
||||
/**
|
||||
* Information about the selected WebView package. This is set from #onWebViewProviderChanged().
|
||||
@@ -86,7 +72,7 @@ public class WebViewZygote {
|
||||
synchronized (sLock) {
|
||||
if (sZygote != null) return sZygote;
|
||||
|
||||
waitForServiceStartAndConnect();
|
||||
connectToZygoteIfNeededLocked();
|
||||
return sZygote;
|
||||
}
|
||||
}
|
||||
@@ -108,21 +94,13 @@ public class WebViewZygote {
|
||||
sMultiprocessEnabled = enabled;
|
||||
|
||||
// When toggling between multi-process being on/off, start or stop the
|
||||
// service. If it is enabled and the zygote is not yet started, bring up the service.
|
||||
// Otherwise, bring down the service. The name may be null if the package
|
||||
// information has not yet been resolved.
|
||||
final String serviceName = getServiceNameLocked();
|
||||
if (serviceName == null) return;
|
||||
|
||||
// zygote. If it is enabled and the zygote is not yet started, launch it.
|
||||
// Otherwise, kill it. The name may be null if the package information has
|
||||
// not yet been resolved.
|
||||
if (enabled) {
|
||||
if (!sStartedService) {
|
||||
SystemService.start(serviceName);
|
||||
sStartedService = true;
|
||||
}
|
||||
connectToZygoteIfNeededLocked();
|
||||
} else {
|
||||
SystemService.stop(serviceName);
|
||||
sStartedService = false;
|
||||
sZygote = null;
|
||||
stopZygoteLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,53 +116,21 @@ public class WebViewZygote {
|
||||
return;
|
||||
}
|
||||
|
||||
final String serviceName = getServiceNameLocked();
|
||||
sZygote = null;
|
||||
|
||||
// The service may enter the RUNNING state before it opens the socket,
|
||||
// so connectToZygoteIfNeededLocked() may still fail.
|
||||
if (SystemService.isStopped(serviceName)) {
|
||||
SystemService.start(serviceName);
|
||||
} else {
|
||||
SystemService.restart(serviceName);
|
||||
}
|
||||
sStartedService = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void waitForServiceStartAndConnect() {
|
||||
if (!sStartedService) {
|
||||
throw new AndroidRuntimeException("Tried waiting for the WebView Zygote Service to " +
|
||||
"start running without first starting the service.");
|
||||
}
|
||||
|
||||
String serviceName;
|
||||
synchronized (sLock) {
|
||||
serviceName = getServiceNameLocked();
|
||||
}
|
||||
try {
|
||||
SystemService.waitForState(serviceName, SystemService.State.RUNNING, 5000);
|
||||
} catch (TimeoutException e) {
|
||||
Log.e(LOGTAG, "Timed out waiting for " + serviceName);
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (sLock) {
|
||||
connectToZygoteIfNeededLocked();
|
||||
stopZygoteLocked();
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("sLock")
|
||||
private static String getServiceNameLocked() {
|
||||
if (sPackage == null)
|
||||
return null;
|
||||
|
||||
if (Arrays.asList(Build.SUPPORTED_64_BIT_ABIS).contains(
|
||||
sPackage.applicationInfo.primaryCpuAbi)) {
|
||||
return WEBVIEW_ZYGOTE_SERVICE_64;
|
||||
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;
|
||||
}
|
||||
|
||||
return WEBVIEW_ZYGOTE_SERVICE_32;
|
||||
}
|
||||
|
||||
@GuardedBy("sLock")
|
||||
@@ -198,14 +144,17 @@ public class WebViewZygote {
|
||||
return;
|
||||
}
|
||||
|
||||
final String serviceName = getServiceNameLocked();
|
||||
if (!SystemService.isRunning(serviceName)) {
|
||||
Log.e(LOGTAG, serviceName + " is not running");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
sZygote = new ZygoteProcess(WEBVIEW_ZYGOTE_SOCKET, null);
|
||||
sZygote = Process.zygoteProcess.startChildZygote(
|
||||
"com.android.internal.os.WebViewZygoteInit",
|
||||
"webview_zygote",
|
||||
Process.WEBVIEW_ZYGOTE_UID,
|
||||
Process.WEBVIEW_ZYGOTE_UID,
|
||||
null, // gids
|
||||
0, // runtimeFlags
|
||||
"webview_zygote", // seInfo
|
||||
sPackage.applicationInfo.primaryCpuAbi, // abi
|
||||
null); // instructionSet
|
||||
|
||||
// All the work below is usually done by LoadedApk, but the zygote can't talk to
|
||||
// PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so
|
||||
@@ -227,14 +176,14 @@ public class WebViewZygote {
|
||||
final String cacheKey = (zipPaths.size() == 1) ? zipPaths.get(0) :
|
||||
TextUtils.join(File.pathSeparator, zipPaths);
|
||||
|
||||
ZygoteProcess.waitForConnectionToZygote(WEBVIEW_ZYGOTE_SOCKET);
|
||||
ZygoteProcess.waitForConnectionToZygote(sZygote.getPrimarySocketAddress());
|
||||
|
||||
Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
|
||||
sZygote.preloadPackageForAbi(zip, librarySearchPath, cacheKey,
|
||||
Build.SUPPORTED_ABIS[0]);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Error connecting to " + serviceName, e);
|
||||
sZygote = null;
|
||||
Log.e(LOGTAG, "Error connecting to webview zygote", e);
|
||||
stopZygoteLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ package com.android.internal.os;
|
||||
|
||||
import android.app.ApplicationLoaders;
|
||||
import android.net.LocalSocket;
|
||||
import android.net.LocalServerSocket;
|
||||
import android.os.Build;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebViewFactory;
|
||||
@@ -118,18 +120,35 @@ class WebViewZygoteInit {
|
||||
}
|
||||
|
||||
public static void main(String argv[]) {
|
||||
sServer = new WebViewZygoteServer();
|
||||
Log.i(TAG, "Starting WebViewZygoteInit");
|
||||
|
||||
// Zygote goes into its own process group.
|
||||
try {
|
||||
Os.setpgid(0, 0);
|
||||
} catch (ErrnoException ex) {
|
||||
throw new RuntimeException("Failed to setpgid(0,0)", ex);
|
||||
String socketName = null;
|
||||
for (String arg : argv) {
|
||||
Log.i(TAG, arg);
|
||||
if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
|
||||
socketName = arg.substring(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG.length());
|
||||
}
|
||||
}
|
||||
if (socketName == null) {
|
||||
throw new RuntimeException("No " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + " specified");
|
||||
}
|
||||
|
||||
try {
|
||||
Os.prctl(OsConstants.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
} catch (ErrnoException ex) {
|
||||
throw new RuntimeException("Failed to set PR_SET_NO_NEW_PRIVS", ex);
|
||||
}
|
||||
|
||||
sServer = new WebViewZygoteServer();
|
||||
|
||||
final Runnable caller;
|
||||
try {
|
||||
sServer.registerServerSocketFromEnv("webview_zygote");
|
||||
sServer.registerServerSocketAtAbstractName(socketName);
|
||||
|
||||
// Add the abstract socket to the FD whitelist so that the native zygote code
|
||||
// can properly detach it after forking.
|
||||
Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName);
|
||||
|
||||
// The select loop returns early in the child process after a fork and
|
||||
// loops forever in the zygote.
|
||||
caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS));
|
||||
|
||||
Reference in New Issue
Block a user