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.content.ActivityNotFoundException; 22 import android.content.BroadcastReceiver; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.pm.PackageManager; 28 import android.net.ConnectivityManager; 29 import android.net.Network; 30 import android.os.AsyncResult; 31 import android.os.Handler; 32 import android.os.Message; 33 import android.os.PersistableBundle; 34 import android.os.UserHandle; 35 import android.telephony.CarrierConfigManager; 36 import android.telephony.SubscriptionManager; 37 import android.telephony.TelephonyManager; 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.Arrays; 49 import java.util.HashMap; 50 import java.util.HashSet; 51 import java.util.Map; 52 import java.util.Set; 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 final Set<String> mCarrierSignalList = new HashSet<>(Arrays.asList( 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 final LocalLog mErrorLocalLog = new LocalLog(20); 109 110 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 111 public void onReceive(Context context, Intent intent) { 112 String action = intent.getAction(); 113 if (DBG) log("CarrierSignalAgent receiver action: " + action); 114 if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { 115 loadCarrierConfig(); 116 } 117 } 118 }; 119 120 private ConnectivityManager.NetworkCallback mNetworkCallback; 121 122 /** Constructor */ CarrierSignalAgent(Phone phone)123 public CarrierSignalAgent(Phone phone) { 124 mPhone = phone; 125 loadCarrierConfig(); 126 // reload configurations on CARRIER_CONFIG_CHANGED 127 mPhone.getContext().registerReceiver(mReceiver, 128 new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); 129 mPhone.getCarrierActionAgent().registerForCarrierAction( 130 CarrierActionAgent.CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS, this, 131 EVENT_REGISTER_DEFAULT_NETWORK_AVAIL, null, false); 132 } 133 134 @Override handleMessage(Message msg)135 public void handleMessage(Message msg) { 136 switch (msg.what) { 137 case EVENT_REGISTER_DEFAULT_NETWORK_AVAIL: 138 AsyncResult ar = (AsyncResult) msg.obj; 139 if (ar.exception != null) { 140 Rlog.e(LOG_TAG, "Register default network exception: " + ar.exception); 141 return; 142 } 143 final ConnectivityManager connectivityMgr = mPhone.getContext() 144 .getSystemService(ConnectivityManager.class); 145 if ((boolean) ar.result) { 146 mNetworkCallback = new ConnectivityManager.NetworkCallback() { 147 @Override 148 public void onAvailable(Network network) { 149 // an optimization to avoid signaling on every default network switch. 150 if (!mDefaultNetworkAvail) { 151 if (DBG) log("Default network available: " + network); 152 Intent intent = new Intent(TelephonyManager 153 .ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE); 154 intent.putExtra( 155 TelephonyManager.EXTRA_DEFAULT_NETWORK_AVAILABLE, true); 156 notifyCarrierSignalReceivers(intent); 157 mDefaultNetworkAvail = true; 158 } 159 } 160 @Override 161 public void onLost(Network network) { 162 if (DBG) log("Default network lost: " + network); 163 Intent intent = new Intent(TelephonyManager 164 .ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE); 165 intent.putExtra( 166 TelephonyManager.EXTRA_DEFAULT_NETWORK_AVAILABLE, false); 167 notifyCarrierSignalReceivers(intent); 168 mDefaultNetworkAvail = false; 169 } 170 }; 171 connectivityMgr.registerDefaultNetworkCallback(mNetworkCallback, mPhone); 172 log("Register default network"); 173 174 } else if (mNetworkCallback != null) { 175 connectivityMgr.unregisterNetworkCallback(mNetworkCallback); 176 mNetworkCallback = null; 177 mDefaultNetworkAvail = false; 178 log("unregister default network"); 179 } 180 break; 181 default: 182 break; 183 } 184 } 185 186 /** 187 * load carrier config and cached the results into a hashMap action -> array list of components. 188 */ loadCarrierConfig()189 private void loadCarrierConfig() { 190 CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() 191 .getSystemService(Context.CARRIER_CONFIG_SERVICE); 192 PersistableBundle b = null; 193 if (configManager != null) { 194 b = configManager.getConfig(); 195 } 196 if (b != null) { 197 synchronized (mCachedWakeSignalConfigs) { 198 log("Loading carrier config: " + KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY); 199 Map<String, Set<ComponentName>> config = parseAndCache( 200 b.getStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY)); 201 // In some rare cases, up-to-date config could be fetched with delay and all signals 202 // have already been delivered the receivers from the default carrier config. 203 // To handle this raciness, we should notify those receivers (from old configs) 204 // and reset carrier actions. This should be done before cached Config got purged 205 // and written with the up-to-date value, Otherwise those receivers from the 206 // old config might lingers without properly clean-up. 207 if (!mCachedWakeSignalConfigs.isEmpty() 208 && !config.equals(mCachedWakeSignalConfigs)) { 209 if (VDBG) log("carrier config changed, reset receivers from old config"); 210 mPhone.getCarrierActionAgent().sendEmptyMessage( 211 CarrierActionAgent.CARRIER_ACTION_RESET); 212 } 213 mCachedWakeSignalConfigs = config; 214 } 215 216 synchronized (mCachedNoWakeSignalConfigs) { 217 log("Loading carrier config: " 218 + KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY); 219 Map<String, Set<ComponentName>> config = parseAndCache( 220 b.getStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY)); 221 if (!mCachedNoWakeSignalConfigs.isEmpty() 222 && !config.equals(mCachedNoWakeSignalConfigs)) { 223 if (VDBG) log("carrier config changed, reset receivers from old config"); 224 mPhone.getCarrierActionAgent().sendEmptyMessage( 225 CarrierActionAgent.CARRIER_ACTION_RESET); 226 } 227 mCachedNoWakeSignalConfigs = config; 228 } 229 } 230 } 231 232 /** 233 * Parse each config with the form {pakName./receiverName : signal1, signal2,.} and cached the 234 * result internally to avoid repeated polling 235 * @see #CARRIER_SIGNAL_DELIMITER 236 * @see #COMPONENT_NAME_DELIMITER 237 * @param configs raw information from carrier config 238 */ parseAndCache(String[] configs)239 private Map<String, Set<ComponentName>> parseAndCache(String[] configs) { 240 Map<String, Set<ComponentName>> newCachedWakeSignalConfigs = new HashMap<>(); 241 if (!ArrayUtils.isEmpty(configs)) { 242 for (String config : configs) { 243 if (!TextUtils.isEmpty(config)) { 244 String[] splitStr = config.trim().split(COMPONENT_NAME_DELIMITER, 2); 245 if (splitStr.length == 2) { 246 ComponentName componentName = ComponentName 247 .unflattenFromString(splitStr[0]); 248 if (componentName == null) { 249 loge("Invalid component name: " + splitStr[0]); 250 continue; 251 } 252 String[] signals = splitStr[1].split(CARRIER_SIGNAL_DELIMITER); 253 for (String s : signals) { 254 if (!mCarrierSignalList.contains(s)) { 255 loge("Invalid signal name: " + s); 256 continue; 257 } 258 Set<ComponentName> componentList = newCachedWakeSignalConfigs.get(s); 259 if (componentList == null) { 260 componentList = new HashSet<>(); 261 newCachedWakeSignalConfigs.put(s, componentList); 262 } 263 componentList.add(componentName); 264 if (VDBG) { 265 logv("Add config " + "{signal: " + s 266 + " componentName: " + componentName + "}"); 267 } 268 } 269 } else { 270 loge("invalid config format: " + config); 271 } 272 } 273 } 274 } 275 return newCachedWakeSignalConfigs; 276 } 277 278 /** 279 * Check if there are registered carrier broadcast receivers to handle the passing intent 280 */ hasRegisteredReceivers(String action)281 public boolean hasRegisteredReceivers(String action) { 282 return mCachedWakeSignalConfigs.containsKey(action) 283 || mCachedNoWakeSignalConfigs.containsKey(action); 284 } 285 286 /** 287 * Broadcast the intents explicitly. 288 * Some correctness checks will be applied before broadcasting. 289 * - for non-wakeup(runtime) receivers, make sure the intent is not declared in their manifests 290 * and apply FLAG_EXCLUDE_STOPPED_PACKAGES to avoid wake-up 291 * - for wakeup(manifest) receivers, make sure there are matched receivers with registered 292 * intents. 293 * 294 * @param intent intent which signals carrier apps 295 * @param receivers a list of component name for broadcast receivers. 296 * Those receivers could either be statically declared in Manifest or 297 * registered during run-time. 298 * @param wakeup true indicate wakeup receivers otherwise non-wakeup receivers 299 */ broadcast(Intent intent, Set<ComponentName> receivers, boolean wakeup)300 private void broadcast(Intent intent, Set<ComponentName> receivers, boolean wakeup) { 301 final PackageManager packageManager = mPhone.getContext().getPackageManager(); 302 for (ComponentName name : receivers) { 303 Intent signal = new Intent(intent); 304 signal.setComponent(name); 305 306 if (wakeup && packageManager.queryBroadcastReceivers(signal, 307 PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) { 308 loge("Carrier signal receivers are configured but unavailable: " 309 + signal.getComponent()); 310 continue; 311 } 312 if (!wakeup && !packageManager.queryBroadcastReceivers(signal, 313 PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) { 314 loge("Runtime signals shouldn't be configured in Manifest: " 315 + signal.getComponent()); 316 continue; 317 } 318 319 SubscriptionManager.putSubscriptionIdExtra(signal, 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