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