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