blob: 50699f8ccf4a6c2a83c30ad8f615147f6ac3a7c2 [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
Gustav Sennton6258dcd2015-10-30 19:25:37 +000019import android.app.ActivityManagerNative;
20import android.app.AppGlobals;
Ben Murdochdc00a842014-07-17 14:55:00 +010021import android.content.BroadcastReceiver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000025import android.content.pm.ApplicationInfo;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000026import android.content.pm.IPackageDeleteObserver;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000027import android.content.pm.PackageInfo;
28import android.content.pm.PackageManager;
29import android.content.pm.Signature;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000030import android.content.pm.UserInfo;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010031import android.os.Binder;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000032import android.os.PatternMatcher;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010033import android.os.Process;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000034import android.os.RemoteException;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000035import android.os.ResultReceiver;
Gustav Sennton23875b22016-02-09 14:11:33 +000036import android.os.UserHandle;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000037import android.os.UserManager;
Gustav Sennton14c033c2016-02-11 12:51:27 +000038import android.provider.Settings.Global;
Gustav Sennton8b179262016-03-14 11:31:14 +000039import android.provider.Settings;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000040import android.util.AndroidRuntimeException;
Primiano Tucci810c0522014-07-25 18:03:16 +010041import android.util.Slog;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010042import android.webkit.IWebViewUpdateService;
Gustav Sennton8b179262016-03-14 11:31:14 +000043import android.webkit.WebViewFactory;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000044import android.webkit.WebViewProviderInfo;
45import android.webkit.WebViewProviderResponse;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010046
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010047import com.android.server.SystemService;
48
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000049import java.io.FileDescriptor;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000050import java.util.ArrayList;
51import java.util.Arrays;
52import java.util.Iterator;
53import java.util.List;
54
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010055/**
56 * Private service to wait for the updatable WebView to be ready for use.
57 * @hide
58 */
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010059public class WebViewUpdateService extends SystemService {
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010060
61 private static final String TAG = "WebViewUpdateService";
Gustav Sennton6258dcd2015-10-30 19:25:37 +000062 private static final int WAIT_TIMEOUT_MS = 4500; // KEY_DISPATCHING_TIMEOUT is 5000.
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010063
Gustav Sennton6258dcd2015-10-30 19:25:37 +000064 // Keeps track of the number of running relro creations
65 private int mNumRelroCreationsStarted = 0;
66 private int mNumRelroCreationsFinished = 0;
67 // Implies that we need to rerun relro creation because we are using an out-of-date package
68 private boolean mWebViewPackageDirty = false;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000069 private boolean mAnyWebViewInstalled = false;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010070
Gustav Sennton6258dcd2015-10-30 19:25:37 +000071 private int NUMBER_OF_RELROS_UNKNOWN = Integer.MAX_VALUE;
72
73 // The WebView package currently in use (or the one we are preparing).
74 private PackageInfo mCurrentWebViewPackage = null;
75 // The WebView providers that are currently available.
76 private WebViewProviderInfo[] mCurrentValidWebViewPackages = null;
Gustav Sennton6ce92c92015-10-23 11:10:39 +010077
Ben Murdochdc00a842014-07-17 14:55:00 +010078 private BroadcastReceiver mWebViewUpdatedReceiver;
Gustav Sennton8b179262016-03-14 11:31:14 +000079 private WebViewUtilityInterface mWebViewUtility;
Ben Murdochdc00a842014-07-17 14:55:00 +010080
81 public WebViewUpdateService(Context context) {
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010082 super(context);
Gustav Sennton8b179262016-03-14 11:31:14 +000083 mWebViewUtility = new WebViewUtilityImpl();
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010084 }
85
86 @Override
87 public void onStart() {
Ben Murdochdc00a842014-07-17 14:55:00 +010088 mWebViewUpdatedReceiver = new BroadcastReceiver() {
89 @Override
90 public void onReceive(Context context, Intent intent) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +000091 // When a package is replaced we will receive two intents, one representing
92 // the removal of the old package and one representing the addition of the
93 // new package.
94 // In the case where we receive an intent to remove the old version of the
Gustav Sennton26c82ff2016-03-11 13:06:40 +000095 // package that is being replaced we early-out here so that we don't run the
96 // update-logic twice.
Gustav Sennton3098cf22015-11-10 03:33:09 +000097 if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)
Gustav Sennton6258dcd2015-10-30 19:25:37 +000098 && intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
Gustav Sennton3098cf22015-11-10 03:33:09 +000099 return;
100 }
101
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000102 // Ensure that we only heed PACKAGE_CHANGED intents if they change an entire
103 // package, not just a component
104 if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) {
105 if (!WebViewFactory.entirePackageChanged(intent)) {
106 return;
107 }
108 }
109
110 if (intent.getAction().equals(Intent.ACTION_USER_ADDED)) {
111 int userId =
112 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
113 handleNewUser(userId);
114 return;
115 }
116
117 updateFallbackState(context, intent);
118
Gustav Sennton8b179262016-03-14 11:31:14 +0000119 for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000120 String webviewPackage = "package:" + provider.packageName;
Gustav Sennton6ce92c92015-10-23 11:10:39 +0100121
122 if (webviewPackage.equals(intent.getDataString())) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000123 boolean updateWebView = false;
Gustav Sennton1e5d8032016-02-25 12:26:36 +0000124 boolean removedOrChangedOldPackage = false;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000125 String oldProviderName = null;
126 PackageInfo newPackage = null;
127 synchronized(WebViewUpdateService.this) {
128 try {
129 updateValidWebViewPackages();
130 newPackage = findPreferredWebViewPackage();
131 if (mCurrentWebViewPackage != null)
132 oldProviderName = mCurrentWebViewPackage.packageName;
133 // Only trigger update actions if the updated package is the one
134 // that will be used, or the one that was in use before the
135 // update, or if we haven't seen a valid WebView package before.
136 updateWebView =
137 provider.packageName.equals(newPackage.packageName)
138 || provider.packageName.equals(oldProviderName)
139 || mCurrentWebViewPackage == null;
140 // We removed the old package if we received an intent to remove
141 // or replace the old package.
Gustav Sennton1e5d8032016-02-25 12:26:36 +0000142 removedOrChangedOldPackage =
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000143 provider.packageName.equals(oldProviderName);
144 if (updateWebView) {
145 onWebViewProviderChanged(newPackage);
146 }
147 } catch (WebViewFactory.MissingWebViewPackageException e) {
148 Slog.e(TAG, "Could not find valid WebView package to create " +
149 "relro with " + e);
150 }
151 }
Gustav Sennton1e5d8032016-02-25 12:26:36 +0000152 if(updateWebView && !removedOrChangedOldPackage
153 && oldProviderName != null) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000154 // If the provider change is the result of adding or replacing a
155 // package that was not the previous provider then we must kill
156 // packages dependent on the old package ourselves. The framework
157 // only kills dependents of packages that are being removed.
Gustav Sennton8b179262016-03-14 11:31:14 +0000158 mWebViewUtility.killPackageDependents(oldProviderName);
Gustav Sennton6ce92c92015-10-23 11:10:39 +0100159 }
160 return;
161 }
Ben Murdochdc00a842014-07-17 14:55:00 +0100162 }
163 }
164 };
165 IntentFilter filter = new IntentFilter();
Gustav Sennton3098cf22015-11-10 03:33:09 +0000166 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
167 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000168 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Ben Murdochdc00a842014-07-17 14:55:00 +0100169 filter.addDataScheme("package");
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000170 // Make sure we only receive intents for WebView packages from our config file.
Gustav Sennton8b179262016-03-14 11:31:14 +0000171 for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000172 filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
173 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100174 getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100175
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000176 IntentFilter userAddedFilter = new IntentFilter();
177 userAddedFilter.addAction(Intent.ACTION_USER_ADDED);
178 getContext().registerReceiver(mWebViewUpdatedReceiver, userAddedFilter);
179
Torne (Richard Coles)fc19b0a2016-02-01 16:16:57 +0000180 publishBinderService("webviewupdate", new BinderService(), true /*allowIsolated*/);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100181 }
Ben Murdochdc00a842014-07-17 14:55:00 +0100182
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000183 private static boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
184 for (WebViewProviderInfo provider : providers) {
185 if (provider.isAvailableByDefault() && provider.isEnabled()
186 && provider.isValidProvider() && !provider.isFallbackPackage()) {
187 return true;
188 }
189 }
190 return false;
191 }
192
193 private static void enablePackageForUser(String packageName, boolean enable, int userId) {
194 try {
195 AppGlobals.getPackageManager().setApplicationEnabledSetting(
196 packageName,
197 enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
198 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
199 userId, null);
200 } catch (RemoteException e) {
201 Slog.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
202 }
203 }
204
205 /**
206 * Called when a new user has been added to update the state of its fallback package.
207 */
208 void handleNewUser(int userId) {
209 if (!isFallbackLogicEnabled()) return;
210
Gustav Sennton8b179262016-03-14 11:31:14 +0000211 WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000212 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
213 if (fallbackProvider == null) return;
214 boolean existsValidNonFallbackProvider =
215 existsValidNonFallbackProvider(webviewProviders);
216
217 enablePackageForUser(fallbackProvider.packageName, !existsValidNonFallbackProvider,
218 userId);
219 }
220
221 /**
222 * Handle the enabled-state of our fallback package, i.e. if there exists some non-fallback
223 * package that is valid (and available by default) then disable the fallback package,
224 * otherwise, enable the fallback package.
225 */
226 void updateFallbackState(final Context context, final Intent intent) {
227 if (!isFallbackLogicEnabled()) return;
228
Gustav Sennton8b179262016-03-14 11:31:14 +0000229 WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000230
231 if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
232 || intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) {
233 // A package was changed / updated / downgraded, early out if it is not one of the
234 // webview packages that are available by default.
235 String changedPackage = null;
236 for (WebViewProviderInfo provider : webviewProviders) {
237 String webviewPackage = "package:" + provider.packageName;
238 if (webviewPackage.equals(intent.getDataString())) {
239 if (provider.isAvailableByDefault()) {
240 changedPackage = provider.packageName;
241 }
242 break;
243 }
244 }
245 if (changedPackage == null) return;
246 }
247
248 // If there exists a valid and enabled non-fallback package - disable the fallback
249 // package, otherwise, enable it.
250 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
251 if (fallbackProvider == null) return;
252 boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
253
254 if (existsValidNonFallbackProvider
255 // During an OTA the primary user's WebView state might differ from other users', so
256 // ignore the state of that user during boot.
257 && (fallbackProvider.isEnabled() || intent == null)) {
258 // Uninstall and disable fallback package for all users.
259 context.getPackageManager().deletePackage(fallbackProvider.packageName,
260 new IPackageDeleteObserver.Stub() {
261 public void packageDeleted(String packageName, int returnCode) {
262 // Ignore returnCode since the deletion could fail, e.g. we might be trying
263 // to delete a non-updated system-package (and we should still disable the
264 // package)
265 UserManager userManager =
266 (UserManager)context.getSystemService(Context.USER_SERVICE);
267 // Disable the fallback package for all users.
268 for(UserInfo userInfo : userManager.getUsers()) {
269 enablePackageForUser(packageName, false, userInfo.id);
270 }
271 }
272 }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
273 } else if (!existsValidNonFallbackProvider
274 // During an OTA the primary user's WebView state might differ from other users', so
275 // ignore the state of that user during boot.
276 && (!fallbackProvider.isEnabled() || intent==null)) {
277 // Enable the fallback package for all users.
278 UserManager userManager =
279 (UserManager)context.getSystemService(Context.USER_SERVICE);
280 for(UserInfo userInfo : userManager.getUsers()) {
281 enablePackageForUser(fallbackProvider.packageName, true, userInfo.id);
282 }
283 }
284 }
285
286 private static boolean isFallbackLogicEnabled() {
287 // Note that this is enabled by default (i.e. if the setting hasn't been set).
288 return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
289 Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
290 }
291
292 private static void enableFallbackLogic(boolean enable) {
293 Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
294 Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
295 }
296
297 /**
298 * Returns the only fallback provider, or null if there is none.
299 */
300 private static WebViewProviderInfo getFallbackProvider(WebViewProviderInfo[] webviewPackages) {
301 for (WebViewProviderInfo provider : webviewPackages) {
302 if (provider.isFallbackPackage()) {
303 return provider;
304 }
305 }
306 return null;
307 }
308
309 private static boolean containsAvailableNonFallbackProvider(
310 WebViewProviderInfo[] webviewPackages) {
311 for (WebViewProviderInfo provider : webviewPackages) {
312 if (provider.isAvailableByDefault() && provider.isEnabled()
313 && provider.isValidProvider() && !provider.isFallbackPackage()) {
314 return true;
315 }
316 }
317 return false;
318 }
319
Gustav Sennton8b179262016-03-14 11:31:14 +0000320 private boolean isFallbackPackage(String packageName) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000321 if (packageName == null || !isFallbackLogicEnabled()) return false;
322
Gustav Sennton8b179262016-03-14 11:31:14 +0000323 WebViewProviderInfo[] webviewPackages = mWebViewUtility.getWebViewPackages();
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000324 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
325 return (fallbackProvider != null
326 && packageName.equals(fallbackProvider.packageName));
327 }
328
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000329 /**
330 * Perform any WebView loading preparations that must happen at boot from the system server,
331 * after the package manager has started or after an update to the webview is installed.
332 * This must be called in the system server.
333 * Currently, this means spawning the child processes which will create the relro files.
334 */
335 public void prepareWebViewInSystemServer() {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000336 updateFallbackState(getContext(), null);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000337 try {
338 synchronized(this) {
339 updateValidWebViewPackages();
340 mCurrentWebViewPackage = findPreferredWebViewPackage();
341 onWebViewProviderChanged(mCurrentWebViewPackage);
342 }
343 } catch (Throwable t) {
344 // Log and discard errors at this stage as we must not crash the system server.
345 Slog.e(TAG, "error preparing webview provider from system server", t);
Ben Murdochdc00a842014-07-17 14:55:00 +0100346 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000347 }
348
349
350 /**
351 * Change WebView provider and provider setting and kill packages using the old provider.
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000352 * Return the new provider (in case we are in the middle of creating relro files this new
353 * provider will not be in use directly, but will when the relros are done).
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000354 */
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000355 private String changeProviderAndSetting(String newProviderName) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000356 PackageInfo oldPackage = null;
357 PackageInfo newPackage = null;
358 synchronized(this) {
359 oldPackage = mCurrentWebViewPackage;
Gustav Sennton8b179262016-03-14 11:31:14 +0000360 mWebViewUtility.updateUserSetting(getContext(), newProviderName);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000361
362 try {
363 newPackage = findPreferredWebViewPackage();
364 if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) {
365 // If we don't perform the user change, revert the settings change.
Gustav Sennton8b179262016-03-14 11:31:14 +0000366 mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000367 return newPackage.packageName;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000368 }
369 } catch (WebViewFactory.MissingWebViewPackageException e) {
370 Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView package "
371 + e);
372 // If we don't perform the user change but don't have an installed WebView package,
373 // we will have changed the setting and it will be used when a package is available.
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000374 return newProviderName;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000375 }
376 onWebViewProviderChanged(newPackage);
377 }
378 // Kill apps using the old provider
Gustav Sennton8b179262016-03-14 11:31:14 +0000379 if (oldPackage != null) {
380 mWebViewUtility.killPackageDependents(oldPackage.packageName);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000381 }
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000382 return newPackage.packageName;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000383 }
384
385 /**
386 * This is called when we change WebView provider, either when the current provider is updated
387 * or a new provider is chosen / takes precedence.
388 */
389 private void onWebViewProviderChanged(PackageInfo newPackage) {
390 synchronized(this) {
391 mAnyWebViewInstalled = true;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000392 if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
393 mCurrentWebViewPackage = newPackage;
Gustav Sennton8b179262016-03-14 11:31:14 +0000394 mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000395
396 // The relro creations might 'finish' (not start at all) before
397 // WebViewFactory.onWebViewProviderChanged which means we might not know the number
398 // of started creations before they finish.
399 mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN;
400 mNumRelroCreationsFinished = 0;
Gustav Sennton8b179262016-03-14 11:31:14 +0000401 mNumRelroCreationsStarted = mWebViewUtility.onWebViewProviderChanged(newPackage);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000402 // If the relro creations finish before we know the number of started creations we
403 // will have to do any cleanup/notifying here.
404 checkIfRelrosDoneLocked();
405 } else {
406 mWebViewPackageDirty = true;
407 }
408 }
409 }
410
411 /**
412 * Updates the currently valid WebView provider packages.
413 * Should be used when a provider has been installed or removed.
414 * @hide
415 * */
416 private void updateValidWebViewPackages() {
417 List<WebViewProviderInfo> webViewProviders =
Gustav Sennton8b179262016-03-14 11:31:14 +0000418 new ArrayList<WebViewProviderInfo>(Arrays.asList(mWebViewUtility.getWebViewPackages()));
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000419 Iterator<WebViewProviderInfo> it = webViewProviders.iterator();
420 // remove non-valid packages
421 while(it.hasNext()) {
422 WebViewProviderInfo current = it.next();
423 if (!current.isValidProvider())
424 it.remove();
425 }
426 synchronized(this) {
427 mCurrentValidWebViewPackages =
428 webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
429 }
430 }
431
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000432 /**
433 * Returns either the package info of the WebView provider determined in the following way:
434 * If the user has chosen a provider then use that if it is valid,
435 * otherwise use the first package in the webview priority list that is valid.
436 *
437 * @hide
438 */
439 private PackageInfo findPreferredWebViewPackage() {
440 WebViewProviderInfo[] providers = mCurrentValidWebViewPackages;
441
Gustav Sennton8b179262016-03-14 11:31:14 +0000442 String userChosenProvider = mWebViewUtility.getUserChosenWebViewProvider(getContext());
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000443
444 // If the user has chosen provider, use that
445 for (WebViewProviderInfo provider : providers) {
Gustav Sennton27f13de2016-01-05 20:22:02 +0000446 if (provider.packageName.equals(userChosenProvider) && provider.isEnabled()) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000447 return provider.getPackageInfo();
448 }
449 }
450
Gustav Sennton27f13de2016-01-05 20:22:02 +0000451 // User did not choose, or the choice failed; use the most stable provider that is
452 // enabled and available by default (not through user choice).
453 for (WebViewProviderInfo provider : providers) {
454 if (provider.isAvailableByDefault() && provider.isEnabled()) {
455 return provider.getPackageInfo();
456 }
457 }
458
459 // Could not find any enabled package either, use the most stable provider.
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000460 for (WebViewProviderInfo provider : providers) {
461 return provider.getPackageInfo();
462 }
Gustav Sennton27f13de2016-01-05 20:22:02 +0000463
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000464 mAnyWebViewInstalled = false;
465 throw new WebViewFactory.MissingWebViewPackageException(
466 "Could not find a loadable WebView package");
467 }
468
469 /**
470 * Returns whether WebView is ready and is not going to go through its preparation phase again
471 * directly.
472 */
473 private boolean webViewIsReadyLocked() {
474 return !mWebViewPackageDirty
475 && (mNumRelroCreationsStarted == mNumRelroCreationsFinished)
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000476 // The current package might be replaced though we haven't received an intent declaring
477 // this yet, the following flag makes anyone loading WebView to wait in this case.
478 && mAnyWebViewInstalled;
479 }
480
481 private void checkIfRelrosDoneLocked() {
482 if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
483 if (mWebViewPackageDirty) {
484 mWebViewPackageDirty = false;
485 // If we have changed provider since we started the relro creation we need to
486 // redo the whole process using the new package instead.
Gustav Sennton26c82ff2016-03-11 13:06:40 +0000487 PackageInfo newPackage = findPreferredWebViewPackage();
488 onWebViewProviderChanged(newPackage);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000489 } else {
490 this.notifyAll();
491 }
492 }
Ben Murdochdc00a842014-07-17 14:55:00 +0100493 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100494
495 private class BinderService extends IWebViewUpdateService.Stub {
496
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000497 @Override
498 public void onShellCommand(FileDescriptor in, FileDescriptor out,
499 FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
500 (new WebViewUpdateServiceShellCommand(this)).exec(
501 this, in, out, err, args, resultReceiver);
502 }
503
504
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100505 /**
506 * The shared relro process calls this to notify us that it's done trying to create a relro
507 * file. This method gets called even if the relro creation has failed or the process
508 * crashed.
509 */
510 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000511 public void notifyRelroCreationCompleted() {
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100512 // Verify that the caller is either the shared relro process (nominal case) or the
513 // system server (only in the case the relro process crashes and we get here via the
514 // crashHandler).
515 if (Binder.getCallingUid() != Process.SHARED_RELRO_UID &&
516 Binder.getCallingUid() != Process.SYSTEM_UID) {
517 return;
518 }
519
Gustav Sennton275d13c2016-02-24 10:58:09 +0000520 long callingId = Binder.clearCallingIdentity();
521 try {
522 synchronized (WebViewUpdateService.this) {
523 mNumRelroCreationsFinished++;
524 checkIfRelrosDoneLocked();
525 }
526 } finally {
527 Binder.restoreCallingIdentity(callingId);
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100528 }
529 }
530
531 /**
532 * WebViewFactory calls this to block WebView loading until the relro file is created.
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000533 * Returns the WebView provider for which we create relro files.
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100534 */
535 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000536 public WebViewProviderResponse waitForAndGetProvider() {
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100537 // The WebViewUpdateService depends on the prepareWebViewInSystemServer call, which
538 // happens later (during the PHASE_ACTIVITY_MANAGER_READY) in SystemServer.java. If
539 // another service there tries to bring up a WebView in the between, the wait below
540 // would deadlock without the check below.
541 if (Binder.getCallingPid() == Process.myPid()) {
542 throw new IllegalStateException("Cannot create a WebView from the SystemServer");
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100543 }
544
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000545 PackageInfo webViewPackage = null;
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100546 final long NS_PER_MS = 1000000;
547 final long timeoutTimeMs = System.nanoTime() / NS_PER_MS + WAIT_TIMEOUT_MS;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000548 boolean webViewReady = false;
549 int webViewStatus = WebViewFactory.LIBLOAD_SUCCESS;
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100550 synchronized (WebViewUpdateService.this) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000551 webViewReady = WebViewUpdateService.this.webViewIsReadyLocked();
552 while (!webViewReady) {
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100553 final long timeNowMs = System.nanoTime() / NS_PER_MS;
554 if (timeNowMs >= timeoutTimeMs) break;
555 try {
556 WebViewUpdateService.this.wait(timeoutTimeMs - timeNowMs);
557 } catch (InterruptedException e) {}
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000558 webViewReady = WebViewUpdateService.this.webViewIsReadyLocked();
559 }
560 // Make sure we return the provider that was used to create the relro file
561 webViewPackage = WebViewUpdateService.this.mCurrentWebViewPackage;
562 if (webViewReady) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000563 } else if (!mAnyWebViewInstalled) {
564 webViewStatus = WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
565 } else {
566 // Either the current relro creation isn't done yet, or the new relro creatioin
567 // hasn't kicked off yet (the last relro creation used an out-of-date WebView).
568 webViewStatus = WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO;
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100569 }
570 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000571 if (!webViewReady) Slog.w(TAG, "creating relro file timed out");
572 return new WebViewProviderResponse(webViewPackage, webViewStatus);
573 }
574
575 /**
576 * This is called from DeveloperSettings when the user changes WebView provider.
577 */
578 @Override // Binder call
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000579 public String changeProviderAndSetting(String newProvider) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000580 if (getContext().checkCallingPermission(
581 android.Manifest.permission.WRITE_SECURE_SETTINGS)
582 != PackageManager.PERMISSION_GRANTED) {
583 String msg = "Permission Denial: changeProviderAndSetting() from pid="
584 + Binder.getCallingPid()
585 + ", uid=" + Binder.getCallingUid()
586 + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
587 Slog.w(TAG, msg);
588 throw new SecurityException(msg);
589 }
590
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000591 return WebViewUpdateService.this.changeProviderAndSetting(newProvider);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000592 }
593
594 @Override // Binder call
595 public WebViewProviderInfo[] getValidWebViewPackages() {
596 synchronized(WebViewUpdateService.this) {
597 return mCurrentValidWebViewPackages;
598 }
599 }
600
601 @Override // Binder call
Gustav Sennton8b179262016-03-14 11:31:14 +0000602 public WebViewProviderInfo[] getAllWebViewPackages() {
603 return WebViewUpdateService.this.mWebViewUtility.getWebViewPackages();
604 }
605
606 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000607 public String getCurrentWebViewPackageName() {
608 synchronized(WebViewUpdateService.this) {
609 if (WebViewUpdateService.this.mCurrentWebViewPackage == null)
610 return null;
611 return WebViewUpdateService.this.mCurrentWebViewPackage.packageName;
612 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100613 }
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000614
615 @Override // Binder call
616 public boolean isFallbackPackage(String packageName) {
Gustav Sennton8b179262016-03-14 11:31:14 +0000617 return WebViewUpdateService.this.isFallbackPackage(packageName);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000618 }
619
620 @Override // Binder call
621 public void enableFallbackLogic(boolean enable) {
622 if (getContext().checkCallingPermission(
623 android.Manifest.permission.WRITE_SECURE_SETTINGS)
624 != PackageManager.PERMISSION_GRANTED) {
625 String msg = "Permission Denial: enableFallbackLogic() from pid="
626 + Binder.getCallingPid()
627 + ", uid=" + Binder.getCallingUid()
628 + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
629 Slog.w(TAG, msg);
630 throw new SecurityException(msg);
631 }
632
633 WebViewUpdateService.enableFallbackLogic(enable);
634 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100635 }
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100636}