Create UidState for SdkSandbox uids related to app.

To allow AppOps from sandbox each sandbox process uid
must have UidState.

Test: AppOpsServiceTest
Bug: 281676778
Change-Id: I667880728a634d13ea0d0db410e7abc970e690d3
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 3446737..7780b39 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1180,6 +1180,8 @@
                                     uidState.pkgOps.put(packageName,
                                             new Ops(packageName, uidState));
                                 }
+
+                                createSandboxUidStateIfNotExistsForAppLocked(uid);
                             }
                         }
                     }
@@ -1261,6 +1263,8 @@
                 ops.put(code, new Op(uidState, packageName, code, uid));
             }
         }
+
+        createSandboxUidStateIfNotExistsForAppLocked(uid);
     }
 
     /**
@@ -4011,6 +4015,11 @@
         return uidState;
     }
 
+    private void createSandboxUidStateIfNotExistsForAppLocked(int uid) {
+        final int sandboxUid = Process.toSdkSandboxUid(uid);
+        getUidStateLocked(sandboxUid, true);
+    }
+
     private void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible) {
         synchronized (this) {
             getUidStateTracker().updateAppWidgetVisibility(uidPackageNames, visible);
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 646f486..79b39b8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -20,7 +20,9 @@
 import static android.app.AppOpsManager.OP_COARSE_LOCATION;
 import static android.app.AppOpsManager.OP_FLAGS_ALL;
 import static android.app.AppOpsManager.OP_FLAG_SELF;
+import static android.app.AppOpsManager.OP_READ_DEVICE_IDENTIFIERS;
 import static android.app.AppOpsManager.OP_READ_SMS;
+import static android.app.AppOpsManager.OP_TAKE_AUDIO_FOCUS;
 import static android.app.AppOpsManager.OP_WIFI_SCAN;
 import static android.app.AppOpsManager.OP_WRITE_SMS;
 import static android.os.UserHandle.getAppId;
@@ -49,8 +51,10 @@
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.OpEntry;
 import android.app.AppOpsManager.PackageOps;
+import android.app.SyncNotedAppOp;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -58,6 +62,7 @@
 import android.permission.PermissionManager;
 import android.provider.Settings;
 import android.util.ArrayMap;
+import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -79,7 +84,6 @@
 import org.mockito.quality.Strictness;
 
 import java.io.File;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -99,12 +103,15 @@
 
     private static final Context sContext = InstrumentationRegistry.getTargetContext();
     private static final String sMyPackageName = sContext.getOpPackageName();
+    private static final String sSdkSandboxPackageName = sContext.getPackageManager()
+            .getSdkSandboxPackageName();
 
     private File mStorageFile;
     private File mRecentAccessesFile;
     private Handler mHandler;
     private AppOpsService mAppOpsService;
     private int mMyUid;
+    private int mSdkSandboxPackageUid;
     private long mTestStartMillis;
     private StaticMockitoSession mMockingSession;
 
@@ -132,6 +139,7 @@
         handlerThread.start();
         mHandler = new Handler(handlerThread.getLooper());
         mMyUid = Process.myUid();
+        mSdkSandboxPackageUid = resolveSdkSandboxPackageUid();
 
         initializeStaticMocks();
 
@@ -152,6 +160,39 @@
         mMockingSession.finishMocking();
     }
 
+    private static int resolveSdkSandboxPackageUid() {
+        try {
+            return sContext.getPackageManager().getPackageUid(
+                    sSdkSandboxPackageName,
+                    PackageManager.PackageInfoFlags.of(0)
+            );
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, "Can't resolve sandbox package uid", e);
+            return Process.INVALID_UID;
+        }
+    }
+
+    private static void mockGetPackage(
+            PackageManagerInternal managerMock,
+            String packageName
+    ) {
+        AndroidPackage packageMock = mock(AndroidPackage.class);
+        when(managerMock.getPackage(packageName)).thenReturn(packageMock);
+    }
+
+    private static void mockGetPackageStateInternal(
+            PackageManagerInternal managerMock,
+            String packageName,
+            int uid
+    ) {
+        PackageStateInternal packageStateInternalMock = mock(PackageStateInternal.class);
+        when(packageStateInternalMock.isPrivileged()).thenReturn(false);
+        when(packageStateInternalMock.getAppId()).thenReturn(uid);
+        when(packageStateInternalMock.getAndroidPackage()).thenReturn(mock(AndroidPackage.class));
+        when(managerMock.getPackageStateInternal(packageName))
+                .thenReturn(packageStateInternalMock);
+    }
+
     private void initializeStaticMocks() {
         mMockingSession = mockitoSession()
                 .strictness(Strictness.LENIENT)
@@ -163,16 +204,11 @@
         // Mock LocalServices.getService(PackageManagerInternal.class).getPackageStateInternal
         // and getPackage dependency needed by AppOpsService
         PackageManagerInternal mockPackageManagerInternal = mock(PackageManagerInternal.class);
-        AndroidPackage mockMyPkg = mock(AndroidPackage.class);
-        when(mockMyPkg.getAttributions()).thenReturn(Collections.emptyList());
-        PackageStateInternal mockMyPSInternal = mock(PackageStateInternal.class);
-        when(mockMyPSInternal.isPrivileged()).thenReturn(false);
-        when(mockMyPSInternal.getAppId()).thenReturn(mMyUid);
-        when(mockMyPSInternal.getAndroidPackage()).thenReturn(mockMyPkg);
-
-        when(mockPackageManagerInternal.getPackageStateInternal(sMyPackageName))
-                .thenReturn(mockMyPSInternal);
-        when(mockPackageManagerInternal.getPackage(sMyPackageName)).thenReturn(mockMyPkg);
+        mockGetPackage(mockPackageManagerInternal, sMyPackageName);
+        mockGetPackageStateInternal(mockPackageManagerInternal, sMyPackageName, mMyUid);
+        mockGetPackage(mockPackageManagerInternal, sSdkSandboxPackageName);
+        mockGetPackageStateInternal(mockPackageManagerInternal, sSdkSandboxPackageName,
+                mSdkSandboxPackageUid);
         when(mockPackageManagerInternal.getPackageUid(eq(sMyPackageName), anyLong(),
                 eq(getUserId(mMyUid)))).thenReturn(mMyUid);
         doReturn(mockPackageManagerInternal).when(
@@ -233,6 +269,21 @@
         assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
     }
 
+    @Test
+    public void testNoteOperationFromSdkSandbox() {
+        int sandboxUid = Process.toSdkSandboxUid(mMyUid);
+
+        // Note an op that's allowed.
+        SyncNotedAppOp allowedResult = mAppOpsService.noteOperation(OP_TAKE_AUDIO_FOCUS, sandboxUid,
+                sSdkSandboxPackageName, null, false, null, false);
+        assertThat(allowedResult.getOpMode()).isEqualTo(MODE_ALLOWED);
+
+        // Note another op that's not allowed.
+        SyncNotedAppOp erroredResult = mAppOpsService.noteOperation(OP_READ_DEVICE_IDENTIFIERS,
+                sandboxUid, sSdkSandboxPackageName, null, false, null, false);
+        assertThat(erroredResult.getOpMode()).isEqualTo(MODE_ERRORED);
+    }
+
     /**
      * Tests the scenario where an operation's permission is controlled by another operation.
      * For example the results of a WIFI_SCAN can be used to infer the location of a user, so the