Add an API for retrieving information about the current WebView package.

Now that WebView can be loaded from one out of a set of packages we
provide an API for fetching information about this package.
Such API is especially useful for debugging crashes.

Bug: 30597460

Change-Id: I13dd746f7efcf2917b517053010b73ea35241325
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 43cdf59..6d97796 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.PatternMatcher;
@@ -224,7 +225,13 @@
 
         @Override // Binder call
         public String getCurrentWebViewPackageName() {
-            return WebViewUpdateService.this.mImpl.getCurrentWebViewPackageName();
+            PackageInfo pi = WebViewUpdateService.this.mImpl.getCurrentWebViewPackage();
+            return pi == null ? null : pi.packageName;
+        }
+
+        @Override // Binder call
+        public PackageInfo getCurrentWebViewPackage() {
+            return WebViewUpdateService.this.mImpl.getCurrentWebViewPackage();
         }
 
         @Override // Binder call
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index 3a93b46..b69a8c1 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -145,8 +145,8 @@
         return mSystemInterface.getWebViewPackages();
     }
 
-    String getCurrentWebViewPackageName() {
-        return mWebViewUpdater.getCurrentWebViewPackageName();
+    PackageInfo getCurrentWebViewPackage() {
+        return mWebViewUpdater.getCurrentWebViewPackage();
     }
 
     void enableFallbackLogic(boolean enable) {
@@ -316,6 +316,7 @@
                                 onWebViewProviderChanged(newPackage);
                             }
                         } catch (WebViewPackageMissingException e) {
+                            mCurrentWebViewPackage = null;
                             Slog.e(TAG, "Could not find valid WebView package to create " +
                                     "relro with " + e);
                         }
@@ -371,6 +372,7 @@
                     providerChanged = (oldPackage == null)
                             || !newPackage.packageName.equals(oldPackage.packageName);
                 } catch (WebViewPackageMissingException e) {
+                    mCurrentWebViewPackage = null;
                     Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView " +
                             "package " + e);
                     // If we don't perform the user change but don't have an installed WebView
@@ -548,11 +550,9 @@
             return new WebViewProviderResponse(webViewPackage, webViewStatus);
         }
 
-        public String getCurrentWebViewPackageName() {
+        public PackageInfo getCurrentWebViewPackage() {
             synchronized(mLock) {
-                if (mCurrentWebViewPackage == null)
-                    return null;
-                return mCurrentWebViewPackage.packageName;
+                return mCurrentWebViewPackage;
             }
         }
 
@@ -579,6 +579,7 @@
                         PackageInfo newPackage = findPreferredWebViewPackage();
                         onWebViewProviderChanged(newPackage);
                     } catch (WebViewPackageMissingException e) {
+                        mCurrentWebViewPackage = null;
                         // If we can't find any valid WebView package we are now in a state where
                         // mAnyWebViewInstalled is false, so loading WebView will be blocked and we
                         // should simply wait until we receive an intent declaring a new package was
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index 7f171fb..0f898e5 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -303,6 +303,31 @@
 
         WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
         assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
+        assertEquals(null, mWebViewUpdateServiceImpl.getCurrentWebViewPackage());
+
+        // Now install a package
+        String singlePackage = "singlePackage";
+        packages = new WebViewProviderInfo[]{
+            new WebViewProviderInfo(singlePackage, "", true, false, null)};
+        setupWithPackages(packages);
+        setEnabledAndValidPackageInfos(packages);
+
+        mWebViewUpdateServiceImpl.packageStateChanged(singlePackage,
+                WebViewUpdateService.PACKAGE_ADDED, 0);
+
+        checkPreparationPhasesForPackage(singlePackage, 1 /* number of finished preparations */);
+        assertEquals(singlePackage,
+                mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
+
+        // Remove the package again
+        mTestSystemImpl.removePackageInfo(singlePackage);
+        mWebViewUpdateServiceImpl.packageStateChanged(singlePackage,
+                WebViewUpdateService.PACKAGE_ADDED, 0);
+
+        // Package removed - ensure our interface states that there is no package
+        response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
+        assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
+        assertEquals(null, mWebViewUpdateServiceImpl.getCurrentWebViewPackage());
     }
 
     public void testFailListingInvalidWebviewPackage() {
@@ -395,7 +420,8 @@
         Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
                 Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
 
-        assertEquals(firstPackage, mWebViewUpdateServiceImpl.getCurrentWebViewPackageName());
+        assertEquals(firstPackage,
+                mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
 
         new Thread(new Runnable() {
             @Override
@@ -1243,4 +1269,42 @@
 
         checkPreparationPhasesForPackage(primaryPackage, 3 /* third preparation phase */);
     }
+
+    public void testGetCurrentWebViewPackage() {
+        PackageInfo firstPackage = createPackageInfo("first", true /* enabled */,
+                        true /* valid */, true /* installed */);
+        firstPackage.versionCode = 100;
+        firstPackage.versionName = "first package version";
+        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+            new WebViewProviderInfo(firstPackage.packageName, "", true, false, null)};
+        setupWithPackages(packages, true);
+        mTestSystemImpl.setPackageInfo(firstPackage);
+
+        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+
+        Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
+                Mockito.argThat(new IsPackageInfoWithName(firstPackage.packageName)));
+
+        mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
+
+        // Ensure the API is correct before running waitForAndGetProvider
+        assertEquals(firstPackage.packageName,
+                mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
+        assertEquals(firstPackage.versionCode,
+                mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionCode);
+        assertEquals(firstPackage.versionName,
+                mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionName);
+
+        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
+        assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
+        assertEquals(firstPackage.packageName, response.packageInfo.packageName);
+
+        // Ensure the API is still correct after running waitForAndGetProvider
+        assertEquals(firstPackage.packageName,
+                mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
+        assertEquals(firstPackage.versionCode,
+                mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionCode);
+        assertEquals(firstPackage.versionName,
+                mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionName);
+    }
 }