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