Resolve cross account user icon validation.

Resolves a vulnerability found with the cross account user icon
validation in StatusHint and TelecomServiceImpl (when registering a
phone account). The reporter found that an uri formatted as `userId%`
isn't parsed properly with the existing reference to Uri.encodedUserInfo.

Bug: 376461551
Bug: 376259166
Flag: EXEMPT bugfix
Test: atest TelecomServiceImplTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:089dc975fc9dce402ec8c6c84e76fa100c9adcf5)
Merged-In: I7a5f64ae01eaf6a133ea04c51bd00dbe1653b74f
Change-Id: I7a5f64ae01eaf6a133ea04c51bd00dbe1653b74f
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 37e9d33..df174c2 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -55,6 +55,7 @@
 import android.telecom.Log;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telecom.StatusHints;
 import android.telecom.TelecomAnalytics;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
@@ -2764,15 +2765,13 @@
         // incompatible types.
         if (icon != null && (icon.getType() == Icon.TYPE_URI
                 || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) {
-            String encodedUser = icon.getUri().getEncodedUserInfo();
-            // If there is no encoded user, the URI is calling into the calling user space
-            if (encodedUser != null) {
-                int userId = Integer.parseInt(encodedUser);
-                if (userId != UserHandle.getUserId(Binder.getCallingUid())) {
-                    // If we are transcending the profile boundary, throw an error.
-                    throw new IllegalArgumentException("Attempting to register a phone account with"
-                            + " an image icon belonging to another user.");
-                }
+            int callingUserId = UserHandle.getCallingUserId();
+            int requestingUserId = StatusHints.getUserIdFromAuthority(
+                    icon.getUri().getAuthority(), callingUserId);
+            if(callingUserId != requestingUserId) {
+                // If we are transcending the profile boundary, throw an error.
+                throw new IllegalArgumentException("Attempting to register a phone account with"
+                        + " an image icon belonging to another user.");
             }
         }
     }
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index 572c975..f539bd0 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -632,6 +632,20 @@
         // This should fail; security exception will be thrown.
         registerPhoneAccountTestHelper(phoneAccount, false);
 
+        icon = Icon.createWithContentUri(
+                new Uri.Builder().scheme("content")
+                        .encodedAuthority("10%40media")
+                        .path("external/images/media/${mediaId.text}".trim())
+                        .build());
+        phoneAccount = makePhoneAccount(phHandle).setIcon(icon).build();
+        // This should fail; security exception will be thrown
+        registerPhoneAccountTestHelper(phoneAccount, false);
+
+        icon = Icon.createWithContentUri( Uri.parse("content://10%40play.ground"));
+        phoneAccount = makePhoneAccount(phHandle).setIcon(icon).build();
+        // This should fail; security exception will be thrown
+        registerPhoneAccountTestHelper(phoneAccount, false);
+
         icon = Icon.createWithContentUri("content://0@media/external/images/media/");
         phoneAccount = makePhoneAccount(phHandle).setIcon(icon).build();
         // This should succeed.