Protect TelecomManager#getPhoneAccount with necessary permission.

Apps targeting API version 31+ should have READ_PHONE_NUMBERS to call
method getPhoneAccount.

Bug: 183407956
Test: UnitTest, CTS test
Change-Id: I60c37687d8ee0b04129f0393a19e0fd4961990e5
(cherry picked from commit 11a19742d03d766567f281dcf31e4efa5b4d636b)
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 9a683ad..6fb2897 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -317,9 +317,21 @@
         }
 
         @Override
-        public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle) {
+        public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle,
+                String callingPackage) {
             synchronized (mLock) {
                 final UserHandle callingUserHandle = Binder.getCallingUserHandle();
+                if (CompatChanges.isChangeEnabled(
+                        TelecomManager.ENABLE_GET_PHONE_ACCOUNT_PERMISSION_PROTECTION,
+                        callingPackage, Binder.getCallingUserHandle())) {
+                    if (Binder.getCallingUid() != Process.SHELL_UID &&
+                            !canGetPhoneAccount(callingPackage, accountHandle)) {
+                        SecurityException e = new SecurityException("getPhoneAccount API requires" +
+                                "READ_PHONE_NUMBERS");
+                        Log.e(this, e, "getPhoneAccount %s", accountHandle);
+                        throw e;
+                    }
+                }
                 long token = Binder.clearCallingIdentity();
                 try {
                     Log.startSession("TSI.gPA");
@@ -329,7 +341,7 @@
                     // profile's phone account handle.
                     return mPhoneAccountRegistrar
                             .getPhoneAccount(accountHandle, callingUserHandle,
-                            /* acrossProfiles */ true);
+                                    /* acrossProfiles */ true);
                 } catch (Exception e) {
                     Log.e(this, e, "getPhoneAccount %s", accountHandle);
                     throw e;
@@ -2422,6 +2434,28 @@
                 == AppOpsManager.MODE_ALLOWED;
     }
 
+    private boolean canGetPhoneAccount(String callingPackage, PhoneAccountHandle accountHandle) {
+        // Allow default dialer, system dialer and sim call manager to be able to do this without
+        // extra permission
+        try {
+            if (isPrivilegedDialerCalling(callingPackage) || isCallerSimCallManager(
+                    accountHandle)) {
+                return true;
+            }
+        } catch (SecurityException e) {
+            // ignore
+        }
+
+        try {
+            mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, null);
+            return true;
+        } catch (SecurityException e) {
+            // Accessing phone state is gated by a special permission.
+            mContext.enforceCallingOrSelfPermission(READ_PHONE_NUMBERS, null);
+            return true;
+        }
+    }
+
     private boolean isCallerSimCallManager(PhoneAccountHandle targetPhoneAccount) {
         long token = Binder.clearCallingIdentity();
         PhoneAccountHandle accountHandle = null;
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index caaf4d6..60d38af 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -39,6 +39,10 @@
     <!-- Used to access Projection State APIs -->
     <uses-permission android:name="android.permission.READ_PROJECTION_STATE"/>
 
+    <!-- Used to access PlatformCompat APIs -->
+    <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+    <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+
     <application android:label="@string/app_name"
                  android:debuggable="true">
         <uses-library android:name="android.test.runner" />
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index fa8ab10..3cec50b 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -460,10 +460,10 @@
     @Test
     public void testGetPhoneAccount() throws RemoteException {
         makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17);
-        assertEquals(TEL_PA_HANDLE_16, mTSIBinder.getPhoneAccount(TEL_PA_HANDLE_16)
-                .getAccountHandle());
-        assertEquals(SIP_PA_HANDLE_17, mTSIBinder.getPhoneAccount(SIP_PA_HANDLE_17)
-                .getAccountHandle());
+        assertEquals(TEL_PA_HANDLE_16, mTSIBinder.getPhoneAccount(TEL_PA_HANDLE_16,
+                mContext.getPackageName()).getAccountHandle());
+        assertEquals(SIP_PA_HANDLE_17, mTSIBinder.getPhoneAccount(SIP_PA_HANDLE_17,
+                mContext.getPackageName()).getAccountHandle());
     }
 
     @SmallTest