Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 602d1323 authored by Robert Sesek's avatar Robert Sesek
Browse files

Reparent the webview_zygote to be a child of the main app_process zygote.

This uses the new ZygoteProcess.startChildZygote() method to launch the
webview_zygote, rather than having init start it. This will share more
memory between the app_process and the webview_zygote, reducing the
overall system footprint.

Bug: 63749735
Test: m
Test: Launch "Third-party licenses" activity from Settings, and it
      renders correctly via the WebView.
Change-Id: I3e39cd8adb9c099c92ee34640428916d90cb2b8f
parent f9fd8dfc
Loading
Loading
Loading
Loading

cmds/webview_zygote/Android.mk

deleted100644 → 0
+0 −51
Original line number Diff line number Diff line
#
# 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)
+0 −76
Original line number Diff line number Diff line
/*
 * 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);
}
+0 −22
Original line number Diff line number Diff line
#
# 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
+0 −22
Original line number Diff line number Diff line
#
# 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
+32 −83
Original line number Diff line number Diff line
@@ -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();
        }
    }
}
Loading