blob: d4949b6893d74c6ae9826b1af1f7cea825bdd958 [file] [log] [blame]
Gustav Sennton79fea482016-04-07 14:22:56 +01001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.server.webkit;
17
18import android.content.Context;
19import android.content.pm.ApplicationInfo;
20import android.content.pm.PackageInfo;
Gustav Sennton79fea482016-04-07 14:22:56 +010021import android.content.pm.Signature;
Gustav Sennton0df2c552016-06-14 15:32:19 +010022import android.os.UserHandle;
Gustav Sennton79fea482016-04-07 14:22:56 +010023import android.util.Slog;
Gustav Sennton364e1602016-12-14 09:10:50 +000024import android.webkit.UserPackage;
Gustav Sennton79fea482016-04-07 14:22:56 +010025import android.webkit.WebViewProviderInfo;
26import android.webkit.WebViewProviderResponse;
27
Gustav Sennton1eb38202016-10-21 13:40:10 +010028import java.io.PrintWriter;
Gustav Senntonb2650162017-04-07 14:41:38 +010029import java.lang.Integer;
Gustav Sennton79fea482016-04-07 14:22:56 +010030import java.util.List;
31
32/**
33 * Implementation of the WebViewUpdateService.
34 * This class doesn't depend on the android system like the actual Service does and can be used
35 * directly by tests (as long as they implement a SystemInterface).
Gustav Sennton47d7ec82016-06-07 15:02:58 +010036 *
37 * This class implements two main features - handling WebView fallback packages and keeping track
38 * of, and preparing, the current WebView implementation. The fallback mechanism is meant to be
39 * uncoupled from the rest of the WebView preparation and does not store any state. The code for
40 * choosing and preparing a WebView implementation needs to keep track of a couple of different
41 * things such as what package is used as WebView implementation.
42 *
43 * The public methods in this class are accessed from WebViewUpdateService either on the UI thread
44 * or on one of multiple Binder threads. This means that the code in this class needs to be
45 * thread-safe. The fallback mechanism shares (almost) no information between threads which makes
46 * it easier to argue about thread-safety (in theory, if timed badly, the fallback mechanism can
47 * incorrectly enable/disable a fallback package but that fault will be corrected when we later
48 * receive an intent for that enabling/disabling). On the other hand, the WebView preparation code
49 * shares state between threads meaning that code that chooses a new WebView implementation or
50 * checks which implementation is being used needs to hold a lock.
51 *
52 * The WebViewUpdateService can be accessed in a couple of different ways.
53 * 1. It is started from the SystemServer at boot - at that point we just initiate some state such
54 * as the WebView preparation class.
55 * 2. The SystemServer calls WebViewUpdateService.prepareWebViewInSystemServer. This happens at boot
56 * and the WebViewUpdateService should not have been accessed before this call. In this call we
57 * enable/disable fallback packages and then choose WebView implementation for the first time.
58 * 3. The update service listens for Intents related to package installs and removals. These intents
59 * are received and processed on the UI thread. Each intent can result in enabling/disabling
60 * fallback packages and changing WebView implementation.
61 * 4. The update service can be reached through Binder calls which are handled on specific binder
62 * threads. These calls can be made from any process. Generally they are used for changing WebView
63 * implementation (from Settings), getting information about the current WebView implementation (for
64 * loading WebView into an app process), or notifying the service about Relro creation being
65 * completed.
66 *
Gustav Sennton79fea482016-04-07 14:22:56 +010067 * @hide
68 */
69public class WebViewUpdateServiceImpl {
70 private static final String TAG = WebViewUpdateServiceImpl.class.getSimpleName();
71
72 private SystemInterface mSystemInterface;
73 private WebViewUpdater mWebViewUpdater;
Gustav Sennton86f7bbe2016-10-24 16:49:32 +010074 final private Context mContext;
Gustav Sennton79fea482016-04-07 14:22:56 +010075
Gustav Senntonb2650162017-04-07 14:41:38 +010076 private final static int MULTIPROCESS_SETTING_ON_VALUE = Integer.MAX_VALUE;
77 private final static int MULTIPROCESS_SETTING_OFF_VALUE = Integer.MIN_VALUE;
78
Gustav Sennton79fea482016-04-07 14:22:56 +010079 public WebViewUpdateServiceImpl(Context context, SystemInterface systemInterface) {
80 mContext = context;
81 mSystemInterface = systemInterface;
82 mWebViewUpdater = new WebViewUpdater(mContext, mSystemInterface);
83 }
84
Gustav Sennton0df2c552016-06-14 15:32:19 +010085 void packageStateChanged(String packageName, int changedState, int userId) {
86 // We don't early out here in different cases where we could potentially early-out (e.g. if
87 // we receive PACKAGE_CHANGED for another user than the system user) since that would
88 // complicate this logic further and open up for more edge cases.
Gustav Sennton79fea482016-04-07 14:22:56 +010089 updateFallbackStateOnPackageChange(packageName, changedState);
90 mWebViewUpdater.packageStateChanged(packageName, changedState);
91 }
92
93 void prepareWebViewInSystemServer() {
94 updateFallbackStateOnBoot();
95 mWebViewUpdater.prepareWebViewInSystemServer();
Torne (Richard Coles)1a4c4e32017-01-10 15:57:41 +000096 mSystemInterface.notifyZygote(isMultiProcessEnabled());
Gustav Sennton79fea482016-04-07 14:22:56 +010097 }
98
99 private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
100 for (WebViewProviderInfo provider : providers) {
101 if (provider.availableByDefault && !provider.isFallback) {
Gustav Sennton364e1602016-12-14 09:10:50 +0000102 // userPackages can contain null objects.
103 List<UserPackage> userPackages =
104 mSystemInterface.getPackageInfoForProviderAllUsers(mContext, provider);
Gustav Sennton924dacd2017-03-10 14:37:15 +0000105 if (WebViewUpdater.isInstalledAndEnabledForAllUsers(userPackages) &&
Gustav Sennton364e1602016-12-14 09:10:50 +0000106 // Checking validity of the package for the system user (rather than all
107 // users) since package validity depends not on the user but on the package
108 // itself.
109 mWebViewUpdater.isValidProvider(provider,
110 userPackages.get(UserHandle.USER_SYSTEM).getPackageInfo())) {
111 return true;
Gustav Sennton79fea482016-04-07 14:22:56 +0100112 }
113 }
114 }
115 return false;
116 }
117
Gustav Sennton79fea482016-04-07 14:22:56 +0100118 void handleNewUser(int userId) {
Gustav Senntona43f1442017-03-23 17:04:23 +0000119 // The system user is always started at boot, and by that point we have already run one
120 // round of the package-changing logic (through prepareWebViewInSystemServer()), so early
121 // out here.
122 if (userId == UserHandle.USER_SYSTEM) return;
Gustav Sennton364e1602016-12-14 09:10:50 +0000123 handleUserChange();
124 }
Gustav Sennton79fea482016-04-07 14:22:56 +0100125
Gustav Sennton364e1602016-12-14 09:10:50 +0000126 void handleUserRemoved(int userId) {
127 handleUserChange();
128 }
Gustav Sennton79fea482016-04-07 14:22:56 +0100129
Gustav Sennton364e1602016-12-14 09:10:50 +0000130 /**
131 * Called when a user was added or removed to ensure fallback logic and WebView preparation are
132 * triggered. This has to be done since the WebView package we use depends on the enabled-state
133 * of packages for all users (so adding or removing a user might cause us to change package).
134 */
135 private void handleUserChange() {
136 if (mSystemInterface.isFallbackLogicEnabled()) {
137 updateFallbackState(mSystemInterface.getWebViewPackages());
138 }
139 // Potentially trigger package-changing logic.
140 mWebViewUpdater.updateCurrentWebViewPackage(null);
Gustav Sennton79fea482016-04-07 14:22:56 +0100141 }
142
143 void notifyRelroCreationCompleted() {
144 mWebViewUpdater.notifyRelroCreationCompleted();
145 }
146
147 WebViewProviderResponse waitForAndGetProvider() {
148 return mWebViewUpdater.waitForAndGetProvider();
149 }
150
151 String changeProviderAndSetting(String newProvider) {
152 return mWebViewUpdater.changeProviderAndSetting(newProvider);
153 }
154
155 WebViewProviderInfo[] getValidWebViewPackages() {
Gustav Sennton364e1602016-12-14 09:10:50 +0000156 return mWebViewUpdater.getValidWebViewPackages();
Gustav Sennton79fea482016-04-07 14:22:56 +0100157 }
158
159 WebViewProviderInfo[] getWebViewPackages() {
160 return mSystemInterface.getWebViewPackages();
161 }
162
Gustav Senntonbf683e02016-09-15 14:42:50 +0100163 PackageInfo getCurrentWebViewPackage() {
164 return mWebViewUpdater.getCurrentWebViewPackage();
Gustav Sennton79fea482016-04-07 14:22:56 +0100165 }
166
167 void enableFallbackLogic(boolean enable) {
168 mSystemInterface.enableFallbackLogic(enable);
169 }
170
171 private void updateFallbackStateOnBoot() {
Gustav Sennton53b78242016-04-07 15:56:10 +0100172 if (!mSystemInterface.isFallbackLogicEnabled()) return;
173
Gustav Sennton79fea482016-04-07 14:22:56 +0100174 WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
Gustav Sennton364e1602016-12-14 09:10:50 +0000175 updateFallbackState(webviewProviders);
Gustav Sennton79fea482016-04-07 14:22:56 +0100176 }
177
178 /**
179 * Handle the enabled-state of our fallback package, i.e. if there exists some non-fallback
180 * package that is valid (and available by default) then disable the fallback package,
181 * otherwise, enable the fallback package.
182 */
183 private void updateFallbackStateOnPackageChange(String changedPackage, int changedState) {
184 if (!mSystemInterface.isFallbackLogicEnabled()) return;
185
186 WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
187
188 // A package was changed / updated / downgraded, early out if it is not one of the
189 // webview packages that are available by default.
190 boolean changedPackageAvailableByDefault = false;
191 for (WebViewProviderInfo provider : webviewProviders) {
192 if (provider.packageName.equals(changedPackage)) {
193 if (provider.availableByDefault) {
194 changedPackageAvailableByDefault = true;
195 }
196 break;
197 }
198 }
199 if (!changedPackageAvailableByDefault) return;
Gustav Sennton364e1602016-12-14 09:10:50 +0000200 updateFallbackState(webviewProviders);
Gustav Sennton79fea482016-04-07 14:22:56 +0100201 }
202
Gustav Sennton364e1602016-12-14 09:10:50 +0000203 private void updateFallbackState(WebViewProviderInfo[] webviewProviders) {
Gustav Sennton79fea482016-04-07 14:22:56 +0100204 // If there exists a valid and enabled non-fallback package - disable the fallback
205 // package, otherwise, enable it.
206 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
207 if (fallbackProvider == null) return;
208 boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
209
Gustav Sennton364e1602016-12-14 09:10:50 +0000210 List<UserPackage> userPackages =
211 mSystemInterface.getPackageInfoForProviderAllUsers(mContext, fallbackProvider);
212 if (existsValidNonFallbackProvider && !isDisabledForAllUsers(userPackages)) {
Gustav Sennton79fea482016-04-07 14:22:56 +0100213 mSystemInterface.uninstallAndDisablePackageForAllUsers(mContext,
214 fallbackProvider.packageName);
215 } else if (!existsValidNonFallbackProvider
Gustav Sennton924dacd2017-03-10 14:37:15 +0000216 && !WebViewUpdater.isInstalledAndEnabledForAllUsers(userPackages)) {
Gustav Sennton79fea482016-04-07 14:22:56 +0100217 // Enable the fallback package for all users.
218 mSystemInterface.enablePackageForAllUsers(mContext,
219 fallbackProvider.packageName, true);
220 }
221 }
222
223 /**
224 * Returns the only fallback provider in the set of given packages, or null if there is none.
225 */
226 private static WebViewProviderInfo getFallbackProvider(WebViewProviderInfo[] webviewPackages) {
227 for (WebViewProviderInfo provider : webviewPackages) {
228 if (provider.isFallback) {
229 return provider;
230 }
231 }
232 return null;
233 }
234
235 boolean isFallbackPackage(String packageName) {
236 if (packageName == null || !mSystemInterface.isFallbackLogicEnabled()) return false;
237
238 WebViewProviderInfo[] webviewPackages = mSystemInterface.getWebViewPackages();
239 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
240 return (fallbackProvider != null
241 && packageName.equals(fallbackProvider.packageName));
242 }
243
Torne (Richard Coles)1a4c4e32017-01-10 15:57:41 +0000244 boolean isMultiProcessEnabled() {
Torne (Richard Coles)dc375072017-01-11 15:48:13 +0000245 int settingValue = mSystemInterface.getMultiProcessSetting(mContext);
246 if (mSystemInterface.isMultiProcessDefaultEnabled()) {
Gustav Senntonb2650162017-04-07 14:41:38 +0100247 // Multiprocess should be enabled unless the user has turned it off manually.
248 return settingValue > MULTIPROCESS_SETTING_OFF_VALUE;
Torne (Richard Coles)dc375072017-01-11 15:48:13 +0000249 } else {
Gustav Senntonb2650162017-04-07 14:41:38 +0100250 // Multiprocess should not be enabled, unless the user has turned it on manually.
251 return settingValue >= MULTIPROCESS_SETTING_ON_VALUE;
Torne (Richard Coles)dc375072017-01-11 15:48:13 +0000252 }
Torne (Richard Coles)1a4c4e32017-01-10 15:57:41 +0000253 }
254
255 void enableMultiProcess(boolean enable) {
256 PackageInfo current = getCurrentWebViewPackage();
Torne (Richard Coles)dc375072017-01-11 15:48:13 +0000257 mSystemInterface.setMultiProcessSetting(mContext,
Gustav Senntonb2650162017-04-07 14:41:38 +0100258 enable ? MULTIPROCESS_SETTING_ON_VALUE : MULTIPROCESS_SETTING_OFF_VALUE);
Torne (Richard Coles)1a4c4e32017-01-10 15:57:41 +0000259 mSystemInterface.notifyZygote(enable);
260 if (current != null) {
261 mSystemInterface.killPackageDependents(current.packageName);
262 }
263 }
264
Gustav Sennton364e1602016-12-14 09:10:50 +0000265 private static boolean isDisabledForAllUsers(List<UserPackage> userPackages) {
266 for (UserPackage userPackage : userPackages) {
267 if (userPackage.getPackageInfo() != null && userPackage.isEnabledPackage()) {
268 return false;
269 }
270 }
271 return true;
Gustav Sennton0df2c552016-06-14 15:32:19 +0100272 }
273
Robert Sesekded20982016-08-15 13:59:13 -0400274 /**
Gustav Sennton1eb38202016-10-21 13:40:10 +0100275 * Dump the state of this Service.
276 */
277 void dumpState(PrintWriter pw) {
278 pw.println("Current WebView Update Service state");
279 pw.println(String.format(" Fallback logic enabled: %b",
280 mSystemInterface.isFallbackLogicEnabled()));
Gustav Senntonb0c715b2017-06-02 11:20:18 +0100281 pw.println(String.format(" Multiprocess enabled: %b", isMultiProcessEnabled()));
Gustav Sennton1eb38202016-10-21 13:40:10 +0100282 mWebViewUpdater.dumpState(pw);
283 }
Gustav Sennton79fea482016-04-07 14:22:56 +0100284}