Loading framework/java/android/bluetooth/BluetoothAdapter.java +33 −66 Original line number Diff line number Diff line Loading @@ -680,30 +680,7 @@ public final class BluetoothAdapter { } /** * Performs action based on user action to turn BT ON * or OFF if BT is in BLE_ON state */ private void notifyUserAction(boolean enable) { try { mServiceLock.readLock().lock(); if (mService == null) { Log.e(TAG, "mService is null"); return; } if (enable) { mService.onLeServiceUp(); //NA:TODO implementation pending } else { mService.onBrEdrDown(); //NA:TODO implementation pending } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { mServiceLock.readLock().unlock(); } } /** * Turns off Bluetooth LE which was earlier turned on by calling EnableBLE(). * Turns off Bluetooth LE which was earlier turned on by calling enableBLE(). * * <p> If the internal Adapter state is STATE_BLE_ON, this would trigger the transition * to STATE_OFF and completely shut-down Bluetooth Loading Loading @@ -733,61 +710,50 @@ public final class BluetoothAdapter { if (!isBleScanAlwaysAvailable()) return false; int state = getLeState(); if (state == BluetoothAdapter.STATE_ON) { if (DBG) Log.d (TAG, "STATE_ON: shouldn't disable"); try { mManagerService.updateBleAppCount(mToken, false); } catch (RemoteException e) { Log.e(TAG, "", e); } return true; } else if (state == BluetoothAdapter.STATE_BLE_ON) { if (DBG) Log.d (TAG, "STATE_BLE_ON"); int bleAppCnt = 0; if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) { String packageName = ActivityThread.currentPackageName(); if (DBG) Log.d (TAG, "disableBLE(): de-registering " + packageName); try { bleAppCnt = mManagerService.updateBleAppCount(mToken, false); mManagerService.updateBleAppCount(mToken, false, packageName); } catch (RemoteException e) { Log.e(TAG, "", e); } if (bleAppCnt == 0) { // Disable only if there are no other clients notifyUserAction(false); } return true; } if (DBG) Log.d (TAG, "STATE_OFF: Already disabled"); if (DBG) Log.d (TAG, "disableBLE(): Already disabled"); return false; } /** * Special Applications who want to only turn on Bluetooth Low Energy (BLE) would * EnableBLE, EnableBLE brings-up Bluetooth so that application can access * only LE related feature (Bluetooth GATT layers interfaces using the respective class) * EnableBLE in turn registers the existance of a special App which wants to * turn on Bluetooth Low enrgy part without making it visible at the settings UI * as Bluetooth ON. * <p>Invoking EnableBLE when Bluetooth is already in ON state, would just registers * the existance of special Application and doesn't do anything to current BT state. * when user turn OFF Bluetooth from UI, if there is an existance of special app, Bluetooth * would stay in BLE_ON state so that LE features are still acessible to the special * Applications. * Applications who want to only use Bluetooth Low Energy (BLE) can call enableBLE. * * <p>This is an asynchronous call: it will return immediately, and * enableBLE registers the existence of an app using only LE functions. * * enableBLE may enable Bluetooth to an LE only mode so that an app can use * LE related features (BluetoothGatt or BluetoothGattServer classes) * * If the user disables Bluetooth while an app is registered to use LE only features, * Bluetooth will remain on in LE only mode for the app. * * When Bluetooth is in LE only mode, it is not shown as ON to the UI. * * <p>This is an asynchronous call: it returns immediately, and * clients should listen for {@link #ACTION_BLE_STATE_CHANGED} * to be notified of subsequent adapter state changes. If this call returns * true, then the adapter state will immediately transition from {@link * #STATE_OFF} to {@link #STATE_BLE_TURNING_ON}, and some time * later transition to either {@link #STATE_OFF} or {@link * #STATE_BLE_ON}. If this call returns false then there was an * immediate problem that will prevent the adapter from being turned on - * such as Airplane mode, or the adapter is already turned on. * (@link #ACTION_BLE_STATE_CHANGED) returns the Bluetooth Adapter's various * to be notified of adapter state changes. * * If this call returns * true, then the adapter state is either in a mode where * LE is available, or will transition from {@link #STATE_OFF} to {@link #STATE_BLE_TURNING_ON}, * and some time later transition to either {@link #STATE_OFF} or {@link #STATE_BLE_ON}. * * If this call returns false then there was an immediate problem that prevents the * adapter from being turned on - such as Airplane mode. * * {@link #ACTION_BLE_STATE_CHANGED} returns the Bluetooth Adapter's various * states, It includes all the classic Bluetooth Adapter states along with * internal BLE only states * * @return true to indicate Bluetooth LE start-up has begun, or false on * @return true to indicate Bluetooth LE will be available, or false on * immediate error * @hide */ Loading @@ -796,13 +762,14 @@ public final class BluetoothAdapter { if (!isBleScanAlwaysAvailable()) return false; try { mManagerService.updateBleAppCount(mToken, true); String packageName = ActivityThread.currentPackageName(); mManagerService.updateBleAppCount(mToken, true, packageName); if (isLeEnabled()) { if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled"); return true; } if (DBG) Log.d(TAG, "enableBLE(): Calling enable"); return mManagerService.enable(ActivityThread.currentPackageName()); return mManagerService.enable(packageName); } catch (RemoteException e) { Log.e(TAG, "", e); } Loading Loading @@ -2094,7 +2061,7 @@ public final class BluetoothAdapter { return true; } try { return mManagerService.enableNoAutoConnect(); return mManagerService.enableNoAutoConnect(ActivityThread.currentPackageName()); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } Loading framework/java/android/bluetooth/IBluetoothManager.aidl +3 −3 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ interface IBluetoothManager void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback); boolean isEnabled(); boolean enable(String packageName); boolean enableNoAutoConnect(); boolean enableNoAutoConnect(String packageName); boolean disable(String packageName, boolean persist); int getState(); IBluetoothGatt getBluetoothGatt(); Loading @@ -47,6 +47,6 @@ interface IBluetoothManager String getName(); boolean isBleScanAlwaysAvailable(); int updateBleAppCount(IBinder b, boolean enable); int updateBleAppCount(IBinder b, boolean enable, String packageName); boolean isBleAppPresent(); } service/java/com/android/server/bluetooth/BluetoothManagerService.java +125 −49 Original line number Diff line number Diff line Loading @@ -57,14 +57,16 @@ import android.os.UserManagerInternal.UserRestrictionsListener; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.util.Slog; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; class BluetoothManagerService extends IBluetoothManager.Stub { private static final String TAG = "BluetoothManagerService"; private static final boolean DBG = true; Loading Loading @@ -137,16 +139,46 @@ class BluetoothManagerService extends IBluetoothManager.Stub { new ReentrantReadWriteLock(); private boolean mBinding; private boolean mUnbinding; // used inside handler thread private boolean mQuietEnable = false; // configuarion from external IBinder call which is used to private boolean mEnable; /** * Used for tracking apps that enabled / disabled Bluetooth. */ private class ActiveLog { private String mPackageName; private boolean mEnable; private long mTimestamp; public ActiveLog(String packageName, boolean enable, long timestamp) { mPackageName = packageName; mEnable = enable; mTimestamp = timestamp; } public long getTime() { return mTimestamp; } public String toString() { return android.text.format.DateFormat.format("MM-dd hh:mm:ss ", mTimestamp) + (mEnable ? " Enabled " : " Disabled ") + " by " + mPackageName; } } private LinkedList<ActiveLog> mActiveLogs; // configuration from external IBinder call which is used to // synchronize with broadcast receiver. private boolean mQuietEnableExternal; // configuarion from external IBinder call which is used to // synchronize with broadcast receiver. private boolean mEnableExternal; // used inside handler thread private boolean mEnable; // Map of apps registered to keep BLE scanning on. private Map<IBinder, ClientDeathRecipient> mBleApps = new ConcurrentHashMap<IBinder, ClientDeathRecipient>(); private int mState; private final BluetoothHandler mHandler; private int mErrorRecoveryRetryCounter; Loading Loading @@ -251,12 +283,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } else if (st == BluetoothAdapter.STATE_ON){ // disable without persisting the setting Slog.d(TAG, "Calling disable"); sendDisableMsg(); sendDisableMsg("airplane mode"); } } else if (mEnableExternal) { // enable without persisting the setting Slog.d(TAG, "Calling enable"); sendEnableMsg(mQuietEnableExternal); sendEnableMsg(mQuietEnableExternal, "airplane mode"); } } } Loading @@ -272,6 +304,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { || context.getResources().getBoolean( com.android.internal.R.bool.config_permissionReviewRequired); mActiveLogs = new LinkedList<ActiveLog>(); mBluetooth = null; mBluetoothBinder = null; mBluetoothGatt = null; Loading @@ -298,15 +331,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mEnableExternal = true; } int sysUiUid = -1; int systemUiUid = -1; try { sysUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui", systemUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui", PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM); } catch (PackageManager.NameNotFoundException e) { // Some platforms, such as wearables do not have a system ui. Slog.w(TAG, "Unable to resolve SystemUI's UID.", e); } mSystemUiUid = sysUiUid; mSystemUiUid = systemUiUid; } /** Loading Loading @@ -484,8 +517,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } class ClientDeathRecipient implements IBinder.DeathRecipient { private String mPackageName; public ClientDeathRecipient(String packageName) { mPackageName = packageName; } public void binderDied() { if (DBG) Slog.d(TAG, "Binder is dead - unregister Ble App"); if (DBG) Slog.d(TAG, "Binder is dead - unregister " + mPackageName); if (isBleAppPresent()) { // Nothing to do, another app is here. return; Loading @@ -504,10 +543,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mBluetoothLock.readLock().unlock(); } } } /** Internal death rec list */ Map<IBinder, ClientDeathRecipient> mBleApps = new ConcurrentHashMap<IBinder, ClientDeathRecipient>(); public String getPackageName() { return mPackageName; } } @Override public boolean isBleScanAlwaysAvailable() { Loading Loading @@ -565,28 +605,22 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } } public int updateBleAppCount(IBinder token, boolean enable) { if (enable) { public int updateBleAppCount(IBinder token, boolean enable, String packageName) { ClientDeathRecipient r = mBleApps.get(token); if (r == null) { ClientDeathRecipient deathRec = new ClientDeathRecipient(); if (r == null && enable) { ClientDeathRecipient deathRec = new ClientDeathRecipient(packageName); try { token.linkToDeath(deathRec, 0); } catch (RemoteException ex) { throw new IllegalArgumentException("Wake lock is already dead."); throw new IllegalArgumentException("BLE app (" + packageName + ") already dead!"); } mBleApps.put(token, deathRec); if (DBG) Slog.d(TAG, "Registered for death Notification"); } } else { ClientDeathRecipient r = mBleApps.get(token); if (r != null) { if (DBG) Slog.d(TAG, "Registered for death of " + packageName); } else if (!enable && r != null) { // Unregister death recipient as the app goes away. token.unlinkToDeath(r, 0); mBleApps.remove(token); if (DBG) Slog.d(TAG, "Unregistered for death Notification"); } if (DBG) Slog.d(TAG, "Unregistered for death of " + packageName); } int appCount = mBleApps.size(); if (DBG) Slog.d(TAG, appCount + " registered Ble Apps"); Loading Loading @@ -667,7 +701,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } } public boolean enableNoAutoConnect() public boolean enableNoAutoConnect(String packageName) { if (isBluetoothDisallowed()) { if (DBG) { Loading @@ -692,7 +726,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { synchronized(mReceiver) { mQuietEnableExternal = true; mEnableExternal = true; sendEnableMsg(true); sendEnableMsg(true, packageName); } return true; } Loading Loading @@ -724,7 +758,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } if (DBG) { Slog.d(TAG,"enable(): mBluetooth =" + mBluetooth + Slog.d(TAG,"enable(" + packageName + "): mBluetooth =" + mBluetooth + " mBinding = " + mBinding + " mState = " + BluetoothAdapter.nameForState(mState)); } Loading @@ -733,7 +767,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mQuietEnableExternal = false; mEnableExternal = true; // waive WRITE_SECURE_SETTINGS permission check sendEnableMsg(false); sendEnableMsg(false, packageName); } if (DBG) Slog.d(TAG, "enable returning"); return true; Loading Loading @@ -768,7 +802,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { persistBluetoothSetting(BLUETOOTH_OFF); } mEnableExternal = false; sendDisableMsg(); sendDisableMsg(packageName); } return true; } Loading Loading @@ -909,7 +943,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) { if (DBG) Slog.d(TAG, "Auto-enabling Bluetooth."); sendEnableMsg(mQuietEnableExternal); sendEnableMsg(mQuietEnableExternal, "system boot"); } else if (!isNameAndAddressSet()) { if (DBG) Slog.d(TAG, "Getting adapter name and address"); Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); Loading Loading @@ -1877,13 +1911,24 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return false; } private void sendDisableMsg() { private void sendDisableMsg(String packageName) { mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE)); addActiveLog(packageName, false); } private void sendEnableMsg(boolean quietMode) { private void sendEnableMsg(boolean quietMode, String packageName) { mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, 0)); addActiveLog(packageName, true); } private void addActiveLog(String packageName, boolean enable) { synchronized (mActiveLogs) { if (mActiveLogs.size() > 10) { mActiveLogs.remove(); } mActiveLogs.add(new ActiveLog(packageName, enable, System.currentTimeMillis())); } } private void recoverBluetoothServiceFromError(boolean clearBle) { Loading Loading @@ -1954,19 +1999,50 @@ class BluetoothManagerService extends IBluetoothManager.Stub { public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); String errorMsg = null; boolean protoOut = (args.length > 0) && args[0].startsWith("--proto"); if (!protoOut) { writer.println("Bluetooth Status"); writer.println(" enabled: " + isEnabled()); writer.println(" state: " + BluetoothAdapter.nameForState(mState)); writer.println(" address: " + mAddress); writer.println(" name: " + mName); if (mEnable) { long onDuration = System.currentTimeMillis() - mActiveLogs.getLast().getTime(); String onDurationString = String.format("%02d:%02d:%02d.%03d", (int)(onDuration / (1000 * 60 * 60)), (int)((onDuration / (1000 * 60)) % 60), (int)((onDuration / 1000) % 60), (int)(onDuration % 1000)); writer.println(" time since enabled: " + onDurationString + "\n"); } writer.println("Enable log:"); for (ActiveLog log : mActiveLogs) { writer.println(log); } writer.println("\n" + mBleApps.size() + " BLE Apps registered:"); for (ClientDeathRecipient app : mBleApps.values()) { writer.println(app.getPackageName()); } writer.flush(); } if (mBluetoothBinder == null) { errorMsg = "Bluetooth Service not connected"; } else { try { mBluetoothBinder.dump(fd, args); } catch (RemoteException re) { errorMsg = "RemoteException while calling Bluetooth Service"; errorMsg = "RemoteException while dumping Bluetooth Service"; } } if (errorMsg != null) { // Silently return if we are extracting metrics in Protobuf format if ((args.length > 0) && args[0].startsWith("--proto")) return; if (protoOut) return; writer.println(errorMsg); } } Loading Loading
framework/java/android/bluetooth/BluetoothAdapter.java +33 −66 Original line number Diff line number Diff line Loading @@ -680,30 +680,7 @@ public final class BluetoothAdapter { } /** * Performs action based on user action to turn BT ON * or OFF if BT is in BLE_ON state */ private void notifyUserAction(boolean enable) { try { mServiceLock.readLock().lock(); if (mService == null) { Log.e(TAG, "mService is null"); return; } if (enable) { mService.onLeServiceUp(); //NA:TODO implementation pending } else { mService.onBrEdrDown(); //NA:TODO implementation pending } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { mServiceLock.readLock().unlock(); } } /** * Turns off Bluetooth LE which was earlier turned on by calling EnableBLE(). * Turns off Bluetooth LE which was earlier turned on by calling enableBLE(). * * <p> If the internal Adapter state is STATE_BLE_ON, this would trigger the transition * to STATE_OFF and completely shut-down Bluetooth Loading Loading @@ -733,61 +710,50 @@ public final class BluetoothAdapter { if (!isBleScanAlwaysAvailable()) return false; int state = getLeState(); if (state == BluetoothAdapter.STATE_ON) { if (DBG) Log.d (TAG, "STATE_ON: shouldn't disable"); try { mManagerService.updateBleAppCount(mToken, false); } catch (RemoteException e) { Log.e(TAG, "", e); } return true; } else if (state == BluetoothAdapter.STATE_BLE_ON) { if (DBG) Log.d (TAG, "STATE_BLE_ON"); int bleAppCnt = 0; if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) { String packageName = ActivityThread.currentPackageName(); if (DBG) Log.d (TAG, "disableBLE(): de-registering " + packageName); try { bleAppCnt = mManagerService.updateBleAppCount(mToken, false); mManagerService.updateBleAppCount(mToken, false, packageName); } catch (RemoteException e) { Log.e(TAG, "", e); } if (bleAppCnt == 0) { // Disable only if there are no other clients notifyUserAction(false); } return true; } if (DBG) Log.d (TAG, "STATE_OFF: Already disabled"); if (DBG) Log.d (TAG, "disableBLE(): Already disabled"); return false; } /** * Special Applications who want to only turn on Bluetooth Low Energy (BLE) would * EnableBLE, EnableBLE brings-up Bluetooth so that application can access * only LE related feature (Bluetooth GATT layers interfaces using the respective class) * EnableBLE in turn registers the existance of a special App which wants to * turn on Bluetooth Low enrgy part without making it visible at the settings UI * as Bluetooth ON. * <p>Invoking EnableBLE when Bluetooth is already in ON state, would just registers * the existance of special Application and doesn't do anything to current BT state. * when user turn OFF Bluetooth from UI, if there is an existance of special app, Bluetooth * would stay in BLE_ON state so that LE features are still acessible to the special * Applications. * Applications who want to only use Bluetooth Low Energy (BLE) can call enableBLE. * * <p>This is an asynchronous call: it will return immediately, and * enableBLE registers the existence of an app using only LE functions. * * enableBLE may enable Bluetooth to an LE only mode so that an app can use * LE related features (BluetoothGatt or BluetoothGattServer classes) * * If the user disables Bluetooth while an app is registered to use LE only features, * Bluetooth will remain on in LE only mode for the app. * * When Bluetooth is in LE only mode, it is not shown as ON to the UI. * * <p>This is an asynchronous call: it returns immediately, and * clients should listen for {@link #ACTION_BLE_STATE_CHANGED} * to be notified of subsequent adapter state changes. If this call returns * true, then the adapter state will immediately transition from {@link * #STATE_OFF} to {@link #STATE_BLE_TURNING_ON}, and some time * later transition to either {@link #STATE_OFF} or {@link * #STATE_BLE_ON}. If this call returns false then there was an * immediate problem that will prevent the adapter from being turned on - * such as Airplane mode, or the adapter is already turned on. * (@link #ACTION_BLE_STATE_CHANGED) returns the Bluetooth Adapter's various * to be notified of adapter state changes. * * If this call returns * true, then the adapter state is either in a mode where * LE is available, or will transition from {@link #STATE_OFF} to {@link #STATE_BLE_TURNING_ON}, * and some time later transition to either {@link #STATE_OFF} or {@link #STATE_BLE_ON}. * * If this call returns false then there was an immediate problem that prevents the * adapter from being turned on - such as Airplane mode. * * {@link #ACTION_BLE_STATE_CHANGED} returns the Bluetooth Adapter's various * states, It includes all the classic Bluetooth Adapter states along with * internal BLE only states * * @return true to indicate Bluetooth LE start-up has begun, or false on * @return true to indicate Bluetooth LE will be available, or false on * immediate error * @hide */ Loading @@ -796,13 +762,14 @@ public final class BluetoothAdapter { if (!isBleScanAlwaysAvailable()) return false; try { mManagerService.updateBleAppCount(mToken, true); String packageName = ActivityThread.currentPackageName(); mManagerService.updateBleAppCount(mToken, true, packageName); if (isLeEnabled()) { if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled"); return true; } if (DBG) Log.d(TAG, "enableBLE(): Calling enable"); return mManagerService.enable(ActivityThread.currentPackageName()); return mManagerService.enable(packageName); } catch (RemoteException e) { Log.e(TAG, "", e); } Loading Loading @@ -2094,7 +2061,7 @@ public final class BluetoothAdapter { return true; } try { return mManagerService.enableNoAutoConnect(); return mManagerService.enableNoAutoConnect(ActivityThread.currentPackageName()); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } Loading
framework/java/android/bluetooth/IBluetoothManager.aidl +3 −3 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ interface IBluetoothManager void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback); boolean isEnabled(); boolean enable(String packageName); boolean enableNoAutoConnect(); boolean enableNoAutoConnect(String packageName); boolean disable(String packageName, boolean persist); int getState(); IBluetoothGatt getBluetoothGatt(); Loading @@ -47,6 +47,6 @@ interface IBluetoothManager String getName(); boolean isBleScanAlwaysAvailable(); int updateBleAppCount(IBinder b, boolean enable); int updateBleAppCount(IBinder b, boolean enable, String packageName); boolean isBleAppPresent(); }
service/java/com/android/server/bluetooth/BluetoothManagerService.java +125 −49 Original line number Diff line number Diff line Loading @@ -57,14 +57,16 @@ import android.os.UserManagerInternal.UserRestrictionsListener; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.util.Slog; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; class BluetoothManagerService extends IBluetoothManager.Stub { private static final String TAG = "BluetoothManagerService"; private static final boolean DBG = true; Loading Loading @@ -137,16 +139,46 @@ class BluetoothManagerService extends IBluetoothManager.Stub { new ReentrantReadWriteLock(); private boolean mBinding; private boolean mUnbinding; // used inside handler thread private boolean mQuietEnable = false; // configuarion from external IBinder call which is used to private boolean mEnable; /** * Used for tracking apps that enabled / disabled Bluetooth. */ private class ActiveLog { private String mPackageName; private boolean mEnable; private long mTimestamp; public ActiveLog(String packageName, boolean enable, long timestamp) { mPackageName = packageName; mEnable = enable; mTimestamp = timestamp; } public long getTime() { return mTimestamp; } public String toString() { return android.text.format.DateFormat.format("MM-dd hh:mm:ss ", mTimestamp) + (mEnable ? " Enabled " : " Disabled ") + " by " + mPackageName; } } private LinkedList<ActiveLog> mActiveLogs; // configuration from external IBinder call which is used to // synchronize with broadcast receiver. private boolean mQuietEnableExternal; // configuarion from external IBinder call which is used to // synchronize with broadcast receiver. private boolean mEnableExternal; // used inside handler thread private boolean mEnable; // Map of apps registered to keep BLE scanning on. private Map<IBinder, ClientDeathRecipient> mBleApps = new ConcurrentHashMap<IBinder, ClientDeathRecipient>(); private int mState; private final BluetoothHandler mHandler; private int mErrorRecoveryRetryCounter; Loading Loading @@ -251,12 +283,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } else if (st == BluetoothAdapter.STATE_ON){ // disable without persisting the setting Slog.d(TAG, "Calling disable"); sendDisableMsg(); sendDisableMsg("airplane mode"); } } else if (mEnableExternal) { // enable without persisting the setting Slog.d(TAG, "Calling enable"); sendEnableMsg(mQuietEnableExternal); sendEnableMsg(mQuietEnableExternal, "airplane mode"); } } } Loading @@ -272,6 +304,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { || context.getResources().getBoolean( com.android.internal.R.bool.config_permissionReviewRequired); mActiveLogs = new LinkedList<ActiveLog>(); mBluetooth = null; mBluetoothBinder = null; mBluetoothGatt = null; Loading @@ -298,15 +331,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mEnableExternal = true; } int sysUiUid = -1; int systemUiUid = -1; try { sysUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui", systemUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui", PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM); } catch (PackageManager.NameNotFoundException e) { // Some platforms, such as wearables do not have a system ui. Slog.w(TAG, "Unable to resolve SystemUI's UID.", e); } mSystemUiUid = sysUiUid; mSystemUiUid = systemUiUid; } /** Loading Loading @@ -484,8 +517,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } class ClientDeathRecipient implements IBinder.DeathRecipient { private String mPackageName; public ClientDeathRecipient(String packageName) { mPackageName = packageName; } public void binderDied() { if (DBG) Slog.d(TAG, "Binder is dead - unregister Ble App"); if (DBG) Slog.d(TAG, "Binder is dead - unregister " + mPackageName); if (isBleAppPresent()) { // Nothing to do, another app is here. return; Loading @@ -504,10 +543,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mBluetoothLock.readLock().unlock(); } } } /** Internal death rec list */ Map<IBinder, ClientDeathRecipient> mBleApps = new ConcurrentHashMap<IBinder, ClientDeathRecipient>(); public String getPackageName() { return mPackageName; } } @Override public boolean isBleScanAlwaysAvailable() { Loading Loading @@ -565,28 +605,22 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } } public int updateBleAppCount(IBinder token, boolean enable) { if (enable) { public int updateBleAppCount(IBinder token, boolean enable, String packageName) { ClientDeathRecipient r = mBleApps.get(token); if (r == null) { ClientDeathRecipient deathRec = new ClientDeathRecipient(); if (r == null && enable) { ClientDeathRecipient deathRec = new ClientDeathRecipient(packageName); try { token.linkToDeath(deathRec, 0); } catch (RemoteException ex) { throw new IllegalArgumentException("Wake lock is already dead."); throw new IllegalArgumentException("BLE app (" + packageName + ") already dead!"); } mBleApps.put(token, deathRec); if (DBG) Slog.d(TAG, "Registered for death Notification"); } } else { ClientDeathRecipient r = mBleApps.get(token); if (r != null) { if (DBG) Slog.d(TAG, "Registered for death of " + packageName); } else if (!enable && r != null) { // Unregister death recipient as the app goes away. token.unlinkToDeath(r, 0); mBleApps.remove(token); if (DBG) Slog.d(TAG, "Unregistered for death Notification"); } if (DBG) Slog.d(TAG, "Unregistered for death of " + packageName); } int appCount = mBleApps.size(); if (DBG) Slog.d(TAG, appCount + " registered Ble Apps"); Loading Loading @@ -667,7 +701,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } } public boolean enableNoAutoConnect() public boolean enableNoAutoConnect(String packageName) { if (isBluetoothDisallowed()) { if (DBG) { Loading @@ -692,7 +726,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { synchronized(mReceiver) { mQuietEnableExternal = true; mEnableExternal = true; sendEnableMsg(true); sendEnableMsg(true, packageName); } return true; } Loading Loading @@ -724,7 +758,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } if (DBG) { Slog.d(TAG,"enable(): mBluetooth =" + mBluetooth + Slog.d(TAG,"enable(" + packageName + "): mBluetooth =" + mBluetooth + " mBinding = " + mBinding + " mState = " + BluetoothAdapter.nameForState(mState)); } Loading @@ -733,7 +767,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mQuietEnableExternal = false; mEnableExternal = true; // waive WRITE_SECURE_SETTINGS permission check sendEnableMsg(false); sendEnableMsg(false, packageName); } if (DBG) Slog.d(TAG, "enable returning"); return true; Loading Loading @@ -768,7 +802,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { persistBluetoothSetting(BLUETOOTH_OFF); } mEnableExternal = false; sendDisableMsg(); sendDisableMsg(packageName); } return true; } Loading Loading @@ -909,7 +943,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) { if (DBG) Slog.d(TAG, "Auto-enabling Bluetooth."); sendEnableMsg(mQuietEnableExternal); sendEnableMsg(mQuietEnableExternal, "system boot"); } else if (!isNameAndAddressSet()) { if (DBG) Slog.d(TAG, "Getting adapter name and address"); Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); Loading Loading @@ -1877,13 +1911,24 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return false; } private void sendDisableMsg() { private void sendDisableMsg(String packageName) { mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE)); addActiveLog(packageName, false); } private void sendEnableMsg(boolean quietMode) { private void sendEnableMsg(boolean quietMode, String packageName) { mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, 0)); addActiveLog(packageName, true); } private void addActiveLog(String packageName, boolean enable) { synchronized (mActiveLogs) { if (mActiveLogs.size() > 10) { mActiveLogs.remove(); } mActiveLogs.add(new ActiveLog(packageName, enable, System.currentTimeMillis())); } } private void recoverBluetoothServiceFromError(boolean clearBle) { Loading Loading @@ -1954,19 +1999,50 @@ class BluetoothManagerService extends IBluetoothManager.Stub { public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); String errorMsg = null; boolean protoOut = (args.length > 0) && args[0].startsWith("--proto"); if (!protoOut) { writer.println("Bluetooth Status"); writer.println(" enabled: " + isEnabled()); writer.println(" state: " + BluetoothAdapter.nameForState(mState)); writer.println(" address: " + mAddress); writer.println(" name: " + mName); if (mEnable) { long onDuration = System.currentTimeMillis() - mActiveLogs.getLast().getTime(); String onDurationString = String.format("%02d:%02d:%02d.%03d", (int)(onDuration / (1000 * 60 * 60)), (int)((onDuration / (1000 * 60)) % 60), (int)((onDuration / 1000) % 60), (int)(onDuration % 1000)); writer.println(" time since enabled: " + onDurationString + "\n"); } writer.println("Enable log:"); for (ActiveLog log : mActiveLogs) { writer.println(log); } writer.println("\n" + mBleApps.size() + " BLE Apps registered:"); for (ClientDeathRecipient app : mBleApps.values()) { writer.println(app.getPackageName()); } writer.flush(); } if (mBluetoothBinder == null) { errorMsg = "Bluetooth Service not connected"; } else { try { mBluetoothBinder.dump(fd, args); } catch (RemoteException re) { errorMsg = "RemoteException while calling Bluetooth Service"; errorMsg = "RemoteException while dumping Bluetooth Service"; } } if (errorMsg != null) { // Silently return if we are extracting metrics in Protobuf format if ((args.length > 0) && args[0].startsWith("--proto")) return; if (protoOut) return; writer.println(errorMsg); } } Loading