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

Commit 869d25db authored by Ziad Youssef's avatar Ziad Youssef
Browse files

Refactor pinning webview logic to System dependencies

Test:  atest com.android.server.webkit.WebViewUpdateServiceTest

Bug: 308907090

Change-Id: I69ca9841fa5a4e186c43b5e69b1572bca68851c4
parent 48c0ff88
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.webkit.Flags.updateServiceV2;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -39,11 +40,14 @@ import android.webkit.WebViewProviderInfo;
import android.webkit.WebViewZygote;

import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
import com.android.server.PinnerService;

import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
@@ -60,6 +64,7 @@ public class SystemImpl implements SystemInterface {
    private static final String TAG_AVAILABILITY = "availableByDefault";
    private static final String TAG_SIGNATURE = "signature";
    private static final String TAG_FALLBACK = "isFallback";
    private static final String PIN_GROUP = "webview";
    private final WebViewProviderInfo[] mWebViewProviderPackages;

    // Initialization-on-demand holder idiom for getting the WebView provider packages once and
@@ -277,6 +282,36 @@ public class SystemImpl implements SystemInterface {
        return true;
    }

    @Override
    public void pinWebviewIfRequired(ApplicationInfo appInfo) {
        PinnerService pinnerService = LocalServices.getService(PinnerService.class);
        int webviewPinQuota = pinnerService.getWebviewPinQuota();
        if (webviewPinQuota <= 0) {
            return;
        }

        pinnerService.unpinGroup(PIN_GROUP);

        ArrayList<String> apksToPin = new ArrayList<>();
        boolean pinSharedFirst = appInfo.metaData.getBoolean("PIN_SHARED_LIBS_FIRST", true);
        for (String sharedLib : appInfo.sharedLibraryFiles) {
            apksToPin.add(sharedLib);
        }
        apksToPin.add(appInfo.sourceDir);
        if (!pinSharedFirst) {
            // We want to prioritize pinning of the native library that is most likely used by apps
            // which in some build flavors live in the main apk and as a shared library for others.
            Collections.reverse(apksToPin);
        }
        for (String apk : apksToPin) {
            if (webviewPinQuota <= 0) {
                break;
            }
            int bytesPinned = pinnerService.pinFile(apk, webviewPinQuota, appInfo, PIN_GROUP);
            webviewPinQuota -= bytesPinned;
        }
    }

    // flags declaring we want extra info from the package manager for webview providers
    private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
            | PackageManager.GET_SIGNATURES | PackageManager.GET_SHARED_LIBRARY_FILES
+3 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.webkit;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.webkit.UserPackage;
@@ -61,4 +62,6 @@ public interface SystemInterface {
    /** Start the zygote if it's not already running. */
    public void ensureZygoteStarted();
    public boolean isMultiProcessDefaultEnabled();

    public void pinWebviewIfRequired(ApplicationInfo appInfo);
}
+1 −40
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@ package com.android.server.webkit;

import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
@@ -30,12 +29,8 @@ import android.webkit.WebViewFactory;
import android.webkit.WebViewProviderInfo;
import android.webkit.WebViewProviderResponse;

import com.android.server.LocalServices;
import com.android.server.PinnerService;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
@@ -93,8 +88,6 @@ class WebViewUpdateServiceImpl implements WebViewUpdateServiceInterface {
    private static final int MULTIPROCESS_SETTING_ON_VALUE = Integer.MAX_VALUE;
    private static final int MULTIPROCESS_SETTING_OFF_VALUE = Integer.MIN_VALUE;

    private static final String PIN_GROUP = "webview";

    private final SystemInterface mSystemInterface;
    private final Context mContext;

@@ -346,38 +339,6 @@ class WebViewUpdateServiceImpl implements WebViewUpdateServiceInterface {
        return newPackage;
    }

    private void pinWebviewIfRequired(ApplicationInfo appInfo) {
        PinnerService pinnerService = LocalServices.getService(PinnerService.class);
        if (pinnerService == null) {
            // This happens in unit tests which do not have services.
            return;
        }
        int webviewPinQuota = pinnerService.getWebviewPinQuota();
        if (webviewPinQuota <= 0) {
            return;
        }

        pinnerService.unpinGroup(PIN_GROUP);

        ArrayList<String> apksToPin = new ArrayList<>();
        boolean pinSharedFirst = appInfo.metaData.getBoolean("PIN_SHARED_LIBS_FIRST", true);
        for (String sharedLib : appInfo.sharedLibraryFiles) {
            apksToPin.add(sharedLib);
        }
        apksToPin.add(appInfo.sourceDir);
        if (!pinSharedFirst) {
            // We want to prioritize pinning of the native library that is most likely used by apps
            // which in some build flavors live in the main apk and as a shared library for others.
            Collections.reverse(apksToPin);
        }
        for (String apk : apksToPin) {
            if (webviewPinQuota <= 0) {
                break;
            }
            int bytesPinned = pinnerService.pinFile(apk, webviewPinQuota, appInfo, PIN_GROUP);
            webviewPinQuota -= bytesPinned;
        }
    }
    /**
     * This is called when we change WebView provider, either when the current provider is
     * updated or a new provider is chosen / takes precedence.
@@ -386,7 +347,7 @@ class WebViewUpdateServiceImpl implements WebViewUpdateServiceInterface {
        synchronized (mLock) {
            mAnyWebViewInstalled = true;
            if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
                pinWebviewIfRequired(newPackage.applicationInfo);
                mSystemInterface.pinWebviewIfRequired(newPackage.applicationInfo);
                mCurrentWebViewPackage = newPackage;

                // The relro creations might 'finish' (not start at all) before
+1 −41
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@ package com.android.server.webkit;

import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
@@ -32,12 +31,8 @@ import android.webkit.WebViewFactory;
import android.webkit.WebViewProviderInfo;
import android.webkit.WebViewProviderResponse;

import com.android.server.LocalServices;
import com.android.server.PinnerService;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
@@ -88,8 +83,6 @@ class WebViewUpdateServiceImpl2 implements WebViewUpdateServiceInterface {
    private static final int VALIDITY_INCORRECT_SIGNATURE = 3;
    private static final int VALIDITY_NO_LIBRARY_FLAG = 4;

    private static final String PIN_GROUP = "webview";

    private final SystemInterface mSystemInterface;
    private final Context mContext;

@@ -356,39 +349,6 @@ class WebViewUpdateServiceImpl2 implements WebViewUpdateServiceInterface {
        return newPackage;
    }

    private void pinWebviewIfRequired(ApplicationInfo appInfo) {
        PinnerService pinnerService = LocalServices.getService(PinnerService.class);
        if (pinnerService == null) {
            // This happens in unit tests which do not have services.
            return;
        }
        int webviewPinQuota = pinnerService.getWebviewPinQuota();
        if (webviewPinQuota <= 0) {
            return;
        }

        pinnerService.unpinGroup(PIN_GROUP);

        ArrayList<String> apksToPin = new ArrayList<>();
        boolean pinSharedFirst = appInfo.metaData.getBoolean("PIN_SHARED_LIBS_FIRST", true);
        for (String sharedLib : appInfo.sharedLibraryFiles) {
            apksToPin.add(sharedLib);
        }
        apksToPin.add(appInfo.sourceDir);
        if (!pinSharedFirst) {
            // We want to prioritize pinning of the native library that is most likely used by apps
            // which in some build flavors live in the main apk and as a shared library for others.
            Collections.reverse(apksToPin);
        }
        for (String apk : apksToPin) {
            if (webviewPinQuota <= 0) {
                break;
            }
            int bytesPinned = pinnerService.pinFile(apk, webviewPinQuota, appInfo, PIN_GROUP);
            webviewPinQuota -= bytesPinned;
        }
    }

    /**
     * This is called when we change WebView provider, either when the current provider is
     * updated or a new provider is chosen / takes precedence.
@@ -397,7 +357,7 @@ class WebViewUpdateServiceImpl2 implements WebViewUpdateServiceInterface {
        synchronized (mLock) {
            mAnyWebViewInstalled = true;
            if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
                pinWebviewIfRequired(newPackage.applicationInfo);
                mSystemInterface.pinWebviewIfRequired(newPackage.applicationInfo);
                mCurrentWebViewPackage = newPackage;

                // The relro creations might 'finish' (not start at all) before
+4 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.webkit;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
@@ -179,4 +180,7 @@ public class TestSystemImpl implements SystemInterface {
    public boolean isMultiProcessDefaultEnabled() {
        return mMultiProcessDefault;
    }

    @Override
    public void pinWebviewIfRequired(ApplicationInfo appInfo) {}
}