• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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 static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PROVISIONING_XML;
20 import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__DMA_CHANGED;
21 import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__TRIGGER_RCS_RECONFIGURATION;
22 
23 import android.Manifest;
24 import android.annotation.NonNull;
25 import android.app.role.OnRoleHoldersChangedListener;
26 import android.app.role.RoleManager;
27 import android.content.BroadcastReceiver;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.content.pm.PackageManager;
32 import android.os.Build;
33 import android.os.Handler;
34 import android.os.HandlerThread;
35 import android.os.Looper;
36 import android.os.Message;
37 import android.os.PersistableBundle;
38 import android.os.RemoteException;
39 import android.os.UserHandle;
40 import android.telephony.CarrierConfigManager;
41 import android.telephony.SubscriptionManager;
42 import android.telephony.TelephonyRegistryManager;
43 import android.telephony.ims.ProvisioningManager;
44 import android.telephony.ims.RcsConfig;
45 import android.telephony.ims.aidl.IImsConfig;
46 import android.telephony.ims.aidl.IRcsConfigCallback;
47 import android.text.TextUtils;
48 import android.util.ArraySet;
49 import android.util.SparseArray;
50 
51 import com.android.ims.FeatureConnector;
52 import com.android.ims.FeatureUpdates;
53 import com.android.ims.RcsFeatureManager;
54 import com.android.internal.annotations.VisibleForTesting;
55 import com.android.internal.telephony.flags.FeatureFlags;
56 import com.android.internal.telephony.metrics.RcsStats;
57 import com.android.internal.telephony.metrics.RcsStats.RcsProvisioningCallback;
58 import com.android.internal.telephony.util.HandlerExecutor;
59 import com.android.internal.util.CollectionUtils;
60 import com.android.telephony.Rlog;
61 
62 import java.util.Arrays;
63 import java.util.HashMap;
64 import java.util.Iterator;
65 import java.util.List;
66 import java.util.concurrent.ConcurrentHashMap;
67 import java.util.concurrent.Executor;
68 
69 /**
70  * Class to monitor RCS Provisioning Status
71  */
72 public class RcsProvisioningMonitor {
73     private static final String TAG = "RcsProvisioningMonitor";
74     private static final boolean DBG = Build.IS_ENG;
75 
76     private static final int EVENT_SUB_CHANGED = 1;
77     private static final int EVENT_DMA_CHANGED = 2;
78     private static final int EVENT_CC_CHANGED  = 3;
79     private static final int EVENT_CONFIG_RECEIVED = 4;
80     private static final int EVENT_RECONFIG_REQUEST = 5;
81     private static final int EVENT_DEVICE_CONFIG_OVERRIDE = 6;
82     private static final int EVENT_CARRIER_CONFIG_OVERRIDE = 7;
83     private static final int EVENT_RESET = 8;
84     private static final int EVENT_FEATURE_ENABLED_OVERRIDE = 9;
85 
86     // indicate that the carrier single registration capable is initial value as
87     // carrier config is not ready yet.
88     private static final int MASK_CAP_CARRIER_INIT = 0xF000;
89 
90     private final PhoneGlobals mPhone;
91     private final Handler mHandler;
92     // Cache the RCS provsioning info and related sub id
93     private final ConcurrentHashMap<Integer, RcsProvisioningInfo> mRcsProvisioningInfos =
94             new ConcurrentHashMap<>();
95     private Boolean mDeviceSingleRegistrationEnabledOverride;
96     private final HashMap<Integer, Boolean> mCarrierSingleRegistrationEnabledOverride =
97             new HashMap<>();
98     private final ConcurrentHashMap<Integer, Boolean> mImsFeatureValidationOverride =
99             new ConcurrentHashMap<>();
100     private String mDmaPackageName;
101     private final SparseArray<RcsFeatureListener> mRcsFeatureListeners = new SparseArray<>();
102     private volatile boolean mTestModeEnabled;
103 
104     private final CarrierConfigManager mCarrierConfigManager;
105     private final DmaChangedListener mDmaChangedListener;
106     private final SubscriptionManager mSubscriptionManager;
107     private final TelephonyRegistryManager mTelephonyRegistryManager;
108     private final RoleManagerAdapter mRoleManager;
109     private FeatureConnectorFactory<RcsFeatureManager> mFeatureFactory;
110 
111     private RcsStats mRcsStats;
112 
113     private static RcsProvisioningMonitor sInstance;
114 
115     @NonNull
116     private final FeatureFlags mFeatureFlags;
117 
118     private final SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener =
119             new SubscriptionManager.OnSubscriptionsChangedListener() {
120         @Override
121         public void onSubscriptionsChanged() {
122             if (!mHandler.hasMessages(EVENT_SUB_CHANGED)) {
123                 mHandler.sendEmptyMessage(EVENT_SUB_CHANGED);
124             }
125         }
126     };
127 
128     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
129         @Override
130         public void onReceive(Context context, Intent intent) {
131             if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(
132                     intent.getAction())) {
133                 int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
134                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
135                 logv("Carrier-config changed for sub : " + subId);
136                 if (SubscriptionManager.isValidSubscriptionId(subId)
137                         && !mHandler.hasMessages(EVENT_CC_CHANGED)) {
138                     mHandler.sendEmptyMessage(EVENT_CC_CHANGED);
139                 }
140             }
141         }
142     };
143 
144     private final class DmaChangedListener implements OnRoleHoldersChangedListener {
145         @Override
onRoleHoldersChanged(String role, UserHandle user)146         public void onRoleHoldersChanged(String role, UserHandle user) {
147             if (RoleManager.ROLE_SMS.equals(role)) {
148                 logv("default messaging application changed.");
149                 mHandler.sendEmptyMessage(EVENT_DMA_CHANGED);
150             }
151         }
152 
register()153         public void register() {
154             try {
155                 mRoleManager.addOnRoleHoldersChangedListenerAsUser(
156                         mPhone.getMainExecutor(), this, UserHandle.SYSTEM);
157             } catch (RuntimeException e) {
158                 loge("Could not register dma change listener due to " + e);
159             }
160         }
161 
unregister()162         public void unregister() {
163             try {
164                 mRoleManager.removeOnRoleHoldersChangedListenerAsUser(this, UserHandle.SYSTEM);
165             } catch (RuntimeException e) {
166                 loge("Could not unregister dma change listener due to " + e);
167             }
168         }
169     }
170 
171     private final class MyHandler extends Handler {
MyHandler(Looper looper)172         MyHandler(Looper looper) {
173             super(looper);
174         }
175 
176         @Override
handleMessage(Message msg)177         public void handleMessage(Message msg) {
178             logv("handleMessage: " + msg);
179             switch (msg.what) {
180                 case EVENT_SUB_CHANGED:
181                     onSubChanged();
182                     break;
183                 case EVENT_DMA_CHANGED:
184                     onDefaultMessagingApplicationChanged();
185                     break;
186                 case EVENT_CC_CHANGED:
187                     onCarrierConfigChange();
188                     break;
189                 case EVENT_CONFIG_RECEIVED:
190                     onConfigReceived(msg.arg1, (byte[]) msg.obj, msg.arg2 == 1);
191                     break;
192                 case EVENT_RECONFIG_REQUEST:
193                     onReconfigRequest(msg.arg1);
194                     break;
195                 case EVENT_DEVICE_CONFIG_OVERRIDE:
196                     Boolean deviceEnabled = (Boolean) msg.obj;
197                     if (!booleanEquals(deviceEnabled, mDeviceSingleRegistrationEnabledOverride)) {
198                         mDeviceSingleRegistrationEnabledOverride = deviceEnabled;
199                         onCarrierConfigChange();
200                     }
201                     break;
202                 case EVENT_CARRIER_CONFIG_OVERRIDE:
203                     Boolean carrierEnabledOverride = (Boolean) msg.obj;
204                     Boolean carrierEnabled = mCarrierSingleRegistrationEnabledOverride.put(
205                             msg.arg1, carrierEnabledOverride);
206                     if (!booleanEquals(carrierEnabledOverride, carrierEnabled)) {
207                         onCarrierConfigChange();
208                     }
209                     break;
210                 case EVENT_RESET:
211                     reset();
212                     break;
213                 default:
214                     loge("Unhandled event " + msg.what);
215             }
216         }
217     }
218 
219     private final class RcsProvisioningInfo {
220         private int mSubId;
221         private volatile int mSingleRegistrationCapability;
222         private volatile byte[] mConfig;
223         private ArraySet<IRcsConfigCallback> mRcsConfigCallbacks;
224         private IImsConfig mIImsConfig;
225         private boolean mHasReconfigRequest;
226 
RcsProvisioningInfo(int subId, int singleRegistrationCapability, byte[] config)227         RcsProvisioningInfo(int subId, int singleRegistrationCapability, byte[] config) {
228             mSubId = subId;
229             mSingleRegistrationCapability = singleRegistrationCapability;
230             mConfig = config;
231             mRcsConfigCallbacks = new ArraySet<>();
232             registerRcsFeatureListener(this);
233         }
234 
getSubId()235         int getSubId() {
236             return mSubId;
237         }
238 
setSingleRegistrationCapability(int singleRegistrationCapability)239         void setSingleRegistrationCapability(int singleRegistrationCapability) {
240             if (mSingleRegistrationCapability != singleRegistrationCapability) {
241                 mSingleRegistrationCapability = singleRegistrationCapability;
242                 notifyDma();
243 
244                 // update whether single registration supported.
245                 mRcsStats.setEnableSingleRegistration(mSubId,
246                         mSingleRegistrationCapability == ProvisioningManager.STATUS_CAPABLE);
247             }
248         }
249 
notifyDma()250         void notifyDma() {
251             // notify only if capable value has been updated when carrier config ready.
252             if ((mSingleRegistrationCapability & MASK_CAP_CARRIER_INIT) != MASK_CAP_CARRIER_INIT) {
253                 logi("notify default messaging app for sub:" + mSubId + " with capability:"
254                         + mSingleRegistrationCapability);
255                 notifyDmaForSub(mSubId, mSingleRegistrationCapability);
256             }
257         }
258 
getSingleRegistrationCapability()259         int getSingleRegistrationCapability() {
260             return mSingleRegistrationCapability;
261         }
262 
setConfig(byte[] config)263         void setConfig(byte[] config) {
264             if (!Arrays.equals(mConfig, config)) {
265                 mConfig = config;
266                 if (mConfig != null) {
267                     notifyRcsAutoConfigurationReceived();
268                 } else {
269                     notifyRcsAutoConfigurationRemoved();
270                 }
271             }
272         }
273 
getConfig()274         byte[] getConfig() {
275             return mConfig;
276         }
277 
addRcsConfigCallback(IRcsConfigCallback cb)278         boolean addRcsConfigCallback(IRcsConfigCallback cb) {
279             if (mIImsConfig == null) {
280                 logd("fail to addRcsConfigCallback as imsConfig is null");
281                 return false;
282             }
283 
284             synchronized (mRcsConfigCallbacks) {
285                 try {
286                     mIImsConfig.addRcsConfigCallback(cb);
287                 } catch (RemoteException e) {
288                     loge("fail to addRcsConfigCallback due to " + e);
289                     return false;
290                 }
291                 mRcsConfigCallbacks.add(cb);
292             }
293             return true;
294         }
295 
removeRcsConfigCallback(IRcsConfigCallback cb)296         boolean removeRcsConfigCallback(IRcsConfigCallback cb) {
297             boolean result = true;
298 
299             synchronized (mRcsConfigCallbacks) {
300                 if (mIImsConfig != null) {
301                     try {
302                         mIImsConfig.removeRcsConfigCallback(cb);
303                     } catch (RemoteException e) {
304                         loge("fail to removeRcsConfigCallback due to " + e);
305                     }
306                 } else {
307                     // Return false but continue to remove the callback
308                     result = false;
309                 }
310 
311                 try {
312                     cb.onRemoved();
313                 } catch (RemoteException e) {
314                     logd("Failed to notify onRemoved due to dead binder of " + cb);
315                 }
316                 mRcsConfigCallbacks.remove(cb);
317             }
318             return result;
319         }
320 
triggerRcsReconfiguration()321         void triggerRcsReconfiguration() {
322             if (mIImsConfig != null) {
323                 try {
324                     logv("triggerRcsReconfiguration for sub:" + mSubId);
325                     mIImsConfig.triggerRcsReconfiguration();
326                     mHasReconfigRequest = false;
327                 } catch (RemoteException e) {
328                     loge("triggerRcsReconfiguration failed due to " + e);
329                 }
330             } else {
331                 logd("triggerRcsReconfiguration failed due to IImsConfig null.");
332                 mHasReconfigRequest = true;
333             }
334         }
335 
destroy()336         void destroy() {
337             unregisterRcsFeatureListener(this);
338             clear();
339             mIImsConfig = null;
340             mRcsConfigCallbacks = null;
341         }
342 
clear()343         void clear() {
344             setConfig(null);
345             clearCallbacks();
346         }
347 
onRcsStatusChanged(IImsConfig binder)348         void onRcsStatusChanged(IImsConfig binder) {
349             logv("onRcsStatusChanged for sub:" + mSubId + ", IImsConfig?" + binder);
350             if (mIImsConfig != binder) {
351                 mIImsConfig = binder;
352                 if (mIImsConfig != null) {
353                     if (mHasReconfigRequest) {
354                         triggerRcsReconfiguration();
355                     } else {
356                         notifyRcsAutoConfigurationReceived();
357                     }
358 
359                     // check callback for metrics if not registered, register callback
360                     registerMetricsCallback();
361                 } else {
362                     // clear callbacks if rcs disconnected
363                     clearCallbacks();
364                 }
365             }
366         }
367 
notifyRcsAutoConfigurationReceived()368         private void notifyRcsAutoConfigurationReceived() {
369             if (mConfig == null) {
370                 logd("Rcs config is null for sub : " + mSubId);
371                 return;
372             }
373 
374             if (mIImsConfig != null) {
375                 try {
376                     logv("notifyRcsAutoConfigurationReceived for sub:" + mSubId);
377                     mIImsConfig.notifyRcsAutoConfigurationReceived(mConfig, false);
378                 } catch (RemoteException e) {
379                     loge("notifyRcsAutoConfigurationReceived failed due to " + e);
380                 }
381             } else {
382                 logd("notifyRcsAutoConfigurationReceived failed due to IImsConfig null.");
383             }
384         }
385 
notifyRcsAutoConfigurationRemoved()386         private void notifyRcsAutoConfigurationRemoved() {
387             if (mIImsConfig != null) {
388                 try {
389                     logv("notifyRcsAutoConfigurationRemoved for sub:" + mSubId);
390                     mIImsConfig.notifyRcsAutoConfigurationRemoved();
391                 } catch (RemoteException e) {
392                     loge("notifyRcsAutoConfigurationRemoved failed due to " + e);
393                 }
394             } else {
395                 logd("notifyRcsAutoConfigurationRemoved failed due to IImsConfig null.");
396             }
397         }
398 
clearCallbacks()399         private void clearCallbacks() {
400             synchronized (mRcsConfigCallbacks) {
401                 Iterator<IRcsConfigCallback> it = mRcsConfigCallbacks.iterator();
402                 while (it.hasNext()) {
403                     IRcsConfigCallback cb = it.next();
404                     if (mIImsConfig != null) {
405                         try {
406                             mIImsConfig.removeRcsConfigCallback(cb);
407                         } catch (RemoteException e) {
408                             loge("fail to removeRcsConfigCallback due to " + e);
409                         }
410                     }
411                     try {
412                         cb.onRemoved();
413                     } catch (RemoteException e) {
414                         logd("Failed to notify onRemoved due to dead binder of " + cb);
415                     }
416                     it.remove();
417                 }
418             }
419         }
420 
registerMetricsCallback()421         private void registerMetricsCallback() {
422             RcsProvisioningCallback rcsProvisioningCallback = mRcsStats.getRcsProvisioningCallback(
423                     mSubId, mSingleRegistrationCapability == ProvisioningManager.STATUS_CAPABLE);
424 
425             // if not yet registered, register callback and set registered value
426             if (rcsProvisioningCallback != null && !rcsProvisioningCallback.getRegistered()) {
427                 if (addRcsConfigCallback(rcsProvisioningCallback)) {
428                     rcsProvisioningCallback.setRegistered(true);
429                 }
430             }
431         }
432     }
433 
434     @VisibleForTesting
435     public interface FeatureConnectorFactory<U extends FeatureUpdates> {
436         /**
437          * @return a {@link FeatureConnector} associated for the given {@link FeatureUpdates}
438          * and slot index.
439          */
create(Context context, int slotIndex, FeatureConnector.Listener<U> listener, Executor executor, String logPrefix)440         FeatureConnector<U> create(Context context, int slotIndex,
441                 FeatureConnector.Listener<U> listener, Executor executor, String logPrefix);
442     }
443 
444     private final class RcsFeatureListener implements FeatureConnector.Listener<RcsFeatureManager> {
445         private final ArraySet<RcsProvisioningInfo> mRcsProvisioningInfos = new ArraySet<>();
446         private RcsFeatureManager mRcsFeatureManager;
447         private FeatureConnector<RcsFeatureManager> mConnector;
448 
RcsFeatureListener(int slotId)449         RcsFeatureListener(int slotId) {
450             mConnector = mFeatureFactory.create(
451                     mPhone, slotId, this, new HandlerExecutor(mHandler), TAG);
452             mConnector.connect();
453         }
454 
destroy()455         void destroy() {
456             mConnector.disconnect();
457             mConnector = null;
458             mRcsFeatureManager = null;
459             mRcsProvisioningInfos.clear();
460         }
461 
addRcsProvisioningInfo(RcsProvisioningInfo info)462         void addRcsProvisioningInfo(RcsProvisioningInfo info) {
463             if (!mRcsProvisioningInfos.contains(info)) {
464                 mRcsProvisioningInfos.add(info);
465                 info.onRcsStatusChanged(mRcsFeatureManager == null ? null
466                         : mRcsFeatureManager.getConfig());
467             }
468         }
469 
removeRcsProvisioningInfo(RcsProvisioningInfo info)470         void removeRcsProvisioningInfo(RcsProvisioningInfo info) {
471             mRcsProvisioningInfos.remove(info);
472         }
473 
474         @Override
connectionReady(RcsFeatureManager manager, int subId)475         public void connectionReady(RcsFeatureManager manager, int subId) {
476             mRcsFeatureManager = manager;
477             mRcsProvisioningInfos.forEach(v -> v.onRcsStatusChanged(manager.getConfig()));
478         }
479 
480         @Override
connectionUnavailable(int reason)481         public void connectionUnavailable(int reason) {
482             mRcsFeatureManager = null;
483             mRcsProvisioningInfos.forEach(v -> v.onRcsStatusChanged(null));
484         }
485     }
486 
487     @VisibleForTesting
RcsProvisioningMonitor(PhoneGlobals app, Looper looper, RoleManagerAdapter roleManager, FeatureConnectorFactory<RcsFeatureManager> factory, RcsStats rcsStats, @NonNull FeatureFlags flags)488     public RcsProvisioningMonitor(PhoneGlobals app, Looper looper, RoleManagerAdapter roleManager,
489             FeatureConnectorFactory<RcsFeatureManager> factory, RcsStats rcsStats,
490             @NonNull FeatureFlags flags) {
491         mPhone = app;
492         mFeatureFlags = flags;
493         mHandler = new MyHandler(looper);
494         mCarrierConfigManager = mPhone.getSystemService(CarrierConfigManager.class);
495         mSubscriptionManager = mPhone.getSystemService(SubscriptionManager.class);
496         mTelephonyRegistryManager = mPhone.getSystemService(TelephonyRegistryManager.class);
497         mRoleManager = roleManager;
498         mDmaPackageName = getDmaPackageName();
499         logv("DMA is " + mDmaPackageName);
500         mDmaChangedListener = new DmaChangedListener();
501         mFeatureFactory = factory;
502         mRcsStats = rcsStats;
503         init();
504     }
505 
506     /**
507      * create an instance
508      */
make(@onNull PhoneGlobals app, @NonNull FeatureFlags flags)509     public static RcsProvisioningMonitor make(@NonNull PhoneGlobals app,
510             @NonNull FeatureFlags flags) {
511         if (sInstance == null) {
512             logd("RcsProvisioningMonitor created.");
513             HandlerThread handlerThread = new HandlerThread(TAG);
514             handlerThread.start();
515             sInstance = new RcsProvisioningMonitor(app, handlerThread.getLooper(),
516                     new RoleManagerAdapterImpl(app), RcsFeatureManager::getConnector,
517                     RcsStats.getInstance(), flags);
518         }
519         return sInstance;
520     }
521 
522     /**
523      * get the instance
524      */
getInstance()525     public static RcsProvisioningMonitor getInstance() {
526         return sInstance;
527     }
528 
init()529     private void init() {
530         logd("init.");
531         IntentFilter filter = new IntentFilter();
532         filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
533         mPhone.registerReceiver(mReceiver, filter);
534         mTelephonyRegistryManager.addOnSubscriptionsChangedListener(
535                 mSubChangedListener, mHandler::post);
536         mDmaChangedListener.register();
537         //initialize configs for all active sub
538         onSubChanged();
539     }
540 
release()541     private void release() {
542         logd("release.");
543         mDmaChangedListener.unregister();
544         mTelephonyRegistryManager.removeOnSubscriptionsChangedListener(mSubChangedListener);
545         mPhone.unregisterReceiver(mReceiver);
546         for (int i = 0; i < mRcsFeatureListeners.size(); i++) {
547             mRcsFeatureListeners.valueAt(i).destroy();
548         }
549         mRcsFeatureListeners.clear();
550         mRcsProvisioningInfos.forEach((k, v)->v.destroy());
551         mRcsProvisioningInfos.clear();
552         mCarrierSingleRegistrationEnabledOverride.clear();
553     }
554 
reset()555     private void reset() {
556         release();
557         init();
558     }
559 
560     /**
561      * destroy the instance
562      */
563     @VisibleForTesting
destroy()564     public void destroy() {
565         logd("destroy it.");
566         release();
567         mHandler.getLooper().quit();
568     }
569 
570     /**
571      * get the handler
572      */
573     @VisibleForTesting
getHandler()574     public Handler getHandler() {
575         return mHandler;
576     }
577 
578     /**
579      * Gets the config for a subscription
580      */
581     @VisibleForTesting
getConfig(int subId)582     public byte[] getConfig(int subId) {
583         if (mRcsProvisioningInfos.containsKey(subId)) {
584             return mRcsProvisioningInfos.get(subId).getConfig();
585         }
586         return null;
587     }
588 
589     /**
590      * Returns whether Rcs Volte single registration is enabled for the sub.
591      */
isRcsVolteSingleRegistrationEnabled(int subId)592     public Boolean isRcsVolteSingleRegistrationEnabled(int subId) {
593         if (mRcsProvisioningInfos.containsKey(subId)) {
594             return mRcsProvisioningInfos.get(subId).getSingleRegistrationCapability()
595                     == ProvisioningManager.STATUS_CAPABLE;
596         }
597         return null;
598     }
599 
600     /**
601      * Called when the new rcs config is received
602      */
updateConfig(int subId, byte[] config, boolean isCompressed)603     public void updateConfig(int subId, byte[] config, boolean isCompressed) {
604         mHandler.sendMessage(mHandler.obtainMessage(
605                 EVENT_CONFIG_RECEIVED, subId, isCompressed ? 1 : 0, config));
606     }
607 
608     /**
609      * Called when the application needs rcs re-config
610      */
requestReconfig(int subId)611     public void requestReconfig(int subId) {
612         mHandler.sendMessage(mHandler.obtainMessage(EVENT_RECONFIG_REQUEST, subId, 0));
613     }
614 
615     /**
616      * Called when the application registers rcs provisioning callback
617      */
registerRcsProvisioningCallback(int subId, IRcsConfigCallback cb)618     public boolean registerRcsProvisioningCallback(int subId, IRcsConfigCallback cb) {
619         RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
620         // should not happen in normal case
621         if (info == null) {
622             logd("fail to register rcs provisioning callback due to subscription unavailable");
623             return false;
624         }
625 
626         return info.addRcsConfigCallback(cb);
627     }
628 
629     /**
630      * Called when the application unregisters rcs provisioning callback
631      */
unregisterRcsProvisioningCallback(int subId, IRcsConfigCallback cb)632     public boolean unregisterRcsProvisioningCallback(int subId, IRcsConfigCallback cb) {
633         RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
634         // should not happen in normal case
635         if (info == null) {
636             logd("fail to unregister rcs provisioning changed due to subscription unavailable");
637             return false;
638         }
639 
640         return info.removeRcsConfigCallback(cb);
641     }
642 
643     /**
644      * Enables or disables test mode.
645      *
646      * <p> If test mode is enabled, any rcs config change will not update the database.
647      */
setTestModeEnabled(boolean enabled)648     public void setTestModeEnabled(boolean enabled) {
649         logv("setTestModeEnabled as " + enabled);
650         if (mTestModeEnabled != enabled) {
651             mTestModeEnabled = enabled;
652             mHandler.sendMessage(mHandler.obtainMessage(EVENT_RESET));
653         }
654     }
655 
656 
657     /**
658      * Returns whether the test mode is enabled.
659      */
getTestModeEnabled()660     public boolean getTestModeEnabled() {
661         return mTestModeEnabled;
662     }
663 
664     /**
665      * override the device config whether single registration is enabled
666      */
overrideDeviceSingleRegistrationEnabled(Boolean enabled)667     public void overrideDeviceSingleRegistrationEnabled(Boolean enabled) {
668         mHandler.sendMessage(mHandler.obtainMessage(EVENT_DEVICE_CONFIG_OVERRIDE, enabled));
669     }
670 
671     /**
672      * Overrides the carrier config whether single registration is enabled
673      */
overrideCarrierSingleRegistrationEnabled(int subId, Boolean enabled)674     public boolean overrideCarrierSingleRegistrationEnabled(int subId, Boolean enabled) {
675         if (!mRcsProvisioningInfos.containsKey(subId)) {
676             return false;
677         }
678         mHandler.sendMessage(mHandler.obtainMessage(
679                 EVENT_CARRIER_CONFIG_OVERRIDE, subId, 0, enabled));
680         return true;
681     }
682 
683     /**
684      * override the rcs feature validation result for a subscription
685      */
overrideImsFeatureValidation(int subId, Boolean enabled)686     public boolean overrideImsFeatureValidation(int subId, Boolean enabled) {
687         if (enabled == null) {
688             mImsFeatureValidationOverride.remove(subId);
689         } else {
690             mImsFeatureValidationOverride.put(subId, enabled);
691         }
692         return true;
693     }
694 
695     /**
696      * Returns the device config whether single registration is enabled
697      */
getDeviceSingleRegistrationEnabled()698     public boolean getDeviceSingleRegistrationEnabled() {
699         for (RcsProvisioningInfo info : mRcsProvisioningInfos.values()) {
700             return (info.getSingleRegistrationCapability()
701                     & ProvisioningManager.STATUS_DEVICE_NOT_CAPABLE) == 0;
702         }
703         return false;
704     }
705 
706     /**
707      * Returns the carrier config whether single registration is enabled
708      */
getCarrierSingleRegistrationEnabled(int subId)709     public boolean getCarrierSingleRegistrationEnabled(int subId) {
710         if (mRcsProvisioningInfos.containsKey(subId)) {
711             return (mRcsProvisioningInfos.get(subId).getSingleRegistrationCapability()
712                     & ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE) == 0;
713         }
714         return false;
715     }
716 
717     /**
718      * Returns the rcs feature validation override value, null if it is not set.
719      */
getImsFeatureValidationOverride(int subId)720     public Boolean getImsFeatureValidationOverride(int subId) {
721         return mImsFeatureValidationOverride.get(subId);
722     }
723 
onDefaultMessagingApplicationChanged()724     private void onDefaultMessagingApplicationChanged() {
725         final String packageName = getDmaPackageName();
726         if (!TextUtils.equals(mDmaPackageName, packageName)) {
727             mDmaPackageName = packageName;
728             logv("new default messaging application " + mDmaPackageName);
729 
730             mRcsProvisioningInfos.forEach((k, v) -> {
731                 v.notifyDma();
732 
733                 byte[] cachedConfig = v.getConfig();
734                 //clear old callbacks
735                 v.clear();
736                 if (isAcsUsed(k)) {
737                     logv("acs used, trigger to re-configure.");
738                     updateConfigForSub(k, null, true);
739                     v.triggerRcsReconfiguration();
740                 } else {
741                     logv("acs not used, set cached config and notify.");
742                     v.setConfig(cachedConfig);
743                 }
744 
745                 // store RCS metrics - DMA changed event
746                 mRcsStats.onRcsClientProvisioningStats(k,
747                         RCS_CLIENT_PROVISIONING_STATS__EVENT__DMA_CHANGED);
748             });
749         }
750     }
751 
updateConfigForSub(int subId, byte[] config, boolean isCompressed)752     private void updateConfigForSub(int subId, byte[] config, boolean isCompressed) {
753         logv("updateConfigForSub, subId:" + subId + ", mTestModeEnabled:" + mTestModeEnabled);
754         if (!mTestModeEnabled) {
755             RcsConfig.updateConfigForSub(mPhone, subId, config, isCompressed);
756         }
757     }
758 
loadConfigForSub(int subId)759     private byte[] loadConfigForSub(int subId) {
760         logv("loadConfigForSub, subId:" + subId + ", mTestModeEnabled:" + mTestModeEnabled);
761         if (!mTestModeEnabled) {
762             return RcsConfig.loadRcsConfigForSub(mPhone, subId, false);
763         }
764         return null;
765     }
766 
isAcsUsed(int subId)767     private boolean isAcsUsed(int subId) {
768         PersistableBundle b = mCarrierConfigManager.getConfigForSubId(subId);
769         if (b == null) {
770             return false;
771         }
772         return b.getBoolean(CarrierConfigManager.KEY_USE_ACS_FOR_RCS_BOOL);
773     }
774 
getSingleRegistrationRequiredByCarrier(int subId)775     private int getSingleRegistrationRequiredByCarrier(int subId) {
776         Boolean enabledByOverride = mCarrierSingleRegistrationEnabledOverride.get(subId);
777         if (enabledByOverride != null) {
778             return enabledByOverride ? ProvisioningManager.STATUS_CAPABLE
779                     : ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE;
780         }
781 
782         PersistableBundle b = mCarrierConfigManager.getConfigForSubId(subId);
783         if (!CarrierConfigManager.isConfigForIdentifiedCarrier(b)) {
784             return MASK_CAP_CARRIER_INIT;
785         }
786         return b.getBoolean(CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL)
787                 ? ProvisioningManager.STATUS_CAPABLE
788                 : ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE;
789     }
790 
getSingleRegistrationCapableValue(int subId)791     private int getSingleRegistrationCapableValue(int subId) {
792         boolean isSingleRegistrationEnabledOnDevice =
793                 mDeviceSingleRegistrationEnabledOverride != null
794                 ? mDeviceSingleRegistrationEnabledOverride
795                 : mPhone.getPackageManager().hasSystemFeature(
796                         PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION);
797 
798         int value = (isSingleRegistrationEnabledOnDevice ? ProvisioningManager.STATUS_CAPABLE
799                 : ProvisioningManager.STATUS_DEVICE_NOT_CAPABLE)
800                 | getSingleRegistrationRequiredByCarrier(subId);
801         logv("SingleRegistrationCapableValue : " + value);
802         return value;
803     }
804 
onCarrierConfigChange()805     private void onCarrierConfigChange() {
806         logv("onCarrierConfigChange");
807         mRcsProvisioningInfos.forEach((subId, info) -> {
808             info.setSingleRegistrationCapability(
809                     getSingleRegistrationCapableValue(subId));
810         });
811     }
812 
onSubChanged()813     private void onSubChanged() {
814         final int[] activeSubs = mSubscriptionManager.getActiveSubscriptionIdList();
815         final ArraySet<Integer> subsToBeDeactivated =
816                 new ArraySet<>(mRcsProvisioningInfos.keySet());
817 
818         for (int i : activeSubs) {
819             subsToBeDeactivated.remove(i);
820             if (!mRcsProvisioningInfos.containsKey(i)) {
821                 byte[] data = loadConfigForSub(i);
822                 int capability = getSingleRegistrationCapableValue(i);
823                 logv("new info is created for sub : " + i + ", single registration capability :"
824                         + capability + ", rcs config : " + Arrays.toString(data));
825                 mRcsProvisioningInfos.put(i, new RcsProvisioningInfo(i, capability, data));
826             }
827         }
828 
829         subsToBeDeactivated.forEach(i -> {
830             RcsProvisioningInfo info = mRcsProvisioningInfos.remove(i);
831             if (info != null) {
832                 info.destroy();
833             }
834         });
835     }
836 
onConfigReceived(int subId, byte[] config, boolean isCompressed)837     private void onConfigReceived(int subId, byte[] config, boolean isCompressed) {
838         logv("onConfigReceived, subId:" + subId + ", config:"
839                 + Arrays.toString(config) + ", isCompressed:" + isCompressed);
840         RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
841         if (info == null) {
842             logd("sub[" + subId + "] has been removed");
843             return;
844         }
845         info.setConfig(isCompressed ? RcsConfig.decompressGzip(config) : config);
846         updateConfigForSub(subId, config, isCompressed);
847 
848         // Supporting ACS means config data comes from ACS
849         // store RCS metrics - received provisioning event
850         if (isAcsUsed(subId)) {
851             mRcsStats.onRcsAcsProvisioningStats(subId, 200,
852                     RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PROVISIONING_XML,
853                     isRcsVolteSingleRegistrationEnabled(subId));
854         }
855     }
856 
onReconfigRequest(int subId)857     private void onReconfigRequest(int subId) {
858         logv("onReconfigRequest, subId:" + subId);
859         RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
860         if (info != null) {
861             info.setConfig(null);
862             // clear rcs config stored in db
863             updateConfigForSub(subId, null, true);
864             info.triggerRcsReconfiguration();
865         }
866 
867         // store RCS metrics - reconfig event
868         mRcsStats.onRcsClientProvisioningStats(subId,
869                 RCS_CLIENT_PROVISIONING_STATS__EVENT__TRIGGER_RCS_RECONFIGURATION);
870     }
871 
notifyDmaForSub(int subId, int capability)872     private void notifyDmaForSub(int subId, int capability) {
873         final Intent intent = new Intent(
874                 ProvisioningManager.ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE);
875         intent.setPackage(mDmaPackageName);
876         intent.putExtra(ProvisioningManager.EXTRA_SUBSCRIPTION_ID, subId);
877         intent.putExtra(ProvisioningManager.EXTRA_STATUS, capability);
878         logv("notify " + intent + ", sub:" + subId + ", capability:" + capability);
879         // Only send permission to the default sms app if it has the correct permissions
880         // except test mode enabled
881         if (!mTestModeEnabled) {
882             if (mFeatureFlags.hsumBroadcast()) {
883                 mPhone.sendBroadcastAsUser(intent, UserHandle.ALL,
884                         Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION);
885             } else {
886                 mPhone.sendBroadcast(intent, Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION);
887             }
888         } else {
889             if (mFeatureFlags.hsumBroadcast()) {
890                 mPhone.sendBroadcastAsUser(intent, UserHandle.ALL);
891             } else {
892                 mPhone.sendBroadcast(intent);
893             }
894         }
895     }
896 
getDmaPackageName()897     private String getDmaPackageName() {
898         try {
899             return CollectionUtils.firstOrNull(mRoleManager.getRoleHolders(RoleManager.ROLE_SMS));
900         } catch (RuntimeException e) {
901             loge("Could not get dma name due to " + e);
902             return null;
903         }
904     }
905 
registerRcsFeatureListener(RcsProvisioningInfo info)906     void registerRcsFeatureListener(RcsProvisioningInfo info) {
907         int slotId = SubscriptionManager.getSlotIndex(info.getSubId());
908         RcsFeatureListener cb = mRcsFeatureListeners.get(slotId);
909         if (cb == null) {
910             cb = new RcsFeatureListener(slotId);
911             mRcsFeatureListeners.put(slotId, cb);
912         }
913         cb.addRcsProvisioningInfo(info);
914     }
915 
unregisterRcsFeatureListener(RcsProvisioningInfo info)916     void unregisterRcsFeatureListener(RcsProvisioningInfo info) {
917         // make sure the info to be removed in any case, even the slotId changed or invalid.
918         for (int i  = 0; i < mRcsFeatureListeners.size(); i++) {
919             mRcsFeatureListeners.valueAt(i).removeRcsProvisioningInfo(info);
920         }
921     }
922 
booleanEquals(Boolean val1, Boolean val2)923     private static boolean booleanEquals(Boolean val1, Boolean val2) {
924         return (val1 == null && val2 == null)
925                 || (Boolean.TRUE.equals(val1) && Boolean.TRUE.equals(val2))
926                 || (Boolean.FALSE.equals(val1) && Boolean.FALSE.equals(val2));
927     }
928 
logv(String msg)929     private static void logv(String msg) {
930         if (DBG) {
931             Rlog.d(TAG, msg);
932         }
933     }
934 
logi(String msg)935     private static void logi(String msg) {
936         Rlog.i(TAG, msg);
937     }
938 
logd(String msg)939     private static void logd(String msg) {
940         Rlog.d(TAG, msg);
941     }
942 
loge(String msg)943     private static void loge(String msg) {
944         Rlog.e(TAG, msg);
945     }
946 
947     /**
948      * {@link RoleManager} is final so we have to wrap the implementation for testing.
949      */
950     @VisibleForTesting
951     public interface RoleManagerAdapter {
952         /** See {@link RoleManager#getRoleHolders(String)} */
getRoleHolders(String roleName)953         List<String> getRoleHolders(String roleName);
954         /** See {@link RoleManager#addOnRoleHoldersChangedListenerAsUser} */
addOnRoleHoldersChangedListenerAsUser(Executor executor, OnRoleHoldersChangedListener listener, UserHandle user)955         void addOnRoleHoldersChangedListenerAsUser(Executor executor,
956                 OnRoleHoldersChangedListener listener, UserHandle user);
957         /** See {@link RoleManager#removeOnRoleHoldersChangedListenerAsUser} */
removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener listener, UserHandle user)958         void removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener listener,
959                 UserHandle user);
960     }
961 
962     private static class RoleManagerAdapterImpl implements RoleManagerAdapter {
963         private final RoleManager mRoleManager;
964 
RoleManagerAdapterImpl(Context context)965         private RoleManagerAdapterImpl(Context context) {
966             mRoleManager = context.getSystemService(RoleManager.class);
967         }
968 
969         @Override
getRoleHolders(String roleName)970         public List<String> getRoleHolders(String roleName) {
971             return mRoleManager.getRoleHolders(roleName);
972         }
973 
974         @Override
addOnRoleHoldersChangedListenerAsUser(Executor executor, OnRoleHoldersChangedListener listener, UserHandle user)975         public void addOnRoleHoldersChangedListenerAsUser(Executor executor,
976                 OnRoleHoldersChangedListener listener, UserHandle user) {
977             mRoleManager.addOnRoleHoldersChangedListenerAsUser(executor, listener, user);
978         }
979 
980         @Override
removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener listener, UserHandle user)981         public void removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener listener,
982                 UserHandle user) {
983             mRoleManager.removeOnRoleHoldersChangedListenerAsUser(listener, user);
984         }
985     }
986 }
987