blob: 846169cbf9c307c3ebba980ffc72e81652b08510 [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
Ben Murdochdc00a842014-07-17 14:55:00 +010019import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000023import android.content.pm.PackageManager;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010024import android.os.Binder;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000025import android.os.PatternMatcher;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010026import android.os.Process;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000027import android.os.ResultReceiver;
Gustav Sennton23875b22016-02-09 14:11:33 +000028import android.os.UserHandle;
Primiano Tucci810c0522014-07-25 18:03:16 +010029import android.util.Slog;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010030import android.webkit.IWebViewUpdateService;
Gustav Sennton8b179262016-03-14 11:31:14 +000031import android.webkit.WebViewFactory;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000032import android.webkit.WebViewProviderInfo;
33import android.webkit.WebViewProviderResponse;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010034
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010035import com.android.server.SystemService;
36
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000037import java.io.FileDescriptor;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000038import java.util.Arrays;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000039
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010040/**
41 * Private service to wait for the updatable WebView to be ready for use.
42 * @hide
43 */
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010044public class WebViewUpdateService extends SystemService {
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010045
46 private static final String TAG = "WebViewUpdateService";
Gustav Sennton6ce92c92015-10-23 11:10:39 +010047
Ben Murdochdc00a842014-07-17 14:55:00 +010048 private BroadcastReceiver mWebViewUpdatedReceiver;
Gustav Sennton79fea482016-04-07 14:22:56 +010049 private WebViewUpdateServiceImpl mImpl;
Ben Murdochdc00a842014-07-17 14:55:00 +010050
Gustav Sennton3a6e6b22016-04-05 14:09:09 +010051 static final int PACKAGE_CHANGED = 0;
52 static final int PACKAGE_ADDED = 1;
53 static final int PACKAGE_ADDED_REPLACED = 2;
54 static final int PACKAGE_REMOVED = 3;
55
Ben Murdochdc00a842014-07-17 14:55:00 +010056 public WebViewUpdateService(Context context) {
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010057 super(context);
Hui Shu9455bd02016-04-08 13:25:26 -070058 mImpl = new WebViewUpdateServiceImpl(context, SystemImpl.getInstance());
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +010059 }
60
61 @Override
62 public void onStart() {
Ben Murdochdc00a842014-07-17 14:55:00 +010063 mWebViewUpdatedReceiver = new BroadcastReceiver() {
64 @Override
65 public void onReceive(Context context, Intent intent) {
Gustav Sennton0df2c552016-06-14 15:32:19 +010066 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
Gustav Sennton3a6e6b22016-04-05 14:09:09 +010067 switch (intent.getAction()) {
68 case Intent.ACTION_PACKAGE_REMOVED:
69 // When a package is replaced we will receive two intents, one
70 // representing the removal of the old package and one representing the
71 // addition of the new package.
72 // In the case where we receive an intent to remove the old version of
73 // the package that is being replaced we early-out here so that we don't
74 // run the update-logic twice.
75 if (intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) return;
Gustav Sennton79fea482016-04-07 14:22:56 +010076 mImpl.packageStateChanged(packageNameFromIntent(intent),
Gustav Sennton0df2c552016-06-14 15:32:19 +010077 PACKAGE_REMOVED, userId);
Gustav Sennton3a6e6b22016-04-05 14:09:09 +010078 break;
79 case Intent.ACTION_PACKAGE_CHANGED:
80 // Ensure that we only heed PACKAGE_CHANGED intents if they change an
81 // entire package, not just a component
82 if (entirePackageChanged(intent)) {
Gustav Sennton79fea482016-04-07 14:22:56 +010083 mImpl.packageStateChanged(packageNameFromIntent(intent),
Gustav Sennton0df2c552016-06-14 15:32:19 +010084 PACKAGE_CHANGED, userId);
Gustav Sennton6258dcd2015-10-30 19:25:37 +000085 }
Gustav Sennton3a6e6b22016-04-05 14:09:09 +010086 break;
87 case Intent.ACTION_PACKAGE_ADDED:
Gustav Sennton79fea482016-04-07 14:22:56 +010088 mImpl.packageStateChanged(packageNameFromIntent(intent),
Gustav Sennton3a6e6b22016-04-05 14:09:09 +010089 (intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)
Gustav Sennton0df2c552016-06-14 15:32:19 +010090 ? PACKAGE_ADDED_REPLACED : PACKAGE_ADDED), userId);
Gustav Sennton3a6e6b22016-04-05 14:09:09 +010091 break;
92 case Intent.ACTION_USER_ADDED:
Gustav Sennton79fea482016-04-07 14:22:56 +010093 mImpl.handleNewUser(userId);
Gustav Sennton3a6e6b22016-04-05 14:09:09 +010094 break;
Ben Murdochdc00a842014-07-17 14:55:00 +010095 }
96 }
97 };
98 IntentFilter filter = new IntentFilter();
Gustav Sennton3098cf22015-11-10 03:33:09 +000099 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
100 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000101 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Ben Murdochdc00a842014-07-17 14:55:00 +0100102 filter.addDataScheme("package");
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000103 // Make sure we only receive intents for WebView packages from our config file.
Gustav Sennton79fea482016-04-07 14:22:56 +0100104 for (WebViewProviderInfo provider : mImpl.getWebViewPackages()) {
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000105 filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
106 }
Gustav Sennton0df2c552016-06-14 15:32:19 +0100107
108 getContext().registerReceiverAsUser(mWebViewUpdatedReceiver, UserHandle.ALL, filter,
109 null /* broadcast permission */, null /* handler */);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100110
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000111 IntentFilter userAddedFilter = new IntentFilter();
112 userAddedFilter.addAction(Intent.ACTION_USER_ADDED);
Gustav Sennton0df2c552016-06-14 15:32:19 +0100113 getContext().registerReceiverAsUser(mWebViewUpdatedReceiver, UserHandle.ALL,
114 userAddedFilter, null /* broadcast permission */, null /* handler */);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000115
Torne (Richard Coles)fc19b0a2016-02-01 16:16:57 +0000116 publishBinderService("webviewupdate", new BinderService(), true /*allowIsolated*/);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100117 }
Ben Murdochdc00a842014-07-17 14:55:00 +0100118
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100119 public void prepareWebViewInSystemServer() {
Gustav Sennton79fea482016-04-07 14:22:56 +0100120 mImpl.prepareWebViewInSystemServer();
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100121 }
122
123 private static String packageNameFromIntent(Intent intent) {
124 return intent.getDataString().substring("package:".length());
125 }
126
Gustav Sennton065b7e62016-04-01 15:11:43 +0100127 /**
128 * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather
129 * than just one of its components).
130 * @hide
131 */
132 public static boolean entirePackageChanged(Intent intent) {
133 String[] componentList =
134 intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
135 return Arrays.asList(componentList).contains(
136 intent.getDataString().substring("package:".length()));
Gustav Senntondbf5eb02016-03-30 14:53:03 +0100137 }
138
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100139 private class BinderService extends IWebViewUpdateService.Stub {
140
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000141 @Override
142 public void onShellCommand(FileDescriptor in, FileDescriptor out,
143 FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
144 (new WebViewUpdateServiceShellCommand(this)).exec(
145 this, in, out, err, args, resultReceiver);
146 }
147
148
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100149 /**
150 * The shared relro process calls this to notify us that it's done trying to create a relro
151 * file. This method gets called even if the relro creation has failed or the process
152 * crashed.
153 */
154 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000155 public void notifyRelroCreationCompleted() {
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100156 // Verify that the caller is either the shared relro process (nominal case) or the
157 // system server (only in the case the relro process crashes and we get here via the
158 // crashHandler).
159 if (Binder.getCallingUid() != Process.SHARED_RELRO_UID &&
160 Binder.getCallingUid() != Process.SYSTEM_UID) {
161 return;
162 }
163
Gustav Sennton275d13c2016-02-24 10:58:09 +0000164 long callingId = Binder.clearCallingIdentity();
165 try {
Gustav Sennton79fea482016-04-07 14:22:56 +0100166 WebViewUpdateService.this.mImpl.notifyRelroCreationCompleted();
Gustav Sennton275d13c2016-02-24 10:58:09 +0000167 } finally {
168 Binder.restoreCallingIdentity(callingId);
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100169 }
170 }
171
172 /**
173 * WebViewFactory calls this to block WebView loading until the relro file is created.
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000174 * Returns the WebView provider for which we create relro files.
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100175 */
176 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000177 public WebViewProviderResponse waitForAndGetProvider() {
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100178 // The WebViewUpdateService depends on the prepareWebViewInSystemServer call, which
179 // happens later (during the PHASE_ACTIVITY_MANAGER_READY) in SystemServer.java. If
180 // another service there tries to bring up a WebView in the between, the wait below
181 // would deadlock without the check below.
182 if (Binder.getCallingPid() == Process.myPid()) {
183 throw new IllegalStateException("Cannot create a WebView from the SystemServer");
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100184 }
185
Gustav Sennton79fea482016-04-07 14:22:56 +0100186 return WebViewUpdateService.this.mImpl.waitForAndGetProvider();
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000187 }
188
189 /**
190 * This is called from DeveloperSettings when the user changes WebView provider.
191 */
192 @Override // Binder call
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000193 public String changeProviderAndSetting(String newProvider) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000194 if (getContext().checkCallingPermission(
195 android.Manifest.permission.WRITE_SECURE_SETTINGS)
196 != PackageManager.PERMISSION_GRANTED) {
197 String msg = "Permission Denial: changeProviderAndSetting() from pid="
198 + Binder.getCallingPid()
199 + ", uid=" + Binder.getCallingUid()
200 + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
201 Slog.w(TAG, msg);
202 throw new SecurityException(msg);
203 }
204
Gustav Senntonab3b6b12016-03-16 17:38:42 +0000205 long callingId = Binder.clearCallingIdentity();
206 try {
Gustav Sennton79fea482016-04-07 14:22:56 +0100207 return WebViewUpdateService.this.mImpl.changeProviderAndSetting(
Gustav Sennton3a6e6b22016-04-05 14:09:09 +0100208 newProvider);
Gustav Senntonab3b6b12016-03-16 17:38:42 +0000209 } finally {
210 Binder.restoreCallingIdentity(callingId);
211 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000212 }
213
214 @Override // Binder call
215 public WebViewProviderInfo[] getValidWebViewPackages() {
Gustav Sennton79fea482016-04-07 14:22:56 +0100216 return WebViewUpdateService.this.mImpl.getValidWebViewPackages();
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000217 }
218
219 @Override // Binder call
Gustav Sennton8b179262016-03-14 11:31:14 +0000220 public WebViewProviderInfo[] getAllWebViewPackages() {
Gustav Sennton79fea482016-04-07 14:22:56 +0100221 return WebViewUpdateService.this.mImpl.getWebViewPackages();
Gustav Sennton8b179262016-03-14 11:31:14 +0000222 }
223
224 @Override // Binder call
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000225 public String getCurrentWebViewPackageName() {
Gustav Sennton79fea482016-04-07 14:22:56 +0100226 return WebViewUpdateService.this.mImpl.getCurrentWebViewPackageName();
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100227 }
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000228
229 @Override // Binder call
230 public boolean isFallbackPackage(String packageName) {
Gustav Sennton79fea482016-04-07 14:22:56 +0100231 return WebViewUpdateService.this.mImpl.isFallbackPackage(packageName);
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000232 }
233
234 @Override // Binder call
235 public void enableFallbackLogic(boolean enable) {
236 if (getContext().checkCallingPermission(
237 android.Manifest.permission.WRITE_SECURE_SETTINGS)
238 != PackageManager.PERMISSION_GRANTED) {
239 String msg = "Permission Denial: enableFallbackLogic() from pid="
240 + Binder.getCallingPid()
241 + ", uid=" + Binder.getCallingUid()
242 + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
243 Slog.w(TAG, msg);
244 throw new SecurityException(msg);
245 }
246
Gustav Sennton6824c7c2016-04-04 14:07:23 +0100247 long callingId = Binder.clearCallingIdentity();
248 try {
249 WebViewUpdateService.this.mImpl.enableFallbackLogic(enable);
250 } finally {
251 Binder.restoreCallingIdentity(callingId);
252 }
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000253 }
Torne (Richard Coles)4dbeb352014-07-29 19:14:24 +0100254 }
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100255}