Merge "Create the WebViewZygote and implement WebViewZygoteInit." am: 8be2850546
am: f80fab010a
Change-Id: I37d0d62662ee96a9eefe2dfa71670d8e4b724889
This commit is contained in:
49
cmds/webview_zygote/Android.mk
Normal file
49
cmds/webview_zygote/Android.mk
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#
|
||||||
|
# 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_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)
|
76
cmds/webview_zygote/webview_zygote.cpp
Normal file
76
cmds/webview_zygote/webview_zygote.cpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
22
cmds/webview_zygote/webview_zygote32.rc
Normal file
22
cmds/webview_zygote/webview_zygote32.rc
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#
|
||||||
|
# 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
|
22
cmds/webview_zygote/webview_zygote64.rc
Normal file
22
cmds/webview_zygote/webview_zygote64.rc
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#
|
||||||
|
# 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,6 +20,7 @@ import android.annotation.TestApi;
|
|||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.system.OsConstants;
|
import android.system.OsConstants;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.webkit.WebViewZygote;
|
||||||
import dalvik.system.VMRuntime;
|
import dalvik.system.VMRuntime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -132,6 +133,12 @@ public class Process {
|
|||||||
*/
|
*/
|
||||||
public static final int CAMERASERVER_UID = 1047;
|
public static final int CAMERASERVER_UID = 1047;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the UID/GID for the WebView zygote process.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static final int WEBVIEW_ZYGOTE_UID = 1051;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the start of a range of UIDs (and GIDs), going from this
|
* Defines the start of a range of UIDs (and GIDs), going from this
|
||||||
* number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
|
* number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
|
||||||
@ -425,6 +432,22 @@ public class Process {
|
|||||||
abi, instructionSet, appDataDir, zygoteArgs);
|
abi, instructionSet, appDataDir, zygoteArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
public static final ProcessStartResult startWebView(final String processClass,
|
||||||
|
final String niceName,
|
||||||
|
int uid, int gid, int[] gids,
|
||||||
|
int debugFlags, int mountExternal,
|
||||||
|
int targetSdkVersion,
|
||||||
|
String seInfo,
|
||||||
|
String abi,
|
||||||
|
String instructionSet,
|
||||||
|
String appDataDir,
|
||||||
|
String[] zygoteArgs) {
|
||||||
|
return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,
|
||||||
|
debugFlags, mountExternal, targetSdkVersion, seInfo,
|
||||||
|
abi, instructionSet, appDataDir, zygoteArgs);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns elapsed milliseconds of the time this process has run.
|
* Returns elapsed milliseconds of the time this process has run.
|
||||||
* @return Returns the number of milliseconds this process has return.
|
* @return Returns the number of milliseconds this process has return.
|
||||||
|
@ -19,7 +19,9 @@ package android.os;
|
|||||||
import android.net.LocalSocket;
|
import android.net.LocalSocket;
|
||||||
import android.net.LocalSocketAddress;
|
import android.net.LocalSocketAddress;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.os.Zygote;
|
import com.android.internal.os.Zygote;
|
||||||
|
import com.android.internal.util.Preconditions;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -110,7 +112,8 @@ public class ZygoteProcess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
|
String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
|
||||||
Log.i("Zygote", "Process: zygote socket opened, supported ABIS: " + abiListString);
|
Log.i("Zygote", "Process: zygote socket " + socketAddress + " opened, supported ABIS: "
|
||||||
|
+ abiListString);
|
||||||
|
|
||||||
return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
|
return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
|
||||||
Arrays.asList(abiListString.split(",")));
|
Arrays.asList(abiListString.split(",")));
|
||||||
@ -135,6 +138,13 @@ public class ZygoteProcess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock object to protect access to the two ZygoteStates below. This lock must be
|
||||||
|
* acquired while communicating over the ZygoteState's socket, to prevent
|
||||||
|
* interleaved access.
|
||||||
|
*/
|
||||||
|
private final Object mLock = new Object();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The state of the connection to the primary zygote.
|
* The state of the connection to the primary zygote.
|
||||||
*/
|
*/
|
||||||
@ -207,6 +217,7 @@ public class ZygoteProcess {
|
|||||||
*
|
*
|
||||||
* @throws ZygoteStartFailedEx if the query failed.
|
* @throws ZygoteStartFailedEx if the query failed.
|
||||||
*/
|
*/
|
||||||
|
@GuardedBy("mLock")
|
||||||
private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
|
private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
// Each query starts with the argument count (1 in this case)
|
// Each query starts with the argument count (1 in this case)
|
||||||
@ -233,6 +244,7 @@ public class ZygoteProcess {
|
|||||||
*
|
*
|
||||||
* @throws ZygoteStartFailedEx if process start failed for any reason
|
* @throws ZygoteStartFailedEx if process start failed for any reason
|
||||||
*/
|
*/
|
||||||
|
@GuardedBy("mLock")
|
||||||
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
|
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
|
||||||
ZygoteState zygoteState, ArrayList<String> args)
|
ZygoteState zygoteState, ArrayList<String> args)
|
||||||
throws ZygoteStartFailedEx {
|
throws ZygoteStartFailedEx {
|
||||||
@ -320,7 +332,6 @@ public class ZygoteProcess {
|
|||||||
String appDataDir,
|
String appDataDir,
|
||||||
String[] extraArgs)
|
String[] extraArgs)
|
||||||
throws ZygoteStartFailedEx {
|
throws ZygoteStartFailedEx {
|
||||||
synchronized(Process.class) {
|
|
||||||
ArrayList<String> argsForZygote = new ArrayList<String>();
|
ArrayList<String> argsForZygote = new ArrayList<String>();
|
||||||
|
|
||||||
// --runtime-args, --setuid=, --setgid=,
|
// --runtime-args, --setuid=, --setgid=,
|
||||||
@ -404,6 +415,7 @@ public class ZygoteProcess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
synchronized(mLock) {
|
||||||
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
|
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -415,7 +427,9 @@ public class ZygoteProcess {
|
|||||||
*/
|
*/
|
||||||
public void establishZygoteConnectionForAbi(String abi) {
|
public void establishZygoteConnectionForAbi(String abi) {
|
||||||
try {
|
try {
|
||||||
|
synchronized(mLock) {
|
||||||
openZygoteSocketIfNeeded(abi);
|
openZygoteSocketIfNeeded(abi);
|
||||||
|
}
|
||||||
} catch (ZygoteStartFailedEx ex) {
|
} catch (ZygoteStartFailedEx ex) {
|
||||||
throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
|
throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
|
||||||
}
|
}
|
||||||
@ -423,9 +437,12 @@ public class ZygoteProcess {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to open socket to Zygote process if not already open. If
|
* Tries to open socket to Zygote process if not already open. If
|
||||||
* already open, does nothing. May block and retry.
|
* already open, does nothing. May block and retry. Requires that mLock be held.
|
||||||
*/
|
*/
|
||||||
|
@GuardedBy("mLock")
|
||||||
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
|
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
|
||||||
|
Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
|
||||||
|
|
||||||
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
|
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
|
||||||
try {
|
try {
|
||||||
primaryZygoteState = ZygoteState.connect(mSocket);
|
primaryZygoteState = ZygoteState.connect(mSocket);
|
||||||
@ -453,4 +470,28 @@ public class ZygoteProcess {
|
|||||||
|
|
||||||
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
|
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructs the zygote to pre-load the classes and native libraries at the given paths
|
||||||
|
* for the specified abi. Not all zygotes support this function.
|
||||||
|
*/
|
||||||
|
public void preloadPackageForAbi(String packagePath, String libsPath, String abi)
|
||||||
|
throws ZygoteStartFailedEx, IOException {
|
||||||
|
synchronized(mLock) {
|
||||||
|
ZygoteState state = openZygoteSocketIfNeeded(abi);
|
||||||
|
state.writer.write("3");
|
||||||
|
state.writer.newLine();
|
||||||
|
|
||||||
|
state.writer.write("--preload-package");
|
||||||
|
state.writer.newLine();
|
||||||
|
|
||||||
|
state.writer.write(packagePath);
|
||||||
|
state.writer.newLine();
|
||||||
|
|
||||||
|
state.writer.write(libsPath);
|
||||||
|
state.writer.newLine();
|
||||||
|
|
||||||
|
state.writer.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -472,6 +472,9 @@ public final class WebViewFactory {
|
|||||||
// Log and discard errors at this stage as we must not crash the system server.
|
// Log and discard errors at this stage as we must not crash the system server.
|
||||||
Log.e(LOGTAG, "error preparing webview native library", t);
|
Log.e(LOGTAG, "error preparing webview native library", t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WebViewZygote.onWebViewProviderChanged(packageInfo);
|
||||||
|
|
||||||
return prepareWebViewInSystemServer(nativeLibs);
|
return prepareWebViewInSystemServer(nativeLibs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
135
core/java/android/webkit/WebViewZygote.java
Normal file
135
core/java/android/webkit/WebViewZygote.java
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.content.pm.PackageInfo;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.SystemService;
|
||||||
|
import android.os.ZygoteProcess;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
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 ZygoteProcess sZygote;
|
||||||
|
|
||||||
|
private static PackageInfo sPackage;
|
||||||
|
|
||||||
|
private static boolean sMultiprocessEnabled = false;
|
||||||
|
|
||||||
|
public static ZygoteProcess getProcess() {
|
||||||
|
connectToZygoteIfNeeded();
|
||||||
|
return sZygote;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPackageName() {
|
||||||
|
return sPackage.packageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setMultiprocessEnabled(boolean enabled) {
|
||||||
|
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 = getServiceName();
|
||||||
|
if (serviceName == null) return;
|
||||||
|
|
||||||
|
if (enabled && sZygote == null) {
|
||||||
|
SystemService.start(serviceName);
|
||||||
|
} else {
|
||||||
|
SystemService.stop(serviceName);
|
||||||
|
sZygote = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onWebViewProviderChanged(PackageInfo packageInfo) {
|
||||||
|
sPackage = packageInfo;
|
||||||
|
|
||||||
|
// If multi-process is not enabled, then do not start the zygote service.
|
||||||
|
if (!sMultiprocessEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String serviceName = getServiceName();
|
||||||
|
|
||||||
|
if (SystemService.isStopped(serviceName)) {
|
||||||
|
SystemService.start(serviceName);
|
||||||
|
} else if (sZygote != null) {
|
||||||
|
SystemService.restart(serviceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
SystemService.waitForState(serviceName, SystemService.State.RUNNING, 5000);
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
Log.e(LOGTAG, "Timed out waiting for " + serviceName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectToZygoteIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getServiceName() {
|
||||||
|
if (sPackage == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (Arrays.asList(Build.SUPPORTED_64_BIT_ABIS).contains(
|
||||||
|
sPackage.applicationInfo.primaryCpuAbi)) {
|
||||||
|
return WEBVIEW_ZYGOTE_SERVICE_64;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WEBVIEW_ZYGOTE_SERVICE_32;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void connectToZygoteIfNeeded() {
|
||||||
|
if (sZygote != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sPackage == null) {
|
||||||
|
Log.e(LOGTAG, "Cannot connect to zygote, no package specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String serviceName = getServiceName();
|
||||||
|
if (!SystemService.isRunning(serviceName)) {
|
||||||
|
Log.e(LOGTAG, serviceName + " is not running");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
sZygote = new ZygoteProcess("webview_zygote", null);
|
||||||
|
|
||||||
|
String packagePath = sPackage.applicationInfo.sourceDir;
|
||||||
|
String libsPath = sPackage.applicationInfo.nativeLibraryDir;
|
||||||
|
|
||||||
|
Log.d(LOGTAG, "Preloading package " + packagePath + " " + libsPath);
|
||||||
|
sZygote.preloadPackageForAbi(packagePath, libsPath, Build.SUPPORTED_ABIS[0]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(LOGTAG, "Error connecting to " + serviceName, e);
|
||||||
|
sZygote = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,15 @@
|
|||||||
|
|
||||||
package com.android.internal.os;
|
package com.android.internal.os;
|
||||||
|
|
||||||
|
import android.net.LocalSocket;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.system.ErrnoException;
|
||||||
|
import android.system.Os;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Startup class for the WebView zygote process.
|
* Startup class for the WebView zygote process.
|
||||||
*
|
*
|
||||||
@ -26,7 +35,48 @@ package com.android.internal.os;
|
|||||||
class WebViewZygoteInit {
|
class WebViewZygoteInit {
|
||||||
public static final String TAG = "WebViewZygoteInit";
|
public static final String TAG = "WebViewZygoteInit";
|
||||||
|
|
||||||
|
private static ZygoteServer sServer;
|
||||||
|
|
||||||
|
private static class WebViewZygoteServer extends ZygoteServer {
|
||||||
|
@Override
|
||||||
|
protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
|
||||||
|
throws IOException {
|
||||||
|
return new WebViewZygoteConnection(socket, abiList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class WebViewZygoteConnection extends ZygoteConnection {
|
||||||
|
WebViewZygoteConnection(LocalSocket socket, String abiList) throws IOException {
|
||||||
|
super(socket, abiList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean handlePreloadPackage(String packagePath, String libsPath) {
|
||||||
|
// TODO: Use preload information to setup the ClassLoader.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String argv[]) {
|
public static void main(String argv[]) {
|
||||||
throw new RuntimeException("Not implemented yet");
|
sServer = new WebViewZygoteServer();
|
||||||
|
|
||||||
|
// Zygote goes into its own process group.
|
||||||
|
try {
|
||||||
|
Os.setpgid(0, 0);
|
||||||
|
} catch (ErrnoException ex) {
|
||||||
|
throw new RuntimeException("Failed to setpgid(0,0)", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
sServer.registerServerSocket("webview_zygote");
|
||||||
|
sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS));
|
||||||
|
sServer.closeServerSocket();
|
||||||
|
} catch (Zygote.MethodAndArgsCaller caller) {
|
||||||
|
caller.run();
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.e(TAG, "Fatal exception:", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ import java.io.InputStreamReader;
|
|||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import libcore.io.IoUtils;
|
import libcore.io.IoUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,6 +170,11 @@ class ZygoteConnection {
|
|||||||
return handleAbiListQuery();
|
return handleAbiListQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parsedArgs.preloadPackage != null) {
|
||||||
|
return handlePreloadPackage(parsedArgs.preloadPackage,
|
||||||
|
parsedArgs.preloadPackageLibs);
|
||||||
|
}
|
||||||
|
|
||||||
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
|
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
|
||||||
throw new ZygoteSecurityException("Client may not specify capabilities: " +
|
throw new ZygoteSecurityException("Client may not specify capabilities: " +
|
||||||
"permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
|
"permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
|
||||||
@ -270,6 +276,10 @@ class ZygoteConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean handlePreloadPackage(String packagePath, String libsPath) {
|
||||||
|
throw new RuntimeException("Zyogte does not support package preloading");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes socket associated with this connection.
|
* Closes socket associated with this connection.
|
||||||
*/
|
*/
|
||||||
@ -374,6 +384,12 @@ class ZygoteConnection {
|
|||||||
*/
|
*/
|
||||||
String appDataDir;
|
String appDataDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to preload a package, with the package path in the remainingArgs.
|
||||||
|
*/
|
||||||
|
String preloadPackage;
|
||||||
|
String preloadPackageLibs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs instance and parses args
|
* Constructs instance and parses args
|
||||||
* @param args zygote command-line args
|
* @param args zygote command-line args
|
||||||
@ -532,6 +548,9 @@ class ZygoteConnection {
|
|||||||
instructionSet = arg.substring(arg.indexOf('=') + 1);
|
instructionSet = arg.substring(arg.indexOf('=') + 1);
|
||||||
} else if (arg.startsWith("--app-data-dir=")) {
|
} else if (arg.startsWith("--app-data-dir=")) {
|
||||||
appDataDir = arg.substring(arg.indexOf('=') + 1);
|
appDataDir = arg.substring(arg.indexOf('=') + 1);
|
||||||
|
} else if (arg.equals("--preload-package")) {
|
||||||
|
preloadPackage = args[++curArg];
|
||||||
|
preloadPackageLibs = args[++curArg];
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -541,6 +560,11 @@ class ZygoteConnection {
|
|||||||
if (args.length - curArg > 0) {
|
if (args.length - curArg > 0) {
|
||||||
throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
|
throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
|
||||||
}
|
}
|
||||||
|
} else if (preloadPackage != null) {
|
||||||
|
if (args.length - curArg > 0) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Unexpected arguments after --preload-package.");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!seenRuntimeArgs) {
|
if (!seenRuntimeArgs) {
|
||||||
throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
|
throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
|
||||||
|
@ -19,6 +19,7 @@ package com.android.internal.os;
|
|||||||
import static android.system.OsConstants.POLLIN;
|
import static android.system.OsConstants.POLLIN;
|
||||||
|
|
||||||
import android.net.LocalServerSocket;
|
import android.net.LocalServerSocket;
|
||||||
|
import android.net.LocalSocket;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.StructPollfd;
|
import android.system.StructPollfd;
|
||||||
@ -80,13 +81,18 @@ class ZygoteServer {
|
|||||||
*/
|
*/
|
||||||
private ZygoteConnection acceptCommandPeer(String abiList) {
|
private ZygoteConnection acceptCommandPeer(String abiList) {
|
||||||
try {
|
try {
|
||||||
return new ZygoteConnection(mServerSocket.accept(), abiList);
|
return createNewConnection(mServerSocket.accept(), abiList);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"IOException during accept()", ex);
|
"IOException during accept()", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
|
||||||
|
throws IOException {
|
||||||
|
return new ZygoteConnection(socket, abiList);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close and clean up zygote sockets. Called on shutdown and on the
|
* Close and clean up zygote sockets. Called on shutdown and on the
|
||||||
* child's exit path.
|
* child's exit path.
|
||||||
|
@ -36,6 +36,7 @@ import android.util.AndroidRuntimeException;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.webkit.WebViewFactory;
|
import android.webkit.WebViewFactory;
|
||||||
import android.webkit.WebViewProviderInfo;
|
import android.webkit.WebViewProviderInfo;
|
||||||
|
import android.webkit.WebViewZygote;
|
||||||
|
|
||||||
import com.android.internal.util.XmlUtils;
|
import com.android.internal.util.XmlUtils;
|
||||||
|
|
||||||
@ -268,6 +269,11 @@ public class SystemImpl implements SystemInterface {
|
|||||||
return pm.getPackageInfo(configInfo.packageName, PACKAGE_FLAGS);
|
return pm.getPackageInfo(configInfo.packageName, PACKAGE_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMultiprocessEnabled(boolean enabled) {
|
||||||
|
WebViewZygote.setMultiprocessEnabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
// flags declaring we want extra info from the package manager for webview providers
|
// flags declaring we want extra info from the package manager for webview providers
|
||||||
private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
|
private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
|
||||||
| PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
|
| PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
|
||||||
|
@ -48,4 +48,6 @@ public interface SystemInterface {
|
|||||||
public boolean systemIsDebuggable();
|
public boolean systemIsDebuggable();
|
||||||
public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
|
public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
|
||||||
throws NameNotFoundException;
|
throws NameNotFoundException;
|
||||||
|
|
||||||
|
public void setMultiprocessEnabled(boolean enabled);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,12 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.content.pm.Signature;
|
import android.content.pm.Signature;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.database.ContentObserver;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
import android.provider.Settings;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.webkit.WebViewFactory;
|
import android.webkit.WebViewFactory;
|
||||||
@ -42,6 +47,7 @@ public class WebViewUpdateServiceImpl {
|
|||||||
|
|
||||||
private SystemInterface mSystemInterface;
|
private SystemInterface mSystemInterface;
|
||||||
private WebViewUpdater mWebViewUpdater;
|
private WebViewUpdater mWebViewUpdater;
|
||||||
|
private SettingsObserver mSettingsObserver;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
public WebViewUpdateServiceImpl(Context context, SystemInterface systemInterface) {
|
public WebViewUpdateServiceImpl(Context context, SystemInterface systemInterface) {
|
||||||
@ -61,6 +67,10 @@ public class WebViewUpdateServiceImpl {
|
|||||||
void prepareWebViewInSystemServer() {
|
void prepareWebViewInSystemServer() {
|
||||||
updateFallbackStateOnBoot();
|
updateFallbackStateOnBoot();
|
||||||
mWebViewUpdater.prepareWebViewInSystemServer();
|
mWebViewUpdater.prepareWebViewInSystemServer();
|
||||||
|
|
||||||
|
// Register for changes in the multiprocess developer option. This has to be done
|
||||||
|
// here, since the update service gets created before the ContentResolver service.
|
||||||
|
mSettingsObserver = new SettingsObserver();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
|
private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
|
||||||
@ -667,4 +677,41 @@ public class WebViewUpdateServiceImpl {
|
|||||||
& ApplicationInfo.PRIVATE_FLAG_HIDDEN) == 0));
|
& ApplicationInfo.PRIVATE_FLAG_HIDDEN) == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Watches for changes in the WEBVIEW_MULTIPROCESS setting and lets
|
||||||
|
* the WebViewZygote know, so it can start or stop the zygote process
|
||||||
|
* appropriately.
|
||||||
|
*/
|
||||||
|
private class SettingsObserver extends ContentObserver {
|
||||||
|
private final ContentResolver mResolver;
|
||||||
|
|
||||||
|
SettingsObserver() {
|
||||||
|
super(new Handler());
|
||||||
|
|
||||||
|
mResolver = mContext.getContentResolver();
|
||||||
|
mResolver.registerContentObserver(
|
||||||
|
Settings.Global.getUriFor(Settings.Global.WEBVIEW_MULTIPROCESS),
|
||||||
|
false, this);
|
||||||
|
|
||||||
|
// Push the current value of the setting immediately.
|
||||||
|
notifyZygote();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChange(boolean selfChange, Uri uri) {
|
||||||
|
notifyZygote();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyZygote() {
|
||||||
|
boolean enableMultiprocess = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
enableMultiprocess = Settings.Global.getInt(mResolver,
|
||||||
|
Settings.Global.WEBVIEW_MULTIPROCESS) == 1;
|
||||||
|
} catch (Settings.SettingNotFoundException ex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
mSystemInterface.setMultiprocessEnabled(enableMultiprocess);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,4 +113,7 @@ public class TestSystemImpl implements SystemInterface {
|
|||||||
public int getFactoryPackageVersion(String packageName) {
|
public int getFactoryPackageVersion(String packageName) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMultiprocessEnabled(boolean enabled) {}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user