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 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 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 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 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. 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. 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. 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 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