Loading android/app/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ cc_library_shared { static_libs: [ "libbluetooth-types", "libutils", "libcutils", ], cflags: [ "-Wall", Loading android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp +6 −3 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <android_util_Binder.h> #include <base/logging.h> #include <base/strings/stringprintf.h> #include <cutils/properties.h> #include <dlfcn.h> #include <errno.h> #include <pthread.h> Loading Loading @@ -599,14 +600,16 @@ static bt_os_callouts_t sBluetoothOsCallouts = { acquire_wake_lock_callout, release_wake_lock_callout, }; #define BLUETOOTH_LIBRARY_NAME "libbluetooth.so" #define PROPERTY_BT_LIBRARY_NAME "ro.bluetooth.library_name" #define DEFAULT_BT_LIBRARY_NAME "libbluetooth.so" int hal_util_load_bt_library(const bt_interface_t** interface) { const char* sym = BLUETOOTH_INTERFACE_STRING; bt_interface_t* itf = nullptr; // Always try to load the default Bluetooth stack on GN builds. const char* path = BLUETOOTH_LIBRARY_NAME; // The library name is not set by default, so the preset library name is used. char path[PROPERTY_VALUE_MAX] = ""; property_get(PROPERTY_BT_LIBRARY_NAME, path, DEFAULT_BT_LIBRARY_NAME); void* handle = dlopen(path, RTLD_NOW); if (!handle) { const char* err_str = dlerror(); Loading android/app/src/com/android/bluetooth/a2dp/A2dpService.java +12 −11 Original line number Diff line number Diff line Loading @@ -113,18 +113,18 @@ public class A2dpService extends ProfileService { mMaxConnectedAudioDevices = mAdapterService.getMaxConnectedAudioDevices(); Log.i(TAG, "Max connected audio devices set to " + mMaxConnectedAudioDevices); // Step 3: Start handler thread for state machines // Step 3: Setup AVRCP mAvrcp = Avrcp.make(this); // Step 4: Start handler thread for state machines mStateMachines.clear(); mStateMachinesThread = new HandlerThread("A2dpService.StateMachines"); mStateMachinesThread.start(); // Step 4: Setup codec config and clear active device // Step 5: Setup codec config and clear active device mA2dpCodecConfig = new A2dpCodecConfig(this, mA2dpNativeInterface); mActiveDevice = null; // Step 5: Setup AVRCP mAvrcp = Avrcp.make(this); // Step 6: Initialize native interface mA2dpNativeInterface.init(mA2dpCodecConfig.codecConfigPriorities()); Loading Loading @@ -165,15 +165,11 @@ public class A2dpService extends ProfileService { mA2dpNativeInterface.cleanup(); mA2dpNativeInterface = null; // Step 5: Cleanup AVRCP mAvrcp.cleanup(); mAvrcp = null; // Step 4: Clear codec config and active device // Step 5: Clear codec config and active device mA2dpCodecConfig = null; mActiveDevice = null; // Step 3: Destroy state machines and stop handler thread // Step 4: Destroy state machines and stop handler thread synchronized (mStateMachines) { for (A2dpStateMachine sm : mStateMachines.values()) { sm.doQuit(); Loading @@ -184,6 +180,11 @@ public class A2dpService extends ProfileService { mStateMachinesThread.quitSafely(); mStateMachinesThread = null; // Step 3: Cleanup AVRCP mAvrcp.doQuit(); mAvrcp.cleanup(); mAvrcp = null; // Step 2: Reset maximum number of connected audio devices mMaxConnectedAudioDevices = 1; Loading android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java +14 −0 Original line number Diff line number Diff line Loading @@ -686,6 +686,20 @@ final class A2dpStateMachine extends StateMachine { mA2dpService.sendBroadcast(intent, A2dpService.BLUETOOTH_PERM); } @Override protected String getLogRecString(Message msg) { StringBuilder builder = new StringBuilder(); builder.append(messageWhatToString(msg.what)); builder.append(": "); builder.append("arg1=") .append(msg.arg1) .append(", arg2=") .append(msg.arg2) .append(", obj=") .append(msg.obj); return builder.toString(); } private static String messageWhatToString(int what) { switch (what) { case CONNECT: Loading android/app/src/com/android/bluetooth/btservice/AdapterService.java +124 −231 Original line number Diff line number Diff line Loading @@ -78,8 +78,6 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class AdapterService extends Service { private static final String TAG = "BluetoothAdapterService"; Loading @@ -97,7 +95,8 @@ public class AdapterService extends Service { private long mEnergyUsedTotalVoltAmpSecMicro; private final SparseArray<UidTraffic> mUidTraffic = new SparseArray<>(); private final ArrayList<ProfileService> mProfiles = new ArrayList<ProfileService>(); private final ArrayList<ProfileService> mRegisteredProfiles = new ArrayList<>(); private final ArrayList<ProfileService> mRunningProfiles = new ArrayList<>(); public static final String ACTION_LOAD_ADAPTER_PROPERTIES = "com.android.bluetooth.btservice.action.LOAD_ADAPTER_PROPERTIES"; Loading Loading @@ -162,7 +161,6 @@ public class AdapterService extends Service { /* TODO: Consider to remove the search API from this class, if changed to use call-back */ private SdpManager mSdpManager = null; private boolean mProfilesStarted; private boolean mNativeAvailable; private boolean mCleaningUp; private final HashMap<String, Integer> mProfileServicesState = new HashMap<String, Integer>(); Loading @@ -183,129 +181,134 @@ public class AdapterService extends Service { private PhonePolicy mPhonePolicy; private ActiveDeviceManager mActiveDeviceManager; /** * Register a {@link ProfileService} with AdapterService. * * @param profile the service being added. */ public void addProfile(ProfileService profile) { synchronized (mProfiles) { if (!mProfiles.contains(profile)) { mProfiles.add(profile); } } Message m = mHandler.obtainMessage(MESSAGE_PROFILE_SERVICE_REGISTERED, profile); mHandler.sendMessage(m); } /** * Unregister a ProfileService with AdapterService. * * @param profile the service being removed. */ public void removeProfile(ProfileService profile) { synchronized (mProfiles) { mProfiles.remove(profile); } Message m = mHandler.obtainMessage(MESSAGE_PROFILE_SERVICE_UNREGISTERED, profile); mHandler.sendMessage(m); } public void onProfileServiceStateChanged(String serviceName, int state) { /** * Notify AdapterService that a ProfileService has started or stopped. * * @param profile the service being removed. * @param state {@link BluetoothAdapter#STATE_ON} or {@link BluetoothAdapter#STATE_OFF} */ public void onProfileServiceStateChanged(ProfileService profile, int state) { if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) { throw new IllegalArgumentException(BluetoothAdapter.nameForState(state)); } Message m = mHandler.obtainMessage(MESSAGE_PROFILE_SERVICE_STATE_CHANGED); m.obj = serviceName; m.obj = profile; m.arg1 = state; mHandler.sendMessage(m); } private void processProfileServiceStateChanged(String serviceName, int state) { boolean doUpdate = false; boolean isBleTurningOn; boolean isBleTurningOff; boolean isTurningOn; boolean isTurningOff; private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED = 1; private static final int MESSAGE_PROFILE_SERVICE_REGISTERED = 2; private static final int MESSAGE_PROFILE_SERVICE_UNREGISTERED = 3; synchronized (mProfileServicesState) { Integer prevState = mProfileServicesState.get(serviceName); if (prevState != null && prevState != state) { mProfileServicesState.put(serviceName, state); doUpdate = true; } } class AdapterServiceHandler extends Handler { @Override public void handleMessage(Message msg) { debugLog("handleMessage() - Message: " + msg.what); if (!doUpdate) { return; switch (msg.what) { case MESSAGE_PROFILE_SERVICE_STATE_CHANGED: debugLog("handleMessage() - MESSAGE_PROFILE_SERVICE_STATE_CHANGED"); processProfileServiceStateChanged((ProfileService) msg.obj, msg.arg1); break; case MESSAGE_PROFILE_SERVICE_REGISTERED: debugLog("handleMessage() - MESSAGE_PROFILE_SERVICE_REGISTERED"); registerProfileService((ProfileService) msg.obj); break; case MESSAGE_PROFILE_SERVICE_UNREGISTERED: debugLog("handleMessage() - MESSAGE_PROFILE_SERVICE_UNREGISTERED"); unregisterProfileService((ProfileService) msg.obj); break; } synchronized (mAdapterStateMachine) { isTurningOff = mAdapterStateMachine.isTurningOff(); isTurningOn = mAdapterStateMachine.isTurningOn(); isBleTurningOn = mAdapterStateMachine.isBleTurningOn(); isBleTurningOff = mAdapterStateMachine.isBleTurningOff(); } debugLog( "processProfileServiceStateChanged() - serviceName=" + serviceName + " isTurningOn=" + isTurningOn + " isTurningOff=" + isTurningOff + " isBleTurningOn=" + isBleTurningOn + " isBleTurningOff=" + isBleTurningOff); if (isBleTurningOn) { if (GattService.class.getName().equals(serviceName)) { debugLog("GattService is started"); mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BLE_STARTED)); private void registerProfileService(ProfileService profile) { if (mRegisteredProfiles.contains(profile)) { Log.e(TAG, profile.getName() + " already registered."); return; } mRegisteredProfiles.add(profile); } } else if (isBleTurningOff) { if (GattService.class.getName().equals(serviceName)) { debugLog("GattService stopped"); mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BLE_STOPPED)); private void unregisterProfileService(ProfileService profile) { if (!mRegisteredProfiles.contains(profile)) { Log.e(TAG, profile.getName() + " not registered (UNREGISTERED)."); return; } } else if (isTurningOff) { //On to BLE_ON //Process stop or disable pending //Check if all services are stopped if so, do cleanup synchronized (mProfileServicesState) { Iterator<Map.Entry<String, Integer>> i = mProfileServicesState.entrySet().iterator(); while (i.hasNext()) { Map.Entry<String, Integer> entry = i.next(); if (GattService.class.getName().equals(entry.getKey())) { continue; mRegisteredProfiles.remove(profile); } if (BluetoothAdapter.STATE_OFF != entry.getValue()) { debugLog("onProfileServiceStateChange() - Profile still running: " + entry.getKey()); private void processProfileServiceStateChanged(ProfileService profile, int state) { switch (state) { case BluetoothAdapter.STATE_ON: if (!mRegisteredProfiles.contains(profile)) { Log.e(TAG, profile.getName() + " not registered (STATE_ON)."); return; } if (mRunningProfiles.contains(profile)) { Log.e(TAG, profile.getName() + " already running."); return; } mRunningProfiles.add(profile); if (GattService.class.getSimpleName().equals(profile.getName())) { mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BLE_STARTED)); } debugLog("onProfileServiceStateChange() - All profile services stopped..."); //Send message to state machine mProfilesStarted = false; if (mRegisteredProfiles.size() == Config.getSupportedProfiles().length && mRegisteredProfiles.size() == mRunningProfiles.size()) { mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STOPPED)); } else if (isTurningOn) { updateInteropDatabase(); //Process start pending //Check if all services are started if so, update state synchronized (mProfileServicesState) { Iterator<Map.Entry<String, Integer>> i = mProfileServicesState.entrySet().iterator(); while (i.hasNext()) { Map.Entry<String, Integer> entry = i.next(); if (GattService.class.getName().equals(entry.getKey())) { continue; mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STARTED)); } if (BluetoothAdapter.STATE_ON != entry.getValue()) { debugLog( "onProfileServiceStateChange() - Profile still not running:" + entry .getKey()); break; case BluetoothAdapter.STATE_OFF: if (!mRegisteredProfiles.contains(profile)) { Log.e(TAG, profile.getName() + " not registered (STATE_OFF)."); return; } if (!mRunningProfiles.contains(profile)) { Log.e(TAG, profile.getName() + " not running."); return; } mRunningProfiles.remove(profile); // If the last profile was removed, or only GATT is left, send BREDR_STOPPED. if ((mRunningProfiles.size() == 0) || (mRunningProfiles.size() == 1 && (GattService.class.getSimpleName() .equals(mRunningProfiles.get(0).getName())))) { mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STOPPED)); } debugLog("onProfileServiceStateChange() - All profile services started."); mProfilesStarted = true; //Send message to state machine if (mRunningProfiles.size() == 0) { mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STARTED)); mAdapterStateMachine.obtainMessage(AdapterState.BLE_STOPPED)); } break; default: Log.e(TAG, "Unhandled profile state: " + state); } } } private final AdapterServiceHandler mHandler = new AdapterServiceHandler(); private void updateInteropDatabase() { interopDatabaseClearNative(); Loading Loading @@ -486,12 +489,6 @@ public class AdapterService extends Service { Config.init(getApplicationContext()); } Class[] supportedProfileServices = Config.getSupportedProfiles(); //Initialize data objects for (Class service : supportedProfileServices) { mProfileServicesState.put(service.getName(), BluetoothAdapter.STATE_OFF); } // Reset |mRemoteDevices| whenever BLE is turned off then on // This is to replace the fact that |mRemoteDevices| was // reinitialized in previous code. Loading @@ -512,11 +509,11 @@ public class AdapterService extends Service { try { mBatteryStats.noteResetBleScan(); } catch (RemoteException e) { // Ignore. Log.w(TAG, "RemoteException trying to send a reset to BatteryStats"); } //Start Gatt service setGattProfileServiceState(supportedProfileServices, BluetoothAdapter.STATE_ON); setProfileServiceState(GattService.class, BluetoothAdapter.STATE_ON); } /** Loading Loading @@ -548,18 +545,7 @@ public class AdapterService extends Service { void startCoreServices() { debugLog("startCoreServices()"); Class[] supportedProfileServices = Config.getSupportedProfiles(); //Start profile services if (!mProfilesStarted && supportedProfileServices.length > 0 && !(supportedProfileServices.length == 1 && supportedProfileServices[0] == GattService.class)) { //Startup all profile services setProfileServiceState(supportedProfileServices, BluetoothAdapter.STATE_ON); } else { debugLog("startCoreProfiles(): Profile Services alreay started"); mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STARTED)); } setAllProfileServiceStates(supportedProfileServices, BluetoothAdapter.STATE_ON); } void startBluetoothDisable() { Loading @@ -567,26 +553,20 @@ public class AdapterService extends Service { mAdapterStateMachine.obtainMessage(AdapterState.BEGIN_DISABLE)); } boolean stopProfileServices() { void stopProfileServices() { Class[] supportedProfileServices = Config.getSupportedProfiles(); if (mProfilesStarted && supportedProfileServices.length > 0) { setProfileServiceState(supportedProfileServices, BluetoothAdapter.STATE_OFF); return true; } if (mRunningProfiles.size() == 0) { debugLog("stopProfileServices() - No profiles services to stop or already stopped."); return false; return; } setAllProfileServiceStates(supportedProfileServices, BluetoothAdapter.STATE_OFF); } boolean stopGattProfileService() { //TODO: can optimize this instead of looping around all supported profiles debugLog("stopGattProfileService()"); Class[] supportedProfileServices = Config.getSupportedProfiles(); setGattProfileServiceState(supportedProfileServices, BluetoothAdapter.STATE_OFF); setProfileServiceState(GattService.class, BluetoothAdapter.STATE_OFF); return true; } void updateAdapterState(int prevState, int newState) { if (mCallbacks != null) { int n = mCallbacks.beginBroadcast(); Loading Loading @@ -685,103 +665,19 @@ public class AdapterService extends Service { } } private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED = 1; private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { debugLog("handleMessage() - Message: " + msg.what); switch (msg.what) { case MESSAGE_PROFILE_SERVICE_STATE_CHANGED: { debugLog("handleMessage() - MESSAGE_PROFILE_SERVICE_STATE_CHANGED"); processProfileServiceStateChanged((String) msg.obj, msg.arg1); } break; } } }; @SuppressWarnings("rawtypes") private void setGattProfileServiceState(Class[] services, int state) { if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) { Log.w(TAG, "setGattProfileServiceState(): invalid state...Leaving..."); return; } int expectedCurrentState = BluetoothAdapter.STATE_OFF; int pendingState = BluetoothAdapter.STATE_TURNING_ON; if (state == BluetoothAdapter.STATE_OFF) { expectedCurrentState = BluetoothAdapter.STATE_ON; pendingState = BluetoothAdapter.STATE_TURNING_OFF; } for (Class service : services) { String serviceName = service.getName(); String simpleName = service.getSimpleName(); if (GattService.class.getSimpleName().equals(simpleName)) { Integer serviceState = mProfileServicesState.get(serviceName); if (serviceState != null && serviceState != expectedCurrentState) { debugLog("setProfileServiceState() - Unable to " + ( state == BluetoothAdapter.STATE_OFF ? "start" : "stop") + " service " + serviceName + ". Invalid state: " + serviceState); continue; } debugLog("setProfileServiceState() - " + (state == BluetoothAdapter.STATE_OFF ? "Stopping" : "Starting") + " service " + serviceName); mProfileServicesState.put(serviceName, pendingState); private void setProfileServiceState(Class service, int state) { Intent intent = new Intent(this, service); intent.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED); intent.putExtra(BluetoothAdapter.EXTRA_STATE, state); startService(intent); return; } } } @SuppressWarnings("rawtypes") private void setProfileServiceState(Class[] services, int state) { if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) { debugLog("setProfileServiceState() - Invalid state, leaving..."); return; } int expectedCurrentState = BluetoothAdapter.STATE_OFF; int pendingState = BluetoothAdapter.STATE_TURNING_ON; if (state == BluetoothAdapter.STATE_OFF) { expectedCurrentState = BluetoothAdapter.STATE_ON; pendingState = BluetoothAdapter.STATE_TURNING_OFF; } private void setAllProfileServiceStates(Class[] services, int state) { for (Class service : services) { String serviceName = service.getName(); String simpleName = service.getSimpleName(); if (GattService.class.getSimpleName().equals(simpleName)) { continue; } Integer serviceState = mProfileServicesState.get(serviceName); if (serviceState != null && serviceState != expectedCurrentState) { debugLog("setProfileServiceState() - Unable to " + ( state == BluetoothAdapter.STATE_OFF ? "start" : "stop") + " service " + serviceName + ". Invalid state: " + serviceState); if (GattService.class.getSimpleName().equals(service.getSimpleName())) { continue; } debugLog("setProfileServiceState() - " + (state == BluetoothAdapter.STATE_OFF ? "Stopping" : "Starting") + " service " + serviceName); mProfileServicesState.put(serviceName, pendingState); Intent intent = new Intent(this, service); intent.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED); intent.putExtra(BluetoothAdapter.EXTRA_STATE, state); startService(intent); setProfileServiceState(service, state); } } Loading Loading @@ -2496,13 +2392,10 @@ public class AdapterService extends Service { + device.getName()); } // Dump profile information StringBuilder sb = new StringBuilder(); synchronized (mProfiles) { for (ProfileService profile : mProfiles) { for (ProfileService profile : mRegisteredProfiles) { profile.dump(sb); } } writer.write(sb.toString()); writer.flush(); Loading @@ -2513,7 +2406,7 @@ public class AdapterService extends Service { private void dumpMetrics(FileDescriptor fd) { BluetoothProto.BluetoothLog metrics = new BluetoothProto.BluetoothLog(); metrics.setNumBondedDevices(getBondedDevices().length); for (ProfileService profile : mProfiles) { for (ProfileService profile : mRegisteredProfiles) { profile.dumpProto(metrics); } byte[] nativeMetricsBytes = dumpMetricsNative(); Loading Loading @@ -2563,9 +2456,9 @@ public class AdapterService extends Service { private static native void classInitNative(); private native boolean initNative(); native boolean initNative(); private native void cleanupNative(); native void cleanupNative(); /*package*/ native boolean enableNative(boolean startRestricted); Loading Loading
android/app/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ cc_library_shared { static_libs: [ "libbluetooth-types", "libutils", "libcutils", ], cflags: [ "-Wall", Loading
android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp +6 −3 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <android_util_Binder.h> #include <base/logging.h> #include <base/strings/stringprintf.h> #include <cutils/properties.h> #include <dlfcn.h> #include <errno.h> #include <pthread.h> Loading Loading @@ -599,14 +600,16 @@ static bt_os_callouts_t sBluetoothOsCallouts = { acquire_wake_lock_callout, release_wake_lock_callout, }; #define BLUETOOTH_LIBRARY_NAME "libbluetooth.so" #define PROPERTY_BT_LIBRARY_NAME "ro.bluetooth.library_name" #define DEFAULT_BT_LIBRARY_NAME "libbluetooth.so" int hal_util_load_bt_library(const bt_interface_t** interface) { const char* sym = BLUETOOTH_INTERFACE_STRING; bt_interface_t* itf = nullptr; // Always try to load the default Bluetooth stack on GN builds. const char* path = BLUETOOTH_LIBRARY_NAME; // The library name is not set by default, so the preset library name is used. char path[PROPERTY_VALUE_MAX] = ""; property_get(PROPERTY_BT_LIBRARY_NAME, path, DEFAULT_BT_LIBRARY_NAME); void* handle = dlopen(path, RTLD_NOW); if (!handle) { const char* err_str = dlerror(); Loading
android/app/src/com/android/bluetooth/a2dp/A2dpService.java +12 −11 Original line number Diff line number Diff line Loading @@ -113,18 +113,18 @@ public class A2dpService extends ProfileService { mMaxConnectedAudioDevices = mAdapterService.getMaxConnectedAudioDevices(); Log.i(TAG, "Max connected audio devices set to " + mMaxConnectedAudioDevices); // Step 3: Start handler thread for state machines // Step 3: Setup AVRCP mAvrcp = Avrcp.make(this); // Step 4: Start handler thread for state machines mStateMachines.clear(); mStateMachinesThread = new HandlerThread("A2dpService.StateMachines"); mStateMachinesThread.start(); // Step 4: Setup codec config and clear active device // Step 5: Setup codec config and clear active device mA2dpCodecConfig = new A2dpCodecConfig(this, mA2dpNativeInterface); mActiveDevice = null; // Step 5: Setup AVRCP mAvrcp = Avrcp.make(this); // Step 6: Initialize native interface mA2dpNativeInterface.init(mA2dpCodecConfig.codecConfigPriorities()); Loading Loading @@ -165,15 +165,11 @@ public class A2dpService extends ProfileService { mA2dpNativeInterface.cleanup(); mA2dpNativeInterface = null; // Step 5: Cleanup AVRCP mAvrcp.cleanup(); mAvrcp = null; // Step 4: Clear codec config and active device // Step 5: Clear codec config and active device mA2dpCodecConfig = null; mActiveDevice = null; // Step 3: Destroy state machines and stop handler thread // Step 4: Destroy state machines and stop handler thread synchronized (mStateMachines) { for (A2dpStateMachine sm : mStateMachines.values()) { sm.doQuit(); Loading @@ -184,6 +180,11 @@ public class A2dpService extends ProfileService { mStateMachinesThread.quitSafely(); mStateMachinesThread = null; // Step 3: Cleanup AVRCP mAvrcp.doQuit(); mAvrcp.cleanup(); mAvrcp = null; // Step 2: Reset maximum number of connected audio devices mMaxConnectedAudioDevices = 1; Loading
android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java +14 −0 Original line number Diff line number Diff line Loading @@ -686,6 +686,20 @@ final class A2dpStateMachine extends StateMachine { mA2dpService.sendBroadcast(intent, A2dpService.BLUETOOTH_PERM); } @Override protected String getLogRecString(Message msg) { StringBuilder builder = new StringBuilder(); builder.append(messageWhatToString(msg.what)); builder.append(": "); builder.append("arg1=") .append(msg.arg1) .append(", arg2=") .append(msg.arg2) .append(", obj=") .append(msg.obj); return builder.toString(); } private static String messageWhatToString(int what) { switch (what) { case CONNECT: Loading
android/app/src/com/android/bluetooth/btservice/AdapterService.java +124 −231 Original line number Diff line number Diff line Loading @@ -78,8 +78,6 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class AdapterService extends Service { private static final String TAG = "BluetoothAdapterService"; Loading @@ -97,7 +95,8 @@ public class AdapterService extends Service { private long mEnergyUsedTotalVoltAmpSecMicro; private final SparseArray<UidTraffic> mUidTraffic = new SparseArray<>(); private final ArrayList<ProfileService> mProfiles = new ArrayList<ProfileService>(); private final ArrayList<ProfileService> mRegisteredProfiles = new ArrayList<>(); private final ArrayList<ProfileService> mRunningProfiles = new ArrayList<>(); public static final String ACTION_LOAD_ADAPTER_PROPERTIES = "com.android.bluetooth.btservice.action.LOAD_ADAPTER_PROPERTIES"; Loading Loading @@ -162,7 +161,6 @@ public class AdapterService extends Service { /* TODO: Consider to remove the search API from this class, if changed to use call-back */ private SdpManager mSdpManager = null; private boolean mProfilesStarted; private boolean mNativeAvailable; private boolean mCleaningUp; private final HashMap<String, Integer> mProfileServicesState = new HashMap<String, Integer>(); Loading @@ -183,129 +181,134 @@ public class AdapterService extends Service { private PhonePolicy mPhonePolicy; private ActiveDeviceManager mActiveDeviceManager; /** * Register a {@link ProfileService} with AdapterService. * * @param profile the service being added. */ public void addProfile(ProfileService profile) { synchronized (mProfiles) { if (!mProfiles.contains(profile)) { mProfiles.add(profile); } } Message m = mHandler.obtainMessage(MESSAGE_PROFILE_SERVICE_REGISTERED, profile); mHandler.sendMessage(m); } /** * Unregister a ProfileService with AdapterService. * * @param profile the service being removed. */ public void removeProfile(ProfileService profile) { synchronized (mProfiles) { mProfiles.remove(profile); } Message m = mHandler.obtainMessage(MESSAGE_PROFILE_SERVICE_UNREGISTERED, profile); mHandler.sendMessage(m); } public void onProfileServiceStateChanged(String serviceName, int state) { /** * Notify AdapterService that a ProfileService has started or stopped. * * @param profile the service being removed. * @param state {@link BluetoothAdapter#STATE_ON} or {@link BluetoothAdapter#STATE_OFF} */ public void onProfileServiceStateChanged(ProfileService profile, int state) { if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) { throw new IllegalArgumentException(BluetoothAdapter.nameForState(state)); } Message m = mHandler.obtainMessage(MESSAGE_PROFILE_SERVICE_STATE_CHANGED); m.obj = serviceName; m.obj = profile; m.arg1 = state; mHandler.sendMessage(m); } private void processProfileServiceStateChanged(String serviceName, int state) { boolean doUpdate = false; boolean isBleTurningOn; boolean isBleTurningOff; boolean isTurningOn; boolean isTurningOff; private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED = 1; private static final int MESSAGE_PROFILE_SERVICE_REGISTERED = 2; private static final int MESSAGE_PROFILE_SERVICE_UNREGISTERED = 3; synchronized (mProfileServicesState) { Integer prevState = mProfileServicesState.get(serviceName); if (prevState != null && prevState != state) { mProfileServicesState.put(serviceName, state); doUpdate = true; } } class AdapterServiceHandler extends Handler { @Override public void handleMessage(Message msg) { debugLog("handleMessage() - Message: " + msg.what); if (!doUpdate) { return; switch (msg.what) { case MESSAGE_PROFILE_SERVICE_STATE_CHANGED: debugLog("handleMessage() - MESSAGE_PROFILE_SERVICE_STATE_CHANGED"); processProfileServiceStateChanged((ProfileService) msg.obj, msg.arg1); break; case MESSAGE_PROFILE_SERVICE_REGISTERED: debugLog("handleMessage() - MESSAGE_PROFILE_SERVICE_REGISTERED"); registerProfileService((ProfileService) msg.obj); break; case MESSAGE_PROFILE_SERVICE_UNREGISTERED: debugLog("handleMessage() - MESSAGE_PROFILE_SERVICE_UNREGISTERED"); unregisterProfileService((ProfileService) msg.obj); break; } synchronized (mAdapterStateMachine) { isTurningOff = mAdapterStateMachine.isTurningOff(); isTurningOn = mAdapterStateMachine.isTurningOn(); isBleTurningOn = mAdapterStateMachine.isBleTurningOn(); isBleTurningOff = mAdapterStateMachine.isBleTurningOff(); } debugLog( "processProfileServiceStateChanged() - serviceName=" + serviceName + " isTurningOn=" + isTurningOn + " isTurningOff=" + isTurningOff + " isBleTurningOn=" + isBleTurningOn + " isBleTurningOff=" + isBleTurningOff); if (isBleTurningOn) { if (GattService.class.getName().equals(serviceName)) { debugLog("GattService is started"); mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BLE_STARTED)); private void registerProfileService(ProfileService profile) { if (mRegisteredProfiles.contains(profile)) { Log.e(TAG, profile.getName() + " already registered."); return; } mRegisteredProfiles.add(profile); } } else if (isBleTurningOff) { if (GattService.class.getName().equals(serviceName)) { debugLog("GattService stopped"); mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BLE_STOPPED)); private void unregisterProfileService(ProfileService profile) { if (!mRegisteredProfiles.contains(profile)) { Log.e(TAG, profile.getName() + " not registered (UNREGISTERED)."); return; } } else if (isTurningOff) { //On to BLE_ON //Process stop or disable pending //Check if all services are stopped if so, do cleanup synchronized (mProfileServicesState) { Iterator<Map.Entry<String, Integer>> i = mProfileServicesState.entrySet().iterator(); while (i.hasNext()) { Map.Entry<String, Integer> entry = i.next(); if (GattService.class.getName().equals(entry.getKey())) { continue; mRegisteredProfiles.remove(profile); } if (BluetoothAdapter.STATE_OFF != entry.getValue()) { debugLog("onProfileServiceStateChange() - Profile still running: " + entry.getKey()); private void processProfileServiceStateChanged(ProfileService profile, int state) { switch (state) { case BluetoothAdapter.STATE_ON: if (!mRegisteredProfiles.contains(profile)) { Log.e(TAG, profile.getName() + " not registered (STATE_ON)."); return; } if (mRunningProfiles.contains(profile)) { Log.e(TAG, profile.getName() + " already running."); return; } mRunningProfiles.add(profile); if (GattService.class.getSimpleName().equals(profile.getName())) { mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BLE_STARTED)); } debugLog("onProfileServiceStateChange() - All profile services stopped..."); //Send message to state machine mProfilesStarted = false; if (mRegisteredProfiles.size() == Config.getSupportedProfiles().length && mRegisteredProfiles.size() == mRunningProfiles.size()) { mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STOPPED)); } else if (isTurningOn) { updateInteropDatabase(); //Process start pending //Check if all services are started if so, update state synchronized (mProfileServicesState) { Iterator<Map.Entry<String, Integer>> i = mProfileServicesState.entrySet().iterator(); while (i.hasNext()) { Map.Entry<String, Integer> entry = i.next(); if (GattService.class.getName().equals(entry.getKey())) { continue; mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STARTED)); } if (BluetoothAdapter.STATE_ON != entry.getValue()) { debugLog( "onProfileServiceStateChange() - Profile still not running:" + entry .getKey()); break; case BluetoothAdapter.STATE_OFF: if (!mRegisteredProfiles.contains(profile)) { Log.e(TAG, profile.getName() + " not registered (STATE_OFF)."); return; } if (!mRunningProfiles.contains(profile)) { Log.e(TAG, profile.getName() + " not running."); return; } mRunningProfiles.remove(profile); // If the last profile was removed, or only GATT is left, send BREDR_STOPPED. if ((mRunningProfiles.size() == 0) || (mRunningProfiles.size() == 1 && (GattService.class.getSimpleName() .equals(mRunningProfiles.get(0).getName())))) { mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STOPPED)); } debugLog("onProfileServiceStateChange() - All profile services started."); mProfilesStarted = true; //Send message to state machine if (mRunningProfiles.size() == 0) { mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STARTED)); mAdapterStateMachine.obtainMessage(AdapterState.BLE_STOPPED)); } break; default: Log.e(TAG, "Unhandled profile state: " + state); } } } private final AdapterServiceHandler mHandler = new AdapterServiceHandler(); private void updateInteropDatabase() { interopDatabaseClearNative(); Loading Loading @@ -486,12 +489,6 @@ public class AdapterService extends Service { Config.init(getApplicationContext()); } Class[] supportedProfileServices = Config.getSupportedProfiles(); //Initialize data objects for (Class service : supportedProfileServices) { mProfileServicesState.put(service.getName(), BluetoothAdapter.STATE_OFF); } // Reset |mRemoteDevices| whenever BLE is turned off then on // This is to replace the fact that |mRemoteDevices| was // reinitialized in previous code. Loading @@ -512,11 +509,11 @@ public class AdapterService extends Service { try { mBatteryStats.noteResetBleScan(); } catch (RemoteException e) { // Ignore. Log.w(TAG, "RemoteException trying to send a reset to BatteryStats"); } //Start Gatt service setGattProfileServiceState(supportedProfileServices, BluetoothAdapter.STATE_ON); setProfileServiceState(GattService.class, BluetoothAdapter.STATE_ON); } /** Loading Loading @@ -548,18 +545,7 @@ public class AdapterService extends Service { void startCoreServices() { debugLog("startCoreServices()"); Class[] supportedProfileServices = Config.getSupportedProfiles(); //Start profile services if (!mProfilesStarted && supportedProfileServices.length > 0 && !(supportedProfileServices.length == 1 && supportedProfileServices[0] == GattService.class)) { //Startup all profile services setProfileServiceState(supportedProfileServices, BluetoothAdapter.STATE_ON); } else { debugLog("startCoreProfiles(): Profile Services alreay started"); mAdapterStateMachine.sendMessage( mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STARTED)); } setAllProfileServiceStates(supportedProfileServices, BluetoothAdapter.STATE_ON); } void startBluetoothDisable() { Loading @@ -567,26 +553,20 @@ public class AdapterService extends Service { mAdapterStateMachine.obtainMessage(AdapterState.BEGIN_DISABLE)); } boolean stopProfileServices() { void stopProfileServices() { Class[] supportedProfileServices = Config.getSupportedProfiles(); if (mProfilesStarted && supportedProfileServices.length > 0) { setProfileServiceState(supportedProfileServices, BluetoothAdapter.STATE_OFF); return true; } if (mRunningProfiles.size() == 0) { debugLog("stopProfileServices() - No profiles services to stop or already stopped."); return false; return; } setAllProfileServiceStates(supportedProfileServices, BluetoothAdapter.STATE_OFF); } boolean stopGattProfileService() { //TODO: can optimize this instead of looping around all supported profiles debugLog("stopGattProfileService()"); Class[] supportedProfileServices = Config.getSupportedProfiles(); setGattProfileServiceState(supportedProfileServices, BluetoothAdapter.STATE_OFF); setProfileServiceState(GattService.class, BluetoothAdapter.STATE_OFF); return true; } void updateAdapterState(int prevState, int newState) { if (mCallbacks != null) { int n = mCallbacks.beginBroadcast(); Loading Loading @@ -685,103 +665,19 @@ public class AdapterService extends Service { } } private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED = 1; private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { debugLog("handleMessage() - Message: " + msg.what); switch (msg.what) { case MESSAGE_PROFILE_SERVICE_STATE_CHANGED: { debugLog("handleMessage() - MESSAGE_PROFILE_SERVICE_STATE_CHANGED"); processProfileServiceStateChanged((String) msg.obj, msg.arg1); } break; } } }; @SuppressWarnings("rawtypes") private void setGattProfileServiceState(Class[] services, int state) { if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) { Log.w(TAG, "setGattProfileServiceState(): invalid state...Leaving..."); return; } int expectedCurrentState = BluetoothAdapter.STATE_OFF; int pendingState = BluetoothAdapter.STATE_TURNING_ON; if (state == BluetoothAdapter.STATE_OFF) { expectedCurrentState = BluetoothAdapter.STATE_ON; pendingState = BluetoothAdapter.STATE_TURNING_OFF; } for (Class service : services) { String serviceName = service.getName(); String simpleName = service.getSimpleName(); if (GattService.class.getSimpleName().equals(simpleName)) { Integer serviceState = mProfileServicesState.get(serviceName); if (serviceState != null && serviceState != expectedCurrentState) { debugLog("setProfileServiceState() - Unable to " + ( state == BluetoothAdapter.STATE_OFF ? "start" : "stop") + " service " + serviceName + ". Invalid state: " + serviceState); continue; } debugLog("setProfileServiceState() - " + (state == BluetoothAdapter.STATE_OFF ? "Stopping" : "Starting") + " service " + serviceName); mProfileServicesState.put(serviceName, pendingState); private void setProfileServiceState(Class service, int state) { Intent intent = new Intent(this, service); intent.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED); intent.putExtra(BluetoothAdapter.EXTRA_STATE, state); startService(intent); return; } } } @SuppressWarnings("rawtypes") private void setProfileServiceState(Class[] services, int state) { if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) { debugLog("setProfileServiceState() - Invalid state, leaving..."); return; } int expectedCurrentState = BluetoothAdapter.STATE_OFF; int pendingState = BluetoothAdapter.STATE_TURNING_ON; if (state == BluetoothAdapter.STATE_OFF) { expectedCurrentState = BluetoothAdapter.STATE_ON; pendingState = BluetoothAdapter.STATE_TURNING_OFF; } private void setAllProfileServiceStates(Class[] services, int state) { for (Class service : services) { String serviceName = service.getName(); String simpleName = service.getSimpleName(); if (GattService.class.getSimpleName().equals(simpleName)) { continue; } Integer serviceState = mProfileServicesState.get(serviceName); if (serviceState != null && serviceState != expectedCurrentState) { debugLog("setProfileServiceState() - Unable to " + ( state == BluetoothAdapter.STATE_OFF ? "start" : "stop") + " service " + serviceName + ". Invalid state: " + serviceState); if (GattService.class.getSimpleName().equals(service.getSimpleName())) { continue; } debugLog("setProfileServiceState() - " + (state == BluetoothAdapter.STATE_OFF ? "Stopping" : "Starting") + " service " + serviceName); mProfileServicesState.put(serviceName, pendingState); Intent intent = new Intent(this, service); intent.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED); intent.putExtra(BluetoothAdapter.EXTRA_STATE, state); startService(intent); setProfileServiceState(service, state); } } Loading Loading @@ -2496,13 +2392,10 @@ public class AdapterService extends Service { + device.getName()); } // Dump profile information StringBuilder sb = new StringBuilder(); synchronized (mProfiles) { for (ProfileService profile : mProfiles) { for (ProfileService profile : mRegisteredProfiles) { profile.dump(sb); } } writer.write(sb.toString()); writer.flush(); Loading @@ -2513,7 +2406,7 @@ public class AdapterService extends Service { private void dumpMetrics(FileDescriptor fd) { BluetoothProto.BluetoothLog metrics = new BluetoothProto.BluetoothLog(); metrics.setNumBondedDevices(getBondedDevices().length); for (ProfileService profile : mProfiles) { for (ProfileService profile : mRegisteredProfiles) { profile.dumpProto(metrics); } byte[] nativeMetricsBytes = dumpMetricsNative(); Loading Loading @@ -2563,9 +2456,9 @@ public class AdapterService extends Service { private static native void classInitNative(); private native boolean initNative(); native boolean initNative(); private native void cleanupNative(); native void cleanupNative(); /*package*/ native boolean enableNative(boolean startRestricted); Loading