Fix connection manager bugs related to work profiles

When calling TelecomManager.addNewIncomingCall with an account
that's was not registered we would crash. Fix was to check
for a null phone account.

Various TelecomManager APIs would throw security exceptions when
called from a work profile. Fix was to:
  - switch to using APIs that allowed the user to be specified.
    For example, using queryIntentServicesAsUse instead of
    getServiceInfo
  - don't look for work profiles if the calling user isn't the
    owner.

The default connection manager (set using a config.xml overlay)
didn't work with work profiles. Fix was to allow the default
connection manager to resolve against the calling process's
user handle.

BUG: 19300886, 19301690, 19301359
Change-Id: I49d75b69dcfc829b74a5483d7a011f17d8d06838
diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java
index eec1427..31114df 100644
--- a/src/com/android/server/telecom/CreateConnectionProcessor.java
+++ b/src/com/android/server/telecom/CreateConnectionProcessor.java
@@ -267,6 +267,10 @@
         // Connection managers are only allowed to manage SIM subscriptions.
         PhoneAccount targetPhoneAccount = mPhoneAccountRegistrar.getPhoneAccount(
                 targetPhoneAccountHandle);
+        if (targetPhoneAccount == null) {
+            Log.d(this, "shouldSetConnectionManager, phone account not found");
+            return false;
+        }
         boolean isSimSubscription = (targetPhoneAccount.getCapabilities() &
                 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) != 0;
         if (!isSimSubscription) {
@@ -326,7 +330,8 @@
             if (mShouldUseConnectionManager && callManagerHandle != null) {
                 PhoneAccount callManager = mPhoneAccountRegistrar
                         .getPhoneAccount(callManagerHandle);
-                if (callManager.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)) {
+                if (callManager != null && callManager.hasCapabilities(
+                        PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)) {
                     CallAttemptRecord callAttemptRecord = new CallAttemptRecord(callManagerHandle,
                             mPhoneAccountRegistrar.
                                     getDefaultOutgoingPhoneAccount(mCall.getHandle().getScheme())
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index bd6e2d2..759a31d 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -27,6 +27,7 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -65,6 +66,7 @@
 import java.lang.SecurityException;
 import java.lang.String;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
@@ -298,8 +300,16 @@
                 mContext.getResources().getString(R.string.default_connection_manager_component);
         if (!TextUtils.isEmpty(defaultConnectionMgr)) {
             ComponentName componentName = ComponentName.unflattenFromString(defaultConnectionMgr);
+            if (componentName == null) {
+                return null;
+            }
+
             // Make sure that the component can be resolved.
             List<ResolveInfo> resolveInfos = resolveComponent(componentName, null);
+            if (resolveInfos.isEmpty()) {
+                resolveInfos = resolveComponent(componentName, Binder.getCallingUserHandle());
+            }
+
             if (!resolveInfos.isEmpty()) {
                 // See if there is registered PhoneAccount by this component.
                 List<PhoneAccountHandle> handles = getAllPhoneAccountHandles();
@@ -381,16 +391,23 @@
             return true;
         }
 
+        if (phoneAccountUserHandle.equals(Binder.getCallingUserHandle())) {
+            return true;
+        }
+
         // Unlike in TelecomServiceImpl, we only care about *profiles* here. We want to make sure
         // that we don't resolve PhoneAccount across *users*, but resolving across *profiles* is
         // fine.
-        List<UserInfo> profileUsers = mUserManager.getProfiles(mCurrentUserHandle.getIdentifier());
-
-        for (UserInfo profileInfo : profileUsers) {
-            if (profileInfo.getUserHandle().equals(phoneAccountUserHandle)) {
-                return true;
+        if (UserHandle.getCallingUserId() == UserHandle.USER_OWNER) {
+            List<UserInfo> profileUsers =
+                    mUserManager.getProfiles(mCurrentUserHandle.getIdentifier());
+            for (UserInfo profileInfo : profileUsers) {
+                if (profileInfo.getUserHandle().equals(phoneAccountUserHandle)) {
+                    return true;
+                }
             }
         }
+
         return false;
     }
 
@@ -404,10 +421,15 @@
         PackageManager pm = mContext.getPackageManager();
         Intent intent = new Intent(ConnectionService.SERVICE_INTERFACE);
         intent.setComponent(componentName);
-        if (userHandle != null) {
-            return pm.queryIntentServicesAsUser(intent, 0, userHandle.getIdentifier());
-        } else {
-            return pm.queryIntentServices(intent, 0);
+        try {
+            if (userHandle != null) {
+                return pm.queryIntentServicesAsUser(intent, 0, userHandle.getIdentifier());
+            } else {
+                return pm.queryIntentServices(intent, 0);
+            }
+        } catch (SecurityException e) {
+            Log.v(this, "%s is not visible for the calling user", componentName);
+            return Collections.EMPTY_LIST;
         }
     }
 
@@ -614,17 +636,19 @@
      * @return {@code True} if the phone account has permission.
      */
     public boolean phoneAccountHasPermission(PhoneAccountHandle phoneAccountHandle) {
-        PackageManager packageManager = mContext.getPackageManager();
-        try {
-            ServiceInfo serviceInfo = packageManager.getServiceInfo(
-                    phoneAccountHandle.getComponentName(), 0);
-
-            return serviceInfo.permission != null &&
-                    serviceInfo.permission.equals(Manifest.permission.BIND_CONNECTION_SERVICE);
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(this, "Name not found %s", e);
+        List<ResolveInfo> resolveInfos = resolveComponent(phoneAccountHandle);
+        if (resolveInfos.isEmpty()) {
+            Log.w(this, "phoneAccount %s not found", phoneAccountHandle.getComponentName());
             return false;
         }
+        for (ResolveInfo resolveInfo : resolveInfos) {
+            ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+            if (serviceInfo == null || !Objects.equals(serviceInfo.permission,
+                    Manifest.permission.BIND_CONNECTION_SERVICE)) {
+                return false;
+            }
+        }
+        return true;
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index e9df1a7..c52c525 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -747,10 +747,12 @@
             return false;
         }
 
+        if (phoneAccountUserHandle.equals(Binder.getCallingUserHandle())) {
+            return true;
+        }
+
         List<UserHandle> profileUserHandles;
-        if (isCallerSystemApp()) {
-            // If the caller lives in /system/priv-app, it can see PhoneAccounts for all of the
-            // *profiles* that the calling user owns, but not for any other *users*.
+        if (UserHandle.getCallingUserId() == UserHandle.USER_OWNER) {
             profileUserHandles = mUserManager.getUserProfiles();
         } else {
             // Otherwise, it has to be owned by the current caller's profile.