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