blob: a9b717693356aa0ad8687ba9efea337052dda0b7 [file] [log] [blame]
Jaikumar Ganesh15c74392010-12-21 22:31:44 -08001/*
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
17package android.bluetooth;
18
Vinit Deshapnde1f12cb52013-08-21 13:09:01 -070019import android.net.BaseNetworkStateTracker;
fredc0f420372012-04-12 00:02:00 -070020import android.os.IBinder;
21import android.os.ServiceManager;
22import android.os.INetworkManagementService;
Jaikumar Ganesh15c74392010-12-21 22:31:44 -080023import android.content.Context;
24import android.net.ConnectivityManager;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -070025import android.net.DhcpResults;
Jaikumar Ganesh15c74392010-12-21 22:31:44 -080026import android.net.LinkCapabilities;
27import android.net.LinkProperties;
28import android.net.NetworkInfo;
29import android.net.NetworkInfo.DetailedState;
30import android.net.NetworkStateTracker;
31import android.net.NetworkUtils;
32import android.os.Handler;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -070033import android.os.Looper;
Jaikumar Ganesh15c74392010-12-21 22:31:44 -080034import android.os.Message;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -070035import android.os.Messenger;
36import android.text.TextUtils;
Jaikumar Ganesh15c74392010-12-21 22:31:44 -080037import android.util.Log;
fredc0f420372012-04-12 00:02:00 -070038import java.net.InterfaceAddress;
39import android.net.LinkAddress;
40import android.net.RouteInfo;
41import java.net.Inet4Address;
42import android.os.SystemProperties;
Jaikumar Ganesh15c74392010-12-21 22:31:44 -080043
Robert Greenwalt665e1ae2012-08-21 19:27:00 -070044import com.android.internal.util.AsyncChannel;
45
Jaikumar Ganesh15c74392010-12-21 22:31:44 -080046import java.util.concurrent.atomic.AtomicBoolean;
47import java.util.concurrent.atomic.AtomicInteger;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -070048import java.util.concurrent.atomic.AtomicReference;
Jaikumar Ganesh15c74392010-12-21 22:31:44 -080049
50/**
51 * This class tracks the data connection associated with Bluetooth
52 * reverse tethering. This is a singleton class and an instance will be
53 * created by ConnectivityService. BluetoothService will call into this
54 * when a reverse tethered connection needs to be activated.
55 *
56 * @hide
57 */
Vinit Deshapnde1f12cb52013-08-21 13:09:01 -070058public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker {
Jaikumar Ganesh15c74392010-12-21 22:31:44 -080059 private static final String NETWORKTYPE = "BLUETOOTH_TETHER";
60 private static final String TAG = "BluetoothTethering";
Matthew Xie563e4142012-10-09 22:10:37 -070061 private static final boolean DBG = true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -070062 private static final boolean VDBG = true;
Jaikumar Ganesh15c74392010-12-21 22:31:44 -080063
64 private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
65 private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
66 private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
67 private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
68
Robert Greenwalt665e1ae2012-08-21 19:27:00 -070069 private final Object mLinkPropertiesLock = new Object();
Robert Greenwalt665e1ae2012-08-21 19:27:00 -070070 private final Object mNetworkInfoLock = new Object();
Jaikumar Ganesh15c74392010-12-21 22:31:44 -080071
72 private BluetoothPan mBluetoothPan;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -070073 private static String mRevTetheredIface;
Jaikumar Ganesh15c74392010-12-21 22:31:44 -080074 /* For sending events to connectivity service handler */
75 private Handler mCsHandler;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -070076 private static BluetoothTetheringDataTracker sInstance;
77 private BtdtHandler mBtdtHandler;
78 private AtomicReference<AsyncChannel> mAsyncChannel = new AtomicReference<AsyncChannel>(null);
Jaikumar Ganesh15c74392010-12-21 22:31:44 -080079
80 private BluetoothTetheringDataTracker() {
81 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORKTYPE, "");
82 mLinkProperties = new LinkProperties();
83 mLinkCapabilities = new LinkCapabilities();
84
85 mNetworkInfo.setIsAvailable(false);
86 setTeardownRequested(false);
87 }
88
89 public static synchronized BluetoothTetheringDataTracker getInstance() {
90 if (sInstance == null) sInstance = new BluetoothTetheringDataTracker();
91 return sInstance;
92 }
93
94 public Object Clone() throws CloneNotSupportedException {
95 throw new CloneNotSupportedException();
96 }
97
98 public void setTeardownRequested(boolean isRequested) {
99 mTeardownRequested.set(isRequested);
100 }
101
102 public boolean isTeardownRequested() {
103 return mTeardownRequested.get();
104 }
105
106 /**
107 * Begin monitoring connectivity
108 */
109 public void startMonitoring(Context context, Handler target) {
Matthew Xie563e4142012-10-09 22:10:37 -0700110 if (DBG) Log.d(TAG, "startMonitoring: target: " + target);
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800111 mContext = context;
112 mCsHandler = target;
Matthew Xie563e4142012-10-09 22:10:37 -0700113 if (VDBG) Log.d(TAG, "startMonitoring: mCsHandler: " + mCsHandler);
Jaikumar Ganesh74ef1192011-02-23 10:22:15 -0800114 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
115 if (adapter != null) {
116 adapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.PAN);
117 }
Robert Greenwalt665e1ae2012-08-21 19:27:00 -0700118 mBtdtHandler = new BtdtHandler(target.getLooper(), this);
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800119 }
120
Jaikumar Ganesh74ef1192011-02-23 10:22:15 -0800121 private BluetoothProfile.ServiceListener mProfileServiceListener =
122 new BluetoothProfile.ServiceListener() {
123 public void onServiceConnected(int profile, BluetoothProfile proxy) {
124 mBluetoothPan = (BluetoothPan) proxy;
125 }
126 public void onServiceDisconnected(int profile) {
127 mBluetoothPan = null;
128 }
129 };
130
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800131 /**
132 * Disable connectivity to a network
133 * TODO: do away with return value after making MobileDataStateTracker async
134 */
135 public boolean teardown() {
136 mTeardownRequested.set(true);
Jaikumar Ganesh74ef1192011-02-23 10:22:15 -0800137 if (mBluetoothPan != null) {
138 for (BluetoothDevice device: mBluetoothPan.getConnectedDevices()) {
139 mBluetoothPan.disconnect(device);
140 }
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800141 }
142 return true;
143 }
144
Irfan Sheriffda6da092012-08-16 12:49:23 -0700145 @Override
146 public void captivePortalCheckComplete() {
147 // not implemented
148 }
149
Wink Savilled747cbc2013-08-07 16:22:47 -0700150 @Override
151 public void captivePortalCheckCompleted(boolean isCaptivePortal) {
152 // not implemented
153 }
154
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800155 /**
156 * Re-enable connectivity to a network after a {@link #teardown()}.
157 */
158 public boolean reconnect() {
159 mTeardownRequested.set(false);
160 //Ignore
161 return true;
162 }
163
164 /**
165 * Turn the wireless radio off for a network.
166 * @param turnOn {@code true} to turn the radio on, {@code false}
167 */
168 public boolean setRadio(boolean turnOn) {
169 return true;
170 }
171
172 /**
173 * @return true - If are we currently tethered with another device.
174 */
175 public synchronized boolean isAvailable() {
176 return mNetworkInfo.isAvailable();
177 }
178
179 /**
180 * Tells the underlying networking system that the caller wants to
181 * begin using the named feature. The interpretation of {@code feature}
182 * is completely up to each networking implementation.
183 * @param feature the name of the feature to be used
184 * @param callingPid the process ID of the process that is issuing this request
185 * @param callingUid the user ID of the process that is issuing this request
186 * @return an integer value representing the outcome of the request.
187 * The interpretation of this value is specific to each networking
188 * implementation+feature combination, except that the value {@code -1}
189 * always indicates failure.
190 * TODO: needs to go away
191 */
192 public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
193 return -1;
194 }
195
196 /**
197 * Tells the underlying networking system that the caller is finished
198 * using the named feature. The interpretation of {@code feature}
199 * is completely up to each networking implementation.
200 * @param feature the name of the feature that is no longer needed.
201 * @param callingPid the process ID of the process that is issuing this request
202 * @param callingUid the user ID of the process that is issuing this request
203 * @return an integer value representing the outcome of the request.
204 * The interpretation of this value is specific to each networking
205 * implementation+feature combination, except that the value {@code -1}
206 * always indicates failure.
207 * TODO: needs to go away
208 */
209 public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
210 return -1;
211 }
212
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700213 @Override
214 public void setUserDataEnable(boolean enabled) {
215 Log.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
216 }
217
218 @Override
219 public void setPolicyDataEnable(boolean enabled) {
220 Log.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")");
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800221 }
222
223 /**
224 * Check if private DNS route is set for the network
225 */
226 public boolean isPrivateDnsRouteSet() {
227 return mPrivateDnsRouteSet.get();
228 }
229
230 /**
231 * Set a flag indicating private DNS route is set
232 */
233 public void privateDnsRouteSet(boolean enabled) {
234 mPrivateDnsRouteSet.set(enabled);
235 }
236
237 /**
238 * Fetch NetworkInfo for the network
239 */
Robert Greenwalt665e1ae2012-08-21 19:27:00 -0700240 public NetworkInfo getNetworkInfo() {
241 synchronized (mNetworkInfoLock) {
242 return new NetworkInfo(mNetworkInfo);
243 }
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800244 }
245
246 /**
247 * Fetch LinkProperties for the network
248 */
Robert Greenwalt665e1ae2012-08-21 19:27:00 -0700249 public LinkProperties getLinkProperties() {
250 synchronized (mLinkPropertiesLock) {
251 return new LinkProperties(mLinkProperties);
252 }
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800253 }
254
255 /**
256 * A capability is an Integer/String pair, the capabilities
257 * are defined in the class LinkSocket#Key.
258 *
259 * @return a copy of this connections capabilities, may be empty but never null.
260 */
261 public LinkCapabilities getLinkCapabilities() {
262 return new LinkCapabilities(mLinkCapabilities);
263 }
264
265 /**
266 * Fetch default gateway address for the network
267 */
268 public int getDefaultGatewayAddr() {
269 return mDefaultGatewayAddr.get();
270 }
271
272 /**
273 * Check if default route is set
274 */
275 public boolean isDefaultRouteSet() {
276 return mDefaultRouteSet.get();
277 }
278
279 /**
280 * Set a flag indicating default route is set for the network
281 */
282 public void defaultRouteSet(boolean enabled) {
283 mDefaultRouteSet.set(enabled);
284 }
285
286 /**
287 * Return the system properties name associated with the tcp buffer sizes
288 * for this network.
289 */
290 public String getTcpBufferSizesPropName() {
291 return "net.tcp.buffersize.wifi";
292 }
293
fredc0f420372012-04-12 00:02:00 -0700294 private static short countPrefixLength(byte [] mask) {
295 short count = 0;
296 for (byte b : mask) {
297 for (int i = 0; i < 8; ++i) {
298 if ((b & (1 << i)) != 0) {
299 ++count;
300 }
301 }
302 }
303 return count;
304 }
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800305
Robert Greenwalt665e1ae2012-08-21 19:27:00 -0700306 void startReverseTether(final LinkProperties linkProperties) {
307 if (linkProperties == null || TextUtils.isEmpty(linkProperties.getInterfaceName())) {
308 Log.e(TAG, "attempted to reverse tether with empty interface");
309 return;
fredc0f420372012-04-12 00:02:00 -0700310 }
Robert Greenwalt665e1ae2012-08-21 19:27:00 -0700311 synchronized (mLinkPropertiesLock) {
312 if (mLinkProperties.getInterfaceName() != null) {
313 Log.e(TAG, "attempted to reverse tether while already in process");
314 return;
315 }
316 mLinkProperties = linkProperties;
317 }
318 Thread dhcpThread = new Thread(new Runnable() {
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800319 public void run() {
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800320 //Currently this thread runs independently.
Robert Greenwalt665e1ae2012-08-21 19:27:00 -0700321 DhcpResults dhcpResults = new DhcpResults();
322 boolean success = NetworkUtils.runDhcp(linkProperties.getInterfaceName(),
323 dhcpResults);
324 synchronized (mLinkPropertiesLock) {
325 if (linkProperties.getInterfaceName() != mLinkProperties.getInterfaceName()) {
326 Log.e(TAG, "obsolete DHCP run aborted");
fredc0f420372012-04-12 00:02:00 -0700327 return;
328 }
Robert Greenwalt665e1ae2012-08-21 19:27:00 -0700329 if (!success) {
330 Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
fredc0f420372012-04-12 00:02:00 -0700331 return;
332 }
Robert Greenwalt665e1ae2012-08-21 19:27:00 -0700333 mLinkProperties = dhcpResults.linkProperties;
334 synchronized (mNetworkInfoLock) {
335 mNetworkInfo.setIsAvailable(true);
336 mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
337 if (mCsHandler != null) {
338 Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED,
339 new NetworkInfo(mNetworkInfo));
340 msg.sendToTarget();
341 }
342 }
343 return;
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800344 }
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800345 }
346 });
Robert Greenwalt665e1ae2012-08-21 19:27:00 -0700347 dhcpThread.start();
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800348 }
349
Robert Greenwalt665e1ae2012-08-21 19:27:00 -0700350 void stopReverseTether() {
351 synchronized (mLinkPropertiesLock) {
352 if (TextUtils.isEmpty(mLinkProperties.getInterfaceName())) {
353 Log.e(TAG, "attempted to stop reverse tether with nothing tethered");
354 return;
355 }
356 NetworkUtils.stopDhcp(mLinkProperties.getInterfaceName());
357 mLinkProperties.clear();
358 synchronized (mNetworkInfoLock) {
359 mNetworkInfo.setIsAvailable(false);
360 mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
361
362 if (mCsHandler != null) {
363 mCsHandler.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo)).
364 sendToTarget();
365 }
366 }
zzy7329e702012-04-27 12:15:57 -0700367 }
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800368 }
Robert Greenwaltd55a6b42011-03-25 13:09:25 -0700369
370 public void setDependencyMet(boolean met) {
371 // not supported on this network
372 }
Lorenzo Colitti69edd642013-03-07 11:01:12 -0800373
374 @Override
375 public void addStackedLink(LinkProperties link) {
376 mLinkProperties.addStackedLink(link);
377 }
378
379 @Override
380 public void removeStackedLink(LinkProperties link) {
381 mLinkProperties.removeStackedLink(link);
382 }
Robert Greenwalt665e1ae2012-08-21 19:27:00 -0700383
384 static class BtdtHandler extends Handler {
385 private AsyncChannel mStackChannel;
386 private final BluetoothTetheringDataTracker mBtdt;
387
388 BtdtHandler(Looper looper, BluetoothTetheringDataTracker parent) {
389 super(looper);
390 mBtdt = parent;
391 }
392
393 @Override
394 public void handleMessage(Message msg) {
395 switch (msg.what) {
396 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
397 if (VDBG) Log.d(TAG, "got CMD_CHANNEL_HALF_CONNECTED");
398 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
399 AsyncChannel ac = (AsyncChannel)msg.obj;
400 if (mBtdt.mAsyncChannel.compareAndSet(null, ac) == false) {
401 Log.e(TAG, "Trying to set mAsyncChannel twice!");
402 } else {
403 ac.sendMessage(
404 AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
405 }
406 }
407 break;
408 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
409 if (VDBG) Log.d(TAG, "got CMD_CHANNEL_DISCONNECTED");
410 mBtdt.stopReverseTether();
411 mBtdt.mAsyncChannel.set(null);
412 break;
413 case NetworkStateTracker.EVENT_NETWORK_CONNECTED:
414 LinkProperties linkProperties = (LinkProperties)(msg.obj);
415 if (VDBG) Log.d(TAG, "got EVENT_NETWORK_CONNECTED, " + linkProperties);
416 mBtdt.startReverseTether(linkProperties);
417 break;
418 case NetworkStateTracker.EVENT_NETWORK_DISCONNECTED:
419 linkProperties = (LinkProperties)(msg.obj);
420 if (VDBG) Log.d(TAG, "got EVENT_NETWORK_DISCONNECTED, " + linkProperties);
421 mBtdt.stopReverseTether();
422 break;
423 }
424 }
425 }
426
427 @Override
428 public void supplyMessenger(Messenger messenger) {
429 if (messenger != null) {
430 new AsyncChannel().connect(mContext, mBtdtHandler, messenger);
431 }
432 }
Jaikumar Ganesh15c74392010-12-21 22:31:44 -0800433}