Home | History | Annotate | Download | only in stub
      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