Added check that callback for showUserSwitchDialog can only be added by CarSysUI

Bug: 154958003
Test: atest CarServiceUnitTest:com.android.car.user.CarUserServiceTest
Change-Id: I2a3296b708b4c1ff019755bc9d360c887d7cbc59
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index fc3d3a4..81922dc 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -40,7 +40,10 @@
 import android.car.userlib.HalCallback;
 import android.car.userlib.UserHalHelper;
 import android.car.userlib.UserHelper;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -296,6 +299,7 @@
         writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
         writer.printf("Request Id for the user switch in process=%d\n ",
                     mRequestIdForUserSwitchInProcess);
+        writer.printf("System UI package name=%s\n", getSystemUiPackageName());
 
         dumpUserMetrics(writer);
     }
@@ -1067,11 +1071,44 @@
      */
     @Override
     public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
-        // TODO(b/154958003): check UID, only carSysUI should be allowed to set it.
         checkManageUsersPermission("setUserSwitchUiCallback");
+
+        // Confirm that caller is system UI.
+        String systemUiPackageName = getSystemUiPackageName();
+        if (systemUiPackageName == null) {
+            throw new IllegalStateException("System UI package not found.");
+        }
+
+        try {
+            int systemUiUid = mContext
+                    .createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0).getPackageManager()
+                    .getPackageUid(systemUiPackageName, PackageManager.MATCH_SYSTEM_ONLY);
+            int callerUid = Binder.getCallingUid();
+            if (systemUiUid != callerUid) {
+                throw new SecurityException("Invalid caller. Only" + systemUiPackageName
+                        + " is allowed to make this call");
+            }
+        } catch (NameNotFoundException e) {
+            throw new IllegalStateException("Package " + systemUiPackageName + " not found.");
+        }
+
         mUserSwitchUiReceiver = receiver;
     }
 
+    // TODO(157082995): This information can be taken from
+    // PackageManageInternalImpl.getSystemUiServiceComponent
+    @Nullable
+    private String getSystemUiPackageName() {
+        try {
+            ComponentName componentName = ComponentName.unflattenFromString(mContext.getResources()
+                    .getString(com.android.internal.R.string.config_systemUIServiceComponent));
+            return componentName.getPackageName();
+        } catch (RuntimeException e) {
+            Log.w(TAG_USER, "error while getting system UI package name.", e);
+            return null;
+        }
+    }
+
     // TODO(b/150413515): use helper to generate UsersInfo
     private UsersInfo getUsersInfo() {
         UserInfo currentUser;
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
index 560d5c6..5a51ac7 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
@@ -70,6 +70,7 @@
 import android.car.userlib.UserHalHelper;
 import android.car.userlib.UserHelper;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
@@ -85,6 +86,7 @@
 import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
 import android.hardware.automotive.vehicle.V2_0.UsersInfo;
 import android.location.LocationManager;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -145,6 +147,7 @@
     @Mock private Drawable mMockedDrawable;
     @Mock private UserMetrics mUserMetrics;
     @Mock IResultReceiver mSwitchUserUiReceiver;
+    @Mock PackageManager mPackageManager;
 
     private final BlockingUserLifecycleListener mUserLifecycleListener =
             BlockingUserLifecycleListener.newDefaultListener();
@@ -979,6 +982,8 @@
     @Test
     public void testSetSwitchUserUI_receiverSetAndCalled() throws Exception {
         mockExistingUsersAndCurrentUser(mAdminUser);
+        int callerId = Binder.getCallingUid();
+        mockCallerUid(callerId, true);
         int requestId = 42;
         mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
         mSwitchUserResponse.requestId = requestId;
@@ -993,6 +998,15 @@
     }
 
     @Test
+    public void testSetSwitchUserUI_nonCarSysUiCaller() throws Exception {
+        int callerId = Binder.getCallingUid();
+        mockCallerUid(callerId, false);
+
+        assertThrows(SecurityException.class,
+                () -> mCarUserService.setUserSwitchUiCallback(mSwitchUserUiReceiver));
+    }
+
+    @Test
     public void testSwitchUser_OEMRequest_success() throws Exception {
         mockExistingUsersAndCurrentUser(mAdminUser);
         mockAmSwitchUser(mRegularUser, true);
@@ -1394,6 +1408,20 @@
         mockHalSwitch(currentUserId, HalCallback.STATUS_OK, response, androidTargetUser);
     }
 
+    private void mockCallerUid(int uid, boolean returnCorrectUid) throws Exception {
+        String packageName = "packageName";
+        String className = "className";
+        when(mMockedResources.getString(anyInt())).thenReturn(packageName + "/" + className);
+        when(mMockContext.createContextAsUser(any(), anyInt())).thenReturn(mMockContext);
+        when(mMockContext.getPackageManager()).thenReturn(mPackageManager);
+
+        if (returnCorrectUid) {
+            when(mPackageManager.getPackageUid(any(), anyInt())).thenReturn(uid);
+        } else {
+            when(mPackageManager.getPackageUid(any(), anyInt())).thenReturn(uid + 1);
+        }
+    }
+
     private BlockingAnswer<Void> mockHalSwitchLateResponse(@UserIdInt int currentUserId,
             @NonNull UserInfo androidTargetUser, @Nullable SwitchUserResponse response) {
         android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =