• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.bluetooth.pan;
18 
19 import android.bluetooth.BluetoothDevice;
20 import android.content.Context;
21 import android.net.ConnectivityManager;
22 import android.net.DhcpResults;
23 import android.net.LinkProperties;
24 import android.net.NetworkAgent;
25 import android.net.NetworkCapabilities;
26 import android.net.NetworkFactory;
27 import android.net.NetworkInfo;
28 import android.net.NetworkInfo.DetailedState;
29 import android.net.NetworkRequest;
30 import android.net.NetworkUtils;
31 import android.os.Looper;
32 import android.os.Message;
33 import android.os.Messenger;
34 import android.os.RemoteException;
35 import android.text.TextUtils;
36 import android.util.Slog;
37 
38 import com.android.bluetooth.pan.PanService;
39 import com.android.internal.util.AsyncChannel;
40 
41 /**
42  * This class tracks the data connection associated with Bluetooth
43  * reverse tethering. PanService calls it when a reverse tethered
44  * connection needs to be activated or deactivated.
45  *
46  * @hide
47  */
48 public class BluetoothTetheringNetworkFactory extends NetworkFactory {
49     private static final String NETWORK_TYPE = "Bluetooth Tethering";
50     private static final String TAG = "BluetoothTetheringNetworkFactory";
51     private static final int NETWORK_SCORE = 69;
52 
53     private final NetworkCapabilities mNetworkCapabilities;
54     private final Context mContext;
55     private final PanService mPanService;
56 
57     // All accesses to these must be synchronized(this).
58     private final NetworkInfo mNetworkInfo;
59     private LinkProperties mLinkProperties;
60     private NetworkAgent mNetworkAgent;
61 
BluetoothTetheringNetworkFactory(Context context, Looper looper, PanService panService)62     public BluetoothTetheringNetworkFactory(Context context, Looper looper, PanService panService) {
63         super(looper, context, NETWORK_TYPE, new NetworkCapabilities());
64 
65         mContext = context;
66         mPanService = panService;
67 
68         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORK_TYPE, "");
69         mLinkProperties = new LinkProperties();
70         mNetworkCapabilities = new NetworkCapabilities();
71         initNetworkCapabilities();
72         setCapabilityFilter(mNetworkCapabilities);
73     }
74 
75     // Called by NetworkFactory when PanService and NetworkFactory both desire a Bluetooth
76     // reverse-tether connection.  A network interface for Bluetooth reverse-tethering can be
77     // assumed to be available because we only register our NetworkFactory when it is so.
78     @Override
startNetwork()79     protected void startNetwork() {
80         // TODO: Handle DHCP renew.
81         Thread dhcpThread = new Thread(new Runnable() {
82             public void run() {
83                 LinkProperties linkProperties;
84                 synchronized (BluetoothTetheringNetworkFactory.this) {
85                     linkProperties = mLinkProperties;
86                     if (linkProperties.getInterfaceName() == null) {
87                         Slog.e(TAG, "attempted to reverse tether without interface name");
88                         return;
89                     }
90                     log("dhcpThread(+" + linkProperties.getInterfaceName() +
91                             "): mNetworkInfo=" + mNetworkInfo);
92                 }
93 
94                 DhcpResults dhcpResults = new DhcpResults();
95                 // TODO: Handle DHCP renewals better.
96                 // In general runDhcp handles DHCP renewals for us, because
97                 // the dhcp client stays running, but if the renewal fails,
98                 // we will lose our IP address and connectivity without
99                 // noticing.
100                 if (!NetworkUtils.runDhcp(linkProperties.getInterfaceName(), dhcpResults)) {
101                     Slog.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
102                     synchronized(BluetoothTetheringNetworkFactory.this) {
103                         setScoreFilter(-1);
104                     }
105                     return;
106                 }
107 
108                 synchronized(BluetoothTetheringNetworkFactory.this) {
109                     mLinkProperties = dhcpResults.toLinkProperties(
110                             linkProperties.getInterfaceName());
111                     mNetworkInfo.setIsAvailable(true);
112                     mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
113 
114                     // Create our NetworkAgent.
115                     mNetworkAgent = new NetworkAgent(getLooper(), mContext, NETWORK_TYPE,
116                             mNetworkInfo, mNetworkCapabilities, mLinkProperties, NETWORK_SCORE) {
117                         public void unwanted() {
118                             BluetoothTetheringNetworkFactory.this.onCancelRequest();
119                         };
120                     };
121                 }
122             }
123         });
124         dhcpThread.start();
125     }
126 
127     // Called from NetworkFactory to indicate ConnectivityService no longer desires a Bluetooth
128     // reverse-tether network.
129     @Override
stopNetwork()130     protected void stopNetwork() {
131         // Let NetworkAgent disconnect do the teardown.
132     }
133 
134     // Called by the NetworkFactory, NetworkAgent or PanService to tear down network.
onCancelRequest()135     private synchronized void onCancelRequest() {
136         if (!TextUtils.isEmpty(mLinkProperties.getInterfaceName())) {
137             NetworkUtils.stopDhcp(mLinkProperties.getInterfaceName());
138         }
139         mLinkProperties.clear();
140         mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
141         if (mNetworkAgent != null) {
142             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
143             mNetworkAgent = null;
144         }
145         for (BluetoothDevice device : mPanService.getConnectedDevices()) {
146              mPanService.disconnect(device);
147         }
148     }
149 
150     // Called by PanService when a network interface for Bluetooth reverse-tethering
151     // becomes available.  We register our NetworkFactory at this point.
startReverseTether(final String iface)152     public void startReverseTether(final String iface) {
153         if (iface == null || TextUtils.isEmpty(iface)) {
154             Slog.e(TAG, "attempted to reverse tether with empty interface");
155             return;
156         }
157         synchronized(this) {
158             if (mLinkProperties.getInterfaceName() != null) {
159                 Slog.e(TAG, "attempted to reverse tether while already in process");
160                 return;
161             }
162             mLinkProperties = new LinkProperties();
163             mLinkProperties.setInterfaceName(iface);
164             // Advertise ourselves to ConnectivityService.
165             register();
166             setScoreFilter(NETWORK_SCORE);
167         }
168     }
169 
170     // Called by PanService when a network interface for Bluetooth reverse-tethering
171     // goes away.  We stop advertising ourselves to ConnectivityService at this point.
stopReverseTether()172     public synchronized void stopReverseTether() {
173         if (TextUtils.isEmpty(mLinkProperties.getInterfaceName())) {
174             Slog.e(TAG, "attempted to stop reverse tether with nothing tethered");
175             return;
176         }
177         onCancelRequest();
178         setScoreFilter(-1);
179         unregister();
180     }
181 
initNetworkCapabilities()182     private void initNetworkCapabilities() {
183         mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH);
184         mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
185         mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
186         // Bluetooth v3 and v4 go up to 24 Mbps.
187         // TODO: Adjust this to actual connection bandwidth.
188         mNetworkCapabilities.setLinkUpstreamBandwidthKbps(24 * 1000);
189         mNetworkCapabilities.setLinkDownstreamBandwidthKbps(24 * 1000);
190     }
191 }
192