blob: 11fd7953e08f5d8c7832be8a150c1a1ab83773e1 [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;
Gustav Sennton79fea482016-04-07 14:22:56 +010019import android.content.pm.PackageInfo;
Torne (Richard Coles)05a766e2019-04-10 17:55:53 -040020import android.os.AsyncTask;
Gustav Sennton0df2c552016-06-14 15:32:19 +010021import android.os.UserHandle;
Torne (Richard Coles)1ac3f112019-05-28 14:39:16 -040022import android.util.Slog;
Gustav Sennton79fea482016-04-07 14:22:56 +010023import android.webkit.WebViewProviderInfo;
24import android.webkit.WebViewProviderResponse;
25
Gustav Sennton1eb38202016-10-21 13:40:10 +010026import java.io.PrintWriter;
Gustav Sennton79fea482016-04-07 14:22:56 +010027
28/**
29 * Implementation of the WebViewUpdateService.
30 * This class doesn't depend on the android system like the actual Service does and can be used
31 * directly by tests (as long as they implement a SystemInterface).
Gustav Sennton47d7ec82016-06-07 15:02:58 +010032 *
Torne (Richard Coles)ef478902019-03-28 15:03:21 -040033 * This class keeps track of and prepares the current WebView implementation, and needs to keep
34 * track of a couple of different things such as what package is used as WebView implementation.
Gustav Sennton47d7ec82016-06-07 15:02:58 +010035 *
36 * The public methods in this class are accessed from WebViewUpdateService either on the UI thread
Torne (Richard Coles)ef478902019-03-28 15:03:21 -040037 * or on one of multiple Binder threads. The WebView preparation code shares state between threads
38 * meaning that code that chooses a new WebView implementation or checks which implementation is
39 * being used needs to hold a lock.
Gustav Sennton47d7ec82016-06-07 15:02:58 +010040 *
41 * The WebViewUpdateService can be accessed in a couple of different ways.
42 * 1. It is started from the SystemServer at boot - at that point we just initiate some state such
43 * as the WebView preparation class.
44 * 2. The SystemServer calls WebViewUpdateService.prepareWebViewInSystemServer. This happens at boot
45 * and the WebViewUpdateService should not have been accessed before this call. In this call we
Torne (Richard Coles)ef478902019-03-28 15:03:21 -040046 * migrate away from the old fallback logic if necessary and then choose WebView implementation for
47 * the first time.
Gustav Sennton47d7ec82016-06-07 15:02:58 +010048 * 3. The update service listens for Intents related to package installs and removals. These intents
Torne (Richard Coles)ef478902019-03-28 15:03:21 -040049 * are received and processed on the UI thread. Each intent can result in changing WebView
50 * implementation.
Gustav Sennton47d7ec82016-06-07 15:02:58 +010051 * 4. The update service can be reached through Binder calls which are handled on specific binder
52 * threads. These calls can be made from any process. Generally they are used for changing WebView
53 * implementation (from Settings), getting information about the current WebView implementation (for
54 * loading WebView into an app process), or notifying the service about Relro creation being
55 * completed.
56 *
Gustav Sennton79fea482016-04-07 14:22:56 +010057 * @hide
58 */
59public class WebViewUpdateServiceImpl {
60 private static final String TAG = WebViewUpdateServiceImpl.class.getSimpleName();
61
62 private SystemInterface mSystemInterface;
63 private WebViewUpdater mWebViewUpdater;
Gustav Sennton86f7bbe2016-10-24 16:49:32 +010064 final private Context mContext;
Gustav Sennton79fea482016-04-07 14:22:56 +010065
Gustav Senntonb2650162017-04-07 14:41:38 +010066 private final static int MULTIPROCESS_SETTING_ON_VALUE = Integer.MAX_VALUE;
67 private final static int MULTIPROCESS_SETTING_OFF_VALUE = Integer.MIN_VALUE;
68
Gustav Sennton79fea482016-04-07 14:22:56 +010069 public WebViewUpdateServiceImpl(Context context, SystemInterface systemInterface) {
70 mContext = context;
71 mSystemInterface = systemInterface;
72 mWebViewUpdater = new WebViewUpdater(mContext, mSystemInterface);
73 }
74
Gustav Sennton0df2c552016-06-14 15:32:19 +010075 void packageStateChanged(String packageName, int changedState, int userId) {
76 // We don't early out here in different cases where we could potentially early-out (e.g. if
77 // we receive PACKAGE_CHANGED for another user than the system user) since that would
78 // complicate this logic further and open up for more edge cases.
Gustav Sennton79fea482016-04-07 14:22:56 +010079 mWebViewUpdater.packageStateChanged(packageName, changedState);
80 }
81
82 void prepareWebViewInSystemServer() {
Torne (Richard Coles)ef478902019-03-28 15:03:21 -040083 migrateFallbackStateOnBoot();
Gustav Sennton79fea482016-04-07 14:22:56 +010084 mWebViewUpdater.prepareWebViewInSystemServer();
Torne (Richard Coles)d6c5a302019-05-28 16:02:19 -040085 if (getCurrentWebViewPackage() == null) {
86 // We didn't find a valid WebView implementation. Try explicitly re-enabling the
87 // fallback package for all users in case it was disabled, even if we already did the
88 // one-time migration before. If this actually changes the state, WebViewUpdater will
89 // see the PackageManager broadcast shortly and try again.
90 WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
91 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
92 if (fallbackProvider != null) {
93 Slog.w(TAG, "No valid provider, trying to enable " + fallbackProvider.packageName);
94 mSystemInterface.enablePackageForAllUsers(mContext, fallbackProvider.packageName,
95 true);
96 } else {
97 Slog.e(TAG, "No valid provider and no fallback available.");
98 }
99 }
100
Torne (Richard Coles)1bc38ed2019-04-25 13:30:37 -0400101 boolean multiProcessEnabled = isMultiProcessEnabled();
102 mSystemInterface.notifyZygote(multiProcessEnabled);
103 if (multiProcessEnabled) {
104 AsyncTask.THREAD_POOL_EXECUTOR.execute(this::startZygoteWhenReady);
105 }
Torne (Richard Coles)05a766e2019-04-10 17:55:53 -0400106 }
107
108 void startZygoteWhenReady() {
109 // Wait on a background thread for RELRO creation to be done. We ignore the return value
110 // because even if RELRO creation failed we still want to start the zygote.
111 waitForAndGetProvider();
112 mSystemInterface.ensureZygoteStarted();
Gustav Sennton79fea482016-04-07 14:22:56 +0100113 }
114
Gustav Sennton79fea482016-04-07 14:22:56 +0100115 void handleNewUser(int userId) {
Gustav Senntona43f1442017-03-23 17:04:23 +0000116 // The system user is always started at boot, and by that point we have already run one
117 // round of the package-changing logic (through prepareWebViewInSystemServer()), so early
118 // out here.
119 if (userId == UserHandle.USER_SYSTEM) return;
Gustav Sennton364e1602016-12-14 09:10:50 +0000120 handleUserChange();
121 }
Gustav Sennton79fea482016-04-07 14:22:56 +0100122
Gustav Sennton364e1602016-12-14 09:10:50 +0000123 void handleUserRemoved(int userId) {
124 handleUserChange();
125 }
Gustav Sennton79fea482016-04-07 14:22:56 +0100126
Gustav Sennton364e1602016-12-14 09:10:50 +0000127 /**
Torne (Richard Coles)ef478902019-03-28 15:03:21 -0400128 * Called when a user was added or removed to ensure WebView preparation is triggered.
129 * This has to be done since the WebView package we use depends on the enabled-state
Gustav Sennton364e1602016-12-14 09:10:50 +0000130 * of packages for all users (so adding or removing a user might cause us to change package).
131 */
132 private void handleUserChange() {
Gustav Sennton364e1602016-12-14 09:10:50 +0000133 // Potentially trigger package-changing logic.
134 mWebViewUpdater.updateCurrentWebViewPackage(null);
Gustav Sennton79fea482016-04-07 14:22:56 +0100135 }
136
137 void notifyRelroCreationCompleted() {
138 mWebViewUpdater.notifyRelroCreationCompleted();
139 }
140
141 WebViewProviderResponse waitForAndGetProvider() {
142 return mWebViewUpdater.waitForAndGetProvider();
143 }
144
145 String changeProviderAndSetting(String newProvider) {
146 return mWebViewUpdater.changeProviderAndSetting(newProvider);
147 }
148
149 WebViewProviderInfo[] getValidWebViewPackages() {
Gustav Sennton364e1602016-12-14 09:10:50 +0000150 return mWebViewUpdater.getValidWebViewPackages();
Gustav Sennton79fea482016-04-07 14:22:56 +0100151 }
152
153 WebViewProviderInfo[] getWebViewPackages() {
154 return mSystemInterface.getWebViewPackages();
155 }
156
Gustav Senntonbf683e02016-09-15 14:42:50 +0100157 PackageInfo getCurrentWebViewPackage() {
158 return mWebViewUpdater.getCurrentWebViewPackage();
Gustav Sennton79fea482016-04-07 14:22:56 +0100159 }
160
Gustav Sennton79fea482016-04-07 14:22:56 +0100161 /**
Torne (Richard Coles)ef478902019-03-28 15:03:21 -0400162 * If the fallback logic is enabled, re-enable any fallback package for all users, then
163 * disable the fallback logic.
164 *
165 * This migrates away from the old fallback mechanism to the new state where packages are never
166 * automatically enableenableisabled.
Gustav Sennton79fea482016-04-07 14:22:56 +0100167 */
Torne (Richard Coles)ef478902019-03-28 15:03:21 -0400168 private void migrateFallbackStateOnBoot() {
Gustav Sennton79fea482016-04-07 14:22:56 +0100169 if (!mSystemInterface.isFallbackLogicEnabled()) return;
170
171 WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
Gustav Sennton79fea482016-04-07 14:22:56 +0100172 WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
Torne (Richard Coles)ef478902019-03-28 15:03:21 -0400173 if (fallbackProvider != null) {
Torne (Richard Coles)1ac3f112019-05-28 14:39:16 -0400174 Slog.i(TAG, "One-time migration: enabling " + fallbackProvider.packageName);
Torne (Richard Coles)ef478902019-03-28 15:03:21 -0400175 mSystemInterface.enablePackageForAllUsers(mContext, fallbackProvider.packageName, true);
Torne (Richard Coles)1ac3f112019-05-28 14:39:16 -0400176 } else {
177 Slog.i(TAG, "Skipping one-time migration: no fallback provider");
Gustav Sennton79fea482016-04-07 14:22:56 +0100178 }
Torne (Richard Coles)ef478902019-03-28 15:03:21 -0400179 mSystemInterface.enableFallbackLogic(false);
Gustav Sennton79fea482016-04-07 14:22:56 +0100180 }
181
182 /**
183 * Returns the only fallback provider in the set of given packages, or null if there is none.
184 */
185 private static WebViewProviderInfo getFallbackProvider(WebViewProviderInfo[] webviewPackages) {
186 for (WebViewProviderInfo provider : webviewPackages) {
187 if (provider.isFallback) {
188 return provider;
189 }
190 }
191 return null;
192 }
193
Torne (Richard Coles)1a4c4e32017-01-10 15:57:41 +0000194 boolean isMultiProcessEnabled() {
Torne (Richard Coles)dc375072017-01-11 15:48:13 +0000195 int settingValue = mSystemInterface.getMultiProcessSetting(mContext);
196 if (mSystemInterface.isMultiProcessDefaultEnabled()) {
Gustav Senntonb2650162017-04-07 14:41:38 +0100197 // Multiprocess should be enabled unless the user has turned it off manually.
198 return settingValue > MULTIPROCESS_SETTING_OFF_VALUE;
Torne (Richard Coles)dc375072017-01-11 15:48:13 +0000199 } else {
Gustav Senntonb2650162017-04-07 14:41:38 +0100200 // Multiprocess should not be enabled, unless the user has turned it on manually.
201 return settingValue >= MULTIPROCESS_SETTING_ON_VALUE;
Torne (Richard Coles)dc375072017-01-11 15:48:13 +0000202 }
Torne (Richard Coles)1a4c4e32017-01-10 15:57:41 +0000203 }
204
205 void enableMultiProcess(boolean enable) {
206 PackageInfo current = getCurrentWebViewPackage();
Torne (Richard Coles)dc375072017-01-11 15:48:13 +0000207 mSystemInterface.setMultiProcessSetting(mContext,
Gustav Senntonb2650162017-04-07 14:41:38 +0100208 enable ? MULTIPROCESS_SETTING_ON_VALUE : MULTIPROCESS_SETTING_OFF_VALUE);
Torne (Richard Coles)1a4c4e32017-01-10 15:57:41 +0000209 mSystemInterface.notifyZygote(enable);
210 if (current != null) {
211 mSystemInterface.killPackageDependents(current.packageName);
212 }
213 }
214
Robert Sesekded20982016-08-15 13:59:13 -0400215 /**
Gustav Sennton1eb38202016-10-21 13:40:10 +0100216 * Dump the state of this Service.
217 */
218 void dumpState(PrintWriter pw) {
219 pw.println("Current WebView Update Service state");
220 pw.println(String.format(" Fallback logic enabled: %b",
221 mSystemInterface.isFallbackLogicEnabled()));
Gustav Senntonb0c715b2017-06-02 11:20:18 +0100222 pw.println(String.format(" Multiprocess enabled: %b", isMultiProcessEnabled()));
Gustav Sennton1eb38202016-10-21 13:40:10 +0100223 mWebViewUpdater.dumpState(pw);
224 }
Gustav Sennton79fea482016-04-07 14:22:56 +0100225}