1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.phone; 18 19 import android.content.Context; 20 import android.net.Uri; 21 import android.os.Binder; 22 import android.os.RemoteException; 23 import android.os.ServiceManager; 24 import android.os.ServiceSpecificException; 25 import android.telephony.SubscriptionManager; 26 import android.telephony.ims.ImsException; 27 import android.telephony.ims.RegistrationManager; 28 import android.telephony.ims.aidl.IImsCapabilityCallback; 29 import android.telephony.ims.aidl.IImsRcsController; 30 import android.telephony.ims.aidl.IImsRegistrationCallback; 31 import android.telephony.ims.aidl.IRcsUceControllerCallback; 32 import android.telephony.ims.aidl.IRcsUcePublishStateCallback; 33 import android.telephony.ims.feature.RcsFeature; 34 import android.telephony.ims.stub.ImsRegistrationImplBase; 35 import android.util.Log; 36 37 import com.android.ims.ImsManager; 38 import com.android.internal.telephony.IIntegerConsumer; 39 import com.android.internal.telephony.Phone; 40 import com.android.internal.telephony.TelephonyPermissions; 41 import com.android.internal.telephony.imsphone.ImsPhone; 42 import com.android.services.telephony.rcs.RcsFeatureController; 43 import com.android.services.telephony.rcs.TelephonyRcsService; 44 import com.android.services.telephony.rcs.UserCapabilityExchangeImpl; 45 46 import java.util.List; 47 48 /** 49 * Implementation of the IImsRcsController interface. 50 */ 51 public class ImsRcsController extends IImsRcsController.Stub { 52 private static final String TAG = "ImsRcsController"; 53 54 /** The singleton instance. */ 55 private static ImsRcsController sInstance; 56 57 private PhoneGlobals mApp; 58 private TelephonyRcsService mRcsService; 59 60 /** 61 * Initialize the singleton ImsRcsController instance. 62 * This is only done once, at startup, from PhoneApp.onCreate(). 63 */ init(PhoneGlobals app)64 static ImsRcsController init(PhoneGlobals app) { 65 synchronized (ImsRcsController.class) { 66 if (sInstance == null) { 67 sInstance = new ImsRcsController(app); 68 } else { 69 Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance); 70 } 71 return sInstance; 72 } 73 } 74 75 /** Private constructor; @see init() */ ImsRcsController(PhoneGlobals app)76 private ImsRcsController(PhoneGlobals app) { 77 Log.i(TAG, "ImsRcsController"); 78 mApp = app; 79 ServiceManager.addService(Context.TELEPHONY_IMS_SERVICE, this); 80 } 81 82 /** 83 * Register a {@link RegistrationManager.RegistrationCallback} to receive IMS network 84 * registration state. 85 */ 86 @Override registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback)87 public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback) { 88 enforceReadPrivilegedPermission("registerImsRegistrationCallback"); 89 final long token = Binder.clearCallingIdentity(); 90 try { 91 getRcsFeatureController(subId).registerImsRegistrationCallback(subId, callback); 92 } catch (ImsException e) { 93 Log.e(TAG, "registerImsRegistrationCallback: sudId=" + subId + ", " + e.getMessage()); 94 throw new ServiceSpecificException(e.getCode()); 95 } finally { 96 Binder.restoreCallingIdentity(token); 97 } 98 } 99 100 /** 101 * Removes an existing {@link RegistrationManager.RegistrationCallback}. 102 */ 103 @Override unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback)104 public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback) { 105 enforceReadPrivilegedPermission("unregisterImsRegistrationCallback"); 106 final long token = Binder.clearCallingIdentity(); 107 try { 108 getRcsFeatureController(subId).unregisterImsRegistrationCallback(subId, callback); 109 } catch (ServiceSpecificException e) { 110 Log.e(TAG, "unregisterImsRegistrationCallback: error=" + e.errorCode); 111 } finally { 112 Binder.restoreCallingIdentity(token); 113 } 114 } 115 116 /** 117 * Get the IMS service registration state for the RcsFeature associated with this sub id. 118 */ 119 @Override getImsRcsRegistrationState(int subId, IIntegerConsumer consumer)120 public void getImsRcsRegistrationState(int subId, IIntegerConsumer consumer) { 121 enforceReadPrivilegedPermission("getImsRcsRegistrationState"); 122 final long token = Binder.clearCallingIdentity(); 123 try { 124 getRcsFeatureController(subId).getRegistrationState(regState -> { 125 try { 126 consumer.accept((regState == null) 127 ? RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED : regState); 128 } catch (RemoteException e) { 129 Log.w(TAG, "getImsRcsRegistrationState: callback is not available."); 130 } 131 }); 132 } finally { 133 Binder.restoreCallingIdentity(token); 134 } 135 } 136 137 /** 138 * Gets the Transport Type associated with the current IMS RCS registration. 139 */ 140 @Override getImsRcsRegistrationTransportType(int subId, IIntegerConsumer consumer)141 public void getImsRcsRegistrationTransportType(int subId, IIntegerConsumer consumer) { 142 enforceReadPrivilegedPermission("getImsRcsRegistrationTransportType"); 143 final long token = Binder.clearCallingIdentity(); 144 try { 145 getRcsFeatureController(subId).getRegistrationTech(regTech -> { 146 // Convert registration tech from ImsRegistrationImplBase -> RegistrationManager 147 int regTechConverted = (regTech == null) 148 ? ImsRegistrationImplBase.REGISTRATION_TECH_NONE : regTech; 149 regTechConverted = RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get( 150 regTechConverted); 151 try { 152 consumer.accept(regTechConverted); 153 } catch (RemoteException e) { 154 Log.w(TAG, "getImsRcsRegistrationTransportType: callback is not available."); 155 } 156 }); 157 } finally { 158 Binder.restoreCallingIdentity(token); 159 } 160 } 161 162 /** 163 * Register a capability callback which will provide RCS availability updates for the 164 * subscription specified. 165 * 166 * @param subId the subscription ID 167 * @param callback The ImsCapabilityCallback to be registered. 168 */ 169 @Override registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback)170 public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) { 171 enforceReadPrivilegedPermission("registerRcsAvailabilityCallback"); 172 final long token = Binder.clearCallingIdentity(); 173 try { 174 getRcsFeatureController(subId).registerRcsAvailabilityCallback(subId, callback); 175 } catch (ImsException e) { 176 Log.e(TAG, "registerRcsAvailabilityCallback: sudId=" + subId + ", " + e.getMessage()); 177 throw new ServiceSpecificException(e.getCode()); 178 } finally { 179 Binder.restoreCallingIdentity(token); 180 } 181 } 182 183 /** 184 * Remove the registered capability callback. 185 * 186 * @param subId the subscription ID 187 * @param callback The ImsCapabilityCallback to be removed. 188 */ 189 @Override unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback)190 public void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) { 191 enforceReadPrivilegedPermission("unregisterRcsAvailabilityCallback"); 192 final long token = Binder.clearCallingIdentity(); 193 try { 194 getRcsFeatureController(subId).unregisterRcsAvailabilityCallback(subId, callback); 195 } finally { 196 Binder.restoreCallingIdentity(token); 197 } 198 } 199 200 @Override registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c)201 public void registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) { 202 enforceReadPrivilegedPermission("registerUcePublishStateCallback"); 203 final long token = Binder.clearCallingIdentity(); 204 try { 205 UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature( 206 UserCapabilityExchangeImpl.class); 207 if (uce == null) { 208 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, 209 "This subscription does not support UCE."); 210 } 211 uce.registerPublishStateCallback(c); 212 } finally { 213 Binder.restoreCallingIdentity(token); 214 } 215 } 216 217 @Override unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c)218 public void unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) { 219 enforceReadPrivilegedPermission("unregisterUcePublishStateCallback"); 220 final long token = Binder.clearCallingIdentity(); 221 try { 222 UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature( 223 UserCapabilityExchangeImpl.class); 224 if (uce == null) { 225 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, 226 "This subscription does not support UCE."); 227 } 228 uce.unregisterUcePublishStateCallback(c); 229 } finally { 230 Binder.restoreCallingIdentity(token); 231 } 232 } 233 234 /** 235 * Query for the capability of an IMS RCS service 236 * 237 * @param subId the subscription ID 238 * @param capability the RCS capability to query. 239 * @param radioTech the radio tech that this capability failed for 240 * @return true if the RCS capability is capable for this subscription, false otherwise. 241 */ 242 @Override isCapable(int subId, @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)243 public boolean isCapable(int subId, 244 @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability, 245 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) { 246 enforceReadPrivilegedPermission("isCapable"); 247 final long token = Binder.clearCallingIdentity(); 248 try { 249 return getRcsFeatureController(subId).isCapable(capability, radioTech); 250 } catch (ImsException e) { 251 Log.e(TAG, "isCapable: sudId=" + subId 252 + ", capability=" + capability + ", " + e.getMessage()); 253 return false; 254 } finally { 255 Binder.restoreCallingIdentity(token); 256 } 257 } 258 259 /** 260 * Query the availability of an IMS RCS capability. 261 * 262 * @param subId the subscription ID 263 * @param capability the RCS capability to query. 264 * @return true if the RCS capability is currently available for the associated subscription, 265 * false otherwise. 266 */ 267 @Override isAvailable(int subId, @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability)268 public boolean isAvailable(int subId, 269 @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) { 270 enforceReadPrivilegedPermission("isAvailable"); 271 final long token = Binder.clearCallingIdentity(); 272 try { 273 return getRcsFeatureController(subId).isAvailable(capability); 274 } catch (ImsException e) { 275 Log.e(TAG, "isAvailable: sudId=" + subId 276 + ", capability=" + capability + ", " + e.getMessage()); 277 return false; 278 } finally { 279 Binder.restoreCallingIdentity(token); 280 } 281 } 282 283 @Override requestCapabilities(int subId, String callingPackage, String callingFeatureId, List<Uri> contactNumbers, IRcsUceControllerCallback c)284 public void requestCapabilities(int subId, String callingPackage, String callingFeatureId, 285 List<Uri> contactNumbers, IRcsUceControllerCallback c) { 286 enforceReadPrivilegedPermission("requestCapabilities"); 287 if (!isUceSettingEnabled(subId, callingPackage, callingFeatureId)) { 288 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, 289 "The user has not enabled UCE for this subscription."); 290 } 291 final long token = Binder.clearCallingIdentity(); 292 try { 293 UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature( 294 UserCapabilityExchangeImpl.class); 295 if (uce == null) { 296 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, 297 "This subscription does not support UCE."); 298 } 299 uce.requestCapabilities(contactNumbers, c); 300 } finally { 301 Binder.restoreCallingIdentity(token); 302 } 303 } 304 305 @Override getUcePublishState(int subId)306 public int getUcePublishState(int subId) { 307 enforceReadPrivilegedPermission("getUcePublishState"); 308 final long token = Binder.clearCallingIdentity(); 309 try { 310 UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature( 311 UserCapabilityExchangeImpl.class); 312 if (uce == null) { 313 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, 314 "This subscription does not support UCE."); 315 } 316 return uce.getUcePublishState(); 317 } finally { 318 Binder.restoreCallingIdentity(token); 319 } 320 } 321 322 @Override isUceSettingEnabled(int subId, String callingPackage, String callingFeatureId)323 public boolean isUceSettingEnabled(int subId, String callingPackage, String callingFeatureId) { 324 if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState( 325 mApp, subId, callingPackage, callingFeatureId, "isUceSettingEnabled")) { 326 Log.w(TAG, "isUceSettingEnabled: READ_PHONE_STATE app op disabled when accessing " 327 + "isUceSettingEnabled"); 328 return false; 329 } 330 final long token = Binder.clearCallingIdentity(); 331 try { 332 return SubscriptionManager.getBooleanSubscriptionProperty(subId, 333 SubscriptionManager.IMS_RCS_UCE_ENABLED, false /*defaultValue*/, mApp); 334 } finally { 335 Binder.restoreCallingIdentity(token); 336 } 337 } 338 339 @Override setUceSettingEnabled(int subId, boolean isEnabled)340 public void setUceSettingEnabled(int subId, boolean isEnabled) { 341 enforceModifyPermission(); 342 final long token = Binder.clearCallingIdentity(); 343 try { 344 SubscriptionManager.setSubscriptionProperty(subId, 345 SubscriptionManager.IMS_RCS_UCE_ENABLED, (isEnabled ? "1" : "0")); 346 } finally { 347 Binder.restoreCallingIdentity(token); 348 } 349 } 350 351 /** 352 * Make sure either called from same process as self (phone) or IPC caller has read privilege. 353 * 354 * @throws SecurityException if the caller does not have the required permission 355 */ enforceReadPrivilegedPermission(String message)356 private void enforceReadPrivilegedPermission(String message) { 357 mApp.enforceCallingOrSelfPermission( 358 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message); 359 } 360 361 /** 362 * Make sure the caller has the MODIFY_PHONE_STATE permission. 363 * 364 * @throws SecurityException if the caller does not have the required permission 365 */ enforceModifyPermission()366 private void enforceModifyPermission() { 367 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null); 368 } 369 370 /** 371 * Retrieve ImsPhone instance. 372 * 373 * @param subId the subscription ID 374 * @return The ImsPhone instance 375 * @throws ServiceSpecificException if getting ImsPhone instance failed. 376 */ getImsPhone(int subId)377 private ImsPhone getImsPhone(int subId) { 378 if (!ImsManager.isImsSupportedOnDevice(mApp)) { 379 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, 380 "IMS is not available on device."); 381 } 382 Phone phone = PhoneGlobals.getPhone(subId); 383 if (phone == null) { 384 throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION, 385 "Invalid subscription Id: " + subId); 386 } 387 ImsPhone imsPhone = (ImsPhone) phone.getImsPhone(); 388 if (imsPhone == null) { 389 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE, 390 "Cannot find ImsPhone instance: " + subId); 391 } 392 return imsPhone; 393 } 394 395 /** 396 * Retrieve RcsFeatureManager instance. 397 * 398 * @param subId the subscription ID 399 * @return The RcsFeatureManager instance 400 * @throws ServiceSpecificException if getting RcsFeatureManager instance failed. 401 */ getRcsFeatureController(int subId)402 private RcsFeatureController getRcsFeatureController(int subId) { 403 if (!ImsManager.isImsSupportedOnDevice(mApp)) { 404 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, 405 "IMS is not available on device."); 406 } 407 if (mRcsService == null) { 408 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, 409 "IMS is not available on device."); 410 } 411 Phone phone = PhoneGlobals.getPhone(subId); 412 if (phone == null) { 413 throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION, 414 "Invalid subscription Id: " + subId); 415 } 416 int slotId = phone.getPhoneId(); 417 RcsFeatureController c = mRcsService.getFeatureController(slotId); 418 if (c == null) { 419 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, 420 "The requested operation is not supported for subId " + subId); 421 } 422 return c; 423 } 424 setRcsService(TelephonyRcsService rcsService)425 void setRcsService(TelephonyRcsService rcsService) { 426 mRcsService = rcsService; 427 } 428 } 429