webview创建过程分析(二)

从前面 webview创建过程分析(一)中我们知道在webview创建过程中会创建WebViewChormiumFactoryProviderWebViewChromium,今天我们来分析下这两个创建过程的源码。

WebViewChormiumFactoryProvider创建过程

public static WebViewChromiumFactoryProvider create(android.webkit.WebViewDelegate delegate) {
        return new WebViewChromiumFactoryProvider(delegate);
    }

从上面的代码可以知道要创建WebViewChromiumFactoryProvider,需要WebViewDelegate,这个delegate是在new WebView的时候创建的。

public WebViewChromiumFactoryProvider(android.webkit.WebViewDelegate delegate) {
        initialize(WebViewDelegateFactory.createProxyDelegate(delegate));
    }

这里会先调用WebViewDelegateFactory的createProxyDelegate方法将客户端的WebViewDelegate的类转换成chromium中的WebViewDelegate,然后调用initialize方法

@SuppressWarnings("NoContextGetApplicationContext")
    private void initialize(WebViewDelegate webViewDelegate) {
        long startTime = SystemClock.elapsedRealtime();
        try (ScopedSysTraceEvent e1 =
                        ScopedSysTraceEvent.scoped("WebViewChromiumFactoryProvider.initialize")) {
            PackageInfo packageInfo;
            try (ScopedSysTraceEvent e2 = ScopedSysTraceEvent.scoped(
                         "WebViewChromiumFactoryProvider.getLoadedPackageInfo")) {
                // The package is used to locate the services for copying crash minidumps and
                // requesting variations seeds. So it must be set before initializing variations and
                // before a renderer has a chance to crash.
                packageInfo = WebViewFactory.getLoadedPackageInfo();
            }
            AwBrowserProcess.setWebViewPackageName(packageInfo.packageName);

            //1.创建WebViewChromiumAwInit对象
            mAwInit = createAwInit();
            mWebViewDelegate = webViewDelegate;
            Context ctx = webViewDelegate.getApplication().getApplicationContext();

            // If the application context is DE, but we have credentials, use a CE context instead
            try (ScopedSysTraceEvent e2 = ScopedSysTraceEvent.scoped(
                         "WebViewChromiumFactoryProvider.checkStorage")) {
                checkStorageIsNotDeviceProtected(webViewDelegate.getApplication());
            } catch (IllegalArgumentException e) {
                assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
                if (!GlueApiHelperForN.isUserUnlocked(ctx)) {
                    throw e;
                }
                ctx = GlueApiHelperForN.createCredentialProtectedStorageContext(ctx);
            }

            // WebView needs to make sure to always use the wrapped application context.
            ctx = ClassLoaderContextWrapperFactory.get(ctx);
            ContextUtils.initApplicationContext(ctx);

            // Find the package ID for the package that WebView's resources come from.
            // This will be the donor package if there is one, not our main package.
            String resourcePackage = packageInfo.packageName;
            if (packageInfo.applicationInfo.metaData != null) {
                resourcePackage = packageInfo.applicationInfo.metaData.getString(
                        "com.android.webview.WebViewDonorPackage", resourcePackage);
            }
            int packageId = webViewDelegate.getPackageId(ctx.getResources(), resourcePackage);

            mAwInit.setUpResourcesOnBackgroundThread(packageId, ctx);

            try (ScopedSysTraceEvent e2 = ScopedSysTraceEvent.scoped(
                         "WebViewChromiumFactoryProvider.initCommandLine")) {
                // This may take ~20 ms only on userdebug devices.
                CommandLineUtil.initCommandLine();
            }

            boolean multiProcess = false;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                // Ask the system if multiprocess should be enabled on O+.
                multiProcess = webViewDelegate.isMultiProcessEnabled();
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                // Check the multiprocess developer setting directly on N.
                multiProcess = Settings.Global.getInt(ctx.getContentResolver(),
                                       Settings.Global.WEBVIEW_MULTIPROCESS, 0)
                        == 1;
            }

            //2.设置是否是多进程
            if (multiProcess) {
                CommandLine cl = CommandLine.getInstance();
                cl.appendSwitch(AwSwitches.WEBVIEW_SANDBOXED_RENDERER);
            }

            int applicationFlags = ctx.getApplicationInfo().flags;
            boolean isAppDebuggable = (applicationFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
            boolean isOsDebuggable = BuildInfo.isDebugAndroid();
            // Enable logging JS console messages in system logs only if the app is debuggable or
            // it's a debugable android build.
            if (isAppDebuggable || isOsDebuggable) {
                CommandLine cl = CommandLine.getInstance();
                cl.appendSwitch(AwSwitches.WEBVIEW_LOG_JS_CONSOLE_MESSAGES);
            }

            ThreadUtils.setWillOverrideUiThread(true);
            BuildInfo.setBrowserPackageInfo(packageInfo);

            //3.加载相关so
            try (StrictModeContext ignored = StrictModeContext.allowDiskWrites()) {
                try (ScopedSysTraceEvent e2 = ScopedSysTraceEvent.scoped(
                             "WebViewChromiumFactoryProvider.loadChromiumLibrary")) {
                    String dataDirectorySuffix = null;
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                        dataDirectorySuffix = webViewDelegate.getDataDirectorySuffix();
                    }
                    AwBrowserProcess.loadLibrary(dataDirectorySuffix);
                }

                try (ScopedSysTraceEvent e2 = ScopedSysTraceEvent.scoped(
                             "WebViewChromiumFactoryProvider.loadGlueLayerPlatSupportLibrary")) {
                    System.loadLibrary("webviewchromium_plat_support");
                }

                deleteContentsOnPackageDowngrade(packageInfo);
            }

            // Now safe to use WebView data directory.

            mAwInit.startVariationsInit();

            mShouldDisableThreadChecking = shouldDisableThreadChecking(ctx);

            //4.设置单例
            setSingleton(this);
        }

        TimesHistogramSample histogram =
                new TimesHistogramSample("Android.WebView.Startup.CreationTime.Stage1.FactoryInit");
        histogram.record(SystemClock.elapsedRealtime() - startTime);
    }

