1924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton/*
2924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton * Copyright (C) 2017 The Android Open Source Project
3924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton *
4924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton * Licensed under the Apache License, Version 2.0 (the "License");
5924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton * you may not use this file except in compliance with the License.
6924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton * You may obtain a copy of the License at
7924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton *
8924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton *      http://www.apache.org/licenses/LICENSE-2.0
9924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton *
10924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton * Unless required by applicable law or agreed to in writing, software
11924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton * distributed under the License is distributed on an "AS IS" BASIS,
12924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton * See the License for the specific language governing permissions and
14924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton * limitations under the License.
15924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton */
16924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonpackage com.android.server.webkit;
17924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
18924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport android.content.Context;
19924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport android.content.pm.PackageInfo;
20924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport android.content.pm.PackageManager.NameNotFoundException;
21924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport android.content.pm.Signature;
22924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport android.os.UserHandle;
23924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport android.util.Base64;
24924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport android.util.Slog;
25924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport android.webkit.UserPackage;
26924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport android.webkit.WebViewFactory;
27924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport android.webkit.WebViewProviderInfo;
28924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport android.webkit.WebViewProviderResponse;
29924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
30924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport java.io.PrintWriter;
31924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport java.util.ArrayList;
32924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport java.util.Arrays;
33924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonimport java.util.List;
34924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
35924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton/**
36924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton * Class that decides what WebView implementation to use and prepares that implementation for
37924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton * use.
38924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton */
39924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Senntonclass WebViewUpdater {
40924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private static final String TAG = WebViewUpdater.class.getSimpleName();
41924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
42924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private static class WebViewPackageMissingException extends Exception {
43924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        public WebViewPackageMissingException(String message) { super(message); }
44924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        public WebViewPackageMissingException(Exception e) { super(e); }
45924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
46924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
47924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private static final int WAIT_TIMEOUT_MS = 1000; // KEY_DISPATCHING_TIMEOUT is 5000.
48924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
49924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private final static int VALIDITY_OK = 0;
50924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private final static int VALIDITY_INCORRECT_SDK_VERSION = 1;
51924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private final static int VALIDITY_INCORRECT_VERSION_CODE = 2;
52924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private final static int VALIDITY_INCORRECT_SIGNATURE = 3;
53924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private final static int VALIDITY_NO_LIBRARY_FLAG = 4;
54924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
55924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private Context mContext;
56924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private SystemInterface mSystemInterface;
57924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private int mMinimumVersionCode = -1;
58924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
59924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    // Keeps track of the number of running relro creations
60924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private int mNumRelroCreationsStarted = 0;
61924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private int mNumRelroCreationsFinished = 0;
62924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    // Implies that we need to rerun relro creation because we are using an out-of-date package
63924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private boolean mWebViewPackageDirty = false;
64924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private boolean mAnyWebViewInstalled = false;
65924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
66924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private int NUMBER_OF_RELROS_UNKNOWN = Integer.MAX_VALUE;
67924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
68924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    // The WebView package currently in use (or the one we are preparing).
69924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private PackageInfo mCurrentWebViewPackage = null;
70924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
71924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private Object mLock = new Object();
72924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
73924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    WebViewUpdater(Context context, SystemInterface systemInterface) {
74924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        mContext = context;
75924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        mSystemInterface = systemInterface;
76924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
77924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
78924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    void packageStateChanged(String packageName, int changedState) {
79924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
80924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            String webviewPackage = provider.packageName;
81924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
82924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (webviewPackage.equals(packageName)) {
83924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                boolean updateWebView = false;
84924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                boolean removedOrChangedOldPackage = false;
85924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                String oldProviderName = null;
86924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                PackageInfo newPackage = null;
87924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                synchronized(mLock) {
88924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    try {
89924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        newPackage = findPreferredWebViewPackage();
90924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        if (mCurrentWebViewPackage != null) {
91924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                            oldProviderName = mCurrentWebViewPackage.packageName;
92924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                            if (changedState == WebViewUpdateService.PACKAGE_CHANGED
93924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                                    && newPackage.packageName.equals(oldProviderName)) {
94924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                                // If we don't change package name we should only rerun the
95924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                                // preparation phase if the current package has been replaced
96924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                                // (not if it has been enabled/disabled).
97924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                                return;
98924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                            }
99924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                            if (newPackage.packageName.equals(oldProviderName)
100924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                                    && (newPackage.lastUpdateTime
101924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                                        == mCurrentWebViewPackage.lastUpdateTime)) {
102924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                                // If the chosen package hasn't been updated, then early-out
103924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                                return;
104924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                            }
105924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        }
106924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        // Only trigger update actions if the updated package is the one
107924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        // that will be used, or the one that was in use before the
108924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        // update, or if we haven't seen a valid WebView package before.
109924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        updateWebView =
110924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                            provider.packageName.equals(newPackage.packageName)
111924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                            || provider.packageName.equals(oldProviderName)
112924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                            || mCurrentWebViewPackage == null;
113924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        // We removed the old package if we received an intent to remove
114924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        // or replace the old package.
115924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        removedOrChangedOldPackage =
116924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                            provider.packageName.equals(oldProviderName);
117924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        if (updateWebView) {
118924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                            onWebViewProviderChanged(newPackage);
119924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        }
120924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    } catch (WebViewPackageMissingException e) {
121924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        mCurrentWebViewPackage = null;
122924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        Slog.e(TAG, "Could not find valid WebView package to create " +
123924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                                "relro with " + e);
124924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    }
125924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                }
126924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                if(updateWebView && !removedOrChangedOldPackage
127924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        && oldProviderName != null) {
128924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    // If the provider change is the result of adding or replacing a
129924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    // package that was not the previous provider then we must kill
130924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    // packages dependent on the old package ourselves. The framework
131924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    // only kills dependents of packages that are being removed.
132924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    mSystemInterface.killPackageDependents(oldProviderName);
133924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                }
134924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                return;
135924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
136924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
137924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
138924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
139924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    void prepareWebViewInSystemServer() {
140924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        try {
141924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            synchronized(mLock) {
142924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                mCurrentWebViewPackage = findPreferredWebViewPackage();
143924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // Don't persist the user-chosen setting across boots if the package being
144924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // chosen is not used (could be disabled or uninstalled) so that the user won't
145924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // be surprised by the device switching to using a certain webview package,
146924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // that was uninstalled/disabled a long time ago, if it is installed/enabled
147924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // again.
148924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                mSystemInterface.updateUserSetting(mContext,
149924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        mCurrentWebViewPackage.packageName);
150924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                onWebViewProviderChanged(mCurrentWebViewPackage);
151924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
152924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        } catch (Throwable t) {
153924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            // Log and discard errors at this stage as we must not crash the system server.
154924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            Slog.e(TAG, "error preparing webview provider from system server", t);
155924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
156924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
157924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
158924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    /**
159924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * Change WebView provider and provider setting and kill packages using the old provider.
160924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * Return the new provider (in case we are in the middle of creating relro files, or
161924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * replacing that provider it will not be in use directly, but will be used when the relros
162924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * or the replacement are done).
163924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     */
164924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    String changeProviderAndSetting(String newProviderName) {
165924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        PackageInfo newPackage = updateCurrentWebViewPackage(newProviderName);
166924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        if (newPackage == null) return "";
167924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        return newPackage.packageName;
168924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
169924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
170924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    /**
171924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * Update the current WebView package.
172924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * @param newProviderName the package to switch to, null if no package has been explicitly
173924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * chosen.
174924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     */
175924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    PackageInfo updateCurrentWebViewPackage(String newProviderName) {
176924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        PackageInfo oldPackage = null;
177924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        PackageInfo newPackage = null;
178924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        boolean providerChanged = false;
179924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        synchronized(mLock) {
180924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            oldPackage = mCurrentWebViewPackage;
181924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
182924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (newProviderName != null) {
183924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                mSystemInterface.updateUserSetting(mContext, newProviderName);
184924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
185924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
186924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            try {
187924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                newPackage = findPreferredWebViewPackage();
188924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                providerChanged = (oldPackage == null)
189924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        || !newPackage.packageName.equals(oldPackage.packageName);
190924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            } catch (WebViewPackageMissingException e) {
191924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // If updated the Setting but don't have an installed WebView package, the
192924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // Setting will be used when a package is available.
193924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                mCurrentWebViewPackage = null;
194924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                Slog.e(TAG, "Couldn't find WebView package to use " + e);
195924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                return null;
196924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
197924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            // Perform the provider change if we chose a new provider
198924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (providerChanged) {
199924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                onWebViewProviderChanged(newPackage);
200924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
201924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
202924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // Kill apps using the old provider only if we changed provider
203924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        if (providerChanged && oldPackage != null) {
204924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            mSystemInterface.killPackageDependents(oldPackage.packageName);
205924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
206924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // Return the new provider, this is not necessarily the one we were asked to switch to,
207924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // but the persistent setting will now be pointing to the provider we were asked to
208924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // switch to anyway.
209924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        return newPackage;
210924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
211924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
212924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    /**
213924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * This is called when we change WebView provider, either when the current provider is
214924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * updated or a new provider is chosen / takes precedence.
215924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     */
216924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private void onWebViewProviderChanged(PackageInfo newPackage) {
217924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        synchronized(mLock) {
218924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            mAnyWebViewInstalled = true;
219924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
220924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                mCurrentWebViewPackage = newPackage;
221924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
222924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // The relro creations might 'finish' (not start at all) before
223924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // WebViewFactory.onWebViewProviderChanged which means we might not know the
224924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // number of started creations before they finish.
225924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN;
226924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                mNumRelroCreationsFinished = 0;
227924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                mNumRelroCreationsStarted =
228924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    mSystemInterface.onWebViewProviderChanged(newPackage);
229924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // If the relro creations finish before we know the number of started creations
230924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // we will have to do any cleanup/notifying here.
231924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                checkIfRelrosDoneLocked();
232924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            } else {
233924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                mWebViewPackageDirty = true;
234924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
235924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
236924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
237924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
238924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    /**
239924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * Fetch only the currently valid WebView packages.
240924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     **/
241924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    WebViewProviderInfo[] getValidWebViewPackages() {
242924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        ProviderAndPackageInfo[] providersAndPackageInfos = getValidWebViewPackagesAndInfos();
243924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        WebViewProviderInfo[] providers =
244924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            new WebViewProviderInfo[providersAndPackageInfos.length];
245924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        for(int n = 0; n < providersAndPackageInfos.length; n++) {
246924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            providers[n] = providersAndPackageInfos[n].provider;
247924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
248924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        return providers;
249924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
250924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
251924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private static class ProviderAndPackageInfo {
252924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        public final WebViewProviderInfo provider;
253924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        public final PackageInfo packageInfo;
254924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
255924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        public ProviderAndPackageInfo(WebViewProviderInfo provider, PackageInfo packageInfo) {
256924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            this.provider = provider;
257924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            this.packageInfo = packageInfo;
258924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
259924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
260924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
261924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos() {
262924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages();
263924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        List<ProviderAndPackageInfo> providers = new ArrayList<>();
264924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        for(int n = 0; n < allProviders.length; n++) {
265924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            try {
266924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                PackageInfo packageInfo =
267924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    mSystemInterface.getPackageInfoForProvider(allProviders[n]);
268924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                if (isValidProvider(allProviders[n], packageInfo)) {
269924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
270924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                }
271924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            } catch (NameNotFoundException e) {
272924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // Don't add non-existent packages
273924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
274924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
275924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        return providers.toArray(new ProviderAndPackageInfo[providers.size()]);
276924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
277924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
278924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    /**
279924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * Returns either the package info of the WebView provider determined in the following way:
280924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * If the user has chosen a provider then use that if it is valid,
281924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * otherwise use the first package in the webview priority list that is valid.
282924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     *
283924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     */
284924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private PackageInfo findPreferredWebViewPackage() throws WebViewPackageMissingException {
285924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos();
286924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
287924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        String userChosenProvider = mSystemInterface.getUserChosenWebViewProvider(mContext);
288924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
289924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // If the user has chosen provider, use that (if it's installed and enabled for all
290924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // users).
291924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        for (ProviderAndPackageInfo providerAndPackage : providers) {
292924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (providerAndPackage.provider.packageName.equals(userChosenProvider)) {
293924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // userPackages can contain null objects.
294924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                List<UserPackage> userPackages =
295924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        mSystemInterface.getPackageInfoForProviderAllUsers(mContext,
296924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                                providerAndPackage.provider);
297924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                if (isInstalledAndEnabledForAllUsers(userPackages)) {
298924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    return providerAndPackage.packageInfo;
299924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                }
300924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
301924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
302924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
303924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // User did not choose, or the choice failed; use the most stable provider that is
304924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // installed and enabled for all users, and available by default (not through
305924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // user choice).
306924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        for (ProviderAndPackageInfo providerAndPackage : providers) {
307924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (providerAndPackage.provider.availableByDefault) {
308924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // userPackages can contain null objects.
309924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                List<UserPackage> userPackages =
310924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        mSystemInterface.getPackageInfoForProviderAllUsers(mContext,
311924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                                providerAndPackage.provider);
312924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                if (isInstalledAndEnabledForAllUsers(userPackages)) {
313924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    return providerAndPackage.packageInfo;
314924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                }
315924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
316924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
317924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
318924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // This should never happen during normal operation (only with modified system images).
319924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        mAnyWebViewInstalled = false;
320924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        throw new WebViewPackageMissingException("Could not find a loadable WebView package");
321924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
322924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
323924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    /**
324924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * Return true iff {@param packageInfos} point to only installed and enabled packages.
325924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * The given packages {@param packageInfos} should all be pointing to the same package, but each
326924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * PackageInfo representing a different user's package.
327924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     */
328924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    static boolean isInstalledAndEnabledForAllUsers(
329924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            List<UserPackage> userPackages) {
330924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        for (UserPackage userPackage : userPackages) {
331924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (!userPackage.isInstalledPackage() || !userPackage.isEnabledPackage()) {
332924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                return false;
333924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
334924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
335924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        return true;
336924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
337924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
338924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    void notifyRelroCreationCompleted() {
339924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        synchronized (mLock) {
340924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            mNumRelroCreationsFinished++;
341924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            checkIfRelrosDoneLocked();
342924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
343924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
344924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
345924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    WebViewProviderResponse waitForAndGetProvider() {
346924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        PackageInfo webViewPackage = null;
347924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        final long NS_PER_MS = 1000000;
348924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        final long timeoutTimeMs = System.nanoTime() / NS_PER_MS + WAIT_TIMEOUT_MS;
349924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        boolean webViewReady = false;
350924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        int webViewStatus = WebViewFactory.LIBLOAD_SUCCESS;
351924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        synchronized (mLock) {
352924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            webViewReady = webViewIsReadyLocked();
353924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            while (!webViewReady) {
354924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                final long timeNowMs = System.nanoTime() / NS_PER_MS;
355924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                if (timeNowMs >= timeoutTimeMs) break;
356924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                try {
357924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    mLock.wait(timeoutTimeMs - timeNowMs);
358924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                } catch (InterruptedException e) {}
359924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                webViewReady = webViewIsReadyLocked();
360924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
361924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            // Make sure we return the provider that was used to create the relro file
362924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            webViewPackage = mCurrentWebViewPackage;
363924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (webViewReady) {
364924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            } else if (!mAnyWebViewInstalled) {
365924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                webViewStatus = WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
366924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            } else {
367924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // Either the current relro creation  isn't done yet, or the new relro creatioin
368924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // hasn't kicked off yet (the last relro creation used an out-of-date WebView).
369924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                webViewStatus = WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO;
370924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                Slog.e(TAG, "Timed out waiting for relro creation, relros started "
371924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        + mNumRelroCreationsStarted
372924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        + " relros finished " + mNumRelroCreationsFinished
373924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        + " package dirty? " + mWebViewPackageDirty);
374924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
375924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
376924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        if (!webViewReady) Slog.w(TAG, "creating relro file timed out");
377924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        return new WebViewProviderResponse(webViewPackage, webViewStatus);
378924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
379924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
380924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    PackageInfo getCurrentWebViewPackage() {
381924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        synchronized(mLock) {
382924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            return mCurrentWebViewPackage;
383924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
384924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
385924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
386924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    /**
387924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * Returns whether WebView is ready and is not going to go through its preparation phase
388924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * again directly.
389924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     */
390924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private boolean webViewIsReadyLocked() {
391924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        return !mWebViewPackageDirty
392924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            && (mNumRelroCreationsStarted == mNumRelroCreationsFinished)
393924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            // The current package might be replaced though we haven't received an intent
394924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            // declaring this yet, the following flag makes anyone loading WebView to wait in
395924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            // this case.
396924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            && mAnyWebViewInstalled;
397924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
398924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
399924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private void checkIfRelrosDoneLocked() {
400924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
401924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (mWebViewPackageDirty) {
402924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                mWebViewPackageDirty = false;
403924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // If we have changed provider since we started the relro creation we need to
404924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                // redo the whole process using the new package instead.
405924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                try {
406924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    PackageInfo newPackage = findPreferredWebViewPackage();
407924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    onWebViewProviderChanged(newPackage);
408924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                } catch (WebViewPackageMissingException e) {
409924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    mCurrentWebViewPackage = null;
410924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    // If we can't find any valid WebView package we are now in a state where
411924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    // mAnyWebViewInstalled is false, so loading WebView will be blocked and we
412924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    // should simply wait until we receive an intent declaring a new package was
413924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    // installed.
414924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                }
415924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            } else {
416924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                mLock.notifyAll();
417924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
418924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
419924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
420924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
421924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    /**
422924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * Returns whether this provider is valid for use as a WebView provider.
423924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     */
424924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    boolean isValidProvider(WebViewProviderInfo configInfo, PackageInfo packageInfo) {
425924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        return VALIDITY_OK == validityResult(configInfo, packageInfo);
426924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
427924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
428924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private int validityResult(WebViewProviderInfo configInfo, PackageInfo packageInfo) {
429924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // Ensure the provider targets this framework release (or a later one).
430924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        if (!UserPackage.hasCorrectTargetSdkVersion(packageInfo)) {
431924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            return VALIDITY_INCORRECT_SDK_VERSION;
432924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
433924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        if (!versionCodeGE(packageInfo.versionCode, getMinimumVersionCode())
434924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                && !mSystemInterface.systemIsDebuggable()) {
435924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            // Webview providers may be downgraded arbitrarily low, prevent that by enforcing
436924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            // minimum version code. This check is only enforced for user builds.
437924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            return VALIDITY_INCORRECT_VERSION_CODE;
438924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
439924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        if (!providerHasValidSignature(configInfo, packageInfo, mSystemInterface)) {
440924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            return VALIDITY_INCORRECT_SIGNATURE;
441924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
442924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        if (WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) == null) {
443924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            return VALIDITY_NO_LIBRARY_FLAG;
444924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
445924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        return VALIDITY_OK;
446924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
447924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
448924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    /**
449924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * Both versionCodes should be from a WebView provider package implemented by Chromium.
450924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * VersionCodes from other kinds of packages won't make any sense in this method.
451924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     *
452924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * An introduction to Chromium versionCode scheme:
453924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * "BBBBPPPAX"
454924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * BBBB: 4 digit branch number. It monotonically increases over time.
455924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * PPP: patch number in the branch. It is padded with zeroes to the left. These three digits
456924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * may change their meaning in the future.
457924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * A: architecture digit.
458924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * X: A digit to differentiate APKs for other reasons.
459924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     *
460924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * This method takes the "BBBB" of versionCodes and compare them.
461924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     *
462924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * @return true if versionCode1 is higher than or equal to versionCode2.
463924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     */
464924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private static boolean versionCodeGE(int versionCode1, int versionCode2) {
465924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        int v1 = versionCode1 / 100000;
466924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        int v2 = versionCode2 / 100000;
467924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
468924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        return v1 >= v2;
469924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
470924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
471924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    /**
472924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * Gets the minimum version code allowed for a valid provider. It is the minimum versionCode
473924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * of all available-by-default and non-fallback WebView provider packages. If there is no
474924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * such WebView provider package on the system, then return -1, which means all positive
475924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * versionCode WebView packages are accepted.
476924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     *
477924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * Note that this is a private method in WebViewUpdater that handles a variable
478924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * (mMinimumVersionCode) which is shared between threads. Furthermore, this method does not
479924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     * hold mLock meaning that we must take extra care to ensure this method is thread-safe.
480924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton     */
481924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private int getMinimumVersionCode() {
482924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        if (mMinimumVersionCode > 0) {
483924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            return mMinimumVersionCode;
484924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
485924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
486924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        int minimumVersionCode = -1;
487924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
488924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (provider.availableByDefault && !provider.isFallback) {
489924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                try {
490924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    int versionCode =
491924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        mSystemInterface.getFactoryPackageVersion(provider.packageName);
492924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    if (minimumVersionCode < 0 || versionCode < minimumVersionCode) {
493924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        minimumVersionCode = versionCode;
494924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    }
495924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                } catch (NameNotFoundException e) {
496924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    // Safe to ignore.
497924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                }
498924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
499924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
500924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
501924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        mMinimumVersionCode = minimumVersionCode;
502924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        return mMinimumVersionCode;
503924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
504924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
505924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private static boolean providerHasValidSignature(WebViewProviderInfo provider,
506924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            PackageInfo packageInfo, SystemInterface systemInterface) {
507924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        if (systemInterface.systemIsDebuggable()) {
508924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            return true;
509924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
510924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        Signature[] packageSignatures;
511924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // If no signature is declared, instead check whether the package is included in the
512924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // system.
513924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        if (provider.signatures == null || provider.signatures.length == 0) {
514924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            return packageInfo.applicationInfo.isSystemApp();
515924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
516924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        packageSignatures = packageInfo.signatures;
517924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        if (packageSignatures.length != 1)
518924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            return false;
519924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
520924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        final byte[] packageSignature = packageSignatures[0].toByteArray();
521924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        // Return whether the package signature matches any of the valid signatures
522924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        for (String signature : provider.signatures) {
523924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
524924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (Arrays.equals(packageSignature, validSignature))
525924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                return true;
526924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
527924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        return false;
528924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
529924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
530924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    void dumpState(PrintWriter pw) {
531924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        synchronized (mLock) {
532924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (mCurrentWebViewPackage == null) {
533924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                pw.println("  Current WebView package is null");
534924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            } else {
535924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                pw.println(String.format("  Current WebView package (name, version): (%s, %s)",
536924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        mCurrentWebViewPackage.packageName,
537924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        mCurrentWebViewPackage.versionName));
538924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
539924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            pw.println(String.format("  Minimum WebView version code: %d",
540924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                  mMinimumVersionCode));
541924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            pw.println(String.format("  Number of relros started: %d",
542924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    mNumRelroCreationsStarted));
543924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            pw.println(String.format("  Number of relros finished: %d",
544924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        mNumRelroCreationsFinished));
545924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            pw.println(String.format("  WebView package dirty: %b", mWebViewPackageDirty));
546924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            pw.println(String.format("  Any WebView package installed: %b",
547924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    mAnyWebViewInstalled));
548924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
549924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            try {
550924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                PackageInfo preferredWebViewPackage = findPreferredWebViewPackage();
551924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                pw.println(String.format(
552924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        "  Preferred WebView package (name, version): (%s, %s)",
553924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        preferredWebViewPackage.packageName,
554924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        preferredWebViewPackage.versionName));
555924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            } catch (WebViewPackageMissingException e) {
556924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                pw.println(String.format("  Preferred WebView package: none"));
557924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
558924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
559924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            dumpAllPackageInformationLocked(pw);
560924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
561924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
562924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
563924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private void dumpAllPackageInformationLocked(PrintWriter pw) {
564924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages();
565924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        pw.println("  WebView packages:");
566924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        for (WebViewProviderInfo provider : allProviders) {
567924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            List<UserPackage> userPackages =
568924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    mSystemInterface.getPackageInfoForProviderAllUsers(mContext, provider);
569924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            PackageInfo systemUserPackageInfo =
570924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    userPackages.get(UserHandle.USER_SYSTEM).getPackageInfo();
571924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (systemUserPackageInfo == null) {
572924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                continue;
573924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
574924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
575924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            int validity = validityResult(provider, systemUserPackageInfo);
576924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            String packageDetails = String.format(
577924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    "versionName: %s, versionCode: %d, targetSdkVersion: %d",
578924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    systemUserPackageInfo.versionName,
579924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    systemUserPackageInfo.versionCode,
580924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                    systemUserPackageInfo.applicationInfo.targetSdkVersion);
581924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            if (validity == VALIDITY_OK) {
582924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                boolean installedForAllUsers = isInstalledAndEnabledForAllUsers(
583924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        mSystemInterface.getPackageInfoForProviderAllUsers(mContext, provider));
584924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                pw.println(String.format(
585924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        "    Valid package %s (%s) is %s installed/enabled for all users",
586924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        systemUserPackageInfo.packageName,
587924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        packageDetails,
588924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        installedForAllUsers ? "" : "NOT"));
589924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            } else {
590924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                pw.println(String.format("    Invalid package %s (%s), reason: %s",
591924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        systemUserPackageInfo.packageName,
592924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        packageDetails,
593924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                        getInvalidityReason(validity)));
594924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            }
595924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
596924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
597924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
598924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    private static String getInvalidityReason(int invalidityReason) {
599924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        switch (invalidityReason) {
600924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            case VALIDITY_INCORRECT_SDK_VERSION:
601924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                return "SDK version too low";
602924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            case VALIDITY_INCORRECT_VERSION_CODE:
603924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                return "Version code too low";
604924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            case VALIDITY_INCORRECT_SIGNATURE:
605924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                return "Incorrect signature";
606924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            case VALIDITY_NO_LIBRARY_FLAG:
607924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                return "No WebView-library manifest flag";
608924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton            default:
609924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton                return "Unexcepted validity-reason";
610924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton        }
611924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton    }
612924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton
613924dacd8a0ec4ee2fc640930d5586b42615fe504Gustav Sennton}
614