Check both permission and AppOp in pollForPermission

FuseDaemon legcay test polls for permission to be  granted/revoked.
Previously, we checked only permission state, a delay in permission
state change update can make poll return before the permission state
has actually changed. Now we check both permission and AppOp to ensure
test starts only after the expected permission is granted/revoked.

Test: atest FuseDaemonHostTest
Bug: 149132662
Bug: 149468946
Change-Id: Id7679e89e8acd384301bcbfe7b574cbb4e3111cb
diff --git a/tests/jni/FuseDaemonTest/legacy/src/com/android/tests/fused/legacy/LegacyFileAccessTest.java b/tests/jni/FuseDaemonTest/legacy/src/com/android/tests/fused/legacy/LegacyFileAccessTest.java
index 1b09f5e..2f897de 100644
--- a/tests/jni/FuseDaemonTest/legacy/src/com/android/tests/fused/legacy/LegacyFileAccessTest.java
+++ b/tests/jni/FuseDaemonTest/legacy/src/com/android/tests/fused/legacy/LegacyFileAccessTest.java
@@ -18,12 +18,13 @@
 
 import static com.android.tests.fused.lib.TestUtils.pollForExternalStorageState;
 
+import static com.android.tests.fused.lib.TestUtils.pollForPermission;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.fail;
 
 import android.Manifest;
-import android.content.pm.PackageManager;
 import android.os.Environment;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -56,9 +57,6 @@
 
     private static final String TAG = "LegacyFileAccessTest";
 
-    private static final long POLLING_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(10);
-    private static final long POLLING_SLEEP_MILLIS = 100;
-
     @Before
     public void setUp() throws Exception {
         pollForExternalStorageState();
@@ -396,20 +394,4 @@
         assertThat(oldPath.exists()).isFalse();
         assertThat(newPath.exists()).isTrue();
     }
-
-    private boolean isPermissionGranted(String perm) {
-        return InstrumentationRegistry.getContext().checkCallingOrSelfPermission(perm)
-                == PackageManager.PERMISSION_GRANTED;
-    }
-
-    private void pollForPermission(String perm, boolean granted) throws Exception {
-        for (int i = 0; i < POLLING_TIMEOUT_MILLIS / POLLING_SLEEP_MILLIS; i++) {
-            if (granted == isPermissionGranted(perm)) {
-                return;
-            }
-            Thread.sleep(POLLING_SLEEP_MILLIS);
-        }
-        fail("Timed out while waiting for permission " + perm + " to be "
-                + (granted ? "granted" : "revoked"));
-    }
 }
diff --git a/tests/jni/FuseDaemonTest/libs/FuseDaemonTestLib/src/com/android/tests/fused/lib/TestUtils.java b/tests/jni/FuseDaemonTest/libs/FuseDaemonTestLib/src/com/android/tests/fused/lib/TestUtils.java
index e564915..d451ece 100644
--- a/tests/jni/FuseDaemonTest/libs/FuseDaemonTestLib/src/com/android/tests/fused/lib/TestUtils.java
+++ b/tests/jni/FuseDaemonTest/libs/FuseDaemonTestLib/src/com/android/tests/fused/lib/TestUtils.java
@@ -36,11 +36,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.provider.MediaStore;
+import android.system.Os;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -76,7 +78,6 @@
     private static final long POLLING_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(10);
     private static final long POLLING_SLEEP_MILLIS = 100;
 
-
     private static final UiAutomation sUiAutomation = InstrumentationRegistry.getInstrumentation()
             .getUiAutomation();
 
@@ -396,6 +397,43 @@
         fail("Timed out while waiting for ExternalStorageState to be MEDIA_MOUNTED");
     }
 
+    public static void pollForPermission(String perm, boolean granted) throws Exception {
+        for (int i = 0; i < POLLING_TIMEOUT_MILLIS / POLLING_SLEEP_MILLIS; i++) {
+            if (granted == checkPermissionAndAppOp(perm)) {
+                return;
+            }
+            Thread.sleep(POLLING_SLEEP_MILLIS);
+        }
+        fail("Timed out while waiting for permission " + perm + " to be "
+                + (granted ? "granted" : "revoked"));
+    }
+
+    /**
+     * Checks if the given {@code permission} is granted and corresponding AppOp is MODE_ALLOWED.
+     */
+    private static boolean checkPermissionAndAppOp(String permission) {
+        final int pid  = Os.getpid();
+        final int uid = Os.getuid();
+        final Context context = getContext();
+        final String packageName = context.getPackageName();
+        if (context.checkPermission(permission, pid, uid) != PackageManager.PERMISSION_GRANTED) {
+            return false;
+        }
+
+        final String op = AppOpsManager.permissionToOp(permission);
+        // No AppOp associated with the given permission, skip AppOp check.
+        if (op == null) return true;
+
+        final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
+        try {
+            appOps.checkPackage(uid, packageName);
+        } catch (SecurityException e) {
+            return false;
+        }
+
+        return appOps.unsafeCheckOpNoThrow(op, uid, packageName) == AppOpsManager.MODE_ALLOWED;
+    }
+
     /**
      * <p>This method drops shell permission identity.
      */