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