• 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.ip.IpManager;
30 import android.net.ip.IpManager.WaitForProvisioningCallback;
31 import android.os.Looper;
32 import android.text.TextUtils;
33 import android.util.Slog;
34 
35 import com.android.bluetooth.pan.PanService;
36 import com.android.internal.util.AsyncChannel;
37 
38 /**
39  * This class tracks the data connection associated with Bluetooth
40  * reverse tethering. PanService calls it when a reverse tethered
41  * connection needs to be activated or deactivated.
42  *
43  * @hide
44  */
45 public class BluetoothTetheringNetworkFactory extends NetworkFactory {
46     private static final String NETWORK_TYPE = "Bluetooth Tethering";
47     private static final String TAG = "BluetoothTetheringNetworkFactory";
48     private static final int NETWORK_SCORE = 69;
49 
50     private final NetworkCapabilities mNetworkCapabilities;
51     private final Context mContext;
52     private final PanService mPanService;
53 
54     // All accesses to these must be synchronized(this).
55     private final NetworkInfo mNetworkInfo;
56     private IpManager mIpManager;
57     private String mInterfaceName;
58     private NetworkAgent mNetworkAgent;
59 
BluetoothTetheringNetworkFactory(Context context, Looper looper, PanService panService)60     public BluetoothTetheringNetworkFactory(Context context, Looper looper, PanService panService) {
61         super(looper, context, NETWORK_TYPE, new NetworkCapabilities());
62 
63         mContext = context;
64         mPanService = panService;
65 
66         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORK_TYPE, "");
67         mNetworkCapabilities = new NetworkCapabilities();
68         initNetworkCapabilities();
69         setCapabilityFilter(mNetworkCapabilities);
70     }
71 
stopIpManagerLocked()72     private void stopIpManagerLocked() {
73         if (mIpManager != null) {
74             mIpManager.shutdown();
75             mIpManager = null;
76         }
77     }
78 
79     // Called by NetworkFactory when PanService and NetworkFactory both desire a Bluetooth
80     // reverse-tether connection.  A network interface for Bluetooth reverse-tethering can be
81     // assumed to be available because we only register our NetworkFactory when it is so.
82     @Override
startNetwork()83     protected void startNetwork() {
84         // TODO: Figure out how to replace this thread with simple invocations
85         // of IpManager. This will likely necessitate a rethink about
86         // NetworkAgent, NetworkInfo, and associated instance lifetimes.
87         Thread ipProvisioningThread = new Thread(new Runnable() {
88             public void run() {
89                 LinkProperties linkProperties;
90                 final WaitForProvisioningCallback ipmCallback = new WaitForProvisioningCallback() {
91                     @Override
92                     public void onLinkPropertiesChange(LinkProperties newLp) {
93                         synchronized (BluetoothTetheringNetworkFactory.this) {
94                             if (mNetworkAgent != null && mNetworkInfo.isConnected()) {
95                                 mNetworkAgent.sendLinkProperties(newLp);
96                             }
97                         }
98                     }
99                 };
100 
101                 synchronized (BluetoothTetheringNetworkFactory.this) {
102                     if (TextUtils.isEmpty(mInterfaceName)) {
103                         Slog.e(TAG, "attempted to reverse tether without interface name");
104                         return;
105                     }
106                     log("ipProvisioningThread(+" + mInterfaceName + "): " +
107                             "mNetworkInfo=" + mNetworkInfo);
108                     mIpManager = new IpManager(mContext, mInterfaceName, ipmCallback);
109                     mIpManager.startProvisioning(
110                             mIpManager.buildProvisioningConfiguration()
111                                     .withoutIpReachabilityMonitor()
112                                     .build());
113                     mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, null);
114                 }
115 
116                 linkProperties = ipmCallback.waitForProvisioning();
117                 if (linkProperties == null) {
118                     Slog.e(TAG, "IP provisioning error.");
119                     synchronized(BluetoothTetheringNetworkFactory.this) {
120                         stopIpManagerLocked();
121                         setScoreFilter(-1);
122                     }
123                     return;
124                 }
125 
126                 synchronized(BluetoothTetheringNetworkFactory.this) {
127                     mNetworkInfo.setIsAvailable(true);
128                     mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
129 
130                     // Create our NetworkAgent.
131                     mNetworkAgent = new NetworkAgent(getLooper(), mContext, NETWORK_TYPE,
132                             mNetworkInfo, mNetworkCapabilities, linkProperties, NETWORK_SCORE) {
133                         public void unwanted() {
134                             BluetoothTetheringNetworkFactory.this.onCancelRequest();
135                         };
136                     };
137                 }
138             }
139         });
140         ipProvisioningThread.start();
141     }
142 
143     // Called from NetworkFactory to indicate ConnectivityService no longer desires a Bluetooth
144     // reverse-tether network.
145     @Override
stopNetwork()146     protected void stopNetwork() {
147         // Let NetworkAgent disconnect do the teardown.
148     }
149 
150     // Called by the NetworkFactory, NetworkAgent or PanService to tear down network.
onCancelRequest()151     private synchronized void onCancelRequest() {
152         stopIpManagerLocked();
153         mInterfaceName = "";
154 
155         mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
156         if (mNetworkAgent != null) {
157             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
158             mNetworkAgent = null;
159         }
160         for (BluetoothDevice device : mPanService.getConnectedDevices()) {
161              mPanService.disconnect(device);
162         }
163     }
164 
165     // Called by PanService when a network interface for Bluetooth reverse-tethering
166     // becomes available.  We register our NetworkFactory at this point.
startReverseTether(final String iface)167     public void startReverseTether(final String iface) {
168         if (iface == null || TextUtils.isEmpty(iface)) {
169             Slog.e(TAG, "attempted to reverse tether with empty interface");
170             return;
171         }
172         synchronized(this) {
173             if (!TextUtils.isEmpty(mInterfaceName)) {
174                 Slog.e(TAG, "attempted to reverse tether while already in process");
175                 return;
176             }
177             mInterfaceName = iface;
178             // Advertise ourselves to ConnectivityService.
179             register();
180             setScoreFilter(NETWORK_SCORE);
181         }
182     }
183 
184     // Called by PanService when a network interface for Bluetooth reverse-tethering
185     // goes away.  We stop advertising ourselves to ConnectivityService at this point.
stopReverseTether()186     public synchronized void stopReverseTether() {
187         if (TextUtils.isEmpty(mInterfaceName)) {
188             Slog.e(TAG, "attempted to stop reverse tether with nothing tethered");
189             return;
190         }
191         onCancelRequest();
192         setScoreFilter(-1);
193         unregister();
194     }
195 
initNetworkCapabilities()196     private void initNetworkCapabilities() {
197         mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH);
198         mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
199         mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
200         // Bluetooth v3 and v4 go up to 24 Mbps.
201         // TODO: Adjust this to actual connection bandwidth.
202         mNetworkCapabilities.setLinkUpstreamBandwidthKbps(24 * 1000);
203         mNetworkCapabilities.setLinkDownstreamBandwidthKbps(24 * 1000);
204     }
205 }
206