1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.phone.vvm; 18 19 import android.annotation.Nullable; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.os.SystemProperties; 24 import android.telecom.PhoneAccountHandle; 25 import android.telecom.TelecomManager; 26 import android.telephony.CarrierConfigManager; 27 import android.telephony.PhoneStateListener; 28 import android.telephony.ServiceState; 29 import android.telephony.SubscriptionManager; 30 import android.telephony.TelephonyManager; 31 import android.util.ArrayMap; 32 import android.util.ArraySet; 33 34 import com.android.internal.telephony.IccCardConstants; 35 import com.android.internal.telephony.PhoneConstants; 36 import com.android.internal.telephony.TelephonyIntents; 37 import com.android.phone.PhoneUtils; 38 39 import java.util.Map; 40 import java.util.Set; 41 42 /** 43 * Tracks the status of all inserted SIMs. Will notify {@link RemoteVvmTaskManager} of when a SIM 44 * connected to the service for the first time after it was inserted or the system booted, and when 45 * the SIM is removed. Losing cell signal or entering airplane mode will not cause the connected 46 * event to be triggered again. Reinserting the SIM will trigger the connected event. Changing the 47 * carrier config will also trigger the connected event. Events will be delayed until the device has 48 * been fully booted (and left FBE mode). 49 */ 50 public class VvmSimStateTracker extends BroadcastReceiver { 51 52 private static final String TAG = "VvmSimStateTracker"; 53 54 /** 55 * Map to keep track of currently inserted SIMs. If the SIM hasn't been connected to the service 56 * before the value will be a {@link ServiceStateListener} that is still waiting for the 57 * connection. A value of {@code null} means the SIM has been connected to the service before. 58 */ 59 private static Map<PhoneAccountHandle, ServiceStateListener> sListeners = new ArrayMap<>(); 60 61 /** 62 * Accounts that has events before the device is booted. The events should be regenerated after 63 * the device has fully booted. 64 */ 65 private static Set<PhoneAccountHandle> sPreBootHandles = new ArraySet<>(); 66 67 /** 68 * Waits for the account to become {@link ServiceState#STATE_IN_SERVICE} and notify the 69 * connected event. Will unregister itself once the event has been triggered. 70 */ 71 private class ServiceStateListener extends PhoneStateListener { 72 73 private final PhoneAccountHandle mPhoneAccountHandle; 74 private final Context mContext; 75 ServiceStateListener(Context context, PhoneAccountHandle phoneAccountHandle)76 public ServiceStateListener(Context context, PhoneAccountHandle phoneAccountHandle) { 77 mContext = context; 78 mPhoneAccountHandle = phoneAccountHandle; 79 } 80 listen()81 public void listen() { 82 TelephonyManager telephonyManager = getTelephonyManager(mContext, mPhoneAccountHandle); 83 if(telephonyManager == null){ 84 VvmLog.e(TAG, "Cannot create TelephonyManager from " + mPhoneAccountHandle); 85 return; 86 } 87 telephonyManager.listen(this, PhoneStateListener.LISTEN_SERVICE_STATE); 88 } 89 unlisten()90 public void unlisten() { 91 // TelephonyManager does not need to be pinned to an account when removing a 92 // PhoneStateListener, and mPhoneAccountHandle might be invalid at this point 93 // (e.g. SIM removal) 94 mContext.getSystemService(TelephonyManager.class) 95 .listen(this, PhoneStateListener.LISTEN_NONE); 96 sListeners.put(mPhoneAccountHandle, null); 97 } 98 99 @Override onServiceStateChanged(ServiceState serviceState)100 public void onServiceStateChanged(ServiceState serviceState) { 101 if (serviceState.getState() == ServiceState.STATE_IN_SERVICE) { 102 VvmLog.i(TAG, "in service"); 103 sendConnected(mContext, mPhoneAccountHandle); 104 unlisten(); 105 } 106 } 107 } 108 109 @Override onReceive(Context context, Intent intent)110 public void onReceive(Context context, Intent intent) { 111 112 final String action = intent.getAction(); 113 if (action == null) { 114 VvmLog.w(TAG, "Null action for intent."); 115 return; 116 } 117 VvmLog.i(TAG, action); 118 switch (action) { 119 case Intent.ACTION_BOOT_COMPLETED: 120 onBootCompleted(context); 121 break; 122 case TelephonyIntents.ACTION_SIM_STATE_CHANGED: 123 if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals( 124 intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE))) { 125 // checkRemovedSim will scan all known accounts with isPhoneAccountActive() to find 126 // which SIM is removed. 127 // ACTION_SIM_STATE_CHANGED only provides subId which cannot be converted to a 128 // PhoneAccountHandle when the SIM is absent. 129 checkRemovedSim(context); 130 } 131 break; 132 case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED: 133 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, 134 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 135 136 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 137 VvmLog.i(TAG, "Received SIM change for invalid subscription id."); 138 checkRemovedSim(context); 139 return; 140 } 141 142 PhoneAccountHandle phoneAccountHandle = 143 PhoneAccountHandleConverter.fromSubId(subId); 144 145 if ("null".equals(phoneAccountHandle.getId())) { 146 VvmLog.e(TAG, 147 "null phone account handle ID, possible modem crash." 148 + " Ignoring carrier config changed event"); 149 return; 150 } 151 onCarrierConfigChanged(context, phoneAccountHandle); 152 } 153 } 154 onBootCompleted(Context context)155 private void onBootCompleted(Context context) { 156 for (PhoneAccountHandle phoneAccountHandle : sPreBootHandles) { 157 TelephonyManager telephonyManager = getTelephonyManager(context, phoneAccountHandle); 158 if (telephonyManager == null) { 159 continue; 160 } 161 if (telephonyManager.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) { 162 sListeners.put(phoneAccountHandle, null); 163 sendConnected(context, phoneAccountHandle); 164 } else { 165 listenToAccount(context, phoneAccountHandle); 166 } 167 } 168 sPreBootHandles.clear(); 169 } 170 sendConnected(Context context, PhoneAccountHandle phoneAccountHandle)171 private void sendConnected(Context context, PhoneAccountHandle phoneAccountHandle) { 172 VvmLog.i(TAG, "Service connected on " + phoneAccountHandle); 173 RemoteVvmTaskManager.startCellServiceConnected(context, phoneAccountHandle); 174 } 175 checkRemovedSim(Context context)176 private void checkRemovedSim(Context context) { 177 SubscriptionManager subscriptionManager = SubscriptionManager.from(context); 178 if (!isBootCompleted()) { 179 for (PhoneAccountHandle phoneAccountHandle : sPreBootHandles) { 180 if (!PhoneUtils.isPhoneAccountActive(subscriptionManager, phoneAccountHandle)) { 181 sPreBootHandles.remove(phoneAccountHandle); 182 } 183 } 184 return; 185 } 186 Set<PhoneAccountHandle> removeList = new ArraySet<>(); 187 for (PhoneAccountHandle phoneAccountHandle : sListeners.keySet()) { 188 if (!PhoneUtils.isPhoneAccountActive(subscriptionManager, phoneAccountHandle)) { 189 removeList.add(phoneAccountHandle); 190 ServiceStateListener listener = sListeners.get(phoneAccountHandle); 191 if (listener != null) { 192 listener.unlisten(); 193 } 194 sendSimRemoved(context, phoneAccountHandle); 195 } 196 } 197 198 for (PhoneAccountHandle phoneAccountHandle : removeList) { 199 sListeners.remove(phoneAccountHandle); 200 } 201 } 202 isBootCompleted()203 private boolean isBootCompleted() { 204 return SystemProperties.getBoolean("sys.boot_completed", false); 205 } 206 sendSimRemoved(Context context, PhoneAccountHandle phoneAccountHandle)207 private void sendSimRemoved(Context context, PhoneAccountHandle phoneAccountHandle) { 208 VvmLog.i(TAG, "Sim removed on " + phoneAccountHandle); 209 RemoteVvmTaskManager.startSimRemoved(context, phoneAccountHandle); 210 } 211 onCarrierConfigChanged(Context context, PhoneAccountHandle phoneAccountHandle)212 private void onCarrierConfigChanged(Context context, PhoneAccountHandle phoneAccountHandle) { 213 if (!isBootCompleted()) { 214 sPreBootHandles.add(phoneAccountHandle); 215 return; 216 } 217 TelephonyManager telephonyManager = getTelephonyManager(context, phoneAccountHandle); 218 if(telephonyManager == null){ 219 int subId = context.getSystemService(TelephonyManager.class).getSubIdForPhoneAccount( 220 context.getSystemService(TelecomManager.class) 221 .getPhoneAccount(phoneAccountHandle)); 222 VvmLog.e(TAG, "Cannot create TelephonyManager from " + phoneAccountHandle + ", subId=" 223 + subId); 224 // TODO(b/33945549): investigate more why this is happening. The PhoneAccountHandle was 225 // just converted from a valid subId so createForPhoneAccountHandle shouldn't really 226 // return null. 227 return; 228 } 229 if (telephonyManager.getServiceState().getState() 230 == ServiceState.STATE_IN_SERVICE) { 231 sendConnected(context, phoneAccountHandle); 232 sListeners.put(phoneAccountHandle, null); 233 } else { 234 listenToAccount(context, phoneAccountHandle); 235 } 236 } 237 listenToAccount(Context context, PhoneAccountHandle phoneAccountHandle)238 private void listenToAccount(Context context, PhoneAccountHandle phoneAccountHandle) { 239 ServiceStateListener listener = new ServiceStateListener(context, phoneAccountHandle); 240 listener.listen(); 241 sListeners.put(phoneAccountHandle, listener); 242 } 243 244 @Nullable getTelephonyManager(Context context, PhoneAccountHandle phoneAccountHandle)245 private static TelephonyManager getTelephonyManager(Context context, 246 PhoneAccountHandle phoneAccountHandle) { 247 return context.getSystemService(TelephonyManager.class) 248 .createForPhoneAccountHandle(phoneAccountHandle); 249 } 250 } 251