• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.bluetooth.BluetoothPan;
21 import android.bluetooth.BluetoothProfile;
22 import android.bluetooth.IBluetoothPan;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.res.Resources.NotFoundException;
26 import android.net.ConnectivityManager;
27 import android.net.InterfaceConfiguration;
28 import android.net.LinkAddress;
29 import android.net.NetworkUtils;
30 import android.os.Binder;
31 import android.os.Handler;
32 import android.os.IBinder;
33 import android.os.INetworkManagementService;
34 import android.os.Message;
35 import android.os.ServiceManager;
36 import android.os.UserManager;
37 import android.provider.Settings;
38 import android.util.Log;
39 
40 import com.android.bluetooth.BluetoothMetricsProto;
41 import com.android.bluetooth.Utils;
42 import com.android.bluetooth.btservice.MetricsLogger;
43 import com.android.bluetooth.btservice.ProfileService;
44 
45 import java.net.InetAddress;
46 import java.util.ArrayList;
47 import java.util.HashMap;
48 import java.util.List;
49 
50 /**
51  * Provides Bluetooth Pan Device profile, as a service in
52  * the Bluetooth application.
53  * @hide
54  */
55 public class PanService extends ProfileService {
56     private static final String TAG = "PanService";
57     private static final boolean DBG = false;
58     private static PanService sPanService;
59 
60     private static final String BLUETOOTH_IFACE_ADDR_START = "192.168.44.1";
61     private static final int BLUETOOTH_MAX_PAN_CONNECTIONS = 5;
62     private static final int BLUETOOTH_PREFIX_LENGTH = 24;
63 
64     private HashMap<BluetoothDevice, BluetoothPanDevice> mPanDevices;
65     private ArrayList<String> mBluetoothIfaceAddresses;
66     private int mMaxPanDevices;
67     private String mPanIfName;
68     private String mNapIfaceAddr;
69     private boolean mNativeAvailable;
70 
71     private static final int MESSAGE_CONNECT = 1;
72     private static final int MESSAGE_DISCONNECT = 2;
73     private static final int MESSAGE_CONNECT_STATE_CHANGED = 11;
74     private boolean mTetherOn = false;
75 
76     private BluetoothTetheringNetworkFactory mNetworkFactory;
77 
78 
79     static {
classInitNative()80         classInitNative();
81     }
82 
83     @Override
initBinder()84     public IProfileServiceBinder initBinder() {
85         return new BluetoothPanBinder(this);
86     }
87 
getPanService()88     public static synchronized PanService getPanService() {
89         if (sPanService == null) {
90             Log.w(TAG, "getPanService(): service is null");
91             return null;
92         }
93         if (!sPanService.isAvailable()) {
94             Log.w(TAG, "getPanService(): service is not available ");
95             return null;
96         }
97         return sPanService;
98     }
99 
setPanService(PanService instance)100     private static synchronized void setPanService(PanService instance) {
101         if (DBG) {
102             Log.d(TAG, "setPanService(): set to: " + instance);
103         }
104         sPanService = instance;
105     }
106 
107     @Override
start()108     protected boolean start() {
109         mPanDevices = new HashMap<BluetoothDevice, BluetoothPanDevice>();
110         mBluetoothIfaceAddresses = new ArrayList<String>();
111         try {
112             mMaxPanDevices = getResources().getInteger(
113                     com.android.internal.R.integer.config_max_pan_devices);
114         } catch (NotFoundException e) {
115             mMaxPanDevices = BLUETOOTH_MAX_PAN_CONNECTIONS;
116         }
117         initializeNative();
118         mNativeAvailable = true;
119 
120         mNetworkFactory =
121                 new BluetoothTetheringNetworkFactory(getBaseContext(), getMainLooper(), this);
122         setPanService(this);
123 
124         return true;
125     }
126 
127     @Override
stop()128     protected boolean stop() {
129         mHandler.removeCallbacksAndMessages(null);
130         return true;
131     }
132 
133     @Override
cleanup()134     protected void cleanup() {
135         // TODO(b/72948646): this should be moved to stop()
136         setPanService(null);
137         if (mNativeAvailable) {
138             cleanupNative();
139             mNativeAvailable = false;
140         }
141         if (mPanDevices != null) {
142            int[] desiredStates = {BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED,
143                                   BluetoothProfile.STATE_DISCONNECTING};
144            List<BluetoothDevice> devList =
145                    getDevicesMatchingConnectionStates(desiredStates);
146            for (BluetoothDevice device : devList) {
147                 BluetoothPanDevice panDevice = mPanDevices.get(device);
148                 Log.d(TAG, "panDevice: " + panDevice + " device address: " + device);
149                 if (panDevice != null) {
150                     handlePanDeviceStateChange(device, mPanIfName,
151                         BluetoothProfile.STATE_DISCONNECTED,
152                         panDevice.mLocalRole, panDevice.mRemoteRole);
153                 }
154             }
155             mPanDevices.clear();
156         }
157     }
158 
159     private final Handler mHandler = new Handler() {
160         @Override
161         public void handleMessage(Message msg) {
162             switch (msg.what) {
163                 case MESSAGE_CONNECT: {
164                     BluetoothDevice device = (BluetoothDevice) msg.obj;
165                     if (!connectPanNative(Utils.getByteAddress(device),
166                             BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE)) {
167                         handlePanDeviceStateChange(device, null, BluetoothProfile.STATE_CONNECTING,
168                                 BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE);
169                         handlePanDeviceStateChange(device, null,
170                                 BluetoothProfile.STATE_DISCONNECTED, BluetoothPan.LOCAL_PANU_ROLE,
171                                 BluetoothPan.REMOTE_NAP_ROLE);
172                         break;
173                     }
174                 }
175                 break;
176                 case MESSAGE_DISCONNECT: {
177                     BluetoothDevice device = (BluetoothDevice) msg.obj;
178                     if (!disconnectPanNative(Utils.getByteAddress(device))) {
179                         handlePanDeviceStateChange(device, mPanIfName,
180                                 BluetoothProfile.STATE_DISCONNECTING, BluetoothPan.LOCAL_PANU_ROLE,
181                                 BluetoothPan.REMOTE_NAP_ROLE);
182                         handlePanDeviceStateChange(device, mPanIfName,
183                                 BluetoothProfile.STATE_DISCONNECTED, BluetoothPan.LOCAL_PANU_ROLE,
184                                 BluetoothPan.REMOTE_NAP_ROLE);
185                         break;
186                     }
187                 }
188                 break;
189                 case MESSAGE_CONNECT_STATE_CHANGED: {
190                     ConnectState cs = (ConnectState) msg.obj;
191                     BluetoothDevice device = getDevice(cs.addr);
192                     // TBD get iface from the msg
193                     if (DBG) {
194                         Log.d(TAG,
195                                 "MESSAGE_CONNECT_STATE_CHANGED: " + device + " state: " + cs.state);
196                     }
197                     handlePanDeviceStateChange(device, mPanIfName /* iface */,
198                             convertHalState(cs.state), cs.local_role, cs.remote_role);
199                 }
200                 break;
201             }
202         }
203     };
204 
205     /**
206      * Handlers for incoming service calls
207      */
208     private static class BluetoothPanBinder extends IBluetoothPan.Stub
209             implements IProfileServiceBinder {
210         private PanService mService;
211 
BluetoothPanBinder(PanService svc)212         BluetoothPanBinder(PanService svc) {
213             mService = svc;
214         }
215 
216         @Override
cleanup()217         public void cleanup() {
218             mService = null;
219         }
220 
getService()221         private PanService getService() {
222             if (!Utils.checkCaller()) {
223                 Log.w(TAG, "Pan call not allowed for non-active user");
224                 return null;
225             }
226 
227             if (mService != null && mService.isAvailable()) {
228                 return mService;
229             }
230             return null;
231         }
232 
233         @Override
connect(BluetoothDevice device)234         public boolean connect(BluetoothDevice device) {
235             PanService service = getService();
236             if (service == null) {
237                 return false;
238             }
239             return service.connect(device);
240         }
241 
242         @Override
disconnect(BluetoothDevice device)243         public boolean disconnect(BluetoothDevice device) {
244             PanService service = getService();
245             if (service == null) {
246                 return false;
247             }
248             return service.disconnect(device);
249         }
250 
251         @Override
getConnectionState(BluetoothDevice device)252         public int getConnectionState(BluetoothDevice device) {
253             PanService service = getService();
254             if (service == null) {
255                 return BluetoothPan.STATE_DISCONNECTED;
256             }
257             return service.getConnectionState(device);
258         }
259 
isPanNapOn()260         private boolean isPanNapOn() {
261             PanService service = getService();
262             if (service == null) {
263                 return false;
264             }
265             return service.isPanNapOn();
266         }
267 
isPanUOn()268         private boolean isPanUOn() {
269             if (DBG) {
270                 Log.d(TAG, "isTetheringOn call getPanLocalRoleNative");
271             }
272             PanService service = getService();
273             if (service == null) {
274                 return false;
275             }
276             return service.isPanUOn();
277         }
278 
279         @Override
isTetheringOn()280         public boolean isTetheringOn() {
281             // TODO(BT) have a variable marking the on/off state
282             PanService service = getService();
283             if (service == null) {
284                 return false;
285             }
286             return service.isTetheringOn();
287         }
288 
289         @Override
setBluetoothTethering(boolean value)290         public void setBluetoothTethering(boolean value) {
291             PanService service = getService();
292             if (service == null) {
293                 return;
294             }
295             Log.d(TAG, "setBluetoothTethering: " + value + ", mTetherOn: " + service.mTetherOn);
296             service.setBluetoothTethering(value);
297         }
298 
299         @Override
getConnectedDevices()300         public List<BluetoothDevice> getConnectedDevices() {
301             PanService service = getService();
302             if (service == null) {
303                 return new ArrayList<BluetoothDevice>(0);
304             }
305             return service.getConnectedDevices();
306         }
307 
308         @Override
getDevicesMatchingConnectionStates(int[] states)309         public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
310             PanService service = getService();
311             if (service == null) {
312                 return new ArrayList<BluetoothDevice>(0);
313             }
314             return service.getDevicesMatchingConnectionStates(states);
315         }
316     }
317 
318     ;
319 
connect(BluetoothDevice device)320     public boolean connect(BluetoothDevice device) {
321         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
322         if (getConnectionState(device) != BluetoothProfile.STATE_DISCONNECTED) {
323             Log.e(TAG, "Pan Device not disconnected: " + device);
324             return false;
325         }
326         Message msg = mHandler.obtainMessage(MESSAGE_CONNECT, device);
327         mHandler.sendMessage(msg);
328         return true;
329     }
330 
disconnect(BluetoothDevice device)331     public boolean disconnect(BluetoothDevice device) {
332         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
333         Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT, device);
334         mHandler.sendMessage(msg);
335         return true;
336     }
337 
getConnectionState(BluetoothDevice device)338     public int getConnectionState(BluetoothDevice device) {
339         BluetoothPanDevice panDevice = mPanDevices.get(device);
340         if (panDevice == null) {
341             return BluetoothPan.STATE_DISCONNECTED;
342         }
343         return panDevice.mState;
344     }
345 
isPanNapOn()346     boolean isPanNapOn() {
347         if (DBG) {
348             Log.d(TAG, "isTetheringOn call getPanLocalRoleNative");
349         }
350         return (getPanLocalRoleNative() & BluetoothPan.LOCAL_NAP_ROLE) != 0;
351     }
352 
isPanUOn()353     boolean isPanUOn() {
354         if (DBG) {
355             Log.d(TAG, "isTetheringOn call getPanLocalRoleNative");
356         }
357         return (getPanLocalRoleNative() & BluetoothPan.LOCAL_PANU_ROLE) != 0;
358     }
359 
isTetheringOn()360     public boolean isTetheringOn() {
361         // TODO(BT) have a variable marking the on/off state
362         return mTetherOn;
363     }
364 
setBluetoothTethering(boolean value)365     void setBluetoothTethering(boolean value) {
366         if (DBG) {
367             Log.d(TAG, "setBluetoothTethering: " + value + ", mTetherOn: " + mTetherOn);
368         }
369         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
370         final Context context = getBaseContext();
371         String pkgName = context.getOpPackageName();
372 
373         // Clear caller identity temporarily so enforceTetherChangePermission UID checks work
374         // correctly
375         final long identityToken = Binder.clearCallingIdentity();
376         try {
377             ConnectivityManager.enforceTetherChangePermission(context, pkgName);
378         } finally {
379             Binder.restoreCallingIdentity(identityToken);
380         }
381 
382         UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
383         if (um.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING) && value) {
384             throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user.");
385         }
386         if (mTetherOn != value) {
387             //drop any existing panu or pan-nap connection when changing the tethering state
388             mTetherOn = value;
389             List<BluetoothDevice> devList = getConnectedDevices();
390             for (BluetoothDevice dev : devList) {
391                 disconnect(dev);
392             }
393         }
394     }
395 
setPriority(BluetoothDevice device, int priority)396     public boolean setPriority(BluetoothDevice device, int priority) {
397         if (device == null) {
398             throw new IllegalArgumentException("Null device");
399         }
400         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
401         Settings.Global.putInt(getContentResolver(),
402                 Settings.Global.getBluetoothPanPriorityKey(device.getAddress()), priority);
403         if (DBG) {
404             Log.d(TAG, "Saved priority " + device + " = " + priority);
405         }
406         return true;
407     }
408 
getPriority(BluetoothDevice device)409     public int getPriority(BluetoothDevice device) {
410         if (device == null) {
411             throw new IllegalArgumentException("Null device");
412         }
413         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
414         return Settings.Global.getInt(getContentResolver(),
415                 Settings.Global.getBluetoothPanPriorityKey(device.getAddress()),
416                 BluetoothProfile.PRIORITY_UNDEFINED);
417     }
418 
getConnectedDevices()419     public List<BluetoothDevice> getConnectedDevices() {
420         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
421         List<BluetoothDevice> devices =
422                 getDevicesMatchingConnectionStates(new int[]{BluetoothProfile.STATE_CONNECTED});
423         return devices;
424     }
425 
getDevicesMatchingConnectionStates(int[] states)426     List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
427         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
428         List<BluetoothDevice> panDevices = new ArrayList<BluetoothDevice>();
429 
430         for (BluetoothDevice device : mPanDevices.keySet()) {
431             int panDeviceState = getConnectionState(device);
432             for (int state : states) {
433                 if (state == panDeviceState) {
434                     panDevices.add(device);
435                     break;
436                 }
437             }
438         }
439         return panDevices;
440     }
441 
442     protected static class ConnectState {
ConnectState(byte[] address, int state, int error, int localRole, int remoteRole)443         public ConnectState(byte[] address, int state, int error, int localRole, int remoteRole) {
444             this.addr = address;
445             this.state = state;
446             this.error = error;
447             this.local_role = localRole;
448             this.remote_role = remoteRole;
449         }
450 
451         public byte[] addr;
452         public int state;
453         public int error;
454         public int local_role;
455         public int remote_role;
456     }
457 
458     ;
459 
onConnectStateChanged(byte[] address, int state, int error, int localRole, int remoteRole)460     private void onConnectStateChanged(byte[] address, int state, int error, int localRole,
461             int remoteRole) {
462         if (DBG) {
463             Log.d(TAG, "onConnectStateChanged: " + state + ", local role:" + localRole
464                     + ", remoteRole: " + remoteRole);
465         }
466         Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED);
467         msg.obj = new ConnectState(address, state, error, localRole, remoteRole);
468         mHandler.sendMessage(msg);
469     }
470 
onControlStateChanged(int localRole, int state, int error, String ifname)471     private void onControlStateChanged(int localRole, int state, int error, String ifname) {
472         if (DBG) {
473             Log.d(TAG, "onControlStateChanged: " + state + ", error: " + error + ", ifname: "
474                     + ifname);
475         }
476         if (error == 0) {
477             mPanIfName = ifname;
478         }
479     }
480 
convertHalState(int halState)481     private static int convertHalState(int halState) {
482         switch (halState) {
483             case CONN_STATE_CONNECTED:
484                 return BluetoothProfile.STATE_CONNECTED;
485             case CONN_STATE_CONNECTING:
486                 return BluetoothProfile.STATE_CONNECTING;
487             case CONN_STATE_DISCONNECTED:
488                 return BluetoothProfile.STATE_DISCONNECTED;
489             case CONN_STATE_DISCONNECTING:
490                 return BluetoothProfile.STATE_DISCONNECTING;
491             default:
492                 Log.e(TAG, "bad pan connection state: " + halState);
493                 return BluetoothProfile.STATE_DISCONNECTED;
494         }
495     }
496 
handlePanDeviceStateChange(BluetoothDevice device, String iface, int state, int localRole, int remoteRole)497     void handlePanDeviceStateChange(BluetoothDevice device, String iface, int state, int localRole,
498             int remoteRole) {
499         if (DBG) {
500             Log.d(TAG, "handlePanDeviceStateChange: device: " + device + ", iface: " + iface
501                     + ", state: " + state + ", localRole:" + localRole + ", remoteRole:"
502                     + remoteRole);
503         }
504         int prevState;
505 
506         BluetoothPanDevice panDevice = mPanDevices.get(device);
507         if (panDevice == null) {
508             Log.i(TAG, "state " + state + " Num of connected pan devices: " + mPanDevices.size());
509             prevState = BluetoothProfile.STATE_DISCONNECTED;
510             panDevice = new BluetoothPanDevice(state, iface, localRole, remoteRole);
511             mPanDevices.put(device, panDevice);
512         } else {
513             prevState = panDevice.mState;
514             panDevice.mState = state;
515             panDevice.mLocalRole = localRole;
516             panDevice.mRemoteRole = remoteRole;
517             panDevice.mIface = iface;
518         }
519 
520         // Avoid race condition that gets this class stuck in STATE_DISCONNECTING. While we
521         // are in STATE_CONNECTING, if a BluetoothPan#disconnect call comes in, the original
522         // connect call will put us in STATE_DISCONNECTED. Then, the disconnect completes and
523         // changes the state to STATE_DISCONNECTING. All future calls to BluetoothPan#connect
524         // will fail until the caller explicitly calls BluetoothPan#disconnect.
525         if (prevState == BluetoothProfile.STATE_DISCONNECTED
526                 && state == BluetoothProfile.STATE_DISCONNECTING) {
527             Log.d(TAG, "Ignoring state change from " + prevState + " to " + state);
528             mPanDevices.remove(device);
529             return;
530         }
531 
532         Log.d(TAG, "handlePanDeviceStateChange preState: " + prevState + " state: " + state);
533         if (prevState == state) {
534             return;
535         }
536         if (remoteRole == BluetoothPan.LOCAL_PANU_ROLE) {
537             if (state == BluetoothProfile.STATE_CONNECTED) {
538                 if ((!mTetherOn) || (localRole == BluetoothPan.LOCAL_PANU_ROLE)) {
539                     Log.d(TAG, "handlePanDeviceStateChange BT tethering is off/Local role"
540                             + " is PANU drop the connection");
541                     mPanDevices.remove(device);
542                     disconnectPanNative(Utils.getByteAddress(device));
543                     return;
544                 }
545                 Log.d(TAG, "handlePanDeviceStateChange LOCAL_NAP_ROLE:REMOTE_PANU_ROLE");
546                 if (mNapIfaceAddr == null) {
547                     mNapIfaceAddr = startTethering(iface);
548                     if (mNapIfaceAddr == null) {
549                         Log.e(TAG, "Error seting up tether interface");
550                         mPanDevices.remove(device);
551                         disconnectPanNative(Utils.getByteAddress(device));
552                         return;
553                     }
554                 }
555             } else if (state == BluetoothProfile.STATE_DISCONNECTED) {
556                 mPanDevices.remove(device);
557                 Log.i(TAG, "remote(PANU) is disconnected, Remaining connected PANU devices: "
558                         + mPanDevices.size());
559                 if (mNapIfaceAddr != null && mPanDevices.size() == 0) {
560                     stopTethering(iface);
561                     mNapIfaceAddr = null;
562                 }
563             }
564         } else if (mNetworkFactory != null) {
565             // PANU Role = reverse Tether
566             Log.d(TAG, "handlePanDeviceStateChange LOCAL_PANU_ROLE:REMOTE_NAP_ROLE state = " + state
567                     + ", prevState = " + prevState);
568             if (state == BluetoothProfile.STATE_CONNECTED) {
569                 mNetworkFactory.startReverseTether(iface);
570             } else if (state == BluetoothProfile.STATE_DISCONNECTED) {
571                 mNetworkFactory.stopReverseTether();
572                 mPanDevices.remove(device);
573             }
574         }
575 
576         if (state == BluetoothProfile.STATE_CONNECTED) {
577             MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.PAN);
578         }
579         /* Notifying the connection state change of the profile before sending the intent for
580            connection state change, as it was causing a race condition, with the UI not being
581            updated with the correct connection state. */
582         Log.d(TAG, "Pan Device state : device: " + device + " State:" + prevState + "->" + state);
583         Intent intent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
584         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
585         intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_STATE, prevState);
586         intent.putExtra(BluetoothPan.EXTRA_STATE, state);
587         intent.putExtra(BluetoothPan.EXTRA_LOCAL_ROLE, localRole);
588         sendBroadcast(intent, BLUETOOTH_PERM);
589     }
590 
startTethering(String iface)591     private String startTethering(String iface) {
592         return configureBtIface(true, iface);
593     }
594 
stopTethering(String iface)595     private String stopTethering(String iface) {
596         return configureBtIface(false, iface);
597     }
598 
configureBtIface(boolean enable, String iface)599     private String configureBtIface(boolean enable, String iface) {
600         Log.i(TAG, "configureBtIface: " + iface + " enable: " + enable);
601 
602         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
603         INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
604         ConnectivityManager cm =
605                 (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
606         String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs();
607 
608         // bring toggle the interfaces
609         String[] currentIfaces = new String[0];
610         try {
611             currentIfaces = service.listInterfaces();
612         } catch (Exception e) {
613             Log.e(TAG, "Error listing Interfaces :" + e);
614             return null;
615         }
616 
617         boolean found = false;
618         for (String currIface : currentIfaces) {
619             if (currIface.equals(iface)) {
620                 found = true;
621                 break;
622             }
623         }
624 
625         if (!found) {
626             return null;
627         }
628 
629         InterfaceConfiguration ifcg = null;
630         String address = null;
631         try {
632             ifcg = service.getInterfaceConfig(iface);
633             if (ifcg != null) {
634                 InetAddress addr = null;
635                 LinkAddress linkAddr = ifcg.getLinkAddress();
636                 if (linkAddr == null || (addr = linkAddr.getAddress()) == null || addr.equals(
637                         NetworkUtils.numericToInetAddress("0.0.0.0")) || addr.equals(
638                         NetworkUtils.numericToInetAddress("::0"))) {
639                     address = BLUETOOTH_IFACE_ADDR_START;
640                     addr = NetworkUtils.numericToInetAddress(address);
641                 }
642 
643                 ifcg.setLinkAddress(new LinkAddress(addr, BLUETOOTH_PREFIX_LENGTH));
644                 if (enable) {
645                     ifcg.setInterfaceUp();
646                 } else {
647                     ifcg.setInterfaceDown();
648                 }
649 
650                 ifcg.clearFlag("running");
651                 service.setInterfaceConfig(iface, ifcg);
652 
653                 if (enable) {
654                     int tetherStatus = cm.tether(iface);
655                     if (tetherStatus != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
656                         Log.e(TAG, "Error tethering " + iface + " tetherStatus: " + tetherStatus);
657                         return null;
658                     }
659                 } else {
660                     int untetherStatus = cm.untether(iface);
661                     Log.i(TAG, "Untethered: " + iface + " untetherStatus: " + untetherStatus);
662                 }
663             }
664         } catch (Exception e) {
665             Log.e(TAG, "Error configuring interface " + iface + ", :" + e);
666             return null;
667         }
668         return address;
669     }
670 
getConnectedPanDevices()671     private List<BluetoothDevice> getConnectedPanDevices() {
672         List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
673 
674         for (BluetoothDevice device : mPanDevices.keySet()) {
675             if (getPanDeviceConnectionState(device) == BluetoothProfile.STATE_CONNECTED) {
676                 devices.add(device);
677             }
678         }
679         return devices;
680     }
681 
getPanDeviceConnectionState(BluetoothDevice device)682     private int getPanDeviceConnectionState(BluetoothDevice device) {
683         BluetoothPanDevice panDevice = mPanDevices.get(device);
684         if (panDevice == null) {
685             return BluetoothProfile.STATE_DISCONNECTED;
686         }
687         return panDevice.mState;
688     }
689 
690     @Override
dump(StringBuilder sb)691     public void dump(StringBuilder sb) {
692         super.dump(sb);
693         println(sb, "mMaxPanDevices: " + mMaxPanDevices);
694         println(sb, "mPanIfName: " + mPanIfName);
695         println(sb, "mTetherOn: " + mTetherOn);
696         println(sb, "mPanDevices:");
697         for (BluetoothDevice device : mPanDevices.keySet()) {
698             println(sb, "  " + device + " : " + mPanDevices.get(device));
699         }
700     }
701 
702     private class BluetoothPanDevice {
703         private int mState;
704         private String mIface;
705         private int mLocalRole; // Which local role is this PAN device bound to
706         private int mRemoteRole; // Which remote role is this PAN device bound to
707 
BluetoothPanDevice(int state, String iface, int localRole, int remoteRole)708         BluetoothPanDevice(int state, String iface, int localRole, int remoteRole) {
709             mState = state;
710             mIface = iface;
711             mLocalRole = localRole;
712             mRemoteRole = remoteRole;
713         }
714     }
715 
716     // Constants matching Hal header file bt_hh.h
717     // bthh_connection_state_t
718     private static final int CONN_STATE_CONNECTED = 0;
719     private static final int CONN_STATE_CONNECTING = 1;
720     private static final int CONN_STATE_DISCONNECTED = 2;
721     private static final int CONN_STATE_DISCONNECTING = 3;
722 
classInitNative()723     private static native void classInitNative();
724 
initializeNative()725     private native void initializeNative();
726 
cleanupNative()727     private native void cleanupNative();
728 
connectPanNative(byte[] btAddress, int localRole, int remoteRole)729     private native boolean connectPanNative(byte[] btAddress, int localRole, int remoteRole);
730 
disconnectPanNative(byte[] btAddress)731     private native boolean disconnectPanNative(byte[] btAddress);
732 
enablePanNative(int localRole)733     private native boolean enablePanNative(int localRole);
734 
getPanLocalRoleNative()735     private native int getPanLocalRoleNative();
736 
737 }
738