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 package com.android.internal.telephony; 17 18 import android.content.BroadcastReceiver; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.IntentFilter; 22 import android.database.ContentObserver; 23 import android.os.AsyncResult; 24 import android.os.Handler; 25 import android.os.Message; 26 import android.os.Registrant; 27 import android.os.RegistrantList; 28 import android.provider.Settings; 29 import android.provider.Telephony; 30 import android.telephony.SubscriptionManager; 31 import android.telephony.TelephonyManager; 32 import android.util.LocalLog; 33 import android.util.Log; 34 35 import com.android.internal.annotations.VisibleForTesting; 36 import com.android.internal.util.IndentingPrintWriter; 37 import com.android.telephony.Rlog; 38 39 import java.io.FileDescriptor; 40 import java.io.PrintWriter; 41 42 /** 43 * Carrier Action Agent(CAA) paired with 44 * {@link com.android.internal.telephony.CarrierSignalAgent CarrierSignalAgent}, 45 * serves as an agent to dispatch carrier actions from carrier apps to different telephony modules, 46 * {@link android.telephony.TelephonyManager#carrierActionSetRadioEnabled(int, boolean) 47 * carrierActionSetRadioEnabled} for example. 48 * 49 * CAA supports dynamic registration where different telephony modules could listen for a specific 50 * carrier action event and implement their own handler. CCA will dispatch the event to all 51 * interested parties and maintain the received action states internally for future inspection. 52 * Each CarrierActionAgent is associated with a phone object. 53 */ 54 public class CarrierActionAgent extends Handler { 55 private static final String LOG_TAG = "CarrierActionAgent"; 56 private static final boolean DBG = true; 57 private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE); 58 59 /** A list of carrier actions */ 60 public static final int CARRIER_ACTION_SET_METERED_APNS_ENABLED = 0; 61 public static final int CARRIER_ACTION_SET_RADIO_ENABLED = 1; 62 public static final int CARRIER_ACTION_RESET = 2; 63 public static final int CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS = 3; 64 public static final int EVENT_APM_SETTINGS_CHANGED = 4; 65 public static final int EVENT_MOBILE_DATA_SETTINGS_CHANGED = 5; 66 public static final int EVENT_DATA_ROAMING_OFF = 6; 67 public static final int EVENT_SIM_STATE_CHANGED = 7; 68 public static final int EVENT_APN_SETTINGS_CHANGED = 8; 69 70 /** Member variables */ 71 private final Phone mPhone; 72 /** registrant list per carrier action */ 73 private RegistrantList mMeteredApnEnableRegistrants = new RegistrantList(); 74 private RegistrantList mRadioEnableRegistrants = new RegistrantList(); 75 private RegistrantList mDefaultNetworkReportRegistrants = new RegistrantList(); 76 /** local log for carrier actions */ 77 private LocalLog mMeteredApnEnabledLog = new LocalLog(8); 78 private LocalLog mRadioEnabledLog = new LocalLog(8); 79 private LocalLog mReportDefaultNetworkStatusLog = new LocalLog(8); 80 /** carrier actions */ 81 private Boolean mCarrierActionOnMeteredApnEnabled = true; 82 private Boolean mCarrierActionOnRadioEnabled = true; 83 private Boolean mCarrierActionReportDefaultNetworkStatus = false; 84 /** content observer for APM change */ 85 private final SettingsObserver mSettingsObserver; 86 87 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 88 @Override 89 public void onReceive(Context context, Intent intent) { 90 final String action = intent.getAction(); 91 final String iccState = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); 92 if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){ 93 if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) { 94 // ignore rebroadcast since carrier apps are direct boot aware. 95 return; 96 } 97 final int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 98 SubscriptionManager.INVALID_PHONE_INDEX); 99 if (mPhone.getPhoneId() == phoneId) { 100 sendMessage(obtainMessage(EVENT_SIM_STATE_CHANGED, iccState)); 101 } 102 } 103 } 104 }; 105 106 /** Constructor */ CarrierActionAgent(Phone phone)107 public CarrierActionAgent(Phone phone) { 108 mPhone = phone; 109 mPhone.getContext().registerReceiver(mReceiver, 110 new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED)); 111 mSettingsObserver = new SettingsObserver(mPhone.getContext(), this); 112 if (DBG) log("Creating CarrierActionAgent"); 113 } 114 115 @Override handleMessage(Message msg)116 public void handleMessage(Message msg) { 117 // skip notification if the input carrier action is same as the current one. 118 Boolean enabled = getCarrierActionEnabled(msg.what); 119 if (enabled != null && enabled == (boolean) msg.obj) return; 120 switch (msg.what) { 121 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 122 mCarrierActionOnMeteredApnEnabled = (boolean) msg.obj; 123 log("SET_METERED_APNS_ENABLED: " + mCarrierActionOnMeteredApnEnabled); 124 mMeteredApnEnabledLog.log("SET_METERED_APNS_ENABLED: " 125 + mCarrierActionOnMeteredApnEnabled); 126 int otaspState = (mCarrierActionOnMeteredApnEnabled) 127 ? mPhone.getServiceStateTracker().getOtasp() 128 : TelephonyManager.OTASP_SIM_UNPROVISIONED; 129 mPhone.notifyOtaspChanged(otaspState); 130 mMeteredApnEnableRegistrants.notifyRegistrants( 131 new AsyncResult(null, mCarrierActionOnMeteredApnEnabled, null)); 132 break; 133 case CARRIER_ACTION_SET_RADIO_ENABLED: 134 mCarrierActionOnRadioEnabled = (boolean) msg.obj; 135 log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled); 136 mRadioEnabledLog.log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled); 137 mRadioEnableRegistrants.notifyRegistrants( 138 new AsyncResult(null, mCarrierActionOnRadioEnabled, null)); 139 break; 140 case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS: 141 mCarrierActionReportDefaultNetworkStatus = (boolean) msg.obj; 142 log("CARRIER_ACTION_REPORT_AT_DEFAULT_NETWORK_STATUS: " 143 + mCarrierActionReportDefaultNetworkStatus); 144 mReportDefaultNetworkStatusLog.log("REGISTER_DEFAULT_NETWORK_STATUS: " 145 + mCarrierActionReportDefaultNetworkStatus); 146 mDefaultNetworkReportRegistrants.notifyRegistrants( 147 new AsyncResult(null, mCarrierActionReportDefaultNetworkStatus, null)); 148 break; 149 case CARRIER_ACTION_RESET: 150 log("CARRIER_ACTION_RESET"); 151 carrierActionReset(); 152 break; 153 case EVENT_APM_SETTINGS_CHANGED: 154 log("EVENT_APM_SETTINGS_CHANGED"); 155 if ((Settings.Global.getInt(mPhone.getContext().getContentResolver(), 156 Settings.Global.AIRPLANE_MODE_ON, 0) != 0)) { 157 carrierActionReset(); 158 } 159 break; 160 case EVENT_MOBILE_DATA_SETTINGS_CHANGED: 161 log("EVENT_MOBILE_DATA_SETTINGS_CHANGED"); 162 if (!mPhone.isUserDataEnabled()) carrierActionReset(); 163 break; 164 case EVENT_DATA_ROAMING_OFF: 165 log("EVENT_DATA_ROAMING_OFF"); 166 // reset carrier actions when exit roaming state. 167 carrierActionReset(); 168 break; 169 case EVENT_SIM_STATE_CHANGED: 170 String iccState = (String) msg.obj; 171 if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState)) { 172 log("EVENT_SIM_STATE_CHANGED status: " + iccState); 173 carrierActionReset(); 174 String mobileData = Settings.Global.MOBILE_DATA; 175 if (TelephonyManager.getDefault().getSimCount() != 1) { 176 mobileData = mobileData + mPhone.getSubId(); 177 } 178 mSettingsObserver.observe(Settings.Global.getUriFor(mobileData), 179 EVENT_MOBILE_DATA_SETTINGS_CHANGED); 180 mSettingsObserver.observe( 181 Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), 182 EVENT_APM_SETTINGS_CHANGED); 183 mSettingsObserver.observe( 184 Telephony.Carriers.CONTENT_URI, EVENT_APN_SETTINGS_CHANGED); 185 if (mPhone.getServiceStateTracker() != null) { 186 mPhone.getServiceStateTracker().registerForDataRoamingOff( 187 this, EVENT_DATA_ROAMING_OFF, null, false); 188 } 189 } else if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) { 190 log("EVENT_SIM_STATE_CHANGED status: " + iccState); 191 carrierActionReset(); 192 mSettingsObserver.unobserve(); 193 if (mPhone.getServiceStateTracker() != null) { 194 mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this); 195 } 196 } 197 break; 198 case EVENT_APN_SETTINGS_CHANGED: 199 log("EVENT_APN_SETTINGS_CHANGED"); 200 // Reset carrier actions when APN change. 201 carrierActionReset(); 202 break; 203 default: 204 loge("Unknown carrier action: " + msg.what); 205 } 206 } 207 208 /** 209 * Action set from carrier app to enable/disable radio 210 */ carrierActionSetRadioEnabled(boolean enabled)211 public void carrierActionSetRadioEnabled(boolean enabled) { 212 sendMessage(obtainMessage(CARRIER_ACTION_SET_RADIO_ENABLED, enabled)); 213 } 214 215 /** 216 * Action set from carrier app to enable/disable metered APNs 217 */ carrierActionSetMeteredApnsEnabled(boolean enabled)218 public void carrierActionSetMeteredApnsEnabled(boolean enabled) { 219 sendMessage(obtainMessage(CARRIER_ACTION_SET_METERED_APNS_ENABLED, enabled)); 220 } 221 222 /** 223 * Action set from carrier app to start/stop reporting default network status. 224 */ carrierActionReportDefaultNetworkStatus(boolean report)225 public void carrierActionReportDefaultNetworkStatus(boolean report) { 226 sendMessage(obtainMessage(CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS, report)); 227 } 228 carrierActionReset()229 public void carrierActionReset() { 230 carrierActionReportDefaultNetworkStatus(false); 231 carrierActionSetMeteredApnsEnabled(true); 232 carrierActionSetRadioEnabled(true); 233 // notify configured carrier apps for reset 234 mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers( 235 new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_RESET)); 236 } 237 getRegistrantsFromAction(int action)238 private RegistrantList getRegistrantsFromAction(int action) { 239 switch (action) { 240 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 241 return mMeteredApnEnableRegistrants; 242 case CARRIER_ACTION_SET_RADIO_ENABLED: 243 return mRadioEnableRegistrants; 244 case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS: 245 return mDefaultNetworkReportRegistrants; 246 default: 247 loge("Unsupported action: " + action); 248 return null; 249 } 250 } 251 getCarrierActionEnabled(int action)252 private Boolean getCarrierActionEnabled(int action) { 253 switch (action) { 254 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 255 return mCarrierActionOnMeteredApnEnabled; 256 case CARRIER_ACTION_SET_RADIO_ENABLED: 257 return mCarrierActionOnRadioEnabled; 258 case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS: 259 return mCarrierActionReportDefaultNetworkStatus; 260 default: 261 loge("Unsupported action: " + action); 262 return null; 263 } 264 } 265 266 /** 267 * Register with CAA for a specific event. 268 * @param action which carrier action registrant is interested in 269 * @param notifyNow if carrier action has once set, notify registrant right after 270 * registering, so that registrants will get the latest carrier action. 271 */ registerForCarrierAction(int action, Handler h, int what, Object obj, boolean notifyNow)272 public void registerForCarrierAction(int action, Handler h, int what, Object obj, 273 boolean notifyNow) { 274 Boolean carrierAction = getCarrierActionEnabled(action); 275 if (carrierAction == null) { 276 throw new IllegalArgumentException("invalid carrier action: " + action); 277 } 278 RegistrantList list = getRegistrantsFromAction(action); 279 Registrant r = new Registrant(h, what, obj); 280 list.add(r); 281 if (notifyNow) { 282 r.notifyRegistrant(new AsyncResult(null, carrierAction, null)); 283 } 284 } 285 286 /** 287 * Unregister with CAA for a specific event. Callers will no longer be notified upon such event. 288 * @param action which carrier action caller is no longer interested in 289 */ unregisterForCarrierAction(Handler h, int action)290 public void unregisterForCarrierAction(Handler h, int action) { 291 RegistrantList list = getRegistrantsFromAction(action); 292 if (list == null) { 293 throw new IllegalArgumentException("invalid carrier action: " + action); 294 } 295 list.remove(h); 296 } 297 298 @VisibleForTesting getContentObserver()299 public ContentObserver getContentObserver() { 300 return mSettingsObserver; 301 } 302 log(String s)303 private void log(String s) { 304 Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 305 } 306 loge(String s)307 private void loge(String s) { 308 Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 309 } 310 logv(String s)311 private void logv(String s) { 312 Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 313 } 314 dump(FileDescriptor fd, PrintWriter pw, String[] args)315 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 316 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 317 pw.println(" mCarrierActionOnMeteredApnsEnabled Log:"); 318 ipw.increaseIndent(); 319 mMeteredApnEnabledLog.dump(fd, ipw, args); 320 ipw.decreaseIndent(); 321 322 pw.println(" mCarrierActionOnRadioEnabled Log:"); 323 ipw.increaseIndent(); 324 mRadioEnabledLog.dump(fd, ipw, args); 325 ipw.decreaseIndent(); 326 327 pw.println(" mCarrierActionReportDefaultNetworkStatus Log:"); 328 ipw.increaseIndent(); 329 mReportDefaultNetworkStatusLog.dump(fd, ipw, args); 330 ipw.decreaseIndent(); 331 } 332 } 333