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

Commit a7b5cbd3 authored by Ben Murdoch's avatar Ben Murdoch Committed by Android Git Automerger
Browse files

am 503115e9: am f3fc680c: Merge changes...

am 503115e9: am f3fc680c: Merge changes I2f40be36,I4af9fd7e,Ib0b4245f,I55acad96,Id276b71e, ... into lmp-dev

* commit '503115e9d59dc0cacff8e58931e913d77ed1acf5':
  Cherry pick Cleanup debug messages in WebViewFactory and WebViewUpdateService DO NOT MERGE
  Cherry pick Move startIsolatedProcess implementation in ActivityManagerService DO NOT MERGE
  CHerry pick Find WebView package name from a config resource. DO NOT MERGE
  Cherry pick Remove dependency on WebView native library path. DO NOT MERGE
  Cherry pick Make WebViewUpdateService a SystemService. DO NOT MERGE
  Cherry pick Refactor ActivityManagerService and make WebViewFactory more pedantic. DO NOT MERGE
  Cherry pick Refactor native library path logic in WebViewFactory DO NOT MERGE
  Cherry pick Append WebView assets to AssetManager when loading the WebView. DO NOT MERGE
  Cherry pick Introduce startIsolatedProcess private API in ActivityManager DO NOT MERGE
  Cherry pick Load the WebView Java code from an APK. DO NOT MERGE
parents 53cdc2e7 57652524
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -25,4 +25,6 @@ public abstract class ActivityManagerInternal {
    // Called by the power manager.
    public abstract void goingToSleep();
    public abstract void wakingUp();
    public abstract int startIsolatedProcess(String entryPoint, String[] mainArgs,
            String processName, String abiOverride, int uid, Runnable crashHandler);
}
+205 −66
Original line number Diff line number Diff line
@@ -16,16 +16,26 @@

package android.webkit;

import android.app.ActivityManagerInternal;
import android.app.Application;
import android.app.AppGlobals;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.Log;
import com.android.server.LocalServices;
import dalvik.system.VMRuntime;

import java.io.File;
import java.util.Arrays;

import com.android.internal.os.Zygote;

@@ -42,17 +52,15 @@ 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";

    public static final String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY =
            "persist.sys.webview.vmsize";
    private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024;

    private static final String LOGTAG = "WebViewFactory";

    private static final boolean DEBUG = false;
