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 =