Use the WebView's loader library to load the real library.
Load libwebviewchromiumloader and use it to load the real WebView library, to enable sharing of the relro segment between different application processes without requiring that the library be preloaded in the zygote. A system service is added to track whether the relro segment file has been prepared, and block loading of the library until it has been. Bug: 13005501 Change-Id: I846b37c7b8e2a4eb8a39e4fd455bccbb2048c173
This commit is contained in:
@@ -241,6 +241,7 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/view/IWindowManager.aidl \
|
||||
core/java/android/view/IWindowSession.aidl \
|
||||
core/java/android/view/IWindowSessionCallback.aidl \
|
||||
core/java/android/webkit/IWebViewUpdateService.aidl \
|
||||
core/java/android/speech/IRecognitionListener.aidl \
|
||||
core/java/android/speech/IRecognitionService.aidl \
|
||||
core/java/android/speech/tts/ITextToSpeechCallback.aidl \
|
||||
|
||||
@@ -130,6 +130,12 @@ public class Process {
|
||||
*/
|
||||
public static final int PACKAGE_INFO_GID = 1032;
|
||||
|
||||
/**
|
||||
* Defines the UID/GID for the shared RELRO file updater process.
|
||||
* @hide
|
||||
*/
|
||||
public static final int SHARED_RELRO_UID = 1037;
|
||||
|
||||
/**
|
||||
* Defines the start of a range of UIDs (and GIDs), going from this
|
||||
* number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
|
||||
|
||||
36
core/java/android/webkit/IWebViewUpdateService.aidl
Normal file
36
core/java/android/webkit/IWebViewUpdateService.aidl
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
/**
|
||||
* Private service to wait for the updatable WebView to be ready for use.
|
||||
* @hide
|
||||
*/
|
||||
interface IWebViewUpdateService {
|
||||
|
||||
/**
|
||||
* Used by the relro file creator to notify the service that it's done.
|
||||
*/
|
||||
void notifyRelroCreationCompleted(boolean is64Bit, boolean success);
|
||||
|
||||
/**
|
||||
* Used by WebViewFactory to block loading of WebView code until
|
||||
* preparations are complete.
|
||||
*/
|
||||
void waitForRelroCreationCompleted(boolean is64Bit);
|
||||
|
||||
}
|
||||
@@ -16,9 +16,18 @@
|
||||
|
||||
package android.webkit;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.StrictMode;
|
||||
import android.util.AndroidRuntimeException;
|
||||
import android.util.Log;
|
||||
import dalvik.system.VMRuntime;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.android.internal.os.Zygote;
|
||||
|
||||
/**
|
||||
* Top level factory, used creating all the main WebView implementation classes.
|
||||
@@ -33,6 +42,17 @@ public final class WebViewFactory {
|
||||
private static final String NULL_WEBVIEW_FACTORY =
|
||||
"com.android.webview.nullwebview.NullWebViewFactoryProvider";
|
||||
|
||||
// TODO(torne): we need to use a system property instead of hardcoding the library paths to
|
||||
// enable it to be changed when a webview update apk is installed.
|
||||
private static final String CHROMIUM_WEBVIEW_NATIVE_LIB_32 =
|
||||
"/system/lib/libwebviewchromium.so";
|
||||
private static final String CHROMIUM_WEBVIEW_NATIVE_LIB_64 =
|
||||
"/system/lib64/libwebviewchromium.so";
|
||||
private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_32 =
|
||||
"/data/misc/shared_relro/libwebviewchromium32.relro";
|
||||
private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 =
|
||||
"/data/misc/shared_relro/libwebviewchromium64.relro";
|
||||
|
||||
private static final String LOGTAG = "WebViewFactory";
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
@@ -41,6 +61,7 @@ public final class WebViewFactory {
|
||||
// same provider.
|
||||
private static WebViewFactoryProvider sProviderInstance;
|
||||
private static final Object sProviderLock = new Object();
|
||||
private static boolean sAddressSpaceReserved = false;
|
||||
|
||||
static WebViewFactoryProvider getProvider() {
|
||||
synchronized (sProviderLock) {
|
||||
@@ -48,6 +69,8 @@ public final class WebViewFactory {
|
||||
// us honest and minimize usage of WebView internals when binding the proxy.
|
||||
if (sProviderInstance != null) return sProviderInstance;
|
||||
|
||||
loadNativeLibrary();
|
||||
|
||||
Class<WebViewFactoryProvider> providerClass;
|
||||
try {
|
||||
providerClass = getFactoryClass();
|
||||
@@ -78,4 +101,121 @@ public final class WebViewFactory {
|
||||
return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any WebView loading preparations that must happen in the zygote.
|
||||
* Currently, this means allocating address space to load the real JNI library later.
|
||||
*/
|
||||
public static void prepareWebViewInZygote() {
|
||||
try {
|
||||
System.loadLibrary("webviewchromium_loader");
|
||||
sAddressSpaceReserved = nativeReserveAddressSpace(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
|
||||
CHROMIUM_WEBVIEW_NATIVE_LIB_64);
|
||||
if (sAddressSpaceReserved) {
|
||||
if (DEBUG) Log.v(LOGTAG, "address space reserved");
|
||||
} else {
|
||||
Log.e(LOGTAG, "reserving address space failed");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Log and discard errors at this stage as we must not crash the zygote.
|
||||
Log.e(LOGTAG, "error preparing native loader", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any WebView loading preparations that must happen at boot from the system server,
|
||||
* after the package manager has started.
|
||||
* This must be called in the system server.
|
||||
* Currently, this means spawning the child processes which will create the relro files.
|
||||
*/
|
||||
public static void prepareWebViewInSystemServer() {
|
||||
if (DEBUG) Log.v(LOGTAG, "creating relro files");
|
||||
if (new File(CHROMIUM_WEBVIEW_NATIVE_LIB_64).exists()) {
|
||||
createRelroFile(Build.SUPPORTED_64_BIT_ABIS[0]);
|
||||
}
|
||||
if (new File(CHROMIUM_WEBVIEW_NATIVE_LIB_32).exists()) {
|
||||
createRelroFile(Build.SUPPORTED_32_BIT_ABIS[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private static void createRelroFile(String abi) {
|
||||
try {
|
||||
Process.start("android.webkit.WebViewFactory$RelroFileCreator",
|
||||
"WebViewLoader-" + abi,
|
||||
Process.SHARED_RELRO_UID,
|
||||
Process.SHARED_RELRO_UID,
|
||||
null,
|
||||
0, // TODO(torne): do we need to set debug flags?
|
||||
Zygote.MOUNT_EXTERNAL_NONE,
|
||||
Build.VERSION.SDK_INT,
|
||||
null,
|
||||
abi,
|
||||
null);
|
||||
} catch (Throwable e) {
|
||||
// Log and discard errors as we must not crash the system server.
|
||||
Log.e(LOGTAG, "error starting relro file creator for abi " + abi, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class RelroFileCreator {
|
||||
// Called in an unprivileged child process to create the relro file.
|
||||
public static void main(String[] args) {
|
||||
if (!sAddressSpaceReserved) {
|
||||
Log.e(LOGTAG, "can't create relro file; address space not reserved");
|
||||
return;
|
||||
}
|
||||
boolean result = nativeCreateRelroFile(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
|
||||
CHROMIUM_WEBVIEW_NATIVE_LIB_64,
|
||||
CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
|
||||
CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
|
||||
if (!result) {
|
||||
Log.e(LOGTAG, "failed to create relro file");
|
||||
} else if (DEBUG) {
|
||||
Log.v(LOGTAG, "created relro file");
|
||||
}
|
||||
try {
|
||||
getUpdateService().notifyRelroCreationCompleted(VMRuntime.getRuntime().is64Bit(),
|
||||
result);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(LOGTAG, "error notifying update service", e);
|
||||
}
|
||||
|
||||
// Must explicitly exit or else this process will just sit around after we return.
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadNativeLibrary() {
|
||||
if (!sAddressSpaceReserved) {
|
||||
Log.e(LOGTAG, "can't load with relro file; address space not reserved");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
getUpdateService().waitForRelroCreationCompleted(VMRuntime.getRuntime().is64Bit());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(LOGTAG, "error waiting for relro creation, proceeding without", e);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean result = nativeLoadWithRelroFile(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
|
||||
CHROMIUM_WEBVIEW_NATIVE_LIB_64,
|
||||
CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
|
||||
CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
|
||||
if (!result) {
|
||||
Log.w(LOGTAG, "failed to load with relro file, proceeding without");
|
||||
} else if (DEBUG) {
|
||||
Log.v(LOGTAG, "loaded with relro file");
|
||||
}
|
||||
}
|
||||
|
||||
private static IWebViewUpdateService getUpdateService() {
|
||||
return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
|
||||
}
|
||||
|
||||
private static native boolean nativeReserveAddressSpace(String lib32, String lib64);
|
||||
private static native boolean nativeCreateRelroFile(String lib32, String lib64,
|
||||
String relro32, String relro64);
|
||||
private static native boolean nativeLoadWithRelroFile(String lib32, String lib64,
|
||||
String relro32, String relro64);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebViewFactory;
|
||||
|
||||
import dalvik.system.VMRuntime;
|
||||
|
||||
@@ -250,6 +251,9 @@ public class ZygoteInit {
|
||||
preloadClasses();
|
||||
preloadResources();
|
||||
preloadOpenGL();
|
||||
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
|
||||
// for memory sharing purposes.
|
||||
WebViewFactory.prepareWebViewInZygote();
|
||||
Log.d(TAG, "end preload");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.android.server.webkit;
|
||||
|
||||
import android.os.Binder;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
import android.webkit.IWebViewUpdateService;
|
||||
|
||||
/**
|
||||
* Private service to wait for the updatable WebView to be ready for use.
|
||||
* @hide
|
||||
*/
|
||||
public class WebViewUpdateService extends IWebViewUpdateService.Stub {
|
||||
|
||||
private static final String TAG = "WebViewUpdateService";
|
||||
|
||||
private boolean mRelroReady32Bit = false;
|
||||
private boolean mRelroReady64Bit = false;
|
||||
|
||||
public WebViewUpdateService() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The shared relro process calls this to notify us that it's done trying to create a relro
|
||||
* file.
|
||||
*/
|
||||
public void notifyRelroCreationCompleted(boolean is64Bit, boolean success) {
|
||||
// Verify that the caller is the shared relro process.
|
||||
if (Binder.getCallingUid() != Process.SHARED_RELRO_UID) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
if (is64Bit) {
|
||||
mRelroReady64Bit = true;
|
||||
} else {
|
||||
mRelroReady32Bit = true;
|
||||
}
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebViewFactory calls this to block WebView loading until the relro file is created.
|
||||
*/
|
||||
public void waitForRelroCreationCompleted(boolean is64Bit) {
|
||||
synchronized (this) {
|
||||
if (is64Bit) {
|
||||
while (!mRelroReady64Bit) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
} else {
|
||||
while (!mRelroReady32Bit) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,7 @@ import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.view.WindowManager;
|
||||
import android.webkit.WebViewFactory;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.os.BinderInternal;
|
||||
@@ -91,6 +92,7 @@ import com.android.server.tv.TvInputManagerService;
|
||||
import com.android.server.twilight.TwilightService;
|
||||
import com.android.server.usb.UsbService;
|
||||
import com.android.server.wallpaper.WallpaperManagerService;
|
||||
import com.android.server.webkit.WebViewUpdateService;
|
||||
import com.android.server.wm.WindowManagerService;
|
||||
|
||||
import dalvik.system.VMRuntime;
|
||||
@@ -408,6 +410,12 @@ public final class SystemServer {
|
||||
Slog.i(TAG, "Reading configuration...");
|
||||
SystemConfig.getInstance();
|
||||
|
||||
Slog.i(TAG, "WebView Update Service");
|
||||
ServiceManager.addService("webviewupdate", new WebViewUpdateService());
|
||||
|
||||
Slog.i(TAG, "WebViewFactory preparation");
|
||||
WebViewFactory.prepareWebViewInSystemServer();
|
||||
|
||||
Slog.i(TAG, "Scheduling Policy");
|
||||
ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user