diff options
author | Sailesh Nepal <sail@google.com> | 2015-02-14 15:44:55 -0800 |
---|---|---|
committer | Etan Cohen <etancohen@google.com> | 2015-03-02 11:31:23 -0800 |
commit | 91fc8099a0690a3367eb206788c9c25ceff31875 (patch) | |
tree | 628c5215b3a8dc06ed6dd077747ef42f5ce67d78 /src/com | |
parent | 78a5e6b9c1595c81f72d7a822617cb78db224e48 (diff) | |
download | android_packages_services_Telecomm-91fc8099a0690a3367eb206788c9c25ceff31875.tar.gz android_packages_services_Telecomm-91fc8099a0690a3367eb206788c9c25ceff31875.tar.bz2 android_packages_services_Telecomm-91fc8099a0690a3367eb206788c9c25ceff31875.zip |
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
Diffstat (limited to 'src/com')
3 files changed, 53 insertions, 22 deletions
diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java index eec14277..31114dfd 100644 --- a/src/com/android/server/telecom/CreateConnectionProcessor.java +++ b/src/com/android/server/telecom/CreateConnectionProcessor.java @@ -267,6 +267,10 @@ final class CreateConnectionProcessor { // 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 @@ final class CreateConnectionProcessor { 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 bd6e2d2b..759a31dc 100644 --- a/src/com/android/server/telecom/PhoneAccountRegistrar.java +++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java @@ -27,6 +27,7 @@ import android.content.pm.UserInfo; 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.Integer; 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 @@ public final class PhoneAccountRegistrar { 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 @@ public final class PhoneAccountRegistrar { 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 @@ public final class PhoneAccountRegistrar { 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 @@ public final class PhoneAccountRegistrar { * @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 e9df1a7a..c52c5251 100644 --- a/src/com/android/server/telecom/TelecomServiceImpl.java +++ b/src/com/android/server/telecom/TelecomServiceImpl.java @@ -747,10 +747,12 @@ public class TelecomServiceImpl { 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. |