Update CtsHostsideNetworkTests to take network capability into account.

Bug: 177641226
Test: atest ./tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
Ignore-AOSP-First: Expedited jobs are not available in AOSP
Change-Id: Ic75ebdc184764b7e7ac02d3e2ca18cbba1c55ee5
diff --git a/tests/cts/hostside/app2/Android.bp b/tests/cts/hostside/app2/Android.bp
index b448459..dd33eed 100644
--- a/tests/cts/hostside/app2/Android.bp
+++ b/tests/cts/hostside/app2/Android.bp
@@ -21,7 +21,7 @@
 android_test_helper_app {
     name: "CtsHostsideNetworkTestsApp2",
     defaults: ["cts_support_defaults"],
-    sdk_version: "current",
+    sdk_version: "test_current",
     static_libs: ["CtsHostsideNetworkTestsAidl"],
     srcs: ["src/**/*.java"],
     // Tag this module as a cts test artifact
diff --git a/tests/cts/hostside/app2/AndroidManifest.xml b/tests/cts/hostside/app2/AndroidManifest.xml
index b85d800..99b653c 100644
--- a/tests/cts/hostside/app2/AndroidManifest.xml
+++ b/tests/cts/hostside/app2/AndroidManifest.xml
@@ -21,20 +21,23 @@
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
 
     <!--
-                 This application is used to listen to RESTRICT_BACKGROUND_CHANGED intents and store
-                 them in a shared preferences which is then read by the test app. These broadcasts are
-                 handled by 2 listeners, one defined the manifest and another dynamically registered by
-                 a service.
+     This application is used to listen to RESTRICT_BACKGROUND_CHANGED intents and store
+     them in a shared preferences which is then read by the test app. These broadcasts are
+     handled by 2 listeners, one defined the manifest and another dynamically registered by
+     a service.
 
-                 The manifest-defined listener also handles ordered broadcasts used to share data with the
-                 test app.
+     The manifest-defined listener also handles ordered broadcasts used to share data with the
+     test app.
 
-                 This application also provides a service, RemoteSocketFactoryService, that the test app can
-                 use to open sockets to remote hosts as a different user ID.
-            -->
-    <application android:usesCleartextTraffic="true">
+     This application also provides a service, RemoteSocketFactoryService, that the test app can
+     use to open sockets to remote hosts as a different user ID.
+    -->
+    <application android:usesCleartextTraffic="true"
+            android:testOnly="true">
+
         <activity android:name=".MyActivity"
              android:exported="true"/>
         <service android:name=".MyService"
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
index 5c45d44..62b508c 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
@@ -15,11 +15,13 @@
  */
 package com.android.cts.net.hostside.app2;
 
+import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -53,6 +55,11 @@
 
     static final String TEST_PKG = "com.android.cts.net.hostside";
     static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
+    static final String KEY_SKIP_VALIDATION_CHECKS = TEST_PKG + ".skip_validation_checks";
+
+    static final int TYPE_COMPONENT_ACTIVTY = 0;
+    static final int TYPE_COMPONENT_FOREGROUND_SERVICE = 1;
+    static final int TYPE_COMPONENT_EXPEDITED_JOB = 2;
 
     static int getUid(Context context) {
         final String packageName = context.getPackageName();
@@ -63,15 +70,57 @@
         }
     }
 
