blob: 181b807481578f74b44babe1b7f07540623c54d5 [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;
69 // Set to true when the current provider is being replaced
70 private boolean mCurrentProviderBeingReplaced = false;
71 private boolean mAnyWebViewInstalled = false;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010072
Gustav Sennton6258dcd2015-10-30 19:25:37 +000073 private int NUMBER_OF_RELROS_UNKNOWN = Integer.MAX_VALUE;
74
75 // The WebView package currently in use (or the one we are preparing).
76 private PackageInfo mCurrentWebViewPackage = null;
77 // The WebView providers that are currently available.
78 private WebViewProviderInfo[] mCurrentValidWebViewPackages = null;
Gustav Sennton6ce92c92015-10-23 11:10:39 +010079
Ben Murdochdc00a842014-07-17 14:55:00 +010080 private BroadcastReceiver mWebViewUpdatedReceiver;
Gustav Sennton8b179262016-03-14 11:31:14 +000081 private WebViewUtilityInterface mWebViewUtility;
Ben Murdochdc00a842014-07-17 14:55:00 +010082
83 public WebViewUpdateService(Context context) {
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010084 super(context);
Gustav Sennton8b179262016-03-14 11:31:14 +000085 mWebViewUtility = new WebViewUtilityImpl();
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010086 }
87
88 @Override
89 public void onStart() {
Ben Murdochdc00a842014-07-17 14:55:00 +010090 mWebViewUpdatedReceiver = new BroadcastReceiver() {
91 @Override
92 public void onReceive(Context context, Intent intent) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +000093 // When a package is replaced we will receive two intents, one representing
94 // the removal of the old package and one representing the addition of the
95 // new package.
96 // In the case where we receive an intent to remove the old version of the
97 // package that is being replaced we set a flag here and early-out so that we
98 // don't change provider while replacing the current package (we will instead
99 // change provider when the new version of the package is being installed).
Gustav Sennton3098cf22015-11-10 03:33:09 +0000100 if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000101 && intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
Gustav Sennton14c033c2016-02-11 12:51:27 +0000102 synchronized(WebViewUpdateService.this) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000103 if (mCurrentWebViewPackage == null) return;
104
105 String webViewPackage = "package:" + mCurrentWebViewPackage.packageName;
106 if (webViewPackage.equals(intent.getDataString()))
107 mCurrentProviderBeingReplaced = true;
108 }
109
Gustav Sennton3098cf22015-11-10 03:33:09 +0000110 return;
111 }
112
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000113 // Ensure that we only heed PACKAGE_CHANGED intents if they change an entire
114 // package, not just a component
115 if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) {
116 if (!WebViewFactory.entirePackageChanged(intent)) {
117 return;
118 }
119 }
120
121 if (intent.getAction().equals(Intent.ACTION_USER_ADDED)) {
122 int userId =
123 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
124 handleNewUser(userId);
125 return;
126 }
127
128 updateFallbackState(context, intent);
129
Gustav Sennton8b179262016-03-14 11:31:14 +0000130 for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000131 String webviewPackage = "package:" + provider.packageName;
Gustav Sennton6ce92c92015-10-23 11:10:39 +0100132
133 if (webviewPackage.equals(intent.getDataString())) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000134 boolean updateWebView = false;
Gustav Sennton1e5d8032016-02-25 12:26:36 +0000135 boolean removedOrChangedOldPackage = false;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000136 String oldProviderName = null;
137 PackageInfo newPackage = null;
138 synchronized(WebViewUpdateService.this) {
139 try {
140 updateValidWebViewPackages();
141 newPackage = findPreferredWebViewPackage();
142 if (mCurrentWebViewPackage != null)
143 oldProviderName = mCurrentWebViewPackage.packageName;
144 // Only trigger update actions if the updated package is the one
145 // that will be used, or the one that was in use before the
146 // update, or if we haven't seen a valid WebView package before.
147 updateWebView =
148 provider.packageName.equals(newPackage.packageName)
149 || provider.packageName.equals(oldProviderName)
150 || mCurrentWebViewPackage == null;
151 // We removed the old package if we received an intent to remove
152 // or replace the old package.
Gustav Sennton1e5d8032016-02-25 12:26:36 +0000153 removedOrChangedOldPackage =
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000154 provider.packageName.equals(oldProviderName);
155 if (updateWebView) {
156 onWebViewProviderChanged(newPackage);
157 }
158 } catch (WebViewFactory.MissingWebViewPackageException e) {
159 Slog.e(TAG, "Could not find valid WebView package to create " +
160 "relro with " + e);
161 }
162 }
Gustav Sennton1e5d8032016-02-25 12:26:36 +0000163 if(updateWebView && !removedOrChangedOldPackage
164 && oldProviderName != null) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000165 // If the provider change is the result of adding or replacing a
166 // package that was not the previous provider then we must kill
167 // packages dependent on the old package ourselves. The framework
168 // only kills dependents of packages that are being removed.
Gustav Sennton8b179262016-03-14 11:31:14 +0000169 mWebViewUtility.killPackageDependents(oldProviderName);
Gustav Sennton6ce92c92015-10-23 11:10:39 +0100170 }
171 return;
172 }
Ben Murdochdc00a842014-07-17 14:55:00 +0100173 }
174 }
175 };
176 IntentFilter filter = new IntentFilter();
Gustav Sennton3098cf22015-11-10 03:33:09 +0000177 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
178 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000179 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Ben Murdochdc00a842014-07-17 14:55:00 +0100180 filter.addDataScheme("package");
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000181 // Make sure we only receive intents for WebView packages from our config file.
Gustav Sennton8b179262016-03-14 11:31:14 +0000182 for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000183 filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
184 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100185 getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100186
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000187 IntentFilter userAddedFilter = new IntentFilter();
188 userAddedFilter.addAction(Intent.ACTION_USER_ADDED);
189 getContext().registerReceiver(mWebViewUpdatedReceiver, userAddedFilter);
190
Torne (Richard Coles)fc19b0a2016-02-01 16:16:57 +0000191 publishBinderService("webviewupdate", new BinderService(), true /*allowIsolated*/);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100192 }
Ben Murdochdc00a842014-07-17 14:55:00 +0100193
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000194 private static boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
195 for (WebViewProviderInfo provider : providers) {
196 if (provider.isAvailableByDefault() && provider.isEnabled()
197 && provider.isValidProvider() && !provider.isFallbackPackage()) {
198 return true;
199 }
200 }
201 return false;
202 }
203
204 private static void enablePackageForUser(String packageName, boolean enable, int userId) {
205 try {
206 AppGlobals.getPackageManager().setApplicationEnabledSetting(
207 packageName,
208 enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
209 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
210 userId, null);
211 } catch (RemoteException e) {
212 Slog.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
213 }
214 }
215
216 /**
217 * Called when a new user has been added to update the state of its fallback package.
218 */
219 void handleNewUser(int userId) {
220 if (!isFallbackLogicEnabled()) return;
221
Gustav Sennton8b179262016-03-14 11:31:14 +0000222 WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000223 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
224 if (fallbackProvider == null) return;
225 boolean existsValidNonFallbackProvider =
226 existsValidNonFallbackProvider(webviewProviders);
227
228 enablePackageForUser(fallbackProvider.packageName, !existsValidNonFallbackProvider,
229 userId);
230 }
231
232 /**
233 * Handle the enabled-state of our fallback package, i.e. if there exists some non-fallback
234 * package that is valid (and available by default) then disable the fallback package,
235 * otherwise, enable the fallback package.
236 */
237 void updateFallbackState(final Context context, final Intent intent) {
238 if (!isFallbackLogicEnabled()) return;
239
Gustav Sennton8b179262016-03-14 11:31:14 +0000240 WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000241
242 if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
243 || intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) {
244 // A package was changed / updated / downgraded, early out if it is not one of the
245 // webview packages that are available by default.
246 String changedPackage = null;
247 for (WebViewProviderInfo provider : webviewProviders) {
248 String webviewPackage = "package:" + provider.packageName;
249 if (webviewPackage.equals(intent.getDataString())) {
250 if (provider.isAvailableByDefault()) {
251 changedPackage = provider.packageName;
252 }
253 break;
254 }
255 }
256 if (changedPackage == null) return;
257 }
258
259 // If there exists a valid and enabled non-fallback package - disable the fallback
260 // package, otherwise, enable it.
261 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
262 if (fallbackProvider == null) return;
263 boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
264
265 if (existsValidNonFallbackProvider
266 // During an OTA the primary user's WebView state might differ from other users', so
267 // ignore the state of that user during boot.
268 && (fallbackProvider.isEnabled() || intent == null)) {
269 // Uninstall and disable fallback package for all users.
270 context.getPackageManager().deletePackage(fallbackProvider.packageName,
271 new IPackageDeleteObserver.Stub() {
272 public void packageDeleted(String packageName, int returnCode) {
273 // Ignore returnCode since the deletion could fail, e.g. we might be trying
274 // to delete a non-updated system-package (and we should still disable the
275 // package)
276 UserManager userManager =
277 (UserManager)context.getSystemService(Context.USER_SERVICE);
278 // Disable the fallback package for all users.
279 for(UserInfo userInfo : userManager.getUsers()) {
280 enablePackageForUser(packageName, false, userInfo.id);
281 }
282 }
283 }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
284 } else if (!existsValidNonFallbackProvider
285 // During an OTA the primary user's WebView state might differ from other users', so
286 // ignore the state of that user during boot.
287 && (!fallbackProvider.isEnabled() || intent==null)) {
288 // Enable the fallback package for all users.
289 UserManager userManager =
290 (UserManager)context.getSystemService(Context.USER_SERVICE);
291 for(UserInfo userInfo : userManager.getUsers()) {
292 enablePackageForUser(fallbackProvider.packageName, true, userInfo.id);
293 }
294 }
295 }
296
297 private static boolean isFallbackLogicEnabled() {
298 // Note that this is enabled by default (i.e. if the setting hasn't been set).
299 return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
300 Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
301 }
302
303 private static void enableFallbackLogic(boolean enable) {
304 Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
305 Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
306 }
307
308 /**
309 * Returns the only fallback provider, or null if there is none.
310 */
311 private static WebViewProviderInfo getFallbackProvider(WebViewProviderInfo[] webviewPackages) {
312 for (WebViewProviderInfo provider : webviewPackages) {
313 if (provider.isFallbackPackage()) {
314 return provider;
315 }
316 }
317 return null;
318 }
319
320 private static boolean containsAvailableNonFallbackProvider(
321 WebViewProviderInfo[] webviewPackages) {
322 for (WebViewProviderInfo provider : webviewPackages) {
323 if (provider.isAvailableByDefault() && provider.isEnabled()
324 && provider.isValidProvider() && !provider.isFallbackPackage()) {
325 return true;
326 }
327 }
328 return false;
329 }
330
Gustav Sennton8b179262016-03-14 11:31:14 +0000331 private boolean isFallbackPackage(String packageName) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000332 if (packageName == null || !isFallbackLogicEnabled()) return false;
333
Gustav Sennton8b179262016-03-14 11:31:14 +0000334 WebViewProviderInfo[] webviewPackages = mWebViewUtility.getWebViewPackages();
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000335 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
336 return (fallbackProvider != null
337 && packageName.equals(fallbackProvider.packageName));
338 }
339
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000340 /**
341 * Perform any WebView loading preparations that must happen at boot from the system server,
342 * after the package manager has started or after an update to the webview is installed.
343 * This must be called in the system server.
344 * Currently, this means spawning the child processes which will create the relro files.
345 */
346 public void prepareWebViewInSystemServer() {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000347 updateFallbackState(getContext(), null);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000348 try {
349 synchronized(this) {
350 updateValidWebViewPackages();
351 mCurrentWebViewPackage = findPreferredWebViewPackage();
352 onWebViewProviderChanged(mCurrentWebViewPackage);
353 }
354 } catch (Throwable t) {
355 // Log and discard errors at this stage as we must not crash the system server.
356 Slog.e(TAG, "error preparing webview provider from system server", t);
Ben Murdochdc00a842014-07-17 14:55:00 +0100357 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000358 }
359
360
361 /**
362 * Change WebView provider and provider setting and kill packages using the old provider.
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000363 * Return the new provider (in case we are in the middle of creating relro files this new
364 * provider will not be in use directly, but will when the relros are done).
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000365 */
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000366 private String changeProviderAndSetting(String newProviderName) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000367 PackageInfo oldPackage = null;
368 PackageInfo newPackage = null;
369 synchronized(this) {
370 oldPackage = mCurrentWebViewPackage;
Gustav Sennton8b179262016-03-14 11:31:14 +0000371 mWebViewUtility.updateUserSetting(getContext(), newProviderName);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000372
373 try {
374 newPackage = findPreferredWebViewPackage();
375 if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) {
376 // If we don't perform the user change, revert the settings change.
Gustav Sennton8b179262016-03-14 11:31:14 +0000377 mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000378 return newPackage.packageName;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000379 }
380 } catch (WebViewFactory.MissingWebViewPackageException e) {
381 Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView package "
382 + e);
383 // If we don't perform the user change but don't have an installed WebView package,
384 // we will have changed the setting and it will be used when a package is available.
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000385 return newProviderName;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000386 }
387 onWebViewProviderChanged(newPackage);
388 }
389 // Kill apps using the old provider
Gustav Sennton8b179262016-03-14 11:31:14 +0000390 if (oldPackage != null) {
391 mWebViewUtility.killPackageDependents(oldPackage.packageName);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000392 }
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000393 return newPackage.packageName;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000394 }
395
396 /**
397 * This is called when we change WebView provider, either when the current provider is updated
398 * or a new provider is chosen / takes precedence.
399 */
400 private void onWebViewProviderChanged(PackageInfo newPackage) {
401 synchronized(this) {
402 mAnyWebViewInstalled = true;
403 // If we have changed provider then the replacement of the old provider is
404 // irrelevant - we can only have chosen a new provider if its package is available.
405 mCurrentProviderBeingReplaced = false;
406 if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
407 mCurrentWebViewPackage = newPackage;
Gustav Sennton8b179262016-03-14 11:31:14 +0000408 mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000409
410 // The relro creations might 'finish' (not start at all) before
411 // WebViewFactory.onWebViewProviderChanged which means we might not know the number
412 // of started creations before they finish.
413 mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN;
414 mNumRelroCreationsFinished = 0;
Gustav Sennton8b179262016-03-14 11:31:14 +0000415 mNumRelroCreationsStarted = mWebViewUtility.onWebViewProviderChanged(newPackage);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000416 // If the relro creations finish before we know the number of started creations we
417 // will have to do any cleanup/notifying here.
418 checkIfRelrosDoneLocked();
419 } else {
420 mWebViewPackageDirty = true;
421 }
422 }
423 }
424
425 /**
426 * Updates the currently valid WebView provider packages.
427 * Should be used when a provider has been installed or removed.
428 * @hide
429 * */
430 private void updateValidWebViewPackages() {
431 List<WebViewProviderInfo> webViewProviders =
Gustav Sennton8b179262016-03-14 11:31:14 +0000432 new ArrayList<WebViewProviderInfo>(Arrays.asList(mWebViewUtility.getWebViewPackages()));
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000433 Iterator<WebViewProviderInfo> it = webViewProviders.iterator();
434 // remove non-valid packages
435 while(it.hasNext()) {
436 WebViewProviderInfo current = it.next();
437 if (!current.isValidProvider())
438 it.remove();
439 }
440 synchronized(this) {
441 mCurrentValidWebViewPackages =
442 webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
443 }
444 }
445
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000446 /**
447 * Returns either the package info of the WebView provider determined in the following way:
448 * If the user has chosen a provider then use that if it is valid,
449 * otherwise use the first package in the webview priority list that is valid.
450 *
451 * @hide
452 */
453 private PackageInfo findPreferredWebViewPackage() {
454 WebViewProviderInfo[] providers = mCurrentValidWebViewPackages;
455
Gustav Sennton8b179262016-03-14 11:31:14 +0000456 String userChosenProvider = mWebViewUtility.getUserChosenWebViewProvider(getContext());
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000457
458 // If the user has chosen provider, use that
459 for (WebViewProviderInfo provider : providers) {
Gustav Sennton27f13de2016-01-05 20:22:02 +0000460 if (provider.packageName.equals(userChosenProvider) && provider.isEnabled()) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000461 return provider.getPackageInfo();
462 }
463 }
464
Gustav Sennton27f13de2016-01-05 20:22:02 +0000465 // User did not choose, or the choice failed; use the most stable provider that is
466 // enabled and available by default (not through user choice).
467 for (WebViewProviderInfo provider : providers) {
468 if (provider.isAvailableByDefault() && provider.isEnabled()) {
469 return provider.getPackageInfo();
470 }
471 }
472
473 // Could not find any enabled package either, use the most stable provider.
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000474 for (WebViewProviderInfo provider : providers) {
475 return provider.getPackageInfo();
476 }
Gustav Sennton27f13de2016-01-05 20:22:02 +0000477
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000478 mAnyWebViewInstalled = false;
479 throw new WebViewFactory.MissingWebViewPackageException(
480 "Could not find a loadable WebView package");
481 }
482
483 /**
484 * Returns whether WebView is ready and is not going to go through its preparation phase again
485 * directly.
486 */
487 private boolean webViewIsReadyLocked() {
488 return !mWebViewPackageDirty
489 && (mNumRelroCreationsStarted == mNumRelroCreationsFinished)
490 && !mCurrentProviderBeingReplaced
491 // The current package might be replaced though we haven't received an intent declaring
492 // this yet, the following flag makes anyone loading WebView to wait in this case.
493 && mAnyWebViewInstalled;
494 }
495
496 private void checkIfRelrosDoneLocked() {
497 if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
498 if (mWebViewPackageDirty) {
499 mWebViewPackageDirty = false;
500 // If we have changed provider since we started the relro creation we need to
501 // redo the whole process using the new package instead.
502 // Though, if the current provider package is being replaced we don't want to change
503 // provider here since we will perform the change either when the package is added
504 // again or when we switch to another provider (whichever comes first).
505 if (!mCurrentProviderBeingReplaced) {
506 PackageInfo newPackage = findPreferredWebViewPackage();
507 onWebViewProviderChanged(newPackage);
508 }
509 } else {
510 this.notifyAll();
511 }
512 }
Ben Murdochdc00a842014-07-17 14:55:00 +0100513 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100514
515 private class BinderService extends IWebViewUpdateService.Stub {
516
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000517 @Override
518 public void onShellCommand(FileDescriptor in, FileDescriptor out,
519 FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
520 (new WebViewUpdateServiceShellCommand(this)).exec(
521 this, in, out, err, args, resultReceiver);
522 }
523
524
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100525 /**
526 * The shared relro process calls this to notify us that it's done trying to create a relro
527 * file. This method gets called even if the relro creation has failed or the process
528 * crashed.
529 */
530 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000531 public void notifyRelroCreationCompleted() {
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100532 // Verify that the caller is either the shared relro process (nominal case) or the
533 // system server (only in the case the relro process crashes and we get here via the
534 // crashHandler).
535 if (Binder.getCallingUid() != Process.SHARED_RELRO_UID &&
536 Binder.getCallingUid() != Process.SYSTEM_UID) {
537 return;
538 }
539
Gustav Sennton275d13c2016-02-24 10:58:09 +0000540 long callingId = Binder.clearCallingIdentity();
541 try {
542 synchronized (WebViewUpdateService.this) {
543 mNumRelroCreationsFinished++;
544 checkIfRelrosDoneLocked();
545 }
546 } finally {
547 Binder.restoreCallingIdentity(callingId);
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100548 }
549 }
550
551 /**
552 * WebViewFactory calls this to block WebView loading until the relro file is created.
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000553 * Returns the WebView provider for which we create relro files.
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100554 */
555 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000556 public WebViewProviderResponse waitForAndGetProvider() {
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100557 // The WebViewUpdateService depends on the prepareWebViewInSystemServer call, which
558 // happens later (during the PHASE_ACTIVITY_MANAGER_READY) in SystemServer.java. If
559 // another service there tries to bring up a WebView in the between, the wait below
560 // would deadlock without the check below.
561 if (Binder.getCallingPid() == Process.myPid()) {
562 throw new IllegalStateException("Cannot create a WebView from the SystemServer");
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100563 }
564
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000565 PackageInfo webViewPackage = null;
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100566 final long NS_PER_MS = 1000000;
567 final long timeoutTimeMs = System.nanoTime() / NS_PER_MS + WAIT_TIMEOUT_MS;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000568 boolean webViewReady = false;
569 int webViewStatus = WebViewFactory.LIBLOAD_SUCCESS;
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100570 synchronized (WebViewUpdateService.this) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000571 webViewReady = WebViewUpdateService.this.webViewIsReadyLocked();
572 while (!webViewReady) {
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100573 final long timeNowMs = System.nanoTime() / NS_PER_MS;
574 if (timeNowMs >= timeoutTimeMs) break;
575 try {
576 WebViewUpdateService.this.wait(timeoutTimeMs - timeNowMs);
577 } catch (InterruptedException e) {}
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000578 webViewReady = WebViewUpdateService.this.webViewIsReadyLocked();
579 }
580 // Make sure we return the provider that was used to create the relro file
581 webViewPackage = WebViewUpdateService.this.mCurrentWebViewPackage;
582 if (webViewReady) {
583 } else if (mCurrentProviderBeingReplaced) {
584 // It is important that we check this flag before the one representing WebView
585 // being installed, otherwise we might think there is no WebView though the
586 // current one is just being replaced.
587 webViewStatus = WebViewFactory.LIBLOAD_WEBVIEW_BEING_REPLACED;
588 } else if (!mAnyWebViewInstalled) {
589 webViewStatus = WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
590 } else {
591 // Either the current relro creation isn't done yet, or the new relro creatioin
592 // hasn't kicked off yet (the last relro creation used an out-of-date WebView).
593 webViewStatus = WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO;
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100594 }
595 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000596 if (!webViewReady) Slog.w(TAG, "creating relro file timed out");
597 return new WebViewProviderResponse(webViewPackage, webViewStatus);
598 }
599
600 /**
601 * This is called from DeveloperSettings when the user changes WebView provider.
602 */
603 @Override // Binder call
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000604 public String changeProviderAndSetting(String newProvider) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000605 if (getContext().checkCallingPermission(
606 android.Manifest.permission.WRITE_SECURE_SETTINGS)
607 != PackageManager.PERMISSION_GRANTED) {
608 String msg = "Permission Denial: changeProviderAndSetting() from pid="
609 + Binder.getCallingPid()
610 + ", uid=" + Binder.getCallingUid()
611 + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
612 Slog.w(TAG, msg);
613 throw new SecurityException(msg);
614 }
615
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000616 return WebViewUpdateService.this.changeProviderAndSetting(newProvider);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000617 }
618
619 @Override // Binder call
620 public WebViewProviderInfo[] getValidWebViewPackages() {
621 synchronized(WebViewUpdateService.this) {
622 return mCurrentValidWebViewPackages;
623 }
624 }
625
626 @Override // Binder call
Gustav Sennton8b179262016-03-14 11:31:14 +0000627 public WebViewProviderInfo[] getAllWebViewPackages() {
628 return WebViewUpdateService.this.mWebViewUtility.getWebViewPackages();
629 }
630
631 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000632 public String getCurrentWebViewPackageName() {
633 synchronized(WebViewUpdateService.this) {
634 if (WebViewUpdateService.this.mCurrentWebViewPackage == null)
635 return null;
636 return WebViewUpdateService.this.mCurrentWebViewPackage.packageName;
637 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100638 }
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000639
640 @Override // Binder call
641 public boolean isFallbackPackage(String packageName) {
Gustav Sennton8b179262016-03-14 11:31:14 +0000642 return WebViewUpdateService.this.isFallbackPackage(packageName);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000643 }
644
645 @Override // Binder call
646 public void enableFallbackLogic(boolean enable) {
647 if (getContext().checkCallingPermission(
648 android.Manifest.permission.WRITE_SECURE_SETTINGS)
649 != PackageManager.PERMISSION_GRANTED) {
650 String msg = "Permission Denial: enableFallbackLogic() from pid="
651 + Binder.getCallingPid()
652 + ", uid=" + Binder.getCallingUid()
653 + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
654 Slog.w(TAG, msg);
655 throw new SecurityException(msg);
656 }
657
658 WebViewUpdateService.enableFallbackLogic(enable);
659 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100660 }
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100661}