blob: 3341a3a54e1ffab124954818dd2b703ffb8700bf [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
19import android.content.Context;
20import android.content.pm.ApplicationInfo;
21import android.content.pm.PackageInfo;
22import android.content.pm.Signature;
23import android.os.Bundle;
24import android.util.Base64;
25import android.test.AndroidTestCase;
26
27import android.webkit.WebViewFactory;
28import android.webkit.WebViewProviderInfo;
29import android.webkit.WebViewProviderResponse;
30
31import java.util.concurrent.CountDownLatch;
32
33import org.hamcrest.Description;
34
35import org.mockito.Mockito;
36import org.mockito.Matchers;
37import org.mockito.ArgumentMatcher;
38
39
40/**
41 * Tests for WebViewUpdateService
42 */
43public class WebViewUpdateServiceTest extends AndroidTestCase {
44 private final static String TAG = WebViewUpdateServiceTest.class.getSimpleName();
45
46 private WebViewUpdateServiceImpl mWebViewUpdateServiceImpl;
47 private TestSystemImpl mTestSystemImpl;
48
49 private static final String WEBVIEW_LIBRARY_FLAG = "com.android.webview.WebViewLibrary";
50
51 @Override
52 protected void setUp() throws Exception {
53 super.setUp();
54 }
55
56 /**
57 * Creates a new instance.
58 */
59 public WebViewUpdateServiceTest() {
60 }
61
62 private void setupWithPackages(WebViewProviderInfo[] packages) {
63 setupWithPackages(packages, true);
64 }
65
66 private void setupWithPackages(WebViewProviderInfo[] packages,
67 boolean fallbackLogicEnabled) {
68 setupWithPackages(packages, fallbackLogicEnabled, 1);
69 }
70
71 private void setupWithPackages(WebViewProviderInfo[] packages,
72 boolean fallbackLogicEnabled, int numRelros) {
73 setupWithPackages(packages, fallbackLogicEnabled, numRelros,
74 true /* isDebuggable == true -> don't check package signatures */);
75 }
76
77 private void setupWithPackages(WebViewProviderInfo[] packages,
78 boolean fallbackLogicEnabled, int numRelros, boolean isDebuggable) {
79 TestSystemImpl testing = new TestSystemImpl(packages, fallbackLogicEnabled, numRelros,
80 isDebuggable);
81 mTestSystemImpl = Mockito.spy(testing);
82 mWebViewUpdateServiceImpl =
83 new WebViewUpdateServiceImpl(null /*Context*/, mTestSystemImpl);
84 }
85
86 private void setEnabledAndValidPackageInfos(WebViewProviderInfo[] providers) {
87 for(WebViewProviderInfo wpi : providers) {
88 mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +010089 true /* valid */, true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +010090 }
91 }
92
Gustav Senntona9159042016-04-11 16:32:52 +010093 private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
Gustav Sennton53b78242016-04-07 15:56:10 +010094 WebViewProviderInfo[] webviewPackages) {
Gustav Senntona9159042016-04-11 16:32:52 +010095 checkCertainPackageUsedAfterWebViewBootPreparation(
96 expectedProviderName, webviewPackages, 1);
Gustav Sennton53b78242016-04-07 15:56:10 +010097 }
98
Gustav Senntona9159042016-04-11 16:32:52 +010099 private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
Gustav Sennton53b78242016-04-07 15:56:10 +0100100 WebViewProviderInfo[] webviewPackages, int numRelros) {
101 setupWithPackages(webviewPackages, true, numRelros);
102 // Add (enabled and valid) package infos for each provider
103 setEnabledAndValidPackageInfos(webviewPackages);
104
105 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
106
107 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
108 Mockito.argThat(new IsPackageInfoWithName(expectedProviderName)));
109
110 for (int n = 0; n < numRelros; n++) {
111 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
112 }
113
114 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
115 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
116 assertEquals(expectedProviderName, response.packageInfo.packageName);
117 }
118
119 // For matching the package name of a PackageInfo
120 private class IsPackageInfoWithName extends ArgumentMatcher<PackageInfo> {
121 private final String mPackageName;
122
123 IsPackageInfoWithName(String name) {
124 mPackageName = name;
125 }
126
127 @Override
128 public boolean matches(Object p) {
129 return ((PackageInfo) p).packageName.equals(mPackageName);
130 }
131
132 // Provide a more useful description in case of mismatch
133 @Override
134 public void describeTo (Description description) {
135 description.appendText(String.format("PackageInfo with name '%s'", mPackageName));
136 }
137 }
138
139 private static PackageInfo createPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100140 String packageName, boolean enabled, boolean valid, boolean installed) {
Gustav Sennton53b78242016-04-07 15:56:10 +0100141 PackageInfo p = new PackageInfo();
142 p.packageName = packageName;
143 p.applicationInfo = new ApplicationInfo();
144 p.applicationInfo.enabled = enabled;
145 p.applicationInfo.metaData = new Bundle();
Gustav Sennton0df2c552016-06-14 15:32:19 +0100146 if (installed) {
147 p.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
148 } else {
149 p.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
150 }
Gustav Sennton53b78242016-04-07 15:56:10 +0100151 if (valid) {
152 // no flag means invalid
153 p.applicationInfo.metaData.putString(WEBVIEW_LIBRARY_FLAG, "blah");
154 }
155 return p;
156 }
157
Gustav Sennton0df2c552016-06-14 15:32:19 +0100158 private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid,
159 boolean installed, Signature[] signatures, long updateTime) {
160 PackageInfo p = createPackageInfo(packageName, enabled, valid, installed);
Gustav Sennton53b78242016-04-07 15:56:10 +0100161 p.signatures = signatures;
Gustav Sennton0df2c552016-06-14 15:32:19 +0100162 p.lastUpdateTime = updateTime;
Gustav Sennton53b78242016-04-07 15:56:10 +0100163 return p;
164 }
165
Gustav Sennton18c9e152016-04-15 15:24:53 +0100166 private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100167 boolean installed, Signature[] signatures, long updateTime, boolean hidden) {
168 PackageInfo p =
169 createPackageInfo(packageName, enabled, valid, installed, signatures, updateTime);
170 if (hidden) {
171 p.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
172 } else {
173 p.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
174 }
Gustav Sennton53b78242016-04-07 15:56:10 +0100175 return p;
176 }
177
Gustav Senntonfd222fc22016-06-16 20:24:23 +0100178 private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid,
179 boolean installed, Signature[] signatures, long updateTime, boolean hidden,
180 int versionCode, boolean isSystemApp) {
181 PackageInfo p = createPackageInfo(packageName, enabled, valid, installed, signatures,
182 updateTime, hidden);
Gustav Sennton18c9e152016-04-15 15:24:53 +0100183 p.versionCode = versionCode;
184 p.applicationInfo.versionCode = versionCode;
185 if (isSystemApp) p.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
186 return p;
187 }
188
Gustav Senntona9159042016-04-11 16:32:52 +0100189 private void checkPreparationPhasesForPackage(String expectedPackage, int numPreparation) {
190 // Verify that onWebViewProviderChanged was called for the numPreparation'th time for the
191 // expected package
192 Mockito.verify(mTestSystemImpl, Mockito.times(numPreparation)).onWebViewProviderChanged(
193 Mockito.argThat(new IsPackageInfoWithName(expectedPackage)));
194
195 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
196
197 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
198 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
199 assertEquals(expectedPackage, response.packageInfo.packageName);
200 }
201
Gustav Sennton53b78242016-04-07 15:56:10 +0100202
203 // ****************
204 // Tests
205 // ****************
206
207
208 public void testWithSinglePackage() {
209 String testPackageName = "test.package.name";
Gustav Senntona9159042016-04-11 16:32:52 +0100210 checkCertainPackageUsedAfterWebViewBootPreparation(testPackageName,
Gustav Sennton53b78242016-04-07 15:56:10 +0100211 new WebViewProviderInfo[] {
212 new WebViewProviderInfo(testPackageName, "",
213 true /*default available*/, false /* fallback */, null)});
214 }
215
216 public void testDefaultPackageUsedOverNonDefault() {
217 String defaultPackage = "defaultPackage";
218 String nonDefaultPackage = "nonDefaultPackage";
219 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
220 new WebViewProviderInfo(nonDefaultPackage, "", false, false, null),
221 new WebViewProviderInfo(defaultPackage, "", true, false, null)};
Gustav Senntona9159042016-04-11 16:32:52 +0100222 checkCertainPackageUsedAfterWebViewBootPreparation(defaultPackage, packages);
Gustav Sennton53b78242016-04-07 15:56:10 +0100223 }
224
225 public void testSeveralRelros() {
226 String singlePackage = "singlePackage";
Gustav Senntona9159042016-04-11 16:32:52 +0100227 checkCertainPackageUsedAfterWebViewBootPreparation(
Gustav Sennton53b78242016-04-07 15:56:10 +0100228 singlePackage,
229 new WebViewProviderInfo[] {
230 new WebViewProviderInfo(singlePackage, "", true /*def av*/, false, null)},
231 2);
232 }
233
234 // Ensure that package with valid signatures is chosen rather than package with invalid
235 // signatures.
236 public void testWithSignatures() {
237 String validPackage = "valid package";
238 String invalidPackage = "invalid package";
239
240 Signature validSignature = new Signature("11");
241 Signature invalidExpectedSignature = new Signature("22");
242 Signature invalidPackageSignature = new Signature("33");
243
244 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
245 new WebViewProviderInfo(invalidPackage, "", true, false, new String[]{
246 Base64.encodeToString(
247 invalidExpectedSignature.toByteArray(), Base64.DEFAULT)}),
248 new WebViewProviderInfo(validPackage, "", true, false, new String[]{
249 Base64.encodeToString(
250 validSignature.toByteArray(), Base64.DEFAULT)})
251 };
252 setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */,
253 false /* isDebuggable */);
254 mTestSystemImpl.setPackageInfo(createPackageInfo(invalidPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100255 true /* valid */, true /* installed */, new Signature[]{invalidPackageSignature}
256 , 0 /* updateTime */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100257 mTestSystemImpl.setPackageInfo(createPackageInfo(validPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100258 true /* valid */, true /* installed */, new Signature[]{validSignature}
259 , 0 /* updateTime */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100260
261 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
262
Gustav Sennton53b78242016-04-07 15:56:10 +0100263
Gustav Senntona9159042016-04-11 16:32:52 +0100264 checkPreparationPhasesForPackage(validPackage, 1 /* first preparation for this package */);
Gustav Sennton53b78242016-04-07 15:56:10 +0100265
266 WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
267 assertEquals(1, validPackages.length);
268 assertEquals(validPackage, validPackages[0].packageName);
269 }
270
271 public void testFailWaitingForRelro() {
272 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
273 new WebViewProviderInfo("packagename", "", true, true, null)};
274 setupWithPackages(packages);
275 setEnabledAndValidPackageInfos(packages);
276
277 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
278
279 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
280 Mockito.argThat(new IsPackageInfoWithName(packages[0].packageName)));
281
282 // Never call notifyRelroCreation()
283
284 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
285 assertEquals(WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO, response.status);
286 }
287
288 public void testFailListingEmptyWebviewPackages() {
289 WebViewProviderInfo[] packages = new WebViewProviderInfo[0];
290 setupWithPackages(packages);
291 setEnabledAndValidPackageInfos(packages);
292
293 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
294
295 Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
296 Matchers.anyObject());
297
298 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
299 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
300 }
301
302 public void testFailListingInvalidWebviewPackage() {
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100303 WebViewProviderInfo wpi = new WebViewProviderInfo("package", "", true, true, null);
Gustav Sennton53b78242016-04-07 15:56:10 +0100304 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {wpi};
305 setupWithPackages(packages);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100306 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100307 createPackageInfo(wpi.packageName, true /* enabled */, false /* valid */,
308 true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100309
310 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100311
312 Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
313 Matchers.anyObject());
314
Gustav Sennton53b78242016-04-07 15:56:10 +0100315 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
316 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100317
318 // Verify that we can recover from failing to list webview packages.
319 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100320 createPackageInfo(wpi.packageName, true /* enabled */, true /* valid */,
321 true /* installed */));
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100322 mWebViewUpdateServiceImpl.packageStateChanged(wpi.packageName,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100323 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100324
325 checkPreparationPhasesForPackage(wpi.packageName, 1);
Gustav Sennton53b78242016-04-07 15:56:10 +0100326 }
327
328 // Test that switching provider using changeProviderAndSetting works.
329 public void testSwitchingProvider() {
330 String firstPackage = "first";
331 String secondPackage = "second";
332 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
333 new WebViewProviderInfo(firstPackage, "", true, false, null),
334 new WebViewProviderInfo(secondPackage, "", true, false, null)};
335 checkSwitchingProvider(packages, firstPackage, secondPackage);
336 }
337
338 public void testSwitchingProviderToNonDefault() {
339 String defaultPackage = "defaultPackage";
340 String nonDefaultPackage = "nonDefaultPackage";
341 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
342 new WebViewProviderInfo(defaultPackage, "", true, false, null),
343 new WebViewProviderInfo(nonDefaultPackage, "", false, false, null)};
344 checkSwitchingProvider(packages, defaultPackage, nonDefaultPackage);
345 }
346
347 private void checkSwitchingProvider(WebViewProviderInfo[] packages, String initialPackage,
348 String finalPackage) {
Gustav Senntona9159042016-04-11 16:32:52 +0100349 checkCertainPackageUsedAfterWebViewBootPreparation(initialPackage, packages);
Gustav Sennton53b78242016-04-07 15:56:10 +0100350
351 mWebViewUpdateServiceImpl.changeProviderAndSetting(finalPackage);
Gustav Senntona9159042016-04-11 16:32:52 +0100352 checkPreparationPhasesForPackage(finalPackage, 1 /* first preparation for this package */);
Gustav Sennton53b78242016-04-07 15:56:10 +0100353
354 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(initialPackage));
355 }
356
357 // Change provider during relro creation by using changeProviderAndSetting
358 public void testSwitchingProviderDuringRelroCreation() {
359 checkChangingProviderDuringRelroCreation(true);
360 }
361
362 // Change provider during relro creation by enabling a provider
363 public void testChangingProviderThroughEnablingDuringRelroCreation() {
364 checkChangingProviderDuringRelroCreation(false);
365 }
366
367 private void checkChangingProviderDuringRelroCreation(boolean settingsChange) {
368 String firstPackage = "first";
369 String secondPackage = "second";
370 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
371 new WebViewProviderInfo(firstPackage, "", true, false, null),
372 new WebViewProviderInfo(secondPackage, "", true, false, null)};
373 setupWithPackages(packages);
374 if (settingsChange) {
375 // Have all packages be enabled, so that we can change provider however we want to
376 setEnabledAndValidPackageInfos(packages);
377 } else {
378 // Have all packages be disabled so that we can change one to enabled later
379 for(WebViewProviderInfo wpi : packages) {
380 mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100381 false /* enabled */, true /* valid */, true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100382 }
383 }
384
385 CountDownLatch countdown = new CountDownLatch(1);
386
387 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
388
389 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
390 Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
391
392 assertEquals(firstPackage, mWebViewUpdateServiceImpl.getCurrentWebViewPackageName());
393
394 new Thread(new Runnable() {
395 @Override
396 public void run() {
397 WebViewProviderResponse threadResponse =
398 mWebViewUpdateServiceImpl.waitForAndGetProvider();
399 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, threadResponse.status);
400 assertEquals(secondPackage, threadResponse.packageInfo.packageName);
401 // Verify that we killed the first package
402 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage));
403 countdown.countDown();
404 }
405 }).start();
406 try {
Gustav Sennton0df2c552016-06-14 15:32:19 +0100407 Thread.sleep(500); // Let the new thread run / be blocked
Gustav Sennton53b78242016-04-07 15:56:10 +0100408 } catch (InterruptedException e) {
409 }
410
411 if (settingsChange) {
412 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
413 } else {
414 // Switch provider by enabling the second one
415 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100416 true /* valid */, true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100417 mWebViewUpdateServiceImpl.packageStateChanged(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100418 secondPackage, WebViewUpdateService.PACKAGE_CHANGED, 0);
Gustav Sennton53b78242016-04-07 15:56:10 +0100419 }
420 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
421 // first package done, should start on second
422
423 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
424 Mockito.argThat(new IsPackageInfoWithName(secondPackage)));
425
426 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
427 // second package done, the other thread should now be unblocked
428 try {
429 countdown.await();
430 } catch (InterruptedException e) {
431 }
432 }
433
434 public void testRunFallbackLogicIfEnabled() {
435 checkFallbackLogicBeingRun(true);
436 }
437
438 public void testDontRunFallbackLogicIfDisabled() {
439 checkFallbackLogicBeingRun(false);
440 }
441
442 private void checkFallbackLogicBeingRun(boolean fallbackLogicEnabled) {
443 String primaryPackage = "primary";
444 String fallbackPackage = "fallback";
445 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
446 new WebViewProviderInfo(
447 primaryPackage, "", true /* default available */, false /* fallback */, null),
448 new WebViewProviderInfo(
449 fallbackPackage, "", true /* default available */, true /* fallback */, null)};
450 setupWithPackages(packages, fallbackLogicEnabled);
451 setEnabledAndValidPackageInfos(packages);
452
453 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
454 // Verify that we disable the fallback package if fallback logic enabled, and don't disable
455 // the fallback package if that logic is disabled
456 if (fallbackLogicEnabled) {
457 Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
458 Matchers.anyObject(), Mockito.eq(fallbackPackage));
459 } else {
460 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
461 Matchers.anyObject(), Matchers.anyObject());
462 }
463 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
464 Mockito.argThat(new IsPackageInfoWithName(primaryPackage)));
465
466 // Enable fallback package
467 mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100468 true /* valid */, true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100469 mWebViewUpdateServiceImpl.packageStateChanged(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100470 fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED, 0);
Gustav Sennton53b78242016-04-07 15:56:10 +0100471
472 if (fallbackLogicEnabled) {
473 // Check that we have now disabled the fallback package twice
474 Mockito.verify(mTestSystemImpl, Mockito.times(2)).uninstallAndDisablePackageForAllUsers(
475 Matchers.anyObject(), Mockito.eq(fallbackPackage));
476 } else {
477 // Check that we still haven't disabled any package
478 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
479 Matchers.anyObject(), Matchers.anyObject());
480 }
481 }
482
483 /**
484 * Scenario for installing primary package when fallback enabled.
485 * 1. Start with only fallback installed
486 * 2. Install non-fallback
487 * 3. Fallback should be disabled
488 */
489 public void testInstallingNonFallbackPackage() {
490 String primaryPackage = "primary";
491 String fallbackPackage = "fallback";
492 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
493 new WebViewProviderInfo(
494 primaryPackage, "", true /* default available */, false /* fallback */, null),
495 new WebViewProviderInfo(
496 fallbackPackage, "", true /* default available */, true /* fallback */, null)};
497 setupWithPackages(packages, true /* isFallbackLogicEnabled */);
498 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100499 createPackageInfo(fallbackPackage, true /* enabled */ , true /* valid */,
500 true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100501
502 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
503 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
504 Matchers.anyObject(), Matchers.anyObject());
Gustav Sennton53b78242016-04-07 15:56:10 +0100505
Gustav Senntona9159042016-04-11 16:32:52 +0100506 checkPreparationPhasesForPackage(fallbackPackage,
507 1 /* first preparation for this package*/);
Gustav Sennton53b78242016-04-07 15:56:10 +0100508
509 // Install primary package
510 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100511 createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */,
512 true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100513 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100514 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
Gustav Sennton53b78242016-04-07 15:56:10 +0100515
Gustav Senntona9159042016-04-11 16:32:52 +0100516 // Verify fallback disabled, primary package used as provider, and fallback package killed
Gustav Sennton53b78242016-04-07 15:56:10 +0100517 Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
518 Matchers.anyObject(), Mockito.eq(fallbackPackage));
Gustav Senntona9159042016-04-11 16:32:52 +0100519 checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation for this package*/);
Gustav Sennton53b78242016-04-07 15:56:10 +0100520 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(fallbackPackage));
521 }
522
523 public void testFallbackChangesEnabledState() {
524 String primaryPackage = "primary";
525 String fallbackPackage = "fallback";
526 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
527 new WebViewProviderInfo(
528 primaryPackage, "", true /* default available */, false /* fallback */, null),
529 new WebViewProviderInfo(
530 fallbackPackage, "", true /* default available */, true /* fallback */, null)};
531 setupWithPackages(packages, true /* fallbackLogicEnabled */);
532 setEnabledAndValidPackageInfos(packages);
533
534 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
535
536 // Verify fallback disabled at boot when primary package enabled
537 Mockito.verify(mTestSystemImpl).enablePackageForUser(
538 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
539 Matchers.anyInt());
540
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100541 checkPreparationPhasesForPackage(primaryPackage, 1);
542
543 // Disable primary package and ensure fallback becomes enabled and used
Gustav Sennton53b78242016-04-07 15:56:10 +0100544 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100545 createPackageInfo(primaryPackage, false /* enabled */, true /* valid */,
546 true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100547 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100548 WebViewUpdateService.PACKAGE_CHANGED, 0);
Gustav Sennton53b78242016-04-07 15:56:10 +0100549
Gustav Sennton53b78242016-04-07 15:56:10 +0100550 Mockito.verify(mTestSystemImpl).enablePackageForUser(
551 Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */,
552 Matchers.anyInt());
553
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100554 checkPreparationPhasesForPackage(fallbackPackage, 1);
555
556
557 // Again enable primary package and verify primary is used and fallback becomes disabled
Gustav Sennton53b78242016-04-07 15:56:10 +0100558 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100559 createPackageInfo(primaryPackage, true /* enabled */, true /* valid */,
560 true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100561 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100562 WebViewUpdateService.PACKAGE_CHANGED, 0);
Gustav Sennton53b78242016-04-07 15:56:10 +0100563
564 // Verify fallback is disabled a second time when primary package becomes enabled
565 Mockito.verify(mTestSystemImpl, Mockito.times(2)).enablePackageForUser(
566 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
567 Matchers.anyInt());
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100568
569 checkPreparationPhasesForPackage(primaryPackage, 2);
Gustav Sennton53b78242016-04-07 15:56:10 +0100570 }
571
572 public void testAddUserWhenFallbackLogicEnabled() {
573 checkAddingNewUser(true);
574 }
575
576 public void testAddUserWhenFallbackLogicDisabled() {
577 checkAddingNewUser(false);
578 }
579
580 public void checkAddingNewUser(boolean fallbackLogicEnabled) {
581 String primaryPackage = "primary";
582 String fallbackPackage = "fallback";
583 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
584 new WebViewProviderInfo(
585 primaryPackage, "", true /* default available */, false /* fallback */, null),
586 new WebViewProviderInfo(
587 fallbackPackage, "", true /* default available */, true /* fallback */, null)};
588 setupWithPackages(packages, fallbackLogicEnabled);
589 setEnabledAndValidPackageInfos(packages);
590 int newUser = 100;
591 mWebViewUpdateServiceImpl.handleNewUser(newUser);
592 if (fallbackLogicEnabled) {
593 // Verify fallback package becomes disabled for new user
594 Mockito.verify(mTestSystemImpl).enablePackageForUser(
595 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
596 Mockito.eq(newUser));
597 } else {
598 // Verify that we don't disable fallback for new user
599 Mockito.verify(mTestSystemImpl, Mockito.never()).enablePackageForUser(
600 Mockito.anyObject(), Matchers.anyBoolean() /* enable */,
601 Matchers.anyInt() /* user */);
602 }
603 }
604
605 /**
606 * Timing dependent test where we verify that the list of valid webview packages becoming empty
607 * at a certain point doesn't crash us or break our state.
608 */
609 public void testNotifyRelroDoesntCrashIfNoPackages() {
610 String firstPackage = "first";
611 String secondPackage = "second";
612 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
613 new WebViewProviderInfo(firstPackage, "", true /* default available */,
614 false /* fallback */, null),
615 new WebViewProviderInfo(secondPackage, "", true /* default available */,
616 false /* fallback */, null)};
617 setupWithPackages(packages);
618 // Add (enabled and valid) package infos for each provider
619 setEnabledAndValidPackageInfos(packages);
620
621 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
622
623 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
624 Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
625
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100626 // Change provider during relro creation to enter a state where we are
627 // waiting for relro creation to complete just to re-run relro creation.
628 // (so that in next notifyRelroCreationCompleted() call we have to list webview packages)
Gustav Sennton53b78242016-04-07 15:56:10 +0100629 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
630
631 // Make packages invalid to cause exception to be thrown
632 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100633 false /* valid */, true /* installed */, null /* signatures */,
634 0 /* updateTime */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100635 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100636 false /* valid */, true /* installed */));
Gustav Sennton53b78242016-04-07 15:56:10 +0100637
638 // This shouldn't throw an exception!
639 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
640
641 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
642 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
643
644 // Now make a package valid again and verify that we can switch back to that
645 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100646 true /* valid */, true /* installed */, null /* signatures */,
647 1 /* updateTime */ ));
Gustav Sennton53b78242016-04-07 15:56:10 +0100648
649 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100650 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
Gustav Sennton53b78242016-04-07 15:56:10 +0100651
Gustav Senntona9159042016-04-11 16:32:52 +0100652 // Ensure we use firstPackage
653 checkPreparationPhasesForPackage(firstPackage, 2 /* second preparation for this package */);
654 }
Gustav Sennton53b78242016-04-07 15:56:10 +0100655
Gustav Senntona9159042016-04-11 16:32:52 +0100656 /**
657 * Verify that even if a user-chosen package is removed temporarily we start using it again when
658 * it is added back.
659 */
660 public void testTempRemovePackageDoesntSwitchProviderPermanently() {
661 String firstPackage = "first";
662 String secondPackage = "second";
663 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
664 new WebViewProviderInfo(firstPackage, "", true /* default available */,
665 false /* fallback */, null),
666 new WebViewProviderInfo(secondPackage, "", true /* default available */,
667 false /* fallback */, null)};
668 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
Gustav Sennton53b78242016-04-07 15:56:10 +0100669
Gustav Senntona9159042016-04-11 16:32:52 +0100670 // Explicitly use the second package
671 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
672 checkPreparationPhasesForPackage(secondPackage, 1 /* first time for this package */);
673
674 // Remove second package (invalidate it) and verify that first package is used
675 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100676 false /* valid */, true /* installed */));
Gustav Senntona9159042016-04-11 16:32:52 +0100677 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100678 WebViewUpdateService.PACKAGE_ADDED, 0);
Gustav Senntona9159042016-04-11 16:32:52 +0100679 checkPreparationPhasesForPackage(firstPackage, 2 /* second time for this package */);
680
681 // Now make the second package valid again and verify that it is used again
682 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100683 true /* valid */, true /* installed */));
Gustav Senntona9159042016-04-11 16:32:52 +0100684 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100685 WebViewUpdateService.PACKAGE_ADDED, 0);
Gustav Senntona9159042016-04-11 16:32:52 +0100686 checkPreparationPhasesForPackage(secondPackage, 2 /* second time for this package */);
687 }
688
689 /**
690 * Ensure that we update the user-chosen setting across boots if the chosen package is no
691 * longer installed and valid.
692 */
693 public void testProviderSettingChangedDuringBootIfProviderNotAvailable() {
694 String chosenPackage = "chosenPackage";
695 String nonChosenPackage = "non-chosenPackage";
696 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
697 new WebViewProviderInfo(chosenPackage, "", true /* default available */,
698 false /* fallback */, null),
699 new WebViewProviderInfo(nonChosenPackage, "", true /* default available */,
700 false /* fallback */, null)};
701
702 setupWithPackages(packages);
703 // Only 'install' nonChosenPackage
704 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100705 createPackageInfo(nonChosenPackage, true /* enabled */, true /* valid */, true /* installed */));
Gustav Senntona9159042016-04-11 16:32:52 +0100706
707 // Set user-chosen package
708 mTestSystemImpl.updateUserSetting(null, chosenPackage);
709
710 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
711
712 // Verify that we switch the setting to point to the current package
713 Mockito.verify(mTestSystemImpl).updateUserSetting(
714 Mockito.anyObject(), Mockito.eq(nonChosenPackage));
715 assertEquals(nonChosenPackage, mTestSystemImpl.getUserChosenWebViewProvider(null));
716
717 checkPreparationPhasesForPackage(nonChosenPackage, 1);
Gustav Sennton53b78242016-04-07 15:56:10 +0100718 }
719
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100720 public void testRecoverFailedListingWebViewPackagesSettingsChange() {
721 checkRecoverAfterFailListingWebviewPackages(true);
722 }
723
724 public void testRecoverFailedListingWebViewPackagesAddedPackage() {
725 checkRecoverAfterFailListingWebviewPackages(false);
726 }
727
728 /**
729 * Test that we can recover correctly from failing to list WebView packages.
730 * settingsChange: whether to fail during changeProviderAndSetting or packageStateChanged
731 */
732 public void checkRecoverAfterFailListingWebviewPackages(boolean settingsChange) {
733 String firstPackage = "first";
734 String secondPackage = "second";
735 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
736 new WebViewProviderInfo(firstPackage, "", true /* default available */,
737 false /* fallback */, null),
738 new WebViewProviderInfo(secondPackage, "", true /* default available */,
739 false /* fallback */, null)};
740 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
741
742 // Make both packages invalid so that we fail listing WebView packages
743 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100744 false /* valid */, true /* installed */));
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100745 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100746 false /* valid */, true /* installed */));
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100747
748 // Change package to hit the webview packages listing problem.
749 if (settingsChange) {
750 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
751 } else {
752 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100753 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100754 }
755
756 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
757 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
758
759 // Make second package valid and verify that we can load it again
760 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100761 true /* valid */, true /* installed */));
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100762
763 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100764 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100765
766
767 checkPreparationPhasesForPackage(secondPackage, 1);
768 }
769
770 public void testDontKillIfPackageReplaced() {
771 checkDontKillIfPackageRemoved(true);
772 }
773
774 public void testDontKillIfPackageRemoved() {
775 checkDontKillIfPackageRemoved(false);
776 }
777
778 public void checkDontKillIfPackageRemoved(boolean replaced) {
779 String firstPackage = "first";
780 String secondPackage = "second";
781 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
782 new WebViewProviderInfo(firstPackage, "", true /* default available */,
783 false /* fallback */, null),
784 new WebViewProviderInfo(secondPackage, "", true /* default available */,
785 false /* fallback */, null)};
786 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
787
788 // Replace or remove the current webview package
789 if (replaced) {
790 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100791 createPackageInfo(firstPackage, true /* enabled */, false /* valid */,
792 true /* installed */));
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100793 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100794 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100795 } else {
796 mTestSystemImpl.removePackageInfo(firstPackage);
797 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
Gustav Sennton0df2c552016-06-14 15:32:19 +0100798 WebViewUpdateService.PACKAGE_REMOVED, 0);
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100799 }
800
801 checkPreparationPhasesForPackage(secondPackage, 1);
802
803 Mockito.verify(mTestSystemImpl, Mockito.never()).killPackageDependents(
804 Mockito.anyObject());
805 }
806
807 public void testKillIfSettingChanged() {
808 String firstPackage = "first";
809 String secondPackage = "second";
810 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
811 new WebViewProviderInfo(firstPackage, "", true /* default available */,
812 false /* fallback */, null),
813 new WebViewProviderInfo(secondPackage, "", true /* default available */,
814 false /* fallback */, null)};
815 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
816
817 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
818
819 checkPreparationPhasesForPackage(secondPackage, 1);
820
821 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage));
822 }
823
824 /**
825 * Test that we kill apps using an old provider when we change the provider setting, even if the
826 * new provider is not the one we intended to change to.
827 */
828 public void testKillIfChangeProviderIncorrectly() {
829 String firstPackage = "first";
830 String secondPackage = "second";
831 String thirdPackage = "third";
832 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
833 new WebViewProviderInfo(firstPackage, "", true /* default available */,
834 false /* fallback */, null),
835 new WebViewProviderInfo(secondPackage, "", true /* default available */,
836 false /* fallback */, null),
837 new WebViewProviderInfo(thirdPackage, "", true /* default available */,
838 false /* fallback */, null)};
839 setupWithPackages(packages);
840 setEnabledAndValidPackageInfos(packages);
841
842 // Start with the setting pointing to the third package
843 mTestSystemImpl.updateUserSetting(null, thirdPackage);
844
845 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
846 checkPreparationPhasesForPackage(thirdPackage, 1);
847
848 mTestSystemImpl.setPackageInfo(
Gustav Sennton0df2c552016-06-14 15:32:19 +0100849 createPackageInfo(secondPackage, true /* enabled */, false /* valid */, true /* installed */));
Gustav Sennton95f7e8e2016-04-14 15:07:09 +0100850
851 // Try to switch to the invalid second package, this should result in switching to the first
852 // package, since that is more preferred than the third one.
853 assertEquals(firstPackage,
854 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage));
855
856 checkPreparationPhasesForPackage(firstPackage, 1);
857
858 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(thirdPackage));
859 }
Gustav Sennton18c9e152016-04-15 15:24:53 +0100860
861 public void testLowerPackageVersionNotValid() {
Hui Shu826a24b2016-04-26 14:53:40 -0700862 checkPackageVersions(new int[]{200000} /* system version */, 100000/* candidate version */,
863 false /* expected validity */);
Gustav Sennton18c9e152016-04-15 15:24:53 +0100864 }
865
866 public void testEqualPackageVersionValid() {
Hui Shu826a24b2016-04-26 14:53:40 -0700867 checkPackageVersions(new int[]{100000} /* system version */, 100000 /* candidate version */,
868 true /* expected validity */);
Gustav Sennton18c9e152016-04-15 15:24:53 +0100869 }
870
871 public void testGreaterPackageVersionValid() {
Hui Shu826a24b2016-04-26 14:53:40 -0700872 checkPackageVersions(new int[]{100000} /* system versions */, 200000 /* candidate version */,
873 true /* expected validity */);
Gustav Sennton18c9e152016-04-15 15:24:53 +0100874 }
875
Hui Shu826a24b2016-04-26 14:53:40 -0700876 public void testLastFiveDigitsIgnored() {
877 checkPackageVersions(new int[]{654321} /* system version */, 612345 /* candidate version */,
878 true /* expected validity */);
Gustav Sennton18c9e152016-04-15 15:24:53 +0100879 }
880
Hui Shu826a24b2016-04-26 14:53:40 -0700881 public void testMinimumSystemVersionUsedTwoDefaultsCandidateValid() {
882 checkPackageVersions(new int[]{300000, 100000} /* system versions */,
883 200000 /* candidate version */, true /* expected validity */);
Gustav Sennton18c9e152016-04-15 15:24:53 +0100884 }
885
Hui Shu826a24b2016-04-26 14:53:40 -0700886 public void testMinimumSystemVersionUsedTwoDefaultsCandidateInvalid() {
887 checkPackageVersions(new int[]{300000, 200000} /* system versions */,
888 100000 /* candidate version */, false /* expected validity */);
Gustav Sennton18c9e152016-04-15 15:24:53 +0100889 }
890
Hui Shu826a24b2016-04-26 14:53:40 -0700891 public void testMinimumSystemVersionUsedSeveralDefaultsCandidateValid() {
892 checkPackageVersions(new int[]{100000, 200000, 300000, 400000, 500000} /* system versions */,
893 100000 /* candidate version */, true /* expected validity */);
894 }
895
896 public void testMinimumSystemVersionUsedSeveralDefaultsCandidateInvalid() {
897 checkPackageVersions(new int[]{200000, 300000, 400000, 500000, 600000} /* system versions */,
898 100000 /* candidate version */, false /* expected validity */);
Gustav Sennton18c9e152016-04-15 15:24:53 +0100899 }
900
901 public void testMinimumSystemVersionUsedFallbackIgnored() {
Hui Shu826a24b2016-04-26 14:53:40 -0700902 checkPackageVersions(new int[]{300000, 400000, 500000, 600000, 700000} /* system versions */,
903 200000 /* candidate version */, false /* expected validity */, true /* add fallback */,
904 100000 /* fallback version */, false /* expected validity of fallback */);
Gustav Sennton18c9e152016-04-15 15:24:53 +0100905 }
906
Hui Shu826a24b2016-04-26 14:53:40 -0700907 public void testFallbackValid() {
908 checkPackageVersions(new int[]{300000, 400000, 500000, 600000, 700000} /* system versions */,
909 200000/* candidate version */, false /* expected validity */, true /* add fallback */,
910 300000 /* fallback version */, true /* expected validity of fallback */);
911 }
912
913 private void checkPackageVersions(int[] systemVersions, int candidateVersion,
914 boolean candidateShouldBeValid) {
915 checkPackageVersions(systemVersions, candidateVersion, candidateShouldBeValid,
916 false, 0, false);
Gustav Sennton18c9e152016-04-15 15:24:53 +0100917 }
918
919 /**
920 * Utility method for checking that package version restriction works as it should.
921 * I.e. that a package with lower version than the system-default is not valid and that a
922 * package with greater than or equal version code is considered valid.
923 */
Hui Shu826a24b2016-04-26 14:53:40 -0700924 private void checkPackageVersions(int[] systemVersions, int candidateVersion,
925 boolean candidateShouldBeValid, boolean addFallback, int fallbackVersion,
926 boolean fallbackShouldBeValid) {
Gustav Sennton18c9e152016-04-15 15:24:53 +0100927 int numSystemPackages = systemVersions.length;
928 int numFallbackPackages = (addFallback ? 1 : 0);
929 int numPackages = systemVersions.length + 1 + numFallbackPackages;
Hui Shu826a24b2016-04-26 14:53:40 -0700930 String candidatePackage = "candidatePackage";
Gustav Sennton18c9e152016-04-15 15:24:53 +0100931 String systemPackage = "systemPackage";
932 String fallbackPackage = "fallbackPackage";
933
934 // Each package needs a valid signature since we set isDebuggable to false
935 Signature signature = new Signature("11");
936 String encodedSignatureString =
937 Base64.encodeToString(signature.toByteArray(), Base64.DEFAULT);
938
939 // Set up config
Hui Shu826a24b2016-04-26 14:53:40 -0700940 // 1. candidatePackage
Gustav Sennton18c9e152016-04-15 15:24:53 +0100941 // 2-N. default available non-fallback packages
942 // N+1. default available fallback package
943 WebViewProviderInfo[] packages = new WebViewProviderInfo[numPackages];
Hui Shu826a24b2016-04-26 14:53:40 -0700944 packages[0] = new WebViewProviderInfo(candidatePackage, "",
Gustav Sennton18c9e152016-04-15 15:24:53 +0100945 false /* available by default */, false /* fallback */,
946 new String[]{encodedSignatureString});
947 for(int n = 1; n < numSystemPackages + 1; n++) {
948 packages[n] = new WebViewProviderInfo(systemPackage + n, "",
949 true /* available by default */, false /* fallback */,
950 new String[]{encodedSignatureString});
951 }
952 if (addFallback) {
953 packages[packages.length-1] = new WebViewProviderInfo(fallbackPackage, "",
954 true /* available by default */, true /* fallback */,
955 new String[]{encodedSignatureString});
956 }
957
958 setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */,
959 false /* isDebuggable */);
960
961 // Set package infos
962 mTestSystemImpl.setPackageInfo(
Hui Shu826a24b2016-04-26 14:53:40 -0700963 createPackageInfo(candidatePackage, true /* enabled */, true /* valid */,
Gustav Senntonfd222fc22016-06-16 20:24:23 +0100964 true /* installed */, new Signature[]{signature}, 0 /* updateTime */,
965 false /* hidden */, candidateVersion, false /* isSystemApp */));
Gustav Sennton18c9e152016-04-15 15:24:53 +0100966 for(int n = 1; n < numSystemPackages + 1; n++) {
967 mTestSystemImpl.setPackageInfo(
968 createPackageInfo(systemPackage + n, true /* enabled */, true /* valid */,
Gustav Senntonfd222fc22016-06-16 20:24:23 +0100969 true /* installed */, new Signature[]{signature}, 0 /* updateTime */,
970 false /* hidden */, systemVersions[n-1], true /* isSystemApp */));
Gustav Sennton18c9e152016-04-15 15:24:53 +0100971 }
972 if (addFallback) {
973 mTestSystemImpl.setPackageInfo(
974 createPackageInfo(fallbackPackage, true /* enabled */, true /* valid */,
Gustav Senntonfd222fc22016-06-16 20:24:23 +0100975 true /* installed */, new Signature[]{signature}, 0 /* updateTime */,
976 false /* hidden */, fallbackVersion, true /* isSystemApp */));
Gustav Sennton18c9e152016-04-15 15:24:53 +0100977 }
978
979 WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
Hui Shu826a24b2016-04-26 14:53:40 -0700980 int expectedNumValidPackages = numSystemPackages;
981 if (candidateShouldBeValid) {
982 expectedNumValidPackages++;
Gustav Sennton18c9e152016-04-15 15:24:53 +0100983 } else {
Hui Shu826a24b2016-04-26 14:53:40 -0700984 // Ensure the candidate package is not one of the valid packages
Gustav Sennton18c9e152016-04-15 15:24:53 +0100985 for(int n = 0; n < validPackages.length; n++) {
Hui Shu826a24b2016-04-26 14:53:40 -0700986 assertFalse(candidatePackage.equals(validPackages[n].packageName));
Gustav Sennton18c9e152016-04-15 15:24:53 +0100987 }
988 }
989
Hui Shu826a24b2016-04-26 14:53:40 -0700990 if (fallbackShouldBeValid) {
991 expectedNumValidPackages += numFallbackPackages;
992 } else {
993 // Ensure the fallback package is not one of the valid packages
994 for(int n = 0; n < validPackages.length; n++) {
995 assertFalse(fallbackPackage.equals(validPackages[n].packageName));
996 }
997 }
998
999 assertEquals(expectedNumValidPackages, validPackages.length);
1000
Gustav Sennton18c9e152016-04-15 15:24:53 +01001001 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
1002
1003 // The non-system package is not available by default so it shouldn't be used here
1004 checkPreparationPhasesForPackage(systemPackage + "1", 1);
1005
Hui Shu826a24b2016-04-26 14:53:40 -07001006 // Try explicitly switching to the candidate package
1007 String packageChange = mWebViewUpdateServiceImpl.changeProviderAndSetting(candidatePackage);
1008 if (candidateShouldBeValid) {
1009 assertEquals(candidatePackage, packageChange);
1010 checkPreparationPhasesForPackage(candidatePackage, 1);
Gustav Sennton18c9e152016-04-15 15:24:53 +01001011 } else {
1012 assertEquals(systemPackage + "1", packageChange);
1013 // We didn't change package so the webview preparation won't run here
1014 }
1015 }
Gustav Senntonfd222fc22016-06-16 20:24:23 +01001016
Gustav Sennton0df2c552016-06-14 15:32:19 +01001017 // Ensure that the update service uses an uninstalled package if that is the only package
1018 // available.
1019 public void testWithSingleUninstalledPackage() {
1020 String testPackageName = "test.package.name";
1021 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
1022 new WebViewProviderInfo(testPackageName, "",
1023 true /*default available*/, false /* fallback */, null)};
1024 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
1025 mTestSystemImpl.setPackageInfo(createPackageInfo(testPackageName, true /* enabled */,
1026 true /* valid */, false /* installed */));
1027
1028 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
1029
1030 checkPreparationPhasesForPackage(testPackageName, 1 /* first preparation phase */);
1031 }
1032
1033 public void testNonhiddenPackageUserOverHidden() {
1034 checkVisiblePackageUserOverNonVisible(false /* true == uninstalled, false == hidden */);
1035 }
1036
1037 public void testInstalledPackageUsedOverUninstalled() {
1038 checkVisiblePackageUserOverNonVisible(true /* true == uninstalled, false == hidden */);
1039 }
1040
1041 private void checkVisiblePackageUserOverNonVisible(boolean uninstalledNotHidden) {
1042 boolean testUninstalled = uninstalledNotHidden;
1043 boolean testHidden = !uninstalledNotHidden;
1044 String installedPackage = "installedPackage";
1045 String uninstalledPackage = "uninstalledPackage";
1046 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
1047 new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */,
1048 false /* fallback */, null),
1049 new WebViewProviderInfo(installedPackage, "", true /* available by default */,
1050 false /* fallback */, null)};
1051
1052 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
1053 mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
1054 true /* valid */, true /* installed */));
1055 mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
1056 true /* valid */, (testUninstalled ? false : true) /* installed */,
1057 null /* signatures */, 0 /* updateTime */, (testHidden ? true : false)));
1058
1059 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
1060
1061 checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
1062 }
1063
1064 public void testCantSwitchToHiddenPackage () {
1065 checkCantSwitchToNonVisiblePackage(false /* true == uninstalled, false == hidden */);
1066 }
1067
1068
1069 public void testCantSwitchToUninstalledPackage () {
1070 checkCantSwitchToNonVisiblePackage(true /* true == uninstalled, false == hidden */);
1071 }
1072
1073 /**
1074 * Ensure that we won't prioritize an uninstalled (or hidden) package even if it is user-chosen,
1075 * and that an uninstalled (or hidden) package is not considered valid (in the
1076 * getValidWebViewPackages() API).
1077 */
1078 private void checkCantSwitchToNonVisiblePackage(boolean uninstalledNotHidden) {
1079 boolean testUninstalled = uninstalledNotHidden;
1080 boolean testHidden = !uninstalledNotHidden;
1081 String installedPackage = "installedPackage";
1082 String uninstalledPackage = "uninstalledPackage";
1083 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
1084 new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */,
1085 false /* fallback */, null),
1086 new WebViewProviderInfo(installedPackage, "", true /* available by default */,
1087 false /* fallback */, null)};
1088
1089 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
1090 mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
1091 true /* valid */, true /* installed */));
1092 mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
1093 true /* valid */, (testUninstalled ? false : true) /* installed */,
1094 null /* signatures */, 0 /* updateTime */,
1095 (testHidden ? true : false) /* hidden */));
1096
1097 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
1098
1099 checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
1100
1101 // Ensure that only the installed package is considered valid
1102 WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
1103 assertEquals(1, validPackages.length);
1104 assertEquals(installedPackage, validPackages[0].packageName);
1105
1106 // ensure that we don't switch to the uninstalled package (it will be used if it becomes
1107 // installed later)
1108 assertEquals(installedPackage,
1109 mWebViewUpdateServiceImpl.changeProviderAndSetting(uninstalledPackage));
1110
1111 // We should only have called onWebViewProviderChanged once (before calling
1112 // changeProviderAndSetting
1113 Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged(
1114 Mockito.argThat(new IsPackageInfoWithName(installedPackage)));
1115 }
1116
1117 public void testHiddenPackageNotPrioritizedEvenIfChosen() {
1118 checkNonvisiblePackageNotPrioritizedEvenIfChosen(
1119 false /* true == uninstalled, false == hidden */);
1120 }
1121
1122 public void testUninstalledPackageNotPrioritizedEvenIfChosen() {
1123 checkNonvisiblePackageNotPrioritizedEvenIfChosen(
1124 true /* true == uninstalled, false == hidden */);
1125 }
1126
1127 public void checkNonvisiblePackageNotPrioritizedEvenIfChosen(boolean uninstalledNotHidden) {
1128 boolean testUninstalled = uninstalledNotHidden;
1129 boolean testHidden = !uninstalledNotHidden;
1130 String installedPackage = "installedPackage";
1131 String uninstalledPackage = "uninstalledPackage";
1132 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
1133 new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */,
1134 false /* fallback */, null),
1135 new WebViewProviderInfo(installedPackage, "", true /* available by default */,
1136 false /* fallback */, null)};
1137
1138 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
1139 mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
1140 true /* valid */, true /* installed */));
1141 mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
1142 true /* valid */, (testUninstalled ? false : true) /* installed */,
1143 null /* signatures */, 0 /* updateTime */,
1144 (testHidden ? true : false) /* hidden */));
1145
1146 // Start with the setting pointing to the uninstalled package
1147 mTestSystemImpl.updateUserSetting(null, uninstalledPackage);
1148
1149 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
1150
1151 checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
1152 }
1153
1154 /**
1155 * Ensures that fallback becomes enabled if the primary package is uninstalled for the current
1156 * user.
1157 */
1158 public void testFallbackEnabledIfPrimaryUninstalled() {
1159 String primaryPackage = "primary";
1160 String fallbackPackage = "fallback";
1161 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
1162 new WebViewProviderInfo(
1163 primaryPackage, "", true /* default available */, false /* fallback */, null),
1164 new WebViewProviderInfo(
1165 fallbackPackage, "", true /* default available */, true /* fallback */, null)};
1166 setupWithPackages(packages, true /* fallback logic enabled */);
1167 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
1168 true /* valid */, false /* installed */));
1169 mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
1170 true /* valid */, true /* installed */));
1171
1172 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
1173 // Verify that we enable the fallback package
1174 Mockito.verify(mTestSystemImpl).enablePackageForAllUsers(
1175 Mockito.anyObject(), Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */);
1176
1177 checkPreparationPhasesForPackage(fallbackPackage, 1 /* first preparation phase */);
1178 }
1179
1180 public void testPreparationRunsIffNewPackage() {
1181 String primaryPackage = "primary";
1182 String fallbackPackage = "fallback";
1183 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
1184 new WebViewProviderInfo(
1185 primaryPackage, "", true /* default available */, false /* fallback */, null),
1186 new WebViewProviderInfo(
1187 fallbackPackage, "", true /* default available */, true /* fallback */, null)};
1188 setupWithPackages(packages, true /* fallback logic enabled */);
1189 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
1190 true /* valid */, true /* installed */, null /* signatures */,
1191 10 /* lastUpdateTime*/ ));
1192 mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
1193 true /* valid */, true /* installed */));
1194
1195 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
1196
1197 checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */);
1198 Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser(
1199 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
1200 Matchers.anyInt() /* user */);
1201
1202
1203 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
1204 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0 /* userId */);
1205 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
1206 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 1 /* userId */);
1207 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
1208 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 2 /* userId */);
1209 // package still has the same update-time so we shouldn't run preparation here
1210 Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged(
1211 Mockito.argThat(new IsPackageInfoWithName(primaryPackage)));
1212 Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser(
1213 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
1214 Matchers.anyInt() /* user */);
1215
1216 // Ensure we can still load the package
1217 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
1218 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
1219 assertEquals(primaryPackage, response.packageInfo.packageName);
1220
1221
1222 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
1223 true /* valid */, true /* installed */, null /* signatures */,
1224 20 /* lastUpdateTime*/ ));
1225 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
1226 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
1227 // The package has now changed - ensure that we have run the preparation phase a second time
1228 checkPreparationPhasesForPackage(primaryPackage, 2 /* second preparation phase */);
1229
1230
1231 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
1232 true /* valid */, true /* installed */, null /* signatures */,
1233 50 /* lastUpdateTime*/ ));
1234 // Receive intent for different user
1235 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
1236 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 2);
1237
1238 checkPreparationPhasesForPackage(primaryPackage, 3 /* third preparation phase */);
1239 }
Gustav Sennton53b78242016-04-07 15:56:10 +01001240}