Home | History | Annotate | Download | only in pan
      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 
     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 
     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
     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
    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.
    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.
    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.
    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 
    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