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