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