1 /* 2 * Copyright (C) 2021 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.imsserviceentitlement; 18 19 import static android.telephony.TelephonyManager.SIM_STATE_LOADED; 20 21 import static com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior.NEEDS_TO_RESET; 22 import static com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior.VALID_DURING_VALIDITY; 23 import static com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior.VALID_WITHOUT_DURATION; 24 import static com.android.imsserviceentitlement.ts43.Ts43Constants.EntitlementVersion.ENTITLEMENT_VERSION_EIGHT; 25 import static com.android.imsserviceentitlement.ts43.Ts43Constants.EntitlementVersion.ENTITLEMENT_VERSION_TWO; 26 import static com.android.imsserviceentitlement.utils.Executors.getAsyncExecutor; 27 28 import android.content.BroadcastReceiver; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.SharedPreferences; 32 import android.os.UserManager; 33 import android.provider.Settings; 34 import android.telephony.CarrierConfigManager; 35 import android.telephony.SubscriptionManager; 36 import android.util.Log; 37 38 import androidx.annotation.VisibleForTesting; 39 import androidx.annotation.WorkerThread; 40 41 import com.android.imsserviceentitlement.entitlement.EntitlementConfiguration; 42 import com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior; 43 import com.android.imsserviceentitlement.job.JobManager; 44 import com.android.imsserviceentitlement.utils.TelephonyUtils; 45 46 /** Watches events and manages service entitlement polling. */ 47 public class ImsEntitlementReceiver extends BroadcastReceiver { 48 private static final String TAG = "IMSSE-ImsEntitlementReceiver"; 49 50 /** 51 * Shared preference name for activation information, the key used in this file should append 52 * slot id if the value depended on carrier. 53 */ 54 private static final String PREFERENCE_ACTIVATION_INFO = "PREFERENCE_ACTIVATION_INFO"; 55 /** 56 * Shared preference key for last known subscription id of a SIM slot; default value {@link 57 * SubscriptionManager#INVALID_SUBSCRIPTION_ID}. 58 */ 59 private static final String KEY_LAST_SUB_ID = "last_sub_id_"; 60 /** Shared preference key for last boot count. */ 61 private static final String KEY_LAST_BOOT_COUNT = "last_boot_count_"; 62 63 @Override onReceive(Context context, Intent intent)64 public void onReceive(Context context, Intent intent) { 65 int currentSubId = 66 intent.getIntExtra( 67 SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, 68 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 69 int slotId = 70 intent.getIntExtra( 71 SubscriptionManager.EXTRA_SLOT_INDEX, 72 SubscriptionManager.INVALID_SIM_SLOT_INDEX); 73 Dependencies dependencies = createDependency(context, currentSubId); 74 if (!dependencies.userManager.isSystemUser() 75 || !SubscriptionManager.isValidSubscriptionId(currentSubId) 76 || dependencies.telephonyUtils.getSimApplicationState() != SIM_STATE_LOADED 77 || !TelephonyUtils.isImsProvisioningRequired(context, currentSubId) 78 || !isEntitlementVersionSupported(context, currentSubId)) { 79 return; 80 } 81 82 String action = intent.getAction(); 83 if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) { 84 final PendingResult result = goAsync(); 85 getAsyncExecutor().execute( 86 () -> handleCarrierConfigChanged( 87 context, currentSubId, slotId, dependencies.jobManager, result)); 88 } 89 } 90 91 /** 92 * Handles the event of SIM change and device boot up while receiving {@link 93 * CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED}. 94 */ 95 @WorkerThread handleCarrierConfigChanged( Context context, int currentSubId, int slotId, JobManager jobManager, PendingResult result)96 private void handleCarrierConfigChanged( 97 Context context, int currentSubId, int slotId, JobManager jobManager, 98 PendingResult result) { 99 boolean shouldQuery = false; 100 101 // Handle SIM changed. 102 int lastSubId = getAndSetSubId(context, currentSubId, slotId); 103 if (currentSubId != lastSubId) { 104 Log.d(TAG, 105 "SubId for slot " + slotId + " changed: " + lastSubId + " -> " + currentSubId); 106 if (SubscriptionManager.isValidSubscriptionId(lastSubId)) { 107 new EntitlementConfiguration(context, lastSubId).reset(); 108 } 109 shouldQuery = true; 110 } 111 112 // Handle device boot up. 113 if (!shouldQuery && isBootUp(context, slotId)) { 114 EntitlementConfiguration entitlementConfiguration = 115 new EntitlementConfiguration(context, currentSubId); 116 ClientBehavior clientBehavior = entitlementConfiguration.entitlementValidation(); 117 Log.d(TAG, "Device boot up, clientBehavior = " + clientBehavior); 118 if (clientBehavior == VALID_DURING_VALIDITY 119 || clientBehavior == VALID_WITHOUT_DURATION 120 || clientBehavior == NEEDS_TO_RESET) { 121 shouldQuery = true; 122 } else { // NEEDS_TO_RESET_EXCEPT_VERS or NEEDS_TO_RESET_EXCEPT_VERS_UNTIL_SETTING_ON 123 int storedEntitlementVersion = entitlementConfiguration.getEntitlementVersion(); 124 int entitlementVersion = 125 TelephonyUtils.getEntitlementVersion(context, currentSubId); 126 if (storedEntitlementVersion != entitlementVersion && entitlementVersion >= 8) { 127 shouldQuery = true; 128 } 129 } 130 } 131 132 if (shouldQuery) { 133 jobManager.queryEntitlementStatusOnceNetworkReady(); 134 } 135 136 if (result != null) { 137 result.finish(); 138 } 139 } 140 141 /** 142 * Returns {@code true} if current boot count greater than previous one. Saves the latest boot 143 * count into shared preference. 144 */ 145 @VisibleForTesting isBootUp(Context context, int slotId)146 boolean isBootUp(Context context, int slotId) { 147 SharedPreferences preferences = 148 context.getSharedPreferences(PREFERENCE_ACTIVATION_INFO, Context.MODE_PRIVATE); 149 int lastBootCount = preferences.getInt(KEY_LAST_BOOT_COUNT + slotId, 0); 150 int currentBootCount = 151 Settings.Global.getInt( 152 context.getContentResolver(), Settings.Global.BOOT_COUNT, /* def= */ -1); 153 preferences.edit().putInt(KEY_LAST_BOOT_COUNT + slotId, currentBootCount).apply(); 154 155 return currentBootCount != lastBootCount; 156 } 157 getAndSetSubId(Context context, int currentSubId, int slotId)158 private int getAndSetSubId(Context context, int currentSubId, int slotId) { 159 SharedPreferences preferences = 160 context.getSharedPreferences(PREFERENCE_ACTIVATION_INFO, Context.MODE_PRIVATE); 161 int lastSubId = preferences.getInt( 162 KEY_LAST_SUB_ID + slotId, SubscriptionManager.INVALID_SUBSCRIPTION_ID); 163 preferences.edit().putInt(KEY_LAST_SUB_ID + slotId, currentSubId).apply(); 164 return lastSubId; 165 } 166 isEntitlementVersionSupported(Context context, int currentSubId)167 private boolean isEntitlementVersionSupported(Context context, int currentSubId) { 168 int entitlementVersion = TelephonyUtils.getEntitlementVersion(context, currentSubId); 169 if (entitlementVersion == ENTITLEMENT_VERSION_TWO 170 || entitlementVersion == ENTITLEMENT_VERSION_EIGHT) { 171 return true; 172 } 173 Log.d(TAG, "Unsupported entitltment version: " + entitlementVersion); 174 return false; 175 } 176 177 /** Returns initialized dependencies */ 178 @VisibleForTesting createDependency(Context context, int subId)179 Dependencies createDependency(Context context, int subId) { 180 // Wrap return value 181 Dependencies ret = new Dependencies(); 182 ret.telephonyUtils = new TelephonyUtils(context, subId); 183 ret.userManager = context.getSystemService(UserManager.class); 184 ret.jobManager = 185 JobManager.getInstance(context, ImsEntitlementPollingService.COMPONENT_NAME, subId); 186 return ret; 187 } 188 189 /** A collection of dependency objects */ 190 protected static class Dependencies { 191 public TelephonyUtils telephonyUtils; 192 public UserManager userManager; 193 public JobManager jobManager; 194 } 195 } 196