1 /* 2 * Copyright (C) 2010 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 android.bluetooth; 18 19 import android.content.Context; 20 import android.net.ConnectivityManager; 21 import android.net.DhcpInfoInternal; 22 import android.net.LinkCapabilities; 23 import android.net.LinkProperties; 24 import android.net.NetworkInfo; 25 import android.net.NetworkInfo.DetailedState; 26 import android.net.NetworkStateTracker; 27 import android.net.NetworkUtils; 28 import android.os.Handler; 29 import android.os.Message; 30 import android.util.Log; 31 32 import java.util.concurrent.atomic.AtomicBoolean; 33 import java.util.concurrent.atomic.AtomicInteger; 34 35 /** 36 * This class tracks the data connection associated with Bluetooth 37 * reverse tethering. This is a singleton class and an instance will be 38 * created by ConnectivityService. BluetoothService will call into this 39 * when a reverse tethered connection needs to be activated. 40 * 41 * @hide 42 */ 43 public class BluetoothTetheringDataTracker implements NetworkStateTracker { 44 private static final String NETWORKTYPE = "BLUETOOTH_TETHER"; 45 private static final String TAG = "BluetoothTethering"; 46 47 private AtomicBoolean mTeardownRequested = new AtomicBoolean(false); 48 private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false); 49 private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0); 50 private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false); 51 52 private LinkProperties mLinkProperties; 53 private LinkCapabilities mLinkCapabilities; 54 private NetworkInfo mNetworkInfo; 55 56 private BluetoothPan mBluetoothPan; 57 private BluetoothDevice mDevice; 58 private static String mIface; 59 60 /* For sending events to connectivity service handler */ 61 private Handler mCsHandler; 62 private Context mContext; 63 public static BluetoothTetheringDataTracker sInstance; 64 BluetoothTetheringDataTracker()65 private BluetoothTetheringDataTracker() { 66 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORKTYPE, ""); 67 mLinkProperties = new LinkProperties(); 68 mLinkCapabilities = new LinkCapabilities(); 69 70 mNetworkInfo.setIsAvailable(false); 71 setTeardownRequested(false); 72 } 73 getInstance()74 public static synchronized BluetoothTetheringDataTracker getInstance() { 75 if (sInstance == null) sInstance = new BluetoothTetheringDataTracker(); 76 return sInstance; 77 } 78 Clone()79 public Object Clone() throws CloneNotSupportedException { 80 throw new CloneNotSupportedException(); 81 } 82 setTeardownRequested(boolean isRequested)83 public void setTeardownRequested(boolean isRequested) { 84 mTeardownRequested.set(isRequested); 85 } 86 isTeardownRequested()87 public boolean isTeardownRequested() { 88 return mTeardownRequested.get(); 89 } 90 91 /** 92 * Begin monitoring connectivity 93 */ startMonitoring(Context context, Handler target)94 public void startMonitoring(Context context, Handler target) { 95 mContext = context; 96 mCsHandler = target; 97 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 98 if (adapter != null) { 99 adapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.PAN); 100 } 101 } 102 103 private BluetoothProfile.ServiceListener mProfileServiceListener = 104 new BluetoothProfile.ServiceListener() { 105 public void onServiceConnected(int profile, BluetoothProfile proxy) { 106 mBluetoothPan = (BluetoothPan) proxy; 107 } 108 public void onServiceDisconnected(int profile) { 109 mBluetoothPan = null; 110 } 111 }; 112 113 /** 114 * Disable connectivity to a network 115 * TODO: do away with return value after making MobileDataStateTracker async 116 */ teardown()117 public boolean teardown() { 118 mTeardownRequested.set(true); 119 if (mBluetoothPan != null) { 120 for (BluetoothDevice device: mBluetoothPan.getConnectedDevices()) { 121 mBluetoothPan.disconnect(device); 122 } 123 } 124 return true; 125 } 126 127 /** 128 * Re-enable connectivity to a network after a {@link #teardown()}. 129 */ reconnect()130 public boolean reconnect() { 131 mTeardownRequested.set(false); 132 //Ignore 133 return true; 134 } 135 136 /** 137 * Turn the wireless radio off for a network. 138 * @param turnOn {@code true} to turn the radio on, {@code false} 139 */ setRadio(boolean turnOn)140 public boolean setRadio(boolean turnOn) { 141 return true; 142 } 143 144 /** 145 * @return true - If are we currently tethered with another device. 146 */ isAvailable()147 public synchronized boolean isAvailable() { 148 return mNetworkInfo.isAvailable(); 149 } 150 151 /** 152 * Tells the underlying networking system that the caller wants to 153 * begin using the named feature. The interpretation of {@code feature} 154 * is completely up to each networking implementation. 155 * @param feature the name of the feature to be used 156 * @param callingPid the process ID of the process that is issuing this request 157 * @param callingUid the user ID of the process that is issuing this request 158 * @return an integer value representing the outcome of the request. 159 * The interpretation of this value is specific to each networking 160 * implementation+feature combination, except that the value {@code -1} 161 * always indicates failure. 162 * TODO: needs to go away 163 */ startUsingNetworkFeature(String feature, int callingPid, int callingUid)164 public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) { 165 return -1; 166 } 167 168 /** 169 * Tells the underlying networking system that the caller is finished 170 * using the named feature. The interpretation of {@code feature} 171 * is completely up to each networking implementation. 172 * @param feature the name of the feature that is no longer needed. 173 * @param callingPid the process ID of the process that is issuing this request 174 * @param callingUid the user ID of the process that is issuing this request 175 * @return an integer value representing the outcome of the request. 176 * The interpretation of this value is specific to each networking 177 * implementation+feature combination, except that the value {@code -1} 178 * always indicates failure. 179 * TODO: needs to go away 180 */ stopUsingNetworkFeature(String feature, int callingPid, int callingUid)181 public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) { 182 return -1; 183 } 184 185 @Override setUserDataEnable(boolean enabled)186 public void setUserDataEnable(boolean enabled) { 187 Log.w(TAG, "ignoring setUserDataEnable(" + enabled + ")"); 188 } 189 190 @Override setPolicyDataEnable(boolean enabled)191 public void setPolicyDataEnable(boolean enabled) { 192 Log.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")"); 193 } 194 195 /** 196 * Check if private DNS route is set for the network 197 */ isPrivateDnsRouteSet()198 public boolean isPrivateDnsRouteSet() { 199 return mPrivateDnsRouteSet.get(); 200 } 201 202 /** 203 * Set a flag indicating private DNS route is set 204 */ privateDnsRouteSet(boolean enabled)205 public void privateDnsRouteSet(boolean enabled) { 206 mPrivateDnsRouteSet.set(enabled); 207 } 208 209 /** 210 * Fetch NetworkInfo for the network 211 */ getNetworkInfo()212 public synchronized NetworkInfo getNetworkInfo() { 213 return mNetworkInfo; 214 } 215 216 /** 217 * Fetch LinkProperties for the network 218 */ getLinkProperties()219 public synchronized LinkProperties getLinkProperties() { 220 return new LinkProperties(mLinkProperties); 221 } 222 223 /** 224 * A capability is an Integer/String pair, the capabilities 225 * are defined in the class LinkSocket#Key. 226 * 227 * @return a copy of this connections capabilities, may be empty but never null. 228 */ getLinkCapabilities()229 public LinkCapabilities getLinkCapabilities() { 230 return new LinkCapabilities(mLinkCapabilities); 231 } 232 233 /** 234 * Fetch default gateway address for the network 235 */ getDefaultGatewayAddr()236 public int getDefaultGatewayAddr() { 237 return mDefaultGatewayAddr.get(); 238 } 239 240 /** 241 * Check if default route is set 242 */ isDefaultRouteSet()243 public boolean isDefaultRouteSet() { 244 return mDefaultRouteSet.get(); 245 } 246 247 /** 248 * Set a flag indicating default route is set for the network 249 */ defaultRouteSet(boolean enabled)250 public void defaultRouteSet(boolean enabled) { 251 mDefaultRouteSet.set(enabled); 252 } 253 254 /** 255 * Return the system properties name associated with the tcp buffer sizes 256 * for this network. 257 */ getTcpBufferSizesPropName()258 public String getTcpBufferSizesPropName() { 259 return "net.tcp.buffersize.wifi"; 260 } 261 262 startReverseTether(String iface, BluetoothDevice device)263 public synchronized void startReverseTether(String iface, BluetoothDevice device) { 264 mIface = iface; 265 mDevice = device; 266 Thread dhcpThread = new Thread(new Runnable() { 267 public void run() { 268 //TODO(): Add callbacks for failure and success case. 269 //Currently this thread runs independently. 270 DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal(); 271 if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) { 272 Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError()); 273 return; 274 } 275 mLinkProperties = dhcpInfoInternal.makeLinkProperties(); 276 mLinkProperties.setInterfaceName(mIface); 277 278 mNetworkInfo.setIsAvailable(true); 279 mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null); 280 281 Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo); 282 msg.sendToTarget(); 283 284 msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); 285 msg.sendToTarget(); 286 } 287 }); 288 dhcpThread.start(); 289 } 290 stopReverseTether(String iface)291 public synchronized void stopReverseTether(String iface) { 292 NetworkUtils.stopDhcp(iface); 293 294 mLinkProperties.clear(); 295 mNetworkInfo.setIsAvailable(false); 296 mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null); 297 298 Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo); 299 msg.sendToTarget(); 300 301 msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); 302 msg.sendToTarget(); 303 } 304 setDependencyMet(boolean met)305 public void setDependencyMet(boolean met) { 306 // not supported on this network 307 } 308 } 309