1 /* 2 * Copyright (C) 2018 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 android.telephony.ims.stub; 18 19 import android.annotation.SystemApi; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.RemoteCallbackList; 23 import android.os.RemoteException; 24 import android.telephony.ims.aidl.IImsConfig; 25 import android.telephony.ims.aidl.IImsConfigCallback; 26 import android.util.Log; 27 28 import com.android.ims.ImsConfig; 29 import com.android.internal.annotations.VisibleForTesting; 30 31 import java.lang.ref.WeakReference; 32 import java.util.HashMap; 33 34 /** 35 * Controls the modification of IMS specific configurations. For more information on the supported 36 * IMS configuration constants, see {@link ImsConfig}. 37 * 38 * The inner class {@link ImsConfigStub} implements methods of IImsConfig AIDL interface. 39 * The IImsConfig AIDL interface is called by ImsConfig, which may exist in many other processes. 40 * ImsConfigImpl access to the configuration parameters may be arbitrarily slow, especially in 41 * during initialization, or times when a lot of configuration parameters are being set/get 42 * (such as during boot up or SIM card change). By providing a cache in ImsConfigStub, we can speed 43 * up access to these configuration parameters, so a query to the ImsConfigImpl does not have to be 44 * performed every time. 45 * @hide 46 */ 47 @SystemApi 48 public class ImsConfigImplBase { 49 50 private static final String TAG = "ImsConfigImplBase"; 51 52 /** 53 * Implements the IImsConfig AIDL interface, which is called by potentially many processes 54 * in order to get/set configuration parameters. 55 * 56 * It holds an object of ImsConfigImplBase class which is usually extended by ImsConfigImpl 57 * with actual implementations from vendors. This class caches provisioned values from 58 * ImsConfigImpl layer because queries through ImsConfigImpl can be slow. When query goes in, 59 * it first checks cache layer. If missed, it will call the vendor implementation of 60 * ImsConfigImplBase API. 61 * and cache the return value if the set succeeds. 62 * 63 * Provides APIs to get/set the IMS service feature/capability/parameters. 64 * The config items include: 65 * 1) Items provisioned by the operator. 66 * 2) Items configured by user. Mainly service feature class. 67 * 68 * @hide 69 */ 70 @VisibleForTesting 71 static public class ImsConfigStub extends IImsConfig.Stub { 72 WeakReference<ImsConfigImplBase> mImsConfigImplBaseWeakReference; 73 private HashMap<Integer, Integer> mProvisionedIntValue = new HashMap<>(); 74 private HashMap<Integer, String> mProvisionedStringValue = new HashMap<>(); 75 76 @VisibleForTesting 77 public ImsConfigStub(ImsConfigImplBase imsConfigImplBase) { 78 mImsConfigImplBaseWeakReference = 79 new WeakReference<ImsConfigImplBase>(imsConfigImplBase); 80 } 81 82 @Override 83 public void addImsConfigCallback(IImsConfigCallback c) throws RemoteException { 84 getImsConfigImpl().addImsConfigCallback(c); 85 } 86 87 @Override 88 public void removeImsConfigCallback(IImsConfigCallback c) throws RemoteException { 89 getImsConfigImpl().removeImsConfigCallback(c); 90 } 91 92 /** 93 * Gets the value for ims service/capabilities parameters. It first checks its local cache, 94 * if missed, it will call ImsConfigImplBase.getConfigInt. 95 * Synchronous blocking call. 96 * 97 * @param item integer key 98 * @return value in Integer format or {@link #CONFIG_RESULT_UNKNOWN} if 99 * unavailable. 100 */ 101 @Override 102 public synchronized int getConfigInt(int item) throws RemoteException { 103 if (mProvisionedIntValue.containsKey(item)) { 104 return mProvisionedIntValue.get(item); 105 } else { 106 int retVal = getImsConfigImpl().getConfigInt(item); 107 if (retVal != ImsConfig.OperationStatusConstants.UNKNOWN) { 108 updateCachedValue(item, retVal, false); 109 } 110 return retVal; 111 } 112 } 113 114 /** 115 * Gets the value for ims service/capabilities parameters. It first checks its local cache, 116 * if missed, it will call #ImsConfigImplBase.getConfigString. 117 * Synchronous blocking call. 118 * 119 * @param item integer key 120 * @return value in String format. 121 */ 122 @Override 123 public synchronized String getConfigString(int item) throws RemoteException { 124 if (mProvisionedIntValue.containsKey(item)) { 125 return mProvisionedStringValue.get(item); 126 } else { 127 String retVal = getImsConfigImpl().getConfigString(item); 128 if (retVal != null) { 129 updateCachedValue(item, retVal, false); 130 } 131 return retVal; 132 } 133 } 134 135 /** 136 * Sets the value for IMS service/capabilities parameters by the operator device 137 * management entity. It sets the config item value in the provisioned storage 138 * from which the master value is derived, and write it into local cache. 139 * Synchronous blocking call. 140 * 141 * @param item integer key 142 * @param value in Integer format. 143 * @return the result of setting the configuration value, defined as either 144 * {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}. 145 */ 146 @Override 147 public synchronized int setConfigInt(int item, int value) throws RemoteException { 148 mProvisionedIntValue.remove(item); 149 int retVal = getImsConfigImpl().setConfig(item, value); 150 if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) { 151 updateCachedValue(item, value, true); 152 } else { 153 Log.d(TAG, "Set provision value of " + item + 154 " to " + value + " failed with error code " + retVal); 155 } 156 157 return retVal; 158 } 159 160 /** 161 * Sets the value for IMS service/capabilities parameters by the operator device 162 * management entity. It sets the config item value in the provisioned storage 163 * from which the master value is derived, and write it into local cache. 164 * Synchronous blocking call. 165 * 166 * @param item as defined in com.android.ims.ImsConfig#ConfigConstants. 167 * @param value in String format. 168 * @return the result of setting the configuration value, defined as either 169 * {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}. 170 */ 171 @Override 172 public synchronized int setConfigString(int item, String value) 173 throws RemoteException { 174 mProvisionedStringValue.remove(item); 175 int retVal = getImsConfigImpl().setConfig(item, value); 176 if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) { 177 updateCachedValue(item, value, true); 178 } 179 180 return retVal; 181 } 182 183 private ImsConfigImplBase getImsConfigImpl() throws RemoteException { 184 ImsConfigImplBase ref = mImsConfigImplBaseWeakReference.get(); 185 if (ref == null) { 186 throw new RemoteException("Fail to get ImsConfigImpl"); 187 } else { 188 return ref; 189 } 190 } 191 192 private void notifyImsConfigChanged(int item, int value) throws RemoteException { 193 getImsConfigImpl().notifyConfigChanged(item, value); 194 } 195 196 private void notifyImsConfigChanged(int item, String value) throws RemoteException { 197 getImsConfigImpl().notifyConfigChanged(item, value); 198 } 199 200 protected synchronized void updateCachedValue(int item, int value, boolean notifyChange) 201 throws RemoteException { 202 mProvisionedIntValue.put(item, value); 203 if (notifyChange) { 204 notifyImsConfigChanged(item, value); 205 } 206 } 207 208 protected synchronized void updateCachedValue(int item, String value, 209 boolean notifyChange) throws RemoteException { 210 mProvisionedStringValue.put(item, value); 211 if (notifyChange) { 212 notifyImsConfigChanged(item, value); 213 } 214 } 215 } 216 217 /** 218 * Callback that the framework uses for receiving Configuration change updates. 219 * {@hide} 220 */ 221 public static class Callback extends IImsConfigCallback.Stub { 222 223 @Override 224 public final void onIntConfigChanged(int item, int value) throws RemoteException { 225 onConfigChanged(item, value); 226 } 227 228 @Override 229 public final void onStringConfigChanged(int item, String value) throws RemoteException { 230 onConfigChanged(item, value); 231 } 232 233 /** 234 * Called when the IMS configuration has changed. 235 * @param item the IMS configuration key constant, as defined in ImsConfig. 236 * @param value the new integer value of the IMS configuration constant. 237 */ 238 public void onConfigChanged(int item, int value) { 239 // Base Implementation 240 } 241 242 /** 243 * Called when the IMS configuration has changed. 244 * @param item the IMS configuration key constant, as defined in ImsConfig. 245 * @param value the new String value of the IMS configuration constant. 246 */ 247 public void onConfigChanged(int item, String value) { 248 // Base Implementation 249 } 250 } 251 252 /** 253 * The configuration requested resulted in an unknown result. This may happen if the 254 * IMS configurations are unavailable. 255 */ 256 public static final int CONFIG_RESULT_UNKNOWN = -1; 257 /** 258 * Setting the configuration value completed. 259 */ 260 public static final int CONFIG_RESULT_SUCCESS = 0; 261 /** 262 * Setting the configuration value failed. 263 */ 264 public static final int CONFIG_RESULT_FAILED = 1; 265 266 private final RemoteCallbackList<IImsConfigCallback> mCallbacks = new RemoteCallbackList<>(); 267 ImsConfigStub mImsConfigStub; 268 269 /** 270 * Used for compatibility between older versions of the ImsService. 271 * @hide 272 */ 273 public ImsConfigImplBase(Context context) { 274 mImsConfigStub = new ImsConfigStub(this); 275 } 276 277 public ImsConfigImplBase() { 278 mImsConfigStub = new ImsConfigStub(this); 279 } 280 281 /** 282 * Adds a {@link Callback} to the list of callbacks notified when a value in the configuration 283 * changes. 284 * @param c callback to add. 285 */ 286 private void addImsConfigCallback(IImsConfigCallback c) { 287 mCallbacks.register(c); 288 } 289 /** 290 * Removes a {@link Callback} to the list of callbacks notified when a value in the 291 * configuration changes. 292 * 293 * @param c callback to remove. 294 */ 295 private void removeImsConfigCallback(IImsConfigCallback c) { 296 mCallbacks.unregister(c); 297 } 298 299 /** 300 * @param item 301 * @param value 302 */ 303 private final void notifyConfigChanged(int item, int value) { 304 // can be null in testing 305 if (mCallbacks == null) { 306 return; 307 } 308 mCallbacks.broadcast(c -> { 309 try { 310 c.onIntConfigChanged(item, value); 311 } catch (RemoteException e) { 312 Log.w(TAG, "notifyConfigChanged(int): dead binder in notify, skipping."); 313 } 314 }); 315 } 316 317 private void notifyConfigChanged(int item, String value) { 318 // can be null in testing 319 if (mCallbacks == null) { 320 return; 321 } 322 mCallbacks.broadcast(c -> { 323 try { 324 c.onStringConfigChanged(item, value); 325 } catch (RemoteException e) { 326 Log.w(TAG, "notifyConfigChanged(string): dead binder in notify, skipping."); 327 } 328 }); 329 } 330 331 /** 332 * @hide 333 */ 334 public IImsConfig getIImsConfig() { return mImsConfigStub; } 335 336 /** 337 * Updates provisioning value and notifies the framework of the change. 338 * Doesn't call {@link #setConfig(int,int)} and assumes the result succeeded. 339 * This should only be used when the IMS implementer implicitly changed provisioned values. 340 * 341 * @param item an integer key. 342 * @param value in Integer format. 343 */ 344 public final void notifyProvisionedValueChanged(int item, int value) { 345 try { 346 mImsConfigStub.updateCachedValue(item, value, true); 347 } catch (RemoteException e) { 348 Log.w(TAG, "notifyProvisionedValueChanged(int): Framework connection is dead."); 349 } 350 } 351 352 /** 353 * Updates provisioning value and notifies the framework of the change. 354 * Doesn't call {@link #setConfig(int,String)} and assumes the result succeeded. 355 * This should only be used when the IMS implementer implicitly changed provisioned values. 356 * 357 * @param item an integer key. 358 * @param value in String format. 359 */ 360 public final void notifyProvisionedValueChanged(int item, String value) { 361 try { 362 mImsConfigStub.updateCachedValue(item, value, true); 363 } catch (RemoteException e) { 364 Log.w(TAG, "notifyProvisionedValueChanged(string): Framework connection is dead."); 365 } 366 } 367 368 /** 369 * Sets the configuration value for this ImsService. 370 * 371 * @param item an integer key. 372 * @param value an integer containing the configuration value. 373 * @return the result of setting the configuration value, defined as either 374 * {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}. 375 */ 376 public int setConfig(int item, int value) { 377 // Base Implementation - To be overridden. 378 return CONFIG_RESULT_FAILED; 379 } 380 381 /** 382 * Sets the configuration value for this ImsService. 383 * 384 * @param item an integer key. 385 * @param value a String containing the new configuration value. 386 * @return Result of setting the configuration value, defined as either 387 * {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}. 388 */ 389 public int setConfig(int item, String value) { 390 // Base Implementation - To be overridden. 391 return CONFIG_RESULT_FAILED; 392 } 393 394 /** 395 * Gets the currently stored value configuration value from the ImsService for {@code item}. 396 * 397 * @param item an integer key. 398 * @return configuration value, stored in integer format or {@link #CONFIG_RESULT_UNKNOWN} if 399 * unavailable. 400 */ 401 public int getConfigInt(int item) { 402 // Base Implementation - To be overridden. 403 return CONFIG_RESULT_UNKNOWN; 404 } 405 406 /** 407 * Gets the currently stored value configuration value from the ImsService for {@code item}. 408 * 409 * @param item an integer key. 410 * @return configuration value, stored in String format or {@code null} if unavailable. 411 */ 412 public String getConfigString(int item) { 413 // Base Implementation - To be overridden. 414 return null; 415 } 416 } 417