• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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.internal.telephony.subscription;
18 
19 import android.annotation.CallbackExecutor;
20 import android.annotation.ColorInt;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.UserIdInt;
24 import android.content.ContentValues;
25 import android.content.Context;
26 import android.database.Cursor;
27 import android.net.Uri;
28 import android.os.Handler;
29 import android.os.Looper;
30 import android.os.ParcelUuid;
31 import android.provider.Telephony;
32 import android.provider.Telephony.SimInfo;
33 import android.telephony.SubscriptionInfo;
34 import android.telephony.SubscriptionManager;
35 import android.telephony.SubscriptionManager.DataRoamingMode;
36 import android.telephony.SubscriptionManager.DeviceToDeviceStatusSharingPreference;
37 import android.telephony.SubscriptionManager.ProfileClass;
38 import android.telephony.SubscriptionManager.SimDisplayNameSource;
39 import android.telephony.SubscriptionManager.SubscriptionType;
40 import android.telephony.SubscriptionManager.UsageSetting;
41 import android.telephony.TelephonyManager;
42 import android.telephony.UiccAccessRule;
43 import android.telephony.ims.ImsMmTelManager;
44 import android.text.TextUtils;
45 import android.util.Base64;
46 import android.util.IndentingPrintWriter;
47 import android.util.LocalLog;
48 
49 import com.android.internal.annotations.GuardedBy;
50 import com.android.internal.annotations.VisibleForTesting;
51 import com.android.internal.telephony.uicc.UiccController;
52 import com.android.internal.util.function.TriConsumer;
53 import com.android.telephony.Rlog;
54 
55 import java.io.FileDescriptor;
56 import java.io.PrintWriter;
57 import java.util.AbstractMap;
58 import java.util.ArrayList;
59 import java.util.Arrays;
60 import java.util.HashMap;
61 import java.util.List;
62 import java.util.Map;
63 import java.util.Objects;
64 import java.util.Set;
65 import java.util.concurrent.Executor;
66 import java.util.concurrent.locks.ReadWriteLock;
67 import java.util.concurrent.locks.ReentrantReadWriteLock;
68 import java.util.function.BiFunction;
69 import java.util.function.Function;
70 import java.util.function.Predicate;
71 import java.util.stream.Collectors;
72 
73 /**
74  * The subscription database manager is the wrapper of {@link SimInfo}
75  * table. It's a full memory cache of the entire subscription database, and the update can be
76  * asynchronously or synchronously. The database's cache allows multi threads to read
77  * simultaneously, if no write is ongoing.
78  *
79  * Note that from Android 14, directly writing into the subscription database through content
80  * resolver with {@link SimInfo#CONTENT_URI} will cause cache/db out of sync. All the read/write
81  * to the database should go through {@link SubscriptionManagerService}.
82  */
83 public class SubscriptionDatabaseManager extends Handler {
84     private static final String LOG_TAG = "SDMGR";
85 
86     /** Whether enabling verbose debugging message or not. */
87     private static final boolean VDBG = false;
88 
89     /** Invalid database row index. */
90     private static final int INVALID_ROW_INDEX = -1;
91 
92     /** The mapping from {@link SimInfo} table to {@link SubscriptionInfoInternal} get methods. */
93     private static final Map<String, Function<SubscriptionInfoInternal, ?>>
94             SUBSCRIPTION_GET_METHOD_MAP = Map.ofEntries(
95             new AbstractMap.SimpleImmutableEntry<>(
96                     SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID,
97                     SubscriptionInfoInternal::getSubscriptionId),
98             new AbstractMap.SimpleImmutableEntry<>(
99                     SimInfo.COLUMN_ICC_ID,
100                     SubscriptionInfoInternal::getIccId),
101             new AbstractMap.SimpleImmutableEntry<>(
102                     SimInfo.COLUMN_SIM_SLOT_INDEX,
103                     SubscriptionInfoInternal::getSimSlotIndex),
104             new AbstractMap.SimpleImmutableEntry<>(
105                     SimInfo.COLUMN_DISPLAY_NAME,
106                     SubscriptionInfoInternal::getDisplayName),
107             new AbstractMap.SimpleImmutableEntry<>(
108                     SimInfo.COLUMN_CARRIER_NAME,
109                     SubscriptionInfoInternal::getCarrierName),
110             new AbstractMap.SimpleImmutableEntry<>(
111                     SimInfo.COLUMN_NAME_SOURCE,
112                     SubscriptionInfoInternal::getDisplayNameSource),
113             new AbstractMap.SimpleImmutableEntry<>(
114                     SimInfo.COLUMN_COLOR,
115                     SubscriptionInfoInternal::getIconTint),
116             new AbstractMap.SimpleImmutableEntry<>(
117                     SimInfo.COLUMN_NUMBER,
118                     SubscriptionInfoInternal::getNumber),
119             new AbstractMap.SimpleImmutableEntry<>(
120                     SimInfo.COLUMN_DATA_ROAMING,
121                     SubscriptionInfoInternal::getDataRoaming),
122             new AbstractMap.SimpleImmutableEntry<>(
123                     SimInfo.COLUMN_MCC_STRING,
124                     SubscriptionInfoInternal::getMcc),
125             new AbstractMap.SimpleImmutableEntry<>(
126                     SimInfo.COLUMN_MNC_STRING,
127                     SubscriptionInfoInternal::getMnc),
128             new AbstractMap.SimpleImmutableEntry<>(
129                     SimInfo.COLUMN_EHPLMNS,
130                     SubscriptionInfoInternal::getEhplmns),
131             new AbstractMap.SimpleImmutableEntry<>(
132                     SimInfo.COLUMN_HPLMNS,
133                     SubscriptionInfoInternal::getHplmns),
134             new AbstractMap.SimpleImmutableEntry<>(
135                     SimInfo.COLUMN_IS_EMBEDDED,
136                     SubscriptionInfoInternal::getEmbedded),
137             new AbstractMap.SimpleImmutableEntry<>(
138                     SimInfo.COLUMN_CARD_ID,
139                     SubscriptionInfoInternal::getCardString),
140             new AbstractMap.SimpleImmutableEntry<>(
141                     SimInfo.COLUMN_ACCESS_RULES,
142                     SubscriptionInfoInternal::getNativeAccessRules),
143             new AbstractMap.SimpleImmutableEntry<>(
144                     SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS,
145                     SubscriptionInfoInternal::getCarrierConfigAccessRules),
146             new AbstractMap.SimpleImmutableEntry<>(
147                     SimInfo.COLUMN_IS_REMOVABLE,
148                     SubscriptionInfoInternal::getRemovableEmbedded),
149             new AbstractMap.SimpleImmutableEntry<>(
150                     SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT,
151                     SubscriptionInfoInternal::getCellBroadcastExtremeThreatAlertEnabled),
152             new AbstractMap.SimpleImmutableEntry<>(
153                     SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT,
154                     SubscriptionInfoInternal::getCellBroadcastSevereThreatAlertEnabled),
155             new AbstractMap.SimpleImmutableEntry<>(
156                     SimInfo.COLUMN_CB_AMBER_ALERT,
157                     SubscriptionInfoInternal::getCellBroadcastAmberAlertEnabled),
158             new AbstractMap.SimpleImmutableEntry<>(
159                     SimInfo.COLUMN_CB_EMERGENCY_ALERT,
160                     SubscriptionInfoInternal::getCellBroadcastEmergencyAlertEnabled),
161             new AbstractMap.SimpleImmutableEntry<>(
162                     SimInfo.COLUMN_CB_ALERT_SOUND_DURATION,
163                     SubscriptionInfoInternal::getCellBroadcastAlertSoundDuration),
164             new AbstractMap.SimpleImmutableEntry<>(
165                     SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL,
166                     SubscriptionInfoInternal::getCellBroadcastAlertReminderInterval),
167             new AbstractMap.SimpleImmutableEntry<>(
168                     SimInfo.COLUMN_CB_ALERT_VIBRATE,
169                     SubscriptionInfoInternal::getCellBroadcastAlertVibrationEnabled),
170             new AbstractMap.SimpleImmutableEntry<>(
171                     SimInfo.COLUMN_CB_ALERT_SPEECH,
172                     SubscriptionInfoInternal::getCellBroadcastAlertSpeechEnabled),
173             new AbstractMap.SimpleImmutableEntry<>(
174                     SimInfo.COLUMN_CB_ETWS_TEST_ALERT,
175                     SubscriptionInfoInternal::getCellBroadcastEtwsTestAlertEnabled),
176             new AbstractMap.SimpleImmutableEntry<>(
177                     SimInfo.COLUMN_CB_CHANNEL_50_ALERT,
178                     SubscriptionInfoInternal::getCellBroadcastAreaInfoMessageEnabled),
179             new AbstractMap.SimpleImmutableEntry<>(
180                     SimInfo.COLUMN_CB_CMAS_TEST_ALERT,
181                     SubscriptionInfoInternal::getCellBroadcastTestAlertEnabled),
182             new AbstractMap.SimpleImmutableEntry<>(
183                     SimInfo.COLUMN_CB_OPT_OUT_DIALOG,
184                     SubscriptionInfoInternal::getCellBroadcastOptOutDialogEnabled),
185             new AbstractMap.SimpleImmutableEntry<>(
186                     SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED,
187                     SubscriptionInfoInternal::getEnhanced4GModeEnabled),
188             new AbstractMap.SimpleImmutableEntry<>(
189                     SimInfo.COLUMN_VT_IMS_ENABLED,
190                     SubscriptionInfoInternal::getVideoTelephonyEnabled),
191             new AbstractMap.SimpleImmutableEntry<>(
192                     SimInfo.COLUMN_WFC_IMS_ENABLED,
193                     SubscriptionInfoInternal::getWifiCallingEnabled),
194             new AbstractMap.SimpleImmutableEntry<>(
195                     SimInfo.COLUMN_WFC_IMS_MODE,
196                     SubscriptionInfoInternal::getWifiCallingMode),
197             new AbstractMap.SimpleImmutableEntry<>(
198                     SimInfo.COLUMN_WFC_IMS_ROAMING_MODE,
199                     SubscriptionInfoInternal::getWifiCallingModeForRoaming),
200             new AbstractMap.SimpleImmutableEntry<>(
201                     SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED,
202                     SubscriptionInfoInternal::getWifiCallingEnabledForRoaming),
203             new AbstractMap.SimpleImmutableEntry<>(
204                     SimInfo.COLUMN_IS_OPPORTUNISTIC,
205                     SubscriptionInfoInternal::getOpportunistic),
206             new AbstractMap.SimpleImmutableEntry<>(
207                     SimInfo.COLUMN_GROUP_UUID,
208                     SubscriptionInfoInternal::getGroupUuid),
209             new AbstractMap.SimpleImmutableEntry<>(
210                     SimInfo.COLUMN_ISO_COUNTRY_CODE,
211                     SubscriptionInfoInternal::getCountryIso),
212             new AbstractMap.SimpleImmutableEntry<>(
213                     SimInfo.COLUMN_CARRIER_ID,
214                     SubscriptionInfoInternal::getCarrierId),
215             new AbstractMap.SimpleImmutableEntry<>(
216                     SimInfo.COLUMN_PROFILE_CLASS,
217                     SubscriptionInfoInternal::getProfileClass),
218             new AbstractMap.SimpleImmutableEntry<>(
219                     SimInfo.COLUMN_SUBSCRIPTION_TYPE,
220                     SubscriptionInfoInternal::getSubscriptionType),
221             new AbstractMap.SimpleImmutableEntry<>(
222                     SimInfo.COLUMN_GROUP_OWNER,
223                     SubscriptionInfoInternal::getGroupOwner),
224             new AbstractMap.SimpleImmutableEntry<>(
225                     SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES,
226                     SubscriptionInfoInternal::getEnabledMobileDataPolicies),
227             new AbstractMap.SimpleImmutableEntry<>(
228                     SimInfo.COLUMN_IMSI,
229                     SubscriptionInfoInternal::getImsi),
230             new AbstractMap.SimpleImmutableEntry<>(
231                     SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED,
232                     SubscriptionInfoInternal::getUiccApplicationsEnabled),
233             new AbstractMap.SimpleImmutableEntry<>(
234                     SimInfo.COLUMN_IMS_RCS_UCE_ENABLED,
235                     SubscriptionInfoInternal::getRcsUceEnabled),
236             new AbstractMap.SimpleImmutableEntry<>(
237                     SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED,
238                     SubscriptionInfoInternal::getCrossSimCallingEnabled),
239             new AbstractMap.SimpleImmutableEntry<>(
240                     SimInfo.COLUMN_RCS_CONFIG,
241                     SubscriptionInfoInternal::getRcsConfig),
242             new AbstractMap.SimpleImmutableEntry<>(
243                     SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS,
244                     SubscriptionInfoInternal::getAllowedNetworkTypesForReasons),
245             new AbstractMap.SimpleImmutableEntry<>(
246                     SimInfo.COLUMN_D2D_STATUS_SHARING,
247                     SubscriptionInfoInternal::getDeviceToDeviceStatusSharingPreference),
248             new AbstractMap.SimpleImmutableEntry<>(
249                     SimInfo.COLUMN_VOIMS_OPT_IN_STATUS,
250                     SubscriptionInfoInternal::getVoImsOptInEnabled),
251             new AbstractMap.SimpleImmutableEntry<>(
252                     SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS,
253                     SubscriptionInfoInternal::getDeviceToDeviceStatusSharingContacts),
254             new AbstractMap.SimpleImmutableEntry<>(
255                     SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED,
256                     SubscriptionInfoInternal::getNrAdvancedCallingEnabled),
257             new AbstractMap.SimpleImmutableEntry<>(
258                     SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER,
259                     SubscriptionInfoInternal::getNumberFromCarrier),
260             new AbstractMap.SimpleImmutableEntry<>(
261                     SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS,
262                     SubscriptionInfoInternal::getNumberFromIms),
263             new AbstractMap.SimpleImmutableEntry<>(
264                     SimInfo.COLUMN_PORT_INDEX,
265                     SubscriptionInfoInternal::getPortIndex),
266             new AbstractMap.SimpleImmutableEntry<>(
267                     SimInfo.COLUMN_USAGE_SETTING,
268                     SubscriptionInfoInternal::getUsageSetting),
269             new AbstractMap.SimpleImmutableEntry<>(
270                     SimInfo.COLUMN_TP_MESSAGE_REF,
271                     SubscriptionInfoInternal::getLastUsedTPMessageReference),
272             new AbstractMap.SimpleImmutableEntry<>(
273                     SimInfo.COLUMN_USER_HANDLE,
274                     SubscriptionInfoInternal::getUserId),
275             new AbstractMap.SimpleImmutableEntry<>(
276                     SimInfo.COLUMN_SATELLITE_ENABLED,
277                     SubscriptionInfoInternal::getSatelliteEnabled)
278     );
279 
280     /**
281      * The mapping from columns in {@link android.provider.Telephony.SimInfo} table to
282      * {@link SubscriptionDatabaseManager} setting integer methods.
283      */
284     private static final Map<String, TriConsumer<SubscriptionDatabaseManager, Integer, Integer>>
285             SUBSCRIPTION_SET_INTEGER_METHOD_MAP = Map.ofEntries(
286             new AbstractMap.SimpleImmutableEntry<>(
287                     SimInfo.COLUMN_SIM_SLOT_INDEX,
288                     SubscriptionDatabaseManager::setSimSlotIndex),
289             new AbstractMap.SimpleImmutableEntry<>(
290                     SimInfo.COLUMN_NAME_SOURCE,
291                     SubscriptionDatabaseManager::setDisplayNameSource),
292             new AbstractMap.SimpleImmutableEntry<>(
293                     SimInfo.COLUMN_COLOR,
294                     SubscriptionDatabaseManager::setIconTint),
295             new AbstractMap.SimpleImmutableEntry<>(
296                     SimInfo.COLUMN_DATA_ROAMING,
297                     SubscriptionDatabaseManager::setDataRoaming),
298             new AbstractMap.SimpleImmutableEntry<>(
299                     SimInfo.COLUMN_IS_EMBEDDED,
300                     SubscriptionDatabaseManager::setEmbedded),
301             new AbstractMap.SimpleImmutableEntry<>(
302                     SimInfo.COLUMN_IS_REMOVABLE,
303                     SubscriptionDatabaseManager::setRemovableEmbedded),
304             new AbstractMap.SimpleImmutableEntry<>(
305                     SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT,
306                     SubscriptionDatabaseManager::setCellBroadcastExtremeThreatAlertEnabled),
307             new AbstractMap.SimpleImmutableEntry<>(
308                     SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT,
309                     SubscriptionDatabaseManager::setCellBroadcastSevereThreatAlertEnabled),
310             new AbstractMap.SimpleImmutableEntry<>(
311                     SimInfo.COLUMN_CB_AMBER_ALERT,
312                     SubscriptionDatabaseManager::setCellBroadcastAmberAlertEnabled),
313             new AbstractMap.SimpleImmutableEntry<>(
314                     SimInfo.COLUMN_CB_EMERGENCY_ALERT,
315                     SubscriptionDatabaseManager::setCellBroadcastEmergencyAlertEnabled),
316             new AbstractMap.SimpleImmutableEntry<>(
317                     SimInfo.COLUMN_CB_ALERT_SOUND_DURATION,
318                     SubscriptionDatabaseManager::setCellBroadcastAlertSoundDuration),
319             new AbstractMap.SimpleImmutableEntry<>(
320                     SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL,
321                     SubscriptionDatabaseManager::setCellBroadcastAlertReminderInterval),
322             new AbstractMap.SimpleImmutableEntry<>(
323                     SimInfo.COLUMN_CB_ALERT_VIBRATE,
324                     SubscriptionDatabaseManager::setCellBroadcastAlertVibrationEnabled),
325             new AbstractMap.SimpleImmutableEntry<>(
326                     SimInfo.COLUMN_CB_ALERT_SPEECH,
327                     SubscriptionDatabaseManager::setCellBroadcastAlertSpeechEnabled),
328             new AbstractMap.SimpleImmutableEntry<>(
329                     SimInfo.COLUMN_CB_ETWS_TEST_ALERT,
330                     SubscriptionDatabaseManager::setCellBroadcastEtwsTestAlertEnabled),
331             new AbstractMap.SimpleImmutableEntry<>(
332                     SimInfo.COLUMN_CB_CHANNEL_50_ALERT,
333                     SubscriptionDatabaseManager::setCellBroadcastAreaInfoMessageEnabled),
334             new AbstractMap.SimpleImmutableEntry<>(
335                     SimInfo.COLUMN_CB_CMAS_TEST_ALERT,
336                     SubscriptionDatabaseManager::setCellBroadcastTestAlertEnabled),
337             new AbstractMap.SimpleImmutableEntry<>(
338                     SimInfo.COLUMN_CB_OPT_OUT_DIALOG,
339                     SubscriptionDatabaseManager::setCellBroadcastOptOutDialogEnabled),
340             new AbstractMap.SimpleImmutableEntry<>(
341                     SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED,
342                     SubscriptionDatabaseManager::setEnhanced4GModeEnabled),
343             new AbstractMap.SimpleImmutableEntry<>(
344                     SimInfo.COLUMN_VT_IMS_ENABLED,
345                     SubscriptionDatabaseManager::setVideoTelephonyEnabled),
346             new AbstractMap.SimpleImmutableEntry<>(
347                     SimInfo.COLUMN_WFC_IMS_ENABLED,
348                     SubscriptionDatabaseManager::setWifiCallingEnabled),
349             new AbstractMap.SimpleImmutableEntry<>(
350                     SimInfo.COLUMN_WFC_IMS_MODE,
351                     SubscriptionDatabaseManager::setWifiCallingMode),
352             new AbstractMap.SimpleImmutableEntry<>(
353                     SimInfo.COLUMN_WFC_IMS_ROAMING_MODE,
354                     SubscriptionDatabaseManager::setWifiCallingModeForRoaming),
355             new AbstractMap.SimpleImmutableEntry<>(
356                     SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED,
357                     SubscriptionDatabaseManager::setWifiCallingEnabledForRoaming),
358             new AbstractMap.SimpleImmutableEntry<>(
359                     SimInfo.COLUMN_IS_OPPORTUNISTIC,
360                     SubscriptionDatabaseManager::setOpportunistic),
361             new AbstractMap.SimpleImmutableEntry<>(
362                     SimInfo.COLUMN_CARRIER_ID,
363                     SubscriptionDatabaseManager::setCarrierId),
364             new AbstractMap.SimpleImmutableEntry<>(
365                     SimInfo.COLUMN_PROFILE_CLASS,
366                     SubscriptionDatabaseManager::setProfileClass),
367             new AbstractMap.SimpleImmutableEntry<>(
368                     SimInfo.COLUMN_SUBSCRIPTION_TYPE,
369                     SubscriptionDatabaseManager::setSubscriptionType),
370             new AbstractMap.SimpleImmutableEntry<>(
371                     SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED,
372                     SubscriptionDatabaseManager::setUiccApplicationsEnabled),
373             new AbstractMap.SimpleImmutableEntry<>(
374                     SimInfo.COLUMN_IMS_RCS_UCE_ENABLED,
375                     SubscriptionDatabaseManager::setRcsUceEnabled),
376             new AbstractMap.SimpleImmutableEntry<>(
377                     SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED,
378                     SubscriptionDatabaseManager::setCrossSimCallingEnabled),
379             new AbstractMap.SimpleImmutableEntry<>(
380                     SimInfo.COLUMN_D2D_STATUS_SHARING,
381                     SubscriptionDatabaseManager::setDeviceToDeviceStatusSharingPreference),
382             new AbstractMap.SimpleImmutableEntry<>(
383                     SimInfo.COLUMN_VOIMS_OPT_IN_STATUS,
384                     SubscriptionDatabaseManager::setVoImsOptInEnabled),
385             new AbstractMap.SimpleImmutableEntry<>(
386                     SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED,
387                     SubscriptionDatabaseManager::setNrAdvancedCallingEnabled),
388             new AbstractMap.SimpleImmutableEntry<>(
389                     SimInfo.COLUMN_PORT_INDEX,
390                     SubscriptionDatabaseManager::setPortIndex),
391             new AbstractMap.SimpleImmutableEntry<>(
392                     SimInfo.COLUMN_USAGE_SETTING,
393                     SubscriptionDatabaseManager::setUsageSetting),
394             new AbstractMap.SimpleImmutableEntry<>(
395                     SimInfo.COLUMN_TP_MESSAGE_REF,
396                     SubscriptionDatabaseManager::setLastUsedTPMessageReference),
397             new AbstractMap.SimpleImmutableEntry<>(
398                     SimInfo.COLUMN_USER_HANDLE,
399                     SubscriptionDatabaseManager::setUserId),
400             new AbstractMap.SimpleImmutableEntry<>(
401                     SimInfo.COLUMN_SATELLITE_ENABLED,
402                     SubscriptionDatabaseManager::setSatelliteEnabled)
403     );
404 
405     /**
406      * The mapping from columns in {@link android.provider.Telephony.SimInfo} table to
407      * {@link SubscriptionDatabaseManager} setting string methods.
408      */
409     private static final Map<String, TriConsumer<SubscriptionDatabaseManager, Integer, String>>
410             SUBSCRIPTION_SET_STRING_METHOD_MAP = Map.ofEntries(
411             new AbstractMap.SimpleImmutableEntry<>(
412                     SimInfo.COLUMN_ICC_ID,
413                     SubscriptionDatabaseManager::setIccId),
414             new AbstractMap.SimpleImmutableEntry<>(
415                     SimInfo.COLUMN_DISPLAY_NAME,
416                     SubscriptionDatabaseManager::setDisplayName),
417             new AbstractMap.SimpleImmutableEntry<>(
418                     SimInfo.COLUMN_CARRIER_NAME,
419                     SubscriptionDatabaseManager::setCarrierName),
420             new AbstractMap.SimpleImmutableEntry<>(
421                     SimInfo.COLUMN_NUMBER,
422                     SubscriptionDatabaseManager::setNumber),
423             new AbstractMap.SimpleImmutableEntry<>(
424                     SimInfo.COLUMN_MCC_STRING,
425                     SubscriptionDatabaseManager::setMcc),
426             new AbstractMap.SimpleImmutableEntry<>(
427                     SimInfo.COLUMN_MNC_STRING,
428                     SubscriptionDatabaseManager::setMnc),
429             new AbstractMap.SimpleImmutableEntry<>(
430                     SimInfo.COLUMN_EHPLMNS,
431                     SubscriptionDatabaseManager::setEhplmns),
432             new AbstractMap.SimpleImmutableEntry<>(
433                     SimInfo.COLUMN_HPLMNS,
434                     SubscriptionDatabaseManager::setHplmns),
435             new AbstractMap.SimpleImmutableEntry<>(
436                     SimInfo.COLUMN_CARD_ID,
437                     SubscriptionDatabaseManager::setCardString),
438             new AbstractMap.SimpleImmutableEntry<>(
439                     SimInfo.COLUMN_GROUP_UUID,
440                     SubscriptionDatabaseManager::setGroupUuid),
441             new AbstractMap.SimpleImmutableEntry<>(
442                     SimInfo.COLUMN_ISO_COUNTRY_CODE,
443                     SubscriptionDatabaseManager::setCountryIso),
444             new AbstractMap.SimpleImmutableEntry<>(
445                     SimInfo.COLUMN_GROUP_OWNER,
446                     SubscriptionDatabaseManager::setGroupOwner),
447             new AbstractMap.SimpleImmutableEntry<>(
448                     SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES,
449                     SubscriptionDatabaseManager::setEnabledMobileDataPolicies),
450             new AbstractMap.SimpleImmutableEntry<>(
451                     SimInfo.COLUMN_IMSI,
452                     SubscriptionDatabaseManager::setImsi),
453             new AbstractMap.SimpleImmutableEntry<>(
454                     SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS,
455                     SubscriptionDatabaseManager::setAllowedNetworkTypesForReasons),
456             new AbstractMap.SimpleImmutableEntry<>(
457                     SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS,
458                     SubscriptionDatabaseManager::setDeviceToDeviceStatusSharingContacts),
459             new AbstractMap.SimpleImmutableEntry<>(
460                     SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER,
461                     SubscriptionDatabaseManager::setNumberFromCarrier),
462             new AbstractMap.SimpleImmutableEntry<>(
463                     SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS,
464                     SubscriptionDatabaseManager::setNumberFromIms)
465     );
466 
467     /**
468      * The mapping from columns in {@link android.provider.Telephony.SimInfo} table to
469      * {@link SubscriptionDatabaseManager} setting byte array methods.
470      */
471     private static final Map<String, TriConsumer<SubscriptionDatabaseManager, Integer, byte[]>>
472             SUBSCRIPTION_SET_BYTE_ARRAY_METHOD_MAP = Map.ofEntries(
473             new AbstractMap.SimpleImmutableEntry<>(
474                     SimInfo.COLUMN_ACCESS_RULES,
475                     SubscriptionDatabaseManager::setNativeAccessRules),
476             new AbstractMap.SimpleImmutableEntry<>(
477                     SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS,
478                     SubscriptionDatabaseManager::setCarrierConfigAccessRules),
479             new AbstractMap.SimpleImmutableEntry<>(
480                     SimInfo.COLUMN_RCS_CONFIG,
481                     SubscriptionDatabaseManager::setRcsConfig)
482     );
483 
484     /**
485      * The columns that should be in-sync between the subscriptions in the same group. Changing
486      * the value in those fields will automatically apply to the rest of the subscriptions in the
487      * group.
488      *
489      * @see SubscriptionManager#getSubscriptionsInGroup(ParcelUuid)
490      */
491     private static final Set<String> GROUP_SHARING_COLUMNS = Set.of(
492             SimInfo.COLUMN_DISPLAY_NAME,
493             SimInfo.COLUMN_NAME_SOURCE,
494             SimInfo.COLUMN_COLOR,
495             SimInfo.COLUMN_DATA_ROAMING,
496             SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED,
497             SimInfo.COLUMN_VT_IMS_ENABLED,
498             SimInfo.COLUMN_WFC_IMS_ENABLED,
499             SimInfo.COLUMN_WFC_IMS_MODE,
500             SimInfo.COLUMN_WFC_IMS_ROAMING_MODE,
501             SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED,
502             SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES,
503             SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED,
504             SimInfo.COLUMN_IMS_RCS_UCE_ENABLED,
505             SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED,
506             SimInfo.COLUMN_RCS_CONFIG,
507             SimInfo.COLUMN_D2D_STATUS_SHARING,
508             SimInfo.COLUMN_VOIMS_OPT_IN_STATUS,
509             SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS,
510             SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED,
511             SimInfo.COLUMN_USER_HANDLE
512     );
513 
514     /**
515      * The deprecated columns that do not have corresponding set methods in
516      * {@link SubscriptionDatabaseManager}.
517      */
518     private static final Set<String> DEPRECATED_DATABASE_COLUMNS = Set.of(
519             SimInfo.COLUMN_DISPLAY_NUMBER_FORMAT,
520             SimInfo.COLUMN_MCC,
521             SimInfo.COLUMN_MNC,
522             SimInfo.COLUMN_SIM_PROVISIONING_STATUS,
523             SimInfo.COLUMN_IS_METERED,
524             SimInfo.COLUMN_DATA_ENABLED_OVERRIDE_RULES,
525             SimInfo.COLUMN_ALLOWED_NETWORK_TYPES
526     );
527 
528     /** The context */
529     @NonNull
530     private final Context mContext;
531 
532     /** The callback used for passing events back to {@link SubscriptionManagerService}. */
533     @NonNull
534     private final SubscriptionDatabaseManagerCallback mCallback;
535 
536     /** UICC controller */
537     private final UiccController mUiccController;
538 
539     /**
540      * The read/write lock to protect the entire database access. Using a Re-entrant read lock as
541      * much more read requests are expected than the write requests. All the access to
542      * {@link #mAllSubscriptionInfoInternalCache} needs to be protected by this lock.
543      */
544     @NonNull
545     private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();
546 
547     /** Indicating whether access the database asynchronously or not. */
548     private final boolean mAsyncMode;
549 
550     /** Local log for most important debug messages. */
551     @NonNull
552     private final LocalLog mLocalLog = new LocalLog(128);
553 
554     /**
555      * The entire subscription database, including subscriptions from inserted, previously inserted
556      * SIMs. This is the full memory cache of the subscription database. The key is the subscription
557      * id. Note all the access to this map needs to be protected by the re-entrant lock
558      * {@link #mReadWriteLock}.
559      *
560      * @see SimInfo
561      */
562     @GuardedBy("mReadWriteLock")
563     @NonNull
564     private final Map<Integer, SubscriptionInfoInternal> mAllSubscriptionInfoInternalCache =
565             new HashMap<>(16);
566 
567     /** Whether database has been initialized after boot up. */
568     @GuardedBy("this")
569     private boolean mDatabaseInitialized = false;
570 
571     /**
572      * This is the callback used for listening events from {@link SubscriptionDatabaseManager}.
573      */
574     public abstract static class SubscriptionDatabaseManagerCallback {
575         /** The executor of the callback. */
576         private final @NonNull Executor mExecutor;
577 
578         /**
579          * Constructor
580          *
581          * @param executor The executor of the callback.
582          */
SubscriptionDatabaseManagerCallback(@onNull @allbackExecutor Executor executor)583         public SubscriptionDatabaseManagerCallback(@NonNull @CallbackExecutor Executor executor) {
584             mExecutor = executor;
585         }
586 
587         /**
588          * @return The executor of the callback.
589          */
590         @VisibleForTesting
getExecutor()591         public @NonNull Executor getExecutor() {
592             return mExecutor;
593         }
594 
595         /**
596          * Invoke the callback from executor.
597          *
598          * @param runnable The callback method to invoke.
599          */
invokeFromExecutor(@onNull Runnable runnable)600         public void invokeFromExecutor(@NonNull Runnable runnable) {
601             mExecutor.execute(runnable);
602         }
603 
604         /**
605          * Called when database has been initialized.
606          */
onInitialized()607         public abstract void onInitialized();
608 
609         /**
610          * Called when subscription changed.
611          *
612          * @param subId The subscription id.
613          */
onSubscriptionChanged(int subId)614         public abstract void onSubscriptionChanged(int subId);
615     }
616 
617     /**
618      * The constructor.
619      *
620      * @param context The context.
621      * @param looper Looper for the handler.
622      * @param callback Subscription database callback.
623      */
SubscriptionDatabaseManager(@onNull Context context, @NonNull Looper looper, @NonNull SubscriptionDatabaseManagerCallback callback)624     public SubscriptionDatabaseManager(@NonNull Context context, @NonNull Looper looper,
625             @NonNull SubscriptionDatabaseManagerCallback callback) {
626         super(looper);
627         log("Created SubscriptionDatabaseManager.");
628         mContext = context;
629         mCallback = callback;
630         mUiccController = UiccController.getInstance();
631         mAsyncMode = mContext.getResources().getBoolean(
632                 com.android.internal.R.bool.config_subscription_database_async_update);
633         initializeDatabase();
634     }
635 
636     /**
637      * Helper method to get specific field from {@link SubscriptionInfoInternal} by the database
638      * column name. {@link SubscriptionInfoInternal} represent one single record in the
639      * {@link SimInfo} table. So every column has a corresponding get method in
640      * {@link SubscriptionInfoInternal} (except for unused or deprecated columns).
641      *
642      * @param subInfo The subscription info.
643      * @param columnName The database column name.
644      *
645      * @return The corresponding value from {@link SubscriptionInfoInternal}.
646      *
647      * @throws IllegalArgumentException if {@code columnName} is invalid.
648      *
649      * @see android.provider.Telephony.SimInfo for all the columns.
650      */
651     @NonNull
getSubscriptionInfoFieldByColumnName( @onNull SubscriptionInfoInternal subInfo, @NonNull String columnName)652     private static Object getSubscriptionInfoFieldByColumnName(
653             @NonNull SubscriptionInfoInternal subInfo, @NonNull String columnName) {
654         if (SUBSCRIPTION_GET_METHOD_MAP.containsKey(columnName)) {
655             return SUBSCRIPTION_GET_METHOD_MAP.get(columnName).apply(subInfo);
656         }
657         throw new IllegalArgumentException("Invalid column name " + columnName);
658     }
659 
660     /**
661      * Get a specific field from the subscription database by {@code subId} and {@code columnName}.
662      *
663      * @param subId The subscription id.
664      * @param columnName The database column name.
665      *
666      * @return The value from subscription database.
667      *
668      * @throws IllegalArgumentException if {@code subId} or {@code columnName} is invalid.
669      *
670      * @see android.provider.Telephony.SimInfo for all the columns.
671      */
672     @NonNull
getSubscriptionProperty(int subId, @NonNull String columnName)673     public Object getSubscriptionProperty(int subId, @NonNull String columnName) {
674         SubscriptionInfoInternal subInfo = getSubscriptionInfoInternal(subId);
675         if (subInfo == null) {
676             throw new IllegalArgumentException("getSubscriptionProperty: Invalid subId " + subId
677                     + ", columnName=" + columnName);
678         }
679 
680         return getSubscriptionInfoFieldByColumnName(subInfo, columnName);
681     }
682 
683     /**
684      * Set a field in the subscription database. Note not all fields are supported.
685      *
686      * @param subId Subscription Id of Subscription.
687      * @param columnName Column name in the database. Note not all fields are supported.
688      * @param value Value to store in the database.
689      *
690      * @throws IllegalArgumentException if {@code subId} or {@code columnName} is invalid, or
691      * {@code value} cannot be converted to the corresponding database column format.
692      * @throws NumberFormatException if a string value cannot be converted to integer.
693      * @throws ClassCastException if {@code value} cannot be casted to the required type.
694      *
695      * @see android.provider.Telephony.SimInfo for all the columns.
696      */
setSubscriptionProperty(int subId, @NonNull String columnName, @NonNull Object value)697     public void setSubscriptionProperty(int subId, @NonNull String columnName,
698             @NonNull Object value) {
699         if (SUBSCRIPTION_SET_INTEGER_METHOD_MAP.containsKey(columnName)) {
700             // For integer type columns, accepting both integer and string that can be converted to
701             // integer.
702             int intValue;
703             if (value instanceof String) {
704                 intValue = Integer.parseInt((String) value);
705             } else if (value instanceof Integer) {
706                 intValue = (int) value;
707             } else {
708                 throw new ClassCastException("columnName=" + columnName + ", cannot cast "
709                         + value.getClass() + " to integer.");
710             }
711             SUBSCRIPTION_SET_INTEGER_METHOD_MAP.get(columnName).accept(this, subId, intValue);
712         } else if (SUBSCRIPTION_SET_STRING_METHOD_MAP.containsKey(columnName)) {
713             // For string type columns. Will throw exception if value is not string type.
714             SUBSCRIPTION_SET_STRING_METHOD_MAP.get(columnName).accept(this, subId, (String) value);
715         } else if (SUBSCRIPTION_SET_BYTE_ARRAY_METHOD_MAP.containsKey(columnName)) {
716             // For byte array type columns, accepting both byte[] and string that can be converted
717             // to byte[] using base 64 encoding/decoding.
718             byte[] byteArrayValue;
719             if (value instanceof String) {
720                 byteArrayValue = Base64.decode((String) value, Base64.DEFAULT);
721             } else if (value instanceof byte[]) {
722                 byteArrayValue = (byte[]) value;
723             } else {
724                 throw new ClassCastException("columnName=" + columnName + ", cannot cast "
725                         + value.getClass() + " to byte[].");
726             }
727             SUBSCRIPTION_SET_BYTE_ARRAY_METHOD_MAP.get(columnName).accept(
728                     this, subId, byteArrayValue);
729         } else {
730             throw new IllegalArgumentException("Does not support set " + columnName + ".");
731         }
732     }
733 
734     /**
735      * Comparing the old/new {@link SubscriptionInfoInternal} and create content values for database
736      * update. If any field in the new subscription info is different from the old one, then each
737      * delta will be added into the {@link ContentValues}.
738      *
739      * @param oldSubInfo The old {@link SubscriptionInfoInternal}.
740      * @param newSubInfo The new {@link SubscriptionInfoInternal}.
741      *
742      * @return The delta content values for database update.
743      */
744     @NonNull
createDeltaContentValues(@ullable SubscriptionInfoInternal oldSubInfo, @NonNull SubscriptionInfoInternal newSubInfo)745     private ContentValues createDeltaContentValues(@Nullable SubscriptionInfoInternal oldSubInfo,
746             @NonNull SubscriptionInfoInternal newSubInfo) {
747         ContentValues deltaContentValues = new ContentValues();
748 
749         for (String columnName : Telephony.SimInfo.getAllColumns()) {
750             if (DEPRECATED_DATABASE_COLUMNS.contains(columnName)) continue;
751             // subId is generated by the database. Cannot be updated.
752             if (columnName.equals(SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID)) continue;
753             Object newValue = getSubscriptionInfoFieldByColumnName(newSubInfo, columnName);
754             if (newValue != null) {
755                 Object oldValue = null;
756                 if (oldSubInfo != null) {
757                     oldValue = getSubscriptionInfoFieldByColumnName(oldSubInfo, columnName);
758                 }
759                 // Some columns need special handling. We need to convert them into a format that
760                 // is accepted by the database.
761                 if (!Objects.equals(oldValue, newValue)) {
762                     deltaContentValues.putObject(columnName, newValue);
763                 }
764             }
765         }
766         return deltaContentValues;
767     }
768 
769     /**
770      * Synchronously insert a new record into the database. This operation is synchronous because
771      * we need to convert the inserted row index into the subscription id.
772      *
773      * @param contentValues The fields of the subscription to be inserted into the database.
774      *
775      * @return The row index of the new record. {@link #INVALID_ROW_INDEX} if insertion failed.
776      */
insertNewRecordIntoDatabaseSync(@onNull ContentValues contentValues)777     private int insertNewRecordIntoDatabaseSync(@NonNull ContentValues contentValues) {
778         Objects.requireNonNull(contentValues);
779         Uri uri = mContext.getContentResolver().insert(SimInfo.CONTENT_URI, contentValues);
780         if (uri != null && uri.getLastPathSegment() != null) {
781             int subId = Integer.parseInt(uri.getLastPathSegment());
782             if (SubscriptionManager.isValidSubscriptionId(subId)) {
783                 logv("insertNewRecordIntoDatabaseSync: contentValues=" + contentValues);
784                 logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId="
785                         + uri.getLastPathSegment());
786                 return subId;
787             }
788         }
789 
790         logel("insertNewRecordIntoDatabaseSync: Failed to insert subscription into database. "
791                 + "contentValues=" + contentValues);
792         return INVALID_ROW_INDEX;
793     }
794 
795     /**
796      * Insert a new subscription info. The subscription info must have subscription id
797      * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}. Note this is a slow method, so be
798      * cautious to call this method.
799      *
800      * @param subInfo The subscription info to update.
801      *
802      * @return The new subscription id. {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} (-1) if
803      * insertion fails.
804      */
insertSubscriptionInfo(@onNull SubscriptionInfoInternal subInfo)805     public int insertSubscriptionInfo(@NonNull SubscriptionInfoInternal subInfo) {
806         Objects.requireNonNull(subInfo);
807         // A new subscription to be inserted must have invalid subscription id.
808         if (SubscriptionManager.isValidSubscriptionId(subInfo.getSubscriptionId())) {
809             throw new RuntimeException("insertSubscriptionInfo: Not a new subscription to "
810                     + "insert. subInfo=" + subInfo);
811         }
812 
813         synchronized (this) {
814             if (!mDatabaseInitialized) {
815                 throw new IllegalStateException(
816                         "Database has not been initialized. Can't insert new "
817                                 + "record at this point.");
818             }
819         }
820 
821         int subId;
822         // Grab the write lock so no other threads can read or write the cache.
823         mReadWriteLock.writeLock().lock();
824         try {
825             // Synchronously insert into the database. Note this should be the only synchronous
826             // write operation performed by the subscription database manager. The reason is that
827             // we need to get the sub id for cache update.
828             subId = insertNewRecordIntoDatabaseSync(createDeltaContentValues(null, subInfo));
829             if (subId > 0) {
830                 mAllSubscriptionInfoInternalCache.put(subId, new SubscriptionInfoInternal
831                         .Builder(subInfo)
832                         .setId(subId).build());
833             } else {
834                 logel("insertSubscriptionInfo: Failed to insert a new subscription. subInfo="
835                         + subInfo);
836             }
837         } finally {
838             mReadWriteLock.writeLock().unlock();
839         }
840 
841         mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId));
842         return subId;
843     }
844 
845     /**
846      * Remove a subscription record from the database.
847      *
848      * @param subId The subscription id of the subscription to be deleted.
849      *
850      * @throws IllegalArgumentException If {@code subId} is invalid.
851      */
removeSubscriptionInfo(int subId)852     public void removeSubscriptionInfo(int subId) {
853         if (!mAllSubscriptionInfoInternalCache.containsKey(subId)) {
854             throw new IllegalArgumentException("subId " + subId + " is invalid.");
855         }
856 
857         mReadWriteLock.writeLock().lock();
858         try {
859             if (mContext.getContentResolver().delete(SimInfo.CONTENT_URI,
860                     SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID + "=?",
861                     new String[]{Integer.toString(subId)}) > 0) {
862                 mAllSubscriptionInfoInternalCache.remove(subId);
863             } else {
864                 logel("Failed to remove subscription with subId=" + subId);
865             }
866         } finally {
867             mReadWriteLock.writeLock().unlock();
868         }
869 
870         mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId));
871     }
872 
873     /**
874      * Update a subscription in the database (synchronously or asynchronously).
875      *
876      * @param subId The subscription id of the subscription to be updated.
877      * @param contentValues The fields to be update.
878      *
879      * @return The number of rows updated. Note if the database is configured as asynchronously
880      * update, then this will be always 1.
881      */
updateDatabase(int subId, @NonNull ContentValues contentValues)882     private int updateDatabase(int subId, @NonNull ContentValues contentValues) {
883         logv("updateDatabase: prepare to update sub " + subId);
884 
885         synchronized (this) {
886             if (!mDatabaseInitialized) {
887                 logel("updateDatabase: Database has not been initialized. Can't update database at "
888                         + "this point. contentValues=" + contentValues);
889                 return 0;
890             }
891         }
892 
893         if (mAsyncMode) {
894             // Perform the update in the handler thread asynchronously.
895             post(() -> {
896                 mContext.getContentResolver().update(Uri.withAppendedPath(
897                         SimInfo.CONTENT_URI, String.valueOf(subId)), contentValues, null, null);
898                 logv("updateDatabase: async updated subscription in the database."
899                             + " subId=" + subId + ", contentValues= " + contentValues.getValues());
900             });
901             return 1;
902         } else {
903             logv("updateDatabase: sync updated subscription in the database."
904                     + " subId=" + subId + ", contentValues= " + contentValues.getValues());
905 
906             return mContext.getContentResolver().update(Uri.withAppendedPath(
907                     SimInfo.CONTENT_URI, String.valueOf(subId)), contentValues, null, null);
908         }
909     }
910 
911     /**
912      * Update a certain field of subscription in the database. Also update the subscription cache
913      * {@link #mAllSubscriptionInfoInternalCache}.
914      *
915      * @param subId The subscription id.
916      * @param columnName The database column name from the database table {@link SimInfo}.
917      * @param newValue The new value to update the subscription info cache
918      * {@link #mAllSubscriptionInfoInternalCache}.
919      * @param builderSetMethod The {@link SubscriptionInfo.Builder} method to set a specific field
920      * when constructing the new {@link SubscriptionInfo}. This should be one of the
921      * SubscriptionInfoInternal.Builder.setXxxx method.
922      * @param <T> The type of newValue for subscription cache update.
923      *
924      * @throws IllegalArgumentException if the subscription does not exist.
925      */
writeDatabaseAndCacheHelper(int subId, @NonNull String columnName, @Nullable T newValue, BiFunction<SubscriptionInfoInternal.Builder, T, SubscriptionInfoInternal.Builder> builderSetMethod)926     private <T> void writeDatabaseAndCacheHelper(int subId, @NonNull String columnName,
927             @Nullable T newValue,
928             BiFunction<SubscriptionInfoInternal.Builder, T, SubscriptionInfoInternal.Builder>
929                     builderSetMethod) {
930         ContentValues contentValues = new ContentValues();
931 
932         // Grab the write lock so no other threads can read or write the cache.
933         mReadWriteLock.writeLock().lock();
934         try {
935             final SubscriptionInfoInternal oldSubInfo =
936                     mAllSubscriptionInfoInternalCache.get(subId);
937             if (oldSubInfo == null) {
938                 logel("Subscription doesn't exist. subId=" + subId + ", columnName=" + columnName);
939                 throw new IllegalArgumentException("Subscription doesn't exist. subId=" + subId
940                         + ", columnName=" + columnName);
941             }
942 
943             // Check if writing this field should automatically write to the rest of subscriptions
944             // in the same group.
945             final boolean syncToGroup = GROUP_SHARING_COLUMNS.contains(columnName);
946 
947             mAllSubscriptionInfoInternalCache.forEach((id, subInfo) -> {
948                 if (id == subId || (syncToGroup && !oldSubInfo.getGroupUuid().isEmpty()
949                         && oldSubInfo.getGroupUuid().equals(subInfo.getGroupUuid()))) {
950                     // Check if the new value is different from the old value in the cache.
951                     if (!Objects.equals(getSubscriptionInfoFieldByColumnName(subInfo, columnName),
952                             newValue)) {
953                         logv("writeDatabaseAndCacheHelper: subId=" + subId + ",columnName="
954                                 + columnName + ", newValue=" + newValue);
955                         // If the value is different, then we need to update the cache. Since all
956                         // fields in SubscriptionInfo are final, we need to create a new
957                         // SubscriptionInfo.
958                         SubscriptionInfoInternal.Builder builder = new SubscriptionInfoInternal
959                                 .Builder(subInfo);
960 
961                         // Apply the new value to the builder. This line is equivalent to
962                         // builder.setXxxxxx(newValue);
963                         builder = builderSetMethod.apply(builder, newValue);
964 
965                         // Prepare the content value for update.
966                         contentValues.putObject(columnName, newValue);
967                         if (updateDatabase(id, contentValues) > 0) {
968                             // Update the subscription database cache.
969                             mAllSubscriptionInfoInternalCache.put(id, builder.build());
970                             mCallback.invokeFromExecutor(()
971                                     -> mCallback.onSubscriptionChanged(subId));
972                         }
973                     }
974                 }
975             });
976         } finally {
977             mReadWriteLock.writeLock().unlock();
978         }
979     }
980 
981     /**
982      * Update the database with the {@link SubscriptionInfoInternal}, and also update the cache.
983      *
984      * @param newSubInfo The new {@link SubscriptionInfoInternal}.
985      *
986      * @throws IllegalArgumentException if the subscription does not exist.
987      */
updateSubscription(@onNull SubscriptionInfoInternal newSubInfo)988     public void updateSubscription(@NonNull SubscriptionInfoInternal newSubInfo) {
989         Objects.requireNonNull(newSubInfo);
990 
991         // Grab the write lock so no other threads can read or write the cache.
992         mReadWriteLock.writeLock().lock();
993         try {
994             int subId = newSubInfo.getSubscriptionId();
995             SubscriptionInfoInternal oldSubInfo = mAllSubscriptionInfoInternalCache.get(
996                     newSubInfo.getSubscriptionId());
997             if (oldSubInfo == null) {
998                 throw new IllegalArgumentException("updateSubscription: subscription does not "
999                         + "exist. subId=" + subId);
1000             }
1001             if (oldSubInfo.equals(newSubInfo)) return;
1002 
1003             if (updateDatabase(subId, createDeltaContentValues(oldSubInfo, newSubInfo)) > 0) {
1004                 mAllSubscriptionInfoInternalCache.put(subId, newSubInfo);
1005                 mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId));
1006             }
1007         } finally {
1008             mReadWriteLock.writeLock().unlock();
1009         }
1010     }
1011 
1012     /**
1013      * Set the ICCID of the SIM that is associated with the subscription.
1014      *
1015      * @param subId Subscription id.
1016      * @param iccId The ICCID of the SIM that is associated with this subscription.
1017      *
1018      * @throws IllegalArgumentException if the subscription does not exist.
1019      */
setIccId(int subId, @NonNull String iccId)1020     public void setIccId(int subId, @NonNull String iccId) {
1021         Objects.requireNonNull(iccId);
1022         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ICC_ID, iccId,
1023                 SubscriptionInfoInternal.Builder::setIccId);
1024     }
1025 
1026     /**
1027      * Set the SIM index of the slot that currently contains the subscription. Set to
1028      * {@link SubscriptionManager#INVALID_SIM_SLOT_INDEX} if the subscription is inactive.
1029      *
1030      * @param subId Subscription id.
1031      * @param simSlotIndex The SIM slot index.
1032      *
1033      * @throws IllegalArgumentException if the subscription does not exist.
1034      */
setSimSlotIndex(int subId, int simSlotIndex)1035     public void setSimSlotIndex(int subId, int simSlotIndex) {
1036         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_SIM_SLOT_INDEX, simSlotIndex,
1037                 SubscriptionInfoInternal.Builder::setSimSlotIndex);
1038     }
1039 
1040     /**
1041      * Set the name displayed to the user that identifies this subscription. This name is used
1042      * in Settings page and can be renamed by the user.
1043      *
1044      * @param subId Subscription id.
1045      * @param displayName The display name.
1046      *
1047      * @throws IllegalArgumentException if the subscription does not exist.
1048      */
setDisplayName(int subId, @NonNull String displayName)1049     public void setDisplayName(int subId, @NonNull String displayName) {
1050         Objects.requireNonNull(displayName);
1051         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_DISPLAY_NAME, displayName,
1052                 SubscriptionInfoInternal.Builder::setDisplayName);
1053     }
1054 
1055     /**
1056      * Set the name displayed to the user that identifies subscription provider name. This name
1057      * is the SPN displayed in status bar and many other places. Can't be renamed by the user.
1058      *
1059      * @param subId Subscription id.
1060      * @param carrierName The carrier name.
1061      *
1062      * @throws IllegalArgumentException if the subscription does not exist.
1063      */
setCarrierName(int subId, @NonNull String carrierName)1064     public void setCarrierName(int subId, @NonNull String carrierName) {
1065         Objects.requireNonNull(carrierName);
1066         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CARRIER_NAME, carrierName,
1067                 SubscriptionInfoInternal.Builder::setCarrierName);
1068     }
1069 
1070     /**
1071      * Set the source of the display name.
1072      *
1073      * @param subId Subscription id.
1074      * @param displayNameSource The source of the display name.
1075      *
1076      * @throws IllegalArgumentException if the subscription does not exist.
1077      *
1078      * @see SubscriptionInfo#getDisplayName()
1079      */
setDisplayNameSource(int subId, @SimDisplayNameSource int displayNameSource)1080     public void setDisplayNameSource(int subId, @SimDisplayNameSource int displayNameSource) {
1081         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_NAME_SOURCE, displayNameSource,
1082                 SubscriptionInfoInternal.Builder::setDisplayNameSource);
1083     }
1084 
1085     /**
1086      * Set the color to be used for tinting the icon when displaying to the user.
1087      *
1088      * @param subId Subscription id.
1089      * @param iconTint The color to be used for tinting the icon when displaying to the user.
1090      *
1091      * @throws IllegalArgumentException if the subscription does not exist.
1092      */
setIconTint(int subId, @ColorInt int iconTint)1093     public void setIconTint(int subId, @ColorInt int iconTint) {
1094         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_COLOR, iconTint,
1095                 SubscriptionInfoInternal.Builder::setIconTint);
1096     }
1097 
1098     /**
1099      * Set the number presented to the user identify this subscription.
1100      *
1101      * @param subId Subscription id.
1102      * @param number the number presented to the user identify this subscription.
1103      *
1104      * @throws IllegalArgumentException if the subscription does not exist.
1105      */
setNumber(int subId, @NonNull String number)1106     public void setNumber(int subId, @NonNull String number) {
1107         Objects.requireNonNull(number);
1108         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_NUMBER, number,
1109                 SubscriptionInfoInternal.Builder::setNumber);
1110     }
1111 
1112     /**
1113      * Set whether user enables data roaming for this subscription or not.
1114      *
1115      * @param subId Subscription id.
1116      * @param dataRoaming Data roaming mode. Either
1117      * {@link SubscriptionManager#DATA_ROAMING_ENABLE} or
1118      * {@link SubscriptionManager#DATA_ROAMING_DISABLE}
1119      *
1120      * @throws IllegalArgumentException if the subscription does not exist.
1121      */
setDataRoaming(int subId, @DataRoamingMode int dataRoaming)1122     public void setDataRoaming(int subId, @DataRoamingMode int dataRoaming) {
1123         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_DATA_ROAMING, dataRoaming,
1124                 SubscriptionInfoInternal.Builder::setDataRoaming);
1125     }
1126 
1127     /**
1128      * Set the mobile country code.
1129      *
1130      * @param subId Subscription id.
1131      * @param mcc The mobile country code.
1132      *
1133      * @throws IllegalArgumentException if the subscription does not exist.
1134      */
setMcc(int subId, @NonNull String mcc)1135     public void setMcc(int subId, @NonNull String mcc) {
1136         Objects.requireNonNull(mcc);
1137         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_MCC_STRING, mcc,
1138                 SubscriptionInfoInternal.Builder::setMcc);
1139     }
1140 
1141     /**
1142      * Set the mobile network code.
1143      *
1144      * @param subId Subscription id.
1145      * @param mnc Mobile network code.
1146      *
1147      * @throws IllegalArgumentException if the subscription does not exist.
1148      */
setMnc(int subId, @NonNull String mnc)1149     public void setMnc(int subId, @NonNull String mnc) {
1150         Objects.requireNonNull(mnc);
1151         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_MNC_STRING, mnc,
1152                 SubscriptionInfoInternal.Builder::setMnc);
1153     }
1154 
1155     /**
1156      * Set EHPLMNs associated with the subscription.
1157      *
1158      * @param subId Subscription id.
1159      * @param ehplmns EHPLMNs associated with the subscription.
1160      *
1161      * @throws IllegalArgumentException if the subscription does not exist.
1162      */
setEhplmns(int subId, @NonNull String[] ehplmns)1163     public void setEhplmns(int subId, @NonNull String[] ehplmns) {
1164         Objects.requireNonNull(ehplmns);
1165         setEhplmns(subId, Arrays.stream(ehplmns)
1166                 .filter(Predicate.not(TextUtils::isEmpty))
1167                 .collect(Collectors.joining(",")));
1168     }
1169 
1170     /**
1171      * Set EHPLMNs associated with the subscription.
1172      *
1173      * @param subId Subscription id.
1174      * @param ehplmns EHPLMNs associated with the subscription.
1175      *
1176      * @throws IllegalArgumentException if the subscription does not exist.
1177      */
setEhplmns(int subId, @NonNull String ehplmns)1178     public void setEhplmns(int subId, @NonNull String ehplmns) {
1179         Objects.requireNonNull(ehplmns);
1180         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_EHPLMNS, ehplmns,
1181                 SubscriptionInfoInternal.Builder::setEhplmns);
1182     }
1183 
1184     /**
1185      * Set HPLMNs associated with the subscription.
1186      *
1187      * @param subId Subscription id.
1188      * @param hplmns HPLMNs associated with the subscription.
1189      *
1190      * @throws IllegalArgumentException if the subscription does not exist.
1191      */
setHplmns(int subId, @NonNull String[] hplmns)1192     public void setHplmns(int subId, @NonNull String[] hplmns) {
1193         Objects.requireNonNull(hplmns);
1194         setHplmns(subId, Arrays.stream(hplmns)
1195                 .filter(Predicate.not(TextUtils::isEmpty))
1196                 .collect(Collectors.joining(",")));
1197     }
1198 
1199     /**
1200      * Set HPLMNs associated with the subscription.
1201      *
1202      * @param subId Subscription id.
1203      * @param hplmns HPLMNs associated with the subscription.
1204      *
1205      * @throws IllegalArgumentException if the subscription does not exist.
1206      */
setHplmns(int subId, @NonNull String hplmns)1207     public void setHplmns(int subId, @NonNull String hplmns) {
1208         Objects.requireNonNull(hplmns);
1209         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_HPLMNS, hplmns,
1210                 SubscriptionInfoInternal.Builder::setHplmns);
1211     }
1212 
1213     /**
1214      * Set whether the subscription is from eSIM or not.
1215      *
1216      * @param subId Subscription id.
1217      * @param isEmbedded if the subscription is from eSIM.
1218      *
1219      * @throws IllegalArgumentException if the subscription does not exist.
1220      */
setEmbedded(int subId, int isEmbedded)1221     public void setEmbedded(int subId, int isEmbedded) {
1222         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_EMBEDDED, isEmbedded,
1223                 SubscriptionInfoInternal.Builder::setEmbedded);
1224     }
1225 
1226     /**
1227      * Set whether the subscription is from eSIM or not.
1228      *
1229      * @param subId Subscription id.
1230      * @param isEmbedded {@code true} if the subscription is from eSIM.
1231      *
1232      * @throws IllegalArgumentException if the subscription does not exist.
1233      */
setEmbedded(int subId, boolean isEmbedded)1234     public void setEmbedded(int subId, boolean isEmbedded) {
1235         setEmbedded(subId, isEmbedded ? 1 : 0);
1236     }
1237 
1238     /**
1239      * Set the card string of the SIM card. This is usually the ICCID or EID.
1240      *
1241      * @param subId Subscription id.
1242      * @param cardString The card string of the SIM card.
1243      *
1244      * @throws IllegalArgumentException if the subscription does not exist.
1245      *
1246      * @see SubscriptionInfo#getCardString()
1247      */
setCardString(int subId, @NonNull String cardString)1248     public void setCardString(int subId, @NonNull String cardString) {
1249         Objects.requireNonNull(cardString);
1250         // Also update the public card id.
1251         setCardId(subId, mUiccController.convertToPublicCardId(cardString));
1252         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CARD_ID, cardString,
1253                 SubscriptionInfoInternal.Builder::setCardString);
1254     }
1255 
1256     /**
1257      * Set the card id. This is the non-PII card id converted from
1258      * {@link SubscriptionInfoInternal#getCardString()}. This field only exists in
1259      * {@link SubscriptionInfo}, but not the database.
1260      *
1261      * @param subId Subscription id.
1262      * @param cardId The card id.
1263      *
1264      * @throws IllegalArgumentException if the subscription does not exist.
1265      */
setCardId(int subId, int cardId)1266     public void setCardId(int subId, int cardId) {
1267         // card id does not have a corresponding SimInfo column. So we only update the cache.
1268 
1269         // Grab the write lock so no other threads can read or write the cache.
1270         mReadWriteLock.writeLock().lock();
1271         try {
1272             SubscriptionInfoInternal subInfoCache = mAllSubscriptionInfoInternalCache.get(subId);
1273             if (subInfoCache == null) {
1274                 throw new IllegalArgumentException("setCardId: Subscription doesn't exist. subId="
1275                         + subId);
1276             }
1277             mAllSubscriptionInfoInternalCache.put(subId,
1278                     new SubscriptionInfoInternal.Builder(subInfoCache)
1279                             .setCardId(cardId).build());
1280         } finally {
1281             mReadWriteLock.writeLock().unlock();
1282         }
1283     }
1284 
1285     /**
1286      * Set the native access rules for this subscription, if it is embedded and defines any.
1287      * This does not include access rules for non-embedded subscriptions.
1288      *
1289      * @param subId Subscription id.
1290      * @param nativeAccessRules The native access rules for this subscription.
1291      *
1292      * @throws IllegalArgumentException if the subscription does not exist.
1293      */
setNativeAccessRules(int subId, @NonNull byte[] nativeAccessRules)1294     public void setNativeAccessRules(int subId, @NonNull byte[] nativeAccessRules) {
1295         Objects.requireNonNull(nativeAccessRules);
1296         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES, nativeAccessRules,
1297                 SubscriptionInfoInternal.Builder::setNativeAccessRules);
1298     }
1299 
1300     /**
1301      * Set the carrier certificates for this subscription that are saved in carrier configs.
1302      * This does not include access rules from the Uicc, whether embedded or non-embedded.
1303      *
1304      * @param subId Subscription id.
1305      * @param carrierConfigAccessRules The carrier certificates for this subscription.
1306      *
1307      * @throws IllegalArgumentException if the subscription does not exist.
1308      */
setCarrierConfigAccessRules(int subId, @NonNull byte[] carrierConfigAccessRules)1309     public void setCarrierConfigAccessRules(int subId, @NonNull byte[] carrierConfigAccessRules) {
1310         Objects.requireNonNull(carrierConfigAccessRules);
1311         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS,
1312                 carrierConfigAccessRules,
1313                 SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules);
1314     }
1315 
1316     /**
1317      * Set the carrier certificates for this subscription that are saved in carrier configs.
1318      * This does not include access rules from the Uicc, whether embedded or non-embedded.
1319      *
1320      * @param subId Subscription id.
1321      * @param carrierConfigAccessRules The carrier certificates for this subscription.
1322      *
1323      * @throws IllegalArgumentException if the subscription does not exist.
1324      */
setCarrierConfigAccessRules(int subId, @NonNull UiccAccessRule[] carrierConfigAccessRules)1325     public void setCarrierConfigAccessRules(int subId,
1326             @NonNull UiccAccessRule[] carrierConfigAccessRules) {
1327         Objects.requireNonNull(carrierConfigAccessRules);
1328         byte[] carrierConfigAccessRulesBytes = UiccAccessRule.encodeRules(carrierConfigAccessRules);
1329         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS,
1330                 carrierConfigAccessRulesBytes,
1331                 SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules);
1332     }
1333 
1334     /**
1335      * Set whether an embedded subscription is on a removable card. Such subscriptions are
1336      * marked inaccessible as soon as the current card is removed. Otherwise, they will remain
1337      * accessible unless explicitly deleted. Only meaningful for embedded subscription.
1338      *
1339      * @param subId Subscription id.
1340      * @param isRemovableEmbedded if the subscription is from the removable embedded SIM.
1341      *
1342      * @throws IllegalArgumentException if the subscription does not exist.
1343      */
setRemovableEmbedded(int subId, int isRemovableEmbedded)1344     public void setRemovableEmbedded(int subId, int isRemovableEmbedded) {
1345         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_REMOVABLE, isRemovableEmbedded,
1346                 SubscriptionInfoInternal.Builder::setRemovableEmbedded);
1347     }
1348 
1349     /**
1350      * Set whether cell broadcast extreme threat alert is enabled by the user or not.
1351      *
1352      * @param subId Subscription id.
1353      * @param isExtremeThreatAlertEnabled whether cell broadcast extreme threat alert is enabled by
1354      * the user or not.
1355      *
1356      * @throws IllegalArgumentException if the subscription does not exist.
1357      */
setCellBroadcastExtremeThreatAlertEnabled(int subId, int isExtremeThreatAlertEnabled)1358     public void setCellBroadcastExtremeThreatAlertEnabled(int subId,
1359             int isExtremeThreatAlertEnabled) {
1360         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT,
1361                 isExtremeThreatAlertEnabled,
1362                 SubscriptionInfoInternal.Builder::setCellBroadcastExtremeThreatAlertEnabled);
1363     }
1364 
1365     /**
1366      * Set whether cell broadcast severe threat alert is enabled by the user or not.
1367      *
1368      * @param subId Subscription id.
1369      * @param isSevereThreatAlertEnabled whether cell broadcast severe threat alert is enabled by
1370      * the user or not.
1371      *
1372      * @throws IllegalArgumentException if the subscription does not exist.
1373      */
setCellBroadcastSevereThreatAlertEnabled(int subId, int isSevereThreatAlertEnabled)1374     public void setCellBroadcastSevereThreatAlertEnabled(int subId,
1375             int isSevereThreatAlertEnabled) {
1376         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT,
1377                 isSevereThreatAlertEnabled,
1378                 SubscriptionInfoInternal.Builder::setCellBroadcastSevereThreatAlertEnabled);
1379     }
1380 
1381     /**
1382      * Set whether cell broadcast amber alert is enabled by the user or not.
1383      *
1384      * @param subId Subscription id.
1385      * @param isAmberAlertEnabled whether cell broadcast amber alert is enabled by
1386      * the user or not.
1387      *
1388      * @throws IllegalArgumentException if the subscription does not exist.
1389      */
setCellBroadcastAmberAlertEnabled(int subId, int isAmberAlertEnabled)1390     public void setCellBroadcastAmberAlertEnabled(int subId, int isAmberAlertEnabled) {
1391         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_AMBER_ALERT, isAmberAlertEnabled,
1392                 SubscriptionInfoInternal.Builder::setCellBroadcastAmberAlertEnabled);
1393     }
1394 
1395     /**
1396      * Set whether cell broadcast emergency alert is enabled by the user or not.
1397      *
1398      * @param subId Subscription id.
1399      * @param isEmergencyAlertEnabled whether cell broadcast emergency alert is enabled by
1400      * the user or not.
1401      *
1402      * @throws IllegalArgumentException if the subscription does not exist.
1403      */
setCellBroadcastEmergencyAlertEnabled(int subId, int isEmergencyAlertEnabled)1404     public void setCellBroadcastEmergencyAlertEnabled(int subId,
1405             int isEmergencyAlertEnabled) {
1406         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_EMERGENCY_ALERT,
1407                 isEmergencyAlertEnabled,
1408                 SubscriptionInfoInternal.Builder::setCellBroadcastEmergencyAlertEnabled);
1409     }
1410 
1411     /**
1412      * Set cell broadcast alert sound duration.
1413      *
1414      * @param subId Subscription id.
1415      * @param alertSoundDuration Alert sound duration in seconds.
1416      *
1417      * @throws IllegalArgumentException if the subscription does not exist.
1418      */
setCellBroadcastAlertSoundDuration(int subId, int alertSoundDuration)1419     public void setCellBroadcastAlertSoundDuration(int subId, int alertSoundDuration) {
1420         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ALERT_SOUND_DURATION,
1421                 alertSoundDuration,
1422                 SubscriptionInfoInternal.Builder::setCellBroadcastAlertSoundDuration);
1423     }
1424 
1425     /**
1426      * Set cell broadcast alert reminder interval.
1427      *
1428      * @param subId Subscription id.
1429      * @param reminderInterval Alert reminder interval in milliseconds.
1430      *
1431      * @throws IllegalArgumentException if the subscription does not exist.
1432      */
setCellBroadcastAlertReminderInterval(int subId, int reminderInterval)1433     public void setCellBroadcastAlertReminderInterval(int subId, int reminderInterval) {
1434         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL,
1435                 reminderInterval,
1436                 SubscriptionInfoInternal.Builder::setCellBroadcastAlertReminderInterval);
1437     }
1438 
1439     /**
1440      * Set whether cell broadcast alert vibration is enabled by the user or not.
1441      *
1442      * @param subId Subscription id.
1443      * @param isAlertVibrationEnabled whether cell broadcast alert vibration is enabled by the user
1444      * or not.
1445      *
1446      * @throws IllegalArgumentException if the subscription does not exist.
1447      */
setCellBroadcastAlertVibrationEnabled(int subId, int isAlertVibrationEnabled)1448     public void setCellBroadcastAlertVibrationEnabled(int subId, int isAlertVibrationEnabled) {
1449         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ALERT_VIBRATE, isAlertVibrationEnabled,
1450                 SubscriptionInfoInternal.Builder::setCellBroadcastAlertVibrationEnabled);
1451     }
1452 
1453     /**
1454      * Set whether cell broadcast alert speech is enabled by the user or not.
1455      *
1456      * @param subId Subscription id.
1457      * @param isAlertSpeechEnabled whether cell broadcast alert speech is enabled by the user or
1458      * not.
1459      *
1460      * @throws IllegalArgumentException if the subscription does not exist.
1461      */
setCellBroadcastAlertSpeechEnabled(int subId, int isAlertSpeechEnabled)1462     public void setCellBroadcastAlertSpeechEnabled(int subId, int isAlertSpeechEnabled) {
1463         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ALERT_SPEECH, isAlertSpeechEnabled,
1464                 SubscriptionInfoInternal.Builder::setCellBroadcastAlertSpeechEnabled);
1465     }
1466 
1467     /**
1468      * Set whether ETWS test alert is enabled by the user or not.
1469      *
1470      * @param subId Subscription id.
1471      * @param isEtwsTestAlertEnabled whether cell broadcast ETWS test alert is enabled by the user
1472      * or not.
1473      *
1474      * @throws IllegalArgumentException if the subscription does not exist.
1475      */
setCellBroadcastEtwsTestAlertEnabled(int subId, int isEtwsTestAlertEnabled)1476     public void setCellBroadcastEtwsTestAlertEnabled(int subId, int isEtwsTestAlertEnabled) {
1477         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ETWS_TEST_ALERT,
1478                 isEtwsTestAlertEnabled,
1479                 SubscriptionInfoInternal.Builder::setCellBroadcastEtwsTestAlertEnabled);
1480     }
1481 
1482     /**
1483      * Set whether area info message is enabled by the user or not.
1484      *
1485      * @param subId Subscription id.
1486      * @param isAreaInfoMessageEnabled whether cell broadcast area info message is enabled by the
1487      * user or not.
1488      *
1489      * @throws IllegalArgumentException if the subscription does not exist.
1490      */
setCellBroadcastAreaInfoMessageEnabled(int subId, int isAreaInfoMessageEnabled)1491     public void setCellBroadcastAreaInfoMessageEnabled(int subId, int isAreaInfoMessageEnabled) {
1492         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_CHANNEL_50_ALERT,
1493                 isAreaInfoMessageEnabled,
1494                 SubscriptionInfoInternal.Builder::setCellBroadcastAreaInfoMessageEnabled);
1495     }
1496 
1497     /**
1498      * Set whether cell broadcast test alert is enabled by the user or not.
1499      *
1500      * @param subId Subscription id.
1501      * @param isTestAlertEnabled whether cell broadcast test alert is enabled by the user or not.
1502      *
1503      * @throws IllegalArgumentException if the subscription does not exist.
1504      */
setCellBroadcastTestAlertEnabled(int subId, int isTestAlertEnabled)1505     public void setCellBroadcastTestAlertEnabled(int subId, int isTestAlertEnabled) {
1506         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_CMAS_TEST_ALERT, isTestAlertEnabled,
1507                 SubscriptionInfoInternal.Builder::setCellBroadcastTestAlertEnabled);
1508     }
1509 
1510     /**
1511      * Set whether cell broadcast opt-out dialog should be shown or not.
1512      *
1513      * @param subId Subscription id.
1514      * @param isOptOutDialogEnabled whether cell broadcast opt-out dialog should be shown or not.
1515      *
1516      * @throws IllegalArgumentException if the subscription does not exist.
1517      */
setCellBroadcastOptOutDialogEnabled(int subId, int isOptOutDialogEnabled)1518     public void setCellBroadcastOptOutDialogEnabled(int subId, int isOptOutDialogEnabled) {
1519         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_OPT_OUT_DIALOG, isOptOutDialogEnabled,
1520                 SubscriptionInfoInternal.Builder::setCellBroadcastOptOutDialogEnabled);
1521     }
1522 
1523     /**
1524      * Set whether enhanced 4G mode is enabled by the user or not.
1525      *
1526      * @param subId Subscription id.
1527      * @param isEnhanced4GModeEnabled whether enhanced 4G mode is enabled by the user or not.
1528      *
1529      * @throws IllegalArgumentException if the subscription does not exist.
1530      */
setEnhanced4GModeEnabled(int subId, int isEnhanced4GModeEnabled)1531     public void setEnhanced4GModeEnabled(int subId, int isEnhanced4GModeEnabled) {
1532         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED,
1533                 isEnhanced4GModeEnabled,
1534                 SubscriptionInfoInternal.Builder::setEnhanced4GModeEnabled);
1535     }
1536 
1537     /**
1538      * Set whether video telephony is enabled by the user or not.
1539      *
1540      * @param subId Subscription id.
1541      * @param isVideoTelephonyEnabled whether video telephony is enabled by the user or not.
1542      *
1543      * @throws IllegalArgumentException if the subscription does not exist.
1544      */
setVideoTelephonyEnabled(int subId, int isVideoTelephonyEnabled)1545     public void setVideoTelephonyEnabled(int subId, int isVideoTelephonyEnabled) {
1546         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_VT_IMS_ENABLED, isVideoTelephonyEnabled,
1547                 SubscriptionInfoInternal.Builder::setVideoTelephonyEnabled);
1548     }
1549 
1550     /**
1551      * Set whether Wi-Fi calling is enabled by the user or not when the device is not roaming.
1552      *
1553      * @param subId Subscription id.
1554      * @param isWifiCallingEnabled whether Wi-Fi calling is enabled by the user or not when the
1555      * device is not roaming.
1556      *
1557      * @throws IllegalArgumentException if the subscription does not exist.
1558      */
setWifiCallingEnabled(int subId, int isWifiCallingEnabled)1559     public void setWifiCallingEnabled(int subId, int isWifiCallingEnabled) {
1560         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ENABLED, isWifiCallingEnabled,
1561                 SubscriptionInfoInternal.Builder::setWifiCallingEnabled);
1562     }
1563 
1564     /**
1565      * Set Wi-Fi calling mode when the device is not roaming.
1566      *
1567      * @param subId Subscription id.
1568      * @param wifiCallingMode Wi-Fi calling mode when the device is not roaming.
1569      *
1570      * @throws IllegalArgumentException if the subscription does not exist.
1571      */
setWifiCallingMode(int subId, @ImsMmTelManager.WiFiCallingMode int wifiCallingMode)1572     public void setWifiCallingMode(int subId,
1573             @ImsMmTelManager.WiFiCallingMode int wifiCallingMode) {
1574         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_MODE, wifiCallingMode,
1575                 SubscriptionInfoInternal.Builder::setWifiCallingMode);
1576     }
1577 
1578     /**
1579      * Set Wi-Fi calling mode when the device is roaming.
1580      *
1581      * @param subId Subscription id.
1582      * @param wifiCallingModeForRoaming Wi-Fi calling mode when the device is roaming.
1583      *
1584      * @throws IllegalArgumentException if the subscription does not exist.
1585      */
setWifiCallingModeForRoaming(int subId, @ImsMmTelManager.WiFiCallingMode int wifiCallingModeForRoaming)1586     public void setWifiCallingModeForRoaming(int subId,
1587             @ImsMmTelManager.WiFiCallingMode int wifiCallingModeForRoaming) {
1588         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ROAMING_MODE,
1589                 wifiCallingModeForRoaming,
1590                 SubscriptionInfoInternal.Builder::setWifiCallingModeForRoaming);
1591     }
1592 
1593     /**
1594      * Set whether Wi-Fi calling is enabled by the user or not when the device is roaming.
1595      *
1596      * @param subId Subscription id.
1597      * @param isWifiCallingEnabledForRoaming whether Wi-Fi calling is enabled by the user or not
1598      * when the device is roaming.
1599      *
1600      * @throws IllegalArgumentException if the subscription does not exist.
1601      */
setWifiCallingEnabledForRoaming(int subId, int isWifiCallingEnabledForRoaming)1602     public void setWifiCallingEnabledForRoaming(int subId, int isWifiCallingEnabledForRoaming) {
1603         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED,
1604                 isWifiCallingEnabledForRoaming,
1605                 SubscriptionInfoInternal.Builder::setWifiCallingEnabledForRoaming);
1606     }
1607 
1608     /**
1609      * Set whether the subscription is opportunistic or not.
1610      *
1611      * @param subId Subscription id.
1612      * @param isOpportunistic if the subscription is opportunistic.
1613      *
1614      * @throws IllegalArgumentException if the subscription does not exist.
1615      */
setOpportunistic(int subId, boolean isOpportunistic)1616     public void setOpportunistic(int subId, boolean isOpportunistic) {
1617         setOpportunistic(subId, isOpportunistic ? 1 : 0);
1618     }
1619 
1620     /**
1621      * Set whether the subscription is opportunistic or not.
1622      *
1623      * @param subId Subscription id.
1624      * @param isOpportunistic if the subscription is opportunistic.
1625      *
1626      * @throws IllegalArgumentException if the subscription does not exist.
1627      */
setOpportunistic(int subId, int isOpportunistic)1628     public void setOpportunistic(int subId, int isOpportunistic) {
1629         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_OPPORTUNISTIC, isOpportunistic,
1630                 SubscriptionInfoInternal.Builder::setOpportunistic);
1631     }
1632 
1633     /**
1634      * Set the group UUID of the subscription group.
1635      *
1636      * @param subId Subscription id.
1637      * @param groupUuid The group UUID.
1638      *
1639      * @throws IllegalArgumentException if the subscription does not exist.
1640      *
1641      * @see SubscriptionInfo#getGroupUuid()
1642      */
setGroupUuid(int subId, @NonNull String groupUuid)1643     public void setGroupUuid(int subId, @NonNull String groupUuid) {
1644         Objects.requireNonNull(groupUuid);
1645         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_GROUP_UUID, groupUuid,
1646                 SubscriptionInfoInternal.Builder::setGroupUuid);
1647     }
1648 
1649     /**
1650      * Set the ISO Country code for the subscription's provider.
1651      *
1652      * @param subId Subscription id.
1653      * @param countryIso The ISO country code for the subscription's provider.
1654      *
1655      * @throws IllegalArgumentException if the subscription does not exist.
1656      */
setCountryIso(int subId, @NonNull String countryIso)1657     public void setCountryIso(int subId, @NonNull String countryIso) {
1658         Objects.requireNonNull(countryIso);
1659         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ISO_COUNTRY_CODE, countryIso,
1660                 SubscriptionInfoInternal.Builder::setCountryIso);
1661     }
1662 
1663     /**
1664      * Set the subscription carrier id.
1665      *
1666      * @param subId Subscription id.
1667      * @param carrierId The carrier id.
1668      *
1669      * @throws IllegalArgumentException if the subscription does not exist.
1670      *
1671      * @see TelephonyManager#getSimCarrierId()
1672      */
setCarrierId(int subId, int carrierId)1673     public void setCarrierId(int subId, int carrierId) {
1674         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CARRIER_ID, carrierId,
1675                 SubscriptionInfoInternal.Builder::setCarrierId);
1676     }
1677 
1678     /**
1679      * Set the profile class populated from the profile metadata if present.
1680      *
1681      * @param subId Subscription id.
1682      * @param profileClass the profile class populated from the profile metadata if present.
1683      *
1684      * @throws IllegalArgumentException if the subscription does not exist.
1685      *
1686      * @see SubscriptionInfo#getProfileClass()
1687      */
setProfileClass(int subId, @ProfileClass int profileClass)1688     public void setProfileClass(int subId, @ProfileClass int profileClass) {
1689         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_PROFILE_CLASS, profileClass,
1690                 SubscriptionInfoInternal.Builder::setProfileClass);
1691     }
1692 
1693     /**
1694      * Set the subscription type.
1695      *
1696      * @param subId Subscription id.
1697      * @param type Subscription type.
1698      *
1699      * @throws IllegalArgumentException if the subscription does not exist.
1700      */
setSubscriptionType(int subId, @SubscriptionType int type)1701     public void setSubscriptionType(int subId, @SubscriptionType int type) {
1702         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_SUBSCRIPTION_TYPE, type,
1703                 SubscriptionInfoInternal.Builder::setType);
1704     }
1705 
1706     /**
1707      * Set the owner package of group the subscription belongs to.
1708      *
1709      * @param subId Subscription id.
1710      * @param groupOwner Owner package of group the subscription belongs to.
1711      *
1712      * @throws IllegalArgumentException if the subscription does not exist.
1713      */
setGroupOwner(int subId, @NonNull String groupOwner)1714     public void setGroupOwner(int subId, @NonNull String groupOwner) {
1715         Objects.requireNonNull(groupOwner);
1716         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_GROUP_OWNER, groupOwner,
1717                 SubscriptionInfoInternal.Builder::setGroupOwner);
1718     }
1719 
1720     /**
1721      * Set the enabled mobile data policies.
1722      *
1723      * @param subId Subscription id.
1724      * @param enabledMobileDataPolicies The enabled mobile data policies.
1725      *
1726      * @throws IllegalArgumentException if the subscription does not exist.
1727      */
setEnabledMobileDataPolicies(int subId, @NonNull String enabledMobileDataPolicies)1728     public void setEnabledMobileDataPolicies(int subId, @NonNull String enabledMobileDataPolicies) {
1729         Objects.requireNonNull(enabledMobileDataPolicies);
1730         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES,
1731                 enabledMobileDataPolicies,
1732                 SubscriptionInfoInternal.Builder::setEnabledMobileDataPolicies);
1733     }
1734 
1735     /**
1736      * Set the IMSI (International Mobile Subscriber Identity) of the subscription.
1737      *
1738      * @param subId Subscription id.
1739      * @param imsi The IMSI.
1740      *
1741      * @throws IllegalArgumentException if the subscription does not exist.
1742      */
setImsi(int subId, @NonNull String imsi)1743     public void setImsi(int subId, @NonNull String imsi) {
1744         Objects.requireNonNull(imsi);
1745         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IMSI, imsi,
1746                 SubscriptionInfoInternal.Builder::setImsi);
1747     }
1748 
1749     /**
1750      * Set whether Uicc applications are configured to enable or not.
1751      *
1752      * @param subId Subscription id.
1753      * @param areUiccApplicationsEnabled if Uicc applications are configured to enable.
1754      *
1755      * @throws IllegalArgumentException if the subscription does not exist.
1756      */
setUiccApplicationsEnabled(int subId, boolean areUiccApplicationsEnabled)1757     public void setUiccApplicationsEnabled(int subId, boolean areUiccApplicationsEnabled) {
1758         setUiccApplicationsEnabled(subId, areUiccApplicationsEnabled ? 1 : 0);
1759     }
1760 
1761     /**
1762      * Set whether Uicc applications are configured to enable or not.
1763      *
1764      * @param subId Subscription id.
1765      * @param areUiccApplicationsEnabled if Uicc applications are configured to enable.
1766      *
1767      * @throws IllegalArgumentException if the subscription does not exist.
1768      */
setUiccApplicationsEnabled(int subId, int areUiccApplicationsEnabled)1769     public void setUiccApplicationsEnabled(int subId, int areUiccApplicationsEnabled) {
1770         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED,
1771                 areUiccApplicationsEnabled,
1772                 SubscriptionInfoInternal.Builder::setUiccApplicationsEnabled);
1773     }
1774 
1775     /**
1776      * Set whether the user has enabled IMS RCS User Capability Exchange (UCE) for this
1777      * subscription.
1778      *
1779      * @param subId Subscription id.
1780      * @param isRcsUceEnabled If the user enabled RCS UCE for this subscription.
1781      *
1782      * @throws IllegalArgumentException if the subscription does not exist.
1783      */
setRcsUceEnabled(int subId, int isRcsUceEnabled)1784     public void setRcsUceEnabled(int subId, int isRcsUceEnabled) {
1785         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, isRcsUceEnabled,
1786                 SubscriptionInfoInternal.Builder::setRcsUceEnabled);
1787     }
1788 
1789     /**
1790      * Set whether the user has enabled cross SIM calling for this subscription.
1791      *
1792      * @param subId Subscription id.
1793      * @param isCrossSimCallingEnabled If the user enabled cross SIM calling for this
1794      * subscription.
1795      *
1796      * @throws IllegalArgumentException if the subscription does not exist.
1797      */
setCrossSimCallingEnabled(int subId, int isCrossSimCallingEnabled)1798     public void setCrossSimCallingEnabled(int subId, int isCrossSimCallingEnabled) {
1799         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED,
1800                 isCrossSimCallingEnabled,
1801                 SubscriptionInfoInternal.Builder::setCrossSimCallingEnabled);
1802     }
1803 
1804     /**
1805      * Set the RCS config for this subscription.
1806      *
1807      * @param subId Subscription id.
1808      * @param rcsConfig The RCS config for this subscription.
1809      *
1810      * @throws IllegalArgumentException if the subscription does not exist.
1811      */
setRcsConfig(int subId, @NonNull byte[] rcsConfig)1812     public void setRcsConfig(int subId, @NonNull byte[] rcsConfig) {
1813         Objects.requireNonNull(rcsConfig);
1814         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_RCS_CONFIG, rcsConfig,
1815                 SubscriptionInfoInternal.Builder::setRcsConfig);
1816     }
1817 
1818     /**
1819      * Set the allowed network types for reasons.
1820      *
1821      * @param subId Subscription id.
1822      * @param allowedNetworkTypesForReasons The allowed network types for reasons in string
1823      * format. The format is "[reason]=[network types bitmask], [reason]=[network types bitmask],
1824      * ...". For example, "user=1239287394, thermal=298791239, carrier=3456812312".
1825      *
1826      * @throws IllegalArgumentException if the subscription does not exist.
1827      */
setAllowedNetworkTypesForReasons(int subId, @NonNull String allowedNetworkTypesForReasons)1828     public void setAllowedNetworkTypesForReasons(int subId,
1829             @NonNull String allowedNetworkTypesForReasons) {
1830         Objects.requireNonNull(allowedNetworkTypesForReasons);
1831         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS,
1832                 allowedNetworkTypesForReasons,
1833                 SubscriptionInfoInternal.Builder::setAllowedNetworkTypesForReasons);
1834     }
1835 
1836     /**
1837      * Set device to device sharing status.
1838      *
1839      * @param subId Subscription id.
1840      * @param deviceToDeviceStatusSharingPreference Device to device sharing status.
1841      *
1842      * @throws IllegalArgumentException if the subscription does not exist.
1843      */
setDeviceToDeviceStatusSharingPreference(int subId, @DeviceToDeviceStatusSharingPreference int deviceToDeviceStatusSharingPreference)1844     public void setDeviceToDeviceStatusSharingPreference(int subId,
1845             @DeviceToDeviceStatusSharingPreference int deviceToDeviceStatusSharingPreference) {
1846         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_D2D_STATUS_SHARING,
1847                 deviceToDeviceStatusSharingPreference,
1848                 SubscriptionInfoInternal.Builder::setDeviceToDeviceStatusSharingPreference);
1849     }
1850 
1851     /**
1852      * Set whether the user has opted-in voice over IMS.
1853      *
1854      * @param subId Subscription id.
1855      * @param isVoImsOptInEnabled Whether the user has opted-in voice over IMS.
1856      *
1857      * @throws IllegalArgumentException if the subscription does not exist.
1858      */
setVoImsOptInEnabled(int subId, int isVoImsOptInEnabled)1859     public void setVoImsOptInEnabled(int subId, int isVoImsOptInEnabled) {
1860         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, isVoImsOptInEnabled,
1861                 SubscriptionInfoInternal.Builder::setVoImsOptInEnabled);
1862     }
1863 
1864     /**
1865      * Set contacts information that allow device to device sharing.
1866      *
1867      * @param subId Subscription id.
1868      * @param deviceToDeviceStatusSharingContacts contacts information that allow device to
1869      * device sharing.
1870      *
1871      * @throws IllegalArgumentException if the subscription does not exist.
1872      */
setDeviceToDeviceStatusSharingContacts(int subId, @NonNull String deviceToDeviceStatusSharingContacts)1873     public void setDeviceToDeviceStatusSharingContacts(int subId,
1874             @NonNull String deviceToDeviceStatusSharingContacts) {
1875         Objects.requireNonNull(deviceToDeviceStatusSharingContacts);
1876         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS,
1877                 deviceToDeviceStatusSharingContacts,
1878                 SubscriptionInfoInternal.Builder::setDeviceToDeviceStatusSharingContacts);
1879     }
1880 
1881     /**
1882      * Set whether the user has enabled NR advanced calling.
1883      *
1884      * @param subId Subscription id.
1885      * @param isNrAdvancedCallingEnabled Whether the user has enabled NR advanced calling.
1886      *
1887      * @throws IllegalArgumentException if the subscription does not exist.
1888      */
setNrAdvancedCallingEnabled(int subId, int isNrAdvancedCallingEnabled)1889     public void setNrAdvancedCallingEnabled(int subId, int isNrAdvancedCallingEnabled) {
1890         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED,
1891                 isNrAdvancedCallingEnabled,
1892                 SubscriptionInfoInternal.Builder::setNrAdvancedCallingEnabled);
1893     }
1894 
1895     /**
1896      * Set the phone number retrieved from carrier.
1897      *
1898      * @param subId Subscription id.
1899      * @param numberFromCarrier The phone number retrieved from carrier.
1900      *
1901      * @throws IllegalArgumentException if the subscription does not exist.
1902      */
setNumberFromCarrier(int subId, @NonNull String numberFromCarrier)1903     public void setNumberFromCarrier(int subId, @NonNull String numberFromCarrier) {
1904         Objects.requireNonNull(numberFromCarrier);
1905         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER,
1906                 numberFromCarrier, SubscriptionInfoInternal.Builder::setNumberFromCarrier);
1907     }
1908 
1909     /**
1910      * Set the phone number retrieved from IMS.
1911      *
1912      * @param subId Subscription id.
1913      * @param numberFromIms The phone number retrieved from IMS.
1914      *
1915      * @throws IllegalArgumentException if the subscription does not exist.
1916      */
setNumberFromIms(int subId, @NonNull String numberFromIms)1917     public void setNumberFromIms(int subId, @NonNull String numberFromIms) {
1918         Objects.requireNonNull(numberFromIms);
1919         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS,
1920                 numberFromIms, SubscriptionInfoInternal.Builder::setNumberFromIms);
1921     }
1922 
1923     /**
1924      * Set the port index of the Uicc card.
1925      *
1926      * @param subId Subscription id.
1927      * @param portIndex The port index of the Uicc card.
1928      *
1929      * @throws IllegalArgumentException if the subscription does not exist.
1930      */
setPortIndex(int subId, int portIndex)1931     public void setPortIndex(int subId, int portIndex) {
1932         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_PORT_INDEX, portIndex,
1933                 SubscriptionInfoInternal.Builder::setPortIndex);
1934     }
1935 
1936     /**
1937      * Set subscription's preferred usage setting.
1938      *
1939      * @param subId Subscription id.
1940      * @param usageSetting Subscription's preferred usage setting.
1941      *
1942      * @throws IllegalArgumentException if the subscription does not exist.
1943      */
setUsageSetting(int subId, @UsageSetting int usageSetting)1944     public void setUsageSetting(int subId, @UsageSetting int usageSetting) {
1945         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_USAGE_SETTING, usageSetting,
1946                 SubscriptionInfoInternal.Builder::setUsageSetting);
1947     }
1948 
1949     /**
1950      * Set last used TP message reference.
1951      *
1952      * @param subId Subscription id.
1953      * @param lastUsedTPMessageReference Last used TP message reference.
1954      *
1955      * @throws IllegalArgumentException if the subscription does not exist.
1956      */
setLastUsedTPMessageReference(int subId, int lastUsedTPMessageReference)1957     public void setLastUsedTPMessageReference(int subId, int lastUsedTPMessageReference) {
1958         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_TP_MESSAGE_REF,
1959                 lastUsedTPMessageReference,
1960                 SubscriptionInfoInternal.Builder::setLastUsedTPMessageReference);
1961     }
1962 
1963     /**
1964      * Set the user id associated with this subscription.
1965      *
1966      * @param subId Subscription id.
1967      * @param userId The user id associated with this subscription.
1968      *
1969      * @throws IllegalArgumentException if the subscription does not exist.
1970      */
setUserId(int subId, @UserIdInt int userId)1971     public void setUserId(int subId, @UserIdInt int userId) {
1972         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_USER_HANDLE, userId,
1973                 SubscriptionInfoInternal.Builder::setUserId);
1974     }
1975 
1976     /**
1977      * Set whether satellite is enabled or not.
1978      *
1979      * @param subId Subscription id.
1980      * @param isSatelliteEnabled if satellite is enabled or not.
1981      *
1982      * @throws IllegalArgumentException if the subscription does not exist.
1983      */
setSatelliteEnabled(int subId, int isSatelliteEnabled)1984     public void setSatelliteEnabled(int subId, int isSatelliteEnabled) {
1985         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_SATELLITE_ENABLED,
1986                 isSatelliteEnabled,
1987                 SubscriptionInfoInternal.Builder::setSatelliteEnabled);
1988     }
1989 
1990     /**
1991      * Set whether group of the subscription is disabled. This is only useful if it's a grouped
1992      * opportunistic subscription. In this case, if all primary (non-opportunistic)
1993      * subscriptions in the group are deactivated (unplugged pSIM or deactivated eSIM profile),
1994      * we should disable this opportunistic subscription.
1995      *
1996      * @param subId Subscription id.
1997      * @param isGroupDisabled if group of the subscription is disabled.
1998      *
1999      * @throws IllegalArgumentException if the subscription does not exist.
2000      */
setGroupDisabled(int subId, boolean isGroupDisabled)2001     public void setGroupDisabled(int subId, boolean isGroupDisabled) {
2002         // group disabled does not have a corresponding SimInfo column. So we only update the cache.
2003 
2004         // Grab the write lock so no other threads can read or write the cache.
2005         mReadWriteLock.writeLock().lock();
2006         try {
2007             SubscriptionInfoInternal subInfoCache = mAllSubscriptionInfoInternalCache.get(subId);
2008             if (subInfoCache == null) {
2009                 throw new IllegalArgumentException("setGroupDisabled: Subscription doesn't exist. "
2010                         + "subId=" + subId);
2011             }
2012             mAllSubscriptionInfoInternalCache.put(subId,
2013                     new SubscriptionInfoInternal.Builder(subInfoCache)
2014                             .setGroupDisabled(isGroupDisabled).build());
2015         } finally {
2016             mReadWriteLock.writeLock().unlock();
2017         }
2018     }
2019 
2020     /**
2021      * Reload the database from content provider to the cache. This must be a synchronous operation
2022      * to prevent cache/database out-of-sync. Callers should be cautious to call this method because
2023      * it might take longer time to complete.
2024      */
reloadDatabaseSync()2025     public void reloadDatabaseSync() {
2026         logl("reloadDatabaseSync");
2027         // Synchronously load the database into the cache.
2028         loadDatabaseInternal();
2029     }
2030 
2031     /**
2032      * Load the database from content provider to the cache.
2033      */
loadDatabaseInternal()2034     private void loadDatabaseInternal() {
2035         logl("loadDatabaseInternal");
2036         try (Cursor cursor = mContext.getContentResolver().query(
2037                 SimInfo.CONTENT_URI, null, null, null, null)) {
2038             mReadWriteLock.writeLock().lock();
2039             try {
2040                 Map<Integer, SubscriptionInfoInternal> newAllSubscriptionInfoInternalCache =
2041                         new HashMap<>();
2042                 boolean changed = false;
2043                 while (cursor != null && cursor.moveToNext()) {
2044                     SubscriptionInfoInternal subInfo = createSubscriptionInfoFromCursor(cursor);
2045                     newAllSubscriptionInfoInternalCache.put(subInfo.getSubscriptionId(), subInfo);
2046                     if (!Objects.equals(mAllSubscriptionInfoInternalCache
2047                             .get(subInfo.getSubscriptionId()), subInfo)) {
2048                         mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(
2049                                 subInfo.getSubscriptionId()));
2050                         changed = true;
2051                     }
2052                 }
2053 
2054                 if (changed) {
2055                     mAllSubscriptionInfoInternalCache.clear();
2056                     mAllSubscriptionInfoInternalCache.putAll(newAllSubscriptionInfoInternalCache);
2057 
2058                     logl("Loaded " + mAllSubscriptionInfoInternalCache.size()
2059                             + " records from the subscription database.");
2060                     mAllSubscriptionInfoInternalCache.forEach(
2061                             (subId, subInfo) -> log("  " + subInfo.toString()));
2062                 }
2063             } finally {
2064                 mReadWriteLock.writeLock().unlock();
2065             }
2066         }
2067     }
2068 
2069     /**
2070      * Initialize the database cache. Load the entire database into the cache.
2071      */
initializeDatabase()2072     private void initializeDatabase() {
2073         if (mAsyncMode) {
2074             // Load the database asynchronously.
2075             post(() -> {
2076                 synchronized (this) {
2077                     loadDatabaseInternal();
2078                     mDatabaseInitialized = true;
2079                     mCallback.invokeFromExecutor(mCallback::onInitialized);
2080                 }
2081             });
2082         } else {
2083             // Load the database synchronously.
2084             synchronized (this) {
2085                 loadDatabaseInternal();
2086                 mDatabaseInitialized = true;
2087                 mCallback.invokeFromExecutor(mCallback::onInitialized);
2088             }
2089         }
2090     }
2091 
2092     /**
2093      * Build the {@link SubscriptionInfoInternal} from database.
2094      *
2095      * @param cursor  The cursor of the database.
2096      *
2097      * @return The subscription info from a single database record.
2098      */
2099     @NonNull
createSubscriptionInfoFromCursor(@onNull Cursor cursor)2100     private SubscriptionInfoInternal createSubscriptionInfoFromCursor(@NonNull Cursor cursor) {
2101         SubscriptionInfoInternal.Builder builder = new SubscriptionInfoInternal.Builder();
2102         int id = cursor.getInt(cursor.getColumnIndexOrThrow(
2103                 SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID));
2104         builder.setId(id)
2105                 .setIccId(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2106                         SimInfo.COLUMN_ICC_ID))))
2107                 .setSimSlotIndex(cursor.getInt(cursor.getColumnIndexOrThrow(
2108                         SimInfo.COLUMN_SIM_SLOT_INDEX)))
2109                 .setDisplayName(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2110                         SimInfo.COLUMN_DISPLAY_NAME))))
2111                 .setCarrierName(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2112                         SimInfo.COLUMN_CARRIER_NAME))))
2113                 .setDisplayNameSource(cursor.getInt(cursor.getColumnIndexOrThrow(
2114                         SimInfo.COLUMN_NAME_SOURCE)))
2115                 .setIconTint(cursor.getInt(cursor.getColumnIndexOrThrow(
2116                         SimInfo.COLUMN_COLOR)))
2117                 .setNumber(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2118                         SimInfo.COLUMN_NUMBER))))
2119                 .setDataRoaming(cursor.getInt(cursor.getColumnIndexOrThrow(
2120                         SimInfo.COLUMN_DATA_ROAMING)))
2121                 .setMcc(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2122                         SimInfo.COLUMN_MCC_STRING))))
2123                 .setMnc(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2124                         SimInfo.COLUMN_MNC_STRING))))
2125                 .setEhplmns(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2126                         SimInfo.COLUMN_EHPLMNS))))
2127                 .setHplmns(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2128                         SimInfo.COLUMN_HPLMNS))))
2129                 .setEmbedded(cursor.getInt(cursor.getColumnIndexOrThrow(
2130                         SimInfo.COLUMN_IS_EMBEDDED)));
2131 
2132         String cardString = TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2133                 SimInfo.COLUMN_CARD_ID)));
2134         builder.setCardString(cardString);
2135         // publicCardId is the publicly exposed int card ID
2136         int publicCardId = mUiccController.convertToPublicCardId(cardString);
2137 
2138         byte[] rules = cursor.getBlob(cursor.getColumnIndexOrThrow(SimInfo.COLUMN_ACCESS_RULES));
2139         if (rules != null) {
2140             builder.setNativeAccessRules(rules);
2141         }
2142 
2143         rules = cursor.getBlob(cursor.getColumnIndexOrThrow(
2144                 SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS));
2145         if (rules != null) {
2146             builder.setCarrierConfigAccessRules(rules);
2147         }
2148 
2149         byte[] config = cursor.getBlob(cursor.getColumnIndexOrThrow(SimInfo.COLUMN_RCS_CONFIG));
2150         if (config != null) {
2151             builder.setRcsConfig(config);
2152         }
2153 
2154         builder.setCardId(publicCardId)
2155                 .setRemovableEmbedded(cursor.getInt(cursor.getColumnIndexOrThrow(
2156                         SimInfo.COLUMN_IS_REMOVABLE)))
2157                 .setCellBroadcastExtremeThreatAlertEnabled(cursor.getInt(cursor
2158                         .getColumnIndexOrThrow(SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT)))
2159                 .setCellBroadcastSevereThreatAlertEnabled(cursor.getInt(cursor
2160                         .getColumnIndexOrThrow(SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT)))
2161                 .setCellBroadcastAmberAlertEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2162                         SimInfo.COLUMN_CB_AMBER_ALERT)))
2163                 .setCellBroadcastEmergencyAlertEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2164                         SimInfo.COLUMN_CB_EMERGENCY_ALERT)))
2165                 .setCellBroadcastAlertSoundDuration(cursor.getInt(cursor.getColumnIndexOrThrow(
2166                         SimInfo.COLUMN_CB_ALERT_SOUND_DURATION)))
2167                 .setCellBroadcastAlertReminderInterval(cursor.getInt(cursor.getColumnIndexOrThrow(
2168                         SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL)))
2169                 .setCellBroadcastAlertVibrationEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2170                         SimInfo.COLUMN_CB_ALERT_VIBRATE)))
2171                 .setCellBroadcastAlertSpeechEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2172                         SimInfo.COLUMN_CB_ALERT_SPEECH)))
2173                 .setCellBroadcastEtwsTestAlertEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2174                         SimInfo.COLUMN_CB_ETWS_TEST_ALERT)))
2175                 .setCellBroadcastAreaInfoMessageEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2176                         SimInfo.COLUMN_CB_CHANNEL_50_ALERT)))
2177                 .setCellBroadcastTestAlertEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2178                         SimInfo.COLUMN_CB_CMAS_TEST_ALERT)))
2179                 .setCellBroadcastOptOutDialogEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2180                         SimInfo.COLUMN_CB_OPT_OUT_DIALOG)))
2181                 .setEnhanced4GModeEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2182                         SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED)))
2183                 .setVideoTelephonyEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2184                         SimInfo.COLUMN_VT_IMS_ENABLED)))
2185                 .setWifiCallingEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2186                         SimInfo.COLUMN_WFC_IMS_ENABLED)))
2187                 .setWifiCallingMode(cursor.getInt(cursor.getColumnIndexOrThrow(
2188                         SimInfo.COLUMN_WFC_IMS_MODE)))
2189                 .setWifiCallingModeForRoaming(cursor.getInt(cursor.getColumnIndexOrThrow(
2190                         SimInfo.COLUMN_WFC_IMS_ROAMING_MODE)))
2191                 .setWifiCallingEnabledForRoaming(cursor.getInt(cursor.getColumnIndexOrThrow(
2192                         SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED)))
2193                 .setOpportunistic(cursor.getInt(cursor.getColumnIndexOrThrow(
2194                         SimInfo.COLUMN_IS_OPPORTUNISTIC)))
2195                 .setGroupUuid(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2196                         SimInfo.COLUMN_GROUP_UUID))))
2197                 .setCountryIso(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2198                         SimInfo.COLUMN_ISO_COUNTRY_CODE))))
2199                 .setCarrierId(cursor.getInt(cursor.getColumnIndexOrThrow(
2200                         SimInfo.COLUMN_CARRIER_ID)))
2201                 .setProfileClass(cursor.getInt(cursor.getColumnIndexOrThrow(
2202                         SimInfo.COLUMN_PROFILE_CLASS)))
2203                 .setType(cursor.getInt(cursor.getColumnIndexOrThrow(
2204                         SimInfo.COLUMN_SUBSCRIPTION_TYPE)))
2205                 .setGroupOwner(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2206                         SimInfo.COLUMN_GROUP_OWNER))))
2207                 .setEnabledMobileDataPolicies(TextUtils.emptyIfNull(
2208                         cursor.getString(cursor.getColumnIndexOrThrow(
2209                                 SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES))))
2210                 .setImsi(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2211                         SimInfo.COLUMN_IMSI))))
2212                 .setUiccApplicationsEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2213                         SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED)))
2214                 .setRcsUceEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2215                         SimInfo.COLUMN_IMS_RCS_UCE_ENABLED)))
2216                 .setCrossSimCallingEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2217                         SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED)))
2218                 .setAllowedNetworkTypesForReasons(TextUtils.emptyIfNull(
2219                         cursor.getString(cursor.getColumnIndexOrThrow(
2220                                 SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS))))
2221                 .setDeviceToDeviceStatusSharingPreference(cursor.getInt(
2222                         cursor.getColumnIndexOrThrow(
2223                                 SimInfo.COLUMN_D2D_STATUS_SHARING)))
2224                 .setVoImsOptInEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2225                         SimInfo.COLUMN_VOIMS_OPT_IN_STATUS)))
2226                 .setDeviceToDeviceStatusSharingContacts(TextUtils.emptyIfNull(cursor.getString(
2227                         cursor.getColumnIndexOrThrow(
2228                                 SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS))))
2229                 .setNrAdvancedCallingEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2230                         SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED)))
2231                 .setNumberFromCarrier(TextUtils.emptyIfNull(cursor.getString(
2232                         cursor.getColumnIndexOrThrow(
2233                                 SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER))))
2234                 .setNumberFromIms(TextUtils.emptyIfNull(cursor.getString(
2235                         cursor.getColumnIndexOrThrow(
2236                                 SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS))))
2237                 .setPortIndex(cursor.getInt(cursor.getColumnIndexOrThrow(
2238                         SimInfo.COLUMN_PORT_INDEX)))
2239                 .setUsageSetting(cursor.getInt(cursor.getColumnIndexOrThrow(
2240                         SimInfo.COLUMN_USAGE_SETTING)))
2241                 .setLastUsedTPMessageReference(cursor.getInt(cursor.getColumnIndexOrThrow(
2242                         SimInfo.COLUMN_TP_MESSAGE_REF)))
2243                 .setUserId(cursor.getInt(cursor.getColumnIndexOrThrow(
2244                         SimInfo.COLUMN_USER_HANDLE)))
2245                 .setSatelliteEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2246                         SimInfo.COLUMN_SATELLITE_ENABLED)));
2247         return builder.build();
2248     }
2249 
2250     /**
2251      * Sync the group sharing fields from reference subscription to the rest of the subscriptions in
2252      * the same group. For example, if user enables wifi calling, the same setting should be applied
2253      * to all subscriptions in the same group.
2254      *
2255      * @param subId The subscription id of reference subscription.
2256      *
2257      * @throws IllegalArgumentException if the subscription does not exist.
2258      */
syncToGroup(int subId)2259     public void syncToGroup(int subId) {
2260         if (!mAllSubscriptionInfoInternalCache.containsKey(subId)) {
2261             throw new IllegalArgumentException("Invalid subId " + subId);
2262         }
2263 
2264         for (String column : GROUP_SHARING_COLUMNS) {
2265             // Get the value from the reference subscription, and set to itself again.
2266             // writeDatabaseAndCacheHelper() will automatically sync to the rest of the group.
2267             setSubscriptionProperty(subId, column, getSubscriptionProperty(subId, column));
2268         }
2269     }
2270 
2271     /**
2272      * Get the subscription info by subscription id.
2273      *
2274      * @param subId The subscription id.
2275      *
2276      * @return The subscription info. {@code null} if not found.
2277      */
2278     @Nullable
getSubscriptionInfoInternal(int subId)2279     public SubscriptionInfoInternal getSubscriptionInfoInternal(int subId) {
2280         mReadWriteLock.readLock().lock();
2281         try {
2282             return mAllSubscriptionInfoInternalCache.get(subId);
2283         } finally {
2284             mReadWriteLock.readLock().unlock();
2285         }
2286     }
2287 
2288     /**
2289      * @return All subscription infos in the database.
2290      */
2291     @NonNull
getAllSubscriptions()2292     public List<SubscriptionInfoInternal> getAllSubscriptions() {
2293         mReadWriteLock.readLock().lock();
2294         try {
2295             return new ArrayList<>(mAllSubscriptionInfoInternalCache.values());
2296         } finally {
2297             mReadWriteLock.readLock().unlock();
2298         }
2299     }
2300 
2301     /**
2302      * Get subscription info by ICCID.
2303      *
2304      * @param iccId The ICCID of the SIM card.
2305      * @return The subscription info if found. {@code null} if not found.
2306      */
2307     @Nullable
getSubscriptionInfoInternalByIccId(@onNull String iccId)2308     public SubscriptionInfoInternal getSubscriptionInfoInternalByIccId(@NonNull String iccId) {
2309         mReadWriteLock.readLock().lock();
2310         try {
2311             return mAllSubscriptionInfoInternalCache.values().stream()
2312                     .filter(subInfo -> subInfo.getIccId().equals(iccId))
2313                     .findFirst()
2314                     .orElse(null);
2315         } finally {
2316             mReadWriteLock.readLock().unlock();
2317         }
2318     }
2319 
2320     /**
2321      * Log debug messages.
2322      *
2323      * @param s debug messages
2324      */
log(@onNull String s)2325     private void log(@NonNull String s) {
2326         Rlog.d(LOG_TAG, s);
2327     }
2328 
2329     /**
2330      * Log error messages.
2331      *
2332      * @param s error messages
2333      */
loge(@onNull String s)2334     private void loge(@NonNull String s) {
2335         Rlog.e(LOG_TAG, s);
2336     }
2337 
2338     /**
2339      * Log verbose messages.
2340      *
2341      * @param s debug messages.
2342      */
logv(@onNull String s)2343     private void logv(@NonNull String s) {
2344         if (VDBG) Rlog.v(LOG_TAG, s);
2345     }
2346 
2347     /**
2348      * Log error messages and also log into the local log.
2349      *
2350      * @param s debug messages
2351      */
logel(@onNull String s)2352     private void logel(@NonNull String s) {
2353         loge(s);
2354         mLocalLog.log(s);
2355     }
2356 
2357     /**
2358      * Log debug messages and also log into the local log.
2359      *
2360      * @param s debug messages
2361      */
logl(@onNull String s)2362     private void logl(@NonNull String s) {
2363         log(s);
2364         mLocalLog.log(s);
2365     }
2366 
2367     /**
2368      * Dump the state of {@link SubscriptionDatabaseManager}.
2369      *
2370      * @param fd File descriptor
2371      * @param printWriter Print writer
2372      * @param args Arguments
2373      */
dump(@onNull FileDescriptor fd, @NonNull PrintWriter printWriter, @NonNull String[] args)2374     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter printWriter,
2375             @NonNull String[] args) {
2376         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
2377         pw.println(SubscriptionDatabaseManager.class.getSimpleName() + ":");
2378         pw.increaseIndent();
2379         pw.println("All subscriptions:");
2380         pw.increaseIndent();
2381         mReadWriteLock.readLock().lock();
2382         try {
2383             mAllSubscriptionInfoInternalCache.forEach((subId, subInfo) -> pw.println(subInfo));
2384         } finally {
2385             mReadWriteLock.readLock().unlock();
2386         }
2387         pw.decreaseIndent();
2388         pw.println();
2389         pw.println("mAsyncMode=" + mAsyncMode);
2390         synchronized (this) {
2391             pw.println("mDatabaseInitialized=" + mDatabaseInitialized);
2392         }
2393         pw.println("mReadWriteLock=" + mReadWriteLock);
2394         pw.println();
2395         pw.println("Local log:");
2396         pw.increaseIndent();
2397         mLocalLog.dump(fd, printWriter, args);
2398         pw.decreaseIndent();
2399         pw.decreaseIndent();
2400     }
2401 }
2402