Migrating frameworks/base BT files
Bug: 206121418
Test: Compile
Change-Id: Idb55371e9d678296fe46e5f4231ec2d12ec8b978
diff --git a/services/Android.bp b/services/Android.bp
index 74d7f65..f33c8c0 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -77,6 +77,7 @@
":services.appwidget-sources",
":services.autofill-sources",
":services.backup-sources",
+ ":services.bluetooth-sources", // TODO(b/214988855) : Remove once apex/service-bluetooth jar is ready
":backuplib-sources",
":services.companion-sources",
":services.contentcapture-sources",
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 95ec9e9..094ed37 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -103,6 +103,7 @@
":android.hardware.biometrics.face-V2-java-source",
":statslog-art-java-gen",
":statslog-contexthub-java-gen",
+ ":services.bluetooth-sources", // TODO(b/214988855) : Remove once apex is ready
":services.core-sources",
":services.core.protologsrc",
":dumpstate_aidl",
diff --git a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
deleted file mode 100644
index 380b1f3..0000000
--- a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.annotation.RequiresPermission;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * The BluetoothAirplaneModeListener handles system airplane mode change callback and checks
- * whether we need to inform BluetoothManagerService on this change.
- *
- * The information of airplane mode turns on would not be passed to the BluetoothManagerService
- * when Bluetooth is on and Bluetooth is in one of the following situations:
- * 1. Bluetooth A2DP is connected.
- * 2. Bluetooth Hearing Aid profile is connected.
- * 3. Bluetooth LE Audio is connected
- */
-class BluetoothAirplaneModeListener {
- private static final String TAG = "BluetoothAirplaneModeListener";
- @VisibleForTesting static final String TOAST_COUNT = "bluetooth_airplane_toast_count";
-
- private static final int MSG_AIRPLANE_MODE_CHANGED = 0;
-
- @VisibleForTesting static final int MAX_TOAST_COUNT = 10; // 10 times
-
- private final BluetoothManagerService mBluetoothManager;
- private final BluetoothAirplaneModeHandler mHandler;
- private BluetoothModeChangeHelper mAirplaneHelper;
-
- @VisibleForTesting int mToastCount = 0;
-
- BluetoothAirplaneModeListener(BluetoothManagerService service, Looper looper, Context context) {
- mBluetoothManager = service;
-
- mHandler = new BluetoothAirplaneModeHandler(looper);
- context.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
- mAirplaneModeObserver);
- }
-
- private final ContentObserver mAirplaneModeObserver = new ContentObserver(null) {
- @Override
- public void onChange(boolean unused) {
- // Post from system main thread to android_io thread.
- Message msg = mHandler.obtainMessage(MSG_AIRPLANE_MODE_CHANGED);
- mHandler.sendMessage(msg);
- }
- };
-
- private class BluetoothAirplaneModeHandler extends Handler {
- BluetoothAirplaneModeHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_AIRPLANE_MODE_CHANGED:
- handleAirplaneModeChange();
- break;
- default:
- Log.e(TAG, "Invalid message: " + msg.what);
- break;
- }
- }
- }
-
- /**
- * Call after boot complete
- */
- @VisibleForTesting
- void start(BluetoothModeChangeHelper helper) {
- Log.i(TAG, "start");
- mAirplaneHelper = helper;
- mToastCount = mAirplaneHelper.getSettingsInt(TOAST_COUNT);
- }
-
- @VisibleForTesting
- boolean shouldPopToast() {
- if (mToastCount >= MAX_TOAST_COUNT) {
- return false;
- }
- mToastCount++;
- mAirplaneHelper.setSettingsInt(TOAST_COUNT, mToastCount);
- return true;
- }
-
- @VisibleForTesting
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- void handleAirplaneModeChange() {
- if (shouldSkipAirplaneModeChange()) {
- Log.i(TAG, "Ignore airplane mode change");
- // Airplane mode enabled when Bluetooth is being used for audio/headering aid.
- // Bluetooth is not disabled in such case, only state is changed to
- // BLUETOOTH_ON_AIRPLANE mode.
- mAirplaneHelper.setSettingsInt(Settings.Global.BLUETOOTH_ON,
- BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
- if (shouldPopToast()) {
- mAirplaneHelper.showToastMessage();
- }
- return;
- }
- if (mAirplaneHelper != null) {
- mAirplaneHelper.onAirplaneModeChanged(mBluetoothManager);
- }
- }
-
- @VisibleForTesting
- boolean shouldSkipAirplaneModeChange() {
- if (mAirplaneHelper == null) {
- return false;
- }
- if (!mAirplaneHelper.isBluetoothOn() || !mAirplaneHelper.isAirplaneModeOn()
- || !mAirplaneHelper.isMediaProfileConnected()) {
- return false;
- }
- return true;
- }
-}
diff --git a/services/core/java/com/android/server/BluetoothDeviceConfigListener.java b/services/core/java/com/android/server/BluetoothDeviceConfigListener.java
deleted file mode 100644
index 611a37d..0000000
--- a/services/core/java/com/android/server/BluetoothDeviceConfigListener.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.provider.DeviceConfig;
-import android.util.Slog;
-
-import java.util.ArrayList;
-
-/**
- * The BluetoothDeviceConfigListener handles system device config change callback and checks
- * whether we need to inform BluetoothManagerService on this change.
- *
- * The information of device config change would not be passed to the BluetoothManagerService
- * when Bluetooth is on and Bluetooth is in one of the following situations:
- * 1. Bluetooth A2DP is connected.
- * 2. Bluetooth Hearing Aid profile is connected.
- */
-class BluetoothDeviceConfigListener {
- private static final String TAG = "BluetoothDeviceConfigListener";
-
- private final BluetoothManagerService mService;
- private final boolean mLogDebug;
-
- BluetoothDeviceConfigListener(BluetoothManagerService service, boolean logDebug) {
- mService = service;
- mLogDebug = logDebug;
- DeviceConfig.addOnPropertiesChangedListener(
- DeviceConfig.NAMESPACE_BLUETOOTH,
- (Runnable r) -> r.run(),
- mDeviceConfigChangedListener);
- }
-
- private final DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener =
- new DeviceConfig.OnPropertiesChangedListener() {
- @Override
- public void onPropertiesChanged(DeviceConfig.Properties properties) {
- if (!properties.getNamespace().equals(DeviceConfig.NAMESPACE_BLUETOOTH)) {
- return;
- }
- if (mLogDebug) {
- ArrayList<String> flags = new ArrayList<>();
- for (String name : properties.getKeyset()) {
- flags.add(name + "='" + properties.getString(name, "") + "'");
- }
- Slog.d(TAG, "onPropertiesChanged: " + String.join(",", flags));
- }
- boolean foundInit = false;
- for (String name : properties.getKeyset()) {
- if (name.startsWith("INIT_")) {
- foundInit = true;
- break;
- }
- }
- if (!foundInit) {
- return;
- }
- mService.onInitFlagsChanged();
- }
- };
-
-}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
deleted file mode 100644
index 262933d..0000000
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ /dev/null
@@ -1,2962 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.Manifest.permission.BLUETOOTH_CONNECT;
-import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
-import static android.os.UserHandle.USER_SYSTEM;
-import static android.permission.PermissionCheckerManager.PERMISSION_HARD_DENIED;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
-import android.app.ActivityManager;
-import android.app.AppGlobals;
-import android.app.AppOpsManager;
-import android.app.BroadcastOptions;
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothHearingAid;
-import android.bluetooth.BluetoothLeAudio;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothProtoEnums;
-import android.bluetooth.IBluetooth;
-import android.bluetooth.IBluetoothCallback;
-import android.bluetooth.IBluetoothGatt;
-import android.bluetooth.IBluetoothHeadset;
-import android.bluetooth.IBluetoothManager;
-import android.bluetooth.IBluetoothManagerCallback;
-import android.bluetooth.IBluetoothProfileServiceConnection;
-import android.bluetooth.IBluetoothStateChangeCallback;
-import android.bluetooth.IBluetoothLeCallControl;
-import android.content.ActivityNotFoundException;
-import android.content.AttributionSource;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.UserInfo;
-import android.database.ContentObserver;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerExemptionManager;
-import android.os.Process;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.permission.PermissionManager;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.text.TextUtils;
-import android.util.FeatureFlagUtils;
-import android.util.Log;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FrameworkStatsLog;
-import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
-import com.android.server.pm.UserRestrictionsUtils;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Locale;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-class BluetoothManagerService extends IBluetoothManager.Stub {
- private static final String TAG = "BluetoothManagerService";
- private static final boolean DBG = true;
-
- private static final String BLUETOOTH_PRIVILEGED =
- android.Manifest.permission.BLUETOOTH_PRIVILEGED;
-
- private static final int ACTIVE_LOG_MAX_SIZE = 20;
- private static final int CRASH_LOG_MAX_SIZE = 100;
-
- private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
- //Maximum msec to wait for service restart
- private static final int SERVICE_RESTART_TIME_MS = 400;
- //Maximum msec to wait for restart due to error
- private static final int ERROR_RESTART_TIME_MS = 3000;
- //Maximum msec to delay MESSAGE_USER_SWITCHED
- private static final int USER_SWITCHED_TIME_MS = 200;
- // Delay for the addProxy function in msec
- private static final int ADD_PROXY_DELAY_MS = 100;
- // Delay for retrying enable and disable in msec
- private static final int ENABLE_DISABLE_DELAY_MS = 300;
- private static final int DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS = 300;
- private static final int DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS = 86400;
-
- private static final int MESSAGE_ENABLE = 1;
- private static final int MESSAGE_DISABLE = 2;
- private static final int MESSAGE_HANDLE_ENABLE_DELAYED = 3;
- private static final int MESSAGE_HANDLE_DISABLE_DELAYED = 4;
- private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
- private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
- private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
- private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
- private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
- private static final int MESSAGE_BLUETOOTH_STATE_CHANGE = 60;
- private static final int MESSAGE_TIMEOUT_BIND = 100;
- private static final int MESSAGE_TIMEOUT_UNBIND = 101;
- private static final int MESSAGE_GET_NAME_AND_ADDRESS = 200;
- private static final int MESSAGE_USER_SWITCHED = 300;
- private static final int MESSAGE_USER_UNLOCKED = 301;
- private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
- private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
- private static final int MESSAGE_RESTORE_USER_SETTING = 500;
- private static final int MESSAGE_INIT_FLAGS_CHANGED = 600;
-
- private static final int RESTORE_SETTING_TO_ON = 1;
- private static final int RESTORE_SETTING_TO_OFF = 0;
-
- private static final int MAX_ERROR_RESTART_RETRIES = 6;
- private static final int MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES = 10;
-
- // Bluetooth persisted setting is off
- private static final int BLUETOOTH_OFF = 0;
- // Bluetooth persisted setting is on
- // and Airplane mode won't affect Bluetooth state at start up
- private static final int BLUETOOTH_ON_BLUETOOTH = 1;
- // Bluetooth persisted setting is on
- // but Airplane mode will affect Bluetooth state at start up
- // and Airplane mode will have higher priority.
- @VisibleForTesting
- static final int BLUETOOTH_ON_AIRPLANE = 2;
-
- private static final int SERVICE_IBLUETOOTH = 1;
- private static final int SERVICE_IBLUETOOTHGATT = 2;
-
- private final Context mContext;
-
- // Locks are not provided for mName and mAddress.
- // They are accessed in handler or broadcast receiver, same thread context.
- private String mAddress;
- private String mName;
- private final ContentResolver mContentResolver;
- private final int mUserId;
- private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
- private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
- private IBinder mBluetoothBinder;
- private IBluetooth mBluetooth;
- private IBluetoothGatt mBluetoothGatt;
- private final ReentrantReadWriteLock mBluetoothLock = new ReentrantReadWriteLock();
- private boolean mBinding;
- private boolean mUnbinding;
-
- private BluetoothModeChangeHelper mBluetoothModeChangeHelper;
-
- private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener;
-
- private BluetoothDeviceConfigListener mBluetoothDeviceConfigListener;
-
- // used inside handler thread
- private boolean mQuietEnable = false;
- private boolean mEnable;
-
- private static CharSequence timeToLog(long timestamp) {
- return android.text.format.DateFormat.format("MM-dd HH:mm:ss", timestamp);
- }
-
- /**
- * Used for tracking apps that enabled / disabled Bluetooth.
- */
- private class ActiveLog {
- private int mReason;
- private String mPackageName;
- private boolean mEnable;
- private long mTimestamp;
-
- ActiveLog(int reason, String packageName, boolean enable, long timestamp) {
- mReason = reason;
- mPackageName = packageName;
- mEnable = enable;
- mTimestamp = timestamp;
- }
-
- public String toString() {
- return timeToLog(mTimestamp) + (mEnable ? " Enabled " : " Disabled ")
- + " due to " + getEnableDisableReasonString(mReason) + " by " + mPackageName;
- }
-
- void dump(ProtoOutputStream proto) {
- proto.write(BluetoothManagerServiceDumpProto.ActiveLog.TIMESTAMP_MS, mTimestamp);
- proto.write(BluetoothManagerServiceDumpProto.ActiveLog.ENABLE, mEnable);
- proto.write(BluetoothManagerServiceDumpProto.ActiveLog.PACKAGE_NAME, mPackageName);
- proto.write(BluetoothManagerServiceDumpProto.ActiveLog.REASON, mReason);
- }
- }
-
- private final LinkedList<ActiveLog> mActiveLogs = new LinkedList<>();
- private final LinkedList<Long> mCrashTimestamps = new LinkedList<>();
- private int mCrashes;
- private long mLastEnabledTime;
-
- // configuration from external IBinder call which is used to
- // synchronize with broadcast receiver.
- private boolean mQuietEnableExternal;
- private boolean mEnableExternal;
-
- // 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;
- private final int mSystemUiUid;
-
- private boolean mIsHearingAidProfileSupported;
-
- private AppOpsManager mAppOps;
-
- // Save a ProfileServiceConnections object for each of the bound
- // bluetooth profile services
- private final Map<Integer, ProfileServiceConnections> mProfileServices = new HashMap<>();
-
- private final boolean mWirelessConsentRequired;
-
- private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
- @Override
- public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
- Message msg =
- mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE, prevState, newState);
- mHandler.sendMessage(msg);
- }
- };
-
- private final UserRestrictionsListener mUserRestrictionsListener =
- new UserRestrictionsListener() {
- @Override
- public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
- Bundle prevRestrictions) {
-
- if (UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions,
- UserManager.DISALLOW_BLUETOOTH_SHARING)) {
- updateOppLauncherComponentState(userId,
- newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING));
- }
-
- // DISALLOW_BLUETOOTH can only be set by DO or PO on the system user.
- if (userId == USER_SYSTEM
- && UserRestrictionsUtils.restrictionsChanged(prevRestrictions,
- newRestrictions, UserManager.DISALLOW_BLUETOOTH)) {
- if (userId == USER_SYSTEM && newRestrictions.getBoolean(
- UserManager.DISALLOW_BLUETOOTH)) {
- updateOppLauncherComponentState(userId, true); // Sharing disallowed
- sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED,
- mContext.getPackageName());
- } else {
- updateOppLauncherComponentState(userId, newRestrictions.getBoolean(
- UserManager.DISALLOW_BLUETOOTH_SHARING));
- }
- }
- }
- };
-
- @VisibleForTesting
- public void onInitFlagsChanged() {
- mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED);
- mHandler.sendEmptyMessageDelayed(
- MESSAGE_INIT_FLAGS_CHANGED,
- DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS);
- }
-
- public boolean onFactoryReset(AttributionSource attributionSource) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
- "Need BLUETOOTH_PRIVILEGED permission");
-
- // Wait for stable state if bluetooth is temporary state.
- int state = getState();
- if (state == BluetoothAdapter.STATE_BLE_TURNING_ON
- || state == BluetoothAdapter.STATE_TURNING_ON
- || state == BluetoothAdapter.STATE_TURNING_OFF) {
- if (!waitForState(Set.of(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_ON))) {
- return false;
- }
- }
-
- // Clear registered LE apps to force shut-off Bluetooth
- clearBleApps();
- state = getState();
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth == null) {
- return false;
- }
- if (state == BluetoothAdapter.STATE_BLE_ON) {
- addActiveLog(
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET,
- mContext.getPackageName(), false);
- mBluetooth.onBrEdrDown(attributionSource);
- return true;
- } else if (state == BluetoothAdapter.STATE_ON) {
- addActiveLog(
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET,
- mContext.getPackageName(), false);
- mBluetooth.disable(attributionSource);
- return true;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to shutdown Bluetooth", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- return false;
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void onAirplaneModeChanged() {
- synchronized (this) {
- if (isBluetoothPersistedStateOn()) {
- if (isAirplaneModeOn()) {
- persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
- } else {
- persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
- }
- }
-
- int st = BluetoothAdapter.STATE_OFF;
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- st = mBluetooth.getState();
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call getState", e);
- return;
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- Slog.d(TAG,
- "Airplane Mode change - current state: " + BluetoothAdapter.nameForState(
- st) + ", isAirplaneModeOn()=" + isAirplaneModeOn());
-
- if (isAirplaneModeOn()) {
- // Clear registered LE apps to force shut-off
- clearBleApps();
-
- // If state is BLE_ON make sure we trigger disableBLE
- if (st == BluetoothAdapter.STATE_BLE_ON) {
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- addActiveLog(
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
- mContext.getPackageName(), false);
- mBluetooth.onBrEdrDown(mContext.getAttributionSource());
- mEnable = false;
- mEnableExternal = false;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call onBrEdrDown", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- } else if (st == BluetoothAdapter.STATE_ON) {
- sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
- mContext.getPackageName());
- }
- } else if (mEnableExternal) {
- sendEnableMsg(mQuietEnableExternal,
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
- mContext.getPackageName());
- }
- }
- }
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
- String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
- if (DBG) {
- Slog.d(TAG, "Bluetooth Adapter name changed to " + newName + " by "
- + mContext.getPackageName());
- }
- if (newName != null) {
- storeNameAndAddress(newName, null);
- }
- } else if (BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED.equals(action)) {
- String newAddress = intent.getStringExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS);
- if (newAddress != null) {
- if (DBG) {
- Slog.d(TAG, "Bluetooth Adapter address changed to " + newAddress);
- }
- storeNameAndAddress(null, newAddress);
- } else {
- if (DBG) {
- Slog.e(TAG, "No Bluetooth Adapter address parameter found");
- }
- }
- } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
- final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
- if (Settings.Global.BLUETOOTH_ON.equals(name)) {
- // The Bluetooth On state may be changed during system restore.
- final String prevValue =
- intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
- final String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
-
- if (DBG) {
- Slog.d(TAG,
- "ACTION_SETTING_RESTORED with BLUETOOTH_ON, prevValue=" + prevValue
- + ", newValue=" + newValue);
- }
-
- if ((newValue != null) && (prevValue != null) && !prevValue.equals(newValue)) {
- Message msg = mHandler.obtainMessage(MESSAGE_RESTORE_USER_SETTING,
- newValue.equals("0") ? RESTORE_SETTING_TO_OFF
- : RESTORE_SETTING_TO_ON, 0);
- mHandler.sendMessage(msg);
- }
- }
- } else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action)
- || BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(action)
- || BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED.equals(action)) {
- final int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
- BluetoothProfile.STATE_CONNECTED);
- if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED)
- && state == BluetoothProfile.STATE_DISCONNECTED
- && !mBluetoothModeChangeHelper.isMediaProfileConnected()) {
- Slog.i(TAG, "Device disconnected, reactivating pending flag changes");
- onInitFlagsChanged();
- }
- }
- }
- };
-
- BluetoothManagerService(Context context) {
- mHandler = new BluetoothHandler(IoThread.get().getLooper());
-
- mContext = context;
-
- mWirelessConsentRequired = context.getResources()
- .getBoolean(com.android.internal.R.bool.config_wirelessConsentRequired);
-
- mCrashes = 0;
- mBluetooth = null;
- mBluetoothBinder = null;
- mBluetoothGatt = null;
- mBinding = false;
- mUnbinding = false;
- mEnable = false;
- mState = BluetoothAdapter.STATE_OFF;
- mQuietEnableExternal = false;
- mEnableExternal = false;
- mAddress = null;
- mName = null;
- mErrorRecoveryRetryCounter = 0;
- mContentResolver = context.getContentResolver();
- mUserId = mContentResolver.getUserId();
- // Observe BLE scan only mode settings change.
- registerForBleScanModeChange();
- mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
- mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
-
- mIsHearingAidProfileSupported = context.getResources()
- .getBoolean(com.android.internal.R.bool.config_hearing_aid_profile_supported);
-
- // TODO: We need a more generic way to initialize the persist keys of FeatureFlagUtils
- String value = SystemProperties.get(FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.HEARING_AID_SETTINGS);
- if (!TextUtils.isEmpty(value)) {
- boolean isHearingAidEnabled = Boolean.parseBoolean(value);
- Log.v(TAG, "set feature flag HEARING_AID_SETTINGS to " + isHearingAidEnabled);
- FeatureFlagUtils.setEnabled(context, FeatureFlagUtils.HEARING_AID_SETTINGS, isHearingAidEnabled);
- if (isHearingAidEnabled && !mIsHearingAidProfileSupported) {
- // Overwrite to enable support by FeatureFlag
- mIsHearingAidProfileSupported = true;
- }
- }
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
- filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
- filter.addAction(Intent.ACTION_SETTING_RESTORED);
- filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
- filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- mContext.registerReceiver(mReceiver, filter);
-
- loadStoredNameAndAddress();
- if (isBluetoothPersistedStateOn()) {
- if (DBG) {
- Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");
- }
- mEnableExternal = true;
- }
-
- String airplaneModeRadios =
- Settings.Global.getString(mContentResolver, Settings.Global.AIRPLANE_MODE_RADIOS);
- if (airplaneModeRadios == null || airplaneModeRadios.contains(
- Settings.Global.RADIO_BLUETOOTH)) {
- mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener(
- this, IoThread.get().getLooper(), context);
- }
-
- int systemUiUid = -1;
- // Check if device is configured with no home screen, which implies no SystemUI.
- boolean noHome = mContext.getResources().getBoolean(R.bool.config_noHomeScreen);
- if (!noHome) {
- PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
- systemUiUid = pm.getPackageUid(pm.getSystemUiServiceComponent().getPackageName(),
- MATCH_SYSTEM_ONLY, USER_SYSTEM);
- }
- if (systemUiUid >= 0) {
- Slog.d(TAG, "Detected SystemUiUid: " + Integer.toString(systemUiUid));
- } else {
- // Some platforms, such as wearables do not have a system ui.
- Slog.w(TAG, "Unable to resolve SystemUI's UID.");
- }
- mSystemUiUid = systemUiUid;
- }
-
- /**
- * Returns true if airplane mode is currently on
- */
- private boolean isAirplaneModeOn() {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
- }
-
- private boolean supportBluetoothPersistedState() {
- return mContext.getResources().getBoolean(R.bool.config_supportBluetoothPersistedState);
- }
-
- /**
- * Returns true if the Bluetooth saved state is "on"
- */
- private boolean isBluetoothPersistedStateOn() {
- if (!supportBluetoothPersistedState()) {
- return false;
- }
- int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1);
- if (DBG) {
- Slog.d(TAG, "Bluetooth persisted state: " + state);
- }
- return state != BLUETOOTH_OFF;
- }
-
- private boolean isBluetoothPersistedStateOnAirplane() {
- if (!supportBluetoothPersistedState()) {
- return false;
- }
- int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1);
- if (DBG) {
- Slog.d(TAG, "Bluetooth persisted state: " + state);
- }
- return state == BLUETOOTH_ON_AIRPLANE;
- }
-
- /**
- * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
- */
- private boolean isBluetoothPersistedStateOnBluetooth() {
- if (!supportBluetoothPersistedState()) {
- return false;
- }
- return Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON,
- BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH;
- }
-
- /**
- * Save the Bluetooth on/off state
- */
- private void persistBluetoothSetting(int value) {
- if (DBG) {
- Slog.d(TAG, "Persisting Bluetooth Setting: " + value);
- }
- // waive WRITE_SECURE_SETTINGS permission check
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.BLUETOOTH_ON, value);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
- }
-
- /**
- * Returns true if the Bluetooth Adapter's name and address is
- * locally cached
- * @return
- */
- private boolean isNameAndAddressSet() {
- return mName != null && mAddress != null && mName.length() > 0 && mAddress.length() > 0;
- }
-
- /**
- * Retrieve the Bluetooth Adapter's name and address and save it in
- * in the local cache
- */
- private void loadStoredNameAndAddress() {
- if (DBG) {
- Slog.d(TAG, "Loading stored name and address");
- }
- if (mContext.getResources()
- .getBoolean(com.android.internal.R.bool.config_bluetooth_address_validation)
- && Settings.Secure.getIntForUser(mContentResolver,
- Settings.Secure.BLUETOOTH_NAME, 0, mUserId)
- == 0) {
- // if the valid flag is not set, don't load the address and name
- if (DBG) {
- Slog.d(TAG, "invalid bluetooth name and address stored");
- }
- return;
- }
- mName = Settings.Secure.getStringForUser(
- mContentResolver, Settings.Secure.BLUETOOTH_NAME, mUserId);
- mAddress = Settings.Secure.getStringForUser(
- mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS, mUserId);
- if (DBG) {
- Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
- }
- }
-
- /**
- * Save the Bluetooth name and address in the persistent store.
- * Only non-null values will be saved.
- * @param name
- * @param address
- */
- private void storeNameAndAddress(String name, String address) {
- if (name != null) {
- Settings.Secure.putStringForUser(mContentResolver, Settings.Secure.BLUETOOTH_NAME, name,
- mUserId);
- mName = name;
- if (DBG) {
- Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getStringForUser(
- mContentResolver, Settings.Secure.BLUETOOTH_NAME,
- mUserId));
- }
- }
-
- if (address != null) {
- Settings.Secure.putStringForUser(mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS,
- address, mUserId);
- mAddress = address;
- if (DBG) {
- Slog.d(TAG,
- "Stored Bluetoothaddress: " + Settings.Secure.getStringForUser(
- mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS,
- mUserId));
- }
- }
-
- if ((name != null) && (address != null)) {
- Settings.Secure.putIntForUser(mContentResolver, Settings.Secure.BLUETOOTH_ADDR_VALID, 1,
- mUserId);
- }
- }
-
- public IBluetooth registerAdapter(IBluetoothManagerCallback callback) {
- if (callback == null) {
- Slog.w(TAG, "Callback is null in registerAdapter");
- return null;
- }
- synchronized (mCallbacks) {
- mCallbacks.register(callback);
- }
- return mBluetooth;
- }
-
- public void unregisterAdapter(IBluetoothManagerCallback callback) {
- if (callback == null) {
- Slog.w(TAG, "Callback is null in unregisterAdapter");
- return;
- }
- synchronized (mCallbacks) {
- mCallbacks.unregister(callback);
- }
- }
-
- public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
- if (callback == null) {
- Slog.w(TAG, "registerStateChangeCallback: Callback is null!");
- return;
- }
- Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
- msg.obj = callback;
- mHandler.sendMessage(msg);
- }
-
- public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
- if (callback == null) {
- Slog.w(TAG, "unregisterStateChangeCallback: Callback is null!");
- return;
- }
- Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
- msg.obj = callback;
- mHandler.sendMessage(msg);
- }
-
- public boolean isEnabled() {
- return getState() == BluetoothAdapter.STATE_ON;
- }
-
- public int getState() {
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) {
- Slog.w(TAG, "getState(): report OFF for non-active and non system user");
- return BluetoothAdapter.STATE_OFF;
- }
-
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- return mBluetooth.getState();
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "getState()", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- return BluetoothAdapter.STATE_OFF;
- }
-
- class ClientDeathRecipient implements IBinder.DeathRecipient {
- private String mPackageName;
-
- ClientDeathRecipient(String packageName) {
- mPackageName = packageName;
- }
-
- public void binderDied() {
- if (DBG) {
- Slog.d(TAG, "Binder is dead - unregister " + mPackageName);
- }
-
- for (Map.Entry<IBinder, ClientDeathRecipient> entry : mBleApps.entrySet()) {
- IBinder token = entry.getKey();
- ClientDeathRecipient deathRec = entry.getValue();
- if (deathRec.equals(this)) {
- updateBleAppCount(token, false, mPackageName);
- break;
- }
- }
- }
-
- public String getPackageName() {
- return mPackageName;
- }
- }
-
- @Override
- public boolean isBleScanAlwaysAvailable() {
- if (isAirplaneModeOn() && !mEnable) {
- return false;
- }
- try {
- return Settings.Global.getInt(mContentResolver,
- Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE) != 0;
- } catch (SettingNotFoundException e) {
- }
- return false;
- }
-
- @Override
- public boolean isHearingAidProfileSupported() {
- return mIsHearingAidProfileSupported;
- }
-
- private boolean isDeviceProvisioned() {
- return Settings.Global.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED,
- 0) != 0;
- }
-
- // Monitor change of BLE scan only mode settings.
- private void registerForProvisioningStateChange() {
- ContentObserver contentObserver = new ContentObserver(null) {
- @Override
- public void onChange(boolean selfChange) {
- if (!isDeviceProvisioned()) {
- if (DBG) {
- Slog.d(TAG, "DEVICE_PROVISIONED setting changed, but device is not "
- + "provisioned");
- }
- return;
- }
- if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED)) {
- Slog.i(TAG, "Device provisioned, reactivating pending flag changes");
- onInitFlagsChanged();
- }
- }
- };
-
- mContentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), false,
- contentObserver);
- }
-
- // Monitor change of BLE scan only mode settings.
- private void registerForBleScanModeChange() {
- ContentObserver contentObserver = new ContentObserver(null) {
- @Override
- public void onChange(boolean selfChange) {
- if (isBleScanAlwaysAvailable()) {
- // Nothing to do
- return;
- }
- // BLE scan is not available.
- disableBleScanMode();
- clearBleApps();
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
- mContext.getPackageName(), false);
- mBluetooth.onBrEdrDown(mContext.getAttributionSource());
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "error when disabling bluetooth", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- }
- };
-
- mContentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE), false,
- contentObserver);
- }
-
- // Disable ble scan only mode.
- private void disableBleScanMode() {
- try {
- mBluetoothLock.writeLock().lock();
- if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
- if (DBG) {
- Slog.d(TAG, "Reseting the mEnable flag for clean disable");
- }
- mEnable = false;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "getState()", e);
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
- }
-
- private int updateBleAppCount(IBinder token, boolean enable, String packageName) {
- ClientDeathRecipient r = mBleApps.get(token);
- if (r == null && enable) {
- ClientDeathRecipient deathRec = new ClientDeathRecipient(packageName);
- try {
- token.linkToDeath(deathRec, 0);
- } catch (RemoteException ex) {
- throw new IllegalArgumentException("BLE app (" + packageName + ") already dead!");
- }
- mBleApps.put(token, deathRec);
- 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 of " + packageName);
- }
- }
- int appCount = mBleApps.size();
- if (DBG) {
- Slog.d(TAG, appCount + " registered Ble Apps");
- }
- return appCount;
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private boolean checkBluetoothPermissions(AttributionSource attributionSource, String message,
- boolean requireForeground) {
- if (isBluetoothDisallowed()) {
- if (DBG) {
- Slog.d(TAG, "checkBluetoothPermissions: bluetooth disallowed");
- }
- return false;
- }
- // Check if packageName belongs to callingUid
- final int callingUid = Binder.getCallingUid();
- final boolean isCallerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;
- if (!isCallerSystem) {
- checkPackage(callingUid, attributionSource.getPackageName());
-
- if (requireForeground && !checkIfCallerIsForegroundUser()) {
- Slog.w(TAG, "Not allowed for non-active and non system user");
- return false;
- }
-
- if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, message)) {
- return false;
- }
- }
- return true;
- }
-
- public boolean enableBle(AttributionSource attributionSource, IBinder token)
- throws RemoteException {
- final String packageName = attributionSource.getPackageName();
- if (!checkBluetoothPermissions(attributionSource, "enableBle", false)) {
- if (DBG) {
- Slog.d(TAG, "enableBle(): bluetooth disallowed");
- }
- return false;
- }
-
- if (DBG) {
- Slog.d(TAG, "enableBle(" + packageName + "): mBluetooth =" + mBluetooth
- + " mBinding = " + mBinding + " mState = "
- + BluetoothAdapter.nameForState(mState));
- }
- updateBleAppCount(token, true, packageName);
-
- if (mState == BluetoothAdapter.STATE_ON
- || mState == BluetoothAdapter.STATE_BLE_ON
- || mState == BluetoothAdapter.STATE_TURNING_ON
- || mState == BluetoothAdapter.STATE_TURNING_OFF
- || mState == BluetoothAdapter.STATE_BLE_TURNING_ON) {
- Log.d(TAG, "enableBLE(): Bluetooth is already enabled or is turning on");
- return true;
- }
- synchronized (mReceiver) {
- // waive WRITE_SECURE_SETTINGS permission check
- sendEnableMsg(false, BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
- packageName, true);
- }
- return true;
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public boolean disableBle(AttributionSource attributionSource, IBinder token)
- throws RemoteException {
- final String packageName = attributionSource.getPackageName();
- if (!checkBluetoothPermissions(attributionSource, "disableBle", false)) {
- if (DBG) {
- Slog.d(TAG, "disableBLE(): bluetooth disallowed");
- }
- return false;
- }
-
- if (DBG) {
- Slog.d(TAG, "disableBle(" + packageName + "): mBluetooth =" + mBluetooth
- + " mBinding = " + mBinding + " mState = "
- + BluetoothAdapter.nameForState(mState));
- }
-
- if (mState == BluetoothAdapter.STATE_OFF) {
- Slog.d(TAG, "disableBLE(): Already disabled");
- return false;
- }
- updateBleAppCount(token, false, packageName);
-
- if (mState == BluetoothAdapter.STATE_BLE_ON && !isBleAppPresent()) {
- if (mEnable) {
- disableBleScanMode();
- }
- if (!mEnableExternal) {
- addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
- packageName, false);
- sendBrEdrDownCallback(attributionSource);
- }
- }
- return true;
- }
-
- // Clear all apps using BLE scan only mode.
- private void clearBleApps() {
- mBleApps.clear();
- }
-
- /** @hide */
- public boolean isBleAppPresent() {
- if (DBG) {
- Slog.d(TAG, "isBleAppPresent() count: " + mBleApps.size());
- }
- return mBleApps.size() > 0;
- }
-
- /**
- * Call IBluetooth.onLeServiceUp() to continue if Bluetooth should be on,
- * call IBluetooth.onBrEdrDown() to disable if Bluetooth should be off.
- */
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- private void continueFromBleOnState() {
- if (DBG) {
- Slog.d(TAG, "continueFromBleOnState()");
- }
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth == null) {
- Slog.e(TAG, "onBluetoothServiceUp: mBluetooth is null!");
- return;
- }
- if (!mEnableExternal && !isBleAppPresent()) {
- Slog.i(TAG, "Bluetooth was disabled while enabling BLE, disable BLE now");
- mEnable = false;
- mBluetooth.onBrEdrDown(mContext.getAttributionSource());
- return;
- }
- if (isBluetoothPersistedStateOnBluetooth() || !isBleAppPresent()) {
- // This triggers transition to STATE_ON
- mBluetooth.onLeServiceUp(mContext.getAttributionSource());
- persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call onServiceUp", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- }
-
- /**
- * Inform BluetoothAdapter instances that BREDR part is down
- * and turn off all service and stack if no LE app needs it
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- private void sendBrEdrDownCallback(AttributionSource attributionSource) {
- if (DBG) {
- Slog.d(TAG, "Calling sendBrEdrDownCallback callbacks");
- }
-
- if (mBluetooth == null) {
- Slog.w(TAG, "Bluetooth handle is null");
- return;
- }
-
- if (isBleAppPresent()) {
- // Need to stay at BLE ON. Disconnect all Gatt connections
- try {
- mBluetoothGatt.unregAll(attributionSource);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to disconnect all apps.", e);
- }
- } else {
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- mBluetooth.onBrEdrDown(attributionSource);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Call to onBrEdrDown() failed.", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- }
-
- }
-
- public boolean enableNoAutoConnect(AttributionSource attributionSource) {
- final String packageName = attributionSource.getPackageName();
- if (!checkBluetoothPermissions(attributionSource, "enableNoAutoConnect", false)) {
- if (DBG) {
- Slog.d(TAG, "enableNoAutoConnect(): not enabling - bluetooth disallowed");
- }
- return false;
- }
-
- if (DBG) {
- Slog.d(TAG, "enableNoAutoConnect(): mBluetooth =" + mBluetooth + " mBinding = "
- + mBinding);
- }
-
- int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
- if (callingAppId != Process.NFC_UID) {
- throw new SecurityException("no permission to enable Bluetooth quietly");
- }
-
- synchronized (mReceiver) {
- mQuietEnableExternal = true;
- mEnableExternal = true;
- sendEnableMsg(true,
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName);
- }
- return true;
- }
-
- public boolean enable(AttributionSource attributionSource) throws RemoteException {
- final String packageName = attributionSource.getPackageName();
- if (!checkBluetoothPermissions(attributionSource, "enable", true)) {
- if (DBG) {
- Slog.d(TAG, "enable(): not enabling - bluetooth disallowed");
- }
- return false;
- }
-
- final int callingUid = Binder.getCallingUid();
- final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;
- if (!callerSystem && !isEnabled() && mWirelessConsentRequired
- && startConsentUiIfNeeded(packageName,
- callingUid, BluetoothAdapter.ACTION_REQUEST_ENABLE)) {
- return false;
- }
-
- if (DBG) {
- Slog.d(TAG, "enable(" + packageName + "): mBluetooth =" + mBluetooth + " mBinding = "
- + mBinding + " mState = " + BluetoothAdapter.nameForState(mState));
- }
-
- synchronized (mReceiver) {
- mQuietEnableExternal = false;
- mEnableExternal = true;
- // waive WRITE_SECURE_SETTINGS permission check
- sendEnableMsg(false,
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName);
- }
- if (DBG) {
- Slog.d(TAG, "enable returning");
- }
- return true;
- }
-
- public boolean disable(AttributionSource attributionSource, boolean persist)
- throws RemoteException {
- if (!persist) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
- "Need BLUETOOTH_PRIVILEGED permission");
- }
-
- final String packageName = attributionSource.getPackageName();
- if (!checkBluetoothPermissions(attributionSource, "disable", true)) {
- if (DBG) {
- Slog.d(TAG, "disable(): not disabling - bluetooth disallowed");
- }
- return false;
- }
-
- final int callingUid = Binder.getCallingUid();
- final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;
- if (!callerSystem && isEnabled() && mWirelessConsentRequired
- && startConsentUiIfNeeded(packageName,
- callingUid, BluetoothAdapter.ACTION_REQUEST_DISABLE)) {
- return false;
- }
-
- if (DBG) {
- Slog.d(TAG, "disable(): mBluetooth = " + mBluetooth + " mBinding = " + mBinding);
- }
-
- synchronized (mReceiver) {
- if (!isBluetoothPersistedStateOnAirplane()) {
- if (persist) {
- persistBluetoothSetting(BLUETOOTH_OFF);
- }
- mEnableExternal = false;
- }
- sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
- packageName);
- }
- return true;
- }
-
- private boolean startConsentUiIfNeeded(String packageName,
- int callingUid, String intentAction) throws RemoteException {
- if (checkBluetoothPermissionWhenWirelessConsentRequired()) {
- return false;
- }
- try {
- // Validate the package only if we are going to use it
- ApplicationInfo applicationInfo = mContext.getPackageManager()
- .getApplicationInfoAsUser(packageName,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
- UserHandle.getUserId(callingUid));
- if (applicationInfo.uid != callingUid) {
- throw new SecurityException("Package " + packageName
- + " not in uid " + callingUid);
- }
-
- Intent intent = new Intent(intentAction);
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
- intent.setFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- try {
- mContext.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- // Shouldn't happen
- Slog.e(TAG, "Intent to handle action " + intentAction + " missing");
- return false;
- }
- return true;
- } catch (PackageManager.NameNotFoundException e) {
- throw new RemoteException(e.getMessage());
- }
- }
-
- /**
- * Check if AppOpsManager is available and the packageName belongs to uid
- *
- * A null package belongs to any uid
- */
- private void checkPackage(int uid, String packageName) {
- if (mAppOps == null) {
- Slog.w(TAG, "checkPackage(): called before system boot up, uid "
- + uid + ", packageName " + packageName);
- throw new IllegalStateException("System has not boot yet");
- }
- if (packageName == null) {
- Slog.w(TAG, "checkPackage(): called with null packageName from " + uid);
- return;
- }
- try {
- mAppOps.checkPackage(uid, packageName);
- } catch (SecurityException e) {
- Slog.w(TAG, "checkPackage(): " + packageName + " does not belong to uid " + uid);
- throw new SecurityException(e.getMessage());
- }
- }
-
- /**
- * Check if the caller must still pass permission check or if the caller is exempted
- * from the consent UI via the MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED check.
- *
- * Commands from some callers may be exempted from triggering the consent UI when
- * enabling bluetooth. This exemption is checked via the
- * MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED and allows calls to skip
- * the consent UI where it may otherwise be required.
- *
- * @hide
- */
- @SuppressLint("AndroidFrameworkRequiresPermission")
- private boolean checkBluetoothPermissionWhenWirelessConsentRequired() {
- int result = mContext.checkCallingPermission(
- android.Manifest.permission.MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED);
- return result == PackageManager.PERMISSION_GRANTED;
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void unbindAndFinish() {
- if (DBG) {
- Slog.d(TAG, "unbindAndFinish(): " + mBluetooth + " mBinding = " + mBinding
- + " mUnbinding = " + mUnbinding);
- }
-
- try {
- mBluetoothLock.writeLock().lock();
- if (mUnbinding) {
- return;
- }
- mUnbinding = true;
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
- mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE);
- if (mBluetooth != null) {
- //Unregister callback object
- try {
- mBluetooth.unregisterCallback(mBluetoothCallback,
- mContext.getAttributionSource());
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to unregister BluetoothCallback", re);
- }
- mBluetoothBinder = null;
- mBluetooth = null;
- mContext.unbindService(mConnection);
- mUnbinding = false;
- mBinding = false;
- } else {
- mUnbinding = false;
- }
- mBluetoothGatt = null;
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
- }
-
- public IBluetoothGatt getBluetoothGatt() {
- // sync protection
- return mBluetoothGatt;
- }
-
- @Override
- public boolean bindBluetoothProfileService(int bluetoothProfile,
- IBluetoothProfileServiceConnection proxy) {
- if (mState != BluetoothAdapter.STATE_ON) {
- if (DBG) {
- Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile
- + ", while Bluetooth was disabled");
- }
- return false;
- }
- synchronized (mProfileServices) {
- ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
- if (psc == null) {
- if (DBG) {
- Slog.d(TAG, "Creating new ProfileServiceConnections object for" + " profile: "
- + bluetoothProfile);
- }
-
- Intent intent;
- if (bluetoothProfile == BluetoothProfile.HEADSET) {
- intent = new Intent(IBluetoothHeadset.class.getName());
- } else if (bluetoothProfile== BluetoothProfile.LE_CALL_CONTROL) {
- intent = new Intent(IBluetoothLeCallControl.class.getName());
- } else {
- return false;
- }
-
- psc = new ProfileServiceConnections(intent);
- if (!psc.bindService()) {
- return false;
- }
-
- mProfileServices.put(new Integer(bluetoothProfile), psc);
- }
- }
-
- // Introducing a delay to give the client app time to prepare
- Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED);
- addProxyMsg.arg1 = bluetoothProfile;
- addProxyMsg.obj = proxy;
- mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS);
- return true;
- }
-
- @Override
- public void unbindBluetoothProfileService(int bluetoothProfile,
- IBluetoothProfileServiceConnection proxy) {
- synchronized (mProfileServices) {
- Integer profile = new Integer(bluetoothProfile);
- ProfileServiceConnections psc = mProfileServices.get(profile);
- if (psc == null) {
- return;
- }
- psc.removeProxy(proxy);
- if (psc.isEmpty()) {
- // All prxoies are disconnected, unbind with the service.
- try {
- mContext.unbindService(psc);
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
- }
- mProfileServices.remove(profile);
- }
- }
- }
-
- private void unbindAllBluetoothProfileServices() {
- synchronized (mProfileServices) {
- for (Integer i : mProfileServices.keySet()) {
- ProfileServiceConnections psc = mProfileServices.get(i);
- try {
- mContext.unbindService(psc);
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
- }
- psc.removeAllProxies();
- }
- mProfileServices.clear();
- }
- }
-
- /**
- * Send enable message and set adapter name and address. Called when the boot phase becomes
- * PHASE_SYSTEM_SERVICES_READY.
- */
- public void handleOnBootPhase() {
- if (DBG) {
- Slog.d(TAG, "Bluetooth boot completed");
- }
- mAppOps = mContext.getSystemService(AppOpsManager.class);
- UserManagerInternal userManagerInternal =
- LocalServices.getService(UserManagerInternal.class);
- userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
- final boolean isBluetoothDisallowed = isBluetoothDisallowed();
- if (isBluetoothDisallowed) {
- return;
- }
- final boolean isSafeMode = mContext.getPackageManager().isSafeMode();
- if (mEnableExternal && isBluetoothPersistedStateOnBluetooth() && !isSafeMode) {
- if (DBG) {
- Slog.d(TAG, "Auto-enabling Bluetooth.");
- }
- sendEnableMsg(mQuietEnableExternal,
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT,
- mContext.getPackageName());
- } else if (!isNameAndAddressSet()) {
- if (DBG) {
- Slog.d(TAG, "Getting adapter name and address");
- }
- Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
- mHandler.sendMessage(getMsg);
- }
-
- mBluetoothModeChangeHelper = new BluetoothModeChangeHelper(mContext);
- if (mBluetoothAirplaneModeListener != null) {
- mBluetoothAirplaneModeListener.start(mBluetoothModeChangeHelper);
- }
- registerForProvisioningStateChange();
- mBluetoothDeviceConfigListener = new BluetoothDeviceConfigListener(this, DBG);
- }
-
- /**
- * Called when switching to a different foreground user.
- */
- public void handleOnSwitchUser(int userHandle) {
- if (DBG) {
- Slog.d(TAG, "User " + userHandle + " switched");
- }
- mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle, 0).sendToTarget();
- }
-
- /**
- * Called when user is unlocked.
- */
- public void handleOnUnlockUser(int userHandle) {
- if (DBG) {
- Slog.d(TAG, "User " + userHandle + " unlocked");
- }
- mHandler.obtainMessage(MESSAGE_USER_UNLOCKED, userHandle, 0).sendToTarget();
- }
-
- /**
- * This class manages the clients connected to a given ProfileService
- * and maintains the connection with that service.
- */
- private final class ProfileServiceConnections
- implements ServiceConnection, IBinder.DeathRecipient {
- final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
- new RemoteCallbackList<IBluetoothProfileServiceConnection>();
- IBinder mService;
- ComponentName mClassName;
- Intent mIntent;
- boolean mInvokingProxyCallbacks = false;
-
- ProfileServiceConnections(Intent intent) {
- mService = null;
- mClassName = null;
- mIntent = intent;
- }
-
- private boolean bindService() {
- int state = BluetoothAdapter.STATE_OFF;
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- state = mBluetooth.getState();
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call getState", e);
- return false;
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- if (state != BluetoothAdapter.STATE_ON) {
- if (DBG) {
- Slog.d(TAG, "Unable to bindService while Bluetooth is disabled");
- }
- return false;
- }
-
- if (mIntent != null && mService == null && doBind(mIntent, this, 0,
- UserHandle.CURRENT_OR_SELF)) {
- Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
- msg.obj = this;
- mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
- return true;
- }
- Slog.w(TAG, "Unable to bind with intent: " + mIntent);
- return false;
- }
-
- private void addProxy(IBluetoothProfileServiceConnection proxy) {
- mProxies.register(proxy);
- if (mService != null) {
- try {
- proxy.onServiceConnected(mClassName, mService);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to connect to proxy", e);
- }
- } else {
- if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
- Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
- msg.obj = this;
- mHandler.sendMessage(msg);
- }
- }
- }
-
- private void removeProxy(IBluetoothProfileServiceConnection proxy) {
- if (proxy != null) {
- if (mProxies.unregister(proxy)) {
- try {
- proxy.onServiceDisconnected(mClassName);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to disconnect proxy", e);
- }
- }
- } else {
- Slog.w(TAG, "Trying to remove a null proxy");
- }
- }
-
- private void removeAllProxies() {
- onServiceDisconnected(mClassName);
- mProxies.kill();
- }
-
- private boolean isEmpty() {
- return mProxies.getRegisteredCallbackCount() == 0;
- }
-
- @Override
- public void onServiceConnected(ComponentName className, IBinder service) {
- // remove timeout message
- mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this);
- mService = service;
- mClassName = className;
- try {
- mService.linkToDeath(this, 0);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to linkToDeath", e);
- }
-
- if (mInvokingProxyCallbacks) {
- Slog.e(TAG, "Proxy callbacks already in progress.");
- return;
- }
- mInvokingProxyCallbacks = true;
-
- final int n = mProxies.beginBroadcast();
- try {
- for (int i = 0; i < n; i++) {
- try {
- mProxies.getBroadcastItem(i).onServiceConnected(className, service);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to connect to proxy", e);
- }
- }
- } finally {
- mProxies.finishBroadcast();
- mInvokingProxyCallbacks = false;
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName className) {
- if (mService == null) {
- return;
- }
- try {
- mService.unlinkToDeath(this, 0);
- } catch (NoSuchElementException e) {
- Log.e(TAG, "error unlinking to death", e);
- }
- mService = null;
- mClassName = null;
-
- if (mInvokingProxyCallbacks) {
- Slog.e(TAG, "Proxy callbacks already in progress.");
- return;
- }
- mInvokingProxyCallbacks = true;
-
- final int n = mProxies.beginBroadcast();
- try {
- for (int i = 0; i < n; i++) {
- try {
- mProxies.getBroadcastItem(i).onServiceDisconnected(className);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to disconnect from proxy", e);
- }
- }
- } finally {
- mProxies.finishBroadcast();
- mInvokingProxyCallbacks = false;
- }
- }
-
- @Override
- public void binderDied() {
- if (DBG) {
- Slog.w(TAG, "Profile service for profile: " + mClassName + " died.");
- }
- onServiceDisconnected(mClassName);
- // Trigger rebind
- Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
- msg.obj = this;
- mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
- }
- }
-
- private void sendBluetoothStateCallback(boolean isUp) {
- try {
- int n = mStateChangeCallbacks.beginBroadcast();
- if (DBG) {
- Slog.d(TAG, "Broadcasting onBluetoothStateChange(" + isUp + ") to " + n
- + " receivers.");
- }
- for (int i = 0; i < n; i++) {
- try {
- mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i, e);
- }
- }
- } finally {
- mStateChangeCallbacks.finishBroadcast();
- }
- }
-
- /**
- * Inform BluetoothAdapter instances that Adapter service is up
- */
- private void sendBluetoothServiceUpCallback() {
- synchronized (mCallbacks) {
- try {
- int n = mCallbacks.beginBroadcast();
- Slog.d(TAG, "Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
- for (int i = 0; i < n; i++) {
- try {
- mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
- }
- }
- } finally {
- mCallbacks.finishBroadcast();
- }
- }
- }
-
- /**
- * Inform BluetoothAdapter instances that Adapter service is down
- */
- private void sendBluetoothServiceDownCallback() {
- synchronized (mCallbacks) {
- try {
- int n = mCallbacks.beginBroadcast();
- Slog.d(TAG, "Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
- for (int i = 0; i < n; i++) {
- try {
- mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
- }
- }
- } finally {
- mCallbacks.finishBroadcast();
- }
- }
- }
-
- public String getAddress(AttributionSource attributionSource) {
- if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, "getAddress")) {
- return null;
- }
-
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) {
- Slog.w(TAG, "getAddress(): not allowed for non-active and non system user");
- return null;
- }
-
- if (mContext.checkCallingOrSelfPermission(Manifest.permission.LOCAL_MAC_ADDRESS)
- != PackageManager.PERMISSION_GRANTED) {
- return BluetoothAdapter.DEFAULT_MAC_ADDRESS;
- }
-
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- return mBluetooth.getAddressWithAttribution(attributionSource);
- }
- } catch (RemoteException e) {
- Slog.e(TAG,
- "getAddress(): Unable to retrieve address remotely. Returning cached address",
- e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- // mAddress is accessed from outside.
- // It is alright without a lock. Here, bluetooth is off, no other thread is
- // changing mAddress
- return mAddress;
- }
-
- public String getName(AttributionSource attributionSource) {
- if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, "getName")) {
- return null;
- }
-
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) {
- Slog.w(TAG, "getName(): not allowed for non-active and non system user");
- return null;
- }
-
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- return mBluetooth.getName(attributionSource);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "getName(): Unable to retrieve name remotely. Returning cached name", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- // mName is accessed from outside.
- // It alright without a lock. Here, bluetooth is off, no other thread is
- // changing mName
- return mName;
- }
-
- private class BluetoothServiceConnection implements ServiceConnection {
- public void onServiceConnected(ComponentName componentName, IBinder service) {
- String name = componentName.getClassName();
- if (DBG) {
- Slog.d(TAG, "BluetoothServiceConnection: " + name);
- }
- Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
- if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
- msg.arg1 = SERVICE_IBLUETOOTH;
- } else if (name.equals("com.android.bluetooth.gatt.GattService")) {
- msg.arg1 = SERVICE_IBLUETOOTHGATT;
- } else {
- Slog.e(TAG, "Unknown service connected: " + name);
- return;
- }
- msg.obj = service;
- mHandler.sendMessage(msg);
- }
-
- public void onServiceDisconnected(ComponentName componentName) {
- // Called if we unexpectedly disconnect.
- String name = componentName.getClassName();
- if (DBG) {
- Slog.d(TAG, "BluetoothServiceConnection, disconnected: " + name);
- }
- Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
- if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
- msg.arg1 = SERVICE_IBLUETOOTH;
- } else if (name.equals("com.android.bluetooth.gatt.GattService")) {
- msg.arg1 = SERVICE_IBLUETOOTHGATT;
- } else {
- Slog.e(TAG, "Unknown service disconnected: " + name);
- return;
- }
- mHandler.sendMessage(msg);
- }
- }
-
- private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
-
- private class BluetoothHandler extends Handler {
- boolean mGetNameAddressOnly = false;
- private int mWaitForEnableRetry;
- private int mWaitForDisableRetry;
-
- BluetoothHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_GET_NAME_AND_ADDRESS:
- if (DBG) {
- Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
- }
- try {
- mBluetoothLock.writeLock().lock();
- if ((mBluetooth == null) && (!mBinding)) {
- if (DBG) {
- Slog.d(TAG, "Binding to service to get name and address");
- }
- mGetNameAddressOnly = true;
- Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
- mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
- Intent i = new Intent(IBluetooth.class.getName());
- if (!doBind(i, mConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
- UserHandle.CURRENT)) {
- mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
- } else {
- mBinding = true;
- }
- } else if (mBluetooth != null) {
- try {
- storeNameAndAddress(
- mBluetooth.getName(mContext.getAttributionSource()),
- mBluetooth.getAddressWithAttribution(
- mContext.getAttributionSource()));
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to grab names", re);
- }
- if (mGetNameAddressOnly && !mEnable) {
- unbindAndFinish();
- }
- mGetNameAddressOnly = false;
- }
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
- break;
-
- case MESSAGE_ENABLE:
- int quietEnable = msg.arg1;
- int isBle = msg.arg2;
- if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED)
- || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) {
- // We are handling enable or disable right now, wait for it.
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ENABLE,
- quietEnable, isBle), ENABLE_DISABLE_DELAY_MS);
- break;
- }
-
- if (DBG) {
- Slog.d(TAG, "MESSAGE_ENABLE(" + quietEnable + "): mBluetooth = "
- + mBluetooth);
- }
- mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mEnable = true;
-
- if (isBle == 0) {
- persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
- }
-
- // Use service interface to get the exact state
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- boolean isHandled = true;
- int state = mBluetooth.getState();
- switch (state) {
- case BluetoothAdapter.STATE_BLE_ON:
- if (isBle == 1) {
- Slog.i(TAG, "Already at BLE_ON State");
- } else {
- Slog.w(TAG, "BT Enable in BLE_ON State, going to ON");
- mBluetooth.onLeServiceUp(mContext.getAttributionSource());
- }
- break;
- case BluetoothAdapter.STATE_BLE_TURNING_ON:
- case BluetoothAdapter.STATE_TURNING_ON:
- case BluetoothAdapter.STATE_ON:
- Slog.i(TAG, "MESSAGE_ENABLE: already enabled");
- break;
- default:
- isHandled = false;
- break;
- }
- if (isHandled) break;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- mQuietEnable = (quietEnable == 1);
- if (mBluetooth == null) {
- handleEnable(mQuietEnable);
- } else {
- //
- // We need to wait until transitioned to STATE_OFF and
- // the previous Bluetooth process has exited. The
- // waiting period has three components:
- // (a) Wait until the local state is STATE_OFF. This
- // is accomplished by sending delay a message
- // MESSAGE_HANDLE_ENABLE_DELAYED
- // (b) Wait until the STATE_OFF state is updated to
- // all components.
- // (c) Wait until the Bluetooth process exits, and
- // ActivityManager detects it.
- // The waiting for (b) and (c) is accomplished by
- // delaying the MESSAGE_RESTART_BLUETOOTH_SERVICE
- // message. The delay time is backed off if Bluetooth
- // continuously failed to turn on itself.
- //
- mWaitForEnableRetry = 0;
- Message enableDelayedMsg =
- mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED);
- mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
- }
- break;
-
- case MESSAGE_DISABLE:
- if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) || mBinding
- || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) {
- // We are handling enable or disable right now, wait for it.
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_DISABLE),
- ENABLE_DISABLE_DELAY_MS);
- break;
- }
-
- if (DBG) {
- Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth
- + ", mBinding = " + mBinding);
- }
- mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
-
- if (mEnable && mBluetooth != null) {
- mWaitForDisableRetry = 0;
- Message disableDelayedMsg =
- mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0);
- mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
- } else {
- mEnable = false;
- handleDisable();
- }
- break;
-
- case MESSAGE_HANDLE_ENABLE_DELAYED: {
- // The Bluetooth is turning off, wait for STATE_OFF
- if (mState != BluetoothAdapter.STATE_OFF) {
- if (mWaitForEnableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
- mWaitForEnableRetry++;
- Message enableDelayedMsg =
- mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED);
- mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
- break;
- } else {
- Slog.e(TAG, "Wait for STATE_OFF timeout");
- }
- }
- // Either state is changed to STATE_OFF or reaches the maximum retry, we
- // should move forward to the next step.
- mWaitForEnableRetry = 0;
- Message restartMsg =
- mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
- Slog.d(TAG, "Handle enable is finished");
- break;
- }
-
- case MESSAGE_HANDLE_DISABLE_DELAYED: {
- boolean disabling = (msg.arg1 == 1);
- Slog.d(TAG, "MESSAGE_HANDLE_DISABLE_DELAYED: disabling:" + disabling);
- if (!disabling) {
- // The Bluetooth is turning on, wait for STATE_ON
- if (mState != BluetoothAdapter.STATE_ON) {
- if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
- mWaitForDisableRetry++;
- Message disableDelayedMsg = mHandler.obtainMessage(
- MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0);
- mHandler.sendMessageDelayed(disableDelayedMsg,
- ENABLE_DISABLE_DELAY_MS);
- break;
- } else {
- Slog.e(TAG, "Wait for STATE_ON timeout");
- }
- }
- // Either state is changed to STATE_ON or reaches the maximum retry, we
- // should move forward to the next step.
- mWaitForDisableRetry = 0;
- mEnable = false;
- handleDisable();
- // Wait for state exiting STATE_ON
- Message disableDelayedMsg =
- mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0);
- mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
- } else {
- // The Bluetooth is turning off, wait for exiting STATE_ON
- if (mState == BluetoothAdapter.STATE_ON) {
- if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
- mWaitForDisableRetry++;
- Message disableDelayedMsg = mHandler.obtainMessage(
- MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0);
- mHandler.sendMessageDelayed(disableDelayedMsg,
- ENABLE_DISABLE_DELAY_MS);
- break;
- } else {
- Slog.e(TAG, "Wait for exiting STATE_ON timeout");
- }
- }
- // Either state is exited from STATE_ON or reaches the maximum retry, we
- // should move forward to the next step.
- Slog.d(TAG, "Handle disable is finished");
- }
- break;
- }
-
- case MESSAGE_RESTORE_USER_SETTING:
- if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) {
- if (DBG) {
- Slog.d(TAG, "Restore Bluetooth state to disabled");
- }
- persistBluetoothSetting(BLUETOOTH_OFF);
- mEnableExternal = false;
- sendDisableMsg(
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING,
- mContext.getPackageName());
- } else if ((msg.arg1 == RESTORE_SETTING_TO_ON) && !mEnable) {
- if (DBG) {
- Slog.d(TAG, "Restore Bluetooth state to enabled");
- }
- mQuietEnableExternal = false;
- mEnableExternal = true;
- // waive WRITE_SECURE_SETTINGS permission check
- sendEnableMsg(false,
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING,
- mContext.getPackageName());
- }
- break;
- case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: {
- IBluetoothStateChangeCallback callback =
- (IBluetoothStateChangeCallback) msg.obj;
- mStateChangeCallbacks.register(callback);
- break;
- }
- case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: {
- IBluetoothStateChangeCallback callback =
- (IBluetoothStateChangeCallback) msg.obj;
- mStateChangeCallbacks.unregister(callback);
- break;
- }
- case MESSAGE_ADD_PROXY_DELAYED: {
- ProfileServiceConnections psc = mProfileServices.get(msg.arg1);
- if (psc == null) {
- break;
- }
- IBluetoothProfileServiceConnection proxy =
- (IBluetoothProfileServiceConnection) msg.obj;
- psc.addProxy(proxy);
- break;
- }
- case MESSAGE_BIND_PROFILE_SERVICE: {
- ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
- removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
- if (psc == null) {
- break;
- }
- psc.bindService();
- break;
- }
- case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: {
- if (DBG) {
- Slog.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
- }
-
- IBinder service = (IBinder) msg.obj;
- try {
- mBluetoothLock.writeLock().lock();
- if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
- mBluetoothGatt =
- IBluetoothGatt.Stub.asInterface(Binder.allowBlocking(service));
- continueFromBleOnState();
- break;
- } // else must be SERVICE_IBLUETOOTH
-
- //Remove timeout
- mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
-
- mBinding = false;
- mBluetoothBinder = service;
- mBluetooth = IBluetooth.Stub.asInterface(Binder.allowBlocking(service));
-
- if (!isNameAndAddressSet()) {
- Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
- mHandler.sendMessage(getMsg);
- if (mGetNameAddressOnly) {
- return;
- }
- }
-
- //Register callback object
- try {
- mBluetooth.registerCallback(mBluetoothCallback,
- mContext.getAttributionSource());
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to register BluetoothCallback", re);
- }
- //Inform BluetoothAdapter instances that service is up
- sendBluetoothServiceUpCallback();
-
- //Do enable request
- try {
- if (!mBluetooth.enable(mQuietEnable, mContext.getAttributionSource())) {
- Slog.e(TAG, "IBluetooth.enable() returned false");
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call enable()", e);
- }
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
-
- if (!mEnable) {
- waitForState(Set.of(BluetoothAdapter.STATE_ON));
- handleDisable();
- waitForState(Set.of(BluetoothAdapter.STATE_OFF,
- BluetoothAdapter.STATE_TURNING_ON,
- BluetoothAdapter.STATE_TURNING_OFF,
- BluetoothAdapter.STATE_BLE_TURNING_ON,
- BluetoothAdapter.STATE_BLE_ON,
- BluetoothAdapter.STATE_BLE_TURNING_OFF));
- }
- break;
- }
- case MESSAGE_BLUETOOTH_STATE_CHANGE: {
- int prevState = msg.arg1;
- int newState = msg.arg2;
- if (DBG) {
- Slog.d(TAG,
- "MESSAGE_BLUETOOTH_STATE_CHANGE: " + BluetoothAdapter.nameForState(
- prevState) + " > " + BluetoothAdapter.nameForState(
- newState));
- }
- mState = newState;
- bluetoothStateChangeHandler(prevState, newState);
- // handle error state transition case from TURNING_ON to OFF
- // unbind and rebind bluetooth service and enable bluetooth
- if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) && (newState
- == BluetoothAdapter.STATE_OFF) && (mBluetooth != null) && mEnable) {
- recoverBluetoothServiceFromError(false);
- }
- if ((prevState == BluetoothAdapter.STATE_TURNING_ON) && (newState
- == BluetoothAdapter.STATE_BLE_ON) && (mBluetooth != null) && mEnable) {
- recoverBluetoothServiceFromError(true);
- }
- // If we tried to enable BT while BT was in the process of shutting down,
- // wait for the BT process to fully tear down and then force a restart
- // here. This is a bit of a hack (b/29363429).
- if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) && (newState
- == BluetoothAdapter.STATE_OFF)) {
- if (mEnable) {
- Slog.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting.");
- waitForState(Set.of(BluetoothAdapter.STATE_OFF));
- Message restartMsg =
- mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
- }
- }
- if (newState == BluetoothAdapter.STATE_ON
- || newState == BluetoothAdapter.STATE_BLE_ON) {
- // bluetooth is working, reset the counter
- if (mErrorRecoveryRetryCounter != 0) {
- Slog.w(TAG, "bluetooth is recovered from error");
- mErrorRecoveryRetryCounter = 0;
- }
- }
- break;
- }
- case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: {
- Slog.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED(" + msg.arg1 + ")");
- try {
- mBluetoothLock.writeLock().lock();
- if (msg.arg1 == SERVICE_IBLUETOOTH) {
- // if service is unbinded already, do nothing and return
- if (mBluetooth == null) {
- break;
- }
- mBluetooth = null;
- } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
- mBluetoothGatt = null;
- break;
- } else {
- Slog.e(TAG, "Unknown argument for service disconnect!");
- break;
- }
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
-
- // log the unexpected crash
- addCrashLog();
- addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH,
- mContext.getPackageName(), false);
- if (mEnable) {
- mEnable = false;
- // Send a Bluetooth Restart message
- Message restartMsg =
- mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
- }
-
- sendBluetoothServiceDownCallback();
-
- // Send BT state broadcast to update
- // the BT icon correctly
- if ((mState == BluetoothAdapter.STATE_TURNING_ON) || (mState
- == BluetoothAdapter.STATE_ON)) {
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
- BluetoothAdapter.STATE_TURNING_OFF);
- mState = BluetoothAdapter.STATE_TURNING_OFF;
- }
- if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
- BluetoothAdapter.STATE_OFF);
- }
-
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
- mState = BluetoothAdapter.STATE_OFF;
- break;
- }
- case MESSAGE_RESTART_BLUETOOTH_SERVICE: {
- mErrorRecoveryRetryCounter++;
- Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE: retry count="
- + mErrorRecoveryRetryCounter);
- if (mErrorRecoveryRetryCounter < MAX_ERROR_RESTART_RETRIES) {
- /* Enable without persisting the setting as
- it doesnt change when IBluetooth
- service restarts */
- mEnable = true;
- addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED,
- mContext.getPackageName(), true);
- handleEnable(mQuietEnable);
- } else {
- Slog.e(TAG, "Reach maximum retry to restart Bluetooth!");
- }
- break;
- }
- case MESSAGE_TIMEOUT_BIND: {
- Slog.e(TAG, "MESSAGE_TIMEOUT_BIND");
- mBluetoothLock.writeLock().lock();
- mBinding = false;
- mBluetoothLock.writeLock().unlock();
- break;
- }
- case MESSAGE_TIMEOUT_UNBIND: {
- Slog.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
- mBluetoothLock.writeLock().lock();
- mUnbinding = false;
- mBluetoothLock.writeLock().unlock();
- break;
- }
-
- case MESSAGE_USER_SWITCHED: {
- if (DBG) {
- Slog.d(TAG, "MESSAGE_USER_SWITCHED");
- }
- mHandler.removeMessages(MESSAGE_USER_SWITCHED);
-
- /* disable and enable BT when detect a user switch */
- if (mBluetooth != null && isEnabled()) {
- restartForReason(BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH);
- } else if (mBinding || mBluetooth != null) {
- Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
- userMsg.arg2 = 1 + msg.arg2;
- // if user is switched when service is binding retry after a delay
- mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
- if (DBG) {
- Slog.d(TAG, "Retry MESSAGE_USER_SWITCHED " + userMsg.arg2);
- }
- }
- break;
- }
- case MESSAGE_USER_UNLOCKED: {
- if (DBG) {
- Slog.d(TAG, "MESSAGE_USER_UNLOCKED");
- }
- mHandler.removeMessages(MESSAGE_USER_SWITCHED);
-
- if (mEnable && !mBinding && (mBluetooth == null)) {
- // We should be connected, but we gave up for some
- // reason; maybe the Bluetooth service wasn't encryption
- // aware, so try binding again.
- if (DBG) {
- Slog.d(TAG, "Enabled but not bound; retrying after unlock");
- }
- handleEnable(mQuietEnable);
- }
- break;
- }
- case MESSAGE_INIT_FLAGS_CHANGED: {
- if (DBG) {
- Slog.d(TAG, "MESSAGE_INIT_FLAGS_CHANGED");
- }
- mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED);
- if (mBluetoothModeChangeHelper.isMediaProfileConnected()) {
- Slog.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by "
- + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS
- + " ms due to existing connections");
- mHandler.sendEmptyMessageDelayed(
- MESSAGE_INIT_FLAGS_CHANGED,
- DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS);
- break;
- }
- if (!isDeviceProvisioned()) {
- Slog.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by "
- + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS
- + "ms because device is not provisioned");
- mHandler.sendEmptyMessageDelayed(
- MESSAGE_INIT_FLAGS_CHANGED,
- DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS);
- break;
- }
- if (mBluetooth != null && isEnabled()) {
- Slog.i(TAG, "Restarting Bluetooth due to init flag change");
- restartForReason(
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED);
- }
- break;
- }
- }
- }
-
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED
- })
- private void restartForReason(int reason) {
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- mBluetooth.unregisterCallback(mBluetoothCallback,
- mContext.getAttributionSource());
- }
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to unregister", re);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
- // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
- bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
- mState = BluetoothAdapter.STATE_OFF;
- }
- if (mState == BluetoothAdapter.STATE_OFF) {
- bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
- mState = BluetoothAdapter.STATE_TURNING_ON;
- }
-
- waitForState(Set.of(BluetoothAdapter.STATE_ON));
-
- if (mState == BluetoothAdapter.STATE_TURNING_ON) {
- bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
- }
-
- unbindAllBluetoothProfileServices();
- // disable
- addActiveLog(reason, mContext.getPackageName(), false);
- handleDisable();
- // Pbap service need receive STATE_TURNING_OFF intent to close
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
- BluetoothAdapter.STATE_TURNING_OFF);
-
- boolean didDisableTimeout =
- !waitForState(Set.of(BluetoothAdapter.STATE_OFF));
-
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
- BluetoothAdapter.STATE_OFF);
- sendBluetoothServiceDownCallback();
-
- try {
- mBluetoothLock.writeLock().lock();
- if (mBluetooth != null) {
- mBluetooth = null;
- // Unbind
- mContext.unbindService(mConnection);
- }
- mBluetoothGatt = null;
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
-
- //
- // If disabling Bluetooth times out, wait for an
- // additional amount of time to ensure the process is
- // shut down completely before attempting to restart.
- //
- if (didDisableTimeout) {
- SystemClock.sleep(3000);
- } else {
- SystemClock.sleep(100);
- }
-
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
- mState = BluetoothAdapter.STATE_OFF;
- // enable
- addActiveLog(reason, mContext.getPackageName(), true);
- // mEnable flag could have been reset on disableBLE. Reenable it.
- mEnable = true;
- handleEnable(mQuietEnable);
- }
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private void handleEnable(boolean quietMode) {
- mQuietEnable = quietMode;
-
- try {
- mBluetoothLock.writeLock().lock();
- if ((mBluetooth == null) && (!mBinding)) {
- Slog.d(TAG, "binding Bluetooth service");
- //Start bind timeout and bind
- Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
- mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
- Intent i = new Intent(IBluetooth.class.getName());
- if (!doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
- UserHandle.CURRENT)) {
- mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
- } else {
- mBinding = true;
- }
- } else if (mBluetooth != null) {
- //Enable bluetooth
- try {
- if (!mBluetooth.enable(mQuietEnable, mContext.getAttributionSource())) {
- Slog.e(TAG, "IBluetooth.enable() returned false");
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call enable()", e);
- }
- }
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
- }
-
- boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
- ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
- intent.setComponent(comp);
- if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
- Slog.e(TAG, "Fail to bind to: " + intent);
- return false;
- }
- return true;
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private void handleDisable() {
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- if (DBG) {
- Slog.d(TAG, "Sending off request.");
- }
- if (!mBluetooth.disable(mContext.getAttributionSource())) {
- Slog.e(TAG, "IBluetooth.disable() returned false");
- }
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call disable()", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- }
-
- private boolean checkIfCallerIsForegroundUser() {
- int foregroundUser;
- int callingUser = UserHandle.getCallingUserId();
- int callingUid = Binder.getCallingUid();
- final long callingIdentity = Binder.clearCallingIdentity();
- UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- UserInfo ui = um.getProfileParent(callingUser);
- int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
- int callingAppId = UserHandle.getAppId(callingUid);
- boolean valid = false;
- try {
- foregroundUser = ActivityManager.getCurrentUser();
- valid = (callingUser == foregroundUser) || parentUser == foregroundUser
- || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid
- || callingAppId == Process.SHELL_UID;
- if (DBG && !valid) {
- Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid + " callingUser="
- + callingUser + " parentUser=" + parentUser + " foregroundUser="
- + foregroundUser);
- }
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
- return valid;
- }
-
- private void sendBleStateChanged(int prevState, int newState) {
- if (DBG) {
- Slog.d(TAG,
- "Sending BLE State Change: " + BluetoothAdapter.nameForState(prevState) + " > "
- + BluetoothAdapter.nameForState(newState));
- }
- // Send broadcast message to everyone else
- Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
- intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
- intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL, null, getTempAllowlistBroadcastOptions());
- }
-
- private boolean isBleState(int state) {
- switch (state) {
- case BluetoothAdapter.STATE_BLE_ON:
- case BluetoothAdapter.STATE_BLE_TURNING_ON:
- case BluetoothAdapter.STATE_BLE_TURNING_OFF:
- return true;
- }
- return false;
- }
-
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- private void bluetoothStateChangeHandler(int prevState, int newState) {
- boolean isStandardBroadcast = true;
- if (prevState == newState) { // No change. Nothing to do.
- return;
- }
- // Notify all proxy objects first of adapter state change
- if (newState == BluetoothAdapter.STATE_BLE_ON || newState == BluetoothAdapter.STATE_OFF) {
- boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
- && newState == BluetoothAdapter.STATE_BLE_ON);
-
- if (newState == BluetoothAdapter.STATE_OFF) {
- // If Bluetooth is off, send service down event to proxy objects, and unbind
- if (DBG) {
- Slog.d(TAG, "Bluetooth is complete send Service Down");
- }
- sendBluetoothServiceDownCallback();
- unbindAndFinish();
- sendBleStateChanged(prevState, newState);
-
- /* Currently, the OFF intent is broadcasted externally only when we transition
- * from TURNING_OFF to BLE_ON state. So if the previous state is a BLE state,
- * we are guaranteed that the OFF intent has been broadcasted earlier and we
- * can safely skip it.
- * Conversely, if the previous state is not a BLE state, it indicates that some
- * sort of crash has occurred, moving us directly to STATE_OFF without ever
- * passing through BLE_ON. We should broadcast the OFF intent in this case. */
- isStandardBroadcast = !isBleState(prevState);
-
- } else if (!intermediate_off) {
- // connect to GattService
- if (DBG) {
- Slog.d(TAG, "Bluetooth is in LE only mode");
- }
- if (mBluetoothGatt != null || !mContext.getPackageManager()
- .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
- continueFromBleOnState();
- } else {
- if (DBG) {
- Slog.d(TAG, "Binding Bluetooth GATT service");
- }
- Intent i = new Intent(IBluetoothGatt.class.getName());
- doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
- UserHandle.CURRENT);
- }
- sendBleStateChanged(prevState, newState);
- //Don't broadcase this as std intent
- isStandardBroadcast = false;
-
- } else if (intermediate_off) {
- if (DBG) {
- Slog.d(TAG, "Intermediate off, back to LE only mode");
- }
- // For LE only mode, broadcast as is
- sendBleStateChanged(prevState, newState);
- sendBluetoothStateCallback(false); // BT is OFF for general users
- // Broadcast as STATE_OFF
- newState = BluetoothAdapter.STATE_OFF;
- sendBrEdrDownCallback(mContext.getAttributionSource());
- }
- } else if (newState == BluetoothAdapter.STATE_ON) {
- boolean isUp = (newState == BluetoothAdapter.STATE_ON);
- sendBluetoothStateCallback(isUp);
- sendBleStateChanged(prevState, newState);
-
- } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON
- || newState == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
- sendBleStateChanged(prevState, newState);
- isStandardBroadcast = false;
-
- } else if (newState == BluetoothAdapter.STATE_TURNING_ON
- || newState == BluetoothAdapter.STATE_TURNING_OFF) {
- sendBleStateChanged(prevState, newState);
- }
-
- if (isStandardBroadcast) {
- if (prevState == BluetoothAdapter.STATE_BLE_ON) {
- // Show prevState of BLE_ON as OFF to standard users
- prevState = BluetoothAdapter.STATE_OFF;
- }
- if (DBG) {
- Slog.d(TAG,
- "Sending State Change: " + BluetoothAdapter.nameForState(prevState) + " > "
- + BluetoothAdapter.nameForState(newState));
- }
- Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
- intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
- intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL, null,
- getTempAllowlistBroadcastOptions());
- }
- }
-
- private boolean waitForState(Set<Integer> states) {
- int i = 0;
- while (i < 10) {
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth == null) {
- break;
- }
- if (states.contains(mBluetooth.getState())) {
- return true;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "getState()", e);
- break;
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- SystemClock.sleep(300);
- i++;
- }
- Slog.e(TAG, "waitForState " + states + " time out");
- return false;
- }
-
- private void sendDisableMsg(int reason, String packageName) {
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
- addActiveLog(reason, packageName, false);
- }
-
- private void sendEnableMsg(boolean quietMode, int reason, String packageName) {
- sendEnableMsg(quietMode, reason, packageName, false);
- }
-
- private void sendEnableMsg(boolean quietMode, int reason, String packageName, boolean isBle) {
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0,
- isBle ? 1 : 0));
- addActiveLog(reason, packageName, true);
- mLastEnabledTime = SystemClock.elapsedRealtime();
- }
-
- private void addActiveLog(int reason, String packageName, boolean enable) {
- synchronized (mActiveLogs) {
- if (mActiveLogs.size() > ACTIVE_LOG_MAX_SIZE) {
- mActiveLogs.remove();
- }
- mActiveLogs.add(
- new ActiveLog(reason, packageName, enable, System.currentTimeMillis()));
- }
-
- int state = enable ? FrameworkStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED :
- FrameworkStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED;
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED,
- Binder.getCallingUid(), null, state, reason, packageName);
- }
-
- private void addCrashLog() {
- synchronized (mCrashTimestamps) {
- if (mCrashTimestamps.size() == CRASH_LOG_MAX_SIZE) {
- mCrashTimestamps.removeFirst();
- }
- mCrashTimestamps.add(System.currentTimeMillis());
- mCrashes++;
- }
- }
-
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- private void recoverBluetoothServiceFromError(boolean clearBle) {
- Slog.e(TAG, "recoverBluetoothServiceFromError");
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- //Unregister callback object
- mBluetooth.unregisterCallback(mBluetoothCallback, mContext.getAttributionSource());
- }
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to unregister", re);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- SystemClock.sleep(500);
-
- // disable
- addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_START_ERROR,
- mContext.getPackageName(), false);
- handleDisable();
-
- waitForState(Set.of(BluetoothAdapter.STATE_OFF));
-
- sendBluetoothServiceDownCallback();
-
- try {
- mBluetoothLock.writeLock().lock();
- if (mBluetooth != null) {
- mBluetooth = null;
- // Unbind
- mContext.unbindService(mConnection);
- }
- mBluetoothGatt = null;
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
-
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
- mState = BluetoothAdapter.STATE_OFF;
-
- if (clearBle) {
- clearBleApps();
- }
-
- mEnable = false;
-
- // Send a Bluetooth Restart message to reenable bluetooth
- Message restartMsg = mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
- }
-
- private boolean isBluetoothDisallowed() {
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- return mContext.getSystemService(UserManager.class)
- .hasUserRestriction(UserManager.DISALLOW_BLUETOOTH, UserHandle.SYSTEM);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
- }
-
- /**
- * Disables BluetoothOppLauncherActivity component, so the Bluetooth sharing option is not
- * offered to the user if Bluetooth or sharing is disallowed. Puts the component to its default
- * state if Bluetooth is not disallowed.
- *
- * @param userId user to disable bluetooth sharing for.
- * @param bluetoothSharingDisallowed whether bluetooth sharing is disallowed.
- */
- private void updateOppLauncherComponentState(int userId, boolean bluetoothSharingDisallowed) {
- final ComponentName oppLauncherComponent = new ComponentName("com.android.bluetooth",
- "com.android.bluetooth.opp.BluetoothOppLauncherActivity");
- final int newState =
- bluetoothSharingDisallowed ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED
- : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
- try {
- final IPackageManager imp = AppGlobals.getPackageManager();
- imp.setComponentEnabledSetting(oppLauncherComponent, newState,
- PackageManager.DONT_KILL_APP, userId);
- } catch (Exception e) {
- // The component was not found, do nothing.
- }
- }
-
- private int getServiceRestartMs() {
- return (mErrorRecoveryRetryCounter + 1) * SERVICE_RESTART_TIME_MS;
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) {
- return;
- }
- if ((args.length > 0) && args[0].startsWith("--proto")) {
- dumpProto(fd);
- return;
- }
- String errorMsg = null;
-
- 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 = SystemClock.elapsedRealtime() - mLastEnabledTime;
- String onDurationString = String.format(Locale.US, "%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);
- }
-
- if (mActiveLogs.size() == 0) {
- writer.println("\nBluetooth never enabled!");
- } else {
- writer.println("\nEnable log:");
- for (ActiveLog log : mActiveLogs) {
- writer.println(" " + log);
- }
- }
-
- writer.println(
- "\nBluetooth crashed " + mCrashes + " time" + (mCrashes == 1 ? "" : "s"));
- if (mCrashes == CRASH_LOG_MAX_SIZE) {
- writer.println("(last " + CRASH_LOG_MAX_SIZE + ")");
- }
- for (Long time : mCrashTimestamps) {
- writer.println(" " + timeToLog(time));
- }
-
- writer.println("\n" + mBleApps.size() + " BLE app" + (mBleApps.size() == 1 ? "" : "s")
- + " registered");
- for (ClientDeathRecipient app : mBleApps.values()) {
- writer.println(" " + app.getPackageName());
- }
-
- writer.println("\nBluetoothManagerService:");
- writer.println(" mEnable:" + mEnable);
- writer.println(" mQuietEnable:" + mQuietEnable);
- writer.println(" mEnableExternal:" + mEnableExternal);
- writer.println(" mQuietEnableExternal:" + mQuietEnableExternal);
-
- writer.println("");
- writer.flush();
- if (args.length == 0) {
- // Add arg to produce output
- args = new String[1];
- args[0] = "--print";
- }
-
- if (mBluetoothBinder == null) {
- errorMsg = "Bluetooth Service not connected";
- } else {
- try {
- mBluetoothBinder.dump(fd, args);
- } catch (RemoteException re) {
- errorMsg = "RemoteException while dumping Bluetooth Service";
- }
- }
- if (errorMsg != null) {
- writer.println(errorMsg);
- }
- }
-
- private void dumpProto(FileDescriptor fd) {
- final ProtoOutputStream proto = new ProtoOutputStream(fd);
- proto.write(BluetoothManagerServiceDumpProto.ENABLED, isEnabled());
- proto.write(BluetoothManagerServiceDumpProto.STATE, mState);
- proto.write(BluetoothManagerServiceDumpProto.STATE_NAME,
- BluetoothAdapter.nameForState(mState));
- proto.write(BluetoothManagerServiceDumpProto.ADDRESS, mAddress);
- proto.write(BluetoothManagerServiceDumpProto.NAME, mName);
- if (mEnable) {
- proto.write(BluetoothManagerServiceDumpProto.LAST_ENABLED_TIME_MS, mLastEnabledTime);
- }
- proto.write(BluetoothManagerServiceDumpProto.CURR_TIMESTAMP_MS,
- SystemClock.elapsedRealtime());
- for (ActiveLog log : mActiveLogs) {
- long token = proto.start(BluetoothManagerServiceDumpProto.ACTIVE_LOGS);
- log.dump(proto);
- proto.end(token);
- }
- proto.write(BluetoothManagerServiceDumpProto.NUM_CRASHES, mCrashes);
- proto.write(BluetoothManagerServiceDumpProto.CRASH_LOG_MAXED,
- mCrashes == CRASH_LOG_MAX_SIZE);
- for (Long time : mCrashTimestamps) {
- proto.write(BluetoothManagerServiceDumpProto.CRASH_TIMESTAMPS_MS, time);
- }
- proto.write(BluetoothManagerServiceDumpProto.NUM_BLE_APPS, mBleApps.size());
- for (ClientDeathRecipient app : mBleApps.values()) {
- proto.write(BluetoothManagerServiceDumpProto.BLE_APP_PACKAGE_NAMES,
- app.getPackageName());
- }
- proto.flush();
- }
-
- private static String getEnableDisableReasonString(int reason) {
- switch (reason) {
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST:
- return "APPLICATION_REQUEST";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE:
- return "AIRPLANE_MODE";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED:
- return "DISALLOWED";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED:
- return "RESTARTED";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_START_ERROR:
- return "START_ERROR";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT:
- return "SYSTEM_BOOT";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH:
- return "CRASH";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH:
- return "USER_SWITCH";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING:
- return "RESTORE_USER_SETTING";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET:
- return "FACTORY_RESET";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED:
- return "INIT_FLAGS_CHANGED";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_UNSPECIFIED:
- default: return "UNKNOWN[" + reason + "]";
- }
- }
-
- @SuppressLint("AndroidFrameworkRequiresPermission")
- private static boolean checkPermissionForDataDelivery(Context context, String permission,
- AttributionSource attributionSource, String message) {
- PermissionManager pm = context.getSystemService(PermissionManager.class);
- if (pm == null) {
- return false;
- }
- AttributionSource currentAttribution = new AttributionSource
- .Builder(context.getAttributionSource())
- .setNext(attributionSource)
- .build();
- final int result = pm.checkPermissionForDataDeliveryFromDataSource(permission,
- currentAttribution, message);
- if (result == PERMISSION_GRANTED) {
- return true;
- }
-
- final String msg = "Need " + permission + " permission for " + attributionSource + ": "
- + message;
- if (result == PERMISSION_HARD_DENIED) {
- throw new SecurityException(msg);
- } else {
- Log.w(TAG, msg);
- return false;
- }
- }
-
- /**
- * Returns true if the BLUETOOTH_CONNECT permission is granted for the calling app. Returns
- * false if the result is a soft denial. Throws SecurityException if the result is a hard
- * denial.
- *
- * <p>Should be used in situations where the app op should not be noted.
- */
- @SuppressLint("AndroidFrameworkRequiresPermission")
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public static boolean checkConnectPermissionForDataDelivery(
- Context context, AttributionSource attributionSource, String message) {
- return checkPermissionForDataDelivery(context, BLUETOOTH_CONNECT,
- attributionSource, message);
- }
-
- static @NonNull Bundle getTempAllowlistBroadcastOptions() {
- final long duration = 10_000;
- final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
- bOptions.setTemporaryAppAllowlist(duration,
- TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
- PowerExemptionManager.REASON_BLUETOOTH_BROADCAST, "");
- return bOptions.toBundle();
- }
-}
diff --git a/services/core/java/com/android/server/BluetoothModeChangeHelper.java b/services/core/java/com/android/server/BluetoothModeChangeHelper.java
deleted file mode 100644
index e5854c9..0000000
--- a/services/core/java/com/android/server/BluetoothModeChangeHelper.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.annotation.RequiresPermission;
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothHearingAid;
-import android.bluetooth.BluetoothLeAudio;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothProfile.ServiceListener;
-import android.content.Context;
-import android.content.res.Resources;
-import android.provider.Settings;
-import android.widget.Toast;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Helper class that handles callout and callback methods without
- * complex logic.
- */
-public class BluetoothModeChangeHelper {
- private volatile BluetoothA2dp mA2dp;
- private volatile BluetoothHearingAid mHearingAid;
- private volatile BluetoothLeAudio mLeAudio;
- private final BluetoothAdapter mAdapter;
- private final Context mContext;
-
- BluetoothModeChangeHelper(Context context) {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
- mContext = context;
-
- mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP);
- mAdapter.getProfileProxy(mContext, mProfileServiceListener,
- BluetoothProfile.HEARING_AID);
- mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.LE_AUDIO);
- }
-
- private final ServiceListener mProfileServiceListener = new ServiceListener() {
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- // Setup Bluetooth profile proxies
- switch (profile) {
- case BluetoothProfile.A2DP:
- mA2dp = (BluetoothA2dp) proxy;
- break;
- case BluetoothProfile.HEARING_AID:
- mHearingAid = (BluetoothHearingAid) proxy;
- break;
- case BluetoothProfile.LE_AUDIO:
- mLeAudio = (BluetoothLeAudio) proxy;
- break;
- default:
- break;
- }
- }
-
- @Override
- public void onServiceDisconnected(int profile) {
- // Clear Bluetooth profile proxies
- switch (profile) {
- case BluetoothProfile.A2DP:
- mA2dp = null;
- break;
- case BluetoothProfile.HEARING_AID:
- mHearingAid = null;
- break;
- case BluetoothProfile.LE_AUDIO:
- mLeAudio = null;
- break;
- default:
- break;
- }
- }
- };
-
- @VisibleForTesting
- public boolean isMediaProfileConnected() {
- return isA2dpConnected() || isHearingAidConnected() || isLeAudioConnected();
- }
-
- @VisibleForTesting
- public boolean isBluetoothOn() {
- final BluetoothAdapter adapter = mAdapter;
- if (adapter == null) {
- return false;
- }
- return adapter.getLeState() == BluetoothAdapter.STATE_ON;
- }
-
- @VisibleForTesting
- public boolean isAirplaneModeOn() {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
- }
-
- @VisibleForTesting
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void onAirplaneModeChanged(BluetoothManagerService managerService) {
- managerService.onAirplaneModeChanged();
- }
-
- @VisibleForTesting
- public int getSettingsInt(String name) {
- return Settings.Global.getInt(mContext.getContentResolver(),
- name, 0);
- }
-
- @VisibleForTesting
- public void setSettingsInt(String name, int value) {
- Settings.Global.putInt(mContext.getContentResolver(),
- name, value);
- }
-
- @VisibleForTesting
- public void showToastMessage() {
- Resources r = mContext.getResources();
- final CharSequence text = r.getString(
- R.string.bluetooth_airplane_mode_toast, 0);
- Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
- }
-
- private boolean isA2dpConnected() {
- final BluetoothA2dp a2dp = mA2dp;
- if (a2dp == null) {
- return false;
- }
- return a2dp.getConnectedDevices().size() > 0;
- }
-
- private boolean isHearingAidConnected() {
- final BluetoothHearingAid hearingAid = mHearingAid;
- if (hearingAid == null) {
- return false;
- }
- return hearingAid.getConnectedDevices().size() > 0;
- }
-
- private boolean isLeAudioConnected() {
- final BluetoothLeAudio leAudio = mLeAudio;
- if (leAudio == null) {
- return false;
- }
- return leAudio.getConnectedDevices().size() > 0;
- }
-}
diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java
deleted file mode 100644
index 1a1eecd..0000000
--- a/services/core/java/com/android/server/BluetoothService.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.bluetooth.BluetoothAdapter;
-import android.content.Context;
-import android.os.UserManager;
-
-import com.android.server.SystemService.TargetUser;
-
-class BluetoothService extends SystemService {
- private BluetoothManagerService mBluetoothManagerService;
- private boolean mInitialized = false;
-
- public BluetoothService(Context context) {
- super(context);
- mBluetoothManagerService = new BluetoothManagerService(context);
- }
-
- private void initialize() {
- if (!mInitialized) {
- mBluetoothManagerService.handleOnBootPhase();
- mInitialized = true;
- }
- }
-
- @Override
- public void onStart() {
- }
-
- @Override
- public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
- publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE,
- mBluetoothManagerService);
- } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY &&
- !UserManager.isHeadlessSystemUserMode()) {
- initialize();
- }
- }
-
- @Override
- public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
- if (!mInitialized) {
- initialize();
- } else {
- mBluetoothManagerService.handleOnSwitchUser(to.getUserIdentifier());
- }
- }
-
- @Override
- public void onUserUnlocking(@NonNull TargetUser user) {
- mBluetoothManagerService.handleOnUnlockUser(user.getUserIdentifier());
- }
-}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index c3a364e..171af77 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -25,6 +25,7 @@
"test-apps/JobTestApp/src/**/*.java",
"test-apps/SuspendTestApp/src/**/*.java",
+ ":service-bluetooth-tests-sources", // TODO(b/214988855) : Remove once framework-bluetooth jar is ready
],
static_libs: [
"frameworks-base-testutils",
diff --git a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java b/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java
deleted file mode 100644
index a1d4c20..0000000
--- a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static org.mockito.Mockito.*;
-
-import android.bluetooth.BluetoothAdapter;
-import android.content.Context;
-import android.os.Looper;
-import android.provider.Settings;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class BluetoothAirplaneModeListenerTest {
- private Context mContext;
- private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener;
- private BluetoothAdapter mBluetoothAdapter;
- private BluetoothModeChangeHelper mHelper;
-
- @Mock BluetoothManagerService mBluetoothManagerService;
-
- @Before
- public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getTargetContext();
-
- mHelper = mock(BluetoothModeChangeHelper.class);
- when(mHelper.getSettingsInt(BluetoothAirplaneModeListener.TOAST_COUNT))
- .thenReturn(BluetoothAirplaneModeListener.MAX_TOAST_COUNT);
- doNothing().when(mHelper).setSettingsInt(anyString(), anyInt());
- doNothing().when(mHelper).showToastMessage();
- doNothing().when(mHelper).onAirplaneModeChanged(any(BluetoothManagerService.class));
-
- mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener(
- mBluetoothManagerService, Looper.getMainLooper(), mContext);
- mBluetoothAirplaneModeListener.start(mHelper);
- }
-
- @Test
- public void testIgnoreOnAirplanModeChange() {
- Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
-
- when(mHelper.isBluetoothOn()).thenReturn(true);
- Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
-
- when(mHelper.isMediaProfileConnected()).thenReturn(true);
- Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
-
- when(mHelper.isAirplaneModeOn()).thenReturn(true);
- Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
- }
-
- @Test
- public void testHandleAirplaneModeChange_InvokeAirplaneModeChanged() {
- mBluetoothAirplaneModeListener.handleAirplaneModeChange();
- verify(mHelper).onAirplaneModeChanged(mBluetoothManagerService);
- }
-
- @Test
- public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_NotPopToast() {
- mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT;
- when(mHelper.isBluetoothOn()).thenReturn(true);
- when(mHelper.isMediaProfileConnected()).thenReturn(true);
- when(mHelper.isAirplaneModeOn()).thenReturn(true);
- mBluetoothAirplaneModeListener.handleAirplaneModeChange();
-
- verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON,
- BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
- verify(mHelper, times(0)).showToastMessage();
- verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService);
- }
-
- @Test
- public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_PopToast() {
- mBluetoothAirplaneModeListener.mToastCount = 0;
- when(mHelper.isBluetoothOn()).thenReturn(true);
- when(mHelper.isMediaProfileConnected()).thenReturn(true);
- when(mHelper.isAirplaneModeOn()).thenReturn(true);
- mBluetoothAirplaneModeListener.handleAirplaneModeChange();
-
- verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON,
- BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
- verify(mHelper).showToastMessage();
- verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService);
- }
-
- @Test
- public void testIsPopToast_PopToast() {
- mBluetoothAirplaneModeListener.mToastCount = 0;
- Assert.assertTrue(mBluetoothAirplaneModeListener.shouldPopToast());
- verify(mHelper).setSettingsInt(BluetoothAirplaneModeListener.TOAST_COUNT, 1);
- }
-
- @Test
- public void testIsPopToast_NotPopToast() {
- mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT;
- Assert.assertFalse(mBluetoothAirplaneModeListener.shouldPopToast());
- verify(mHelper, times(0)).setSettingsInt(anyString(), anyInt());
- }
-}