blob: ebec44554210aebd1e57dac6abbb6d34748b0cbc [file] [log] [blame]
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +01001/*
2 * Copyright (C) 2012 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 */
16
17package com.android.server.webkit;
18
Ben Murdochdc00a842014-07-17 14:55:00 +010019import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
Hui Shu9e8c0582016-03-24 17:02:58 -070023import android.content.pm.ApplicationInfo;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000024import android.content.pm.PackageInfo;
25import android.content.pm.PackageManager;
Gustav Senntondbf5eb02016-03-30 14:53:03 +010026import android.content.pm.PackageManager.NameNotFoundException;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000027import android.content.pm.Signature;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010028import android.os.Binder;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000029import android.os.PatternMatcher;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010030import android.os.Process;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000031import android.os.ResultReceiver;
Gustav Sennton23875b22016-02-09 14:11:33 +000032import android.os.UserHandle;
Gustav Senntondbf5eb02016-03-30 14:53:03 +010033import android.util.Base64;
Primiano Tucci810c0522014-07-25 18:03:16 +010034import android.util.Slog;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010035import android.webkit.IWebViewUpdateService;
Gustav Sennton8b179262016-03-14 11:31:14 +000036import android.webkit.WebViewFactory;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000037import android.webkit.WebViewProviderInfo;
38import android.webkit.WebViewProviderResponse;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010039
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010040import com.android.server.SystemService;
41
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000042import java.io.FileDescriptor;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000043import java.util.ArrayList;
44import java.util.Arrays;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000045import java.util.List;
46
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010047/**
48 * Private service to wait for the updatable WebView to be ready for use.
49 * @hide
50 */
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010051public class WebViewUpdateService extends SystemService {
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010052
53 private static final String TAG = "WebViewUpdateService";
Gustav Sennton6ce92c92015-10-23 11:10:39 +010054
Ben Murdochdc00a842014-07-17 14:55:00 +010055 private BroadcastReceiver mWebViewUpdatedReceiver;
Gustav Sennton065b7e62016-04-01 15:11:43 +010056 private SystemInterface mSystemInterface;
Ben Murdochdc00a842014-07-17 14:55:00 +010057
Gustav Sennton3a6e6b22016-04-05 14:09:09 +010058 static final int PACKAGE_CHANGED = 0;
59 static final int PACKAGE_ADDED = 1;
60 static final int PACKAGE_ADDED_REPLACED = 2;
61 static final int PACKAGE_REMOVED = 3;
62
63 private WebViewUpdater mWebViewUpdater;
64
Ben Murdochdc00a842014-07-17 14:55:00 +010065 public WebViewUpdateService(Context context) {
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010066 super(context);
Gustav Sennton065b7e62016-04-01 15:11:43 +010067 mSystemInterface = new SystemImpl();
Gustav Sennton3a6e6b22016-04-05 14:09:09 +010068 mWebViewUpdater = new WebViewUpdater(getContext(), mSystemInterface);
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010069 }
70
71 @Override
72 public void onStart() {
Ben Murdochdc00a842014-07-17 14:55:00 +010073 mWebViewUpdatedReceiver = new BroadcastReceiver() {
74 @Override
75 public void onReceive(Context context, Intent intent) {
Gustav Sennton3a6e6b22016-04-05 14:09:09 +010076 switch (intent.getAction()) {
77 case Intent.ACTION_PACKAGE_REMOVED:
78 // When a package is replaced we will receive two intents, one
79 // representing the removal of the old package and one representing the
80 // addition of the new package.
81 // In the case where we receive an intent to remove the old version of
82 // the package that is being replaced we early-out here so that we don't
83 // run the update-logic twice.
84 if (intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) return;
85 packageStateChanged(packageNameFromIntent(intent), PACKAGE_REMOVED);
86 break;
87 case Intent.ACTION_PACKAGE_CHANGED:
88 // Ensure that we only heed PACKAGE_CHANGED intents if they change an
89 // entire package, not just a component
90 if (entirePackageChanged(intent)) {
91 packageStateChanged(packageNameFromIntent(intent), PACKAGE_CHANGED);
Gustav Sennton6258dcd2015-10-30 19:25:37 +000092 }
Gustav Sennton3a6e6b22016-04-05 14:09:09 +010093 break;
94 case Intent.ACTION_PACKAGE_ADDED:
95 packageStateChanged(packageNameFromIntent(intent),
96 (intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)
97 ? PACKAGE_ADDED_REPLACED : PACKAGE_ADDED));
98 break;
99 case Intent.ACTION_USER_ADDED:
100 int userId =
101 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
102 handleNewUser(userId);
103 break;
Ben Murdochdc00a842014-07-17 14:55:00 +0100104 }
105 }
106 };
107 IntentFilter filter = new IntentFilter();
Gustav Sennton3098cf22015-11-10 03:33:09 +0000108 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
109 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000110 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Ben Murdochdc00a842014-07-17 14:55:00 +0100111 filter.addDataScheme("package");
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000112 // Make sure we only receive intents for WebView packages from our config file.
Gustav Sennton065b7e62016-04-01 15:11:43 +0100113 for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000114 filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
115 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100116 getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100117
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000118 IntentFilter userAddedFilter = new IntentFilter();
119 userAddedFilter.addAction(Intent.ACTION_USER_ADDED);
120 getContext().registerReceiver(mWebViewUpdatedReceiver, userAddedFilter);
121
Torne (Richard Coles)fc19b0a2016-02-01 16:16:57 +0000122 publishBinderService("webviewupdate", new BinderService(), true /*allowIsolated*/);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100123 }
Ben Murdochdc00a842014-07-17 14:55:00 +0100124
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100125 private void packageStateChanged(String packageName, int changedState) {
126 updateFallbackState(packageName, changedState);
127 mWebViewUpdater.packageStateChanged(packageName, changedState);
128 }
129
130 public void prepareWebViewInSystemServer() {
131 updateFallbackStateOnBoot();
132 mWebViewUpdater.prepareWebViewInSystemServer();
133 }
134
135 private static String packageNameFromIntent(Intent intent) {
136 return intent.getDataString().substring("package:".length());
137 }
138
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100139 private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000140 for (WebViewProviderInfo provider : providers) {
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100141 if (provider.availableByDefault && !provider.isFallback) {
142 try {
Gustav Sennton065b7e62016-04-01 15:11:43 +0100143 PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(provider);
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100144 if (isEnabledPackage(packageInfo)
145 && mWebViewUpdater.isValidProvider(provider, packageInfo)) {
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100146 return true;
147 }
148 } catch (NameNotFoundException e) {
149 // A non-existent provider is neither valid nor enabled
150 }
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000151 }
152 }
153 return false;
154 }
155
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000156 /**
157 * Called when a new user has been added to update the state of its fallback package.
158 */
159 void handleNewUser(int userId) {
Gustav Sennton065b7e62016-04-01 15:11:43 +0100160 if (!mSystemInterface.isFallbackLogicEnabled()) return;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000161
Gustav Sennton065b7e62016-04-01 15:11:43 +0100162 WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000163 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
164 if (fallbackProvider == null) return;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000165
Gustav Sennton065b7e62016-04-01 15:11:43 +0100166 mSystemInterface.enablePackageForUser(fallbackProvider.packageName,
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100167 !existsValidNonFallbackProvider(webviewProviders), userId);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000168 }
169
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100170 public void updateFallbackStateOnBoot() {
171 WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
172 updateFallbackState(webviewProviders, true);
173 }
174
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000175 /**
176 * Handle the enabled-state of our fallback package, i.e. if there exists some non-fallback
177 * package that is valid (and available by default) then disable the fallback package,
178 * otherwise, enable the fallback package.
179 */
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100180 public void updateFallbackState(String changedPackage, int changedState) {
Gustav Sennton065b7e62016-04-01 15:11:43 +0100181 if (!mSystemInterface.isFallbackLogicEnabled()) return;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000182
Gustav Sennton065b7e62016-04-01 15:11:43 +0100183 WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000184
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100185 // A package was changed / updated / downgraded, early out if it is not one of the
186 // webview packages that are available by default.
187 boolean changedPackageAvailableByDefault = false;
188 for (WebViewProviderInfo provider : webviewProviders) {
189 if (provider.packageName.equals(changedPackage)) {
190 if (provider.availableByDefault) {
191 changedPackageAvailableByDefault = true;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000192 }
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100193 break;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000194 }
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000195 }
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100196 if (!changedPackageAvailableByDefault) return;
197 updateFallbackState(webviewProviders, false);
198 }
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000199
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100200 private void updateFallbackState(WebViewProviderInfo[] webviewProviders, boolean isBoot) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000201 // If there exists a valid and enabled non-fallback package - disable the fallback
202 // package, otherwise, enable it.
203 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
204 if (fallbackProvider == null) return;
205 boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
206
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100207 boolean isFallbackEnabled = false;
208 try {
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100209 isFallbackEnabled = isEnabledPackage(
210 mSystemInterface.getPackageInfoForProvider(fallbackProvider));
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100211 } catch (NameNotFoundException e) {
212 }
213
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000214 if (existsValidNonFallbackProvider
215 // During an OTA the primary user's WebView state might differ from other users', so
216 // ignore the state of that user during boot.
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100217 && (isFallbackEnabled || isBoot)) {
218 mSystemInterface.uninstallAndDisablePackageForAllUsers(getContext(),
Gustav Sennton065b7e62016-04-01 15:11:43 +0100219 fallbackProvider.packageName);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000220 } else if (!existsValidNonFallbackProvider
221 // During an OTA the primary user's WebView state might differ from other users', so
222 // ignore the state of that user during boot.
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100223 && (!isFallbackEnabled || isBoot)) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000224 // Enable the fallback package for all users.
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100225 mSystemInterface.enablePackageForAllUsers(getContext(),
226 fallbackProvider.packageName, true);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000227 }
228 }
229
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000230 /**
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100231 * Returns the only fallback provider in the set of given packages, or null if there is none.
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000232 */
233 private static WebViewProviderInfo getFallbackProvider(WebViewProviderInfo[] webviewPackages) {
234 for (WebViewProviderInfo provider : webviewPackages) {
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100235 if (provider.isFallback) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000236 return provider;
237 }
238 }
239 return null;
240 }
241
Gustav Sennton8b179262016-03-14 11:31:14 +0000242 private boolean isFallbackPackage(String packageName) {
Gustav Sennton065b7e62016-04-01 15:11:43 +0100243 if (packageName == null || !mSystemInterface.isFallbackLogicEnabled()) return false;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000244
Gustav Sennton065b7e62016-04-01 15:11:43 +0100245 WebViewProviderInfo[] webviewPackages = mSystemInterface.getWebViewPackages();
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000246 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
247 return (fallbackProvider != null
248 && packageName.equals(fallbackProvider.packageName));
249 }
250
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000251 /**
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100252 * Class that decides what WebView implementation to use and prepares that implementation for
253 * use.
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000254 */
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100255 private static class WebViewUpdater {
256 private Context mContext;
257 private SystemInterface mSystemInterface;
258 private int mMinimumVersionCode = -1;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000259
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100260 public WebViewUpdater(Context context, SystemInterface systemInterface) {
261 mContext = context;
262 mSystemInterface = systemInterface;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000263 }
264
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100265 private static final int WAIT_TIMEOUT_MS = 4500; // KEY_DISPATCHING_TIMEOUT is 5000.
Gustav Sennton27f13de2016-01-05 20:22:02 +0000266
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100267 // Keeps track of the number of running relro creations
268 private int mNumRelroCreationsStarted = 0;
269 private int mNumRelroCreationsFinished = 0;
270 // Implies that we need to rerun relro creation because we are using an out-of-date package
271 private boolean mWebViewPackageDirty = false;
272 private boolean mAnyWebViewInstalled = false;
Gustav Sennton27f13de2016-01-05 20:22:02 +0000273
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100274 private int NUMBER_OF_RELROS_UNKNOWN = Integer.MAX_VALUE;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000275
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100276 // The WebView package currently in use (or the one we are preparing).
277 private PackageInfo mCurrentWebViewPackage = null;
Gustav Sennton065b7e62016-04-01 15:11:43 +0100278
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100279 private Object mLock = new Object();
Hui Shu9e8c0582016-03-24 17:02:58 -0700280
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100281 public void packageStateChanged(String packageName, int changedState) {
282 for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
283 String webviewPackage = provider.packageName;
284
285 if (webviewPackage.equals(packageName)) {
286 boolean updateWebView = false;
287 boolean removedOrChangedOldPackage = false;
288 String oldProviderName = null;
289 PackageInfo newPackage = null;
290 synchronized(mLock) {
291 try {
292 newPackage = findPreferredWebViewPackage();
293 if (mCurrentWebViewPackage != null)
294 oldProviderName = mCurrentWebViewPackage.packageName;
295 // Only trigger update actions if the updated package is the one
296 // that will be used, or the one that was in use before the
297 // update, or if we haven't seen a valid WebView package before.
298 updateWebView =
299 provider.packageName.equals(newPackage.packageName)
300 || provider.packageName.equals(oldProviderName)
301 || mCurrentWebViewPackage == null;
302 // We removed the old package if we received an intent to remove
303 // or replace the old package.
304 removedOrChangedOldPackage =
305 provider.packageName.equals(oldProviderName);
306 if (updateWebView) {
307 onWebViewProviderChanged(newPackage);
308 }
309 } catch (WebViewFactory.MissingWebViewPackageException e) {
310 Slog.e(TAG, "Could not find valid WebView package to create " +
311 "relro with " + e);
312 }
Hui Shu9e8c0582016-03-24 17:02:58 -0700313 }
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100314 if(updateWebView && !removedOrChangedOldPackage
315 && oldProviderName != null) {
316 // If the provider change is the result of adding or replacing a
317 // package that was not the previous provider then we must kill
318 // packages dependent on the old package ourselves. The framework
319 // only kills dependents of packages that are being removed.
320 mSystemInterface.killPackageDependents(oldProviderName);
321 }
322 return;
Hui Shu9e8c0582016-03-24 17:02:58 -0700323 }
324 }
325 }
326
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100327 public void prepareWebViewInSystemServer() {
328 try {
329 synchronized(mLock) {
330 mCurrentWebViewPackage = findPreferredWebViewPackage();
331 onWebViewProviderChanged(mCurrentWebViewPackage);
332 }
333 } catch (Throwable t) {
334 // Log and discard errors at this stage as we must not crash the system server.
335 Slog.e(TAG, "error preparing webview provider from system server", t);
336 }
337 }
Hui Shu9e8c0582016-03-24 17:02:58 -0700338
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100339 /**
340 * Change WebView provider and provider setting and kill packages using the old provider.
341 * Return the new provider (in case we are in the middle of creating relro files this new
342 * provider will not be in use directly, but will when the relros are done).
343 */
344 public String changeProviderAndSetting(String newProviderName) {
345 PackageInfo oldPackage = null;
346 PackageInfo newPackage = null;
347 synchronized(mLock) {
348 oldPackage = mCurrentWebViewPackage;
349 mSystemInterface.updateUserSetting(mContext, newProviderName);
350
351 try {
352 newPackage = findPreferredWebViewPackage();
353 if (oldPackage != null
354 && newPackage.packageName.equals(oldPackage.packageName)) {
355 // If we don't perform the user change, revert the settings change.
356 mSystemInterface.updateUserSetting(mContext, newPackage.packageName);
357 return newPackage.packageName;
358 }
359 } catch (WebViewFactory.MissingWebViewPackageException e) {
360 Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView " +
361 "package " + e);
362 // If we don't perform the user change but don't have an installed WebView
363 // package, we will have changed the setting and it will be used when a package
364 // is available.
365 return newProviderName;
366 }
367 onWebViewProviderChanged(newPackage);
368 }
369 // Kill apps using the old provider
370 if (oldPackage != null) {
371 mSystemInterface.killPackageDependents(oldPackage.packageName);
372 }
373 return newPackage.packageName;
374 }
375
376 /**
377 * This is called when we change WebView provider, either when the current provider is
378 * updated or a new provider is chosen / takes precedence.
379 */
380 private void onWebViewProviderChanged(PackageInfo newPackage) {
381 synchronized(mLock) {
382 mAnyWebViewInstalled = true;
383 if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
384 mCurrentWebViewPackage = newPackage;
385 mSystemInterface.updateUserSetting(mContext, newPackage.packageName);
386
387 // The relro creations might 'finish' (not start at all) before
388 // WebViewFactory.onWebViewProviderChanged which means we might not know the
389 // number of started creations before they finish.
390 mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN;
391 mNumRelroCreationsFinished = 0;
392 mNumRelroCreationsStarted =
393 mSystemInterface.onWebViewProviderChanged(newPackage);
394 // If the relro creations finish before we know the number of started creations
395 // we will have to do any cleanup/notifying here.
396 checkIfRelrosDoneLocked();
397 } else {
398 mWebViewPackageDirty = true;
399 }
400 }
401 }
402
403 private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos() {
404 WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages();
405 List<ProviderAndPackageInfo> providers = new ArrayList<>();
406 for(int n = 0; n < allProviders.length; n++) {
407 try {
408 PackageInfo packageInfo =
409 mSystemInterface.getPackageInfoForProvider(allProviders[n]);
410 if (isValidProvider(allProviders[n], packageInfo)) {
411 providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
412 }
413 } catch (NameNotFoundException e) {
414 // Don't add non-existent packages
415 }
416 }
417 return providers.toArray(new ProviderAndPackageInfo[providers.size()]);
418 }
419
420 /**
421 * Fetch only the currently valid WebView packages.
422 **/
423 public WebViewProviderInfo[] getValidWebViewPackages() {
424 ProviderAndPackageInfo[] providersAndPackageInfos = getValidWebViewPackagesAndInfos();
425 WebViewProviderInfo[] providers =
426 new WebViewProviderInfo[providersAndPackageInfos.length];
427 for(int n = 0; n < providersAndPackageInfos.length; n++) {
428 providers[n] = providersAndPackageInfos[n].provider;
429 }
430 return providers;
431 }
432
433
434 private class ProviderAndPackageInfo {
435 public final WebViewProviderInfo provider;
436 public final PackageInfo packageInfo;
437
438 public ProviderAndPackageInfo(WebViewProviderInfo provider, PackageInfo packageInfo) {
439 this.provider = provider;
440 this.packageInfo = packageInfo;
441 }
442 }
443
444 /**
445 * Returns either the package info of the WebView provider determined in the following way:
446 * If the user has chosen a provider then use that if it is valid,
447 * otherwise use the first package in the webview priority list that is valid.
448 *
449 */
450 private PackageInfo findPreferredWebViewPackage() {
451 ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos();
452
453 String userChosenProvider = mSystemInterface.getUserChosenWebViewProvider(mContext);
454
455 // If the user has chosen provider, use that
456 for (ProviderAndPackageInfo providerAndPackage : providers) {
457 if (providerAndPackage.provider.packageName.equals(userChosenProvider)
458 && isEnabledPackage(providerAndPackage.packageInfo)) {
459 return providerAndPackage.packageInfo;
460 }
461 }
462
463 // User did not choose, or the choice failed; use the most stable provider that is
464 // enabled and available by default (not through user choice).
465 for (ProviderAndPackageInfo providerAndPackage : providers) {
466 if (providerAndPackage.provider.availableByDefault
467 && isEnabledPackage(providerAndPackage.packageInfo)) {
468 return providerAndPackage.packageInfo;
469 }
470 }
471
472 // Could not find any enabled package either, use the most stable provider.
473 for (ProviderAndPackageInfo providerAndPackage : providers) {
474 return providerAndPackage.packageInfo;
475 }
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;
514 }
515 }
516 if (!webViewReady) Slog.w(TAG, "creating relro file timed out");
517 return new WebViewProviderResponse(webViewPackage, webViewStatus);
518 }
519
520 public String getCurrentWebViewPackageName() {
521 synchronized(mLock) {
522 if (mCurrentWebViewPackage == null)
523 return null;
524 return mCurrentWebViewPackage.packageName;
525 }
526 }
527
528 /**
529 * Returns whether WebView is ready and is not going to go through its preparation phase
530 * again directly.
531 */
532 private boolean webViewIsReadyLocked() {
533 return !mWebViewPackageDirty
534 && (mNumRelroCreationsStarted == mNumRelroCreationsFinished)
535 // The current package might be replaced though we haven't received an intent
536 // declaring this yet, the following flag makes anyone loading WebView to wait in
537 // this case.
538 && mAnyWebViewInstalled;
539 }
540
541 private void checkIfRelrosDoneLocked() {
542 if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
543 if (mWebViewPackageDirty) {
544 mWebViewPackageDirty = false;
545 // If we have changed provider since we started the relro creation we need to
546 // redo the whole process using the new package instead.
547 PackageInfo newPackage = findPreferredWebViewPackage();
548 onWebViewProviderChanged(newPackage);
549 } else {
550 mLock.notifyAll();
551 }
552 }
553 }
554
555 /**
556 * Returns whether this provider is valid for use as a WebView provider.
557 */
558 public boolean isValidProvider(WebViewProviderInfo configInfo,
559 PackageInfo packageInfo) {
560 if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0
561 && packageInfo.versionCode < getMinimumVersionCode()
562 && !mSystemInterface.systemIsDebuggable()) {
563 // Non-system package webview providers may be downgraded arbitrarily low, prevent
564 // that by enforcing minimum version code. This check is only enforced for user
565 // builds.
566 return false;
567 }
568 if (providerHasValidSignature(configInfo, packageInfo, mSystemInterface) &&
569 WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) != null) {
570 return true;
571 }
Hui Shu9e8c0582016-03-24 17:02:58 -0700572 return false;
573 }
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100574
575 /**
576 * Gets the minimum version code allowed for a valid provider. It is the minimum versionCode
577 * of all available-by-default and non-fallback WebView provider packages. If there is no
578 * such WebView provider package on the system, then return -1, which means all positive
579 * versionCode WebView packages are accepted.
580 */
581 private int getMinimumVersionCode() {
582 if (mMinimumVersionCode > 0) {
583 return mMinimumVersionCode;
584 }
585
586 for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
587 if (provider.availableByDefault && !provider.isFallback) {
588 try {
589 int versionCode =
590 mSystemInterface.getFactoryPackageVersion(provider.packageName);
591 if (mMinimumVersionCode < 0 || versionCode < mMinimumVersionCode) {
592 mMinimumVersionCode = versionCode;
593 }
594 } catch (PackageManager.NameNotFoundException e) {
595 // Safe to ignore.
596 }
597 }
598 }
599
600 return mMinimumVersionCode;
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100601 }
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100602 }
603
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100604 private static boolean providerHasValidSignature(WebViewProviderInfo provider,
605 PackageInfo packageInfo, SystemInterface systemInterface) {
606 if (systemInterface.systemIsDebuggable()) {
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100607 return true;
Gustav Sennton065b7e62016-04-01 15:11:43 +0100608 }
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100609 Signature[] packageSignatures;
610 // If no signature is declared, instead check whether the package is included in the
611 // system.
612 if (provider.signatures == null || provider.signatures.length == 0) {
613 return packageInfo.applicationInfo.isSystemApp();
614 }
615 packageSignatures = packageInfo.signatures;
616 if (packageSignatures.length != 1)
617 return false;
618
619 final byte[] packageSignature = packageSignatures[0].toByteArray();
620 // Return whether the package signature matches any of the valid signatures
621 for (String signature : provider.signatures) {
622 final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
623 if (Arrays.equals(packageSignature, validSignature))
624 return true;
625 }
626 return false;
627 }
628
629 /**
630 * Returns whether the given package is enabled.
631 * This state can be changed by the user from Settings->Apps
632 */
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100633 private static boolean isEnabledPackage(PackageInfo packageInfo) {
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100634 return packageInfo.applicationInfo.enabled;
635 }
636
Gustav Sennton065b7e62016-04-01 15:11:43 +0100637 /**
638 * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather
639 * than just one of its components).
640 * @hide
641 */
642 public static boolean entirePackageChanged(Intent intent) {
643 String[] componentList =
644 intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
645 return Arrays.asList(componentList).contains(
646 intent.getDataString().substring("package:".length()));
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100647 }
648
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100649 private class BinderService extends IWebViewUpdateService.Stub {
650
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000651 @Override
652 public void onShellCommand(FileDescriptor in, FileDescriptor out,
653 FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
654 (new WebViewUpdateServiceShellCommand(this)).exec(
655 this, in, out, err, args, resultReceiver);
656 }
657
658
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100659 /**
660 * The shared relro process calls this to notify us that it's done trying to create a relro
661 * file. This method gets called even if the relro creation has failed or the process
662 * crashed.
663 */
664 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000665 public void notifyRelroCreationCompleted() {
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100666 // Verify that the caller is either the shared relro process (nominal case) or the
667 // system server (only in the case the relro process crashes and we get here via the
668 // crashHandler).
669 if (Binder.getCallingUid() != Process.SHARED_RELRO_UID &&
670 Binder.getCallingUid() != Process.SYSTEM_UID) {
671 return;
672 }
673
Gustav Sennton275d13c2016-02-24 10:58:09 +0000674 long callingId = Binder.clearCallingIdentity();
675 try {
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100676 WebViewUpdateService.this.mWebViewUpdater.notifyRelroCreationCompleted();
Gustav Sennton275d13c2016-02-24 10:58:09 +0000677 } finally {
678 Binder.restoreCallingIdentity(callingId);
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100679 }
680 }
681
682 /**
683 * WebViewFactory calls this to block WebView loading until the relro file is created.
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000684 * Returns the WebView provider for which we create relro files.
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100685 */
686 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000687 public WebViewProviderResponse waitForAndGetProvider() {
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100688 // The WebViewUpdateService depends on the prepareWebViewInSystemServer call, which
689 // happens later (during the PHASE_ACTIVITY_MANAGER_READY) in SystemServer.java. If
690 // another service there tries to bring up a WebView in the between, the wait below
691 // would deadlock without the check below.
692 if (Binder.getCallingPid() == Process.myPid()) {
693 throw new IllegalStateException("Cannot create a WebView from the SystemServer");
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100694 }
695
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100696 return WebViewUpdateService.this.mWebViewUpdater.waitForAndGetProvider();
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000697 }
698
699 /**
700 * This is called from DeveloperSettings when the user changes WebView provider.
701 */
702 @Override // Binder call
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000703 public String changeProviderAndSetting(String newProvider) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000704 if (getContext().checkCallingPermission(
705 android.Manifest.permission.WRITE_SECURE_SETTINGS)
706 != PackageManager.PERMISSION_GRANTED) {
707 String msg = "Permission Denial: changeProviderAndSetting() from pid="
708 + Binder.getCallingPid()
709 + ", uid=" + Binder.getCallingUid()
710 + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
711 Slog.w(TAG, msg);
712 throw new SecurityException(msg);
713 }
714
Gustav Senntonab3b6b12016-03-16 17:38:42 +0000715 long callingId = Binder.clearCallingIdentity();
716 try {
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100717 return WebViewUpdateService.this.mWebViewUpdater.changeProviderAndSetting(
718 newProvider);
Gustav Senntonab3b6b12016-03-16 17:38:42 +0000719 } finally {
720 Binder.restoreCallingIdentity(callingId);
721 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000722 }
723
724 @Override // Binder call
725 public WebViewProviderInfo[] getValidWebViewPackages() {
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100726 return WebViewUpdateService.this.mWebViewUpdater.getValidWebViewPackages();
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000727 }
728
729 @Override // Binder call
Gustav Sennton8b179262016-03-14 11:31:14 +0000730 public WebViewProviderInfo[] getAllWebViewPackages() {
Gustav Sennton065b7e62016-04-01 15:11:43 +0100731 return WebViewUpdateService.this.mSystemInterface.getWebViewPackages();
Gustav Sennton8b179262016-03-14 11:31:14 +0000732 }
733
734 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000735 public String getCurrentWebViewPackageName() {
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100736 return WebViewUpdateService.this.mWebViewUpdater.getCurrentWebViewPackageName();
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100737 }
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000738
739 @Override // Binder call
740 public boolean isFallbackPackage(String packageName) {
Gustav Sennton8b179262016-03-14 11:31:14 +0000741 return WebViewUpdateService.this.isFallbackPackage(packageName);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000742 }
743
744 @Override // Binder call
745 public void enableFallbackLogic(boolean enable) {
746 if (getContext().checkCallingPermission(
747 android.Manifest.permission.WRITE_SECURE_SETTINGS)
748 != PackageManager.PERMISSION_GRANTED) {
749 String msg = "Permission Denial: enableFallbackLogic() from pid="
750 + Binder.getCallingPid()
751 + ", uid=" + Binder.getCallingUid()
752 + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
753 Slog.w(TAG, msg);
754 throw new SecurityException(msg);
755 }
756
Gustav Sennton065b7e62016-04-01 15:11:43 +0100757 WebViewUpdateService.this.mSystemInterface.enableFallbackLogic(enable);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000758 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100759 }
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100760}