ConnectivityService.java revision 4e8dfefb06227a911eb5abfcb2591d8eae5db42b
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.Slog; 43 44import com.android.internal.telephony.Phone; 45 46import com.android.server.connectivity.Tethering; 47 48import java.io.FileDescriptor; 49import java.io.PrintWriter; 50import java.util.ArrayList; 51import java.util.GregorianCalendar; 52import java.util.List; 53 54/** 55 * @hide 56 */ 57public class ConnectivityService extends IConnectivityManager.Stub { 58 59 private static final boolean DBG = true; 60 private static final String TAG = "ConnectivityService"; 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 private Tethering mTethering; 70 private boolean mTetheringConfigValid = false; 71 72 /** 73 * Sometimes we want to refer to the individual network state 74 * trackers separately, and sometimes we just want to treat them 75 * abstractly. 76 */ 77 private NetworkStateTracker mNetTrackers[]; 78 79 /** 80 * A per Net list of the PID's that requested access to the net 81 * used both as a refcount and for per-PID DNS selection 82 */ 83 private List mNetRequestersPids[]; 84 85 // priority order of the nettrackers 86 // (excluding dynamically set mNetworkPreference) 87 // TODO - move mNetworkTypePreference into this 88 private int[] mPriorityList; 89 90 private Context mContext; 91 private int mNetworkPreference; 92 private int mActiveDefaultNetwork = -1; 93 // 0 is full bad, 100 is full good 94 private int mDefaultInetCondition = 0; 95 private int mDefaultInetConditionPublished = 0; 96 private boolean mInetConditionChangeInFlight = false; 97 private int mDefaultConnectionSequence = 0; 98 99 private int mNumDnsEntries; 100 101 private boolean mTestMode; 102 private static ConnectivityService sServiceInstance; 103 104 private Handler mHandler; 105 106 // list of DeathRecipients used to make sure features are turned off when 107 // a process dies 108 private List mFeatureUsers; 109 110 private boolean mSystemReady; 111 private Intent mInitialBroadcast; 112 113 // used in DBG mode to track inet condition reports 114 private static final int INET_CONDITION_LOG_MAX_SIZE = 15; 115 private ArrayList mInetLog; 116 117 private static class NetworkAttributes { 118 /** 119 * Class for holding settings read from resources. 120 */ 121 public String mName; 122 public int mType; 123 public int mRadio; 124 public int mPriority; 125 public NetworkInfo.State mLastState; 126 public NetworkAttributes(String init) { 127 String fragments[] = init.split(","); 128 mName = fragments[0].toLowerCase(); 129 mType = Integer.parseInt(fragments[1]); 130 mRadio = Integer.parseInt(fragments[2]); 131 mPriority = Integer.parseInt(fragments[3]); 132 mLastState = NetworkInfo.State.UNKNOWN; 133 } 134 public boolean isDefault() { 135 return (mType == mRadio); 136 } 137 } 138 NetworkAttributes[] mNetAttributes; 139 int mNetworksDefined; 140 141 private static class RadioAttributes { 142 public int mSimultaneity; 143 public int mType; 144 public RadioAttributes(String init) { 145 String fragments[] = init.split(","); 146 mType = Integer.parseInt(fragments[0]); 147 mSimultaneity = Integer.parseInt(fragments[1]); 148 } 149 } 150 RadioAttributes[] mRadioAttributes; 151 152 private static class ConnectivityThread extends Thread { 153 private Context mContext; 154 155 private ConnectivityThread(Context context) { 156 super("ConnectivityThread"); 157 mContext = context; 158 } 159 160 @Override 161 public void run() { 162 Looper.prepare(); 163 synchronized (this) { 164 sServiceInstance = new ConnectivityService(mContext); 165 notifyAll(); 166 } 167 Looper.loop(); 168 } 169 170 public static ConnectivityService getServiceInstance(Context context) { 171 ConnectivityThread thread = new ConnectivityThread(context); 172 thread.start(); 173 174 synchronized (thread) { 175 while (sServiceInstance == null) { 176 try { 177 // Wait until sServiceInstance has been initialized. 178 thread.wait(); 179 } catch (InterruptedException ignore) { 180 Slog.e(TAG, 181 "Unexpected InterruptedException while waiting"+ 182 " for ConnectivityService thread"); 183 } 184 } 185 } 186 187 return sServiceInstance; 188 } 189 } 190 191 public static ConnectivityService getInstance(Context context) { 192 return ConnectivityThread.getServiceInstance(context); 193 } 194 195 private ConnectivityService(Context context) { 196 if (DBG) Slog.v(TAG, "ConnectivityService starting up"); 197 198 // setup our unique device name 199 String id = Settings.Secure.getString(context.getContentResolver(), 200 Settings.Secure.ANDROID_ID); 201 if (id != null && id.length() > 0) { 202 String name = new String("android_").concat(id); 203 SystemProperties.set("net.hostname", name); 204 } 205 206 mContext = context; 207 mNetTrackers = new NetworkStateTracker[ 208 ConnectivityManager.MAX_NETWORK_TYPE+1]; 209 mHandler = new MyHandler(); 210 211 mNetworkPreference = getPersistedNetworkPreference(); 212 213 mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1]; 214 mNetAttributes = new NetworkAttributes[ConnectivityManager.MAX_NETWORK_TYPE+1]; 215 216 // Load device network attributes from resources 217 String[] raStrings = context.getResources().getStringArray( 218 com.android.internal.R.array.radioAttributes); 219 for (String raString : raStrings) { 220 RadioAttributes r = new RadioAttributes(raString); 221 if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) { 222 Slog.e(TAG, "Error in radioAttributes - ignoring attempt to define type " + r.mType); 223 continue; 224 } 225 if (mRadioAttributes[r.mType] != null) { 226 Slog.e(TAG, "Error in radioAttributes - ignoring attempt to redefine type " + 227 r.mType); 228 continue; 229 } 230 mRadioAttributes[r.mType] = r; 231 } 232 233 String[] naStrings = context.getResources().getStringArray( 234 com.android.internal.R.array.networkAttributes); 235 for (String naString : naStrings) { 236 try { 237 NetworkAttributes n = new NetworkAttributes(naString); 238 if (n.mType > ConnectivityManager.MAX_NETWORK_TYPE) { 239 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to define type " + 240 n.mType); 241 continue; 242 } 243 if (mNetAttributes[n.mType] != null) { 244 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to redefine type " + 245 n.mType); 246 continue; 247 } 248 if (mRadioAttributes[n.mRadio] == null) { 249 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to use undefined " + 250 "radio " + n.mRadio + " in network type " + n.mType); 251 continue; 252 } 253 mNetAttributes[n.mType] = n; 254 mNetworksDefined++; 255 } catch(Exception e) { 256 // ignore it - leave the entry null 257 } 258 } 259 260 // high priority first 261 mPriorityList = new int[mNetworksDefined]; 262 { 263 int insertionPoint = mNetworksDefined-1; 264 int currentLowest = 0; 265 int nextLowest = 0; 266 while (insertionPoint > -1) { 267 for (NetworkAttributes na : mNetAttributes) { 268 if (na == null) continue; 269 if (na.mPriority < currentLowest) continue; 270 if (na.mPriority > currentLowest) { 271 if (na.mPriority < nextLowest || nextLowest == 0) { 272 nextLowest = na.mPriority; 273 } 274 continue; 275 } 276 mPriorityList[insertionPoint--] = na.mType; 277 } 278 currentLowest = nextLowest; 279 nextLowest = 0; 280 } 281 } 282 283 mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; 284 for (int i : mPriorityList) { 285 mNetRequestersPids[i] = new ArrayList(); 286 } 287 288 mFeatureUsers = new ArrayList(); 289 290 mNumDnsEntries = 0; 291 292 mTestMode = SystemProperties.get("cm.test.mode").equals("true") 293 && SystemProperties.get("ro.build.type").equals("eng"); 294 /* 295 * Create the network state trackers for Wi-Fi and mobile 296 * data. Maybe this could be done with a factory class, 297 * but it's not clear that it's worth it, given that 298 * the number of different network types is not going 299 * to change very often. 300 */ 301 boolean noMobileData = !getMobileDataEnabled(); 302 for (int netType : mPriorityList) { 303 switch (mNetAttributes[netType].mRadio) { 304 case ConnectivityManager.TYPE_WIFI: 305 if (DBG) Slog.v(TAG, "Starting Wifi Service."); 306 WifiStateTracker wst = new WifiStateTracker(context, mHandler); 307 WifiService wifiService = new WifiService(context, wst); 308 ServiceManager.addService(Context.WIFI_SERVICE, wifiService); 309 wifiService.startWifi(); 310 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst; 311 wst.startMonitoring(); 312 313 break; 314 case ConnectivityManager.TYPE_MOBILE: 315 mNetTrackers[netType] = new MobileDataStateTracker(context, mHandler, 316 netType, mNetAttributes[netType].mName); 317 mNetTrackers[netType].startMonitoring(); 318 if (noMobileData) { 319 if (DBG) Slog.d(TAG, "tearing down Mobile networks due to setting"); 320 mNetTrackers[netType].teardown(); 321 } 322 break; 323 default: 324 Slog.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " + 325 mNetAttributes[netType].mRadio); 326 continue; 327 } 328 } 329 330 mTethering = new Tethering(mContext, mHandler.getLooper()); 331 mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) || 332 !mTethering.isDunRequired()) && 333 (mTethering.getTetherableUsbRegexs().length != 0 || 334 mTethering.getTetherableWifiRegexs().length != 0) && 335 mTethering.getUpstreamIfaceRegexs().length != 0); 336 337 if (DBG) { 338 mInetLog = new ArrayList(); 339 } 340 } 341 342 343 /** 344 * Sets the preferred network. 345 * @param preference the new preference 346 */ 347 public synchronized void setNetworkPreference(int preference) { 348 enforceChangePermission(); 349 if (ConnectivityManager.isNetworkTypeValid(preference) && 350 mNetAttributes[preference] != null && 351 mNetAttributes[preference].isDefault()) { 352 if (mNetworkPreference != preference) { 353 persistNetworkPreference(preference); 354 mNetworkPreference = preference; 355 enforcePreference(); 356 } 357 } 358 } 359 360 public int getNetworkPreference() { 361 enforceAccessPermission(); 362 return mNetworkPreference; 363 } 364 365 private void persistNetworkPreference(int networkPreference) { 366 final ContentResolver cr = mContext.getContentResolver(); 367 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, 368 networkPreference); 369 } 370 371 private int getPersistedNetworkPreference() { 372 final ContentResolver cr = mContext.getContentResolver(); 373 374 final int networkPrefSetting = Settings.Secure 375 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1); 376 if (networkPrefSetting != -1) { 377 return networkPrefSetting; 378 } 379 380 return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE; 381 } 382 383 /** 384 * Make the state of network connectivity conform to the preference settings 385 * In this method, we only tear down a non-preferred network. Establishing 386 * a connection to the preferred network is taken care of when we handle 387 * the disconnect event from the non-preferred network 388 * (see {@link #handleDisconnect(NetworkInfo)}). 389 */ 390 private void enforcePreference() { 391 if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected()) 392 return; 393 394 if (!mNetTrackers[mNetworkPreference].isAvailable()) 395 return; 396 397 for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) { 398 if (t != mNetworkPreference && mNetTrackers[t] != null && 399 mNetTrackers[t].getNetworkInfo().isConnected()) { 400 if (DBG) { 401 Slog.d(TAG, "tearing down " + 402 mNetTrackers[t].getNetworkInfo() + 403 " in enforcePreference"); 404 } 405 teardown(mNetTrackers[t]); 406 } 407 } 408 } 409 410 private boolean teardown(NetworkStateTracker netTracker) { 411 if (netTracker.teardown()) { 412 netTracker.setTeardownRequested(true); 413 return true; 414 } else { 415 return false; 416 } 417 } 418 419 /** 420 * Return NetworkInfo for the active (i.e., connected) network interface. 421 * It is assumed that at most one network is active at a time. If more 422 * than one is active, it is indeterminate which will be returned. 423 * @return the info for the active network, or {@code null} if none is 424 * active 425 */ 426 public NetworkInfo getActiveNetworkInfo() { 427 enforceAccessPermission(); 428 for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { 429 if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) { 430 continue; 431 } 432 NetworkStateTracker t = mNetTrackers[type]; 433 NetworkInfo info = t.getNetworkInfo(); 434 if (info.isConnected()) { 435 if (DBG && type != mActiveDefaultNetwork) Slog.e(TAG, 436 "connected default network is not " + 437 "mActiveDefaultNetwork!"); 438 return info; 439 } 440 } 441 return null; 442 } 443 444 public NetworkInfo getNetworkInfo(int networkType) { 445 enforceAccessPermission(); 446 if (ConnectivityManager.isNetworkTypeValid(networkType)) { 447 NetworkStateTracker t = mNetTrackers[networkType]; 448 if (t != null) 449 return t.getNetworkInfo(); 450 } 451 return null; 452 } 453 454 public NetworkInfo[] getAllNetworkInfo() { 455 enforceAccessPermission(); 456 NetworkInfo[] result = new NetworkInfo[mNetworksDefined]; 457 int i = 0; 458 for (NetworkStateTracker t : mNetTrackers) { 459 if(t != null) result[i++] = t.getNetworkInfo(); 460 } 461 return result; 462 } 463 464 public boolean setRadios(boolean turnOn) { 465 boolean result = true; 466 enforceChangePermission(); 467 for (NetworkStateTracker t : mNetTrackers) { 468 if (t != null) result = t.setRadio(turnOn) && result; 469 } 470 return result; 471 } 472 473 public boolean setRadio(int netType, boolean turnOn) { 474 enforceChangePermission(); 475 if (!ConnectivityManager.isNetworkTypeValid(netType)) { 476 return false; 477 } 478 NetworkStateTracker tracker = mNetTrackers[netType]; 479 return tracker != null && tracker.setRadio(turnOn); 480 } 481 482 /** 483 * Used to notice when the calling process dies so we can self-expire 484 * 485 * Also used to know if the process has cleaned up after itself when 486 * our auto-expire timer goes off. The timer has a link to an object. 487 * 488 */ 489 private class FeatureUser implements IBinder.DeathRecipient { 490 int mNetworkType; 491 String mFeature; 492 IBinder mBinder; 493 int mPid; 494 int mUid; 495 long mCreateTime; 496 497 FeatureUser(int type, String feature, IBinder binder) { 498 super(); 499 mNetworkType = type; 500 mFeature = feature; 501 mBinder = binder; 502 mPid = getCallingPid(); 503 mUid = getCallingUid(); 504 mCreateTime = System.currentTimeMillis(); 505 506 try { 507 mBinder.linkToDeath(this, 0); 508 } catch (RemoteException e) { 509 binderDied(); 510 } 511 } 512 513 void unlinkDeathRecipient() { 514 mBinder.unlinkToDeath(this, 0); 515 } 516 517 public void binderDied() { 518 Slog.d(TAG, "ConnectivityService FeatureUser binderDied(" + 519 mNetworkType + ", " + mFeature + ", " + mBinder + "), created " + 520 (System.currentTimeMillis() - mCreateTime) + " mSec ago"); 521 stopUsingNetworkFeature(this, false); 522 } 523 524 public void expire() { 525 Slog.d(TAG, "ConnectivityService FeatureUser expire(" + 526 mNetworkType + ", " + mFeature + ", " + mBinder +"), created " + 527 (System.currentTimeMillis() - mCreateTime) + " mSec ago"); 528 stopUsingNetworkFeature(this, false); 529 } 530 531 public String toString() { 532 return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " + 533 (System.currentTimeMillis() - mCreateTime) + " mSec ago"; 534 } 535 } 536 537 // javadoc from interface 538 public int startUsingNetworkFeature(int networkType, String feature, 539 IBinder binder) { 540 if (DBG) { 541 Slog.d(TAG, "startUsingNetworkFeature for net " + networkType + 542 ": " + feature); 543 } 544 enforceChangePermission(); 545 if (!ConnectivityManager.isNetworkTypeValid(networkType) || 546 mNetAttributes[networkType] == null) { 547 return Phone.APN_REQUEST_FAILED; 548 } 549 550 FeatureUser f = new FeatureUser(networkType, feature, binder); 551 552 // TODO - move this into the MobileDataStateTracker 553 int usedNetworkType = networkType; 554 if(networkType == ConnectivityManager.TYPE_MOBILE) { 555 if (!getMobileDataEnabled()) { 556 if (DBG) Slog.d(TAG, "requested special network with data disabled - rejected"); 557 return Phone.APN_TYPE_NOT_AVAILABLE; 558 } 559 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { 560 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS; 561 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { 562 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL; 563 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) { 564 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; 565 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { 566 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; 567 } 568 } 569 NetworkStateTracker network = mNetTrackers[usedNetworkType]; 570 if (network != null) { 571 if (usedNetworkType != networkType) { 572 Integer currentPid = new Integer(getCallingPid()); 573 574 NetworkStateTracker radio = mNetTrackers[networkType]; 575 NetworkInfo ni = network.getNetworkInfo(); 576 577 if (ni.isAvailable() == false) { 578 if (DBG) Slog.d(TAG, "special network not available"); 579 return Phone.APN_TYPE_NOT_AVAILABLE; 580 } 581 582 synchronized(this) { 583 mFeatureUsers.add(f); 584 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { 585 // this gets used for per-pid dns when connected 586 mNetRequestersPids[usedNetworkType].add(currentPid); 587 } 588 } 589 mHandler.sendMessageDelayed(mHandler.obtainMessage( 590 NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK, 591 f), getRestoreDefaultNetworkDelay()); 592 593 594 if ((ni.isConnectedOrConnecting() == true) && 595 !network.isTeardownRequested()) { 596 if (ni.isConnected() == true) { 597 // add the pid-specific dns 598 handleDnsConfigurationChange(networkType); 599 if (DBG) Slog.d(TAG, "special network already active"); 600 return Phone.APN_ALREADY_ACTIVE; 601 } 602 if (DBG) Slog.d(TAG, "special network already connecting"); 603 return Phone.APN_REQUEST_STARTED; 604 } 605 606 // check if the radio in play can make another contact 607 // assume if cannot for now 608 609 if (DBG) Slog.d(TAG, "reconnecting to special network"); 610 network.reconnect(); 611 return Phone.APN_REQUEST_STARTED; 612 } else { 613 synchronized(this) { 614 mFeatureUsers.add(f); 615 } 616 mHandler.sendMessageDelayed(mHandler.obtainMessage( 617 NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK, 618 f), getRestoreDefaultNetworkDelay()); 619 620 return network.startUsingNetworkFeature(feature, 621 getCallingPid(), getCallingUid()); 622 } 623 } 624 return Phone.APN_TYPE_NOT_AVAILABLE; 625 } 626 627 // javadoc from interface 628 public int stopUsingNetworkFeature(int networkType, String feature) { 629 enforceChangePermission(); 630 631 int pid = getCallingPid(); 632 int uid = getCallingUid(); 633 634 FeatureUser u = null; 635 boolean found = false; 636 637 synchronized(this) { 638 for (int i = 0; i < mFeatureUsers.size() ; i++) { 639 u = (FeatureUser)mFeatureUsers.get(i); 640 if (uid == u.mUid && pid == u.mPid && 641 networkType == u.mNetworkType && 642 TextUtils.equals(feature, u.mFeature)) { 643 found = true; 644 break; 645 } 646 } 647 } 648 if (found && u != null) { 649 // stop regardless of how many other time this proc had called start 650 return stopUsingNetworkFeature(u, true); 651 } else { 652 // none found! 653 if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature - not a live request"); 654 return 1; 655 } 656 } 657 658 private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) { 659 int networkType = u.mNetworkType; 660 String feature = u.mFeature; 661 int pid = u.mPid; 662 int uid = u.mUid; 663 664 NetworkStateTracker tracker = null; 665 boolean callTeardown = false; // used to carry our decision outside of sync block 666 667 if (DBG) { 668 Slog.d(TAG, "stopUsingNetworkFeature for net " + networkType + 669 ": " + feature); 670 } 671 672 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 673 return -1; 674 } 675 676 // need to link the mFeatureUsers list with the mNetRequestersPids state in this 677 // sync block 678 synchronized(this) { 679 // check if this process still has an outstanding start request 680 if (!mFeatureUsers.contains(u)) { 681 if (DBG) Slog.d(TAG, "ignoring - this process has no outstanding requests"); 682 return 1; 683 } 684 u.unlinkDeathRecipient(); 685 mFeatureUsers.remove(mFeatureUsers.indexOf(u)); 686 // If we care about duplicate requests, check for that here. 687 // 688 // This is done to support the extension of a request - the app 689 // can request we start the network feature again and renew the 690 // auto-shutoff delay. Normal "stop" calls from the app though 691 // do not pay attention to duplicate requests - in effect the 692 // API does not refcount and a single stop will counter multiple starts. 693 if (ignoreDups == false) { 694 for (int i = 0; i < mFeatureUsers.size() ; i++) { 695 FeatureUser x = (FeatureUser)mFeatureUsers.get(i); 696 if (x.mUid == u.mUid && x.mPid == u.mPid && 697 x.mNetworkType == u.mNetworkType && 698 TextUtils.equals(x.mFeature, u.mFeature)) { 699 if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature as dup is found"); 700 return 1; 701 } 702 } 703 } 704 705 // TODO - move to MobileDataStateTracker 706 int usedNetworkType = networkType; 707 if (networkType == ConnectivityManager.TYPE_MOBILE) { 708 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { 709 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS; 710 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { 711 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL; 712 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) { 713 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; 714 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { 715 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; 716 } 717 } 718 tracker = mNetTrackers[usedNetworkType]; 719 if (tracker == null) { 720 if (DBG) Slog.d(TAG, "ignoring - no known tracker for net type " + usedNetworkType); 721 return -1; 722 } 723 if (usedNetworkType != networkType) { 724 Integer currentPid = new Integer(pid); 725 mNetRequestersPids[usedNetworkType].remove(currentPid); 726 reassessPidDns(pid, true); 727 if (mNetRequestersPids[usedNetworkType].size() != 0) { 728 if (DBG) Slog.d(TAG, "not tearing down special network - " + 729 "others still using it"); 730 return 1; 731 } 732 callTeardown = true; 733 } 734 } 735 if (DBG) Slog.d(TAG, "Doing network teardown"); 736 if (callTeardown) { 737 tracker.teardown(); 738 return 1; 739 } else { 740 // do it the old fashioned way 741 return tracker.stopUsingNetworkFeature(feature, pid, uid); 742 } 743 } 744 745 /** 746 * Ensure that a network route exists to deliver traffic to the specified 747 * host via the specified network interface. 748 * @param networkType the type of the network over which traffic to the 749 * specified host is to be routed 750 * @param hostAddress the IP address of the host to which the route is 751 * desired 752 * @return {@code true} on success, {@code false} on failure 753 */ 754 public boolean requestRouteToHost(int networkType, int hostAddress) { 755 enforceChangePermission(); 756 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 757 return false; 758 } 759 NetworkStateTracker tracker = mNetTrackers[networkType]; 760 761 if (tracker == null || !tracker.getNetworkInfo().isConnected() || 762 tracker.isTeardownRequested()) { 763 if (DBG) { 764 Slog.d(TAG, "requestRouteToHost on down network (" + networkType + ") - dropped"); 765 } 766 return false; 767 } 768 return tracker.requestRouteToHost(hostAddress); 769 } 770 771 /** 772 * @see ConnectivityManager#getBackgroundDataSetting() 773 */ 774 public boolean getBackgroundDataSetting() { 775 return Settings.Secure.getInt(mContext.getContentResolver(), 776 Settings.Secure.BACKGROUND_DATA, 1) == 1; 777 } 778 779 /** 780 * @see ConnectivityManager#setBackgroundDataSetting(boolean) 781 */ 782 public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) { 783 mContext.enforceCallingOrSelfPermission( 784 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING, 785 "ConnectivityService"); 786 787 if (getBackgroundDataSetting() == allowBackgroundDataUsage) return; 788 789 Settings.Secure.putInt(mContext.getContentResolver(), 790 Settings.Secure.BACKGROUND_DATA, 791 allowBackgroundDataUsage ? 1 : 0); 792 793 Intent broadcast = new Intent( 794 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); 795 mContext.sendBroadcast(broadcast); 796 } 797 798 /** 799 * @see ConnectivityManager#getMobileDataEnabled() 800 */ 801 public boolean getMobileDataEnabled() { 802 enforceAccessPermission(); 803 boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(), 804 Settings.Secure.MOBILE_DATA, 1) == 1; 805 if (DBG) Slog.d(TAG, "getMobileDataEnabled returning " + retVal); 806 return retVal; 807 } 808 809 /** 810 * @see ConnectivityManager#setMobileDataEnabled(boolean) 811 */ 812 public synchronized void setMobileDataEnabled(boolean enabled) { 813 enforceChangePermission(); 814 if (DBG) Slog.d(TAG, "setMobileDataEnabled(" + enabled + ")"); 815 816 if (getMobileDataEnabled() == enabled) return; 817 818 Settings.Secure.putInt(mContext.getContentResolver(), 819 Settings.Secure.MOBILE_DATA, enabled ? 1 : 0); 820 821 if (enabled) { 822 if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) { 823 if (DBG) Slog.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]); 824 mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect(); 825 } 826 } else { 827 for (NetworkStateTracker nt : mNetTrackers) { 828 if (nt == null) continue; 829 int netType = nt.getNetworkInfo().getType(); 830 if (mNetAttributes[netType].mRadio == ConnectivityManager.TYPE_MOBILE) { 831 if (DBG) Slog.d(TAG, "tearing down " + nt); 832 nt.teardown(); 833 } 834 } 835 } 836 } 837 838 private int getNumConnectedNetworks() { 839 int numConnectedNets = 0; 840 841 for (NetworkStateTracker nt : mNetTrackers) { 842 if (nt != null && nt.getNetworkInfo().isConnected() && 843 !nt.isTeardownRequested()) { 844 ++numConnectedNets; 845 } 846 } 847 return numConnectedNets; 848 } 849 850 private void enforceAccessPermission() { 851 mContext.enforceCallingOrSelfPermission( 852 android.Manifest.permission.ACCESS_NETWORK_STATE, 853 "ConnectivityService"); 854 } 855 856 private void enforceChangePermission() { 857 mContext.enforceCallingOrSelfPermission( 858 android.Manifest.permission.CHANGE_NETWORK_STATE, 859 "ConnectivityService"); 860 } 861 862 // TODO Make this a special check when it goes public 863 private void enforceTetherChangePermission() { 864 mContext.enforceCallingOrSelfPermission( 865 android.Manifest.permission.CHANGE_NETWORK_STATE, 866 "ConnectivityService"); 867 } 868 869 private void enforceTetherAccessPermission() { 870 mContext.enforceCallingOrSelfPermission( 871 android.Manifest.permission.ACCESS_NETWORK_STATE, 872 "ConnectivityService"); 873 } 874 875 /** 876 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active 877 * network, we ignore it. If it is for the active network, we send out a 878 * broadcast. But first, we check whether it might be possible to connect 879 * to a different network. 880 * @param info the {@code NetworkInfo} for the network 881 */ 882 private void handleDisconnect(NetworkInfo info) { 883 884 int prevNetType = info.getType(); 885 886 mNetTrackers[prevNetType].setTeardownRequested(false); 887 /* 888 * If the disconnected network is not the active one, then don't report 889 * this as a loss of connectivity. What probably happened is that we're 890 * getting the disconnect for a network that we explicitly disabled 891 * in accordance with network preference policies. 892 */ 893 if (!mNetAttributes[prevNetType].isDefault()) { 894 List pids = mNetRequestersPids[prevNetType]; 895 for (int i = 0; i<pids.size(); i++) { 896 Integer pid = (Integer)pids.get(i); 897 // will remove them because the net's no longer connected 898 // need to do this now as only now do we know the pids and 899 // can properly null things that are no longer referenced. 900 reassessPidDns(pid.intValue(), false); 901 } 902 } 903 904 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 905 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 906 if (info.isFailover()) { 907 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 908 info.setFailover(false); 909 } 910 if (info.getReason() != null) { 911 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 912 } 913 if (info.getExtraInfo() != null) { 914 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 915 info.getExtraInfo()); 916 } 917 918 NetworkStateTracker newNet = null; 919 if (mNetAttributes[prevNetType].isDefault()) { 920 newNet = tryFailover(prevNetType); 921 if (newNet != null) { 922 NetworkInfo switchTo = newNet.getNetworkInfo(); 923 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 924 } else { 925 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 926 } 927 } 928 // do this before we broadcast the change 929 handleConnectivityChange(prevNetType); 930 931 sendStickyBroadcast(intent); 932 /* 933 * If the failover network is already connected, then immediately send 934 * out a followup broadcast indicating successful failover 935 */ 936 if (newNet != null && newNet.getNetworkInfo().isConnected()) { 937 sendConnectedBroadcast(newNet.getNetworkInfo()); 938 } 939 } 940 941 // returns null if no failover available 942 private NetworkStateTracker tryFailover(int prevNetType) { 943 /* 944 * If this is a default network, check if other defaults are available 945 * or active 946 */ 947 NetworkStateTracker newNet = null; 948 if (mNetAttributes[prevNetType].isDefault()) { 949 if (mActiveDefaultNetwork == prevNetType) { 950 mActiveDefaultNetwork = -1; 951 } 952 953 int newType = -1; 954 int newPriority = -1; 955 boolean noMobileData = !getMobileDataEnabled(); 956 for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) { 957 if (checkType == prevNetType) continue; 958 if (mNetAttributes[checkType] == null) continue; 959 if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_MOBILE && 960 noMobileData) { 961 if (DBG) { 962 Slog.d(TAG, "not failing over to mobile type " + checkType + 963 " because Mobile Data Disabled"); 964 } 965 continue; 966 } 967 if (mNetAttributes[checkType].isDefault()) { 968 /* TODO - if we have multiple nets we could use 969 * we may want to put more thought into which we choose 970 */ 971 if (checkType == mNetworkPreference) { 972 newType = checkType; 973 break; 974 } 975 if (mNetAttributes[checkType].mPriority > newPriority) { 976 newType = checkType; 977 newPriority = mNetAttributes[newType].mPriority; 978 } 979 } 980 } 981 982 if (newType != -1) { 983 newNet = mNetTrackers[newType]; 984 /** 985 * See if the other network is available to fail over to. 986 * If is not available, we enable it anyway, so that it 987 * will be able to connect when it does become available, 988 * but we report a total loss of connectivity rather than 989 * report that we are attempting to fail over. 990 */ 991 if (newNet.isAvailable()) { 992 NetworkInfo switchTo = newNet.getNetworkInfo(); 993 switchTo.setFailover(true); 994 if (!switchTo.isConnectedOrConnecting() || 995 newNet.isTeardownRequested()) { 996 newNet.reconnect(); 997 } 998 if (DBG) { 999 if (switchTo.isConnected()) { 1000 Slog.v(TAG, "Switching to already connected " + 1001 switchTo.getTypeName()); 1002 } else { 1003 Slog.v(TAG, "Attempting to switch to " + 1004 switchTo.getTypeName()); 1005 } 1006 } 1007 } else { 1008 newNet.reconnect(); 1009 newNet = null; // not officially avail.. try anyway, but 1010 // report no failover 1011 } 1012 } 1013 } 1014 1015 return newNet; 1016 } 1017 1018 private void sendConnectedBroadcast(NetworkInfo info) { 1019 sendGeneralBroadcast(info, ConnectivityManager.CONNECTIVITY_ACTION); 1020 } 1021 1022 private void sendInetConditionBroadcast(NetworkInfo info) { 1023 sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION); 1024 } 1025 1026 private void sendGeneralBroadcast(NetworkInfo info, String bcastType) { 1027 Intent intent = new Intent(bcastType); 1028 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 1029 if (info.isFailover()) { 1030 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 1031 info.setFailover(false); 1032 } 1033 if (info.getReason() != null) { 1034 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 1035 } 1036 if (info.getExtraInfo() != null) { 1037 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 1038 info.getExtraInfo()); 1039 } 1040 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); 1041 sendStickyBroadcast(intent); 1042 } 1043 1044 /** 1045 * Called when an attempt to fail over to another network has failed. 1046 * @param info the {@link NetworkInfo} for the failed network 1047 */ 1048 private void handleConnectionFailure(NetworkInfo info) { 1049 mNetTrackers[info.getType()].setTeardownRequested(false); 1050 1051 String reason = info.getReason(); 1052 String extraInfo = info.getExtraInfo(); 1053 1054 if (DBG) { 1055 String reasonText; 1056 if (reason == null) { 1057 reasonText = "."; 1058 } else { 1059 reasonText = " (" + reason + ")."; 1060 } 1061 Slog.v(TAG, "Attempt to connect to " + info.getTypeName() + 1062 " failed" + reasonText); 1063 } 1064 1065 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 1066 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 1067 if (getActiveNetworkInfo() == null) { 1068 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1069 } 1070 if (reason != null) { 1071 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); 1072 } 1073 if (extraInfo != null) { 1074 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); 1075 } 1076 if (info.isFailover()) { 1077 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 1078 info.setFailover(false); 1079 } 1080 1081 NetworkStateTracker newNet = null; 1082 if (mNetAttributes[info.getType()].isDefault()) { 1083 newNet = tryFailover(info.getType()); 1084 if (newNet != null) { 1085 NetworkInfo switchTo = newNet.getNetworkInfo(); 1086 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 1087 } else { 1088 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1089 } 1090 } 1091 1092 sendStickyBroadcast(intent); 1093 /* 1094 * If the failover network is already connected, then immediately send 1095 * out a followup broadcast indicating successful failover 1096 */ 1097 if (newNet != null && newNet.getNetworkInfo().isConnected()) { 1098 sendConnectedBroadcast(newNet.getNetworkInfo()); 1099 } 1100 } 1101 1102 private void sendStickyBroadcast(Intent intent) { 1103 synchronized(this) { 1104 if (!mSystemReady) { 1105 mInitialBroadcast = new Intent(intent); 1106 } 1107 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1108 mContext.sendStickyBroadcast(intent); 1109 } 1110 } 1111 1112 void systemReady() { 1113 synchronized(this) { 1114 mSystemReady = true; 1115 if (mInitialBroadcast != null) { 1116 mContext.sendStickyBroadcast(mInitialBroadcast); 1117 mInitialBroadcast = null; 1118 } 1119 } 1120 } 1121 1122 private void handleConnect(NetworkInfo info) { 1123 int type = info.getType(); 1124 1125 // snapshot isFailover, because sendConnectedBroadcast() resets it 1126 boolean isFailover = info.isFailover(); 1127 NetworkStateTracker thisNet = mNetTrackers[type]; 1128 1129 // if this is a default net and other default is running 1130 // kill the one not preferred 1131 if (mNetAttributes[type].isDefault()) { 1132 if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { 1133 if ((type != mNetworkPreference && 1134 mNetAttributes[mActiveDefaultNetwork].mPriority > 1135 mNetAttributes[type].mPriority) || 1136 mNetworkPreference == mActiveDefaultNetwork) { 1137 // don't accept this one 1138 if (DBG) Slog.v(TAG, "Not broadcasting CONNECT_ACTION " + 1139 "to torn down network " + info.getTypeName()); 1140 teardown(thisNet); 1141 return; 1142 } else { 1143 // tear down the other 1144 NetworkStateTracker otherNet = 1145 mNetTrackers[mActiveDefaultNetwork]; 1146 if (DBG) Slog.v(TAG, "Policy requires " + 1147 otherNet.getNetworkInfo().getTypeName() + 1148 " teardown"); 1149 if (!teardown(otherNet)) { 1150 Slog.e(TAG, "Network declined teardown request"); 1151 return; 1152 } 1153 if (isFailover) { 1154 otherNet.releaseWakeLock(); 1155 } 1156 } 1157 } 1158 mActiveDefaultNetwork = type; 1159 // this will cause us to come up initially as unconnected and switching 1160 // to connected after our normal pause unless somebody reports us as reall 1161 // disconnected 1162 mDefaultInetConditionPublished = 0; 1163 mDefaultConnectionSequence++; 1164 mInetConditionChangeInFlight = false; 1165 // Don't do this - if we never sign in stay, grey 1166 //reportNetworkCondition(mActiveDefaultNetwork, 100); 1167 } 1168 thisNet.setTeardownRequested(false); 1169 thisNet.updateNetworkSettings(); 1170 handleConnectivityChange(type); 1171 sendConnectedBroadcast(info); 1172 } 1173 1174 private void handleScanResultsAvailable(NetworkInfo info) { 1175 int networkType = info.getType(); 1176 if (networkType != ConnectivityManager.TYPE_WIFI) { 1177 if (DBG) Slog.v(TAG, "Got ScanResultsAvailable for " + 1178 info.getTypeName() + " network. Don't know how to handle."); 1179 } 1180 1181 mNetTrackers[networkType].interpretScanResultsAvailable(); 1182 } 1183 1184 private void handleNotificationChange(boolean visible, int id, 1185 Notification notification) { 1186 NotificationManager notificationManager = (NotificationManager) mContext 1187 .getSystemService(Context.NOTIFICATION_SERVICE); 1188 1189 if (visible) { 1190 notificationManager.notify(id, notification); 1191 } else { 1192 notificationManager.cancel(id); 1193 } 1194 } 1195 1196 /** 1197 * After a change in the connectivity state of any network, We're mainly 1198 * concerned with making sure that the list of DNS servers is setupup 1199 * according to which networks are connected, and ensuring that the 1200 * right routing table entries exist. 1201 */ 1202 private void handleConnectivityChange(int netType) { 1203 /* 1204 * If a non-default network is enabled, add the host routes that 1205 * will allow it's DNS servers to be accessed. 1206 */ 1207 handleDnsConfigurationChange(netType); 1208 1209 if (mNetTrackers[netType].getNetworkInfo().isConnected()) { 1210 if (mNetAttributes[netType].isDefault()) { 1211 mNetTrackers[netType].addDefaultRoute(); 1212 } else { 1213 mNetTrackers[netType].addPrivateDnsRoutes(); 1214 } 1215 } else { 1216 if (mNetAttributes[netType].isDefault()) { 1217 mNetTrackers[netType].removeDefaultRoute(); 1218 } else { 1219 mNetTrackers[netType].removePrivateDnsRoutes(); 1220 } 1221 } 1222 } 1223 1224 /** 1225 * Adjust the per-process dns entries (net.dns<x>.<pid>) based 1226 * on the highest priority active net which this process requested. 1227 * If there aren't any, clear it out 1228 */ 1229 private void reassessPidDns(int myPid, boolean doBump) 1230 { 1231 if (DBG) Slog.d(TAG, "reassessPidDns for pid " + myPid); 1232 for(int i : mPriorityList) { 1233 if (mNetAttributes[i].isDefault()) { 1234 continue; 1235 } 1236 NetworkStateTracker nt = mNetTrackers[i]; 1237 if (nt.getNetworkInfo().isConnected() && 1238 !nt.isTeardownRequested()) { 1239 List pids = mNetRequestersPids[i]; 1240 for (int j=0; j<pids.size(); j++) { 1241 Integer pid = (Integer)pids.get(j); 1242 if (pid.intValue() == myPid) { 1243 String[] dnsList = nt.getNameServers(); 1244 writePidDns(dnsList, myPid); 1245 if (doBump) { 1246 bumpDns(); 1247 } 1248 return; 1249 } 1250 } 1251 } 1252 } 1253 // nothing found - delete 1254 for (int i = 1; ; i++) { 1255 String prop = "net.dns" + i + "." + myPid; 1256 if (SystemProperties.get(prop).length() == 0) { 1257 if (doBump) { 1258 bumpDns(); 1259 } 1260 return; 1261 } 1262 SystemProperties.set(prop, ""); 1263 } 1264 } 1265 1266 private void writePidDns(String[] dnsList, int pid) { 1267 int j = 1; 1268 for (String dns : dnsList) { 1269 if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { 1270 SystemProperties.set("net.dns" + j++ + "." + pid, dns); 1271 } 1272 } 1273 } 1274 1275 private void bumpDns() { 1276 /* 1277 * Bump the property that tells the name resolver library to reread 1278 * the DNS server list from the properties. 1279 */ 1280 String propVal = SystemProperties.get("net.dnschange"); 1281 int n = 0; 1282 if (propVal.length() != 0) { 1283 try { 1284 n = Integer.parseInt(propVal); 1285 } catch (NumberFormatException e) {} 1286 } 1287 SystemProperties.set("net.dnschange", "" + (n+1)); 1288 } 1289 1290 private void handleDnsConfigurationChange(int netType) { 1291 // add default net's dns entries 1292 NetworkStateTracker nt = mNetTrackers[netType]; 1293 if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { 1294 String[] dnsList = nt.getNameServers(); 1295 if (mNetAttributes[netType].isDefault()) { 1296 int j = 1; 1297 for (String dns : dnsList) { 1298 if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { 1299 if (DBG) { 1300 Slog.d(TAG, "adding dns " + dns + " for " + 1301 nt.getNetworkInfo().getTypeName()); 1302 } 1303 SystemProperties.set("net.dns" + j++, dns); 1304 } 1305 } 1306 for (int k=j ; k<mNumDnsEntries; k++) { 1307 if (DBG) Slog.d(TAG, "erasing net.dns" + k); 1308 SystemProperties.set("net.dns" + k, ""); 1309 } 1310 mNumDnsEntries = j; 1311 } else { 1312 // set per-pid dns for attached secondary nets 1313 List pids = mNetRequestersPids[netType]; 1314 for (int y=0; y< pids.size(); y++) { 1315 Integer pid = (Integer)pids.get(y); 1316 writePidDns(dnsList, pid.intValue()); 1317 } 1318 } 1319 } 1320 bumpDns(); 1321 } 1322 1323 private int getRestoreDefaultNetworkDelay() { 1324 String restoreDefaultNetworkDelayStr = SystemProperties.get( 1325 NETWORK_RESTORE_DELAY_PROP_NAME); 1326 if(restoreDefaultNetworkDelayStr != null && 1327 restoreDefaultNetworkDelayStr.length() != 0) { 1328 try { 1329 return Integer.valueOf(restoreDefaultNetworkDelayStr); 1330 } catch (NumberFormatException e) { 1331 } 1332 } 1333 return RESTORE_DEFAULT_NETWORK_DELAY; 1334 } 1335 1336 @Override 1337 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1338 if (mContext.checkCallingOrSelfPermission( 1339 android.Manifest.permission.DUMP) 1340 != PackageManager.PERMISSION_GRANTED) { 1341 pw.println("Permission Denial: can't dump ConnectivityService " + 1342 "from from pid=" + Binder.getCallingPid() + ", uid=" + 1343 Binder.getCallingUid()); 1344 return; 1345 } 1346 pw.println(); 1347 for (NetworkStateTracker nst : mNetTrackers) { 1348 if (nst != null) { 1349 if (nst.getNetworkInfo().isConnected()) { 1350 pw.println("Active network: " + nst.getNetworkInfo(). 1351 getTypeName()); 1352 } 1353 pw.println(nst.getNetworkInfo()); 1354 pw.println(nst); 1355 pw.println(); 1356 } 1357 } 1358 1359 pw.println("Network Requester Pids:"); 1360 for (int net : mPriorityList) { 1361 String pidString = net + ": "; 1362 for (Object pid : mNetRequestersPids[net]) { 1363 pidString = pidString + pid.toString() + ", "; 1364 } 1365 pw.println(pidString); 1366 } 1367 pw.println(); 1368 1369 pw.println("FeatureUsers:"); 1370 for (Object requester : mFeatureUsers) { 1371 pw.println(requester.toString()); 1372 } 1373 pw.println(); 1374 1375 mTethering.dump(fd, pw, args); 1376 1377 if (mInetLog != null) { 1378 pw.println(); 1379 pw.println("Inet condition reports:"); 1380 for(int i = 0; i < mInetLog.size(); i++) { 1381 pw.println(mInetLog.get(i)); 1382 } 1383 } 1384 } 1385 1386 // must be stateless - things change under us. 1387 private class MyHandler extends Handler { 1388 @Override 1389 public void handleMessage(Message msg) { 1390 NetworkInfo info; 1391 switch (msg.what) { 1392 case NetworkStateTracker.EVENT_STATE_CHANGED: 1393 info = (NetworkInfo) msg.obj; 1394 int type = info.getType(); 1395 NetworkInfo.State state = info.getState(); 1396 // only do this optimization for wifi. It going into scan mode for location 1397 // services generates alot of noise. Meanwhile the mms apn won't send out 1398 // subsequent notifications when on default cellular because it never 1399 // disconnects.. so only do this to wifi notifications. Fixed better when the 1400 // APN notifications are standardized. 1401 if (mNetAttributes[type].mLastState == state && 1402 mNetAttributes[type].mRadio == ConnectivityManager.TYPE_WIFI) { 1403 if (DBG) { 1404 // TODO - remove this after we validate the dropping doesn't break 1405 // anything 1406 Slog.d(TAG, "Dropping ConnectivityChange for " + 1407 info.getTypeName() + ": " + 1408 state + "/" + info.getDetailedState()); 1409 } 1410 return; 1411 } 1412 mNetAttributes[type].mLastState = state; 1413 1414 if (DBG) Slog.d(TAG, "ConnectivityChange for " + 1415 info.getTypeName() + ": " + 1416 state + "/" + info.getDetailedState()); 1417 1418 // Connectivity state changed: 1419 // [31-13] Reserved for future use 1420 // [12-9] Network subtype (for mobile network, as defined 1421 // by TelephonyManager) 1422 // [8-3] Detailed state ordinal (as defined by 1423 // NetworkInfo.DetailedState) 1424 // [2-0] Network type (as defined by ConnectivityManager) 1425 int eventLogParam = (info.getType() & 0x7) | 1426 ((info.getDetailedState().ordinal() & 0x3f) << 3) | 1427 (info.getSubtype() << 9); 1428 EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED, 1429 eventLogParam); 1430 1431 if (info.getDetailedState() == 1432 NetworkInfo.DetailedState.FAILED) { 1433 handleConnectionFailure(info); 1434 } else if (state == NetworkInfo.State.DISCONNECTED) { 1435 handleDisconnect(info); 1436 } else if (state == NetworkInfo.State.SUSPENDED) { 1437 // TODO: need to think this over. 1438 // the logic here is, handle SUSPENDED the same as 1439 // DISCONNECTED. The only difference being we are 1440 // broadcasting an intent with NetworkInfo that's 1441 // suspended. This allows the applications an 1442 // opportunity to handle DISCONNECTED and SUSPENDED 1443 // differently, or not. 1444 handleDisconnect(info); 1445 } else if (state == NetworkInfo.State.CONNECTED) { 1446 handleConnect(info); 1447 } 1448 break; 1449 1450 case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE: 1451 info = (NetworkInfo) msg.obj; 1452 handleScanResultsAvailable(info); 1453 break; 1454 1455 case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED: 1456 handleNotificationChange(msg.arg1 == 1, msg.arg2, 1457 (Notification) msg.obj); 1458 break; 1459 1460 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: 1461 info = (NetworkInfo) msg.obj; 1462 type = info.getType(); 1463 handleDnsConfigurationChange(type); 1464 break; 1465 1466 case NetworkStateTracker.EVENT_ROAMING_CHANGED: 1467 // fill me in 1468 break; 1469 1470 case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: 1471 // fill me in 1472 break; 1473 case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK: 1474 FeatureUser u = (FeatureUser)msg.obj; 1475 u.expire(); 1476 break; 1477 case NetworkStateTracker.EVENT_INET_CONDITION_CHANGE: 1478 if (DBG) { 1479 Slog.d(TAG, "Inet connectivity change, net=" + 1480 msg.arg1 + ", condition=" + msg.arg2 + 1481 ",mActiveDefaultNetwork=" + mActiveDefaultNetwork); 1482 } 1483 if (mActiveDefaultNetwork == -1) { 1484 if (DBG) Slog.d(TAG, "no active default network - aborting"); 1485 break; 1486 } 1487 if (mActiveDefaultNetwork != msg.arg1) { 1488 if (DBG) Slog.d(TAG, "given net not default - aborting"); 1489 break; 1490 } 1491 mDefaultInetCondition = msg.arg2; 1492 int delay; 1493 if (mInetConditionChangeInFlight == false) { 1494 if (DBG) Slog.d(TAG, "starting a change hold"); 1495 // setup a new hold to debounce this 1496 if (mDefaultInetCondition > 50) { 1497 delay = Settings.Secure.getInt(mContext.getContentResolver(), 1498 Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500); 1499 } else { 1500 delay = Settings.Secure.getInt(mContext.getContentResolver(), 1501 Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000); 1502 } 1503 mInetConditionChangeInFlight = true; 1504 sendMessageDelayed(obtainMessage( 1505 NetworkStateTracker.EVENT_INET_CONDITION_HOLD_END, 1506 mActiveDefaultNetwork, mDefaultConnectionSequence), delay); 1507 } else { 1508 // we've set the new condition, when this hold ends that will get 1509 // picked up 1510 if (DBG) Slog.d(TAG, "currently in hold - not setting new end evt"); 1511 } 1512 break; 1513 case NetworkStateTracker.EVENT_INET_CONDITION_HOLD_END: 1514 if (DBG) { 1515 Slog.d(TAG, "Inet hold end, net=" + msg.arg1 + 1516 ", condition =" + mDefaultInetCondition + 1517 ", published condition =" + mDefaultInetConditionPublished); 1518 } 1519 mInetConditionChangeInFlight = false; 1520 1521 if (mActiveDefaultNetwork == -1) { 1522 if (DBG) Slog.d(TAG, "no active default network - aborting"); 1523 break; 1524 } 1525 if (mDefaultConnectionSequence != msg.arg2) { 1526 if (DBG) Slog.d(TAG, "event hold for obsolete network - aborting"); 1527 break; 1528 } 1529 if (mDefaultInetConditionPublished == mDefaultInetCondition) { 1530 if (DBG) Slog.d(TAG, "no change in condition - aborting"); 1531 break; 1532 } 1533 NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); 1534 if (networkInfo.isConnected() == false) { 1535 if (DBG) Slog.d(TAG, "default network not connected - aborting"); 1536 break; 1537 } 1538 mDefaultInetConditionPublished = mDefaultInetCondition; 1539 sendInetConditionBroadcast(networkInfo); 1540 break; 1541 } 1542 } 1543 } 1544 1545 // javadoc from interface 1546 public int tether(String iface) { 1547 enforceTetherChangePermission(); 1548 1549 if (isTetheringSupported()) { 1550 return mTethering.tether(iface); 1551 } else { 1552 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 1553 } 1554 } 1555 1556 // javadoc from interface 1557 public int untether(String iface) { 1558 enforceTetherChangePermission(); 1559 1560 if (isTetheringSupported()) { 1561 return mTethering.untether(iface); 1562 } else { 1563 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 1564 } 1565 } 1566 1567 // javadoc from interface 1568 public int getLastTetherError(String iface) { 1569 enforceTetherAccessPermission(); 1570 1571 if (isTetheringSupported()) { 1572 return mTethering.getLastTetherError(iface); 1573 } else { 1574 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 1575 } 1576 } 1577 1578 // TODO - proper iface API for selection by property, inspection, etc 1579 public String[] getTetherableUsbRegexs() { 1580 enforceTetherAccessPermission(); 1581 if (isTetheringSupported()) { 1582 return mTethering.getTetherableUsbRegexs(); 1583 } else { 1584 return new String[0]; 1585 } 1586 } 1587 1588 public String[] getTetherableWifiRegexs() { 1589 enforceTetherAccessPermission(); 1590 if (isTetheringSupported()) { 1591 return mTethering.getTetherableWifiRegexs(); 1592 } else { 1593 return new String[0]; 1594 } 1595 } 1596 1597 // TODO - move iface listing, queries, etc to new module 1598 // javadoc from interface 1599 public String[] getTetherableIfaces() { 1600 enforceTetherAccessPermission(); 1601 return mTethering.getTetherableIfaces(); 1602 } 1603 1604 public String[] getTetheredIfaces() { 1605 enforceTetherAccessPermission(); 1606 return mTethering.getTetheredIfaces(); 1607 } 1608 1609 public String[] getTetheringErroredIfaces() { 1610 enforceTetherAccessPermission(); 1611 return mTethering.getErroredIfaces(); 1612 } 1613 1614 // if ro.tether.denied = true we default to no tethering 1615 // gservices could set the secure setting to 1 though to enable it on a build where it 1616 // had previously been turned off. 1617 public boolean isTetheringSupported() { 1618 enforceTetherAccessPermission(); 1619 int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1); 1620 boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(), 1621 Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0); 1622 return tetherEnabledInSettings && mTetheringConfigValid; 1623 } 1624 1625 // 100 percent is full good, 0 is full bad. 1626 public void reportInetCondition(int networkType, int percentage) { 1627 if (DBG) Slog.d(TAG, "reportNetworkCondition(" + networkType + ", " + percentage + ")"); 1628 mContext.enforceCallingOrSelfPermission( 1629 android.Manifest.permission.STATUS_BAR, 1630 "ConnectivityService"); 1631 1632 if (DBG) { 1633 int pid = getCallingPid(); 1634 int uid = getCallingUid(); 1635 String s = pid + "(" + uid + ") reports inet is " + 1636 (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " + 1637 "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime(); 1638 mInetLog.add(s); 1639 while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) { 1640 mInetLog.remove(0); 1641 } 1642 } 1643 mHandler.sendMessage(mHandler.obtainMessage( 1644 NetworkStateTracker.EVENT_INET_CONDITION_CHANGE, networkType, percentage)); 1645 } 1646} 1647