initialize方法主要执行几个步骤

  1. 创建 WebViewChromiumAwInit对象
  2. 设置多进程相关信息
  3. 加载so
  4. 设置自己为单例

我们看下这几步执行的一些具体内容

protected WebViewChromiumAwInit createAwInit() {
        try (ScopedSysTraceEvent e2 =
                        ScopedSysTraceEvent.scoped("WebViewChromiumFactoryProvider.createAwInit")) {
            return new WebViewChromiumAwInit(this);
        }
    }


WebViewChromiumAwInit(WebViewChromiumFactoryProvider factory) {
        mFactory = factory;
        // Do not make calls into 'factory' in this ctor - this ctor is called from the
        // WebViewChromiumFactoryProvider ctor, so 'factory' is not properly initialized yet.
    }

这里主要就是new了一个WebViewChromiumAwInit对象,同时为mFactory赋值,指向的是一个WebViewChromiumFactoryProvider对象。

  •  设置多进程相关信息

这里会通过CommandLine对象将多进程相关的信息存起来,CommandLine是单例模式的

  • 加载so

主要通过AwBrowserProcess来加载so

public static void loadLibrary(String processDataDirSuffix) {
        LibraryLoader.getInstance().setLibraryProcessType(LibraryProcessType.PROCESS_WEBVIEW);
        if (processDataDirSuffix == null) {
            PathUtils.setPrivateDataDirectorySuffix(WEBVIEW_DIR_BASENAME, "WebView");
        } else {
            String processDataDirName = WEBVIEW_DIR_BASENAME + "_" + processDataDirSuffix;
            PathUtils.setPrivateDataDirectorySuffix(processDataDirName, processDataDirName);
        }
        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
        try {
            LibraryLoader.getInstance().loadNow();
            // Switch the command line implementation from Java to native.
            // It's okay for the WebView to do this before initialization because we have
            // setup the JNI bindings by this point.
            LibraryLoader.getInstance().switchCommandLineForWebView();
        } finally {
            StrictMode.setThreadPolicy(oldPolicy);
        }
    }

上面就是WebViewChormiumFactoryProvider创建过程中涉及到的一些逻辑

WebViewChromium创建过程

public WebViewChromium(WebViewChromiumFactoryProvider factory, WebView webView,
            WebView.PrivateAccess webViewPrivate, boolean shouldDisableThreadChecking) {
        try (ScopedSysTraceEvent e1 = ScopedSysTraceEvent.scoped("WebViewChromium.constructor")) {
            WebViewChromiumFactoryProvider.checkStorageIsNotDeviceProtected(webView.getContext());
            mWebView = webView;
            mWebViewPrivate = webViewPrivate;
            mHitTestResult = new WebView.HitTestResult();
            mContext = ClassLoaderContextWrapperFactory.get(mWebView.getContext());
            mAppTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
            mFactory = factory;
            mShouldDisableThreadChecking = shouldDisableThreadChecking;
            factory.getWebViewDelegate().addWebViewAssetPath(mWebView.getContext());
            mSharedWebViewChromium =
                    new SharedWebViewChromium(mFactory.getRunQueue(), mFactory.getAwInit());
        }
    }

