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