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.ApplicationInfo;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.SystemService;
|
import android.os.ChildZygoteProcess;
|
||||||
|
import android.os.Process;
|
||||||
import android.os.ZygoteProcess;
|
import android.os.ZygoteProcess;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.AndroidRuntimeException;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public class WebViewZygote {
|
public class WebViewZygote {
|
||||||
private static final String LOGTAG = "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.
|
* Lock object that protects all other static members.
|
||||||
*/
|
*/
|
||||||
@@ -53,14 +46,7 @@ public class WebViewZygote {
|
|||||||
* is not running or is not connected.
|
* is not running or is not connected.
|
||||||
*/
|
*/
|
||||||
@GuardedBy("sLock")
|
@GuardedBy("sLock")
|
||||||
private static ZygoteProcess sZygote;
|
private static ChildZygoteProcess sZygote;
|
||||||
|
|
||||||
/**
|
|
||||||
* Variable that allows us to determine whether the WebView zygote Service has already been
|
|
||||||
* started.
|
|
||||||
*/
|
|
||||||
@GuardedBy("sLock")
|
|
||||||
private static boolean sStartedService = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about the selected WebView package. This is set from #onWebViewProviderChanged().
|
* Information about the selected WebView package. This is set from #onWebViewProviderChanged().
|
||||||
@@ -86,7 +72,7 @@ public class WebViewZygote {
|
|||||||
synchronized (sLock) {
|
synchronized (sLock) {
|
||||||
if (sZygote != null) return sZygote;
|
if (sZygote != null) return sZygote;
|
||||||
|
|
||||||
waitForServiceStartAndConnect();
|
connectToZygoteIfNeededLocked();
|
||||||
return sZygote;
|
return sZygote;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,21 +94,13 @@ public class WebViewZygote {
|
|||||||
sMultiprocessEnabled = enabled;
|
sMultiprocessEnabled = enabled;
|
||||||
|
|
||||||
// When toggling between multi-process being on/off, start or stop the
|
// 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.
|
// zygote. If it is enabled and the zygote is not yet started, launch it.
|
||||||
// Otherwise, bring down the service. The name may be null if the package
|
// Otherwise, kill it. The name may be null if the package information has
|
||||||
// information has not yet been resolved.
|
// not yet been resolved.
|
||||||
final String serviceName = getServiceNameLocked();
|
|
||||||
if (serviceName == null) return;
|
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (!sStartedService) {
|
connectToZygoteIfNeededLocked();
|
||||||
SystemService.start(serviceName);
|
|
||||||
sStartedService = true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
SystemService.stop(serviceName);
|
stopZygoteLocked();
|
||||||
sStartedService = false;
|
|
||||||
sZygote = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,53 +116,21 @@ public class WebViewZygote {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String serviceName = getServiceNameLocked();
|
stopZygoteLocked();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy("sLock")
|
@GuardedBy("sLock")
|
||||||
private static String getServiceNameLocked() {
|
private static void stopZygoteLocked() {
|
||||||
if (sPackage == null)
|
if (sZygote != null) {
|
||||||
return 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
|
||||||
if (Arrays.asList(Build.SUPPORTED_64_BIT_ABIS).contains(
|
// setMultiprocessEnabled() or onWebViewProviderChanged(), the WebViewUpdater
|
||||||
sPackage.applicationInfo.primaryCpuAbi)) {
|
// will kill all processes that depend on the WebView package.
|
||||||
return WEBVIEW_ZYGOTE_SERVICE_64;
|
sZygote.close();
|
||||||
|
Process.killProcess(sZygote.getPid());
|
||||||
|
sZygote = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return WEBVIEW_ZYGOTE_SERVICE_32;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy("sLock")
|
@GuardedBy("sLock")
|
||||||
@@ -198,14 +144,17 @@ public class WebViewZygote {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String serviceName = getServiceNameLocked();
|
|
||||||
if (!SystemService.isRunning(serviceName)) {
|
|
||||||
Log.e(LOGTAG, serviceName + " is not running");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
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
|
// 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
|
// 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) :
|
final String cacheKey = (zipPaths.size() == 1) ? zipPaths.get(0) :
|
||||||
TextUtils.join(File.pathSeparator, zipPaths);
|
TextUtils.join(File.pathSeparator, zipPaths);
|
||||||
|
|
||||||
ZygoteProcess.waitForConnectionToZygote(WEBVIEW_ZYGOTE_SOCKET);
|
ZygoteProcess.waitForConnectionToZygote(sZygote.getPrimarySocketAddress());
|
||||||
|
|
||||||
Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
|
Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
|
||||||
sZygote.preloadPackageForAbi(zip, librarySearchPath, cacheKey,
|
sZygote.preloadPackageForAbi(zip, librarySearchPath, cacheKey,
|
||||||
Build.SUPPORTED_ABIS[0]);
|
Build.SUPPORTED_ABIS[0]);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(LOGTAG, "Error connecting to " + serviceName, e);
|
Log.e(LOGTAG, "Error connecting to webview zygote", e);
|
||||||
sZygote = null;
|
stopZygoteLocked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ package com.android.internal.os;
|
|||||||
|
|
||||||
import android.app.ApplicationLoaders;
|
import android.app.ApplicationLoaders;
|
||||||
import android.net.LocalSocket;
|
import android.net.LocalSocket;
|
||||||
|
import android.net.LocalServerSocket;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
|
import android.system.OsConstants;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.webkit.WebViewFactory;
|
import android.webkit.WebViewFactory;
|
||||||
@@ -118,18 +120,35 @@ class WebViewZygoteInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String argv[]) {
|
public static void main(String argv[]) {
|
||||||
sServer = new WebViewZygoteServer();
|
Log.i(TAG, "Starting WebViewZygoteInit");
|
||||||
|
|
||||||
// Zygote goes into its own process group.
|
String socketName = null;
|
||||||
try {
|
for (String arg : argv) {
|
||||||
Os.setpgid(0, 0);
|
Log.i(TAG, arg);
|
||||||
} catch (ErrnoException ex) {
|
if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
|
||||||
throw new RuntimeException("Failed to setpgid(0,0)", ex);
|
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;
|
final Runnable caller;
|
||||||
try {
|
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
|
// The select loop returns early in the child process after a fork and
|
||||||
// loops forever in the zygote.
|
// loops forever in the zygote.
|
||||||
caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS));
|
caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS));
|
||||||
|
|||||||
Reference in New Issue
Block a user