这里主要是为一些成员变量赋值,同时会创建SharedWebViewChromium对象

public SharedWebViewChromium(WebViewChromiumRunQueue runQueue, WebViewChromiumAwInit awInit) {
        mRunQueue = runQueue;
        mAwInit = awInit;
    }

SharedWebViewChromium对象的创建过程主要是为两个成员mRunQueue和mAwInit赋值。其中mAwInit对象就是在前面 WebViewChormiumFactoryProvider的创建过程中创建的,mRunQueue是通过mFactory.getRunQueue来赋值的。我们看下这个WebViewChromiumRunQueue是干什么的

private final WebViewChromiumRunQueue mRunQueue = new WebViewChromiumRunQueue(
            () -> { return WebViewChromiumFactoryProvider.this.mAwInit.hasStarted(); });

    /* package */ WebViewChromiumRunQueue getRunQueue() {
        return mRunQueue;
    }
public WebViewChromiumRunQueue(ChromiumHasStartedCallable chromiumHasStartedCallable) {
        mQueue = new ConcurrentLinkedQueue<Runnable>();
        mChromiumHasStartedCallable = chromiumHasStartedCallable;
    }

这里主要就是创建一个WebViewChromiumRunQueue,里面有个包含Runnable的队列。

以上就是 WebViewChromium创建过程中的一些执行逻辑。

WebViewChromium初始化过程

前面webview创建过程分析(一)中我们知道,在new WebView的过程中会调用WebViewChromium的init方法,我们看下在init过程中都执行了什么逻辑。

@Override
    // BUG=6790250 |javaScriptInterfaces| was only ever used by the obsolete DumpRenderTree
    // so is ignored. TODO: remove it from WebViewProvider.
    public void init(final Map<String, Object> javaScriptInterfaces,
            final boolean privateBrowsing) {
        long startTime = SystemClock.elapsedRealtime();
        boolean isFirstWebViewInit = !mFactory.hasStarted();
        try (ScopedSysTraceEvent e1 = ScopedSysTraceEvent.scoped("WebViewChromium.init")) {
            if (privateBrowsing) {
                mFactory.startYourEngines(true);
                final String msg = "Private browsing is not supported in WebView.";
                if (mAppTargetSdkVersion >= Build.VERSION_CODES.KITKAT) {
                    throw new IllegalArgumentException(msg);
                } else {
                    Log.w(TAG, msg);
                    TextView warningLabel = new TextView(mContext);
                    warningLabel.setText(mContext.getString(
                            org.chromium.android_webview.R.string.private_browsing_warning));
                    mWebView.addView(warningLabel);
                }
            }

            // We will defer real initialization until we know which thread to do it on, unless:
            // - we are on the main thread already (common case),
            // - the app is targeting >= JB MR2, in which case checkThread enforces that all usage
            //   comes from a single thread. (Note in JB MR2 this exception was in WebView.java).
            if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2) {

                //1.启动browser进程
                mFactory.startYourEngines(false);
                checkThread();
            } else if (!mFactory.hasStarted()) {
                if (Looper.myLooper() == Looper.getMainLooper()) {
                    mFactory.startYourEngines(true);
                }
            }

            final boolean isAccessFromFileURLsGrantedByDefault =
                    mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN;
            final boolean areLegacyQuirksEnabled =
                    mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT;
            final boolean allowEmptyDocumentPersistence =
                    mAppTargetSdkVersion <= Build.VERSION_CODES.M;
            final boolean allowGeolocationOnInsecureOrigins =
                    mAppTargetSdkVersion <= Build.VERSION_CODES.M;

            // https://crbug.com/698752
            final boolean doNotUpdateSelectionOnMutatingSelectionRange =
                    mAppTargetSdkVersion <= Build.VERSION_CODES.M;

            //2.创建ConetntsClientAdapter
            mContentsClientAdapter =
                    mFactory.createWebViewContentsClientAdapter(mWebView, mContext);
            try (ScopedSysTraceEvent e2 =
                            ScopedSysTraceEvent.scoped("WebViewChromium.ContentSettingsAdapter")) {

                //3.创建WebSettings
                mWebSettings = mFactory.createCo
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值