@@ -64,8 +72,8 @@ public final class WebViewFactory {
    private static boolean sAddressSpaceReserved = false;

    public static String getWebViewPackageName() {
        // TODO: Make this dynamic based on resource configuration.
        return "com.android.webview";
        return AppGlobals.getInitialApplication().getString(
                com.android.internal.R.string.config_webViewPackageName);
    }

    static WebViewFactoryProvider getProvider() {
@@ -99,10 +107,18 @@ public final class WebViewFactory {
    }

    private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException {
        Application initialApplication = AppGlobals.getInitialApplication();
        try {
            return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY);
        } catch (ClassNotFoundException e) {
            Log.e(LOGTAG, "Chromium WebView does not exist");
            Context webViewContext = initialApplication.createPackageContext(
                    getWebViewPackageName(),
                    Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
            initialApplication.getAssets().addAssetPath(
                    webViewContext.getApplicationInfo().sourceDir);
            ClassLoader clazzLoader = webViewContext.getClassLoader();
            return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY, true,
                                                                 clazzLoader);
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(LOGTAG, "Chromium WebView package does not exist");
            return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
        }
    }
@@ -114,81 +130,199 @@ public final class WebViewFactory {
    public static void prepareWebViewInZygote() {
        try {
            System.loadLibrary("webviewchromium_loader");
            sAddressSpaceReserved = nativeReserveAddressSpace(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
                                                              CHROMIUM_WEBVIEW_NATIVE_LIB_64);
            long addressSpaceToReserve =
                    SystemProperties.getLong(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
                    CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
            sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);

            if (sAddressSpaceReserved) {
                if (DEBUG) Log.v(LOGTAG, "address space reserved");
                if (DEBUG) {
                    Log.v(LOGTAG, "address space reserved: " + addressSpaceToReserve + " bytes");
                }
            } else {
                Log.e(LOGTAG, "reserving address space failed");
                Log.e(LOGTAG, "reserving " + addressSpaceToReserve +
                        " bytes of address space failed");
            }
        } catch (Throwable e) {
        } catch (Throwable t) {
            // Log and discard errors at this stage as we must not crash the zygote.
            Log.e(LOGTAG, "error preparing native loader", e);
            Log.e(LOGTAG, "error preparing native loader", t);
        }
    }

    /**
     * Perform any WebView loading preparations that must happen at boot from the system server,
     * after the package manager has started.
     * after the package manager has started or after an update to the webview is installed.
     * 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() {
        String[] nativePaths = null;
        try {
            nativePaths = getWebViewNativeLibraryPaths();
        } catch (PackageManager.NameNotFoundException e) {
        }
        prepareWebViewInSystemServer(nativePaths);
    }

    private static void prepareWebViewInSystemServer(String[] nativeLibraryPaths) {
        if (DEBUG) Log.v(LOGTAG, "creating relro files");
        if (new File(CHROMIUM_WEBVIEW_NATIVE_LIB_64).exists()) {
            createRelroFile(Build.SUPPORTED_64_BIT_ABIS[0]);

        // We must always trigger createRelRo regardless of the value of nativeLibraryPaths. Any
        // unexpected values will be handled there to ensure that we trigger notifying any process
        // waiting on relreo creation.
        if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
            if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
            createRelroFile(false /* is64Bit */, nativeLibraryPaths);
        }

        if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
            if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
            createRelroFile(true /* is64Bit */, nativeLibraryPaths);
        }
    }

    public static void onWebViewUpdateInstalled() {
        String[] nativeLibs = null;
        try {
            nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths();
        } catch (PackageManager.NameNotFoundException e) {
        }

        if (nativeLibs != null) {
            long newVmSize = 0L;

            for (String path : nativeLibs) {
                if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path);
                if (path == null) continue;
                File f = new File(path);
                if (f.exists()) {
                    long length = f.length();
                    if (length > newVmSize) {
                        newVmSize = length;
                    }
                }
            }

            if (DEBUG) {
                Log.v(LOGTAG, "Based on library size, need " + newVmSize +
                        " bytes of address space.");
            }
            // The required memory can be larger than the file on disk (due to .bss), and an
            // upgraded version of the library will likely be larger, so always attempt to reserve
            // twice as much as we think to allow for the library to grow during this boot cycle.
            newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
            Log.d(LOGTAG, "Setting new address space to " + newVmSize);
            SystemProperties.set(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
                    Long.toString(newVmSize));
        }
        prepareWebViewInSystemServer(nativeLibs);
    }
        if (new File(CHROMIUM_WEBVIEW_NATIVE_LIB_32).exists()) {
            createRelroFile(Build.SUPPORTED_32_BIT_ABIS[0]);

    private static String[] getWebViewNativeLibraryPaths()
            throws PackageManager.NameNotFoundException {
        final String NATIVE_LIB_FILE_NAME = "libwebviewchromium.so";

        PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
        ApplicationInfo ai = pm.getApplicationInfo(getWebViewPackageName(), 0);

        String path32;
        String path64;
        boolean primaryArchIs64bit = VMRuntime.is64BitAbi(ai.primaryCpuAbi);
        if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) {
            // Multi-arch case.
            if (primaryArchIs64bit) {
                // Primary arch: 64-bit, secondary: 32-bit.
                path64 = ai.nativeLibraryDir;
                path32 = ai.secondaryNativeLibraryDir;
            } else {
                // Primary arch: 32-bit, secondary: 64-bit.
                path64 = ai.secondaryNativeLibraryDir;
                path32 = ai.nativeLibraryDir;
            }
        } else if (primaryArchIs64bit) {
            // Single-arch 64-bit.
            path64 = ai.nativeLibraryDir;
            path32 = "";
        } else {
            // Single-arch 32-bit.
            path32 = ai.nativeLibraryDir;
            path64 = "";
        }
        if (!TextUtils.isEmpty(path32)) path32 += "/" + NATIVE_LIB_FILE_NAME;
        if (!TextUtils.isEmpty(path64)) path64 += "/" + NATIVE_LIB_FILE_NAME;
        return new String[] { path32, path64 };
    }

    private static void createRelroFile(final boolean is64Bit, String[] nativeLibraryPaths) {
        final String abi =
                is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];

        // crashHandler is invoked by the ActivityManagerService when the isolated process crashes.
        Runnable crashHandler = new Runnable() {
            @Override
            public void run() {
                try {
                    Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without");
                    getUpdateService().notifyRelroCreationCompleted(is64Bit, false);
                } catch (RemoteException e) {
                    Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage());
                }
            }
        };

    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) {
            if (nativeLibraryPaths == null
                    || nativeLibraryPaths[0] == null || nativeLibraryPaths[1] == null) {
                throw new IllegalArgumentException(
                        "Native library paths to the WebView RelRo process must not be null!");
            }
            int pid = LocalServices.getService(ActivityManagerInternal.class).startIsolatedProcess(
                    RelroFileCreator.class.getName(), nativeLibraryPaths, "WebViewLoader-" + abi, abi,
                    Process.SHARED_RELRO_UID, crashHandler);
            if (pid <= 0) throw new Exception("Failed to start the relro file creator process");
        } catch (Throwable t) {
            // Log and discard errors as we must not crash the system server.
            Log.e(LOGTAG, "error starting relro file creator for abi " + abi, e);
            Log.e(LOGTAG, "error starting relro file creator for abi " + abi, t);
            crashHandler.run();
        }
    }

    private static class RelroFileCreator {
        // Called in an unprivileged child process to create the relro file.
        public static void main(String[] args) {
            boolean result = false;
            boolean is64Bit = VMRuntime.getRuntime().is64Bit();
            try{
                if (args.length != 2 || args[0] == null || args[1] == null) {
                    Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args));
                    return;
                }
                Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), " +
                        " 32-bit lib: " + args[0] + ", 64-bit lib: " + args[1]);
                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,
                result = nativeCreateRelroFile(args[0] /* path32 */,
                                               args[1] /* path64 */,
                                               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");
            }
                if (result && DEBUG) Log.v(LOGTAG, "created relro file");
            } finally {
                // We must do our best to always notify the update service, even if something fails.
                try {
                getUpdateService().notifyRelroCreationCompleted(VMRuntime.getRuntime().is64Bit(),
                                                                result);
                    getUpdateService().notifyRelroCreationCompleted(is64Bit, result);
                } catch (RemoteException e) {
                    Log.e(LOGTAG, "error notifying update service", e);
                }

                if (!result) Log.e(LOGTAG, "failed to create relro file");

                // Must explicitly exit or else this process will just sit around after we return.
                System.exit(0);
            }
        }
    }

    private static void loadNativeLibrary() {
        if (!sAddressSpaceReserved) {
@@ -203,8 +337,10 @@ public final class WebViewFactory {
            return;
        }

        boolean result = nativeLoadWithRelroFile(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
                                                 CHROMIUM_WEBVIEW_NATIVE_LIB_64,
        try {
            String[] args = getWebViewNativeLibraryPaths();
            boolean result = nativeLoadWithRelroFile(args[0] /* path32 */,
                                                     args[1] /* path64 */,
                                                     CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
                                                     CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
            if (!result) {
@@ -212,13 +348,16 @@ public final class WebViewFactory {
            } else if (DEBUG) {
                Log.v(LOGTAG, "loaded with relro file");
            }
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(LOGTAG, "Failed to list WebView package libraries for loadNativeLibrary", e);
        }
    }

    private static IWebViewUpdateService getUpdateService() {
        return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
    }

    private static native boolean nativeReserveAddressSpace(String lib32, String lib64);
    private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
    private static native boolean nativeCreateRelroFile(String lib32, String lib64,
                                                        String relro32, String relro64);
    private static native boolean nativeLoadWithRelroFile(String lib32, String lib64,
+4 −0
Original line number Diff line number Diff line
@@ -1661,4 +1661,8 @@
    <!--Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet
        string that's stored in 8-bit unpacked format) characters.-->
    <bool translatable="false" name="config_sms_decode_gsm_8bit_data">false</bool>

    <!-- Package name providing WebView implementation. -->
    <string name="config_webViewPackageName" translatable="false">com.android.webview</string>

</resources>
+1 −0
Original line number Diff line number Diff line
@@ -1839,6 +1839,7 @@
  <java-symbol type="attr" name="actionModeWebSearchDrawable" />
  <java-symbol type="string" name="websearch" />
  <java-symbol type="drawable" name="ic_media_video_poster" />
  <java-symbol type="string" name="config_webViewPackageName" />

  <!-- From SubtitleView -->
  <java-symbol type="dimen" name="subtitle_corner_radius" />
+100 −34

File changed.

Preview size limit exceeded, changes collapsed.

Loading