Add network consent check before connecting to RKP server.

Some restricted regions require a check for network consent before
making a network call. We assume that using GMS application gives a
consent for making network calls since GMS by default is dependent on
network connection with Google.

Test: atest RkpdAppUnitTests
Bug: 298881366
Change-Id: I6fedbc6b400735fa612ce33d3253df16f5f7aebd
diff --git a/app/src/com/android/rkpdapp/interfaces/ServerInterface.java b/app/src/com/android/rkpdapp/interfaces/ServerInterface.java
index 7ed18b2..f11c527 100644
--- a/app/src/com/android/rkpdapp/interfaces/ServerInterface.java
+++ b/app/src/com/android/rkpdapp/interfaces/ServerInterface.java
@@ -17,6 +17,7 @@
 package com.android.rkpdapp.interfaces;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
 import android.net.TrafficStats;
@@ -69,6 +70,9 @@
     private static final String CERTIFICATE_SIGNING_URL = ":signCertificates";
     private static final String CHALLENGE_PARAMETER = "challenge";
     private static final String REQUEST_ID_PARAMETER = "request_id";
+    private static final String GMS_PACKAGE = "com.google.android.gms";
+    private static final String CHINA_GMS_FEATURE = "cn.google.services";
+
     private final Context mContext;
     private final boolean mIsAsync;
 
@@ -230,6 +234,12 @@
             throw new RkpdException(RkpdException.ErrorCode.NO_NETWORK_CONNECTIVITY,
                     "No network detected.");
         }
+        // Since fetchGeek would be the first call for any sort of provisioning, we are okay
+        // checking network consent here.
+        if (!assumeNetworkConsent(mContext)) {
+            throw new RkpdException(RkpdException.ErrorCode.NETWORK_COMMUNICATION_ERROR,
+                    "Network communication consent not provided. Need to enable GMSCore app.");
+        }
         byte[] input = CborUtils.buildProvisioningInfo(mContext);
         byte[] cborBytes =
                 connectAndGetData(metrics, generateFetchGeekUrl(), input, Operation.FETCH_GEEK);
@@ -343,6 +353,29 @@
         return new String(bytes, charset);
     }
 
+    /**
+     * Checks whether GMSCore is installed and enabled for restricted regions.
+     * This lets us assume that user has consented to connecting to Google
+     * servers to provide attestation service.
+     * For all other regions, we assume consent by default since this is an
+     * Android OS-level application.
+     *
+     * @return True if user consent can be assumed else false.
+     */
+    @VisibleForTesting
+    public static boolean assumeNetworkConsent(Context context) {
+        PackageManager pm = context.getPackageManager();
+        if (pm.hasSystemFeature(CHINA_GMS_FEATURE)) {
+            // For china GMS, we can simply check whether GMS package is installed and enabled.
+            try {
+                return pm.getApplicationInfo(GMS_PACKAGE, 0).enabled;
+            } catch (PackageManager.NameNotFoundException e) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     private static Charset getCharsetFromContentTypeHeader(String contentType) {
         final String[] contentTypeParts = contentType.split(";");
         if (contentTypeParts.length != 2) {
diff --git a/app/tests/unit/src/com/android/rkpdapp/unittest/ServerInterfaceTest.java b/app/tests/unit/src/com/android/rkpdapp/unittest/ServerInterfaceTest.java
index 6f85dba..ed1f64a 100644
--- a/app/tests/unit/src/com/android/rkpdapp/unittest/ServerInterfaceTest.java
+++ b/app/tests/unit/src/com/android/rkpdapp/unittest/ServerInterfaceTest.java
@@ -20,6 +20,8 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
 import android.util.Base64;
@@ -410,6 +412,35 @@
                 ServerInterface.SYNC_CONNECT_TIMEOUT_OPEN_MS);
     }
 
+    @Test
+    public void testConnectionConsent() throws Exception {
+        String cnGmsFeature = "cn.google.services";
+        PackageManager mockedPackageManager = Mockito.mock(PackageManager.class);
+        Context mockedContext = Mockito.mock(Context.class);
+        ApplicationInfo fakeApplicationInfo = new ApplicationInfo();
+
+        Mockito.when(mockedContext.getPackageManager()).thenReturn(mockedPackageManager);
+        Mockito.when(mockedPackageManager.hasSystemFeature(cnGmsFeature)).thenReturn(true);
+        Mockito.when(mockedPackageManager.getApplicationInfo(Mockito.any(), Mockito.eq(0)))
+                .thenReturn(fakeApplicationInfo);
+
+        fakeApplicationInfo.enabled = false;
+        assertThat(ServerInterface.assumeNetworkConsent(mockedContext)).isFalse();
+
+        fakeApplicationInfo.enabled = true;
+        assertThat(ServerInterface.assumeNetworkConsent(mockedContext)).isTrue();
+
+        Mockito.when(mockedPackageManager.getApplicationInfo(Mockito.any(), Mockito.eq(0)))
+                .thenThrow(new PackageManager.NameNotFoundException());
+        assertThat(ServerInterface.assumeNetworkConsent(mockedContext)).isFalse();
+
+        Mockito.when(mockedPackageManager.hasSystemFeature(cnGmsFeature)).thenReturn(false);
+        assertThat(ServerInterface.assumeNetworkConsent(mockedContext)).isTrue();
+
+        fakeApplicationInfo.enabled = false;
+        assertThat(ServerInterface.assumeNetworkConsent(mockedContext)).isTrue();
+    }
+
     private void mockConnectivityFailure(ConnectivityState state) {
         ConnectivityManager mockedConnectivityManager = Mockito.mock(ConnectivityManager.class);