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