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 static android.telephony.CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY; 19 import static android.telephony.CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY; 20 21 import android.annotation.Nullable; 22 import android.content.ActivityNotFoundException; 23 import android.content.ComponentName; 24 import android.content.Intent; 25 import android.content.pm.PackageManager; 26 import android.net.ConnectivityManager; 27 import android.net.Network; 28 import android.os.AsyncResult; 29 import android.os.Build; 30 import android.os.Handler; 31 import android.os.Message; 32 import android.os.PersistableBundle; 33 import android.os.UserHandle; 34 import android.telephony.CarrierConfigManager; 35 import android.telephony.SubscriptionManager; 36 import android.telephony.TelephonyManager; 37 import android.telephony.data.ApnSetting; 38 import android.text.TextUtils; 39 import android.util.LocalLog; 40 import android.util.Log; 41 42 import com.android.internal.telephony.util.ArrayUtils; 43 import com.android.internal.util.IndentingPrintWriter; 44 import com.android.telephony.Rlog; 45 46 import java.io.FileDescriptor; 47 import java.io.PrintWriter; 48 import java.util.HashMap; 49 import java.util.HashSet; 50 import java.util.Map; 51 import java.util.Set; 52 import java.util.stream.Collectors; 53 54 /** 55 * This class act as an CarrierSignalling Agent. 56 * it load registered carrier signalling receivers from carrier config, cache the result to avoid 57 * repeated polling and send the intent to the interested receivers. 58 * Each CarrierSignalAgent is associated with a phone object. 59 */ 60 public class CarrierSignalAgent extends Handler { 61 62 private static final String LOG_TAG = CarrierSignalAgent.class.getSimpleName(); 63 private static final boolean DBG = true; 64 private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE); 65 private static final boolean WAKE = true; 66 private static final boolean NO_WAKE = false; 67 68 /** delimiters for parsing config of the form: pakName./receiverName : signal1, signal2,..*/ 69 private static final String COMPONENT_NAME_DELIMITER = "\\s*:\\s*"; 70 private static final String CARRIER_SIGNAL_DELIMITER = "\\s*,\\s*"; 71 72 /** Member variables */ 73 private final Phone mPhone; 74 private boolean mDefaultNetworkAvail; 75 76 /** 77 * This is a map of intent action -> set of component name of statically registered 78 * carrier signal receivers(wakeup receivers). 79 * Those intents are declared in the Manifest files, aiming to wakeup broadcast receivers. 80 * Carrier apps should be careful when configuring the wake signal list to avoid unnecessary 81 * wakeup. Note we use Set as the entry value to compare config directly regardless of element 82 * order. 83 * @see CarrierConfigManager#KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY 84 */ 85 private Map<String, Set<ComponentName>> mCachedWakeSignalConfigs = new HashMap<>(); 86 87 /** 88 * This is a map of intent action -> set of component name of dynamically registered 89 * carrier signal receivers(non-wakeup receivers). Those intents will not wake up the apps. 90 * Note Carrier apps should avoid configuring no wake signals in there Manifest files. 91 * Note we use Set as the entry value to compare config directly regardless of element order. 92 * @see CarrierConfigManager#KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY 93 */ 94 private Map<String, Set<ComponentName>> mCachedNoWakeSignalConfigs = new HashMap<>(); 95 96 private static final int EVENT_REGISTER_DEFAULT_NETWORK_AVAIL = 0; 97 98 /** 99 * This is a list of supported signals from CarrierSignalAgent 100 */ 101 private static final Set<String> VALID_CARRIER_SIGNAL_ACTIONS = Set.of( 102 TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE, 103 TelephonyManager.ACTION_CARRIER_SIGNAL_REDIRECTED, 104 TelephonyManager.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED, 105 TelephonyManager.ACTION_CARRIER_SIGNAL_RESET, 106 TelephonyManager.ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE); 107 108 private static final Map<String, String> NEW_ACTION_TO_COMPAT_MAP = Map.of( 109 TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE, 110 TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE, 111 TelephonyManager.ACTION_CARRIER_SIGNAL_REDIRECTED, 112 TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED, 113 TelephonyManager.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED, 114 TelephonyIntents.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED, 115 TelephonyManager.ACTION_CARRIER_SIGNAL_RESET, 116 TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET, 117 TelephonyManager.ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE, 118 TelephonyIntents.ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE); 119 120 private static final Map<String, String> COMPAT_ACTION_TO_NEW_MAP = NEW_ACTION_TO_COMPAT_MAP 121 .entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey)); 122 123 private final LocalLog mErrorLocalLog = new LocalLog(16); 124 125 private ConnectivityManager.NetworkCallback mNetworkCallback; 126 127 /** Constructor */ CarrierSignalAgent(Phone phone)128 public CarrierSignalAgent(Phone phone) { 129 mPhone = phone; 130 CarrierConfigManager carrierConfigManager = mPhone.getContext().getSystemService( 131 CarrierConfigManager.class); 132 loadCarrierConfig(); 133 if (carrierConfigManager != null) { 134 carrierConfigManager.registerCarrierConfigChangeListener( 135 mPhone.getContext().getMainExecutor(), 136 (slotIndex, subId, carrierId, specificCarrierId) -> { 137 if (slotIndex == mPhone.getPhoneId()) { 138 loadCarrierConfig(); 139 } 140 }); 141 } 142 mPhone.getCarrierActionAgent().registerForCarrierAction( 143 CarrierActionAgent.CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS, this, 144 EVENT_REGISTER_DEFAULT_NETWORK_AVAIL, null, false); 145 } 146 147 @Override handleMessage(Message msg)148 public void handleMessage(Message msg) { 149 switch (msg.what) { 150 case EVENT_REGISTER_DEFAULT_NETWORK_AVAIL: 151 AsyncResult ar = (AsyncResult) msg.obj; 152 if (ar.exception != null) { 153 Rlog.e(LOG_TAG, "Register default network exception: " + ar.exception); 154 return; 155 } 156 final ConnectivityManager connectivityMgr = mPhone.getContext() 157 .getSystemService(ConnectivityManager.class); 158 if ((boolean) ar.result) { 159 mNetworkCallback = new ConnectivityManager.NetworkCallback() { 160 @Override 161 public void onAvailable(Network network) { 162 // an optimization to avoid signaling on every default network switch. 163 if (!mDefaultNetworkAvail) { 164 if (DBG) log("Default network available: " + network); 165 Intent intent = new Intent(TelephonyManager 166 .ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE); 167 intent.putExtra( 168 TelephonyManager.EXTRA_DEFAULT_NETWORK_AVAILABLE, true); 169 notifyCarrierSignalReceivers(intent); 170 mDefaultNetworkAvail = true; 171 } 172 } 173 @Override 174 public void onLost(Network network) { 175 if (DBG) log("Default network lost: " + network); 176 Intent intent = new Intent(TelephonyManager 177 .ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE); 178 intent.putExtra( 179 TelephonyManager.EXTRA_DEFAULT_NETWORK_AVAILABLE, false); 180 notifyCarrierSignalReceivers(intent); 181 mDefaultNetworkAvail = false; 182 } 183 }; 184 connectivityMgr.registerDefaultNetworkCallback(mNetworkCallback, mPhone); 185 log("Register default network"); 186 187 } else if (mNetworkCallback != null) { 188 connectivityMgr.unregisterNetworkCallback(mNetworkCallback); 189 mNetworkCallback = null; 190 mDefaultNetworkAvail = false; 191 log("unregister default network"); 192 } 193 break; 194 default: 195 break; 196 } 197 } 198 199 /** 200 * load carrier config and cached the results into a hashMap action -> array list of components. 201 */ loadCarrierConfig()202 private void loadCarrierConfig() { 203 PersistableBundle b = 204 CarrierConfigManager.getCarrierConfigSubset( 205 mPhone.getContext(), 206 mPhone.getSubId(), 207 KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY, 208 KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY); 209 if (b.isEmpty()) { 210 return; 211 } 212 213 synchronized (mCachedWakeSignalConfigs) { 214 log("Loading carrier config: " + KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY); 215 Map<String, Set<ComponentName>> config = parseAndCache( 216 b.getStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY)); 217 // In some rare cases, up-to-date config could be fetched with delay and all signals 218 // have already been delivered the receivers from the default carrier config. 219 // To handle this raciness, we should notify those receivers (from old configs) 220 // and reset carrier actions. This should be done before cached Config got purged 221 // and written with the up-to-date value, Otherwise those receivers from the 222 // old config might lingers without properly clean-up. 223 if (!mCachedWakeSignalConfigs.isEmpty() 224 && !config.equals(mCachedWakeSignalConfigs)) { 225 if (VDBG) log("carrier config changed, reset receivers from old config"); 226 mPhone.getCarrierActionAgent().sendEmptyMessage( 227 CarrierActionAgent.CARRIER_ACTION_RESET); 228 } 229 mCachedWakeSignalConfigs = config; 230 } 231 232 synchronized (mCachedNoWakeSignalConfigs) { 233 log("Loading carrier config: " 234 + KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY); 235 Map<String, Set<ComponentName>> config = parseAndCache( 236 b.getStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY)); 237 if (!mCachedNoWakeSignalConfigs.isEmpty() 238 && !config.equals(mCachedNoWakeSignalConfigs)) { 239 if (VDBG) log("carrier config changed, reset receivers from old config"); 240 mPhone.getCarrierActionAgent().sendEmptyMessage( 241 CarrierActionAgent.CARRIER_ACTION_RESET); 242 } 243 mCachedNoWakeSignalConfigs = config; 244 } 245 } 246 247 /** 248 * Parse each config with the form {pakName./receiverName : signal1, signal2,.} and cached the 249 * result internally to avoid repeated polling 250 * @see #CARRIER_SIGNAL_DELIMITER 251 * @see #COMPONENT_NAME_DELIMITER 252 * @param configs raw information from carrier config 253 */ parseAndCache(String[] configs)254 private Map<String, Set<ComponentName>> parseAndCache(String[] configs) { 255 Map<String, Set<ComponentName>> newCachedWakeSignalConfigs = new HashMap<>(); 256 if (!ArrayUtils.isEmpty(configs)) { 257 for (String config : configs) { 258 if (!TextUtils.isEmpty(config)) { 259 String[] splitStr = config.trim().split(COMPONENT_NAME_DELIMITER, 2); 260 if (splitStr.length == 2) { 261 ComponentName componentName = ComponentName 262 .unflattenFromString(splitStr[0]); 263 if (componentName == null) { 264 loge("Invalid component name: " + splitStr[0]); 265 continue; 266 } 267 String[] signals = splitStr[1].split(CARRIER_SIGNAL_DELIMITER); 268 for (String s : signals) { 269 if (!VALID_CARRIER_SIGNAL_ACTIONS.contains(s)) { 270 // It could be a legacy action in the com.android.internal.telephony 271 // namespace. If that's the case, translate it to the new actions. 272 if (COMPAT_ACTION_TO_NEW_MAP.containsKey(s)) { 273 s = COMPAT_ACTION_TO_NEW_MAP.get(s); 274 } else { 275 loge("Invalid signal name: " + s); 276 continue; 277 } 278 } 279 Set<ComponentName> componentList = newCachedWakeSignalConfigs.get(s); 280 if (componentList == null) { 281 componentList = new HashSet<>(); 282 newCachedWakeSignalConfigs.put(s, componentList); 283 } 284 componentList.add(componentName); 285 if (VDBG) { 286 logv("Add config " + "{signal: " + s 287 + " componentName: " + componentName + "}"); 288 } 289 } 290 } else { 291 loge("invalid config format: " + config); 292 } 293 } 294 } 295 } 296 return newCachedWakeSignalConfigs; 297 } 298 299 /** 300 * Check if there are registered carrier broadcast receivers to handle the passing intent 301 */ hasRegisteredReceivers(String action)302 public boolean hasRegisteredReceivers(String action) { 303 return mCachedWakeSignalConfigs.containsKey(action) 304 || mCachedNoWakeSignalConfigs.containsKey(action); 305 } 306 307 /** 308 * Broadcast the intents explicitly. 309 * Some correctness checks will be applied before broadcasting. 310 * - for non-wakeup(runtime) receivers, make sure the intent is not declared in their manifests 311 * and apply FLAG_EXCLUDE_STOPPED_PACKAGES to avoid wake-up 312 * - for wakeup(manifest) receivers, make sure there are matched receivers with registered 313 * intents. 314 * 315 * @param intent intent which signals carrier apps 316 * @param receivers a list of component name for broadcast receivers. 317 * Those receivers could either be statically declared in Manifest or 318 * registered during run-time. 319 * @param wakeup true indicate wakeup receivers otherwise non-wakeup receivers 320 */ broadcast(Intent intent, Set<ComponentName> receivers, boolean wakeup)321 private void broadcast(Intent intent, Set<ComponentName> receivers, boolean wakeup) { 322 final PackageManager packageManager = mPhone.getContext().getPackageManager(); 323 for (ComponentName name : receivers) { 324 Intent signal = new Intent(intent); 325 if (wakeup) { 326 signal.setComponent(name); 327 } else { 328 // Explicit intents won't reach dynamically registered receivers -- set the package 329 // instead. 330 signal.setPackage(name.getPackageName()); 331 } 332 333 if (wakeup && packageManager.queryBroadcastReceivers(signal, 334 PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) { 335 loge("Carrier signal receivers are configured but unavailable: " 336 + signal.getComponent()); 337 continue; 338 } 339 if (!wakeup && !packageManager.queryBroadcastReceivers(signal, 340 PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) { 341 loge("Runtime signals shouldn't be configured in Manifest: " 342 + signal.getComponent()); 343 continue; 344 } 345 346 SubscriptionManager.putSubscriptionIdExtra(signal, mPhone.getSubId()); 347 signal.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 348 if (!wakeup) signal.setFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); 349 350 Intent compatIntent = null; 351 try { 352 if (mPhone.getContext().getPackageManager() 353 .getApplicationInfo(name.getPackageName(), 0).targetSdkVersion 354 <= Build.VERSION_CODES.R) { 355 compatIntent = createCompatIntent(signal); 356 } 357 } catch (PackageManager.NameNotFoundException e) { 358 // ignore, don't do anything special for compatibility 359 } 360 try { 361 Intent intentToSend = compatIntent == null ? signal : compatIntent; 362 mPhone.getContext().sendBroadcastAsUser(intentToSend, UserHandle.ALL); 363 if (DBG) { 364 log("Sending signal " + intentToSend.getAction() 365 + " to the carrier signal receiver: " + intentToSend.getComponent()); 366 } 367 } catch (ActivityNotFoundException e) { 368 loge("Send broadcast failed: " + e); 369 } 370 } 371 } 372 373 /** 374 * Match the intent against cached tables to find a list of registered carrier signal 375 * receivers and broadcast the intent. 376 * @param intent broadcasting intent, it could belong to wakeup, non-wakeup signal list or both 377 * 378 */ notifyCarrierSignalReceivers(Intent intent)379 public void notifyCarrierSignalReceivers(Intent intent) { 380 Set<ComponentName> receiverSet; 381 382 synchronized (mCachedWakeSignalConfigs) { 383 receiverSet = mCachedWakeSignalConfigs.get(intent.getAction()); 384 if (!ArrayUtils.isEmpty(receiverSet)) { 385 broadcast(intent, receiverSet, WAKE); 386 } 387 } 388 389 synchronized (mCachedNoWakeSignalConfigs) { 390 receiverSet = mCachedNoWakeSignalConfigs.get(intent.getAction()); 391 if (!ArrayUtils.isEmpty(receiverSet)) { 392 broadcast(intent, receiverSet, NO_WAKE); 393 } 394 } 395 } 396 createCompatIntent(Intent original)397 private static @Nullable Intent createCompatIntent(Intent original) { 398 String compatAction = NEW_ACTION_TO_COMPAT_MAP.get(original.getAction()); 399 if (compatAction == null) { 400 Rlog.i(LOG_TAG, "intent action " + original.getAction() + " does not have a" 401 + " compat alternative for component " + original.getComponent()); 402 return null; 403 } 404 Intent compatIntent = new Intent(original); 405 compatIntent.setAction(compatAction); 406 for (String extraKey : original.getExtras().keySet()) { 407 switch (extraKey) { 408 case TelephonyManager.EXTRA_REDIRECTION_URL: 409 compatIntent.putExtra(TelephonyIntents.EXTRA_REDIRECTION_URL, 410 original.getStringExtra(TelephonyManager.EXTRA_REDIRECTION_URL)); 411 break; 412 case TelephonyManager.EXTRA_DATA_FAIL_CAUSE: 413 compatIntent.putExtra(TelephonyIntents.EXTRA_ERROR_CODE, 414 original.getIntExtra(TelephonyManager.EXTRA_DATA_FAIL_CAUSE, -1)); 415 break; 416 case TelephonyManager.EXTRA_PCO_ID: 417 compatIntent.putExtra(TelephonyIntents.EXTRA_PCO_ID, 418 original.getIntExtra(TelephonyManager.EXTRA_PCO_ID, -1)); 419 break; 420 case TelephonyManager.EXTRA_PCO_VALUE: 421 compatIntent.putExtra(TelephonyIntents.EXTRA_PCO_VALUE, 422 original.getByteArrayExtra(TelephonyManager.EXTRA_PCO_VALUE)); 423 break; 424 case TelephonyManager.EXTRA_DEFAULT_NETWORK_AVAILABLE: 425 compatIntent.putExtra(TelephonyIntents.EXTRA_DEFAULT_NETWORK_AVAILABLE, 426 original.getBooleanExtra( 427 TelephonyManager.EXTRA_DEFAULT_NETWORK_AVAILABLE, false)); 428 break; 429 case TelephonyManager.EXTRA_APN_TYPE: 430 int apnType = original.getIntExtra(TelephonyManager.EXTRA_APN_TYPE, 431 ApnSetting.TYPE_DEFAULT); 432 compatIntent.putExtra(TelephonyIntents.EXTRA_APN_TYPE_INT, apnType); 433 compatIntent.putExtra(TelephonyIntents.EXTRA_APN_TYPE, 434 ApnSetting.getApnTypesStringFromBitmask(apnType)); 435 break; 436 case TelephonyManager.EXTRA_APN_PROTOCOL: 437 int apnProtocol = original.getIntExtra(TelephonyManager.EXTRA_APN_PROTOCOL, -1); 438 compatIntent.putExtra(TelephonyIntents.EXTRA_APN_PROTOCOL_INT, apnProtocol); 439 compatIntent.putExtra(TelephonyIntents.EXTRA_APN_PROTOCOL, 440 ApnSetting.getProtocolStringFromInt(apnProtocol)); 441 break; 442 } 443 } 444 return compatIntent; 445 } 446 log(String s)447 private void log(String s) { 448 Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 449 } 450 loge(String s)451 private void loge(String s) { 452 mErrorLocalLog.log(s); 453 Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 454 } 455 logv(String s)456 private void logv(String s) { 457 Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 458 } 459 dump(FileDescriptor fd, PrintWriter pw, String[] args)460 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 461 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 462 pw.println("mCachedWakeSignalConfigs:"); 463 ipw.increaseIndent(); 464 for (Map.Entry<String, Set<ComponentName>> entry : mCachedWakeSignalConfigs.entrySet()) { 465 pw.println("signal: " + entry.getKey() + " componentName list: " + entry.getValue()); 466 } 467 ipw.decreaseIndent(); 468 469 pw.println("mCachedNoWakeSignalConfigs:"); 470 ipw.increaseIndent(); 471 for (Map.Entry<String, Set<ComponentName>> entry : mCachedNoWakeSignalConfigs.entrySet()) { 472 pw.println("signal: " + entry.getKey() + " componentName list: " + entry.getValue()); 473 } 474 ipw.decreaseIndent(); 475 476 pw.println("mDefaultNetworkAvail: " + mDefaultNetworkAvail); 477 478 pw.println("error log:"); 479 ipw.increaseIndent(); 480 mErrorLocalLog.dump(fd, pw, args); 481 ipw.decreaseIndent(); 482 } 483 } 484