blob: 82c7bdbd2d15d8a2934f1cef67b3d102e280e77d [file] [log] [blame]
Gustav Sennton53b78242016-04-07 15:56:10 +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 */
16
17package com.android.server.webkit;
18
Gustav Sennton86f7bbe2016-10-24 16:49:32 +010019import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21
Gustav Sennton53b78242016-04-07 15:56:10 +010022import android.content.Context;
23import android.content.pm.ApplicationInfo;
24import android.content.pm.PackageInfo;
25import android.content.pm.Signature;
26import android.os.Bundle;
Gustav Sennton86f7bbe2016-10-24 16:49:32 +010027import android.support.test.InstrumentationRegistry;
28import android.support.test.runner.AndroidJUnit4;
29import android.test.suitebuilder.annotation.MediumTest;
Gustav Sennton53b78242016-04-07 15:56:10 +010030import android.util.Base64;
Gustav Sennton53b78242016-04-07 15:56:10 +010031import android.webkit.WebViewFactory;
32import android.webkit.WebViewProviderInfo;
33import android.webkit.WebViewProviderResponse;
34
Gustav Sennton53b78242016-04-07 15:56:10 +010035import org.hamcrest.Description;
36
Gustav Sennton86f7bbe2016-10-24 16:49:32 +010037import org.junit.Test;
38import org.junit.runner.RunWith;
39
Gustav Sennton53b78242016-04-07 15:56:10 +010040import org.mockito.Mockito;
41import org.mockito.Matchers;
42import org.mockito.ArgumentMatcher;
43
Gustav Sennton86f7bbe2016-10-24 16:49:32 +010044import java.util.concurrent.CountDownLatch;
45
Gustav Sennton53b78242016-04-07 15:56:10 +010046
47/**
48 * Tests for WebViewUpdateService
49 */
Gustav Sennton86f7bbe2016-10-24 16:49:32 +010050// Use MediumTest instead of SmallTest as the implementation of WebViewUpdateService
51// is intended to work on several threads and uses at least one sleep/wait-statement.
52@RunWith(AndroidJUnit4.class)
53@MediumTest
54public class WebViewUpdateServiceTest {
Gustav Sennton53b78242016-04-07 15:56:10 +010055 private final static String TAG = WebViewUpdateServiceTest.class.getSimpleName();
56
57 private WebViewUpdateServiceImpl mWebViewUpdateServiceImpl;
58 private TestSystemImpl mTestSystemImpl;
59
60 private static final String WEBVIEW_LIBRARY_FLAG = "com.android.webview.WebViewLibrary";
61
Gustav Sennton53b78242016-04-07 15:56:10 +010062 /**
63 * Creates a new instance.
64 */
65 public WebViewUpdateServiceTest() {
66 }
67
68 private void setupWithPackages(WebViewProviderInfo[] packages) {
69 setupWithPackages(packages, true);
70 }
71
72 private void setupWithPackages(WebViewProviderInfo[] packages,
73 boolean fallbackLogicEnabled) {
74 setupWithPackages(packages, fallbackLogicEnabled, 1);
75 }
76
77 private void setupWithPackages(WebViewProviderInfo[] packages,
78 boolean fallbackLogicEnabled, int numRelros) {
79 setupWithPackages(packages, fallbackLogicEnabled, numRelros,
80 true /* isDebuggable == true -> don't check package signatures */);
81 }
82
83 private void setupWithPackages(WebViewProviderInfo[] packages,
84 boolean fallbackLogicEnabled, int numRelros, boolean isDebuggable) {
85 TestSystemImpl testing = new TestSystemImpl(packages, fallbackLogicEnabled, numRelros,
86 isDebuggable);
87 mTestSystemImpl = Mockito.spy(testing);
88 mWebViewUpdateServiceImpl =
89 new WebViewUpdateServiceImpl(null /*Context*/, mTestSystemImpl);
90 }
91
92 private void setEnabledAndValidPackageInfos(WebViewProviderInfo[] providers) {
93 for(WebViewProviderInfo wpi : providers) {
94 mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +010095 true /* valid */, true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +010096 }
97 }
98
Gustav Senntona9159042016-04-11 16:32:52 +010099 private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
Gustav Sennton53b78242016-04-07 15:56:10 +0100100 WebViewProviderInfo[] webviewPackages) {
Gustav Senntona9159042016-04-11 16:32:52 +0100101 checkCertainPackageUsedAfterWebViewBootPreparation(
102 expectedProviderName, webviewPackages, 1);
Gustav Sennton53b78242016-04-07 15:56:10 +0100103 }
104
Gustav Senntona9159042016-04-11 16:32:52 +0100105 private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
Gustav Sennton53b78242016-04-07 15:56:10 +0100106 WebViewProviderInfo[] webviewPackages, int numRelros) {
107 setupWithPackages(webviewPackages, true, numRelros);
108 // Add (enabled and valid) package infos for each provider
109 setEnabledAndValidPackageInfos(webviewPackages);
110
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100111 runWebViewBootPreparationOnMainSync();
Gustav Sennton53b78242016-04-07 15:56:10 +0100112
113 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
114 Mockito.argThat(new IsPackageInfoWithName(expectedProviderName)));
115
116 for (int n = 0; n < numRelros; n++) {
117 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
118 }
119
120 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
121 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
122 assertEquals(expectedProviderName, response.packageInfo.packageName);
123 }
124
125 // For matching the package name of a PackageInfo
126 private class IsPackageInfoWithName extends ArgumentMatcher<PackageInfo> {
127 private final String mPackageName;
128
129 IsPackageInfoWithName(String name) {
130 mPackageName = name;
131 }
132
133 @Override
134 public boolean matches(Object p) {
135 return ((PackageInfo) p).packageName.equals(mPackageName);
136 }
137
138 // Provide a more useful description in case of mismatch
139 @Override
140 public void describeTo (Description description) {
141 description.appendText(String.format("PackageInfo with name '%s'", mPackageName));
142 }
143 }
144
145 private static PackageInfo createPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100146 String packageName, boolean enabled, boolean valid, boolean installed) {
Gustav Sennton53b78242016-04-07 15:56:10 +0100147 PackageInfo p = new PackageInfo();
148 p.packageName = packageName;
149 p.applicationInfo = new ApplicationInfo();
150 p.applicationInfo.enabled = enabled;
151 p.applicationInfo.metaData = new Bundle();
Gustav Sennton0df2c552016-06-14 15:32:19 +0100152 if (installed) {
153 p.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
154 } else {
155 p.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
156 }
Gustav Sennton53b78242016-04-07 15:56:10 +0100157 if (valid) {
158 // no flag means invalid
159 p.applicationInfo.metaData.putString(WEBVIEW_LIBRARY_FLAG, "blah");
160 }
161 return p;
162 }
163
Gustav Sennton0df2c552016-06-14 15:32:19 +0100164 private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid,
165 boolean installed, Signature[] signatures, long updateTime) {
166 PackageInfo p = createPackageInfo(packageName, enabled, valid, installed);
Gustav Sennton53b78242016-04-07 15:56:10 +0100167 p.signatures = signatures;
Gustav Sennton0df2c552016-06-14 15:32:19 +0100168 p.lastUpdateTime = updateTime;
169 return p;
170 }
171
172 private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid,
173 boolean installed, Signature[] signatures, long updateTime, boolean hidden) {
174 PackageInfo p =
175 createPackageInfo(packageName, enabled, valid, installed, signatures, updateTime);
176 if (hidden) {
177 p.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
178 } else {
179 p.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
180 }
Gustav Sennton53b78242016-04-07 15:56:10 +0100181 return p;
182 }
183
Gustav Senntona9159042016-04-11 16:32:52 +0100184 private void checkPreparationPhasesForPackage(String expectedPackage, int numPreparation) {
185 // Verify that onWebViewProviderChanged was called for the numPreparation'th time for the
186 // expected package
187 Mockito.verify(mTestSystemImpl, Mockito.times(numPreparation)).onWebViewProviderChanged(
188 Mockito.argThat(new IsPackageInfoWithName(expectedPackage)));
189
190 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
191
192 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
193 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
194 assertEquals(expectedPackage, response.packageInfo.packageName);
195 }
196
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100197 /**
198 * The WebView preparation boot phase is run on the main thread (especially on a thread with a
199 * looper) so to avoid bugs where our tests fail because a looper hasn't been attached to the
200 * thread running prepareWebViewInSystemServer we run it on the main thread.
201 */
202 private void runWebViewBootPreparationOnMainSync() {
203 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
204 @Override
205 public void run() {
206 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
207 }
208 });
209 }
210
Gustav Sennton53b78242016-04-07 15:56:10 +0100211
212 // ****************
213 // Tests
214 // ****************
215
216
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100217 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100218 public void testWithSinglePackage() {
219 String testPackageName = "test.package.name";
Gustav Senntona9159042016-04-11 16:32:52 +0100220 checkCertainPackageUsedAfterWebViewBootPreparation(testPackageName,
Gustav Sennton53b78242016-04-07 15:56:10 +0100221 new WebViewProviderInfo[] {
222 new WebViewProviderInfo(testPackageName, "",
223 true /*default available*/, false /* fallback */, null)});
224 }
225
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100226 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100227 public void testDefaultPackageUsedOverNonDefault() {
228 String defaultPackage = "defaultPackage";
229 String nonDefaultPackage = "nonDefaultPackage";
230 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
231 new WebViewProviderInfo(nonDefaultPackage, "", false, false, null),
232 new WebViewProviderInfo(defaultPackage, "", true, false, null)};
Gustav Senntona9159042016-04-11 16:32:52 +0100233 checkCertainPackageUsedAfterWebViewBootPreparation(defaultPackage, packages);
Gustav Sennton53b78242016-04-07 15:56:10 +0100234 }
235
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100236 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100237 public void testSeveralRelros() {
238 String singlePackage = "singlePackage";
Gustav Senntona9159042016-04-11 16:32:52 +0100239 checkCertainPackageUsedAfterWebViewBootPreparation(
Gustav Sennton53b78242016-04-07 15:56:10 +0100240 singlePackage,
241 new WebViewProviderInfo[] {
242 new WebViewProviderInfo(singlePackage, "", true /*def av*/, false, null)},
243 2);
244 }
245
246 // Ensure that package with valid signatures is chosen rather than package with invalid
247 // signatures.
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100248 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100249 public void testWithSignatures() {
250 String validPackage = "valid package";
251 String invalidPackage = "invalid package";
252
253 Signature validSignature = new Signature("11");
254 Signature invalidExpectedSignature = new Signature("22");
255 Signature invalidPackageSignature = new Signature("33");
256
257 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
258 new WebViewProviderInfo(invalidPackage, "", true, false, new String[]{
259 Base64.encodeToString(
260 invalidExpectedSignature.toByteArray(), Base64.DEFAULT)}),
261 new WebViewProviderInfo(validPackage, "", true, false, new String[]{
262 Base64.encodeToString(
263 validSignature.toByteArray(), Base64.DEFAULT)})
264 };
265 setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */,
266 false /* isDebuggable */);
267 mTestSystemImpl.setPackageInfo(createPackageInfo(invalidPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100268 true /* valid */, true /* installed */, new Signature[]{invalidPackageSignature}
269 , 0 /* updateTime */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100270 mTestSystemImpl.setPackageInfo(createPackageInfo(validPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100271 true /* valid */, true /* installed */, new Signature[]{validSignature}
272 , 0 /* updateTime */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100273
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100274 runWebViewBootPreparationOnMainSync();
Gustav Sennton53b78242016-04-07 15:56:10 +0100275
Gustav Sennton53b78242016-04-07 15:56:10 +0100276
Gustav Senntona9159042016-04-11 16:32:52 +0100277 checkPreparationPhasesForPackage(validPackage, 1 /* first preparation for this package */);
Gustav Sennton53b78242016-04-07 15:56:10 +0100278
279 WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
280 assertEquals(1, validPackages.length);
281 assertEquals(validPackage, validPackages[0].packageName);
282 }
283
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100284 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100285 public void testFailWaitingForRelro() {
286 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
287 new WebViewProviderInfo("packagename", "", true, true, null)};
288 setupWithPackages(packages);
289 setEnabledAndValidPackageInfos(packages);
290
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100291 runWebViewBootPreparationOnMainSync();
Gustav Sennton53b78242016-04-07 15:56:10 +0100292
293 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
294 Mockito.argThat(new IsPackageInfoWithName(packages[0].packageName)));
295
296 // Never call notifyRelroCreation()
297
298 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
299 assertEquals(WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO, response.status);
300 }
301
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100302 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100303 public void testFailListingEmptyWebviewPackages() {
304 WebViewProviderInfo[] packages = new WebViewProviderInfo[0];
305 setupWithPackages(packages);
306 setEnabledAndValidPackageInfos(packages);
307
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100308 runWebViewBootPreparationOnMainSync();
Gustav Sennton53b78242016-04-07 15:56:10 +0100309
310 Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
311 Matchers.anyObject());
312
313 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
314 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
315 }
316
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100317 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100318 public void testFailListingInvalidWebviewPackage() {
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100319 WebViewProviderInfo wpi = new WebViewProviderInfo("package", "", true, true, null);
Gustav Sennton53b78242016-04-07 15:56:10 +0100320 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {wpi};
321 setupWithPackages(packages);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100322 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100323 createPackageInfo(wpi.packageName, true /* enabled */, false /* valid */,
324 true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100325
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100326 runWebViewBootPreparationOnMainSync();
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100327
328 Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
329 Matchers.anyObject());
330
Gustav Sennton53b78242016-04-07 15:56:10 +0100331 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
332 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100333
334 // Verify that we can recover from failing to list webview packages.
335 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100336 createPackageInfo(wpi.packageName, true /* enabled */, true /* valid */,
337 true /* installed */));
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100338 mWebViewUpdateServiceImpl.packageStateChanged(wpi.packageName,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100339 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100340
341 checkPreparationPhasesForPackage(wpi.packageName, 1);
Gustav Sennton53b78242016-04-07 15:56:10 +0100342 }
343
344 // Test that switching provider using changeProviderAndSetting works.
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100345 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100346 public void testSwitchingProvider() {
347 String firstPackage = "first";
348 String secondPackage = "second";
349 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
350 new WebViewProviderInfo(firstPackage, "", true, false, null),
351 new WebViewProviderInfo(secondPackage, "", true, false, null)};
352 checkSwitchingProvider(packages, firstPackage, secondPackage);
353 }
354
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100355 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100356 public void testSwitchingProviderToNonDefault() {
357 String defaultPackage = "defaultPackage";
358 String nonDefaultPackage = "nonDefaultPackage";
359 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
360 new WebViewProviderInfo(defaultPackage, "", true, false, null),
361 new WebViewProviderInfo(nonDefaultPackage, "", false, false, null)};
362 checkSwitchingProvider(packages, defaultPackage, nonDefaultPackage);
363 }
364
365 private void checkSwitchingProvider(WebViewProviderInfo[] packages, String initialPackage,
366 String finalPackage) {
Gustav Senntona9159042016-04-11 16:32:52 +0100367 checkCertainPackageUsedAfterWebViewBootPreparation(initialPackage, packages);
Gustav Sennton53b78242016-04-07 15:56:10 +0100368
369 mWebViewUpdateServiceImpl.changeProviderAndSetting(finalPackage);
Gustav Senntona9159042016-04-11 16:32:52 +0100370 checkPreparationPhasesForPackage(finalPackage, 1 /* first preparation for this package */);
Gustav Sennton53b78242016-04-07 15:56:10 +0100371
372 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(initialPackage));
373 }
374
375 // Change provider during relro creation by using changeProviderAndSetting
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100376 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100377 public void testSwitchingProviderDuringRelroCreation() {
378 checkChangingProviderDuringRelroCreation(true);
379 }
380
381 // Change provider during relro creation by enabling a provider
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100382 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100383 public void testChangingProviderThroughEnablingDuringRelroCreation() {
384 checkChangingProviderDuringRelroCreation(false);
385 }
386
387 private void checkChangingProviderDuringRelroCreation(boolean settingsChange) {
388 String firstPackage = "first";
389 String secondPackage = "second";
390 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
391 new WebViewProviderInfo(firstPackage, "", true, false, null),
392 new WebViewProviderInfo(secondPackage, "", true, false, null)};
393 setupWithPackages(packages);
394 if (settingsChange) {
395 // Have all packages be enabled, so that we can change provider however we want to
396 setEnabledAndValidPackageInfos(packages);
397 } else {
398 // Have all packages be disabled so that we can change one to enabled later
399 for(WebViewProviderInfo wpi : packages) {
400 mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100401 false /* enabled */, true /* valid */, true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100402 }
403 }
404
405 CountDownLatch countdown = new CountDownLatch(1);
406
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100407 runWebViewBootPreparationOnMainSync();
Gustav Sennton53b78242016-04-07 15:56:10 +0100408
409 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
410 Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
411
412 assertEquals(firstPackage, mWebViewUpdateServiceImpl.getCurrentWebViewPackageName());
413
414 new Thread(new Runnable() {
415 @Override
416 public void run() {
417 WebViewProviderResponse threadResponse =
418 mWebViewUpdateServiceImpl.waitForAndGetProvider();
419 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, threadResponse.status);
420 assertEquals(secondPackage, threadResponse.packageInfo.packageName);
421 // Verify that we killed the first package
422 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage));
423 countdown.countDown();
424 }
425 }).start();
426 try {
Gustav Sennton0df2c552016-06-14 15:32:19 +0100427 Thread.sleep(500); // Let the new thread run / be blocked
Gustav Sennton53b78242016-04-07 15:56:10 +0100428 } catch (InterruptedException e) {
429 }
430
431 if (settingsChange) {
432 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
433 } else {
434 // Switch provider by enabling the second one
435 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100436 true /* valid */, true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100437 mWebViewUpdateServiceImpl.packageStateChanged(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100438 secondPackage, WebViewUpdateService.PACKAGE_CHANGED, 0);
Gustav Sennton53b78242016-04-07 15:56:10 +0100439 }
440 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
441 // first package done, should start on second
442
443 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
444 Mockito.argThat(new IsPackageInfoWithName(secondPackage)));
445
446 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
447 // second package done, the other thread should now be unblocked
448 try {
449 countdown.await();
450 } catch (InterruptedException e) {
451 }
452 }
453
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100454 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100455 public void testRunFallbackLogicIfEnabled() {
456 checkFallbackLogicBeingRun(true);
457 }
458
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100459 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100460 public void testDontRunFallbackLogicIfDisabled() {
461 checkFallbackLogicBeingRun(false);
462 }
463
464 private void checkFallbackLogicBeingRun(boolean fallbackLogicEnabled) {
465 String primaryPackage = "primary";
466 String fallbackPackage = "fallback";
467 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
468 new WebViewProviderInfo(
469 primaryPackage, "", true /* default available */, false /* fallback */, null),
470 new WebViewProviderInfo(
471 fallbackPackage, "", true /* default available */, true /* fallback */, null)};
472 setupWithPackages(packages, fallbackLogicEnabled);
473 setEnabledAndValidPackageInfos(packages);
474
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100475 runWebViewBootPreparationOnMainSync();
Gustav Sennton53b78242016-04-07 15:56:10 +0100476 // Verify that we disable the fallback package if fallback logic enabled, and don't disable
477 // the fallback package if that logic is disabled
478 if (fallbackLogicEnabled) {
479 Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
480 Matchers.anyObject(), Mockito.eq(fallbackPackage));
481 } else {
482 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
483 Matchers.anyObject(), Matchers.anyObject());
484 }
485 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
486 Mockito.argThat(new IsPackageInfoWithName(primaryPackage)));
487
488 // Enable fallback package
489 mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100490 true /* valid */, true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100491 mWebViewUpdateServiceImpl.packageStateChanged(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100492 fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED, 0);
Gustav Sennton53b78242016-04-07 15:56:10 +0100493
494 if (fallbackLogicEnabled) {
495 // Check that we have now disabled the fallback package twice
496 Mockito.verify(mTestSystemImpl, Mockito.times(2)).uninstallAndDisablePackageForAllUsers(
497 Matchers.anyObject(), Mockito.eq(fallbackPackage));
498 } else {
499 // Check that we still haven't disabled any package
500 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
501 Matchers.anyObject(), Matchers.anyObject());
502 }
503 }
504
505 /**
506 * Scenario for installing primary package when fallback enabled.
507 * 1. Start with only fallback installed
508 * 2. Install non-fallback
509 * 3. Fallback should be disabled
510 */
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100511 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100512 public void testInstallingNonFallbackPackage() {
513 String primaryPackage = "primary";
514 String fallbackPackage = "fallback";
515 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
516 new WebViewProviderInfo(
517 primaryPackage, "", true /* default available */, false /* fallback */, null),
518 new WebViewProviderInfo(
519 fallbackPackage, "", true /* default available */, true /* fallback */, null)};
520 setupWithPackages(packages, true /* isFallbackLogicEnabled */);
521 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100522 createPackageInfo(fallbackPackage, true /* enabled */ , true /* valid */,
523 true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100524
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100525 runWebViewBootPreparationOnMainSync();
Gustav Sennton53b78242016-04-07 15:56:10 +0100526 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
527 Matchers.anyObject(), Matchers.anyObject());
Gustav Sennton53b78242016-04-07 15:56:10 +0100528
Gustav Senntona9159042016-04-11 16:32:52 +0100529 checkPreparationPhasesForPackage(fallbackPackage,
530 1 /* first preparation for this package*/);
Gustav Sennton53b78242016-04-07 15:56:10 +0100531
532 // Install primary package
533 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100534 createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */,
535 true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100536 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100537 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
Gustav Sennton53b78242016-04-07 15:56:10 +0100538
Gustav Senntona9159042016-04-11 16:32:52 +0100539 // Verify fallback disabled, primary package used as provider, and fallback package killed
Gustav Sennton53b78242016-04-07 15:56:10 +0100540 Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
541 Matchers.anyObject(), Mockito.eq(fallbackPackage));
Gustav Senntona9159042016-04-11 16:32:52 +0100542 checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation for this package*/);
Gustav Sennton53b78242016-04-07 15:56:10 +0100543 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(fallbackPackage));
544 }
545
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100546 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100547 public void testFallbackChangesEnabledState() {
548 String primaryPackage = "primary";
549 String fallbackPackage = "fallback";
550 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
551 new WebViewProviderInfo(
552 primaryPackage, "", true /* default available */, false /* fallback */, null),
553 new WebViewProviderInfo(
554 fallbackPackage, "", true /* default available */, true /* fallback */, null)};
555 setupWithPackages(packages, true /* fallbackLogicEnabled */);
556 setEnabledAndValidPackageInfos(packages);
557
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100558 runWebViewBootPreparationOnMainSync();
Gustav Sennton53b78242016-04-07 15:56:10 +0100559
560 // Verify fallback disabled at boot when primary package enabled
561 Mockito.verify(mTestSystemImpl).enablePackageForUser(
562 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
563 Matchers.anyInt());
564
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100565 checkPreparationPhasesForPackage(primaryPackage, 1);
566
567 // Disable primary package and ensure fallback becomes enabled and used
Gustav Sennton53b78242016-04-07 15:56:10 +0100568 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100569 createPackageInfo(primaryPackage, false /* enabled */, true /* valid */,
570 true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100571 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100572 WebViewUpdateService.PACKAGE_CHANGED, 0);
Gustav Sennton53b78242016-04-07 15:56:10 +0100573
Gustav Sennton53b78242016-04-07 15:56:10 +0100574 Mockito.verify(mTestSystemImpl).enablePackageForUser(
575 Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */,
576 Matchers.anyInt());
577
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100578 checkPreparationPhasesForPackage(fallbackPackage, 1);
579
580
581 // Again enable primary package and verify primary is used and fallback becomes disabled
Gustav Sennton53b78242016-04-07 15:56:10 +0100582 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100583 createPackageInfo(primaryPackage, true /* enabled */, true /* valid */,
584 true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100585 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100586 WebViewUpdateService.PACKAGE_CHANGED, 0);
Gustav Sennton53b78242016-04-07 15:56:10 +0100587
588 // Verify fallback is disabled a second time when primary package becomes enabled
589 Mockito.verify(mTestSystemImpl, Mockito.times(2)).enablePackageForUser(
590 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
591 Matchers.anyInt());
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100592
593 checkPreparationPhasesForPackage(primaryPackage, 2);
Gustav Sennton53b78242016-04-07 15:56:10 +0100594 }
595
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100596 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100597 public void testAddUserWhenFallbackLogicEnabled() {
598 checkAddingNewUser(true);
599 }
600
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100601 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100602 public void testAddUserWhenFallbackLogicDisabled() {
603 checkAddingNewUser(false);
604 }
605
606 public void checkAddingNewUser(boolean fallbackLogicEnabled) {
607 String primaryPackage = "primary";
608 String fallbackPackage = "fallback";
609 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
610 new WebViewProviderInfo(
611 primaryPackage, "", true /* default available */, false /* fallback */, null),
612 new WebViewProviderInfo(
613 fallbackPackage, "", true /* default available */, true /* fallback */, null)};
614 setupWithPackages(packages, fallbackLogicEnabled);
615 setEnabledAndValidPackageInfos(packages);
616 int newUser = 100;
617 mWebViewUpdateServiceImpl.handleNewUser(newUser);
618 if (fallbackLogicEnabled) {
619 // Verify fallback package becomes disabled for new user
620 Mockito.verify(mTestSystemImpl).enablePackageForUser(
621 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
622 Mockito.eq(newUser));
623 } else {
624 // Verify that we don't disable fallback for new user
625 Mockito.verify(mTestSystemImpl, Mockito.never()).enablePackageForUser(
626 Mockito.anyObject(), Matchers.anyBoolean() /* enable */,
627 Matchers.anyInt() /* user */);
628 }
629 }
630
631 /**
632 * Timing dependent test where we verify that the list of valid webview packages becoming empty
633 * at a certain point doesn't crash us or break our state.
634 */
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100635 @Test
Gustav Sennton53b78242016-04-07 15:56:10 +0100636 public void testNotifyRelroDoesntCrashIfNoPackages() {
637 String firstPackage = "first";
638 String secondPackage = "second";
639 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
640 new WebViewProviderInfo(firstPackage, "", true /* default available */,
641 false /* fallback */, null),
642 new WebViewProviderInfo(secondPackage, "", true /* default available */,
643 false /* fallback */, null)};
644 setupWithPackages(packages);
645 // Add (enabled and valid) package infos for each provider
646 setEnabledAndValidPackageInfos(packages);
647
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100648 runWebViewBootPreparationOnMainSync();
Gustav Sennton53b78242016-04-07 15:56:10 +0100649
650 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
651 Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
652
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100653 // Change provider during relro creation to enter a state where we are
654 // waiting for relro creation to complete just to re-run relro creation.
655 // (so that in next notifyRelroCreationCompleted() call we have to list webview packages)
Gustav Sennton53b78242016-04-07 15:56:10 +0100656 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
657
658 // Make packages invalid to cause exception to be thrown
659 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100660 false /* valid */, true /* installed */, null /* signatures */,
661 0 /* updateTime */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100662 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100663 false /* valid */, true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100664
665 // This shouldn't throw an exception!
666 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
667
668 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
669 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
670
671 // Now make a package valid again and verify that we can switch back to that
672 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100673 true /* valid */, true /* installed */, null /* signatures */,
674 1 /* updateTime */ ));
Gustav Sennton53b78242016-04-07 15:56:10 +0100675
676 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100677 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
Gustav Sennton53b78242016-04-07 15:56:10 +0100678
Gustav Senntona9159042016-04-11 16:32:52 +0100679 // Ensure we use firstPackage
680 checkPreparationPhasesForPackage(firstPackage, 2 /* second preparation for this package */);
681 }
Gustav Sennton53b78242016-04-07 15:56:10 +0100682
Gustav Senntona9159042016-04-11 16:32:52 +0100683 /**
684 * Verify that even if a user-chosen package is removed temporarily we start using it again when
685 * it is added back.
686 */
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100687 @Test
Gustav Senntona9159042016-04-11 16:32:52 +0100688 public void testTempRemovePackageDoesntSwitchProviderPermanently() {
689 String firstPackage = "first";
690 String secondPackage = "second";
691 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
692 new WebViewProviderInfo(firstPackage, "", true /* default available */,
693 false /* fallback */, null),
694 new WebViewProviderInfo(secondPackage, "", true /* default available */,
695 false /* fallback */, null)};
696 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
Gustav Sennton53b78242016-04-07 15:56:10 +0100697
Gustav Senntona9159042016-04-11 16:32:52 +0100698 // Explicitly use the second package
699 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
700 checkPreparationPhasesForPackage(secondPackage, 1 /* first time for this package */);
701
702 // Remove second package (invalidate it) and verify that first package is used
703 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100704 false /* valid */, true /* installed */));
Gustav Senntona9159042016-04-11 16:32:52 +0100705 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100706 WebViewUpdateService.PACKAGE_ADDED, 0);
Gustav Senntona9159042016-04-11 16:32:52 +0100707 checkPreparationPhasesForPackage(firstPackage, 2 /* second time for this package */);
708
709 // Now make the second package valid again and verify that it is used again
710 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100711 true /* valid */, true /* installed */));
Gustav Senntona9159042016-04-11 16:32:52 +0100712 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100713 WebViewUpdateService.PACKAGE_ADDED, 0);
Gustav Senntona9159042016-04-11 16:32:52 +0100714 checkPreparationPhasesForPackage(secondPackage, 2 /* second time for this package */);
715 }
716
717 /**
718 * Ensure that we update the user-chosen setting across boots if the chosen package is no
719 * longer installed and valid.
720 */
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100721 @Test
Gustav Senntona9159042016-04-11 16:32:52 +0100722 public void testProviderSettingChangedDuringBootIfProviderNotAvailable() {
723 String chosenPackage = "chosenPackage";
724 String nonChosenPackage = "non-chosenPackage";
725 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
726 new WebViewProviderInfo(chosenPackage, "", true /* default available */,
727 false /* fallback */, null),
728 new WebViewProviderInfo(nonChosenPackage, "", true /* default available */,
729 false /* fallback */, null)};
730
731 setupWithPackages(packages);
732 // Only 'install' nonChosenPackage
733 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100734 createPackageInfo(nonChosenPackage, true /* enabled */, true /* valid */, true /* installed */));
Gustav Senntona9159042016-04-11 16:32:52 +0100735
736 // Set user-chosen package
737 mTestSystemImpl.updateUserSetting(null, chosenPackage);
738
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100739 runWebViewBootPreparationOnMainSync();
Gustav Senntona9159042016-04-11 16:32:52 +0100740
741 // Verify that we switch the setting to point to the current package
742 Mockito.verify(mTestSystemImpl).updateUserSetting(
743 Mockito.anyObject(), Mockito.eq(nonChosenPackage));
744 assertEquals(nonChosenPackage, mTestSystemImpl.getUserChosenWebViewProvider(null));
745
746 checkPreparationPhasesForPackage(nonChosenPackage, 1);
Gustav Sennton53b78242016-04-07 15:56:10 +0100747 }
748
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100749 @Test
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100750 public void testRecoverFailedListingWebViewPackagesSettingsChange() {
751 checkRecoverAfterFailListingWebviewPackages(true);
752 }
753
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100754 @Test
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100755 public void testRecoverFailedListingWebViewPackagesAddedPackage() {
756 checkRecoverAfterFailListingWebviewPackages(false);
757 }
758
759 /**
760 * Test that we can recover correctly from failing to list WebView packages.
761 * settingsChange: whether to fail during changeProviderAndSetting or packageStateChanged
762 */
763 public void checkRecoverAfterFailListingWebviewPackages(boolean settingsChange) {
764 String firstPackage = "first";
765 String secondPackage = "second";
766 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
767 new WebViewProviderInfo(firstPackage, "", true /* default available */,
768 false /* fallback */, null),
769 new WebViewProviderInfo(secondPackage, "", true /* default available */,
770 false /* fallback */, null)};
771 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
772
773 // Make both packages invalid so that we fail listing WebView packages
774 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100775 false /* valid */, true /* installed */));
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100776 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100777 false /* valid */, true /* installed */));
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100778
779 // Change package to hit the webview packages listing problem.
780 if (settingsChange) {
781 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
782 } else {
783 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100784 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100785 }
786
787 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
788 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
789
790 // Make second package valid and verify that we can load it again
791 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100792 true /* valid */, true /* installed */));
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100793
794 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100795 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100796
797
798 checkPreparationPhasesForPackage(secondPackage, 1);
799 }
800
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100801 @Test
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100802 public void testDontKillIfPackageReplaced() {
803 checkDontKillIfPackageRemoved(true);
804 }
805
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100806 @Test
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100807 public void testDontKillIfPackageRemoved() {
808 checkDontKillIfPackageRemoved(false);
809 }
810
811 public void checkDontKillIfPackageRemoved(boolean replaced) {
812 String firstPackage = "first";
813 String secondPackage = "second";
814 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
815 new WebViewProviderInfo(firstPackage, "", true /* default available */,
816 false /* fallback */, null),
817 new WebViewProviderInfo(secondPackage, "", true /* default available */,
818 false /* fallback */, null)};
819 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
820
821 // Replace or remove the current webview package
822 if (replaced) {
823 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100824 createPackageInfo(firstPackage, true /* enabled */, false /* valid */,
825 true /* installed */));
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100826 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100827 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100828 } else {
829 mTestSystemImpl.removePackageInfo(firstPackage);
830 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100831 WebViewUpdateService.PACKAGE_REMOVED, 0);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100832 }
833
834 checkPreparationPhasesForPackage(secondPackage, 1);
835
836 Mockito.verify(mTestSystemImpl, Mockito.never()).killPackageDependents(
837 Mockito.anyObject());
838 }
839
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100840 @Test
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100841 public void testKillIfSettingChanged() {
842 String firstPackage = "first";
843 String secondPackage = "second";
844 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
845 new WebViewProviderInfo(firstPackage, "", true /* default available */,
846 false /* fallback */, null),
847 new WebViewProviderInfo(secondPackage, "", true /* default available */,
848 false /* fallback */, null)};
849 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
850
851 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
852
853 checkPreparationPhasesForPackage(secondPackage, 1);
854
855 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage));
856 }
857
858 /**
859 * Test that we kill apps using an old provider when we change the provider setting, even if the
860 * new provider is not the one we intended to change to.
861 */
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100862 @Test
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100863 public void testKillIfChangeProviderIncorrectly() {
864 String firstPackage = "first";
865 String secondPackage = "second";
866 String thirdPackage = "third";
867 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
868 new WebViewProviderInfo(firstPackage, "", true /* default available */,
869 false /* fallback */, null),
870 new WebViewProviderInfo(secondPackage, "", true /* default available */,
871 false /* fallback */, null),
872 new WebViewProviderInfo(thirdPackage, "", true /* default available */,
873 false /* fallback */, null)};
874 setupWithPackages(packages);
875 setEnabledAndValidPackageInfos(packages);
876
877 // Start with the setting pointing to the third package
878 mTestSystemImpl.updateUserSetting(null, thirdPackage);
879
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100880 runWebViewBootPreparationOnMainSync();
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100881 checkPreparationPhasesForPackage(thirdPackage, 1);
882
883 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100884 createPackageInfo(secondPackage, true /* enabled */, false /* valid */, true /* installed */));
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100885
886 // Try to switch to the invalid second package, this should result in switching to the first
887 // package, since that is more preferred than the third one.
888 assertEquals(firstPackage,
889 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage));
890
891 checkPreparationPhasesForPackage(firstPackage, 1);
892
893 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(thirdPackage));
894 }
Gustav Sennton0df2c552016-06-14 15:32:19 +0100895
896 // Ensure that the update service uses an uninstalled package if that is the only package
897 // available.
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100898 @Test
Gustav Sennton0df2c552016-06-14 15:32:19 +0100899 public void testWithSingleUninstalledPackage() {
900 String testPackageName = "test.package.name";
901 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
902 new WebViewProviderInfo(testPackageName, "",
903 true /*default available*/, false /* fallback */, null)};
904 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
905 mTestSystemImpl.setPackageInfo(createPackageInfo(testPackageName, true /* enabled */,
906 true /* valid */, false /* installed */));
907
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100908 runWebViewBootPreparationOnMainSync();
Gustav Sennton0df2c552016-06-14 15:32:19 +0100909
910 checkPreparationPhasesForPackage(testPackageName, 1 /* first preparation phase */);
911 }
912
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100913 @Test
Gustav Sennton0df2c552016-06-14 15:32:19 +0100914 public void testNonhiddenPackageUserOverHidden() {
915 checkVisiblePackageUserOverNonVisible(false /* true == uninstalled, false == hidden */);
916 }
917
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100918 @Test
Gustav Sennton0df2c552016-06-14 15:32:19 +0100919 public void testInstalledPackageUsedOverUninstalled() {
920 checkVisiblePackageUserOverNonVisible(true /* true == uninstalled, false == hidden */);
921 }
922
923 private void checkVisiblePackageUserOverNonVisible(boolean uninstalledNotHidden) {
924 boolean testUninstalled = uninstalledNotHidden;
925 boolean testHidden = !uninstalledNotHidden;
926 String installedPackage = "installedPackage";
927 String uninstalledPackage = "uninstalledPackage";
928 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
929 new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */,
930 false /* fallback */, null),
931 new WebViewProviderInfo(installedPackage, "", true /* available by default */,
932 false /* fallback */, null)};
933
934 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
935 mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
936 true /* valid */, true /* installed */));
937 mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
938 true /* valid */, (testUninstalled ? false : true) /* installed */,
939 null /* signatures */, 0 /* updateTime */, (testHidden ? true : false)));
940
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100941 runWebViewBootPreparationOnMainSync();
Gustav Sennton0df2c552016-06-14 15:32:19 +0100942
943 checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
944 }
945
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100946 @Test
Gustav Sennton0df2c552016-06-14 15:32:19 +0100947 public void testCantSwitchToHiddenPackage () {
948 checkCantSwitchToNonVisiblePackage(false /* true == uninstalled, false == hidden */);
949 }
950
951
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100952 @Test
Gustav Sennton0df2c552016-06-14 15:32:19 +0100953 public void testCantSwitchToUninstalledPackage () {
954 checkCantSwitchToNonVisiblePackage(true /* true == uninstalled, false == hidden */);
955 }
956
957 /**
958 * Ensure that we won't prioritize an uninstalled (or hidden) package even if it is user-chosen,
959 * and that an uninstalled (or hidden) package is not considered valid (in the
960 * getValidWebViewPackages() API).
961 */
962 private void checkCantSwitchToNonVisiblePackage(boolean uninstalledNotHidden) {
963 boolean testUninstalled = uninstalledNotHidden;
964 boolean testHidden = !uninstalledNotHidden;
965 String installedPackage = "installedPackage";
966 String uninstalledPackage = "uninstalledPackage";
967 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
968 new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */,
969 false /* fallback */, null),
970 new WebViewProviderInfo(installedPackage, "", true /* available by default */,
971 false /* fallback */, null)};
972
973 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
974 mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
975 true /* valid */, true /* installed */));
976 mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
977 true /* valid */, (testUninstalled ? false : true) /* installed */,
978 null /* signatures */, 0 /* updateTime */,
979 (testHidden ? true : false) /* hidden */));
980
Gustav Sennton86f7bbe2016-10-24 16:49:32 +0100981 runWebViewBootPreparationOnMainSync();
Gustav Sennton0df2c552016-06-14 15:32:19 +0100982
983 checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
984
985 // Ensure that only the installed package is considered valid
986 WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
987 assertEquals(1, validPackages.length);
988 assertEquals(installedPackage, validPackages[0].packageName);
989
990 // ensure that we don't switch to the uninstalled package (it will be used if it becomes
991 // installed later)
992 assertEquals(installedPackage,
993 mWebViewUpdateServiceImpl.changeProviderAndSetting(uninstalledPackage));
994
995 // We should only have called onWebViewProviderChanged once (before calling
996 // changeProviderAndSetting
997 Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged(
998 Mockito.argThat(new IsPackageInfoWithName(installedPackage)));
999 }
1000
Gustav Sennton86f7bbe2016-10-24 16:49:32 +01001001 @Test
Gustav Sennton0df2c552016-06-14 15:32:19 +01001002 public void testHiddenPackageNotPrioritizedEvenIfChosen() {
1003 checkNonvisiblePackageNotPrioritizedEvenIfChosen(
1004 false /* true == uninstalled, false == hidden */);
1005 }
1006
Gustav Sennton86f7bbe2016-10-24 16:49:32 +01001007 @Test
Gustav Sennton0df2c552016-06-14 15:32:19 +01001008 public void testUninstalledPackageNotPrioritizedEvenIfChosen() {
1009 checkNonvisiblePackageNotPrioritizedEvenIfChosen(
1010 true /* true == uninstalled, false == hidden */);
1011 }
1012
1013 public void checkNonvisiblePackageNotPrioritizedEvenIfChosen(boolean uninstalledNotHidden) {
1014 boolean testUninstalled = uninstalledNotHidden;
1015 boolean testHidden = !uninstalledNotHidden;
1016 String installedPackage = "installedPackage";
1017 String uninstalledPackage = "uninstalledPackage";
1018 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
1019 new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */,
1020 false /* fallback */, null),
1021 new WebViewProviderInfo(installedPackage, "", true /* available by default */,
1022 false /* fallback */, null)};
1023
1024 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
1025 mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
1026 true /* valid */, true /* installed */));
1027 mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
1028 true /* valid */, (testUninstalled ? false : true) /* installed */,
1029 null /* signatures */, 0 /* updateTime */,
1030 (testHidden ? true : false) /* hidden */));
1031
1032 // Start with the setting pointing to the uninstalled package
1033 mTestSystemImpl.updateUserSetting(null, uninstalledPackage);
1034
Gustav Sennton86f7bbe2016-10-24 16:49:32 +01001035 runWebViewBootPreparationOnMainSync();
Gustav Sennton0df2c552016-06-14 15:32:19 +01001036
1037 checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
1038 }
1039
1040 /**
1041 * Ensures that fallback becomes enabled if the primary package is uninstalled for the current
1042 * user.
1043 */
Gustav Sennton86f7bbe2016-10-24 16:49:32 +01001044 @Test
Gustav Sennton0df2c552016-06-14 15:32:19 +01001045 public void testFallbackEnabledIfPrimaryUninstalled() {
1046 String primaryPackage = "primary";
1047 String fallbackPackage = "fallback";
1048 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
1049 new WebViewProviderInfo(
1050 primaryPackage, "", true /* default available */, false /* fallback */, null),
1051 new WebViewProviderInfo(
1052 fallbackPackage, "", true /* default available */, true /* fallback */, null)};
1053 setupWithPackages(packages, true /* fallback logic enabled */);
1054 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
1055 true /* valid */, false /* installed */));
1056 mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
1057 true /* valid */, true /* installed */));
1058
Gustav Sennton86f7bbe2016-10-24 16:49:32 +01001059 runWebViewBootPreparationOnMainSync();
Gustav Sennton0df2c552016-06-14 15:32:19 +01001060 // Verify that we enable the fallback package
1061 Mockito.verify(mTestSystemImpl).enablePackageForAllUsers(
1062 Mockito.anyObject(), Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */);
1063
1064 checkPreparationPhasesForPackage(fallbackPackage, 1 /* first preparation phase */);
1065 }
1066
Gustav Sennton86f7bbe2016-10-24 16:49:32 +01001067 @Test
Gustav Sennton0df2c552016-06-14 15:32:19 +01001068 public void testPreparationRunsIffNewPackage() {
1069 String primaryPackage = "primary";
1070 String fallbackPackage = "fallback";
1071 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
1072 new WebViewProviderInfo(
1073 primaryPackage, "", true /* default available */, false /* fallback */, null),
1074 new WebViewProviderInfo(
1075 fallbackPackage, "", true /* default available */, true /* fallback */, null)};
1076 setupWithPackages(packages, true /* fallback logic enabled */);
1077 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
1078 true /* valid */, true /* installed */, null /* signatures */,
1079 10 /* lastUpdateTime*/ ));
1080 mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
1081 true /* valid */, true /* installed */));
1082
Gustav Sennton86f7bbe2016-10-24 16:49:32 +01001083 runWebViewBootPreparationOnMainSync();
Gustav Sennton0df2c552016-06-14 15:32:19 +01001084
1085 checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */);
1086 Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser(
1087 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
1088 Matchers.anyInt() /* user */);
1089
1090
1091 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
1092 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0 /* userId */);
1093 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
1094 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 1 /* userId */);
1095 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
1096 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 2 /* userId */);
1097 // package still has the same update-time so we shouldn't run preparation here
1098 Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged(
1099 Mockito.argThat(new IsPackageInfoWithName(primaryPackage)));
1100 Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser(
1101 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
1102 Matchers.anyInt() /* user */);
1103
1104 // Ensure we can still load the package
1105 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
1106 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
1107 assertEquals(primaryPackage, response.packageInfo.packageName);
1108
1109
1110 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
1111 true /* valid */, true /* installed */, null /* signatures */,
1112 20 /* lastUpdateTime*/ ));
1113 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
1114 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
1115 // The package has now changed - ensure that we have run the preparation phase a second time
1116 checkPreparationPhasesForPackage(primaryPackage, 2 /* second preparation phase */);
1117
1118
1119 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
1120 true /* valid */, true /* installed */, null /* signatures */,
1121 50 /* lastUpdateTime*/ ));
1122 // Receive intent for different user
1123 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
1124 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 2);
1125
1126 checkPreparationPhasesForPackage(primaryPackage, 3 /* third preparation phase */);
1127 }
Gustav Sennton53b78242016-04-07 15:56:10 +01001128}