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