blob: 791fbbca385c4fd71d8ba9a8e17d5c66f77b9b21 [file] [log] [blame]
Gustav Sennton79fea482016-04-07 14:22:56 +01001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.server.webkit;
17
18import android.content.Context;
19import android.content.pm.ApplicationInfo;
20import android.content.pm.PackageInfo;
21import android.content.pm.PackageManager.NameNotFoundException;
22import android.content.pm.Signature;
Robert Sesekded20982016-08-15 13:59:13 -040023import android.database.ContentObserver;
24import android.net.Uri;
25import android.os.Handler;
Gustav Sennton0df2c552016-06-14 15:32:19 +010026import android.os.UserHandle;
Gustav Sennton79fea482016-04-07 14:22:56 +010027import android.util.Base64;
28import android.util.Slog;
29import android.webkit.WebViewFactory;
30import android.webkit.WebViewProviderInfo;
31import android.webkit.WebViewProviderResponse;
32
33import java.util.ArrayList;
34import java.util.Arrays;
35import java.util.List;
36
37/**
38 * Implementation of the WebViewUpdateService.
39 * This class doesn't depend on the android system like the actual Service does and can be used
40 * directly by tests (as long as they implement a SystemInterface).
41 * @hide
42 */
43public class WebViewUpdateServiceImpl {
44 private static final String TAG = WebViewUpdateServiceImpl.class.getSimpleName();
45
46 private SystemInterface mSystemInterface;
47 private WebViewUpdater mWebViewUpdater;
Robert Sesekded20982016-08-15 13:59:13 -040048 private SettingsObserver mSettingsObserver;
Gustav Sennton86f7bbe2016-10-24 16:49:32 +010049 final private Context mContext;
Gustav Sennton79fea482016-04-07 14:22:56 +010050
51 public WebViewUpdateServiceImpl(Context context, SystemInterface systemInterface) {
52 mContext = context;
53 mSystemInterface = systemInterface;
54 mWebViewUpdater = new WebViewUpdater(mContext, mSystemInterface);
55 }
56
Gustav Sennton0df2c552016-06-14 15:32:19 +010057 void packageStateChanged(String packageName, int changedState, int userId) {
58 // We don't early out here in different cases where we could potentially early-out (e.g. if
59 // we receive PACKAGE_CHANGED for another user than the system user) since that would
60 // complicate this logic further and open up for more edge cases.
Gustav Sennton79fea482016-04-07 14:22:56 +010061 updateFallbackStateOnPackageChange(packageName, changedState);
62 mWebViewUpdater.packageStateChanged(packageName, changedState);
63 }
64
65 void prepareWebViewInSystemServer() {
66 updateFallbackStateOnBoot();
67 mWebViewUpdater.prepareWebViewInSystemServer();
Robert Sesekded20982016-08-15 13:59:13 -040068
69 // Register for changes in the multiprocess developer option. This has to be done
70 // here, since the update service gets created before the ContentResolver service.
71 mSettingsObserver = new SettingsObserver();
Gustav Sennton79fea482016-04-07 14:22:56 +010072 }
73
74 private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
75 for (WebViewProviderInfo provider : providers) {
76 if (provider.availableByDefault && !provider.isFallback) {
77 try {
78 PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(provider);
Gustav Sennton0df2c552016-06-14 15:32:19 +010079 if (isInstalledPackage(packageInfo) && isEnabledPackage(packageInfo)
Gustav Sennton79fea482016-04-07 14:22:56 +010080 && mWebViewUpdater.isValidProvider(provider, packageInfo)) {
81 return true;
82 }
83 } catch (NameNotFoundException e) {
84 // A non-existent provider is neither valid nor enabled
85 }
86 }
87 }
88 return false;
89 }
90
91 /**
92 * Called when a new user has been added to update the state of its fallback package.
93 */
94 void handleNewUser(int userId) {
95 if (!mSystemInterface.isFallbackLogicEnabled()) return;
96
97 WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
98 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
99 if (fallbackProvider == null) return;
100
101 mSystemInterface.enablePackageForUser(fallbackProvider.packageName,
102 !existsValidNonFallbackProvider(webviewProviders), userId);
103 }
104
105 void notifyRelroCreationCompleted() {
106 mWebViewUpdater.notifyRelroCreationCompleted();
107 }
108
109 WebViewProviderResponse waitForAndGetProvider() {
110 return mWebViewUpdater.waitForAndGetProvider();
111 }
112
113 String changeProviderAndSetting(String newProvider) {
114 return mWebViewUpdater.changeProviderAndSetting(newProvider);
115 }
116
117 WebViewProviderInfo[] getValidWebViewPackages() {
Gustav Sennton0df2c552016-06-14 15:32:19 +0100118 return mWebViewUpdater.getValidAndInstalledWebViewPackages();
Gustav Sennton79fea482016-04-07 14:22:56 +0100119 }
120
121 WebViewProviderInfo[] getWebViewPackages() {
122 return mSystemInterface.getWebViewPackages();
123 }
124
125 String getCurrentWebViewPackageName() {
126 return mWebViewUpdater.getCurrentWebViewPackageName();
127 }
128
129 void enableFallbackLogic(boolean enable) {
130 mSystemInterface.enableFallbackLogic(enable);
131 }
132
133 private void updateFallbackStateOnBoot() {
Gustav Sennton53b78242016-04-07 15:56:10 +0100134 if (!mSystemInterface.isFallbackLogicEnabled()) return;
135
Gustav Sennton79fea482016-04-07 14:22:56 +0100136 WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
137 updateFallbackState(webviewProviders, true);
138 }
139
140 /**
141 * Handle the enabled-state of our fallback package, i.e. if there exists some non-fallback
142 * package that is valid (and available by default) then disable the fallback package,
143 * otherwise, enable the fallback package.
144 */
145 private void updateFallbackStateOnPackageChange(String changedPackage, int changedState) {
146 if (!mSystemInterface.isFallbackLogicEnabled()) return;
147
148 WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
149
150 // A package was changed / updated / downgraded, early out if it is not one of the
151 // webview packages that are available by default.
152 boolean changedPackageAvailableByDefault = false;
153 for (WebViewProviderInfo provider : webviewProviders) {
154 if (provider.packageName.equals(changedPackage)) {
155 if (provider.availableByDefault) {
156 changedPackageAvailableByDefault = true;
157 }
158 break;
159 }
160 }
161 if (!changedPackageAvailableByDefault) return;
162 updateFallbackState(webviewProviders, false);
163 }
164
165 private void updateFallbackState(WebViewProviderInfo[] webviewProviders, boolean isBoot) {
166 // If there exists a valid and enabled non-fallback package - disable the fallback
167 // package, otherwise, enable it.
168 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
169 if (fallbackProvider == null) return;
170 boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
171
172 boolean isFallbackEnabled = false;
173 try {
174 isFallbackEnabled = isEnabledPackage(
175 mSystemInterface.getPackageInfoForProvider(fallbackProvider));
176 } catch (NameNotFoundException e) {
Gustav Senntonff396f22016-04-08 18:33:30 +0100177 // No fallback package installed -> early out.
178 return;
Gustav Sennton79fea482016-04-07 14:22:56 +0100179 }
180
181 if (existsValidNonFallbackProvider
182 // During an OTA the primary user's WebView state might differ from other users', so
183 // ignore the state of that user during boot.
184 && (isFallbackEnabled || isBoot)) {
185 mSystemInterface.uninstallAndDisablePackageForAllUsers(mContext,
186 fallbackProvider.packageName);
187 } else if (!existsValidNonFallbackProvider
188 // During an OTA the primary user's WebView state might differ from other users', so
189 // ignore the state of that user during boot.
190 && (!isFallbackEnabled || isBoot)) {
191 // Enable the fallback package for all users.
192 mSystemInterface.enablePackageForAllUsers(mContext,
193 fallbackProvider.packageName, true);
194 }
195 }
196
197 /**
198 * Returns the only fallback provider in the set of given packages, or null if there is none.
199 */
200 private static WebViewProviderInfo getFallbackProvider(WebViewProviderInfo[] webviewPackages) {
201 for (WebViewProviderInfo provider : webviewPackages) {
202 if (provider.isFallback) {
203 return provider;
204 }
205 }
206 return null;
207 }
208
209 boolean isFallbackPackage(String packageName) {
210 if (packageName == null || !mSystemInterface.isFallbackLogicEnabled()) return false;
211
212 WebViewProviderInfo[] webviewPackages = mSystemInterface.getWebViewPackages();
213 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
214 return (fallbackProvider != null
215 && packageName.equals(fallbackProvider.packageName));
216 }
217
218 /**
219 * Class that decides what WebView implementation to use and prepares that implementation for
220 * use.
221 */
222 private static class WebViewUpdater {
223 private Context mContext;
224 private SystemInterface mSystemInterface;
225 private int mMinimumVersionCode = -1;
226
227 public WebViewUpdater(Context context, SystemInterface systemInterface) {
228 mContext = context;
229 mSystemInterface = systemInterface;
230 }
231
Gustav Senntonfd07efa2016-05-23 13:09:03 +0100232 private static final int WAIT_TIMEOUT_MS = 1000; // KEY_DISPATCHING_TIMEOUT is 5000.
Gustav Sennton79fea482016-04-07 14:22:56 +0100233
234 // Keeps track of the number of running relro creations
235 private int mNumRelroCreationsStarted = 0;
236 private int mNumRelroCreationsFinished = 0;
237 // Implies that we need to rerun relro creation because we are using an out-of-date package
238 private boolean mWebViewPackageDirty = false;
239 private boolean mAnyWebViewInstalled = false;
240
241 private int NUMBER_OF_RELROS_UNKNOWN = Integer.MAX_VALUE;
242
243 // The WebView package currently in use (or the one we are preparing).
244 private PackageInfo mCurrentWebViewPackage = null;
245
246 private Object mLock = new Object();
247
248 public void packageStateChanged(String packageName, int changedState) {
249 for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
250 String webviewPackage = provider.packageName;
251
252 if (webviewPackage.equals(packageName)) {
253 boolean updateWebView = false;
254 boolean removedOrChangedOldPackage = false;
255 String oldProviderName = null;
256 PackageInfo newPackage = null;
257 synchronized(mLock) {
258 try {
259 newPackage = findPreferredWebViewPackage();
Gustav Sennton2198a532016-04-12 16:38:28 +0100260 if (mCurrentWebViewPackage != null) {
Gustav Sennton79fea482016-04-07 14:22:56 +0100261 oldProviderName = mCurrentWebViewPackage.packageName;
Gustav Sennton2198a532016-04-12 16:38:28 +0100262 if (changedState == WebViewUpdateService.PACKAGE_CHANGED
263 && newPackage.packageName.equals(oldProviderName)) {
264 // If we don't change package name we should only rerun the
265 // preparation phase if the current package has been replaced
266 // (not if it has been enabled/disabled).
267 return;
268 }
Gustav Sennton0df2c552016-06-14 15:32:19 +0100269 if (newPackage.packageName.equals(oldProviderName)
270 && (newPackage.lastUpdateTime
271 == mCurrentWebViewPackage.lastUpdateTime)) {
272 // If the chosen package hasn't been updated, then early-out
273 return;
274 }
Gustav Sennton2198a532016-04-12 16:38:28 +0100275 }
Gustav Sennton79fea482016-04-07 14:22:56 +0100276 // Only trigger update actions if the updated package is the one
277 // that will be used, or the one that was in use before the
278 // update, or if we haven't seen a valid WebView package before.
279 updateWebView =
280 provider.packageName.equals(newPackage.packageName)
281 || provider.packageName.equals(oldProviderName)
282 || mCurrentWebViewPackage == null;
283 // We removed the old package if we received an intent to remove
284 // or replace the old package.
285 removedOrChangedOldPackage =
286 provider.packageName.equals(oldProviderName);
287 if (updateWebView) {
288 onWebViewProviderChanged(newPackage);
289 }
290 } catch (WebViewFactory.MissingWebViewPackageException e) {
291 Slog.e(TAG, "Could not find valid WebView package to create " +
292 "relro with " + e);
293 }
294 }
295 if(updateWebView && !removedOrChangedOldPackage
296 && oldProviderName != null) {
297 // If the provider change is the result of adding or replacing a
298 // package that was not the previous provider then we must kill
299 // packages dependent on the old package ourselves. The framework
300 // only kills dependents of packages that are being removed.
301 mSystemInterface.killPackageDependents(oldProviderName);
302 }
303 return;
304 }
305 }
306 }
307
308 public void prepareWebViewInSystemServer() {
309 try {
310 synchronized(mLock) {
311 mCurrentWebViewPackage = findPreferredWebViewPackage();
Gustav Senntona9159042016-04-11 16:32:52 +0100312 // Don't persist the user-chosen setting across boots if the package being
313 // chosen is not used (could be disabled or uninstalled) so that the user won't
314 // be surprised by the device switching to using a certain webview package,
315 // that was uninstalled/disabled a long time ago, if it is installed/enabled
316 // again.
317 mSystemInterface.updateUserSetting(mContext,
318 mCurrentWebViewPackage.packageName);
Gustav Sennton79fea482016-04-07 14:22:56 +0100319 onWebViewProviderChanged(mCurrentWebViewPackage);
320 }
321 } catch (Throwable t) {
322 // Log and discard errors at this stage as we must not crash the system server.
323 Slog.e(TAG, "error preparing webview provider from system server", t);
324 }
325 }
326
327 /**
328 * Change WebView provider and provider setting and kill packages using the old provider.
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100329 * Return the new provider (in case we are in the middle of creating relro files, or
330 * replacing that provider it will not be in use directly, but will be used when the relros
331 * or the replacement are done).
Gustav Sennton79fea482016-04-07 14:22:56 +0100332 */
333 public String changeProviderAndSetting(String newProviderName) {
334 PackageInfo oldPackage = null;
335 PackageInfo newPackage = null;
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100336 boolean providerChanged = false;
Gustav Sennton79fea482016-04-07 14:22:56 +0100337 synchronized(mLock) {
338 oldPackage = mCurrentWebViewPackage;
339 mSystemInterface.updateUserSetting(mContext, newProviderName);
340
341 try {
342 newPackage = findPreferredWebViewPackage();
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100343 providerChanged = (oldPackage == null)
344 || !newPackage.packageName.equals(oldPackage.packageName);
Gustav Sennton79fea482016-04-07 14:22:56 +0100345 } catch (WebViewFactory.MissingWebViewPackageException e) {
346 Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView " +
347 "package " + e);
348 // If we don't perform the user change but don't have an installed WebView
349 // package, we will have changed the setting and it will be used when a package
350 // is available.
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100351 return "";
Gustav Sennton79fea482016-04-07 14:22:56 +0100352 }
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100353 // Perform the provider change if we chose a new provider
354 if (providerChanged) {
355 onWebViewProviderChanged(newPackage);
356 }
Gustav Sennton79fea482016-04-07 14:22:56 +0100357 }
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100358 // Kill apps using the old provider only if we changed provider
359 if (providerChanged && oldPackage != null) {
Gustav Sennton79fea482016-04-07 14:22:56 +0100360 mSystemInterface.killPackageDependents(oldPackage.packageName);
361 }
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100362 // Return the new provider, this is not necessarily the one we were asked to switch to
363 // But the persistent setting will now be pointing to the provider we were asked to
364 // switch to anyway
Gustav Sennton79fea482016-04-07 14:22:56 +0100365 return newPackage.packageName;
366 }
367
368 /**
369 * This is called when we change WebView provider, either when the current provider is
370 * updated or a new provider is chosen / takes precedence.
371 */
372 private void onWebViewProviderChanged(PackageInfo newPackage) {
373 synchronized(mLock) {
374 mAnyWebViewInstalled = true;
375 if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
376 mCurrentWebViewPackage = newPackage;
Gustav Sennton79fea482016-04-07 14:22:56 +0100377
378 // The relro creations might 'finish' (not start at all) before
379 // WebViewFactory.onWebViewProviderChanged which means we might not know the
380 // number of started creations before they finish.
381 mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN;
382 mNumRelroCreationsFinished = 0;
383 mNumRelroCreationsStarted =
384 mSystemInterface.onWebViewProviderChanged(newPackage);
385 // If the relro creations finish before we know the number of started creations
386 // we will have to do any cleanup/notifying here.
387 checkIfRelrosDoneLocked();
388 } else {
389 mWebViewPackageDirty = true;
390 }
391 }
392 }
393
Gustav Sennton0df2c552016-06-14 15:32:19 +0100394 private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos(boolean onlyInstalled) {
Gustav Sennton79fea482016-04-07 14:22:56 +0100395 WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages();
396 List<ProviderAndPackageInfo> providers = new ArrayList<>();
397 for(int n = 0; n < allProviders.length; n++) {
398 try {
399 PackageInfo packageInfo =
400 mSystemInterface.getPackageInfoForProvider(allProviders[n]);
Gustav Sennton0df2c552016-06-14 15:32:19 +0100401 if ((!onlyInstalled || isInstalledPackage(packageInfo))
402 && isValidProvider(allProviders[n], packageInfo)) {
Gustav Sennton79fea482016-04-07 14:22:56 +0100403 providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
404 }
405 } catch (NameNotFoundException e) {
406 // Don't add non-existent packages
407 }
408 }
409 return providers.toArray(new ProviderAndPackageInfo[providers.size()]);
410 }
411
412 /**
413 * Fetch only the currently valid WebView packages.
414 **/
Gustav Sennton0df2c552016-06-14 15:32:19 +0100415 public WebViewProviderInfo[] getValidAndInstalledWebViewPackages() {
416 ProviderAndPackageInfo[] providersAndPackageInfos =
417 getValidWebViewPackagesAndInfos(true /* only fetch installed packages */);
Gustav Sennton79fea482016-04-07 14:22:56 +0100418 WebViewProviderInfo[] providers =
419 new WebViewProviderInfo[providersAndPackageInfos.length];
420 for(int n = 0; n < providersAndPackageInfos.length; n++) {
421 providers[n] = providersAndPackageInfos[n].provider;
422 }
423 return providers;
424 }
425
426
Hui Shu9455bd02016-04-08 13:25:26 -0700427 private static class ProviderAndPackageInfo {
Gustav Sennton79fea482016-04-07 14:22:56 +0100428 public final WebViewProviderInfo provider;
429 public final PackageInfo packageInfo;
430
431 public ProviderAndPackageInfo(WebViewProviderInfo provider, PackageInfo packageInfo) {
432 this.provider = provider;
433 this.packageInfo = packageInfo;
434 }
435 }
436
437 /**
438 * Returns either the package info of the WebView provider determined in the following way:
439 * If the user has chosen a provider then use that if it is valid,
440 * otherwise use the first package in the webview priority list that is valid.
441 *
442 */
443 private PackageInfo findPreferredWebViewPackage() {
Gustav Sennton0df2c552016-06-14 15:32:19 +0100444 ProviderAndPackageInfo[] providers =
445 getValidWebViewPackagesAndInfos(false /* onlyInstalled */);
Gustav Sennton79fea482016-04-07 14:22:56 +0100446
447 String userChosenProvider = mSystemInterface.getUserChosenWebViewProvider(mContext);
448
449 // If the user has chosen provider, use that
450 for (ProviderAndPackageInfo providerAndPackage : providers) {
451 if (providerAndPackage.provider.packageName.equals(userChosenProvider)
Gustav Sennton0df2c552016-06-14 15:32:19 +0100452 && isInstalledPackage(providerAndPackage.packageInfo)
Gustav Sennton79fea482016-04-07 14:22:56 +0100453 && isEnabledPackage(providerAndPackage.packageInfo)) {
454 return providerAndPackage.packageInfo;
455 }
456 }
457
458 // User did not choose, or the choice failed; use the most stable provider that is
Gustav Sennton0df2c552016-06-14 15:32:19 +0100459 // installed and enabled for the device owner, and available by default (not through
460 // user choice).
Gustav Sennton79fea482016-04-07 14:22:56 +0100461 for (ProviderAndPackageInfo providerAndPackage : providers) {
462 if (providerAndPackage.provider.availableByDefault
Gustav Sennton0df2c552016-06-14 15:32:19 +0100463 && isInstalledPackage(providerAndPackage.packageInfo)
Gustav Sennton79fea482016-04-07 14:22:56 +0100464 && isEnabledPackage(providerAndPackage.packageInfo)) {
465 return providerAndPackage.packageInfo;
466 }
467 }
468
Gustav Sennton0df2c552016-06-14 15:32:19 +0100469 // Could not find any installed and enabled package either, use the most stable and
470 // default-available provider.
Gustav Sennton79fea482016-04-07 14:22:56 +0100471 for (ProviderAndPackageInfo providerAndPackage : providers) {
Gustav Senntona9159042016-04-11 16:32:52 +0100472 if (providerAndPackage.provider.availableByDefault) {
473 return providerAndPackage.packageInfo;
474 }
Gustav Sennton79fea482016-04-07 14:22:56 +0100475 }
476
477 mAnyWebViewInstalled = false;
478 throw new WebViewFactory.MissingWebViewPackageException(
479 "Could not find a loadable WebView package");
480 }
481
482 public void notifyRelroCreationCompleted() {
483 synchronized (mLock) {
484 mNumRelroCreationsFinished++;
485 checkIfRelrosDoneLocked();
486 }
487 }
488
489 public WebViewProviderResponse waitForAndGetProvider() {
490 PackageInfo webViewPackage = null;
491 final long NS_PER_MS = 1000000;
492 final long timeoutTimeMs = System.nanoTime() / NS_PER_MS + WAIT_TIMEOUT_MS;
493 boolean webViewReady = false;
494 int webViewStatus = WebViewFactory.LIBLOAD_SUCCESS;
495 synchronized (mLock) {
496 webViewReady = webViewIsReadyLocked();
497 while (!webViewReady) {
498 final long timeNowMs = System.nanoTime() / NS_PER_MS;
499 if (timeNowMs >= timeoutTimeMs) break;
500 try {
501 mLock.wait(timeoutTimeMs - timeNowMs);
502 } catch (InterruptedException e) {}
503 webViewReady = webViewIsReadyLocked();
504 }
505 // Make sure we return the provider that was used to create the relro file
506 webViewPackage = mCurrentWebViewPackage;
507 if (webViewReady) {
508 } else if (!mAnyWebViewInstalled) {
509 webViewStatus = WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
510 } else {
511 // Either the current relro creation isn't done yet, or the new relro creatioin
512 // hasn't kicked off yet (the last relro creation used an out-of-date WebView).
513 webViewStatus = WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO;
Gustav Senntonfd07efa2016-05-23 13:09:03 +0100514 Slog.e(TAG, "Timed out waiting for relro creation, relros started "
515 + mNumRelroCreationsStarted
516 + " relros finished " + mNumRelroCreationsFinished
517 + " package dirty? " + mWebViewPackageDirty);
Gustav Sennton79fea482016-04-07 14:22:56 +0100518 }
519 }
520 if (!webViewReady) Slog.w(TAG, "creating relro file timed out");
521 return new WebViewProviderResponse(webViewPackage, webViewStatus);
522 }
523
524 public String getCurrentWebViewPackageName() {
525 synchronized(mLock) {
526 if (mCurrentWebViewPackage == null)
527 return null;
528 return mCurrentWebViewPackage.packageName;
529 }
530 }
531
532 /**
533 * Returns whether WebView is ready and is not going to go through its preparation phase
534 * again directly.
535 */
536 private boolean webViewIsReadyLocked() {
537 return !mWebViewPackageDirty
538 && (mNumRelroCreationsStarted == mNumRelroCreationsFinished)
539 // The current package might be replaced though we haven't received an intent
540 // declaring this yet, the following flag makes anyone loading WebView to wait in
541 // this case.
542 && mAnyWebViewInstalled;
543 }
544
545 private void checkIfRelrosDoneLocked() {
546 if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
547 if (mWebViewPackageDirty) {
548 mWebViewPackageDirty = false;
549 // If we have changed provider since we started the relro creation we need to
550 // redo the whole process using the new package instead.
Gustav Sennton53b78242016-04-07 15:56:10 +0100551 try {
552 PackageInfo newPackage = findPreferredWebViewPackage();
553 onWebViewProviderChanged(newPackage);
554 } catch (WebViewFactory.MissingWebViewPackageException e) {
555 // If we can't find any valid WebView package we are now in a state where
556 // mAnyWebViewInstalled is false, so loading WebView will be blocked and we
557 // should simply wait until we receive an intent declaring a new package was
558 // installed.
559 }
Gustav Sennton79fea482016-04-07 14:22:56 +0100560 } else {
561 mLock.notifyAll();
562 }
563 }
564 }
565
566 /**
Hui Shub5f554a2016-04-20 17:17:44 -0700567 * Both versionCodes should be from a WebView provider package implemented by Chromium.
568 * VersionCodes from other kinds of packages won't make any sense in this method.
569 *
570 * An introduction to Chromium versionCode scheme:
571 * "BBBBPPPAX"
572 * BBBB: 4 digit branch number. It monotonically increases over time.
573 * PPP: patch number in the branch. It is padded with zeroes to the left. These three digits may
574 * change their meaning in the future.
575 * A: architecture digit.
576 * X: A digit to differentiate APKs for other reasons.
577 *
578 * This method takes the "BBBB" of versionCodes and compare them.
579 *
580 * @return true if versionCode1 is higher than or equal to versionCode2.
581 */
582 private static boolean versionCodeGE(int versionCode1, int versionCode2) {
583 int v1 = versionCode1 / 100000;
584 int v2 = versionCode2 / 100000;
585
586 return v1 >= v2;
587 }
588
589 /**
Gustav Sennton79fea482016-04-07 14:22:56 +0100590 * Returns whether this provider is valid for use as a WebView provider.
591 */
592 public boolean isValidProvider(WebViewProviderInfo configInfo,
593 PackageInfo packageInfo) {
Hui Shub5f554a2016-04-20 17:17:44 -0700594 if (!versionCodeGE(packageInfo.versionCode, getMinimumVersionCode())
Gustav Sennton79fea482016-04-07 14:22:56 +0100595 && !mSystemInterface.systemIsDebuggable()) {
Hui Shub5f554a2016-04-20 17:17:44 -0700596 // Webview providers may be downgraded arbitrarily low, prevent that by enforcing
597 // minimum version code. This check is only enforced for user builds.
Gustav Sennton79fea482016-04-07 14:22:56 +0100598 return false;
599 }
600 if (providerHasValidSignature(configInfo, packageInfo, mSystemInterface) &&
601 WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) != null) {
602 return true;
603 }
604 return false;
605 }
606
607 /**
608 * Gets the minimum version code allowed for a valid provider. It is the minimum versionCode
609 * of all available-by-default and non-fallback WebView provider packages. If there is no
610 * such WebView provider package on the system, then return -1, which means all positive
611 * versionCode WebView packages are accepted.
612 */
613 private int getMinimumVersionCode() {
614 if (mMinimumVersionCode > 0) {
615 return mMinimumVersionCode;
616 }
617
618 for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
619 if (provider.availableByDefault && !provider.isFallback) {
620 try {
621 int versionCode =
622 mSystemInterface.getFactoryPackageVersion(provider.packageName);
623 if (mMinimumVersionCode < 0 || versionCode < mMinimumVersionCode) {
624 mMinimumVersionCode = versionCode;
625 }
626 } catch (NameNotFoundException e) {
627 // Safe to ignore.
628 }
629 }
630 }
631
632 return mMinimumVersionCode;
633 }
634 }
635
636 private static boolean providerHasValidSignature(WebViewProviderInfo provider,
637 PackageInfo packageInfo, SystemInterface systemInterface) {
638 if (systemInterface.systemIsDebuggable()) {
639 return true;
640 }
641 Signature[] packageSignatures;
642 // If no signature is declared, instead check whether the package is included in the
643 // system.
644 if (provider.signatures == null || provider.signatures.length == 0) {
645 return packageInfo.applicationInfo.isSystemApp();
646 }
647 packageSignatures = packageInfo.signatures;
648 if (packageSignatures.length != 1)
649 return false;
650
651 final byte[] packageSignature = packageSignatures[0].toByteArray();
652 // Return whether the package signature matches any of the valid signatures
653 for (String signature : provider.signatures) {
654 final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
655 if (Arrays.equals(packageSignature, validSignature))
656 return true;
657 }
658 return false;
659 }
660
661 /**
662 * Returns whether the given package is enabled.
663 * This state can be changed by the user from Settings->Apps
664 */
665 private static boolean isEnabledPackage(PackageInfo packageInfo) {
666 return packageInfo.applicationInfo.enabled;
667 }
668
Gustav Sennton0df2c552016-06-14 15:32:19 +0100669 /**
670 * Return true if the package is installed and not hidden
671 */
672 private static boolean isInstalledPackage(PackageInfo packageInfo) {
673 return (((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0)
674 && ((packageInfo.applicationInfo.privateFlags
675 & ApplicationInfo.PRIVATE_FLAG_HIDDEN) == 0));
676 }
677
Robert Sesekded20982016-08-15 13:59:13 -0400678 /**
679 * Watches for changes in the WEBVIEW_MULTIPROCESS setting and lets
680 * the WebViewZygote know, so it can start or stop the zygote process
681 * appropriately.
682 */
683 private class SettingsObserver extends ContentObserver {
Robert Sesekded20982016-08-15 13:59:13 -0400684 SettingsObserver() {
685 super(new Handler());
686
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100687 mSystemInterface.registerContentObserver(mContext, this);
Robert Sesekded20982016-08-15 13:59:13 -0400688
689 // Push the current value of the setting immediately.
690 notifyZygote();
691 }
692
693 @Override
694 public void onChange(boolean selfChange, Uri uri) {
695 notifyZygote();
696 }
697
698 private void notifyZygote() {
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100699 mSystemInterface.setMultiProcessEnabledFromContext(mContext);
Robert Sesekded20982016-08-15 13:59:13 -0400700 }
701 }
Gustav Sennton79fea482016-04-07 14:22:56 +0100702}