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