blob: c4f9cc125411eb8bb52d2e109ae6cdf9a3188169 [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;
Gustav Senntondbf5eb02016-03-30 14:53:03 +010029import android.content.pm.PackageManager.NameNotFoundException;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000030import android.content.pm.Signature;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000031import android.content.pm.UserInfo;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010032import android.os.Binder;
Gustav Senntondbf5eb02016-03-30 14:53:03 +010033import android.os.Build;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000034import android.os.PatternMatcher;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010035import android.os.Process;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000036import android.os.RemoteException;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000037import android.os.ResultReceiver;
Gustav Sennton23875b22016-02-09 14:11:33 +000038import android.os.UserHandle;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000039import android.os.UserManager;
Gustav Sennton14c033c2016-02-11 12:51:27 +000040import android.provider.Settings.Global;
Gustav Sennton8b179262016-03-14 11:31:14 +000041import android.provider.Settings;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000042import android.util.AndroidRuntimeException;
Gustav Senntondbf5eb02016-03-30 14:53:03 +010043import android.util.Base64;
Primiano Tucci810c0522014-07-25 18:03:16 +010044import android.util.Slog;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010045import android.webkit.IWebViewUpdateService;
Gustav Sennton8b179262016-03-14 11:31:14 +000046import android.webkit.WebViewFactory;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000047import android.webkit.WebViewProviderInfo;
48import android.webkit.WebViewProviderResponse;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010049
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010050import com.android.server.SystemService;
51
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000052import java.io.FileDescriptor;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000053import java.util.ArrayList;
54import java.util.Arrays;
55import java.util.Iterator;
56import java.util.List;
57
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010058/**
59 * Private service to wait for the updatable WebView to be ready for use.
60 * @hide
61 */
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010062public class WebViewUpdateService extends SystemService {
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010063
64 private static final String TAG = "WebViewUpdateService";
Gustav Sennton6258dcd2015-10-30 19:25:37 +000065 private static final int WAIT_TIMEOUT_MS = 4500; // KEY_DISPATCHING_TIMEOUT is 5000.
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010066
Gustav Sennton6258dcd2015-10-30 19:25:37 +000067 // Keeps track of the number of running relro creations
68 private int mNumRelroCreationsStarted = 0;
69 private int mNumRelroCreationsFinished = 0;
70 // Implies that we need to rerun relro creation because we are using an out-of-date package
71 private boolean mWebViewPackageDirty = false;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000072 private boolean mAnyWebViewInstalled = false;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010073
Gustav Sennton6258dcd2015-10-30 19:25:37 +000074 private int NUMBER_OF_RELROS_UNKNOWN = Integer.MAX_VALUE;
75
76 // The WebView package currently in use (or the one we are preparing).
77 private PackageInfo mCurrentWebViewPackage = null;
Gustav Sennton6ce92c92015-10-23 11:10:39 +010078
Ben Murdochdc00a842014-07-17 14:55:00 +010079 private BroadcastReceiver mWebViewUpdatedReceiver;
Gustav Sennton8b179262016-03-14 11:31:14 +000080 private WebViewUtilityInterface mWebViewUtility;
Ben Murdochdc00a842014-07-17 14:55:00 +010081
82 public WebViewUpdateService(Context context) {
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010083 super(context);
Gustav Sennton8b179262016-03-14 11:31:14 +000084 mWebViewUtility = new WebViewUtilityImpl();
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010085 }
86
87 @Override
88 public void onStart() {
Ben Murdochdc00a842014-07-17 14:55:00 +010089 mWebViewUpdatedReceiver = new BroadcastReceiver() {
90 @Override
91 public void onReceive(Context context, Intent intent) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +000092 // When a package is replaced we will receive two intents, one representing
93 // the removal of the old package and one representing the addition of the
94 // new package.
95 // In the case where we receive an intent to remove the old version of the
Gustav Sennton26c82ff2016-03-11 13:06:40 +000096 // package that is being replaced we early-out here so that we don't run the
97 // update-logic twice.
Gustav Sennton3098cf22015-11-10 03:33:09 +000098 if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)
Gustav Sennton6258dcd2015-10-30 19:25:37 +000099 && intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
Gustav Sennton3098cf22015-11-10 03:33:09 +0000100 return;
101 }
102
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000103 // Ensure that we only heed PACKAGE_CHANGED intents if they change an entire
104 // package, not just a component
105 if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) {
106 if (!WebViewFactory.entirePackageChanged(intent)) {
107 return;
108 }
109 }
110
111 if (intent.getAction().equals(Intent.ACTION_USER_ADDED)) {
112 int userId =
113 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
114 handleNewUser(userId);
115 return;
116 }
117
118 updateFallbackState(context, intent);
119
Gustav Sennton8b179262016-03-14 11:31:14 +0000120 for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000121 String webviewPackage = "package:" + provider.packageName;
Gustav Sennton6ce92c92015-10-23 11:10:39 +0100122
123 if (webviewPackage.equals(intent.getDataString())) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000124 boolean updateWebView = false;
Gustav Sennton1e5d8032016-02-25 12:26:36 +0000125 boolean removedOrChangedOldPackage = false;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000126 String oldProviderName = null;
127 PackageInfo newPackage = null;
128 synchronized(WebViewUpdateService.this) {
129 try {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000130 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 Senntondbf5eb02016-03-30 14:53:03 +0100183 private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000184 for (WebViewProviderInfo provider : providers) {
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100185 if (provider.availableByDefault && !provider.isFallback) {
186 try {
187 PackageInfo packageInfo = getPackageInfoForProvider(provider);
188 if (isEnabledPackage(packageInfo) && isValidProvider(provider, packageInfo)) {
189 return true;
190 }
191 } catch (NameNotFoundException e) {
192 // A non-existent provider is neither valid nor enabled
193 }
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000194 }
195 }
196 return false;
197 }
198
199 private static void enablePackageForUser(String packageName, boolean enable, int userId) {
200 try {
201 AppGlobals.getPackageManager().setApplicationEnabledSetting(
202 packageName,
203 enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
204 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
205 userId, null);
206 } catch (RemoteException e) {
207 Slog.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
208 }
209 }
210
211 /**
212 * Called when a new user has been added to update the state of its fallback package.
213 */
214 void handleNewUser(int userId) {
215 if (!isFallbackLogicEnabled()) return;
216
Gustav Sennton8b179262016-03-14 11:31:14 +0000217 WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000218 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
219 if (fallbackProvider == null) return;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000220
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100221 enablePackageForUser(fallbackProvider.packageName,
222 !existsValidNonFallbackProvider(webviewProviders), userId);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000223 }
224
225 /**
226 * Handle the enabled-state of our fallback package, i.e. if there exists some non-fallback
227 * package that is valid (and available by default) then disable the fallback package,
228 * otherwise, enable the fallback package.
229 */
230 void updateFallbackState(final Context context, final Intent intent) {
231 if (!isFallbackLogicEnabled()) return;
232
Gustav Sennton8b179262016-03-14 11:31:14 +0000233 WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000234
235 if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
236 || intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) {
237 // A package was changed / updated / downgraded, early out if it is not one of the
238 // webview packages that are available by default.
239 String changedPackage = null;
240 for (WebViewProviderInfo provider : webviewProviders) {
241 String webviewPackage = "package:" + provider.packageName;
242 if (webviewPackage.equals(intent.getDataString())) {
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100243 if (provider.availableByDefault) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000244 changedPackage = provider.packageName;
245 }
246 break;
247 }
248 }
249 if (changedPackage == null) return;
250 }
251
252 // If there exists a valid and enabled non-fallback package - disable the fallback
253 // package, otherwise, enable it.
254 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
255 if (fallbackProvider == null) return;
256 boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
257
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100258 boolean isFallbackEnabled = false;
259 try {
260 isFallbackEnabled = isEnabledPackage(getPackageInfoForProvider(fallbackProvider));
261 } catch (NameNotFoundException e) {
262 }
263
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000264 if (existsValidNonFallbackProvider
265 // During an OTA the primary user's WebView state might differ from other users', so
266 // ignore the state of that user during boot.
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100267 && (isFallbackEnabled || intent == null)) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000268 // Uninstall and disable fallback package for all users.
269 context.getPackageManager().deletePackage(fallbackProvider.packageName,
270 new IPackageDeleteObserver.Stub() {
271 public void packageDeleted(String packageName, int returnCode) {
272 // Ignore returnCode since the deletion could fail, e.g. we might be trying
273 // to delete a non-updated system-package (and we should still disable the
274 // package)
275 UserManager userManager =
276 (UserManager)context.getSystemService(Context.USER_SERVICE);
277 // Disable the fallback package for all users.
278 for(UserInfo userInfo : userManager.getUsers()) {
279 enablePackageForUser(packageName, false, userInfo.id);
280 }
281 }
282 }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
283 } else if (!existsValidNonFallbackProvider
284 // During an OTA the primary user's WebView state might differ from other users', so
285 // ignore the state of that user during boot.
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100286 && (!isFallbackEnabled || intent==null)) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000287 // Enable the fallback package for all users.
288 UserManager userManager =
289 (UserManager)context.getSystemService(Context.USER_SERVICE);
290 for(UserInfo userInfo : userManager.getUsers()) {
291 enablePackageForUser(fallbackProvider.packageName, true, userInfo.id);
292 }
293 }
294 }
295
296 private static boolean isFallbackLogicEnabled() {
297 // Note that this is enabled by default (i.e. if the setting hasn't been set).
298 return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
299 Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
300 }
301
302 private static void enableFallbackLogic(boolean enable) {
303 Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
304 Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
305 }
306
307 /**
308 * Returns the only fallback provider, or null if there is none.
309 */
310 private static WebViewProviderInfo getFallbackProvider(WebViewProviderInfo[] webviewPackages) {
311 for (WebViewProviderInfo provider : webviewPackages) {
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100312 if (provider.isFallback) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000313 return provider;
314 }
315 }
316 return null;
317 }
318
Gustav Sennton8b179262016-03-14 11:31:14 +0000319 private boolean isFallbackPackage(String packageName) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000320 if (packageName == null || !isFallbackLogicEnabled()) return false;
321
Gustav Sennton8b179262016-03-14 11:31:14 +0000322 WebViewProviderInfo[] webviewPackages = mWebViewUtility.getWebViewPackages();
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000323 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
324 return (fallbackProvider != null
325 && packageName.equals(fallbackProvider.packageName));
326 }
327
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000328 /**
329 * Perform any WebView loading preparations that must happen at boot from the system server,
330 * after the package manager has started or after an update to the webview is installed.
331 * This must be called in the system server.
332 * Currently, this means spawning the child processes which will create the relro files.
333 */
334 public void prepareWebViewInSystemServer() {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000335 updateFallbackState(getContext(), null);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000336 try {
337 synchronized(this) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000338 mCurrentWebViewPackage = findPreferredWebViewPackage();
339 onWebViewProviderChanged(mCurrentWebViewPackage);
340 }
341 } catch (Throwable t) {
342 // Log and discard errors at this stage as we must not crash the system server.
343 Slog.e(TAG, "error preparing webview provider from system server", t);
Ben Murdochdc00a842014-07-17 14:55:00 +0100344 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000345 }
346
347
348 /**
349 * Change WebView provider and provider setting and kill packages using the old provider.
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000350 * Return the new provider (in case we are in the middle of creating relro files this new
351 * provider will not be in use directly, but will when the relros are done).
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000352 */
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000353 private String changeProviderAndSetting(String newProviderName) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000354 PackageInfo oldPackage = null;
355 PackageInfo newPackage = null;
356 synchronized(this) {
357 oldPackage = mCurrentWebViewPackage;
Gustav Sennton8b179262016-03-14 11:31:14 +0000358 mWebViewUtility.updateUserSetting(getContext(), newProviderName);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000359
360 try {
361 newPackage = findPreferredWebViewPackage();
362 if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) {
363 // If we don't perform the user change, revert the settings change.
Gustav Sennton8b179262016-03-14 11:31:14 +0000364 mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000365 return newPackage.packageName;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000366 }
367 } catch (WebViewFactory.MissingWebViewPackageException e) {
368 Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView package "
369 + e);
370 // If we don't perform the user change but don't have an installed WebView package,
371 // we will have changed the setting and it will be used when a package is available.
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000372 return newProviderName;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000373 }
374 onWebViewProviderChanged(newPackage);
375 }
376 // Kill apps using the old provider
Gustav Sennton8b179262016-03-14 11:31:14 +0000377 if (oldPackage != null) {
378 mWebViewUtility.killPackageDependents(oldPackage.packageName);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000379 }
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000380 return newPackage.packageName;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000381 }
382
383 /**
384 * This is called when we change WebView provider, either when the current provider is updated
385 * or a new provider is chosen / takes precedence.
386 */
387 private void onWebViewProviderChanged(PackageInfo newPackage) {
388 synchronized(this) {
389 mAnyWebViewInstalled = true;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000390 if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
391 mCurrentWebViewPackage = newPackage;
Gustav Sennton8b179262016-03-14 11:31:14 +0000392 mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000393
394 // The relro creations might 'finish' (not start at all) before
395 // WebViewFactory.onWebViewProviderChanged which means we might not know the number
396 // of started creations before they finish.
397 mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN;
398 mNumRelroCreationsFinished = 0;
Gustav Sennton8b179262016-03-14 11:31:14 +0000399 mNumRelroCreationsStarted = mWebViewUtility.onWebViewProviderChanged(newPackage);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000400 // If the relro creations finish before we know the number of started creations we
401 // will have to do any cleanup/notifying here.
402 checkIfRelrosDoneLocked();
403 } else {
404 mWebViewPackageDirty = true;
405 }
406 }
407 }
408
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100409 private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos() {
410 WebViewProviderInfo[] allProviders = mWebViewUtility.getWebViewPackages();
411 List<ProviderAndPackageInfo> providers = new ArrayList<>();
412 for(int n = 0; n < allProviders.length; n++) {
413 try {
414 PackageInfo packageInfo = getPackageInfoForProvider(allProviders[n]);
415 if (isValidProvider(allProviders[n], packageInfo)) {
416 providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
417 }
418 } catch (NameNotFoundException e) {
419 // Don't add non-existent packages
420 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000421 }
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100422 return providers.toArray(new ProviderAndPackageInfo[providers.size()]);
423 }
424
425 /**
426 * Fetch only the currently valid WebView packages.
427 **/
428 private WebViewProviderInfo[] getValidWebViewPackages() {
429 ProviderAndPackageInfo[] providersAndPackageInfos = getValidWebViewPackagesAndInfos();
430 WebViewProviderInfo[] providers = new WebViewProviderInfo[providersAndPackageInfos.length];
431 for(int n = 0; n < providersAndPackageInfos.length; n++) {
432 providers[n] = providersAndPackageInfos[n].provider;
433 }
434 return providers;
435 }
436
437 private class ProviderAndPackageInfo {
438 public final WebViewProviderInfo provider;
439 public final PackageInfo packageInfo;
440
441 public ProviderAndPackageInfo(WebViewProviderInfo provider, PackageInfo packageInfo) {
442 this.provider = provider;
443 this.packageInfo = packageInfo;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000444 }
445 }
446
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000447 /**
448 * Returns either the package info of the WebView provider determined in the following way:
449 * If the user has chosen a provider then use that if it is valid,
450 * otherwise use the first package in the webview priority list that is valid.
451 *
452 * @hide
453 */
454 private PackageInfo findPreferredWebViewPackage() {
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100455 ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos();
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000456
Gustav Sennton8b179262016-03-14 11:31:14 +0000457 String userChosenProvider = mWebViewUtility.getUserChosenWebViewProvider(getContext());
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000458
459 // If the user has chosen provider, use that
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100460 for (ProviderAndPackageInfo providerAndPackage : providers) {
461 if (providerAndPackage.provider.packageName.equals(userChosenProvider)
462 && isEnabledPackage(providerAndPackage.packageInfo)) {
463 return providerAndPackage.packageInfo;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000464 }
465 }
466
Gustav Sennton27f13de2016-01-05 20:22:02 +0000467 // User did not choose, or the choice failed; use the most stable provider that is
468 // enabled and available by default (not through user choice).
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100469 for (ProviderAndPackageInfo providerAndPackage : providers) {
470 if (providerAndPackage.provider.availableByDefault
471 && isEnabledPackage(providerAndPackage.packageInfo)) {
472 return providerAndPackage.packageInfo;
Gustav Sennton27f13de2016-01-05 20:22:02 +0000473 }
474 }
475
476 // Could not find any enabled package either, use the most stable provider.
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100477 for (ProviderAndPackageInfo providerAndPackage : providers) {
478 return providerAndPackage.packageInfo;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000479 }
Gustav Sennton27f13de2016-01-05 20:22:02 +0000480
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000481 mAnyWebViewInstalled = false;
482 throw new WebViewFactory.MissingWebViewPackageException(
483 "Could not find a loadable WebView package");
484 }
485
486 /**
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100487 * Returns whether this provider is valid for use as a WebView provider.
488 */
489 private static boolean isValidProvider(WebViewProviderInfo configInfo,
490 PackageInfo packageInfo) {
491 if (providerHasValidSignature(configInfo, packageInfo) &&
492 WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) != null) {
493 return true;
494 }
495 return false;
496 }
497
498 private static boolean providerHasValidSignature(WebViewProviderInfo provider,
499 PackageInfo packageInfo) {
500 if (Build.IS_DEBUGGABLE)
501 return true;
502 Signature[] packageSignatures;
503 // If no signature is declared, instead check whether the package is included in the
504 // system.
505 if (provider.signatures == null || provider.signatures.length == 0) {
506 return packageInfo.applicationInfo.isSystemApp();
507 }
508 packageSignatures = packageInfo.signatures;
509 if (packageSignatures.length != 1)
510 return false;
511
512 final byte[] packageSignature = packageSignatures[0].toByteArray();
513 // Return whether the package signature matches any of the valid signatures
514 for (String signature : provider.signatures) {
515 final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
516 if (Arrays.equals(packageSignature, validSignature))
517 return true;
518 }
519 return false;
520 }
521
522 /**
523 * Returns whether the given package is enabled.
524 * This state can be changed by the user from Settings->Apps
525 */
526 private static boolean isEnabledPackage(PackageInfo packageInfo) {
527 return packageInfo.applicationInfo.enabled;
528 }
529
530 private static PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
531 throws NameNotFoundException {
532 PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
533 return pm.getPackageInfo(configInfo.packageName, PACKAGE_FLAGS);
534 }
535
536 // flags declaring we want extra info from the package manager for webview providers
537 private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
538 | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
539
540 /**
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000541 * Returns whether WebView is ready and is not going to go through its preparation phase again
542 * directly.
543 */
544 private boolean webViewIsReadyLocked() {
545 return !mWebViewPackageDirty
546 && (mNumRelroCreationsStarted == mNumRelroCreationsFinished)
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000547 // The current package might be replaced though we haven't received an intent declaring
548 // this yet, the following flag makes anyone loading WebView to wait in this case.
549 && mAnyWebViewInstalled;
550 }
551
552 private void checkIfRelrosDoneLocked() {
553 if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
554 if (mWebViewPackageDirty) {
555 mWebViewPackageDirty = false;
556 // If we have changed provider since we started the relro creation we need to
557 // redo the whole process using the new package instead.
Gustav Sennton26c82ff2016-03-11 13:06:40 +0000558 PackageInfo newPackage = findPreferredWebViewPackage();
559 onWebViewProviderChanged(newPackage);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000560 } else {
561 this.notifyAll();
562 }
563 }
Ben Murdochdc00a842014-07-17 14:55:00 +0100564 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100565
566 private class BinderService extends IWebViewUpdateService.Stub {
567
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000568 @Override
569 public void onShellCommand(FileDescriptor in, FileDescriptor out,
570 FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
571 (new WebViewUpdateServiceShellCommand(this)).exec(
572 this, in, out, err, args, resultReceiver);
573 }
574
575
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100576 /**
577 * The shared relro process calls this to notify us that it's done trying to create a relro
578 * file. This method gets called even if the relro creation has failed or the process
579 * crashed.
580 */
581 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000582 public void notifyRelroCreationCompleted() {
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100583 // Verify that the caller is either the shared relro process (nominal case) or the
584 // system server (only in the case the relro process crashes and we get here via the
585 // crashHandler).
586 if (Binder.getCallingUid() != Process.SHARED_RELRO_UID &&
587 Binder.getCallingUid() != Process.SYSTEM_UID) {
588 return;
589 }
590
Gustav Sennton275d13c2016-02-24 10:58:09 +0000591 long callingId = Binder.clearCallingIdentity();
592 try {
593 synchronized (WebViewUpdateService.this) {
594 mNumRelroCreationsFinished++;
595 checkIfRelrosDoneLocked();
596 }
597 } finally {
598 Binder.restoreCallingIdentity(callingId);
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100599 }
600 }
601
602 /**
603 * WebViewFactory calls this to block WebView loading until the relro file is created.
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000604 * Returns the WebView provider for which we create relro files.
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100605 */
606 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000607 public WebViewProviderResponse waitForAndGetProvider() {
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100608 // The WebViewUpdateService depends on the prepareWebViewInSystemServer call, which
609 // happens later (during the PHASE_ACTIVITY_MANAGER_READY) in SystemServer.java. If
610 // another service there tries to bring up a WebView in the between, the wait below
611 // would deadlock without the check below.
612 if (Binder.getCallingPid() == Process.myPid()) {
613 throw new IllegalStateException("Cannot create a WebView from the SystemServer");
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100614 }
615
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000616 PackageInfo webViewPackage = null;
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100617 final long NS_PER_MS = 1000000;
618 final long timeoutTimeMs = System.nanoTime() / NS_PER_MS + WAIT_TIMEOUT_MS;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000619 boolean webViewReady = false;
620 int webViewStatus = WebViewFactory.LIBLOAD_SUCCESS;
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100621 synchronized (WebViewUpdateService.this) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000622 webViewReady = WebViewUpdateService.this.webViewIsReadyLocked();
623 while (!webViewReady) {
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100624 final long timeNowMs = System.nanoTime() / NS_PER_MS;
625 if (timeNowMs >= timeoutTimeMs) break;
626 try {
627 WebViewUpdateService.this.wait(timeoutTimeMs - timeNowMs);
628 } catch (InterruptedException e) {}
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000629 webViewReady = WebViewUpdateService.this.webViewIsReadyLocked();
630 }
631 // Make sure we return the provider that was used to create the relro file
632 webViewPackage = WebViewUpdateService.this.mCurrentWebViewPackage;
633 if (webViewReady) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000634 } else if (!mAnyWebViewInstalled) {
635 webViewStatus = WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
636 } else {
637 // Either the current relro creation isn't done yet, or the new relro creatioin
638 // hasn't kicked off yet (the last relro creation used an out-of-date WebView).
639 webViewStatus = WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO;
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100640 }
641 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000642 if (!webViewReady) Slog.w(TAG, "creating relro file timed out");
643 return new WebViewProviderResponse(webViewPackage, webViewStatus);
644 }
645
646 /**
647 * This is called from DeveloperSettings when the user changes WebView provider.
648 */
649 @Override // Binder call
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000650 public String changeProviderAndSetting(String newProvider) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000651 if (getContext().checkCallingPermission(
652 android.Manifest.permission.WRITE_SECURE_SETTINGS)
653 != PackageManager.PERMISSION_GRANTED) {
654 String msg = "Permission Denial: changeProviderAndSetting() from pid="
655 + Binder.getCallingPid()
656 + ", uid=" + Binder.getCallingUid()
657 + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
658 Slog.w(TAG, msg);
659 throw new SecurityException(msg);
660 }
661
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000662 return WebViewUpdateService.this.changeProviderAndSetting(newProvider);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000663 }
664
665 @Override // Binder call
666 public WebViewProviderInfo[] getValidWebViewPackages() {
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100667 return WebViewUpdateService.this.getValidWebViewPackages();
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000668 }
669
670 @Override // Binder call
Gustav Sennton8b179262016-03-14 11:31:14 +0000671 public WebViewProviderInfo[] getAllWebViewPackages() {
672 return WebViewUpdateService.this.mWebViewUtility.getWebViewPackages();
673 }
674
675 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000676 public String getCurrentWebViewPackageName() {
677 synchronized(WebViewUpdateService.this) {
678 if (WebViewUpdateService.this.mCurrentWebViewPackage == null)
679 return null;
680 return WebViewUpdateService.this.mCurrentWebViewPackage.packageName;
681 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100682 }
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000683
684 @Override // Binder call
685 public boolean isFallbackPackage(String packageName) {
Gustav Sennton8b179262016-03-14 11:31:14 +0000686 return WebViewUpdateService.this.isFallbackPackage(packageName);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000687 }
688
689 @Override // Binder call
690 public void enableFallbackLogic(boolean enable) {
691 if (getContext().checkCallingPermission(
692 android.Manifest.permission.WRITE_SECURE_SETTINGS)
693 != PackageManager.PERMISSION_GRANTED) {
694 String msg = "Permission Denial: enableFallbackLogic() from pid="
695 + Binder.getCallingPid()
696 + ", uid=" + Binder.getCallingUid()
697 + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
698 Slog.w(TAG, msg);
699 throw new SecurityException(msg);
700 }
701
702 WebViewUpdateService.enableFallbackLogic(enable);
703 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100704 }
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100705}