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