ConnectivityService.java revision 0f79b54c3a0b4141b1da38fa301571a89e165632
1/* 2 * Copyright (C) 2008 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 17package com.android.server; 18 19import android.app.Notification; 20import android.app.NotificationManager; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.pm.PackageManager; 25import android.net.ConnectivityManager; 26import android.net.IConnectivityManager; 27import android.net.MobileDataStateTracker; 28import android.net.NetworkInfo; 29import android.net.NetworkStateTracker; 30import android.net.wifi.WifiStateTracker; 31import android.os.Binder; 32import android.os.Handler; 33import android.os.IBinder; 34import android.os.Looper; 35import android.os.Message; 36import android.os.RemoteException; 37import android.os.ServiceManager; 38import android.os.SystemProperties; 39import android.provider.Settings; 40import android.text.TextUtils; 41import android.util.EventLog; 42import android.util.Log; 43 44import com.android.internal.telephony.Phone; 45 46import java.io.FileDescriptor; 47import java.io.PrintWriter; 48import java.util.ArrayList; 49import java.util.List; 50 51/** 52 * @hide 53 */ 54public class ConnectivityService extends IConnectivityManager.Stub { 55 56 private static final boolean DBG = true; 57 private static final String TAG = "ConnectivityService"; 58 59 // Event log tags (must be in sync with event-log-tags) 60 private static final int EVENTLOG_CONNECTIVITY_STATE_CHANGED = 50020; 61 62 // how long to wait before switching back to a radio's default network 63 private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000; 64 // system property that can override the above value 65 private static final String NETWORK_RESTORE_DELAY_PROP_NAME = 66 "android.telephony.apn-restore"; 67 68 /** 69 * Sometimes we want to refer to the individual network state 70 * trackers separately, and sometimes we just want to treat them 71 * abstractly. 72 */ 73 private NetworkStateTracker mNetTrackers[]; 74 75 /** 76 * A per Net list of the PID's that requested access to the net 77 * used both as a refcount and for per-PID DNS selection 78 */ 79 private List mNetRequestersPids[]; 80 81 private WifiWatchdogService mWifiWatchdogService; 82 83 // priority order of the nettrackers 84 // (excluding dynamically set mNetworkPreference) 85 // TODO - move mNetworkTypePreference into this 86 private int[] mPriorityList; 87 88 private Context mContext; 89 private int mNetworkPreference; 90 private int mActiveDefaultNetwork = -1; 91 92 private int mNumDnsEntries; 93 94 private boolean mTestMode; 95 private static ConnectivityService sServiceInstance; 96 97 private Handler mHandler; 98 99 // list of DeathRecipients used to make sure features are turned off when 100 // a process dies 101 private List mFeatureUsers; 102 103 private boolean mSystemReady; 104 private ArrayList<Intent> mDeferredBroadcasts; 105 106 private class NetworkAttributes { 107 /** 108 * Class for holding settings read from resources. 109 */ 110 public String mName; 111 public int mType; 112 public int mRadio; 113 public int mPriority; 114 public NetworkAttributes(String init) { 115 String fragments[] = init.split(","); 116 mName = fragments[0].toLowerCase(); 117 if (fragments[1].toLowerCase().equals("wifi")) { 118 mRadio = ConnectivityManager.TYPE_WIFI; 119 } else { 120 mRadio = ConnectivityManager.TYPE_MOBILE; 121 } 122 if (mName.equals("default")) { 123 mType = mRadio; 124 } else if (mName.equals("mms")) { 125 mType = ConnectivityManager.TYPE_MOBILE_MMS; 126 } else if (mName.equals("supl")) { 127 mType = ConnectivityManager.TYPE_MOBILE_SUPL; 128 } else if (mName.equals("dun")) { 129 mType = ConnectivityManager.TYPE_MOBILE_DUN; 130 } else if (mName.equals("hipri")) { 131 mType = ConnectivityManager.TYPE_MOBILE_HIPRI; 132 } 133 mPriority = Integer.parseInt(fragments[2]); 134 } 135 public boolean isDefault() { 136 return (mType == mRadio); 137 } 138 } 139 NetworkAttributes[] mNetAttributes; 140 141 private class RadioAttributes { 142 public String mName; 143 public int mPriority; 144 public int mSimultaneity; 145 public int mType; 146 public RadioAttributes(String init) { 147 String fragments[] = init.split(","); 148 mName = fragments[0].toLowerCase(); 149 mPriority = Integer.parseInt(fragments[1]); 150 mSimultaneity = Integer.parseInt(fragments[2]); 151 if (mName.equals("wifi")) { 152 mType = ConnectivityManager.TYPE_WIFI; 153 } else { 154 mType = ConnectivityManager.TYPE_MOBILE; 155 } 156 } 157 } 158 RadioAttributes[] mRadioAttributes; 159 160 private static class ConnectivityThread extends Thread { 161 private Context mContext; 162 163 private ConnectivityThread(Context context) { 164 super("ConnectivityThread"); 165 mContext = context; 166 } 167 168 @Override 169 public void run() { 170 Looper.prepare(); 171 synchronized (this) { 172 sServiceInstance = new ConnectivityService(mContext); 173 notifyAll(); 174 } 175 Looper.loop(); 176 } 177 178 public static ConnectivityService getServiceInstance(Context context) { 179 ConnectivityThread thread = new ConnectivityThread(context); 180 thread.start(); 181 182 synchronized (thread) { 183 while (sServiceInstance == null) { 184 try { 185 // Wait until sServiceInstance has been initialized. 186 thread.wait(); 187 } catch (InterruptedException ignore) { 188 Log.e(TAG, 189 "Unexpected InterruptedException while waiting"+ 190 " for ConnectivityService thread"); 191 } 192 } 193 } 194 195 return sServiceInstance; 196 } 197 } 198 199 public static ConnectivityService getInstance(Context context) { 200 return ConnectivityThread.getServiceInstance(context); 201 } 202 203 private ConnectivityService(Context context) { 204 if (DBG) Log.v(TAG, "ConnectivityService starting up"); 205 mContext = context; 206 mNetTrackers = new NetworkStateTracker[ 207 ConnectivityManager.MAX_NETWORK_TYPE+1]; 208 mHandler = new MyHandler(); 209 210 mNetworkPreference = getPersistedNetworkPreference(); 211 212 // Load device network attributes from resources 213 mNetAttributes = new NetworkAttributes[ 214 ConnectivityManager.MAX_NETWORK_TYPE+1]; 215 mRadioAttributes = new RadioAttributes[ 216 ConnectivityManager.MAX_RADIO_TYPE+1]; 217 String[] naStrings = context.getResources().getStringArray( 218 com.android.internal.R.array.networkAttributes); 219 // TODO - what if the setting has gaps/unknown types? 220 for (String a : naStrings) { 221 NetworkAttributes n = new NetworkAttributes(a); 222 mNetAttributes[n.mType] = n; 223 } 224 String[] raStrings = context.getResources().getStringArray( 225 com.android.internal.R.array.radioAttributes); 226 for (String a : raStrings) { 227 RadioAttributes r = new RadioAttributes(a); 228 mRadioAttributes[r.mType] = r; 229 } 230 231 // high priority first 232 mPriorityList = new int[naStrings.length]; 233 { 234 int priority = 0; //lowest 235 int nextPos = naStrings.length-1; 236 while (nextPos>-1) { 237 for (int i = 0; i < mNetAttributes.length; i++) { 238 if(mNetAttributes[i].mPriority == priority) { 239 mPriorityList[nextPos--] = i; 240 } 241 } 242 priority++; 243 } 244 } 245 246 mNetRequestersPids = 247 new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; 248 for (int i=0; i<=ConnectivityManager.MAX_NETWORK_TYPE; i++) { 249 mNetRequestersPids[i] = new ArrayList(); 250 } 251 252 mFeatureUsers = new ArrayList(); 253 254 /* 255 * Create the network state trackers for Wi-Fi and mobile 256 * data. Maybe this could be done with a factory class, 257 * but it's not clear that it's worth it, given that 258 * the number of different network types is not going 259 * to change very often. 260 */ 261 if (DBG) Log.v(TAG, "Starting Wifi Service."); 262 WifiStateTracker wst = new WifiStateTracker(context, mHandler); 263 WifiService wifiService = new WifiService(context, wst); 264 ServiceManager.addService(Context.WIFI_SERVICE, wifiService); 265 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst; 266 267 mNetTrackers[ConnectivityManager.TYPE_MOBILE] = 268 new MobileDataStateTracker(context, mHandler, 269 ConnectivityManager.TYPE_MOBILE, Phone.APN_TYPE_DEFAULT, 270 "MOBILE"); 271 272 mNetTrackers[ConnectivityManager.TYPE_MOBILE_MMS] = 273 new MobileDataStateTracker(context, mHandler, 274 ConnectivityManager.TYPE_MOBILE_MMS, Phone.APN_TYPE_MMS, 275 "MOBILE_MMS"); 276 277 mNetTrackers[ConnectivityManager.TYPE_MOBILE_SUPL] = 278 new MobileDataStateTracker(context, mHandler, 279 ConnectivityManager.TYPE_MOBILE_SUPL, Phone.APN_TYPE_SUPL, 280 "MOBILE_SUPL"); 281 282 mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] = 283 new MobileDataStateTracker(context, mHandler, 284 ConnectivityManager.TYPE_MOBILE_DUN, Phone.APN_TYPE_DUN, 285 "MOBILE_DUN"); 286 287 mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI] = 288 new MobileDataStateTracker(context, mHandler, 289 ConnectivityManager.TYPE_MOBILE_HIPRI, Phone.APN_TYPE_HIPRI, 290 "MOBILE_HIPRI"); 291 292 mNumDnsEntries = 0; 293 294 mTestMode = SystemProperties.get("cm.test.mode").equals("true") 295 && SystemProperties.get("ro.build.type").equals("eng"); 296 297 for (NetworkStateTracker t : mNetTrackers) 298 t.startMonitoring(); 299 300 // Constructing this starts it too 301 mWifiWatchdogService = new WifiWatchdogService(context, wst); 302 } 303 304 /** 305 * Sets the preferred network. 306 * @param preference the new preference 307 */ 308 public synchronized void setNetworkPreference(int preference) { 309 enforceChangePermission(); 310 if (ConnectivityManager.isNetworkTypeValid(preference) && 311 mNetAttributes[preference].isDefault()) { 312 if (mNetworkPreference != preference) { 313 persistNetworkPreference(preference); 314 mNetworkPreference = preference; 315 enforcePreference(); 316 } 317 } 318 } 319 320 public int getNetworkPreference() { 321 enforceAccessPermission(); 322 return mNetworkPreference; 323 } 324 325 private void persistNetworkPreference(int networkPreference) { 326 final ContentResolver cr = mContext.getContentResolver(); 327 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, 328 networkPreference); 329 } 330 331 private int getPersistedNetworkPreference() { 332 final ContentResolver cr = mContext.getContentResolver(); 333 334 final int networkPrefSetting = Settings.Secure 335 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1); 336 if (networkPrefSetting != -1) { 337 return networkPrefSetting; 338 } 339 340 return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE; 341 } 342 343 /** 344 * Make the state of network connectivity conform to the preference settings 345 * In this method, we only tear down a non-preferred network. Establishing 346 * a connection to the preferred network is taken care of when we handle 347 * the disconnect event from the non-preferred network 348 * (see {@link #handleDisconnect(NetworkInfo)}). 349 */ 350 private void enforcePreference() { 351 if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected()) 352 return; 353 354 if (!mNetTrackers[mNetworkPreference].isAvailable()) 355 return; 356 357 for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) { 358 if (t != mNetworkPreference && 359 mNetTrackers[t].getNetworkInfo().isConnected()) { 360 teardown(mNetTrackers[t]); 361 } 362 } 363 } 364 365 private boolean teardown(NetworkStateTracker netTracker) { 366 if (netTracker.teardown()) { 367 netTracker.setTeardownRequested(true); 368 return true; 369 } else { 370 return false; 371 } 372 } 373 374 /** 375 * Return NetworkInfo for the active (i.e., connected) network interface. 376 * It is assumed that at most one network is active at a time. If more 377 * than one is active, it is indeterminate which will be returned. 378 * @return the info for the active network, or {@code null} if none is 379 * active 380 */ 381 public NetworkInfo getActiveNetworkInfo() { 382 enforceAccessPermission(); 383 for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { 384 if (!mNetAttributes[type].isDefault()) { 385 continue; 386 } 387 NetworkStateTracker t = mNetTrackers[type]; 388 NetworkInfo info = t.getNetworkInfo(); 389 if (info.isConnected()) { 390 if (DBG && type != mActiveDefaultNetwork) Log.e(TAG, 391 "connected default network is not " + 392 "mActiveDefaultNetwork!"); 393 return info; 394 } 395 } 396 return null; 397 } 398 399 public NetworkInfo getNetworkInfo(int networkType) { 400 enforceAccessPermission(); 401 if (ConnectivityManager.isNetworkTypeValid(networkType)) { 402 NetworkStateTracker t = mNetTrackers[networkType]; 403 if (t != null) 404 return t.getNetworkInfo(); 405 } 406 return null; 407 } 408 409 public NetworkInfo[] getAllNetworkInfo() { 410 enforceAccessPermission(); 411 NetworkInfo[] result = new NetworkInfo[mNetTrackers.length]; 412 int i = 0; 413 for (NetworkStateTracker t : mNetTrackers) { 414 result[i++] = t.getNetworkInfo(); 415 } 416 return result; 417 } 418 419 public boolean setRadios(boolean turnOn) { 420 boolean result = true; 421 enforceChangePermission(); 422 for (NetworkStateTracker t : mNetTrackers) { 423 result = t.setRadio(turnOn) && result; 424 } 425 return result; 426 } 427 428 public boolean setRadio(int netType, boolean turnOn) { 429 enforceChangePermission(); 430 if (!ConnectivityManager.isNetworkTypeValid(netType)) { 431 return false; 432 } 433 NetworkStateTracker tracker = mNetTrackers[netType]; 434 return tracker != null && tracker.setRadio(turnOn); 435 } 436 437 private class FeatureUser implements IBinder.DeathRecipient { 438 int mNetworkType; 439 String mFeature; 440 IBinder mBinder; 441 int mPid; 442 int mUid; 443 444 FeatureUser(int type, String feature, IBinder binder) { 445 super(); 446 mNetworkType = type; 447 mFeature = feature; 448 mBinder = binder; 449 mPid = getCallingPid(); 450 mUid = getCallingUid(); 451 try { 452 mBinder.linkToDeath(this, 0); 453 } catch (RemoteException e) { 454 binderDied(); 455 } 456 } 457 458 void unlinkDeathRecipient() { 459 mBinder.unlinkToDeath(this, 0); 460 } 461 462 public void binderDied() { 463 Log.d(TAG, "ConnectivityService FeatureUser binderDied(" + 464 mNetworkType + ", " + mFeature + ", " + mBinder); 465 stopUsingNetworkFeature(mNetworkType, mFeature, mPid, mUid); 466 } 467 468 } 469 470 public int startUsingNetworkFeature(int networkType, String feature, 471 IBinder binder) { 472 if (DBG) { 473 Log.d(TAG, "startUsingNetworkFeature for net " + networkType + 474 ": " + feature); 475 } 476 enforceChangePermission(); 477 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 478 return Phone.APN_REQUEST_FAILED; 479 } 480 481 synchronized (mFeatureUsers) { 482 mFeatureUsers.add(new FeatureUser(networkType, feature, binder)); 483 } 484 485 // TODO - move this into the MobileDataStateTracker 486 int usedNetworkType = networkType; 487 if(networkType == ConnectivityManager.TYPE_MOBILE) { 488 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { 489 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS; 490 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { 491 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL; 492 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) { 493 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; 494 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { 495 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; 496 } 497 } 498 NetworkStateTracker network = mNetTrackers[usedNetworkType]; 499 if (network != null) { 500 if (usedNetworkType != networkType) { 501 Integer currentPid = new Integer(getCallingPid()); 502 503 NetworkStateTracker radio = mNetTrackers[networkType]; 504 NetworkInfo ni = network.getNetworkInfo(); 505 506 if (ni.isAvailable() == false) { 507 if (DBG) Log.d(TAG, "special network not available"); 508 return Phone.APN_TYPE_NOT_AVAILABLE; 509 } 510 511 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { 512 // this gets used for per-pid dns when connected 513 mNetRequestersPids[usedNetworkType].add(currentPid); 514 } 515 516 if (ni.isConnectedOrConnecting() == true) { 517 if (ni.isConnected() == true) { 518 // add the pid-specific dns 519 handleDnsConfigurationChange(); 520 if (DBG) Log.d(TAG, "special network already active"); 521 return Phone.APN_ALREADY_ACTIVE; 522 } 523 if (DBG) Log.d(TAG, "special network already connecting"); 524 return Phone.APN_REQUEST_STARTED; 525 } 526 527 // check if the radio in play can make another contact 528 // assume if cannot for now 529 530 // since we have to drop the default on this radio, setup 531 // an automatic event to switch back 532 if(mHandler.hasMessages(NetworkStateTracker. 533 EVENT_RESTORE_DEFAULT_NETWORK, radio) || 534 radio.getNetworkInfo().isConnectedOrConnecting()) { 535 mHandler.removeMessages(NetworkStateTracker. 536 EVENT_RESTORE_DEFAULT_NETWORK, 537 radio); 538 mHandler.sendMessageDelayed(mHandler.obtainMessage( 539 NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK, 540 radio), getRestoreDefaultNetworkDelay()); 541 } 542 if (DBG) Log.d(TAG, "reconnecting to special network"); 543 network.reconnect(); 544 return Phone.APN_REQUEST_STARTED; 545 } else { 546 return network.startUsingNetworkFeature(feature, 547 getCallingPid(), getCallingUid()); 548 } 549 } 550 return Phone.APN_TYPE_NOT_AVAILABLE; 551 } 552 553 public int stopUsingNetworkFeature(int networkType, String feature) { 554 return stopUsingNetworkFeature(networkType, feature, getCallingPid(), 555 getCallingUid()); 556 } 557 558 private int stopUsingNetworkFeature(int networkType, String feature, 559 int pid, int uid) { 560 if (DBG) { 561 Log.d(TAG, "stopUsingNetworkFeature for net " + networkType + 562 ": " + feature); 563 } 564 enforceChangePermission(); 565 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 566 return -1; 567 } 568 569 synchronized (mFeatureUsers) { 570 for (int i=0; i < mFeatureUsers.size(); i++) { 571 FeatureUser u = (FeatureUser)mFeatureUsers.get(i); 572 if (uid == u.mUid && pid == u.mPid && 573 networkType == u.mNetworkType && 574 TextUtils.equals(feature, u.mFeature)) { 575 u.unlinkDeathRecipient(); 576 mFeatureUsers.remove(i); 577 break; 578 } 579 } 580 } 581 582 // TODO - move to MobileDataStateTracker 583 int usedNetworkType = networkType; 584 if (networkType == ConnectivityManager.TYPE_MOBILE) { 585 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { 586 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS; 587 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { 588 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL; 589 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) { 590 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; 591 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { 592 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; 593 } 594 } 595 NetworkStateTracker tracker = mNetTrackers[usedNetworkType]; 596 if(usedNetworkType != networkType) { 597 Integer currentPid = new Integer(pid); 598 if (mNetRequestersPids[usedNetworkType].remove(currentPid)) { 599 reassessPidDns(pid, true); 600 } 601 if (mNetRequestersPids[usedNetworkType].size() != 0) { 602 if (DBG) Log.d(TAG, "not tearing down special network - " + 603 "others still using it"); 604 return 1; 605 } 606 607 tracker.teardown(); 608 NetworkStateTracker radio = mNetTrackers[networkType]; 609 // Check if we want to revert to the default 610 if (mHandler.hasMessages(NetworkStateTracker. 611 EVENT_RESTORE_DEFAULT_NETWORK, radio)) { 612 mHandler.removeMessages(NetworkStateTracker. 613 EVENT_RESTORE_DEFAULT_NETWORK, radio); 614 radio.reconnect(); 615 } 616 return 1; 617 } else { 618 return tracker.stopUsingNetworkFeature(feature, pid, uid); 619 } 620 } 621 622 /** 623 * Ensure that a network route exists to deliver traffic to the specified 624 * host via the specified network interface. 625 * @param networkType the type of the network over which traffic to the 626 * specified host is to be routed 627 * @param hostAddress the IP address of the host to which the route is 628 * desired 629 * @return {@code true} on success, {@code false} on failure 630 */ 631 public boolean requestRouteToHost(int networkType, int hostAddress) { 632 enforceChangePermission(); 633 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 634 return false; 635 } 636 NetworkStateTracker tracker = mNetTrackers[networkType]; 637 /* 638 * If there's only one connected network, and it's the one requested, 639 * then we don't have to do anything - the requested route already 640 * exists. If it's not the requested network, then it's not possible 641 * to establish the requested route. Finally, if there is more than 642 * one connected network, then we must insert an entry in the routing 643 * table. 644 */ 645 if (getNumConnectedNetworks() > 1) { 646 return tracker.requestRouteToHost(hostAddress); 647 } else { 648 return (mNetAttributes[networkType].isDefault() && 649 tracker.getNetworkInfo().isConnected()); 650 } 651 } 652 653 /** 654 * @see ConnectivityManager#getBackgroundDataSetting() 655 */ 656 public boolean getBackgroundDataSetting() { 657 return Settings.Secure.getInt(mContext.getContentResolver(), 658 Settings.Secure.BACKGROUND_DATA, 1) == 1; 659 } 660 661 /** 662 * @see ConnectivityManager#setBackgroundDataSetting(boolean) 663 */ 664 public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) { 665 mContext.enforceCallingOrSelfPermission( 666 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING, 667 "ConnectivityService"); 668 669 if (getBackgroundDataSetting() == allowBackgroundDataUsage) return; 670 671 Settings.Secure.putInt(mContext.getContentResolver(), 672 Settings.Secure.BACKGROUND_DATA, 673 allowBackgroundDataUsage ? 1 : 0); 674 675 Intent broadcast = new Intent( 676 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); 677 mContext.sendBroadcast(broadcast); 678 } 679 680 private int getNumConnectedNetworks() { 681 int numConnectedNets = 0; 682 683 for (NetworkStateTracker nt : mNetTrackers) { 684 if (nt.getNetworkInfo().isConnected() && 685 !nt.isTeardownRequested()) { 686 ++numConnectedNets; 687 } 688 } 689 return numConnectedNets; 690 } 691 692 private void enforceAccessPermission() { 693 mContext.enforceCallingOrSelfPermission( 694 android.Manifest.permission.ACCESS_NETWORK_STATE, 695 "ConnectivityService"); 696 } 697 698 private void enforceChangePermission() { 699 mContext.enforceCallingOrSelfPermission( 700 android.Manifest.permission.CHANGE_NETWORK_STATE, 701 "ConnectivityService"); 702 } 703 704 /** 705 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active 706 * network, we ignore it. If it is for the active network, we send out a 707 * broadcast. But first, we check whether it might be possible to connect 708 * to a different network. 709 * @param info the {@code NetworkInfo} for the network 710 */ 711 private void handleDisconnect(NetworkInfo info) { 712 713 if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName()); 714 int prevNetType = info.getType(); 715 716 mNetTrackers[prevNetType].setTeardownRequested(false); 717 /* 718 * If the disconnected network is not the active one, then don't report 719 * this as a loss of connectivity. What probably happened is that we're 720 * getting the disconnect for a network that we explicitly disabled 721 * in accordance with network preference policies. 722 */ 723 if (!mNetAttributes[prevNetType].isDefault()) { 724 List pids = mNetRequestersPids[prevNetType]; 725 for (int i = 0; i<pids.size(); i++) { 726 Integer pid = (Integer)pids.get(i); 727 // will remove them because the net's no longer connected 728 // need to do this now as only now do we know the pids and 729 // can properly null things that are no longer referenced. 730 reassessPidDns(pid.intValue(), false); 731 } 732 } 733 734 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 735 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 736 if (info.isFailover()) { 737 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 738 info.setFailover(false); 739 } 740 if (info.getReason() != null) { 741 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 742 } 743 if (info.getExtraInfo() != null) { 744 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 745 info.getExtraInfo()); 746 } 747 748 /* 749 * If this is a default network, check if other defaults are available 750 * or active 751 */ 752 NetworkStateTracker newNet = null; 753 if (mNetAttributes[prevNetType].isDefault()) { 754 if (DBG) Log.d(TAG, "disconnecting a default network"); 755 if (mActiveDefaultNetwork == prevNetType) { 756 mActiveDefaultNetwork = -1; 757 } 758 759 int newType = -1; 760 int newPriority = -1; 761 for (int checkType=0; checkType <= 762 ConnectivityManager.MAX_NETWORK_TYPE; checkType++) { 763 if (checkType == prevNetType) { 764 continue; 765 } 766 if (mNetAttributes[checkType].isDefault()) { 767 /* TODO - if we have multiple nets we could use 768 * we may want to put more thought into which we choose 769 */ 770 if (checkType == mNetworkPreference) { 771 newType = checkType; 772 break; 773 } 774 if (mRadioAttributes[mNetAttributes[checkType].mRadio]. 775 mPriority > newPriority) { 776 newType = checkType; 777 newPriority = mRadioAttributes[mNetAttributes[newType]. 778 mRadio].mPriority; 779 } 780 } 781 } 782 783 if (newType != -1) { 784 newNet = mNetTrackers[newType]; 785 /** 786 * See if the other network is available to fail over to. 787 * If is not available, we enable it anyway, so that it 788 * will be able to connect when it does become available, 789 * but we report a total loss of connectivity rather than 790 * report that we are attempting to fail over. 791 */ 792 if (newNet.isAvailable()) { 793 NetworkInfo switchTo = newNet.getNetworkInfo(); 794 switchTo.setFailover(true); 795 if (!switchTo.isConnectedOrConnecting()) { 796 newNet.reconnect(); 797 } 798 if (DBG) { 799 if (switchTo.isConnected()) { 800 Log.v(TAG, "Switching to already connected " + 801 switchTo.getTypeName()); 802 } else { 803 Log.v(TAG, "Attempting to switch to " + 804 switchTo.getTypeName()); 805 } 806 } 807 intent.putExtra(ConnectivityManager. 808 EXTRA_OTHER_NETWORK_INFO, switchTo); 809 } else { 810 newNet.reconnect(); 811 } 812 } else { 813 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, 814 true); 815 } 816 } 817 818 // do this before we broadcast the change 819 handleConnectivityChange(); 820 821 if (DBG) Log.v(TAG, "Sending DISCONNECT bcast for " + 822 info.getTypeName() + 823 (newNet == null || !newNet.isAvailable() ? "" : " other=" + 824 newNet.getNetworkInfo().getTypeName())); 825 826 sendStickyBroadcast(intent); 827 /* 828 * If the failover network is already connected, then immediately send 829 * out a followup broadcast indicating successful failover 830 */ 831 if (newNet != null && newNet.getNetworkInfo().isConnected()) 832 sendConnectedBroadcast(newNet.getNetworkInfo()); 833 } 834 835 private void sendConnectedBroadcast(NetworkInfo info) { 836 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 837 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 838 if (info.isFailover()) { 839 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 840 info.setFailover(false); 841 } 842 if (info.getReason() != null) { 843 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 844 } 845 if (info.getExtraInfo() != null) { 846 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 847 info.getExtraInfo()); 848 } 849 sendStickyBroadcast(intent); 850 } 851 852 /** 853 * Called when an attempt to fail over to another network has failed. 854 * @param info the {@link NetworkInfo} for the failed network 855 */ 856 private void handleConnectionFailure(NetworkInfo info) { 857 mNetTrackers[info.getType()].setTeardownRequested(false); 858 859 String reason = info.getReason(); 860 String extraInfo = info.getExtraInfo(); 861 862 if (DBG) { 863 String reasonText; 864 if (reason == null) { 865 reasonText = "."; 866 } else { 867 reasonText = " (" + reason + ")."; 868 } 869 Log.v(TAG, "Attempt to connect to " + info.getTypeName() + 870 " failed" + reasonText); 871 } 872 873 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 874 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 875 if (getActiveNetworkInfo() == null) { 876 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 877 } 878 if (reason != null) { 879 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); 880 } 881 if (extraInfo != null) { 882 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); 883 } 884 if (info.isFailover()) { 885 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 886 info.setFailover(false); 887 } 888 sendStickyBroadcast(intent); 889 } 890 891 private void sendStickyBroadcast(Intent intent) { 892 synchronized(this) { 893 if (mSystemReady) { 894 mContext.sendStickyBroadcast(intent); 895 } else { 896 if (mDeferredBroadcasts == null) { 897 mDeferredBroadcasts = new ArrayList<Intent>(); 898 } 899 mDeferredBroadcasts.add(intent); 900 } 901 } 902 } 903 904 void systemReady() { 905 synchronized(this) { 906 mSystemReady = true; 907 if (mDeferredBroadcasts != null) { 908 int count = mDeferredBroadcasts.size(); 909 for (int i = 0; i < count; i++) { 910 mContext.sendStickyBroadcast(mDeferredBroadcasts.get(i)); 911 } 912 mDeferredBroadcasts = null; 913 } 914 } 915 } 916 917 private void handleConnect(NetworkInfo info) { 918 if (DBG) Log.d(TAG, "Handle CONNECT for " + info.getTypeName()); 919 920 int type = info.getType(); 921 922 // snapshot isFailover, because sendConnectedBroadcast() resets it 923 boolean isFailover = info.isFailover(); 924 NetworkStateTracker thisNet = mNetTrackers[type]; 925 926 // if this is a default net and other default is running 927 // kill the one not preferred 928 if (mNetAttributes[type].isDefault()) { 929 if (DBG) Log.d(TAG, "connecting to a default network"); 930 if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { 931 if ((type != mNetworkPreference && 932 mNetAttributes[mActiveDefaultNetwork].mPriority > 933 mNetAttributes[type].mPriority) || 934 mNetworkPreference == mActiveDefaultNetwork) { 935 // don't accept this one 936 if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION " + 937 "to torn down network " + info.getTypeName()); 938 teardown(thisNet); 939 return; 940 } else { 941 // tear down the other 942 NetworkStateTracker otherNet = 943 mNetTrackers[mActiveDefaultNetwork]; 944 if (DBG) Log.v(TAG, "Policy requires " + 945 otherNet.getNetworkInfo().getTypeName() + 946 " teardown"); 947 if (!teardown(otherNet)) { 948 Log.e(TAG, "Network declined teardown request"); 949 return; 950 } 951 if (isFailover) { 952 otherNet.releaseWakeLock(); 953 } 954 } 955 } 956 mActiveDefaultNetwork = type; 957 } 958 thisNet.setTeardownRequested(false); 959 if (DBG) Log.d(TAG, "Sending CONNECT bcast for " + info.getTypeName()); 960 thisNet.updateNetworkSettings(); 961 handleConnectivityChange(); 962 sendConnectedBroadcast(info); 963 } 964 965 private void handleScanResultsAvailable(NetworkInfo info) { 966 int networkType = info.getType(); 967 if (networkType != ConnectivityManager.TYPE_WIFI) { 968 if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " + 969 info.getTypeName() + " network. Don't know how to handle."); 970 } 971 972 mNetTrackers[networkType].interpretScanResultsAvailable(); 973 } 974 975 private void handleNotificationChange(boolean visible, int id, 976 Notification notification) { 977 NotificationManager notificationManager = (NotificationManager) mContext 978 .getSystemService(Context.NOTIFICATION_SERVICE); 979 980 if (visible) { 981 notificationManager.notify(id, notification); 982 } else { 983 notificationManager.cancel(id); 984 } 985 } 986 987 /** 988 * After any kind of change in the connectivity state of any network, 989 * make sure that anything that depends on the connectivity state of 990 * more than one network is set up correctly. We're mainly concerned 991 * with making sure that the list of DNS servers is set up according 992 * to which networks are connected, and ensuring that the right routing 993 * table entries exist. 994 */ 995 private void handleConnectivityChange() { 996 if (DBG) Log.d(TAG, "handleConnectivityChange"); 997 /* 998 * If a non-default network is enabled, add the host routes that 999 * will allow it's DNS servers to be accessed. Only 1000 * If both mobile and wifi are enabled, add the host routes that 1001 * will allow MMS traffic to pass on the mobile network. But 1002 * remove the default route for the mobile network, so that there 1003 * will be only one default route, to ensure that all traffic 1004 * except MMS will travel via Wi-Fi. 1005 */ 1006 handleDnsConfigurationChange(); 1007 1008 for (int netType : mPriorityList) { 1009 if (mNetTrackers[netType].getNetworkInfo().isConnected()) { 1010 if (mNetAttributes[netType].isDefault()) { 1011 mNetTrackers[netType].addDefaultRoute(); 1012 } else { 1013 mNetTrackers[netType].addPrivateDnsRoutes(); 1014 } 1015 } else { 1016 if (mNetAttributes[netType].isDefault()) { 1017 mNetTrackers[netType].removeDefaultRoute(); 1018 } else { 1019 mNetTrackers[netType].removePrivateDnsRoutes(); 1020 } 1021 } 1022 } 1023 } 1024 1025 /** 1026 * Adjust the per-process dns entries (net.dns<x>.<pid>) based 1027 * on the highest priority active net which this process requested. 1028 * If there aren't any, clear it out 1029 */ 1030 private void reassessPidDns(int myPid, boolean doBump) 1031 { 1032 if (DBG) Log.d(TAG, "reassessPidDns for pid " + myPid); 1033 for(int i : mPriorityList) { 1034 if (mNetAttributes[i].isDefault()) { 1035 continue; 1036 } 1037 NetworkStateTracker nt = mNetTrackers[i]; 1038 if (nt.getNetworkInfo().isConnected() && 1039 !nt.isTeardownRequested()) { 1040 List pids = mNetRequestersPids[i]; 1041 for (int j=0; j<pids.size(); j++) { 1042 Integer pid = (Integer)pids.get(j); 1043 if (pid.intValue() == myPid) { 1044 String[] dnsList = nt.getNameServers(); 1045 writePidDns(dnsList, myPid); 1046 if (doBump) { 1047 bumpDns(); 1048 } 1049 return; 1050 } 1051 } 1052 } 1053 } 1054 // nothing found - delete 1055 for (int i = 1; ; i++) { 1056 String prop = "net.dns" + i + "." + myPid; 1057 if (SystemProperties.get(prop).length() == 0) { 1058 if (doBump) { 1059 bumpDns(); 1060 } 1061 return; 1062 } 1063 SystemProperties.set(prop, ""); 1064 } 1065 } 1066 1067 private void writePidDns(String[] dnsList, int pid) { 1068 int j = 1; 1069 for (String dns : dnsList) { 1070 if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { 1071 SystemProperties.set("net.dns" + j++ + "." + pid, dns); 1072 } 1073 } 1074 } 1075 1076 private void bumpDns() { 1077 /* 1078 * Bump the property that tells the name resolver library to reread 1079 * the DNS server list from the properties. 1080 */ 1081 String propVal = SystemProperties.get("net.dnschange"); 1082 int n = 0; 1083 if (propVal.length() != 0) { 1084 try { 1085 n = Integer.parseInt(propVal); 1086 } catch (NumberFormatException e) {} 1087 } 1088 SystemProperties.set("net.dnschange", "" + (n+1)); 1089 } 1090 1091 private void handleDnsConfigurationChange() { 1092 if (DBG) Log.d(TAG, "handleDnsConfig Change"); 1093 // add default net's dns entries 1094 for (int x = mPriorityList.length-1; x>= 0; x--) { 1095 int netType = mPriorityList[x]; 1096 NetworkStateTracker nt = mNetTrackers[netType]; 1097 if (DBG) Log.d(TAG, " checking " + nt); 1098 if (nt != null && nt.getNetworkInfo().isConnected() && 1099 !nt.isTeardownRequested()) { 1100 if (DBG) Log.d(TAG, " connected"); 1101 String[] dnsList = nt.getNameServers(); 1102 if (mNetAttributes[netType].isDefault()) { 1103 int j = 1; 1104 for (String dns : dnsList) { 1105 if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { 1106 SystemProperties.set("net.dns" + j++, dns); 1107 } 1108 } 1109 for (int k=j ; k<mNumDnsEntries; k++) { 1110 SystemProperties.set("net.dns" + j, ""); 1111 } 1112 mNumDnsEntries = j; 1113 } else { 1114 // set per-pid dns for attached secondary nets 1115 List pids = mNetRequestersPids[netType]; 1116 for (int y=0; y< pids.size(); y++) { 1117 Integer pid = (Integer)pids.get(y); 1118 writePidDns(dnsList, pid.intValue()); 1119 } 1120 } 1121 } 1122 } 1123 1124 bumpDns(); 1125 } 1126 1127 private int getRestoreDefaultNetworkDelay() { 1128 String restoreDefaultNetworkDelayStr = SystemProperties.get( 1129 NETWORK_RESTORE_DELAY_PROP_NAME); 1130 if(restoreDefaultNetworkDelayStr != null && 1131 restoreDefaultNetworkDelayStr.length() != 0) { 1132 try { 1133 return Integer.valueOf(restoreDefaultNetworkDelayStr); 1134 } catch (NumberFormatException e) { 1135 } 1136 } 1137 return RESTORE_DEFAULT_NETWORK_DELAY; 1138 } 1139 1140 @Override 1141 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1142 if (mContext.checkCallingOrSelfPermission( 1143 android.Manifest.permission.DUMP) 1144 != PackageManager.PERMISSION_GRANTED) { 1145 pw.println("Permission Denial: can't dump ConnectivityService " + 1146 "from from pid=" + Binder.getCallingPid() + ", uid=" + 1147 Binder.getCallingUid()); 1148 return; 1149 } 1150 pw.println(); 1151 for (NetworkStateTracker nst : mNetTrackers) { 1152 if (nst.getNetworkInfo().isConnected()) { 1153 pw.println("Active network: " + nst.getNetworkInfo(). 1154 getTypeName()); 1155 } 1156 pw.println(nst.getNetworkInfo()); 1157 pw.println(nst); 1158 pw.println(); 1159 } 1160 } 1161 1162 // must be stateless - things change under us. 1163 private class MyHandler extends Handler { 1164 @Override 1165 public void handleMessage(Message msg) { 1166 NetworkInfo info; 1167 switch (msg.what) { 1168 case NetworkStateTracker.EVENT_STATE_CHANGED: 1169 info = (NetworkInfo) msg.obj; 1170 if (DBG) Log.d(TAG, "ConnectivityChange for " + 1171 info.getTypeName() + ": " + 1172 info.getState() + "/" + info.getDetailedState()); 1173 1174 // Connectivity state changed: 1175 // [31-13] Reserved for future use 1176 // [12-9] Network subtype (for mobile network, as defined 1177 // by TelephonyManager) 1178 // [8-3] Detailed state ordinal (as defined by 1179 // NetworkInfo.DetailedState) 1180 // [2-0] Network type (as defined by ConnectivityManager) 1181 int eventLogParam = (info.getType() & 0x7) | 1182 ((info.getDetailedState().ordinal() & 0x3f) << 3) | 1183 (info.getSubtype() << 9); 1184 EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED, 1185 eventLogParam); 1186 1187 if (info.getDetailedState() == 1188 NetworkInfo.DetailedState.FAILED) { 1189 handleConnectionFailure(info); 1190 } else if (info.getState() == 1191 NetworkInfo.State.DISCONNECTED) { 1192 handleDisconnect(info); 1193 } else if (info.getState() == NetworkInfo.State.SUSPENDED) { 1194 // TODO: need to think this over. 1195 // the logic here is, handle SUSPENDED the same as 1196 // DISCONNECTED. The only difference being we are 1197 // broadcasting an intent with NetworkInfo that's 1198 // suspended. This allows the applications an 1199 // opportunity to handle DISCONNECTED and SUSPENDED 1200 // differently, or not. 1201 handleDisconnect(info); 1202 } else if (info.getState() == NetworkInfo.State.CONNECTED) { 1203 handleConnect(info); 1204 } 1205 break; 1206 1207 case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE: 1208 info = (NetworkInfo) msg.obj; 1209 handleScanResultsAvailable(info); 1210 break; 1211 1212 case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED: 1213 handleNotificationChange(msg.arg1 == 1, msg.arg2, 1214 (Notification) msg.obj); 1215 1216 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: 1217 handleDnsConfigurationChange(); 1218 break; 1219 1220 case NetworkStateTracker.EVENT_ROAMING_CHANGED: 1221 // fill me in 1222 break; 1223 1224 case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: 1225 // fill me in 1226 break; 1227 case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK: 1228 for (NetworkStateTracker net : mNetTrackers) { 1229 NetworkInfo i = net.getNetworkInfo(); 1230 if (i.isConnected() && 1231 !mNetAttributes[i.getType()].isDefault()) { 1232 teardown(net); 1233 } 1234 } 1235 break; 1236 } 1237 } 1238 } 1239} 1240