-    static void notifyNetworkStateObserver(Context context, Intent intent) {
+    private static boolean validateComponentState(Context context, int componentType,
+            INetworkStateObserver observer) throws RemoteException {
+        final ActivityManager activityManager = context.getSystemService(ActivityManager.class);
+        switch (componentType) {
+            case TYPE_COMPONENT_ACTIVTY: {
+                final int procState = activityManager.getUidProcessState(Process.myUid());
+                if (procState != ActivityManager.PROCESS_STATE_TOP) {
+                    observer.onNetworkStateChecked(
+                            INetworkStateObserver.RESULT_ERROR_UNEXPECTED_PROC_STATE,
+                            "Unexpected procstate: " + procState);
+                    return false;
+                }
+                return true;
+            }
+            case TYPE_COMPONENT_FOREGROUND_SERVICE: {
+                final int procState = activityManager.getUidProcessState(Process.myUid());
+                if (procState != ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+                    observer.onNetworkStateChecked(
+                            INetworkStateObserver.RESULT_ERROR_UNEXPECTED_PROC_STATE,
+                            "Unexpected procstate: " + procState);
+                    return false;
+                }
+                return true;
+            }
+            case TYPE_COMPONENT_EXPEDITED_JOB: {
+                final int capabilities = activityManager.getUidProcessCapabilities(Process.myUid());
+                if ((capabilities & ActivityManager.PROCESS_CAPABILITY_NETWORK) == 0) {
+                    observer.onNetworkStateChecked(
+                            INetworkStateObserver.RESULT_ERROR_UNEXPECTED_CAPABILITIES,
+                            "Unexpected capabilities: " + capabilities);
+                    return false;
+                }
+                return true;
+            }
+            default: {
+                observer.onNetworkStateChecked(INetworkStateObserver.RESULT_ERROR_OTHER,
+                        "Unknown component type: " + componentType);
+                return false;
+            }
+        }
+    }
+
+    static void notifyNetworkStateObserver(Context context, Intent intent, int componentType) {
         if (intent == null) {
             return;
         }
         final Bundle extras = intent.getExtras();
-        notifyNetworkStateObserver(context, extras);
+        notifyNetworkStateObserver(context, extras, componentType);
     }
 
-    static void notifyNetworkStateObserver(Context context, Bundle extras) {
+    static void notifyNetworkStateObserver(Context context, Bundle extras, int componentType) {
         if (extras == null) {
             return;
         }
@@ -79,17 +128,17 @@
                 extras.getBinder(KEY_NETWORK_STATE_OBSERVER));
         if (observer != null) {
             try {
-                if (!observer.isForeground()) {
-                    Log.e(TAG, "App didn't come to foreground");
-                    observer.onNetworkStateChecked(null);
+                final boolean skipValidation = extras.getBoolean(KEY_SKIP_VALIDATION_CHECKS);
+                if (!skipValidation && !validateComponentState(context, componentType, observer)) {
                     return;
                 }
             } catch (RemoteException e) {
-                Log.e(TAG, "Error occurred while reading the proc state: " + e);
+                Log.e(TAG, "Error occurred while informing the validation result: " + e);
             }
             AsyncTask.execute(() -> {
                 try {
                     observer.onNetworkStateChecked(
+                            INetworkStateObserver.RESULT_SUCCESS_NETWORK_STATE_CHECKED,
                             MyBroadcastReceiver.checkNetworkStatus(context));
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error occurred while notifying the observer: " + e);
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
index 286cc2f..9fdb9c9 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
@@ -18,6 +18,7 @@
 import static com.android.cts.net.hostside.app2.Common.ACTION_FINISH_ACTIVITY;
 import static com.android.cts.net.hostside.app2.Common.TAG;
 import static com.android.cts.net.hostside.app2.Common.TEST_PKG;
+import static com.android.cts.net.hostside.app2.Common.TYPE_COMPONENT_ACTIVTY;
 
 import android.app.Activity;
 import android.content.BroadcastReceiver;
@@ -42,7 +43,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         Log.d(TAG, "MyActivity.onCreate()");
-        Common.notifyNetworkStateObserver(this, getIntent());
+        Common.notifyNetworkStateObserver(this, getIntent(), TYPE_COMPONENT_ACTIVTY);
         finishCommandReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
index ff4ba65..b55761c 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
@@ -17,6 +17,7 @@
 
 import static com.android.cts.net.hostside.app2.Common.TAG;
 import static com.android.cts.net.hostside.app2.Common.TEST_PKG;
+import static com.android.cts.net.hostside.app2.Common.TYPE_COMPONENT_FOREGROUND_SERVICE;
 
 import android.R;
 import android.app.Notification;
@@ -58,7 +59,7 @@
                 startForeground(42, new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
                         .setSmallIcon(R.drawable.ic_dialog_alert) // any icon is fine
                         .build());
-                Common.notifyNetworkStateObserver(this, intent);
+                Common.notifyNetworkStateObserver(this, intent, TYPE_COMPONENT_FOREGROUND_SERVICE);
                 break;
             case FLAG_STOP_FOREGROUND:
                 Log.d(TAG, "Stopping foreground");
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyJobService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyJobService.java
index fd4bd32..51c3157 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyJobService.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyJobService.java
@@ -17,6 +17,7 @@
 
 import static com.android.cts.net.hostside.app2.Common.ACTION_FINISH_JOB;
 import static com.android.cts.net.hostside.app2.Common.TAG;
+import static com.android.cts.net.hostside.app2.Common.TYPE_COMPONENT_EXPEDITED_JOB;
 
 import android.app.job.JobParameters;
 import android.app.job.JobService;
@@ -39,7 +40,8 @@
     @Override
     public boolean onStartJob(JobParameters params) {
         Log.v(TAG, "MyJobService.onStartJob()");
-        Common.notifyNetworkStateObserver(this, params.getTransientExtras());
+        Common.notifyNetworkStateObserver(this, params.getTransientExtras(),
+                TYPE_COMPONENT_EXPEDITED_JOB);
         mFinishCommandReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {