Example system service test under Ravenwood.

This change demonstrates a moderately complex test of a specific
system service, in this case `UriGrantsManagerService`.

Bug: 292141694
Test: atest FrameworksServicesTestsRavenwood FrameworksServicesTests
Change-Id: Ia16632f2c9a1e24deb9c1320fdbb1c099e3d74c3
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index c86ccfd..c7a75ed 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -117,6 +117,7 @@
  * developer guide.</p>
  * </div>
  */
+@android.ravenwood.annotation.RavenwoodKeepPartialClass
 public abstract class ContentProvider implements ContentInterface, ComponentCallbacks2 {
 
     private static final String TAG = "ContentProvider";
@@ -2781,6 +2782,7 @@
     }
 
     /** @hide */
+    @android.ravenwood.annotation.RavenwoodKeep
     private Uri maybeGetUriWithoutUserId(Uri uri) {
         if (mSingleUser) {
             return uri;
@@ -2789,6 +2791,7 @@
     }
 
     /** @hide */
+    @android.ravenwood.annotation.RavenwoodKeep
     public static int getUserIdFromAuthority(String auth, int defaultUserId) {
         if (auth == null) return defaultUserId;
         int end = auth.lastIndexOf('@');
@@ -2803,17 +2806,20 @@
     }
 
     /** @hide */
+    @android.ravenwood.annotation.RavenwoodKeep
     public static int getUserIdFromAuthority(String auth) {
         return getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
     }
 
     /** @hide */
+    @android.ravenwood.annotation.RavenwoodKeep
     public static int getUserIdFromUri(Uri uri, int defaultUserId) {
         if (uri == null) return defaultUserId;
         return getUserIdFromAuthority(uri.getAuthority(), defaultUserId);
     }
 
     /** @hide */
+    @android.ravenwood.annotation.RavenwoodKeep
     public static int getUserIdFromUri(Uri uri) {
         return getUserIdFromUri(uri, UserHandle.USER_CURRENT);
     }
@@ -2824,6 +2830,7 @@
      * @hide
      */
     @TestApi
+    @android.ravenwood.annotation.RavenwoodKeep
     public @NonNull static UserHandle getUserHandleFromUri(@NonNull Uri uri) {
         return UserHandle.of(getUserIdFromUri(uri, Process.myUserHandle().getIdentifier()));
     }
@@ -2834,6 +2841,7 @@
      * If there is no userId in the authority, it symply returns the argument
      * @hide
      */
+    @android.ravenwood.annotation.RavenwoodKeep
     public static String getAuthorityWithoutUserId(String auth) {
         if (auth == null) return null;
         int end = auth.lastIndexOf('@');
@@ -2841,6 +2849,7 @@
     }
 
     /** @hide */
+    @android.ravenwood.annotation.RavenwoodKeep
     public static Uri getUriWithoutUserId(Uri uri) {
         if (uri == null) return null;
         Uri.Builder builder = uri.buildUpon();
@@ -2849,6 +2858,7 @@
     }
 
     /** @hide */
+    @android.ravenwood.annotation.RavenwoodKeep
     public static boolean uriHasUserId(Uri uri) {
         if (uri == null) return false;
         return !TextUtils.isEmpty(uri.getUserInfo());
@@ -2872,6 +2882,7 @@
      */
     @NonNull
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @android.ravenwood.annotation.RavenwoodKeep
     public static Uri createContentUriForUser(
             @NonNull Uri contentUri, @NonNull UserHandle userHandle) {
         if (!ContentResolver.SCHEME_CONTENT.equals(contentUri.getScheme())) {
@@ -2898,6 +2909,7 @@
 
     /** @hide */
     @UnsupportedAppUsage
+    @android.ravenwood.annotation.RavenwoodKeep
     public static Uri maybeAddUserId(Uri uri, int userId) {
         if (uri == null) return null;
         if (userId != UserHandle.USER_CURRENT
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index 831fce1..e3f1932 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -88,6 +88,8 @@
 android.graphics.Rect
 android.graphics.RectF
 
+android.content.ContentProvider
+
 com.android.server.LocalServices
 
 com.android.internal.os.SomeArgs
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 7862f58..e501b9d 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -146,17 +146,31 @@
             mGrantedUriPermissions = new SparseArray<>();
 
     private UriGrantsManagerService() {
-        this(SystemServiceManager.ensureSystemDir());
+        this(SystemServiceManager.ensureSystemDir(), "uri-grants");
     }
 
-    private UriGrantsManagerService(File systemDir) {
+    private UriGrantsManagerService(File systemDir, String commitTag) {
         mH = new H(IoThread.get().getLooper());
-        mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"), "uri-grants");
+        final File file = new File(systemDir, "urigrants.xml");
+        mGrantFile = (commitTag != null) ? new AtomicFile(file, commitTag) : new AtomicFile(file);
     }
 
     @VisibleForTesting
     static UriGrantsManagerService createForTest(File systemDir) {
-        final UriGrantsManagerService service = new UriGrantsManagerService(systemDir);
+        final UriGrantsManagerService service = new UriGrantsManagerService(systemDir, null) {
+            @VisibleForTesting
+            protected int checkUidPermission(String permission, int uid) {
+                // Tests have no permission granted
+                return PackageManager.PERMISSION_DENIED;
+            }
+
+            @VisibleForTesting
+            protected int checkComponentPermission(String permission, int uid, int owningUid,
+                    boolean exported) {
+                // Tests have no permission granted
+                return PackageManager.PERMISSION_DENIED;
+            }
+        };
         service.mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
         service.mPmInternal = LocalServices.getService(PackageManagerInternal.class);
         return service;
@@ -202,7 +216,8 @@
         }
     }
 
-    private int checkUidPermission(String permission, int uid) {
+    @VisibleForTesting
+    protected int checkUidPermission(String permission, int uid) {
         try {
             return AppGlobals.getPackageManager().checkUidPermission(permission, uid);
         } catch (RemoteException e) {
@@ -210,6 +225,12 @@
         }
     }
 
+    @VisibleForTesting
+    protected int checkComponentPermission(String permission, int uid, int owningUid,
+            boolean exported) {
+        return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported);
+    }
+
     /**
      * Grant uri permissions to the specified app.
      *
@@ -916,7 +937,7 @@
             ProviderInfo pi, GrantUri grantUri, int uid, final int modeFlags) {
         if (DEBUG) Slog.v(TAG, "checkHoldingPermissions: uri=" + grantUri + " uid=" + uid);
         if (UserHandle.getUserId(uid) != grantUri.sourceUserId) {
-            if (ActivityManager.checkComponentPermission(INTERACT_ACROSS_USERS, uid, -1, true)
+            if (checkComponentPermission(INTERACT_ACROSS_USERS, uid, -1, true)
                     != PERMISSION_GRANTED) {
                 return false;
             }
@@ -1340,7 +1361,7 @@
         if (uid == Process.SYSTEM_UID || uid == Process.ROOT_UID) {
             return true;
         }
-        return ActivityManager.checkComponentPermission(
+        return checkComponentPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                     uid, /* owningUid = */-1, /* exported = */ true)
                     == PackageManager.PERMISSION_GRANTED;
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 2ece8c7..9b84190 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -79,6 +79,7 @@
         "coretests-aidl",
         "securebox",
         "flag-junit",
+        "ravenwood-junit",
     ],
 
     libs: [
@@ -140,6 +141,23 @@
     resource_zips: [":FrameworksServicesTests_apks_as_resources"],
 }
 
+android_ravenwood_test {
+    name: "FrameworksServicesTestsRavenwood",
+    libs: [
+        "android.test.mock",
+    ],
+    static_libs: [
+        "androidx.annotation_annotation",
+        "androidx.test.rules",
+        "mockito_ravenwood",
+        "services.core",
+    ],
+    srcs: [
+        "src/com/android/server/uri/**/*.java",
+    ],
+    auto_gen_config: true,
+}
+
 java_library {
     name: "servicestests-core-utils",
     srcs: [
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
index e418d2f..769ec5f 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
@@ -57,17 +57,22 @@
 import android.net.Uri;
 import android.os.Process;
 import android.os.UserHandle;
+import android.platform.test.ravenwood.RavenwoodRule;
 import android.util.ArraySet;
 
 import androidx.test.InstrumentationRegistry;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.util.Arrays;
 import java.util.Set;
 
 public class UriGrantsManagerServiceTest {
+    @Rule
+    public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
     private UriGrantsMockContext mContext;
     private UriGrantsManagerInternal mService;
 
@@ -79,7 +84,7 @@
 
     @Before
     public void setUp() throws Exception {
-        mContext = new UriGrantsMockContext(InstrumentationRegistry.getContext());
+        mContext = new UriGrantsMockContext();
         mService = UriGrantsManagerService.createForTest(mContext.getFilesDir()).getLocalService();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
index 7eb6c97..4c11de09 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
@@ -21,11 +21,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import android.annotation.NonNull;
 import android.app.ActivityManagerInternal;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -33,18 +29,19 @@
 import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
 import android.net.Uri;
-import android.os.FileUtils;
 import android.os.PatternMatcher;
 import android.os.Process;
 import android.os.UserHandle;
-import android.test.mock.MockContentResolver;
+import android.test.mock.MockContext;
 import android.test.mock.MockPackageManager;
 
 import com.android.server.LocalServices;
 
 import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
 
-public class UriGrantsMockContext extends ContextWrapper {
+public class UriGrantsMockContext extends MockContext {
     static final String TAG = "UriGrants";
 
     static final int FLAG_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION;
@@ -98,19 +95,14 @@
     private final File mDir;
 
     private final MockPackageManager mPackage;
-    private final MockContentResolver mResolver;
 
     final ActivityManagerInternal mAmInternal;
     final PackageManagerInternal mPmInternal;
 
-    public UriGrantsMockContext(@NonNull Context base) {
-        super(base);
-        mDir = new File(base.getFilesDir(), TAG);
-        mDir.mkdirs();
-        FileUtils.deleteContents(mDir);
+    public UriGrantsMockContext() throws IOException {
+        mDir = Files.createTempDirectory(TAG).toFile();
 
         mPackage = new MockPackageManager();
-        mResolver = new MockContentResolver(this);
 
         mAmInternal = mock(ActivityManagerInternal.class);
         LocalServices.removeServiceForTest(ActivityManagerInternal.class);
@@ -239,11 +231,6 @@
     }
 
     @Override
-    public ContentResolver getContentResolver() {
-        return mResolver;
-    }
-
-    @Override
     public File getFilesDir() {
         return mDir;
     }
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriPermissionTest.java b/services/tests/servicestests/src/com/android/server/uri/UriPermissionTest.java
index 07005a9..4d4f5ed 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriPermissionTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriPermissionTest.java
@@ -35,12 +35,18 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import android.platform.test.ravenwood.RavenwoodRule;
+
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 public class UriPermissionTest {
+    @Rule
+    public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
     @Mock
     private UriGrantsManagerInternal mService;