diff options
164 files changed, 2200 insertions, 4028 deletions
diff --git a/Android.bp b/Android.bp index 7be2e6ec9e..aef08f38e9 100644 --- a/Android.bp +++ b/Android.bp @@ -76,6 +76,8 @@ cc_defaults { // there are too many unused parameters in all the code. "-Wno-unused-parameter", ], + c_std: "c99", + cpp_std: "c++17", } // Address Sanitizer is flaky on Android x86_64 binaries but it's not on x86 diff --git a/android/app/Android.bp b/android/app/Android.bp index 2bf58974cb..239d410074 100644 --- a/android/app/Android.bp +++ b/android/app/Android.bp @@ -55,7 +55,7 @@ java_library { cc_library_shared { name: "libbluetooth_jni", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], srcs: ["jni/**/*.cpp"], version_script: "libbluetooth_jni.map", header_libs: [ @@ -77,7 +77,7 @@ cc_library_shared { // is required to maintain FIPS compliance. stl: "libc++_static", static_libs: [ - "android.hardware.audio.common-V1-ndk", + "android.hardware.audio.common-V2-ndk", "android.hardware.audio.common@5.0", "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.bluetooth.audio@2.0", @@ -100,6 +100,7 @@ cc_library_shared { "libbluetooth-types", "libbluetooth_core_rs", "libbluetooth_core_rs_bridge", + "libbluetooth_gd", "libbt-audio-hal-interface", "libbt-bta", "libbt-bta-core", @@ -118,6 +119,7 @@ cc_library_shared { "libchrome", "libcutils", "libevent", + "libflatbuffers-cpp", "libfmq", "libg722codec", "libhidlbase", @@ -125,6 +127,7 @@ cc_library_shared { "libmodpb64", "libopus", "libosi", + "libprotobuf-cpp-lite", "libudrv-uipc", "libutils", ], @@ -148,7 +151,7 @@ cc_library_shared { cc_library { name: "libbluetooth-core", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], header_libs: [ "jni_headers", "libbluetooth_headers", @@ -199,8 +202,12 @@ android_app { srcs: [ ":statslog-bluetooth-java-gen", ":statslog-bt-restricted-java-gen", + "proto/keystore.proto", "src/**/*.java", ], + proto: { + type: "lite", + }, aaptflags: [ "--custom-package", "com.android.bluetooth", diff --git a/android/app/AndroidManifest.xml b/android/app/AndroidManifest.xml index 929cc0e42b..7a398344c0 100644 --- a/android/app/AndroidManifest.xml +++ b/android/app/AndroidManifest.xml @@ -221,17 +221,6 @@ </intent-filter> </service> - <!-- Generic Attribute (GATT) Profile Service --> - <service android:process="@string/process" - android:name="com.android.bluetooth.gatt.GattService" - android:enabled="true" - android:exported="true" - android:permission="android.permission.ACCESS_BLUETOOTH_SHARE"> - <intent-filter> - <action android:name="android.bluetooth.IBluetoothGatt"/> - </intent-filter> - </service> - <!-- Hearing Aid Profile (HAP) client Profile Service --> <service android:process="@string/process" android:name="com.android.bluetooth.hap.HapClientService" diff --git a/android/app/jni/com_android_bluetooth_btservice_ActivityAttribution.cpp b/android/app/jni/com_android_bluetooth_btservice_ActivityAttribution.cpp index 4e0247dccc..2790b00903 100644 --- a/android/app/jni/com_android_bluetooth_btservice_ActivityAttribution.cpp +++ b/android/app/jni/com_android_bluetooth_btservice_ActivityAttribution.cpp @@ -24,138 +24,10 @@ #include "com_android_bluetooth.h" #include "hardware/bt_activity_attribution.h" -using bluetooth::activity_attribution::ActivityAttributionCallbacks; using bluetooth::activity_attribution::ActivityAttributionInterface; namespace android { -static jmethodID method_onWakeup; -static jmethodID method_onActivityLogsReady; - static ActivityAttributionInterface* sActivityAttributionInterface = nullptr; -static std::shared_timed_mutex interface_mutex; - -static jobject mCallbacksObj = nullptr; -static std::shared_timed_mutex callbacks_mutex; - -class ActivityAttributionCallbacksImpl : public ActivityAttributionCallbacks { - public: - ~ActivityAttributionCallbacksImpl() = default; - - void OnWakeup(const Activity activity, const RawAddress& bd_addr) override { - LOG(INFO) << __func__; - - std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; - - ScopedLocalRef<jbyteArray> addr( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); - if (!addr.get()) { - LOG(ERROR) - << "Failed to allocate jbyteArray for bd_addr of wakeup callback"; - return; - } - - sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), - (jbyte*)&bd_addr); - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onWakeup, (jint)activity, - addr.get()); - } - - void OnActivityLogsReady( - const std::vector<BtaaAggregationEntry> logs) override { - LOG(INFO) << __func__; - - std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; - - jsize logs_size = logs.size() * sizeof(BtaaAggregationEntry); - ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), - sCallbackEnv->NewByteArray(logs_size)); - if (!addr.get()) { - LOG(ERROR) << "Failed to allocate jbyteArray for logs from activity " - "logging callback"; - return; - } - - sCallbackEnv->SetByteArrayRegion(addr.get(), 0, logs_size, - (jbyte*)logs.data()); - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onActivityLogsReady, - addr.get()); - } -}; - -static ActivityAttributionCallbacksImpl sActivityAttributionCallbacks; - -static void classInitNative(JNIEnv* env, jclass clazz) { - method_onWakeup = env->GetMethodID(clazz, "onWakeup", "(I[B)V"); - method_onActivityLogsReady = - env->GetMethodID(clazz, "onActivityLogsReady", "([B)V"); - - LOG(INFO) << __func__ << ": succeeds"; -} - -static void initNative(JNIEnv* env, jobject object) { - std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex); - std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex); - const bt_interface_t* btInf = getBluetoothInterface(); - if (btInf == nullptr) { - LOG(ERROR) << "Bluetooth module is not loaded"; - return; - } - - if (sActivityAttributionInterface != nullptr) { - LOG(INFO) - << "Cleaning up ActivityAttribution Interface before initializing..."; - sActivityAttributionInterface->Cleanup(); - sActivityAttributionInterface = nullptr; - } - - if (mCallbacksObj != nullptr) { - LOG(INFO) << "Cleaning up ActivityAttribution callback object"; - env->DeleteGlobalRef(mCallbacksObj); - mCallbacksObj = nullptr; - } - - if ((mCallbacksObj = env->NewGlobalRef(object)) == nullptr) { - LOG(ERROR) - << "Failed to allocate Global Ref for ActivityAttribution Callbacks"; - return; - } - - sActivityAttributionInterface = - (ActivityAttributionInterface*)btInf->get_profile_interface( - BT_ACTIVITY_ATTRIBUTION_ID); - if (sActivityAttributionInterface == nullptr) { - LOG(ERROR) << "Failed to get ActivityAttribution Interface"; - return; - } - - sActivityAttributionInterface->RegisterCallbacks( - &sActivityAttributionCallbacks); -} - -static void cleanupNative(JNIEnv* env, jobject object) { - std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex); - std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex); - - const bt_interface_t* btInf = getBluetoothInterface(); - if (btInf == nullptr) { - LOG(ERROR) << "Bluetooth module is not loaded"; - return; - } - - if (sActivityAttributionInterface != nullptr) { - sActivityAttributionInterface->Cleanup(); - sActivityAttributionInterface = nullptr; - } - - if (mCallbacksObj != nullptr) { - env->DeleteGlobalRef(mCallbacksObj); - mCallbacksObj = nullptr; - } -} static void notifyActivityAttributionInfoNative(JNIEnv* env, jobject object, jint uid, jstring packageName, @@ -186,9 +58,6 @@ static void notifyActivityAttributionInfoNative(JNIEnv* env, jobject object, } static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "()V", (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, {"notifyActivityAttributionInfoNative", "(ILjava/lang/String;Ljava/lang/String;)V", (void*)notifyActivityAttributionInfoNative}, diff --git a/android/app/jni/com_android_bluetooth_gatt.cpp b/android/app/jni/com_android_bluetooth_gatt.cpp index 1290aae868..1c329d68b2 100644 --- a/android/app/jni/com_android_bluetooth_gatt.cpp +++ b/android/app/jni/com_android_bluetooth_gatt.cpp @@ -2682,7 +2682,7 @@ static void stopDistanceMeasurementNative(JNIEnv* env, jobject object, * JNI function definitinos */ -// JNI functions defined in AdvertiseManager class. +// JNI functions defined in AdvertiseManagerNativeInterface class. static JNINativeMethod sAdvertiseMethods[] = { {"classInitNative", "()V", (void*)advertiseClassInitNative}, {"initializeNative", "()V", (void*)advertiseInitializeNative}, @@ -2691,8 +2691,8 @@ static JNINativeMethod sAdvertiseMethods[] = { "(Landroid/bluetooth/le/AdvertisingSetParameters;[B[BLandroid/bluetooth/" "le/PeriodicAdvertisingParameters;[BIIII)V", (void*)startAdvertisingSetNative}, - {"getOwnAddressNative", "(I)V", (void*)getOwnAddressNative}, {"stopAdvertisingSetNative", "(I)V", (void*)stopAdvertisingSetNative}, + {"getOwnAddressNative", "(I)V", (void*)getOwnAddressNative}, {"enableAdvertisingSetNative", "(IZII)V", (void*)enableAdvertisingSetNative}, {"setAdvertisingDataNative", "(I[B)V", (void*)setAdvertisingDataNative}, @@ -2848,8 +2848,8 @@ int register_com_android_bluetooth_gatt(JNIEnv* env) { env, "com/android/bluetooth/gatt/ScanNativeInterface", sScanMethods, NELEM(sScanMethods)); register_success &= jniRegisterNativeMethods( - env, "com/android/bluetooth/gatt/AdvertiseManager", sAdvertiseMethods, - NELEM(sAdvertiseMethods)); + env, "com/android/bluetooth/gatt/AdvertiseManagerNativeInterface", + sAdvertiseMethods, NELEM(sAdvertiseMethods)); register_success &= jniRegisterNativeMethods( env, "com/android/bluetooth/gatt/PeriodicScanManager", sPeriodicScanMethods, NELEM(sPeriodicScanMethods)); diff --git a/system/gd/proto/bluetooth/bluetoothKeystore/keystore.proto b/android/app/proto/keystore.proto index d0e418bd28..f0641ff6fa 100644 --- a/system/gd/proto/bluetooth/bluetoothKeystore/keystore.proto +++ b/android/app/proto/keystore.proto @@ -16,9 +16,6 @@ syntax = "proto2"; -// C++ namespace: bluetooth::metrics::BluetoothMetricsProto -package bluetooth.keystore.BluetoothKeystoreProto; - option java_package = "com.android.bluetooth"; option java_outer_classname = "BluetoothKeystoreProto"; diff --git a/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java b/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java index e7b0920476..02e8a5ace4 100644 --- a/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java +++ b/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java @@ -134,6 +134,7 @@ public class A2dpSinkService extends ProfileService { * Set the device that should be allowed to actively stream */ public boolean setActiveDevice(BluetoothDevice device) { + Log.i(TAG, "setActiveDevice(device=" + device + ")"); synchronized (mActiveDeviceLock) { if (mNativeInterface.setActiveDevice(device)) { mActiveDevice = device; diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java b/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java index 25c7f9e7a1..a43594df76 100644 --- a/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java +++ b/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java @@ -208,8 +208,12 @@ public class AvrcpControllerService extends ProfileService { */ @VisibleForTesting boolean setActiveDevice(BluetoothDevice device) { + if (DBG) { + Log.d(TAG, "setActiveDevice(device=" + device + ")"); + } A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService(); if (a2dpSinkService == null) { + Log.w(TAG, "setActiveDevice(device=" + device + "): A2DP Sink not available"); return false; } @@ -242,6 +246,8 @@ public class AvrcpControllerService extends ProfileService { return true; } } + + Log.w(TAG, "setActiveDevice(device=" + device + "): A2DP Sink request failed"); return false; } @@ -333,15 +339,21 @@ public class AvrcpControllerService extends ProfileService { for (AvrcpControllerStateMachine stateMachine : mDeviceStateMap.values()) { requestedNode = stateMachine.findNode(parentMediaId); if (requestedNode != null) { - Log.d(TAG, "Found a node"); break; } } } + + if (DBG) { + Log.d(TAG, "getContents(" + parentMediaId + "): " + + (requestedNode == null + ? "Failed to find node" + : "node=" + requestedNode + ", device=" + requestedNode.getDevice())); + } + // If we don't find a node in the tree then do not have any way to browse for the contents. // Return an empty list instead. if (requestedNode == null) { - if (DBG) Log.d(TAG, "Didn't find a node"); return new BrowseResult(new ArrayList(0), BrowseResult.ERROR_MEDIA_ID_INVALID); } if (parentMediaId.equals(BrowseTree.ROOT) && requestedNode.getChildrenCount() == 0) { @@ -355,9 +367,8 @@ public class AvrcpControllerService extends ProfileService { List<MediaItem> contents = requestedNode.getContents(); - if (DBG) Log.d(TAG, "Returning contents"); if (!requestedNode.isCached()) { - if (DBG) Log.d(TAG, "node is not cached"); + if (DBG) Log.d(TAG, "getContents(" + parentMediaId + "): node download pending"); refreshContents(requestedNode); /* Ongoing downloads can have partial results and we want to make sure they get sent * to the client. If a download gets kicked off as a result of this request, the @@ -365,6 +376,10 @@ public class AvrcpControllerService extends ProfileService { */ return new BrowseResult(contents, BrowseResult.DOWNLOAD_PENDING); } + if (DBG) { + Log.d(TAG, "getContents(" + parentMediaId + "): return node, contents=" + + requestedNode.getContents()); + } return new BrowseResult(contents, BrowseResult.SUCCESS); } diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java b/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java index 290dc35cb4..9f43d8199f 100644 --- a/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java +++ b/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java @@ -581,6 +581,8 @@ class AvrcpControllerStateMachine extends StateMachine { mAddressedPlayer.updateCurrentTrack(track); if (isActive()) { BluetoothMediaBrowserService.trackChanged(track); + BluetoothMediaBrowserService.notifyChanged( + mAddressedPlayer.getPlaybackState()); } if (previousTrack != null) { removeUnusedArtwork(previousTrack.getCoverArtUuid()); diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java b/android/app/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java index 25df4cd613..8d68409fb2 100644 --- a/android/app/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java +++ b/android/app/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java @@ -86,6 +86,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(Intent.ACTION_LOCALE_CHANGED)) { + if (DBG) Log.d(TAG, "Locale has updated"); if (sBluetoothMediaBrowserService == null) return; MediaSessionCompat session = sBluetoothMediaBrowserService.getSession(); MediaControllerCompat controller = session.getController(); @@ -106,7 +107,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat { */ @Override public void onCreate() { - if (DBG) Log.d(TAG, "onCreate"); + if (DBG) Log.d(TAG, "Service Created"); super.onCreate(); // Create and configure the MediaSessionCompat @@ -128,6 +129,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat { @Override public void onDestroy() { + if (DBG) Log.d(TAG, "Service Destroyed"); unregisterReceiver(mReceiver); mReceiver = null; } @@ -191,6 +193,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat { AvrcpControllerService avrcpControllerService = AvrcpControllerService.getAvrcpControllerService(); if (avrcpControllerService == null) { + Log.w(TAG, "getContents(id=" + parentMediaId + "): AVRCP Controller Service not ready"); return new BrowseResult(new ArrayList(0), BrowseResult.ERROR_NO_AVRCP_SERVICE); } else { return avrcpControllerService.getContents(parentMediaId); @@ -227,7 +230,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat { @Override public synchronized void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result) { - if (DBG) Log.d(TAG, "onLoadChildren parentMediaId= " + parentMediaId); + if (DBG) Log.d(TAG, "Request for contents, id= " + parentMediaId); BrowseResult contents = getContents(parentMediaId); byte status = contents.getStatus(); List<MediaItem> results = contents.getResults(); @@ -236,8 +239,8 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat { result.detach(); } else { if (DBG) { - Log.d(TAG, "id= " + parentMediaId + ", status= " + contents.getStatusString() - + ", results=" + results); + Log.d(TAG, "Received Contents, id= " + parentMediaId + ", status= " + + contents.getStatusString() + ", results=" + results); } result.sendResult(results); } @@ -245,7 +248,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat { @Override public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) { - if (DBG) Log.d(TAG, "onGetRoot"); + Log.i(TAG, "Browser Client Connection Request, client='" + clientPackageName + "')"); Bundle style = getDefaultStyle(); return new BrowserRoot(BrowseTree.ROOT, style); } @@ -263,6 +266,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat { } else { mSession.setQueue(null); } + if (DBG) Log.d(TAG, "Now Playing List Changed, queue=" + mMediaQueue); } private void clearNowPlayingQueue() { @@ -275,6 +279,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat { if (node.getScope() == AvrcpControllerService.BROWSE_SCOPE_NOW_PLAYING) { sBluetoothMediaBrowserService.updateNowPlayingQueue(node); } else { + if (DBG) Log.d(TAG, "Browse Node contents changed, node=" + node); sBluetoothMediaBrowserService.notifyChildrenChanged(node.getID()); } } @@ -293,7 +298,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat { } static synchronized void trackChanged(AvrcpItem track) { - if (DBG) Log.d(TAG, "trackChanged setMetadata=" + track); + if (DBG) Log.d(TAG, "Track Changed, track=" + track); if (sBluetoothMediaBrowserService != null) { if (track != null) { sBluetoothMediaBrowserService.mSession.setMetadata(track.toMediaMetadata()); @@ -307,7 +312,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat { } static synchronized void notifyChanged(PlaybackStateCompat playbackState) { - Log.d(TAG, "notifyChanged PlaybackState" + playbackState); + if (DBG) Log.d(TAG, "Playback State Changed, state=" + playbackState); if (sBluetoothMediaBrowserService != null) { sBluetoothMediaBrowserService.mSession.setPlaybackState(playbackState); } else { @@ -340,15 +345,16 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat { /** * Get playback state */ - public static synchronized int getPlaybackState() { + public static synchronized PlaybackStateCompat getPlaybackState() { if (sBluetoothMediaBrowserService != null) { - PlaybackStateCompat currentPlaybackState = - sBluetoothMediaBrowserService.mSession.getController().getPlaybackState(); - if (currentPlaybackState != null) { - return currentPlaybackState.getState(); - } + MediaSessionCompat session = sBluetoothMediaBrowserService.getSession(); + if (session == null) return null; + MediaControllerCompat controller = session.getController(); + PlaybackStateCompat playbackState = + controller == null ? null : controller.getPlaybackState(); + return playbackState; } - return PlaybackStateCompat.STATE_ERROR; + return null; } /** diff --git a/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java index faa10ccadc..73530ed150 100644 --- a/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java +++ b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java @@ -24,7 +24,6 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHearingAid; -import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothSinkAudioPolicy; import android.content.BroadcastReceiver; @@ -68,12 +67,9 @@ import java.util.Set; * devices is more than one, the rules below will apply. * 2) The selected A2DP active device is the one used for AVRCP as well. * 3) The HFP active device might be different from the A2DP active device. - * 4) The Active Device Manager always listens for ACTION_ACTIVE_DEVICE_CHANGED - * broadcasts for each profile: - * - BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED for LE audio - * If such broadcast is received (e.g., triggered indirectly by user - * action on the UI), the device in the received broadcast is marked - * as the current active device for that profile. + * 4) The Active Device Manager always listens for the change of active devices. + * When it changed (e.g., triggered indirectly by user action on the UI), + * the new active device is marked as the current active device for that profile. * 5) If there is a HearingAid active device, then A2DP, HFP and LE audio active devices * must be set to null (i.e., A2DP, HFP and LE audio cannot have active devices). * The reason is that A2DP, HFP or LE audio cannot be used together with HearingAid. @@ -88,11 +84,8 @@ import java.util.Set; * 7) If the currently active device (per profile) is disconnected, the * Active Device Manager just marks that the profile has no active device, * and the lastly activated BT device that is still connected would be selected. - * 8) If there is already an active device, and the corresponding - * ACTION_ACTIVE_DEVICE_CHANGED broadcast is received, the device - * contained in the broadcast is marked as active. However, if - * the contained device is null, the corresponding profile is marked - * as having no active device. + * 8) If there is already an active device, however, if active device change notified + * with a null device, the corresponding profile is marked as having no active device. * 9) If a wired audio device is connected, the audio output is switched * by the Audio Framework itself to that device. We detect this here, * and the active device for each profile (A2DP/HFP/HearingAid/LE audio) is set @@ -151,7 +144,6 @@ public class ActiveDeviceManager { private BluetoothDevice mClassicDeviceToBeActivated = null; private BluetoothDevice mClassicDeviceNotToBeActivated = null; - // Broadcast receiver for all changes private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -168,32 +160,6 @@ public class ActiveDeviceManager { if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { int currentState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); mHandler.post(() -> handleAdapterStateChanged(currentState)); - return; - } - - final BluetoothDevice device = intent.getParcelableExtra( - BluetoothDevice.EXTRA_DEVICE, BluetoothDevice.class); - final int previousState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1); - final int currentState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); - - if (currentState != -1 && previousState == currentState) { - return; - } - - switch (action) { - case BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED: - if (currentState == BluetoothProfile.STATE_CONNECTED) { - mHandler.post(() -> handleLeAudioConnected(device)); - } else if (previousState == BluetoothProfile.STATE_CONNECTED) { - mHandler.post(() -> handleLeAudioDisconnected(device)); - } - break; - case BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED: - mHandler.post(() -> handleLeAudioActiveDeviceChanged(device)); - break; - default: - Log.e(TAG, "Received unexpected intent, action=" + action); - break; } } }; @@ -247,6 +213,30 @@ public class ActiveDeviceManager { } /** + * Called when LE audio connection state changed by LeAudioService + * + * @param device The device of which connection state was changed + * @param prevState The previous connection state of the device + * @param newState The new connection state of the device + */ + public void leAudioConnectionStateChanged(BluetoothDevice device, int prevState, int newState) { + if (newState == BluetoothProfile.STATE_CONNECTED) { + mHandler.post(() -> handleLeAudioConnected(device)); + } else if (prevState == BluetoothProfile.STATE_CONNECTED) { + mHandler.post(() -> handleLeAudioDisconnected(device)); + } + } + + /** + * Called when LE audio active state changed by LeAudioService + * + * @param device The device currently activated. {@code null} if no LE audio device activated + */ + public void leAudioActiveStateChanged(BluetoothDevice device) { + mHandler.post(() -> handleLeAudioActiveDeviceChanged(device)); + } + + /** * Called when HearingAid connection state changed by HearingAidService * * @param device The device of which connection state was changed @@ -848,8 +838,6 @@ public class ActiveDeviceManager { IntentFilter filter = new IntentFilter(); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); - filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED); - filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED); mAdapterService.registerReceiver(mReceiver, filter, Context.RECEIVER_EXPORTED); mAudioManager.registerAudioDeviceCallback(mAudioManagerAudioDeviceCallback, mHandler); diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterService.java b/android/app/src/com/android/bluetooth/btservice/AdapterService.java index 5225557914..f84cc69ff4 100644 --- a/android/app/src/com/android/bluetooth/btservice/AdapterService.java +++ b/android/app/src/com/android/bluetooth/btservice/AdapterService.java @@ -79,11 +79,9 @@ import android.bluetooth.UidTraffic; import android.companion.CompanionDeviceManager; import android.content.AttributionSource; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.AsyncTask; @@ -122,6 +120,7 @@ import com.android.bluetooth.bass_client.BassClientService; import com.android.bluetooth.btservice.InteropUtil.InteropFeature; import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; import com.android.bluetooth.btservice.activityattribution.ActivityAttributionService; +import com.android.bluetooth.btservice.bluetoothkeystore.BluetoothKeystoreNativeInterface; import com.android.bluetooth.btservice.bluetoothkeystore.BluetoothKeystoreService; import com.android.bluetooth.btservice.storage.DatabaseManager; import com.android.bluetooth.btservice.storage.MetadataDatabase; @@ -284,17 +283,29 @@ public class AdapterService extends Service { return sAdapterService; } - private static synchronized void setAdapterService(AdapterService instance) { - Log.d(TAG, "setAdapterService() - trying to set service to " + instance); + /** Allow test to set an AdapterService to be return by AdapterService.getAdapterService() */ + @VisibleForTesting + public static synchronized void setAdapterService(AdapterService instance) { if (instance == null) { + Log.e(TAG, "setAdapterService() - instance is null"); return; } + Log.d(TAG, "setAdapterService() - set service to " + instance); sAdapterService = instance; } - private static synchronized void clearAdapterService(AdapterService current) { - if (sAdapterService == current) { + /** Clear test Adapter service. See {@code setAdapterService} */ + @VisibleForTesting + public static synchronized void clearAdapterService(AdapterService instance) { + if (sAdapterService == instance) { + Log.d(TAG, "clearAdapterService() - This adapter was cleared " + instance); sAdapterService = null; + } else { + Log.d( + TAG, + "clearAdapterService() - incorrect cleared adapter." + + (" Instance=" + instance) + + (" vs sAdapterService=" + sAdapterService)); } } @@ -370,7 +381,7 @@ public class AdapterService extends Service { private BassClientService mBassClientService; private BatteryService mBatteryService; private BluetoothQualityReportNativeInterface mBluetoothQualityReportNativeInterface; - private IBluetoothGatt mBluetoothGatt; + private GattService mGattService; private volatile boolean mTestModeEnabled = false; @@ -424,8 +435,6 @@ public class AdapterService extends Service { private static final int MESSAGE_PROFILE_SERVICE_REGISTERED = 2; private static final int MESSAGE_PROFILE_SERVICE_UNREGISTERED = 3; private static final int MESSAGE_PREFERRED_AUDIO_PROFILES_AUDIO_FRAMEWORK_TIMEOUT = 4; - private static final int MESSAGE_ON_PROFILE_SERVICE_BIND = 5; - private static final int MESSAGE_ON_PROFILE_SERVICE_UNBIND = 6; class AdapterServiceHandler extends Handler { AdapterServiceHandler(Looper looper) { @@ -449,14 +458,6 @@ public class AdapterService extends Service { verboseLog("handleMessage() - MESSAGE_PROFILE_SERVICE_UNREGISTERED"); unregisterProfileService((ProfileService) msg.obj); break; - case MESSAGE_ON_PROFILE_SERVICE_BIND: - verboseLog("handleMessage() - MESSAGE_ON_PROFILE_SERVICE_BIND"); - onGattBind((IBinder) msg.obj); - break; - case MESSAGE_ON_PROFILE_SERVICE_UNBIND: - verboseLog("handleMessage() - MESSAGE_ON_PROFILE_SERVICE_UNBIND"); - onGattUnbind(); - break; case MESSAGE_PREFERRED_AUDIO_PROFILES_AUDIO_FRAMEWORK_TIMEOUT: errorLog( "handleMessage() - " @@ -496,22 +497,6 @@ public class AdapterService extends Service { mRegisteredProfiles.remove(profile); } - private void onGattBind(IBinder service) { - mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service); - try { - mBluetoothGatt.startService(); - } catch (RemoteException e) { - Log.e(TAG, "onGattBind: RemoteException", e); - } - } - - private void onGattUnbind() { - mBluetoothGatt = null; - Log.e( - TAG, - "onGattUnbind: Gatt service has disconnected from AdapterService unexpectedly"); - } - private void processProfileServiceStateChanged(ProfileService profile, int state) { switch (state) { case BluetoothAdapter.STATE_ON: @@ -639,7 +624,9 @@ public class AdapterService extends Service { mAdapterProperties = new AdapterProperties(this); mAdapterStateMachine = new AdapterState(this, mLooper); mJniCallbacks = new JniCallbacks(this, mAdapterProperties); - mBluetoothKeystoreService = new BluetoothKeystoreService(isCommonCriteriaMode()); + mBluetoothKeystoreService = + new BluetoothKeystoreService( + new BluetoothKeystoreNativeInterface(), isCommonCriteriaMode()); mBluetoothKeystoreService.start(); int configCompareResult = mBluetoothKeystoreService.getCompareResult(); @@ -716,7 +703,6 @@ public class AdapterService extends Service { mBluetoothSocketManagerBinder = new BluetoothSocketManagerBinder(this); mActivityAttributionService = new ActivityAttributionService(); - mActivityAttributionService.start(); setAdapterService(this); @@ -1003,47 +989,11 @@ public class AdapterService extends Service { } } - class GattServiceConnection implements ServiceConnection { - public void onServiceConnected(ComponentName componentName, IBinder service) { - String name = componentName.getClassName(); - if (DBG) { - Log.d(TAG, "GattServiceConnection.onServiceConnected: " + name); - } - if (!name.equals(GattService.class.getName())) { - Log.e(TAG, "Unknown service connected: " + name); - return; - } - mHandler.obtainMessage(MESSAGE_ON_PROFILE_SERVICE_BIND, service).sendToTarget(); - } - - public void onServiceDisconnected(ComponentName componentName) { - // Called if we unexpectedly disconnect. This should never happen. - String name = componentName.getClassName(); - Log.e(TAG, "GattServiceConnection.onServiceDisconnected: " + name); - if (!name.equals(GattService.class.getName())) { - Log.e(TAG, "Unknown service disconnected: " + name); - return; - } - mHandler.sendEmptyMessage(MESSAGE_ON_PROFILE_SERVICE_UNBIND); - } - } - - private GattServiceConnection mGattConnection = new GattServiceConnection(); - private void startGattProfileService() { mStartedProfiles.add(GattService.class.getSimpleName()); - Intent intent = new Intent(this, GattService.class); - if (!bindServiceAsUser( - intent, - mGattConnection, - Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, - UserHandle.CURRENT)) { - // This should never happen - // unbindService will be called during stopGattProfileService triggered by AdapterState - Log.e(TAG, "Error while binding to gatt. This Bluetooth session will timeout"); - unbindService(mGattConnection); - } + mGattService = new GattService(this); + ((ProfileService) mGattService).doStart(); } private void stopGattProfileService() { @@ -1054,15 +1004,10 @@ public class AdapterService extends Service { } mStartedProfiles.remove(GattService.class.getSimpleName()); - - try { - if (mBluetoothGatt != null) { - mBluetoothGatt.stopService(); - } - } catch (RemoteException e) { - Log.e(TAG, "stopGattProfileService: RemoteException", e); + if (mGattService != null) { + ((ProfileService) mGattService).doStop(); + mGattService = null; } - unbindService(mGattConnection); } private void invalidateBluetoothGetStateCache() { @@ -1360,10 +1305,6 @@ public class AdapterService extends Service { mSdpManager = null; } - if (mActivityAttributionService != null) { - mActivityAttributionService.cleanup(); - } - if (mNativeAvailable) { debugLog("cleanup() - Cleaning up adapter native"); cleanupNative(); @@ -5014,7 +4955,7 @@ public class AdapterService extends Service { if (service == null) { return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } - if (!callerIsSystem(TAG, "setPreferredAudioProfiles")) { + if (!callerIsSystem(TAG, "notifyActiveDeviceChangeApplied")) { return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; } requireNonNull(device); @@ -5246,6 +5187,7 @@ public class AdapterService extends Service { try { AdapterService service = getService(); if (service != null) { + enforceBluetoothPrivilegedPermission(service); service.unregAllGattClient(source); } receiver.send(null); @@ -6885,16 +6827,15 @@ public class AdapterService extends Service { } IBluetoothGatt getBluetoothGatt() { - return mBluetoothGatt; + if (mGattService == null) { + return null; + } + return IBluetoothGatt.Stub.asInterface(((ProfileService) mGattService).getBinder()); } void unregAllGattClient(AttributionSource source) { - if (mBluetoothGatt != null) { - try { - mBluetoothGatt.unregAll(source); - } catch (RemoteException e) { - Log.e(TAG, "Unable to disconnect all apps.", e); - } + if (mGattService != null) { + mGattService.unregAll(source); } } diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterState.java b/android/app/src/com/android/bluetooth/btservice/AdapterState.java index 87134e4673..ae395bf173 100644 --- a/android/app/src/com/android/bluetooth/btservice/AdapterState.java +++ b/android/app/src/com/android/bluetooth/btservice/AdapterState.java @@ -77,10 +77,14 @@ final class AdapterState extends StateMachine { static final String BLE_STOP_TIMEOUT_DELAY_PROPERTY = "ro.bluetooth.ble_stop_timeout_delay"; - static final int BLE_START_TIMEOUT_DELAY = 4000; - static final int BLE_STOP_TIMEOUT_DELAY = 4000; - static final int BREDR_START_TIMEOUT_DELAY = 4000; - static final int BREDR_STOP_TIMEOUT_DELAY = 4000; + static final int BLE_START_TIMEOUT_DELAY = + 4000 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); + static final int BLE_STOP_TIMEOUT_DELAY = + 4000 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); + static final int BREDR_START_TIMEOUT_DELAY = + 4000 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); + static final int BREDR_STOP_TIMEOUT_DELAY = + 4000 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); private AdapterService mAdapterService; private TurningOnState mTurningOnState = new TurningOnState(); diff --git a/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java b/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java index a1af22f3c3..2bd4abb39b 100644 --- a/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java +++ b/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java @@ -250,6 +250,11 @@ final class BondStateMachine extends StateMachine { } break; case SSP_REQUEST: + if (devProp == null) { + errorLog("devProp is null, maybe the device is disconnected"); + break; + } + int passkey = msg.arg1; int variant = msg.arg2; boolean displayPasskey = @@ -262,6 +267,11 @@ final class BondStateMachine extends StateMachine { variant); break; case PIN_REQUEST: + if (devProp == null) { + errorLog("devProp is null, maybe the device is disconnected"); + break; + } + BluetoothClass btClass = dev.getBluetoothClass(); int btDeviceClass = btClass.getDeviceClass(); if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD || btDeviceClass diff --git a/android/app/src/com/android/bluetooth/btservice/Config.java b/android/app/src/com/android/bluetooth/btservice/Config.java index bc0ed8408c..caa1a0004a 100644 --- a/android/app/src/com/android/bluetooth/btservice/Config.java +++ b/android/app/src/com/android/bluetooth/btservice/Config.java @@ -56,6 +56,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Set; public class Config { @@ -171,9 +172,14 @@ public class Config { profile.mSupported = enabled; } } + if (enabled) { + sSupportedProfiles.add(profileClass); + } else { + sSupportedProfiles.remove(profileClass); + } } - private static Class[] sSupportedProfiles = new Class[0]; + private static List<Class> sSupportedProfiles = new ArrayList<>(); private static boolean sIsGdEnabledUptoScanningLayer = false; @@ -211,15 +217,20 @@ public class Config { setProfileEnabled(HearingAidService.class, false); } - ArrayList<Class> profiles = new ArrayList<>(PROFILE_SERVICES_AND_FLAGS.length); - for (ProfileConfig config : PROFILE_SERVICES_AND_FLAGS) { - Log.i(TAG, "init: profile=" + config.mClass.getSimpleName() + ", enabled=" - + config.mSupported); - if (config.mSupported) { - profiles.add(config.mClass); + synchronized (sSupportedProfiles) { + sSupportedProfiles.clear(); + for (ProfileConfig config : PROFILE_SERVICES_AND_FLAGS) { + Log.i( + TAG, + "init: profile=" + + config.mClass.getSimpleName() + + ", enabled=" + + config.mSupported); + if (config.mSupported) { + sSupportedProfiles.add(config.mClass); + } } } - sSupportedProfiles = profiles.toArray(new Class[profiles.size()]); if (ctx == null) { return; @@ -253,19 +264,17 @@ public class Config { * Remove the input profiles from the supported list. */ static void removeProfileFromSupportedList(HashSet<Class> nonSupportedProfiles) { - ArrayList<Class> profilesList = new ArrayList<Class>(Arrays.asList(sSupportedProfiles)); - Iterator<Class> iter = profilesList.iterator(); - - while (iter.hasNext()) { - Class profileClass = iter.next(); - - if (nonSupportedProfiles.contains(profileClass)) { - iter.remove(); - Log.v(TAG, "Remove " + profileClass.getSimpleName() + " from supported list."); + synchronized (sSupportedProfiles) { + Iterator<Class> iter = sSupportedProfiles.iterator(); + while (iter.hasNext()) { + Class profileClass = iter.next(); + + if (nonSupportedProfiles.contains(profileClass)) { + iter.remove(); + Log.v(TAG, "Remove " + profileClass.getSimpleName() + " from supported list."); + } } } - - sSupportedProfiles = profilesList.toArray(new Class[profilesList.size()]); } static void updateSupportedProfileMask(Boolean enable, Class profile, int supportedProfile) { @@ -286,7 +295,9 @@ public class Config { } static Class[] getSupportedProfiles() { - return sSupportedProfiles; + synchronized (sSupportedProfiles) { + return sSupportedProfiles.toArray(new Class[0]); + } } static boolean isGdEnabledUpToScanningLayer() { diff --git a/android/app/src/com/android/bluetooth/btservice/ProfileService.java b/android/app/src/com/android/bluetooth/btservice/ProfileService.java index 5795847d1b..acd72c7c69 100644 --- a/android/app/src/com/android/bluetooth/btservice/ProfileService.java +++ b/android/app/src/com/android/bluetooth/btservice/ProfileService.java @@ -18,6 +18,8 @@ package com.android.bluetooth.btservice; import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static java.util.Objects.requireNonNull; + import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.app.Service; @@ -180,6 +182,11 @@ public abstract class ProfileService extends Service { return mBinder; } + IBinder getBinder() { + requireNonNull(mBinder, "Binder is null. onCreate need to be called first"); + return mBinder; + } + @Override // Suppressed since this is called from framework @SuppressLint("AndroidFrameworkRequiresPermission") @@ -295,7 +302,7 @@ public abstract class ProfileService extends Service { android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS }) - protected void doStart() { + void doStart() { Log.v(mName, "doStart"); if (mAdapter == null) { Log.w(mName, "Can't start profile service: device does not have BT"); @@ -321,7 +328,7 @@ public abstract class ProfileService extends Service { mAdapterService.onProfileServiceStateChanged(this, BluetoothAdapter.STATE_ON); } - protected void doStop() { + void doStop() { Log.v(mName, "doStop"); if (mAdapterService == null || mAdapterService.isStartedProfile(mName)) { Log.w(mName, "Unexpectedly do Stop, don't stop."); diff --git a/android/app/src/com/android/bluetooth/btservice/activityAttribution/ActivityAttributionNativeInterface.java b/android/app/src/com/android/bluetooth/btservice/activityAttribution/ActivityAttributionNativeInterface.java index b9cb9d778d..7755ce2d2c 100644 --- a/android/app/src/com/android/bluetooth/btservice/activityAttribution/ActivityAttributionNativeInterface.java +++ b/android/app/src/com/android/bluetooth/btservice/activityAttribution/ActivityAttributionNativeInterface.java @@ -21,26 +21,15 @@ */ package com.android.bluetooth.btservice.activityattribution; -import android.util.Log; - import com.android.internal.annotations.GuardedBy; -import java.util.Arrays; - /** ActivityAttribution Native Interface to/from JNI. */ public class ActivityAttributionNativeInterface { - private static final boolean DBG = false; - private static final String TAG = "ActivityAttributionNativeInterface"; - @GuardedBy("INSTANCE_LOCK") private static ActivityAttributionNativeInterface sInstance; private static final Object INSTANCE_LOCK = new Object(); - static { - classInitNative(); - } - /** Get singleton instance. */ public static ActivityAttributionNativeInterface getInstance() { synchronized (INSTANCE_LOCK) { @@ -51,40 +40,11 @@ public class ActivityAttributionNativeInterface { } } - /** Initializes the native interface. */ - public void init() { - initNative(); - } - - /** Cleanup the native interface. */ - public void cleanup() { - cleanupNative(); - } - /** Notify the UID and package name of the app, and the address of associated active device */ public void notifyActivityAttributionInfo(int uid, String packageName, String deviceAddress) { notifyActivityAttributionInfoNative(uid, packageName, deviceAddress); } - // Callbacks from the native stack back into the Java framework. - // All callbacks are routed via the Service which will disambiguate which - // state machine the message should be routed to. - - private void onWakeup(int activity, byte[] address) { - Log.i(TAG, "onWakeup() BTAA: " + activity); - } - - private void onActivityLogsReady(byte[] logs) { - Log.i(TAG, "onActivityLogsReady() BTAA: " + Arrays.toString(logs)); - } - - // Native methods that call into the JNI interface - private static native void classInitNative(); - - private native void initNative(); - - private native void cleanupNative(); - private native void notifyActivityAttributionInfoNative( - int uid, String packageName, String deviceAddress); + int uid, String packageName, String deviceAddress); } diff --git a/android/app/src/com/android/bluetooth/btservice/activityAttribution/ActivityAttributionService.java b/android/app/src/com/android/bluetooth/btservice/activityAttribution/ActivityAttributionService.java index 033459812a..5194a25313 100644 --- a/android/app/src/com/android/bluetooth/btservice/activityAttribution/ActivityAttributionService.java +++ b/android/app/src/com/android/bluetooth/btservice/activityAttribution/ActivityAttributionService.java @@ -16,108 +16,31 @@ package com.android.bluetooth.btservice.activityattribution; -import android.util.Log; +import static java.util.Objects.requireNonNull; -import java.util.Objects; +import android.util.Log; /** * Service used for attributes wakeup, wakelock and Bluetooth traffic into per-app and per-device * based activities. */ public class ActivityAttributionService { - private boolean mCleaningUp; - private static ActivityAttributionService sActivityAttributionService; - private static final boolean DBG = false; - private static final String TAG = "ActivityAttributionService"; - - ActivityAttributionNativeInterface mActivityAttributionNativeInterface; - - /** Start and initialize the Activity Attribution service. */ - public void start() { - debugLog("start()"); - - if (sActivityAttributionService != null) { - Log.e(TAG, "start() called twice"); - return; - } - - mActivityAttributionNativeInterface = - Objects.requireNonNull( - ActivityAttributionNativeInterface.getInstance(), - "ActivityAttributionNativeInterface " - + "cannot be null when ActivityAttributionService starts"); - - // Mark service as started - setActivityAttributionService(this); - } - - /** Cleans up the Activity Attribution service. */ - public void cleanup() { - debugLog("cleanup"); - if (mCleaningUp) { - debugLog("already doing cleanup"); - return; - } - - mCleaningUp = true; - - if (sActivityAttributionService == null) { - debugLog("cleanup() called before start()"); - return; - } - - // Mark service as stopped - setActivityAttributionService(null); + private static final String TAG = ActivityAttributionService.class.getSimpleName(); - // Cleanup native interface - mActivityAttributionNativeInterface.cleanup(); - mActivityAttributionNativeInterface = null; - } - - /** Get the ActivityAttributionService instance */ - public static synchronized ActivityAttributionService getActivityAttributionService() { - if (sActivityAttributionService == null) { - Log.w(TAG, "getActivityAttributionService(): service is NULL"); - return null; - } - - if (!sActivityAttributionService.isAvailable()) { - Log.w(TAG, "getActivityAttributionService(): service is not available"); - return null; - } - return sActivityAttributionService; - } - - /** Init JNI */ - public void initJni() { - debugLog("initJni()"); - // Initialize native interface - mActivityAttributionNativeInterface.init(); - } + private final ActivityAttributionNativeInterface mActivityAttributionNativeInterface = + requireNonNull( + ActivityAttributionNativeInterface.getInstance(), + "ActivityAttributionNativeInterface cannot be null"); /** Notify the UID and package name of the app, and the address of associated active device */ public void notifyActivityAttributionInfo(int uid, String packageName, String deviceAddress) { - Log.d(TAG, "notifyActivityAttributionInfo" - + " UID=" + uid - + " packageName=" + packageName - + " deviceAddress=" + deviceAddress); + Log.d( + TAG, + "notifyActivityAttributionInfo()" + + (" UID=" + uid) + + (" packageName=" + packageName) + + (" deviceAddress=" + deviceAddress)); mActivityAttributionNativeInterface.notifyActivityAttributionInfo( uid, packageName, deviceAddress); } - - private boolean isAvailable() { - return !mCleaningUp; - } - - private static synchronized void setActivityAttributionService( - ActivityAttributionService instance) { - debugLog("setActivityAttributionService(): set to: " + instance); - sActivityAttributionService = instance; - } - - private static void debugLog(String msg) { - if (DBG) { - Log.d(TAG, msg); - } - } } diff --git a/android/app/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreNativeInterface.java b/android/app/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreNativeInterface.java index ebee407821..0b616accaf 100644 --- a/android/app/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreNativeInterface.java +++ b/android/app/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreNativeInterface.java @@ -18,44 +18,27 @@ package com.android.bluetooth.btservice.bluetoothkeystore; import android.util.Log; -import com.android.internal.annotations.GuardedBy; import java.io.IOException; import java.security.NoSuchAlgorithmException; -final class BluetoothKeystoreNativeInterface { +/** Native interface to be used by BluetoothKeystoreService */ +public class BluetoothKeystoreNativeInterface { + private static final String TAG = BluetoothKeystoreNativeInterface.class.getSimpleName(); - private static final String TAG = "BluetoothKeystoreNativeInterface"; - - @GuardedBy("INSTANCE_LOCK") - private static BluetoothKeystoreNativeInterface sInstance; - private static final Object INSTANCE_LOCK = new Object(); + private BluetoothKeystoreService mBluetoothKeystoreService = null; static { classInitNative(); } - private BluetoothKeystoreNativeInterface() { - } - - /** - * Get singleton instance. - */ - public static BluetoothKeystoreNativeInterface getInstance() { - synchronized (INSTANCE_LOCK) { - if (sInstance == null) { - sInstance = new BluetoothKeystoreNativeInterface(); - } - return sInstance; - } - } - /** * Initializes the native interface. * - * priorities to configure. + * <p>priorities to configure. */ - public void init() { + public void init(BluetoothKeystoreService service) { + mBluetoothKeystoreService = service; initNative(); } @@ -64,6 +47,7 @@ final class BluetoothKeystoreNativeInterface { */ public void cleanup() { cleanupNative(); + mBluetoothKeystoreService = null; } // Callbacks from the native stack back into the Java framework. @@ -71,30 +55,36 @@ final class BluetoothKeystoreNativeInterface { // state machine the message should be routed to. private void setEncryptKeyOrRemoveKeyCallback(String prefixString, String decryptedString) { - BluetoothKeystoreService service = BluetoothKeystoreService.getBluetoothKeystoreService(); - if (service != null) { - try { - service.setEncryptKeyOrRemoveKey(prefixString, decryptedString); - } catch (InterruptedException e) { - Log.e(TAG, "Interrupted while operating."); - } catch (IOException e) { - Log.e(TAG, "IO error while file operating."); - } catch (NoSuchAlgorithmException e) { - Log.e(TAG, "encrypt could not find the algorithm: SHA256"); - } - } else { - Log.e(TAG, "Event ignored, service not available: " + prefixString); + final BluetoothKeystoreService service = mBluetoothKeystoreService; + + if (service == null) { + Log.e( + TAG, + "setEncryptKeyOrRemoveKeyCallback: Event ignored, service not available: " + + prefixString); + return; + } + + try { + service.setEncryptKeyOrRemoveKey(prefixString, decryptedString); + } catch (InterruptedException e) { + Log.e(TAG, "Interrupted while operating."); + } catch (IOException e) { + Log.e(TAG, "IO error while file operating."); + } catch (NoSuchAlgorithmException e) { + Log.e(TAG, "encrypt could not find the algorithm: SHA256"); } } private String getKeyCallback(String prefixString) { - BluetoothKeystoreService service = BluetoothKeystoreService.getBluetoothKeystoreService(); - if (service != null) { - return service.getKey(prefixString); - } else { - Log.e(TAG, "Event ignored, service not available: " + prefixString); + final BluetoothKeystoreService service = mBluetoothKeystoreService; + + if (service == null) { + Log.e(TAG, "getKeyCallback: Event ignored, service not available: " + prefixString); return null; } + + return service.getKey(prefixString); } // Native methods that call into the JNI interface diff --git a/android/app/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreService.java b/android/app/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreService.java index 25b06c3775..743534420b 100644 --- a/android/app/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreService.java +++ b/android/app/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreService.java @@ -46,7 +46,6 @@ import java.util.Base64; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -99,7 +98,7 @@ public class BluetoothKeystoreService { private static final int CONFIG_BACKUP_COMPARE_PASS = 0b10; private int mCompareResult; - BluetoothKeystoreNativeInterface mBluetoothKeystoreNativeInterface; + private final BluetoothKeystoreNativeInterface mBluetoothKeystoreNativeInterface; private ComputeDataThread mEncryptDataThread; private ComputeDataThread mDecryptDataThread; @@ -113,8 +112,10 @@ public class BluetoothKeystoreService { private Base64.Decoder mDecoder = Base64.getDecoder(); private Base64.Encoder mEncoder = Base64.getEncoder(); - public BluetoothKeystoreService(boolean isCommonCriteriaMode) { + public BluetoothKeystoreService( + BluetoothKeystoreNativeInterface nativeInterface, boolean isCommonCriteriaMode) { debugLog("new BluetoothKeystoreService isCommonCriteriaMode: " + isCommonCriteriaMode); + mBluetoothKeystoreNativeInterface = nativeInterface; mIsCommonCriteriaMode = isCommonCriteriaMode; mCompareResult = CONFIG_COMPARE_INIT; startThread(); @@ -140,13 +141,6 @@ public class BluetoothKeystoreService { return; } - mBluetoothKeystoreNativeInterface = Objects.requireNonNull( - BluetoothKeystoreNativeInterface.getInstance(), - "BluetoothKeystoreNativeInterface cannot be null when BluetoothKeystore starts"); - - // Mark service as started - setBluetoothKeystoreService(this); - try { if (!keyStore.containsAlias(KEYALIAS) && mIsCommonCriteriaMode) { infoLog("Enable Common Criteria mode for the first time, pass hash check."); @@ -187,12 +181,9 @@ public class BluetoothKeystoreService { debugLog("cleanup() called before start()"); return; } - // Mark service as stopped - setBluetoothKeystoreService(null); // Cleanup native interface mBluetoothKeystoreNativeInterface.cleanup(); - mBluetoothKeystoreNativeInterface = null; if (mIsCommonCriteriaMode) { cleanupForCommonCriteriaModeEnable(); @@ -296,9 +287,7 @@ public class BluetoothKeystoreService { stopThread(); startThread(); // Initialize native interface - if (mBluetoothKeystoreNativeInterface != null) { - mBluetoothKeystoreNativeInterface.init(); - } + mBluetoothKeystoreNativeInterface.init(this); } private boolean isAvailable() { @@ -306,28 +295,6 @@ public class BluetoothKeystoreService { } /** - * Get the BluetoothKeystoreService instance - */ - public static synchronized BluetoothKeystoreService getBluetoothKeystoreService() { - if (sBluetoothKeystoreService == null) { - debugLog("getBluetoothKeystoreService(): service is NULL"); - return null; - } - - if (!sBluetoothKeystoreService.isAvailable()) { - debugLog("getBluetoothKeystoreService(): service is not available"); - return null; - } - return sBluetoothKeystoreService; - } - - private static synchronized void setBluetoothKeystoreService( - BluetoothKeystoreService instance) { - debugLog("setBluetoothKeystoreService(): set to: " + instance); - sBluetoothKeystoreService = instance; - } - - /** * Gets result of the checksum comparison */ public int getCompareResult() { diff --git a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java index c2dbaaffce..2809b08d77 100644 --- a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java +++ b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java @@ -847,7 +847,7 @@ public class CsipSetCoordinatorService extends ProfileService { intent.addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); - sendBroadcast(intent, BLUETOOTH_PRIVILEGED); + sendOrderedBroadcast(intent, BLUETOOTH_PRIVILEGED); /* Notify registered parties */ handleSetMemberAvailable(device, groupId); @@ -890,7 +890,7 @@ public class CsipSetCoordinatorService extends ProfileService { if (intent != null) { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); - sendBroadcast(intent, BLUETOOTH_PRIVILEGED); + sendOrderedBroadcast(intent, BLUETOOTH_PRIVILEGED); } synchronized (mStateMachines) { diff --git a/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java b/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java index e105abff5b..a632ef9210 100644 --- a/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java +++ b/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java @@ -51,20 +51,23 @@ public class AdvertiseManager { private final GattService mService; private final AdapterService mAdapterService; + private final AdvertiseManagerNativeInterface mNativeInterface; private final AdvertiserMap mAdvertiserMap; private Handler mHandler; Map<IBinder, AdvertiserInfo> mAdvertisers = Collections.synchronizedMap(new HashMap<>()); static int sTempRegistrationId = -1; - /** - * Constructor of {@link AdvertiseManager}. - */ - AdvertiseManager(GattService service, AdapterService adapterService, + /** Constructor of {@link AdvertiseManager}. */ + AdvertiseManager( + GattService service, + AdvertiseManagerNativeInterface nativeInterface, + AdapterService adapterService, AdvertiserMap advertiserMap) { if (DBG) { Log.d(TAG, "advertise manager created"); } mService = service; + mNativeInterface = nativeInterface; mAdapterService = adapterService; mAdvertiserMap = advertiserMap; } @@ -73,7 +76,7 @@ public class AdvertiseManager { * Start a {@link HandlerThread} that handles advertising operations. */ void start() { - initializeNative(); + mNativeInterface.init(this); HandlerThread thread = new HandlerThread("BluetoothAdvertiseManager"); thread.start(); mHandler = new Handler(thread.getLooper()); @@ -83,7 +86,7 @@ public class AdvertiseManager { if (DBG) { Log.d(TAG, "cleanup()"); } - cleanupNative(); + mNativeInterface.cleanup(); mAdvertisers.clear(); sTempRegistrationId = -1; @@ -157,7 +160,7 @@ public class AdvertiseManager { if (entry == null) { Log.i(TAG, "onAdvertisingSetStarted() - no callback found for regId " + regId); // Advertising set was stopped before it was properly registered. - stopAdvertisingSetNative(advertiserId); + mNativeInterface.stopAdvertisingSet(advertiserId); return; } @@ -252,8 +255,15 @@ public class AdvertiseManager { mAdvertiserMap.recordAdvertiseStart(cbId, parameters, advertiseData, scanResponse, periodicParameters, periodicData, duration, maxExtAdvEvents); - startAdvertisingSetNative(parameters, advDataBytes, scanResponseBytes, - periodicParameters, periodicDataBytes, duration, maxExtAdvEvents, cbId, + mNativeInterface.startAdvertisingSet( + parameters, + advDataBytes, + scanResponseBytes, + periodicParameters, + periodicDataBytes, + duration, + maxExtAdvEvents, + cbId, serverIf); } catch (IllegalArgumentException e) { @@ -289,7 +299,7 @@ public class AdvertiseManager { Log.w(TAG, "getOwnAddress() - bad advertiserId " + advertiserId); return; } - getOwnAddressNative(advertiserId); + mNativeInterface.getOwnAddress(advertiserId); } void stopAdvertisingSet(IAdvertisingSetCallback callback) { @@ -313,7 +323,7 @@ public class AdvertiseManager { return; } - stopAdvertisingSetNative(advertiserId); + mNativeInterface.stopAdvertisingSet(advertiserId); try { callback.onAdvertisingSetStopped(advertiserId); @@ -330,7 +340,7 @@ public class AdvertiseManager { Log.w(TAG, "enableAdvertisingSet() - bad advertiserId " + advertiserId); return; } - enableAdvertisingSetNative(advertiserId, enable, duration, maxExtAdvEvents); + mNativeInterface.enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents); mAdvertiserMap.enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents); @@ -344,8 +354,8 @@ public class AdvertiseManager { } String deviceName = AdapterService.getAdapterService().getName(); try { - setAdvertisingDataNative(advertiserId, - AdvertiseHelper.advertiseDataToBytes(data, deviceName)); + mNativeInterface.setAdvertisingData( + advertiserId, AdvertiseHelper.advertiseDataToBytes(data, deviceName)); mAdvertiserMap.setAdvertisingData(advertiserId, data); } catch (IllegalArgumentException e) { @@ -366,8 +376,8 @@ public class AdvertiseManager { } String deviceName = AdapterService.getAdapterService().getName(); try { - setScanResponseDataNative(advertiserId, - AdvertiseHelper.advertiseDataToBytes(data, deviceName)); + mNativeInterface.setScanResponseData( + advertiserId, AdvertiseHelper.advertiseDataToBytes(data, deviceName)); mAdvertiserMap.setScanResponseData(advertiserId, data); } catch (IllegalArgumentException e) { @@ -386,7 +396,7 @@ public class AdvertiseManager { Log.w(TAG, "setAdvertisingParameters() - bad advertiserId " + advertiserId); return; } - setAdvertisingParametersNative(advertiserId, parameters); + mNativeInterface.setAdvertisingParameters(advertiserId, parameters); mAdvertiserMap.setAdvertisingParameters(advertiserId, parameters); } @@ -398,7 +408,7 @@ public class AdvertiseManager { Log.w(TAG, "setPeriodicAdvertisingParameters() - bad advertiserId " + advertiserId); return; } - setPeriodicAdvertisingParametersNative(advertiserId, parameters); + mNativeInterface.setPeriodicAdvertisingParameters(advertiserId, parameters); mAdvertiserMap.setPeriodicAdvertisingParameters(advertiserId, parameters); } @@ -411,8 +421,8 @@ public class AdvertiseManager { } String deviceName = AdapterService.getAdapterService().getName(); try { - setPeriodicAdvertisingDataNative(advertiserId, - AdvertiseHelper.advertiseDataToBytes(data, deviceName)); + mNativeInterface.setPeriodicAdvertisingData( + advertiserId, AdvertiseHelper.advertiseDataToBytes(data, deviceName)); mAdvertiserMap.setPeriodicAdvertisingData(advertiserId, data); } catch (IllegalArgumentException e) { @@ -431,7 +441,7 @@ public class AdvertiseManager { Log.w(TAG, "setPeriodicAdvertisingEnable() - bad advertiserId " + advertiserId); return; } - setPeriodicAdvertisingEnableNative(advertiserId, enable); + mNativeInterface.setPeriodicAdvertisingEnable(advertiserId, enable); } void onAdvertisingDataSet(int advertiserId, int status) throws Exception { @@ -538,40 +548,4 @@ public class AdvertiseManager { stats.onPeriodicAdvertiseEnabled(enable); } } - - static { - classInitNative(); - } - - private static native void classInitNative(); - - private native void initializeNative(); - - private native void cleanupNative(); - - private native void startAdvertisingSetNative(AdvertisingSetParameters parameters, - byte[] advertiseData, byte[] scanResponse, - PeriodicAdvertisingParameters periodicParameters, byte[] periodicData, int duration, - int maxExtAdvEvents, int regId, int serverIf); - - private native void getOwnAddressNative(int advertiserId); - - private native void stopAdvertisingSetNative(int advertiserId); - - private native void enableAdvertisingSetNative(int advertiserId, boolean enable, int duration, - int maxExtAdvEvents); - - private native void setAdvertisingDataNative(int advertiserId, byte[] data); - - private native void setScanResponseDataNative(int advertiserId, byte[] data); - - private native void setAdvertisingParametersNative(int advertiserId, - AdvertisingSetParameters parameters); - - private native void setPeriodicAdvertisingParametersNative(int advertiserId, - PeriodicAdvertisingParameters parameters); - - private native void setPeriodicAdvertisingDataNative(int advertiserId, byte[] data); - - private native void setPeriodicAdvertisingEnableNative(int advertiserId, boolean enable); } diff --git a/android/app/src/com/android/bluetooth/gatt/AdvertiseManagerNativeInterface.java b/android/app/src/com/android/bluetooth/gatt/AdvertiseManagerNativeInterface.java new file mode 100644 index 0000000000..7529bdb86d --- /dev/null +++ b/android/app/src/com/android/bluetooth/gatt/AdvertiseManagerNativeInterface.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2023 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.bluetooth.gatt; + +import android.bluetooth.le.AdvertisingSetParameters; +import android.bluetooth.le.PeriodicAdvertisingParameters; + +import androidx.annotation.VisibleForTesting; + +/** Native interface for AdvertiseManager */ +@VisibleForTesting +public class AdvertiseManagerNativeInterface { + AdvertiseManager mManager; + + void init(AdvertiseManager manager) { + mManager = manager; + initializeNative(); + } + + void cleanup() { + cleanupNative(); + mManager = null; + } + + void startAdvertisingSet( + AdvertisingSetParameters parameters, + byte[] advertiseDataBytes, + byte[] scanResponseBytes, + PeriodicAdvertisingParameters periodicParameters, + byte[] periodicDataBytes, + int duration, + int maxExtAdvEvents, + int cbId, + int serverIf) { + startAdvertisingSetNative( + parameters, + advertiseDataBytes, + scanResponseBytes, + periodicParameters, + periodicDataBytes, + duration, + maxExtAdvEvents, + cbId, + serverIf); + } + + void stopAdvertisingSet(int advertiserId) { + stopAdvertisingSetNative(advertiserId); + } + + void getOwnAddress(int advertiserId) { + getOwnAddressNative(advertiserId); + } + + void enableAdvertisingSet(int advertiserId, boolean enable, int duration, int maxExtAdvEvents) { + enableAdvertisingSetNative(advertiserId, enable, duration, maxExtAdvEvents); + } + + void setAdvertisingData(int advertiserId, byte[] advertiseDataBytes) { + setAdvertisingDataNative(advertiserId, advertiseDataBytes); + } + + void setScanResponseData(int advertiserId, byte[] advertiseDataBytes) { + setScanResponseDataNative(advertiserId, advertiseDataBytes); + } + + void setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters) { + setAdvertisingParametersNative(advertiserId, parameters); + } + + void setPeriodicAdvertisingParameters( + int advertiserId, PeriodicAdvertisingParameters parameters) { + setPeriodicAdvertisingParametersNative(advertiserId, parameters); + } + + void setPeriodicAdvertisingData(int advertiserId, byte[] advertiseDataBytes) { + setPeriodicAdvertisingDataNative(advertiserId, advertiseDataBytes); + } + + void setPeriodicAdvertisingEnable(int advertiserId, boolean enable) { + setPeriodicAdvertisingEnableNative(advertiserId, enable); + } + + static { + classInitNative(); + } + + void onAdvertisingSetStarted(int regId, int advertiserId, int txPower, int status) + throws Exception { + mManager.onAdvertisingSetStarted(regId, advertiserId, txPower, status); + } + + void onOwnAddressRead(int advertiserId, int addressType, String address) throws Exception { + mManager.onOwnAddressRead(advertiserId, addressType, address); + } + + void onAdvertisingEnabled(int advertiserId, boolean enable, int status) throws Exception { + mManager.onAdvertisingEnabled(advertiserId, enable, status); + } + + void onAdvertisingDataSet(int advertiserId, int status) throws Exception { + mManager.onAdvertisingDataSet(advertiserId, status); + } + + void onScanResponseDataSet(int advertiserId, int status) throws Exception { + mManager.onScanResponseDataSet(advertiserId, status); + } + + void onAdvertisingParametersUpdated(int advertiserId, int txPower, int status) + throws Exception { + mManager.onAdvertisingParametersUpdated(advertiserId, txPower, status); + } + + void onPeriodicAdvertisingParametersUpdated(int advertiserId, int status) throws Exception { + mManager.onPeriodicAdvertisingParametersUpdated(advertiserId, status); + } + + void onPeriodicAdvertisingDataSet(int advertiserId, int status) throws Exception { + mManager.onPeriodicAdvertisingDataSet(advertiserId, status); + } + + void onPeriodicAdvertisingEnabled(int advertiserId, boolean enable, int status) + throws Exception { + mManager.onPeriodicAdvertisingEnabled(advertiserId, enable, status); + } + + private static native void classInitNative(); + + private native void initializeNative(); + + private native void cleanupNative(); + + private native void startAdvertisingSetNative( + AdvertisingSetParameters parameters, + byte[] advertiseData, + byte[] scanResponse, + PeriodicAdvertisingParameters periodicParameters, + byte[] periodicData, + int duration, + int maxExtAdvEvents, + int regId, + int serverIf); + + private native void stopAdvertisingSetNative(int advertiserId); + + private native void getOwnAddressNative(int advertiserId); + + private native void enableAdvertisingSetNative( + int advertiserId, boolean enable, int duration, int maxExtAdvEvents); + + private native void setAdvertisingDataNative(int advertiserId, byte[] data); + + private native void setScanResponseDataNative(int advertiserId, byte[] data); + + private native void setAdvertisingParametersNative( + int advertiserId, AdvertisingSetParameters parameters); + + private native void setPeriodicAdvertisingParametersNative( + int advertiserId, PeriodicAdvertisingParameters parameters); + + private native void setPeriodicAdvertisingDataNative(int advertiserId, byte[] data); + + private native void setPeriodicAdvertisingEnableNative(int advertiserId, boolean enable); +} diff --git a/android/app/src/com/android/bluetooth/gatt/GattService.java b/android/app/src/com/android/bluetooth/gatt/GattService.java index eaf11c027f..0156835787 100644 --- a/android/app/src/com/android/bluetooth/gatt/GattService.java +++ b/android/app/src/com/android/bluetooth/gatt/GattService.java @@ -56,6 +56,7 @@ import android.bluetooth.le.ScanSettings; import android.companion.AssociationInfo; import android.companion.CompanionDeviceManager; import android.content.AttributionSource; +import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.PackageInfoFlags; @@ -290,6 +291,11 @@ public class GattService extends ProfileService { private Handler mTestModeHandler; private final Object mTestModeLock = new Object(); + public GattService(Context ctx) { + attachBaseContext(ctx); + onCreate(); + } + public static boolean isEnabled() { return BluetoothProperties.isProfileGattEnabled().orElse(true); } @@ -341,7 +347,12 @@ public class GattService extends ProfileService { mBluetoothAdapterProxy = BluetoothAdapterProxy.getInstance(); mCompanionManager = getSystemService(CompanionDeviceManager.class); mAppOps = getSystemService(AppOpsManager.class); - mAdvertiseManager = new AdvertiseManager(this, mAdapterService, mAdvertiserMap); + mAdvertiseManager = + new AdvertiseManager( + this, + new AdvertiseManagerNativeInterface(), + mAdapterService, + mAdvertiserMap); mAdvertiseManager.start(); mScanManager = GattObjectsFactory.getInstance() @@ -607,34 +618,6 @@ public class GattService extends ProfileService { } @Override - public void startService() { - GattService service = mService; - if (service == null) { - Log.e(TAG, "startService: Service is null"); - return; - } - if (!Utils.checkConnectPermissionForDataDelivery( - service, null, "GattService startService")) { - return; - } - service.doStart(); - } - - @Override - public void stopService() { - GattService service = mService; - if (service == null) { - Log.e(TAG, "stopService: Service is null"); - return; - } - if (!Utils.checkConnectPermissionForDataDelivery( - service, null, "GattService stopService")) { - return; - } - service.doStop(); - } - - @Override public void getDevicesMatchingConnectionStates(int[] states, AttributionSource attributionSource, SynchronousResultReceiver receiver) { try { @@ -1773,15 +1756,6 @@ public class GattService extends ProfileService { } @Override - public void unregAll(AttributionSource attributionSource) { - GattService service = getService(); - if (service == null) { - return; - } - service.unregAll(attributionSource); - } - - @Override public void numHwTrackFiltersAvailable(AttributionSource attributionSource, SynchronousResultReceiver receiver) { try { @@ -3430,7 +3404,7 @@ public class GattService extends ProfileService { } @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - void unregAll(AttributionSource attributionSource) { + public void unregAll(AttributionSource attributionSource) { for (Integer appId : mClientMap.getAllAppsIds()) { if (DBG) { Log.d(TAG, "unreg:" + appId); diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java index b5691062ee..9c2c7fee48 100644 --- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java +++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java @@ -1127,6 +1127,37 @@ public class LeAudioService extends ProfileService { } /** + * Send broadcast intent about LeAudio connection state changed. This is called by + * LeAudioStateMachine. + */ + void notifyConnectionStateChanged(BluetoothDevice device, int newState, int prevState) { + if (DBG) { + Log.d( + TAG, + "Notify connection state changed." + + device + + "(" + + prevState + + " -> " + + newState + + ")"); + } + + mAdapterService + .getActiveDeviceManager() + .leAudioConnectionStateChanged(device, prevState, newState); + Intent intent = new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED); + intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); + intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); + intent.addFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT + | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + Utils.sendBroadcast( + this, intent, BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions()); + } + + /** * Send broadcast intent about LeAudio active device. * This is called when AudioManager confirms, LeAudio device * is added or removed. @@ -1138,6 +1169,7 @@ public class LeAudioService extends ProfileService { + ". Currently active device is " + mActiveAudioOutDevice); } + mAdapterService.getActiveDeviceManager().leAudioActiveStateChanged(device); Intent intent = new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioStateMachine.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioStateMachine.java index a1411f6934..0eb7577d72 100644 --- a/android/app/src/com/android/bluetooth/le_audio/LeAudioStateMachine.java +++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioStateMachine.java @@ -47,15 +47,11 @@ package com.android.bluetooth.le_audio; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothProfile; -import android.content.Intent; import android.os.Looper; import android.os.Message; import android.util.Log; -import static android.Manifest.permission.BLUETOOTH_CONNECT; -import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.ProfileService; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.State; @@ -514,15 +510,7 @@ final class LeAudioStateMachine extends StateMachine { private void broadcastConnectionState(int newState, int prevState) { log("Connection state " + mDevice + ": " + profileStateToString(prevState) + "->" + profileStateToString(newState)); - - Intent intent = new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED); - intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); - intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); - intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT - | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); - Utils.sendBroadcast(mService, intent, BLUETOOTH_CONNECT, - Utils.getTempAllowlistBroadcastOptions()); + mService.notifyConnectionStateChanged(mDevice, newState, prevState); } private static String messageWhatToString(int what) { diff --git a/android/app/tests/unit/AndroidTest.xml b/android/app/tests/unit/AndroidTest.xml index 37bd75b6eb..212b245d6e 100644 --- a/android/app/tests/unit/AndroidTest.xml +++ b/android/app/tests/unit/AndroidTest.xml @@ -30,6 +30,10 @@ <option name="run-command" value="settings put global ble_scan_always_enabled 0" /> <option name="run-command" value="cmd bluetooth_manager disable" /> <option name="run-command" value="cmd bluetooth_manager wait-for-state:STATE_OFF" /> + <option name="run-command" value="settings put global satellite_mode_radios bluetooth" /> + <option name="run-command" value="settings put global satellite_mode_enabled 1" /> + <option name="teardown-command" value="settings delete global satellite_mode_radios" /> + <option name="teardown-command" value="settings put global satellite_mode_enabled 0" /> <option name="teardown-command" value="cmd bluetooth_manager enable" /> <option name="teardown-command" value="cmd bluetooth_manager wait-for-state:STATE_ON" /> <option name="teardown-command" value="settings put global ble_scan_always_enabled 1" /> diff --git a/android/app/tests/unit/src/com/android/bluetooth/TestUtils.java b/android/app/tests/unit/src/com/android/bluetooth/TestUtils.java index 4104391c2e..d605ef2f8e 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/TestUtils.java +++ b/android/app/tests/unit/src/com/android/bluetooth/TestUtils.java @@ -39,6 +39,7 @@ import androidx.test.uiautomator.UiDevice; import com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.ProfileService; +import com.android.bluetooth.gatt.GattService; import org.junit.Assert; import org.junit.rules.TestRule; @@ -51,8 +52,6 @@ import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.HashMap; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; @@ -93,49 +92,45 @@ public class TestUtils { /** * Set the return value of {@link AdapterService#getAdapterService()} to a test specified value * - * @param adapterService the designated {@link AdapterService} in test, must not be null, can - * be mocked or spied - * @throws NoSuchMethodException when setAdapterService method is not found - * @throws IllegalAccessException when setAdapterService method cannot be accessed - * @throws InvocationTargetException when setAdapterService method cannot be invoked, which - * should never happen since setAdapterService is a static - * method + * @param adapterService the designated {@link AdapterService} in test, must not be null, can be + * mocked or spied */ - public static void setAdapterService(AdapterService adapterService) - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + public static void setAdapterService(AdapterService adapterService) { Assert.assertNull("AdapterService.getAdapterService() must be null before setting another" + " AdapterService", AdapterService.getAdapterService()); Assert.assertNotNull("Adapter service should not be null", adapterService); // We cannot mock AdapterService.getAdapterService() with Mockito. - // Hence we need to use reflection to call a private method to - // initialize properly the AdapterService.sAdapterService field. - Method method = - AdapterService.class.getDeclaredMethod("setAdapterService", AdapterService.class); - method.setAccessible(true); - method.invoke(null, adapterService); + // Hence we need to set AdapterService.sAdapterService field. + AdapterService.setAdapterService(adapterService); } /** * Clear the return value of {@link AdapterService#getAdapterService()} to null * - * @param adapterService the {@link AdapterService} used when calling - * {@link TestUtils#setAdapterService(AdapterService)} - * @throws NoSuchMethodException when clearAdapterService method is not found - * @throws IllegalAccessException when clearAdapterService method cannot be accessed - * @throws InvocationTargetException when clearAdappterService method cannot be invoked, - * which should never happen since clearAdapterService is a - * static method + * @param adapterService the {@link AdapterService} used when calling {@link + * TestUtils#setAdapterService(AdapterService)} */ - public static void clearAdapterService(AdapterService adapterService) - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + public static void clearAdapterService(AdapterService adapterService) { Assert.assertSame("AdapterService.getAdapterService() must return the same object as the" + " supplied adapterService in this method", adapterService, AdapterService.getAdapterService()); Assert.assertNotNull("Adapter service should not be null", adapterService); - Method method = - AdapterService.class.getDeclaredMethod("clearAdapterService", AdapterService.class); - method.setAccessible(true); - method.invoke(null, adapterService); + AdapterService.clearAdapterService(adapterService); + } + + /** Helper function to mock getSystemService calls */ + public static <T> void mockGetSystemService( + Context ctx, String serviceName, Class<T> serviceClass, T mockService) { + when(ctx.getSystemService(eq(serviceName))).thenReturn(mockService); + when(ctx.getSystemServiceName(eq(serviceClass))).thenReturn(serviceName); + } + + /** Helper function to mock getSystemService calls */ + public static <T> T mockGetSystemService( + Context ctx, String serviceName, Class<T> serviceClass) { + T mockedService = mock(serviceClass); + mockGetSystemService(ctx, serviceName, serviceClass, mockedService); + return mockedService; } /** @@ -156,6 +151,9 @@ public class TestUtils { */ public static <T extends ProfileService> void startService(ServiceTestRule serviceTestRule, Class<T> profileServiceClass) throws TimeoutException { + if (profileServiceClass == GattService.class) { + Assert.assertFalse("GattService cannot be started as a service", true); + } AdapterService adapterService = AdapterService.getAdapterService(); Assert.assertNotNull("Adapter service should not be null", adapterService); Assert.assertTrue("AdapterService.getAdapterService() must return a mocked or spied object" diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java index 80c62f0edc..2fa6849c3e 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java @@ -405,7 +405,7 @@ public class AvrcpControllerStateMachineTest { BluetoothMediaBrowserService.getTransportControls(); Assert.assertNotNull(transportControls); Assert.assertEquals(PlaybackStateCompat.STATE_NONE, - BluetoothMediaBrowserService.getPlaybackState()); + BluetoothMediaBrowserService.getPlaybackState().getState()); mAvrcpStateMachine.disconnect(); numBroadcastsSent += 2; verify(mAvrcpControllerService, @@ -434,7 +434,7 @@ public class AvrcpControllerStateMachineTest { int numBroadcastsSent = setUpConnectedState(false, true); Assert.assertEquals(1, mAvrcpControllerService.sBrowseTree.mRootNode.getChildrenCount()); Assert.assertEquals(PlaybackStateCompat.STATE_NONE, - BluetoothMediaBrowserService.getPlaybackState()); + BluetoothMediaBrowserService.getPlaybackState().getState()); mAvrcpStateMachine.disconnect(); numBroadcastsSent += 2; verify(mAvrcpControllerService, @@ -1268,6 +1268,69 @@ public class AvrcpControllerStateMachineTest { Assert.assertFalse(mAvrcpStateMachine.isActive()); } + @Test + public void testTrackChangedWhileActive_currentTrackAndQueueNumberUpdated() { + setUpConnectedState(true, true); + + // Set track + AvrcpItem track = makeTrack("Song 1", "artist", "album", 1, 2, "none", 10, null); + setCurrentTrack(track); + + // Set current Now Playing list + List<AvrcpItem> nowPlayingList = new ArrayList<AvrcpItem>(); + nowPlayingList.add(makeNowPlayingItem(1, "Song 1")); + nowPlayingList.add(makeNowPlayingItem(2, "Song 2")); + setNowPlayingList(nowPlayingList); + + // Set playing + setPlaybackState(PlaybackStateCompat.STATE_PLAYING); + + // Wait + TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper()); + + // Verify track and playback state + MediaSessionCompat session = BluetoothMediaBrowserService.getSession(); + Assert.assertNotNull(session); + MediaControllerCompat controller = session.getController(); + Assert.assertNotNull(controller); + + MediaMetadataCompat metadata = controller.getMetadata(); + Assert.assertNotNull(metadata); + Assert.assertEquals("Song 1", metadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE)); + Assert.assertEquals("artist", metadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST)); + Assert.assertEquals("album", metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM)); + Assert.assertEquals(1, metadata.getLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER)); + Assert.assertEquals(2, metadata.getLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS)); + Assert.assertEquals("none", metadata.getString(MediaMetadataCompat.METADATA_KEY_GENRE)); + Assert.assertEquals(10, metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION)); + + PlaybackStateCompat playbackState = controller.getPlaybackState(); + Assert.assertNotNull(playbackState); + Assert.assertEquals(PlaybackStateCompat.STATE_PLAYING, playbackState.getState()); + Assert.assertEquals(0, playbackState.getActiveQueueItemId()); + + // Track changes, with new metadata and new track number + track = makeTrack("Song 2", "artist", "album", 2, 2, "none", 10, null); + setCurrentTrack(track); + TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper()); + + // Assert new track metadata and active queue item + metadata = controller.getMetadata(); + Assert.assertNotNull(metadata); + Assert.assertEquals("Song 2", metadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE)); + Assert.assertEquals("artist", metadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST)); + Assert.assertEquals("album", metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM)); + Assert.assertEquals(2, metadata.getLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER)); + Assert.assertEquals(2, metadata.getLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS)); + Assert.assertEquals("none", metadata.getString(MediaMetadataCompat.METADATA_KEY_GENRE)); + Assert.assertEquals(10, metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION)); + + playbackState = controller.getPlaybackState(); + Assert.assertNotNull(playbackState); + Assert.assertEquals(PlaybackStateCompat.STATE_PLAYING, playbackState.getState()); + Assert.assertEquals(1, playbackState.getActiveQueueItemId()); + } + /** * Test receiving a track change update when we're not the active device */ @@ -1318,7 +1381,7 @@ public class AvrcpControllerStateMachineTest { eq(mTestAddress), eq(AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE), eq(KEY_DOWN)); verify(mA2dpSinkService, never()).requestAudioFocus(mTestDevice, true); Assert.assertEquals(PlaybackStateCompat.STATE_ERROR, - BluetoothMediaBrowserService.getPlaybackState()); + BluetoothMediaBrowserService.getPlaybackState().getState()); } /** diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java index 24f282dafa..1b444ced73 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java @@ -32,11 +32,9 @@ import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothSinkAudioPolicy; import android.content.Context; -import android.content.Intent; import android.media.AudioManager; import android.util.ArrayMap; import android.util.SparseIntArray; @@ -1249,11 +1247,8 @@ public class ActiveDeviceManagerTest { private void leAudioConnected(BluetoothDevice device) { mMostRecentDevice = device; - Intent intent = new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED); - intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); - intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_DISCONNECTED); - intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED); - mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent); + mActiveDeviceManager.leAudioConnectionStateChanged( + device, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED); } /** @@ -1264,11 +1259,8 @@ public class ActiveDeviceManagerTest { mMostRecentDevice = (mDeviceConnectionStack.size() > 0) ? mDeviceConnectionStack.get(mDeviceConnectionStack.size() - 1) : null; - Intent intent = new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED); - intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); - intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTED); - intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED); - mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent); + mActiveDeviceManager.leAudioConnectionStateChanged( + device, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); } /** @@ -1279,9 +1271,7 @@ public class ActiveDeviceManagerTest { mDeviceConnectionStack.add(device); mMostRecentDevice = device; - Intent intent = new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED); - intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); - mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent); + mActiveDeviceManager.leAudioActiveStateChanged(device); } /** diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceFactoryResetTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceFactoryResetTest.java index 9d81e88e5f..beb4a4554c 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceFactoryResetTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceFactoryResetTest.java @@ -36,6 +36,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.content.res.Resources; +import android.hardware.display.DisplayManager; import android.media.AudioManager; import android.os.BatteryStatsManager; import android.os.Binder; @@ -91,16 +92,10 @@ public class AdapterServiceFactoryResetTest { private @Mock android.app.Application mApplication; private @Mock MetricsLogger mMockMetricsLogger; - // Mocked SystemService - private @Mock AlarmManager mMockAlarmManager; - private @Mock AppOpsManager mMockAppOpsManager; - private @Mock AudioManager mMockAudioManager; - private @Mock DevicePolicyManager mMockDevicePolicyManager; - private @Mock UserManager mMockUserManager; - // SystemService that are not mocked private BluetoothManager mBluetoothManager; private CompanionDeviceManager mCompanionDeviceManager; + private DisplayManager mDisplayManager; private PowerManager mPowerManager; private PermissionCheckerManager mPermissionCheckerManager; private PermissionManager mPermissionManager; @@ -131,6 +126,12 @@ public class AdapterServiceFactoryResetTest { when(mMockContext.getSystemServiceName(eq(serviceClass))).thenReturn(serviceName); } + <T> T mockGetSystemService(String serviceName, Class<T> serviceClass) { + T mockedService = mock(serviceClass); + mockGetSystemService(serviceName, serviceClass, mockedService); + return mockedService; + } + @Before public void setUp() throws PackageManager.NameNotFoundException { Log.e(TAG, "setUp()"); @@ -156,23 +157,20 @@ public class AdapterServiceFactoryResetTest { } }); - mPowerManager = InstrumentationRegistry.getTargetContext() - .getSystemService(PowerManager.class); - mPermissionCheckerManager = InstrumentationRegistry.getTargetContext() - .getSystemService(PermissionCheckerManager.class); - - mPermissionManager = InstrumentationRegistry.getTargetContext() - .getSystemService(PermissionManager.class); + Context targetContext = InstrumentationRegistry.getTargetContext(); - mBluetoothManager = InstrumentationRegistry.getTargetContext() - .getSystemService(BluetoothManager.class); - - mCompanionDeviceManager = - InstrumentationRegistry.getTargetContext() - .getSystemService(CompanionDeviceManager.class); + mBluetoothManager = targetContext.getSystemService(BluetoothManager.class); + mCompanionDeviceManager = targetContext.getSystemService(CompanionDeviceManager.class); + mDisplayManager = targetContext.getSystemService(DisplayManager.class); + mPermissionCheckerManager = targetContext.getSystemService(PermissionCheckerManager.class); + mPermissionManager = targetContext.getSystemService(PermissionManager.class); + mPowerManager = targetContext.getSystemService(PowerManager.class); when(mMockContext.getCacheDir()) .thenReturn(InstrumentationRegistry.getTargetContext().getCacheDir()); + when(mMockContext.getUser()) + .thenReturn(InstrumentationRegistry.getTargetContext().getUser()); + when(mMockContext.getPackageName()).thenReturn("com.android.bluetooth"); when(mMockContext.getApplicationInfo()).thenReturn(mMockApplicationInfo); when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver); when(mMockContext.getApplicationContext()).thenReturn(mMockContext); @@ -182,12 +180,13 @@ public class AdapterServiceFactoryResetTest { when(mMockContext.getUserId()).thenReturn(Process.BLUETOOTH_UID); when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); - mockGetSystemService(Context.ALARM_SERVICE, AlarmManager.class, mMockAlarmManager); - mockGetSystemService(Context.APP_OPS_SERVICE, AppOpsManager.class, mMockAppOpsManager); - mockGetSystemService(Context.AUDIO_SERVICE, AudioManager.class, mMockAudioManager); - mockGetSystemService( - Context.DEVICE_POLICY_SERVICE, DevicePolicyManager.class, mMockDevicePolicyManager); - mockGetSystemService(Context.USER_SERVICE, UserManager.class, mMockUserManager); + mockGetSystemService(Context.ALARM_SERVICE, AlarmManager.class); + mockGetSystemService(Context.APP_OPS_SERVICE, AppOpsManager.class); + mockGetSystemService(Context.AUDIO_SERVICE, AudioManager.class); + DevicePolicyManager dpm = + mockGetSystemService(Context.DEVICE_POLICY_SERVICE, DevicePolicyManager.class); + doReturn(false).when(dpm).isCommonCriteriaModeEnabled(any()); + mockGetSystemService(Context.USER_SERVICE, UserManager.class); mockGetSystemService( Context.BATTERY_STATS_SERVICE, BatteryStatsManager.class, mBatteryStatsManager); @@ -196,6 +195,7 @@ public class AdapterServiceFactoryResetTest { Context.COMPANION_DEVICE_SERVICE, CompanionDeviceManager.class, mCompanionDeviceManager); + mockGetSystemService(Context.DISPLAY_SERVICE, DisplayManager.class, mDisplayManager); mockGetSystemService( Context.PERMISSION_CHECKER_SERVICE, PermissionCheckerManager.class, @@ -221,8 +221,6 @@ public class AdapterServiceFactoryResetTest { UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid); Utils.setForegroundUserId(callingUser.getIdentifier()); - when(mMockDevicePolicyManager.isCommonCriteriaModeEnabled(any())).thenReturn(false); - when(mIBluetoothCallback.asBinder()).thenReturn(mBinder); doReturn(Process.BLUETOOTH_UID).when(mMockPackageManager) diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceRestartTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceRestartTest.java index 96ccb11add..e02a34d8d4 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceRestartTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceRestartTest.java @@ -162,6 +162,9 @@ public class AdapterServiceRestartTest { when(mMockContext.getCacheDir()).thenReturn(InstrumentationRegistry.getTargetContext() .getCacheDir()); + when(mMockContext.getUser()) + .thenReturn(InstrumentationRegistry.getTargetContext().getUser()); + when(mMockContext.getPackageName()).thenReturn("com.android.bluetooth"); when(mMockContext.getApplicationInfo()).thenReturn(mMockApplicationInfo); when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver); when(mMockContext.getApplicationContext()).thenReturn(mMockContext); diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java index 61aefd7b9f..db52e36d63 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java @@ -26,6 +26,7 @@ import static android.bluetooth.BluetoothAdapter.STATE_TURNING_OFF; import static android.bluetooth.BluetoothAdapter.STATE_TURNING_ON; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -43,6 +44,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.content.res.Resources; +import android.hardware.display.DisplayManager; import android.media.AudioManager; import android.os.BatteryStatsManager; import android.os.Binder; @@ -142,16 +144,10 @@ public class AdapterServiceTest { private @Mock android.app.Application mApplication; private @Mock MetricsLogger mMockMetricsLogger; - // Mocked SystemService - private @Mock AlarmManager mMockAlarmManager; - private @Mock AppOpsManager mMockAppOpsManager; - private @Mock AudioManager mMockAudioManager; - private @Mock DevicePolicyManager mMockDevicePolicyManager; - private @Mock UserManager mMockUserManager; - // SystemService that are not mocked private BluetoothManager mBluetoothManager; private CompanionDeviceManager mCompanionDeviceManager; + private DisplayManager mDisplayManager; private PowerManager mPowerManager; private PermissionCheckerManager mPermissionCheckerManager; private PermissionManager mPermissionManager; @@ -222,8 +218,11 @@ public class AdapterServiceTest { } <T> void mockGetSystemService(String serviceName, Class<T> serviceClass, T mockService) { - when(mMockContext.getSystemService(eq(serviceName))).thenReturn(mockService); - when(mMockContext.getSystemServiceName(eq(serviceClass))).thenReturn(serviceName); + TestUtils.mockGetSystemService(mMockContext, serviceName, serviceClass, mockService); + } + + <T> T mockGetSystemService(String serviceName, Class<T> serviceClass) { + return TestUtils.mockGetSystemService(mMockContext, serviceName, serviceClass); } @Before @@ -251,23 +250,20 @@ public class AdapterServiceTest { } }); - mPowerManager = InstrumentationRegistry.getTargetContext() - .getSystemService(PowerManager.class); - mPermissionCheckerManager = InstrumentationRegistry.getTargetContext() - .getSystemService(PermissionCheckerManager.class); - - mPermissionManager = InstrumentationRegistry.getTargetContext() - .getSystemService(PermissionManager.class); + Context targetContext = InstrumentationRegistry.getTargetContext(); - mBluetoothManager = InstrumentationRegistry.getTargetContext() - .getSystemService(BluetoothManager.class); - - mCompanionDeviceManager = - InstrumentationRegistry.getTargetContext() - .getSystemService(CompanionDeviceManager.class); + mBluetoothManager = targetContext.getSystemService(BluetoothManager.class); + mCompanionDeviceManager = targetContext.getSystemService(CompanionDeviceManager.class); + mDisplayManager = targetContext.getSystemService(DisplayManager.class); + mPermissionCheckerManager = targetContext.getSystemService(PermissionCheckerManager.class); + mPermissionManager = targetContext.getSystemService(PermissionManager.class); + mPowerManager = targetContext.getSystemService(PowerManager.class); when(mMockContext.getCacheDir()).thenReturn(InstrumentationRegistry.getTargetContext() .getCacheDir()); + when(mMockContext.getUser()) + .thenReturn(InstrumentationRegistry.getTargetContext().getUser()); + when(mMockContext.getPackageName()).thenReturn("com.android.bluetooth"); when(mMockContext.getApplicationInfo()).thenReturn(mMockApplicationInfo); when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver); when(mMockContext.getApplicationContext()).thenReturn(mMockContext); @@ -277,12 +273,13 @@ public class AdapterServiceTest { when(mMockContext.getUserId()).thenReturn(Process.BLUETOOTH_UID); when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); - mockGetSystemService(Context.ALARM_SERVICE, AlarmManager.class, mMockAlarmManager); - mockGetSystemService(Context.APP_OPS_SERVICE, AppOpsManager.class, mMockAppOpsManager); - mockGetSystemService(Context.AUDIO_SERVICE, AudioManager.class, mMockAudioManager); - mockGetSystemService( - Context.DEVICE_POLICY_SERVICE, DevicePolicyManager.class, mMockDevicePolicyManager); - mockGetSystemService(Context.USER_SERVICE, UserManager.class, mMockUserManager); + mockGetSystemService(Context.ALARM_SERVICE, AlarmManager.class); + mockGetSystemService(Context.APP_OPS_SERVICE, AppOpsManager.class); + mockGetSystemService(Context.AUDIO_SERVICE, AudioManager.class); + DevicePolicyManager dpm = + mockGetSystemService(Context.DEVICE_POLICY_SERVICE, DevicePolicyManager.class); + doReturn(false).when(dpm).isCommonCriteriaModeEnabled(any()); + mockGetSystemService(Context.USER_SERVICE, UserManager.class); mockGetSystemService( Context.BATTERY_STATS_SERVICE, BatteryStatsManager.class, mBatteryStatsManager); @@ -291,6 +288,7 @@ public class AdapterServiceTest { Context.COMPANION_DEVICE_SERVICE, CompanionDeviceManager.class, mCompanionDeviceManager); + mockGetSystemService(Context.DISPLAY_SERVICE, DisplayManager.class, mDisplayManager); mockGetSystemService( Context.PERMISSION_CHECKER_SERVICE, PermissionCheckerManager.class, @@ -303,8 +301,6 @@ public class AdapterServiceTest { .thenReturn(InstrumentationRegistry.getTargetContext() .getSharedPreferences("AdapterServiceTestPrefs", Context.MODE_PRIVATE)); - doReturn(true).when(mMockContext).bindServiceAsUser(any(), any(), anyInt(), any()); - doAnswer(invocation -> { Object[] args = invocation.getArguments(); return InstrumentationRegistry.getTargetContext().getDatabasePath((String) args[0]); @@ -316,8 +312,6 @@ public class AdapterServiceTest { UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid); Utils.setForegroundUserId(callingUser.getIdentifier()); - when(mMockDevicePolicyManager.isCommonCriteriaModeEnabled(any())).thenReturn(false); - when(mIBluetoothCallback.asBinder()).thenReturn(mBinder); doReturn(Process.BLUETOOTH_UID).when(mMockPackageManager) @@ -367,14 +361,23 @@ public class AdapterServiceTest { syncHandler(mLooper, what); } + private void dropNextMessage(int what) { + Message msg = mLooper.nextMessage(); + assertThat(msg).isNotNull(); + assertWithMessage("Not the expected Message:\n" + msg).that(msg.what).isEqualTo(what); + Log.d(TAG, "Message dropped on purpose: " + msg); + } + private static void syncHandler(TestLooper looper, int... what) { IntStream.of(what) .forEach( w -> { Message msg = looper.nextMessage(); assertThat(msg).isNotNull(); - assertThat(msg.what).isEqualTo(w); - Log.d(TAG, "Processing message: " + msg.what); + assertWithMessage("Not the expected Message:\n" + msg) + .that(msg.what) + .isEqualTo(w); + Log.d(TAG, "Processing message: " + msg); msg.getTarget().dispatchMessage(msg); }); } @@ -422,12 +425,9 @@ public class AdapterServiceTest { adapter.enable(false); syncHandler(looper, AdapterState.BLE_TURN_ON); verifyStateChange(callback, STATE_OFF, STATE_BLE_TURNING_ON); - verify(ctx).bindServiceAsUser(any(), any(), anyInt(), any()); - adapter.addProfile(gattService); syncHandler(looper, MESSAGE_PROFILE_SERVICE_REGISTERED); - adapter.onProfileServiceStateChanged(gattService, STATE_ON); syncHandler(looper, MESSAGE_PROFILE_SERVICE_STATE_CHANGED); // Native loop is not in TestLooper and it will send a event later @@ -550,9 +550,7 @@ public class AdapterServiceTest { adapter.stopBle(); syncHandler(looper, AdapterState.BLE_TURN_OFF); verifyStateChange(callback, STATE_BLE_ON, STATE_BLE_TURNING_OFF); - verify(ctx).unbindService(any()); - adapter.onProfileServiceStateChanged(gattService, STATE_OFF); syncHandler(looper, MESSAGE_PROFILE_SERVICE_STATE_CHANGED); // Native loop is not in TestLooper and it will send a event later @@ -630,14 +628,15 @@ public class AdapterServiceTest { mAdapterService.enable(false); syncHandler(AdapterState.BLE_TURN_ON); verifyStateChange(STATE_OFF, STATE_BLE_TURNING_ON); - verify(mMockContext).bindServiceAsUser(any(), any(), anyInt(), any()); - - mAdapterService.addProfile(mMockGattService); + assertThat(mAdapterService.getBluetoothGatt()).isNotNull(); syncHandler(MESSAGE_PROFILE_SERVICE_REGISTERED); + // Fetch next message and never process it to simulate a timeout. + dropNextMessage(MESSAGE_PROFILE_SERVICE_STATE_CHANGED); + mLooper.moveTimeForward(120_000); // Skip time so the timeout fires syncHandler(AdapterState.BLE_START_TIMEOUT); - verify(mMockContext).unbindService(any()); + assertThat(mAdapterService.getBluetoothGatt()).isNull(); // Native loop is not in TestLooper and it will send a event later mLooper.startAutoDispatch(); @@ -666,7 +665,11 @@ public class AdapterServiceTest { mAdapterService.stopBle(); syncHandler(AdapterState.BLE_TURN_OFF); verifyStateChange(STATE_BLE_ON, STATE_BLE_TURNING_OFF, CONTEXT_SWITCH_MS); - verify(mMockContext).unbindService(any()); // Stop GATT + assertThat(mAdapterService.getBluetoothGatt()).isNull(); + + // Fetch Gatt message and never process it to simulate a timeout. + dropNextMessage(MESSAGE_PROFILE_SERVICE_STATE_CHANGED); + dropNextMessage(MESSAGE_PROFILE_SERVICE_UNREGISTERED); mLooper.moveTimeForward(120_000); // Skip time so the timeout fires syncHandler(AdapterState.BLE_STOP_TIMEOUT); @@ -711,7 +714,7 @@ public class AdapterServiceTest { verifyStateChange(STATE_TURNING_OFF, STATE_BLE_ON); // Ensure GATT is still running - verify(mMockContext, times(0)).unbindService(any()); + assertThat(mAdapterService.getBluetoothGatt()).isNotNull(); } /** @@ -735,10 +738,9 @@ public class AdapterServiceTest { mLooper.moveTimeForward(120_000); // Skip time so the timeout fires syncHandler(AdapterState.BREDR_STOP_TIMEOUT); verifyStateChange(STATE_TURNING_OFF, STATE_BLE_TURNING_OFF); - verify(mMockContext).unbindService(any()); - mAdapterService.onProfileServiceStateChanged(mMockGattService, STATE_OFF); syncHandler(MESSAGE_PROFILE_SERVICE_STATE_CHANGED); + syncHandler(MESSAGE_PROFILE_SERVICE_UNREGISTERED); // TODO(b/280518177): The only timeout to fire here should be the BREDR mLooper.moveTimeForward(120_000); // Skip time so the timeout fires @@ -778,10 +780,7 @@ public class AdapterServiceTest { // Do not call stopBle(). The Adapter should turn itself off. syncHandler(AdapterState.BLE_TURN_OFF); verifyStateChange(STATE_BLE_ON, STATE_BLE_TURNING_OFF, CONTEXT_SWITCH_MS); - verify(mMockContext).unbindService(any()); // stop Gatt - - mAdapterService.onProfileServiceStateChanged(mMockGattService, STATE_OFF); - syncHandler(MESSAGE_PROFILE_SERVICE_STATE_CHANGED); + syncHandler(MESSAGE_PROFILE_SERVICE_STATE_CHANGED); // stop GATT // Native loop is not in TestLooper and it will send a event later mLooper.startAutoDispatch(); diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/ConfigTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/ConfigTest.java new file mode 100644 index 0000000000..7b97035ed5 --- /dev/null +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/ConfigTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2023 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.bluetooth.btservice; + +import static com.google.common.truth.Truth.assertThat; + +import com.android.bluetooth.csip.CsipSetCoordinatorService; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.Arrays; + +@RunWith(JUnit4.class) +public final class ConfigTest { + @Test + public void setProfileEnabled() { + boolean enabled = + Arrays.stream(Config.getSupportedProfiles()) + .anyMatch(cls -> cls == CsipSetCoordinatorService.class); + + Config.setProfileEnabled(CsipSetCoordinatorService.class, false); + assertThat( + Arrays.stream(Config.getSupportedProfiles()) + .anyMatch(cls -> cls == CsipSetCoordinatorService.class)) + .isFalse(); + + Config.setProfileEnabled(CsipSetCoordinatorService.class, true); + assertThat( + Arrays.stream(Config.getSupportedProfiles()) + .anyMatch(cls -> cls == CsipSetCoordinatorService.class)) + .isTrue(); + + Config.setProfileEnabled(CsipSetCoordinatorService.class, enabled); + } +} diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/ProfileServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/ProfileServiceTest.java index 4cc055e35d..15721bb004 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/ProfileServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/ProfileServiceTest.java @@ -16,6 +16,10 @@ package com.android.bluetooth.btservice; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; @@ -32,6 +36,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.TestUtils; import com.android.bluetooth.btservice.storage.DatabaseManager; +import com.android.bluetooth.gatt.GattService; import org.junit.After; import org.junit.Assert; @@ -78,7 +83,13 @@ public class ProfileServiceTest { } private void setAllProfilesState(int state, int invocationNumber) throws TimeoutException { + int profileCount = mProfiles.length; for (Class profile : mProfiles) { + if (profile == GattService.class) { + // GattService is no longer a service to be start independently + profileCount--; + continue; + } setProfileState(profile, state); } if (invocationNumber == 0) { @@ -87,11 +98,15 @@ public class ProfileServiceTest { return; } ArgumentCaptor<ProfileService> argument = ArgumentCaptor.forClass(ProfileService.class); - verify(mMockAdapterService, timeout(PROFILE_START_MILLIS).times( - mProfiles.length * invocationNumber)).onProfileServiceStateChanged( - argument.capture(), eq(state)); + verify( + mMockAdapterService, + timeout(PROFILE_START_MILLIS).times(profileCount * invocationNumber)) + .onProfileServiceStateChanged(argument.capture(), eq(state)); List<ProfileService> argumentProfiles = argument.getAllValues(); for (Class profile : mProfiles) { + if (profile == GattService.class) { + continue; + } int matches = 0; for (ProfileService arg : argumentProfiles) { if (arg.getClass().getName().equals(profile.getName())) { @@ -118,27 +133,41 @@ public class ProfileServiceTest { return mStartedProfileMap.get((String) args[0]); } }); + doReturn(mDatabaseManager).when(mMockAdapterService).getDatabase(); + when(mMockAdapterService.getSystemService(Context.LOCATION_SERVICE)) .thenReturn(mLocationManager); when(mMockAdapterService.getSystemServiceName(LocationManager.class)) .thenReturn(Context.LOCATION_SERVICE); + // Despite calling on the Mock of adapterService, mockito cannot handle native method and + // will call the real method instead, allowing to initialize the native library + // when(mMockAdapterService.initNative(anyBoolean(), anyBoolean(), anyInt(), any(), + // anyBoolean(), anyString())).thenCallRealMethod(); + doCallRealMethod() + .when(mMockAdapterService) + .initNative(anyBoolean(), anyBoolean(), anyInt(), any(), anyBoolean(), anyString()); + doCallRealMethod().when(mMockAdapterService).enableNative(); + doCallRealMethod().when(mMockAdapterService).disableNative(); + doCallRealMethod().when(mMockAdapterService).cleanupNative(); + mProfiles = Config.getSupportedProfiles(); + TestUtils.setAdapterService(mMockAdapterService); + + Assert.assertNotNull(AdapterService.getAdapterService()); mMockAdapterService.initNative(false /* is_restricted */, false /* is_common_criteria_mode */, 0 /* config_compare_result */, new String[0], false, ""); - - TestUtils.setAdapterService(mMockAdapterService); - doReturn(mDatabaseManager).when(mMockAdapterService).getDatabase(); - - Assert.assertNotNull(AdapterService.getAdapterService()); + mMockAdapterService.enableNative(); } @After public void tearDown() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + mMockAdapterService.disableNative(); mMockAdapterService.cleanupNative(); + TestUtils.clearAdapterService(mMockAdapterService); mMockAdapterService = null; mProfiles = null; @@ -172,13 +201,18 @@ public class ProfileServiceTest { */ @Test public void testEnableDisableInterleaved() throws TimeoutException { + int invocationNumber = mProfiles.length; for (Class profile : mProfiles) { + if (profile == GattService.class) { + // GattService is no longer a service to be start independently + invocationNumber--; + continue; + } setProfileState(profile, BluetoothAdapter.STATE_ON); setProfileState(profile, BluetoothAdapter.STATE_OFF); } ArgumentCaptor<ProfileService> starts = ArgumentCaptor.forClass(ProfileService.class); ArgumentCaptor<ProfileService> stops = ArgumentCaptor.forClass(ProfileService.class); - int invocationNumber = mProfiles.length; verify(mMockAdapterService, timeout(PROFILE_START_MILLIS).times(invocationNumber)).onProfileServiceStateChanged( starts.capture(), eq(BluetoothAdapter.STATE_ON)); @@ -204,6 +238,10 @@ public class ProfileServiceTest { public void testRepeatedEnableDisableSingly() throws TimeoutException { int profileNumber = 0; for (Class profile : mProfiles) { + if (profile == GattService.class) { + // GattService is no longer a service to be start independently + continue; + } for (int i = 0; i < NUM_REPEATS; i++) { setProfileState(profile, BluetoothAdapter.STATE_ON); ArgumentCaptor<ProfileService> start = @@ -230,6 +268,10 @@ public class ProfileServiceTest { public void testProfileServiceRegisterUnregister() throws TimeoutException { int profileNumber = 0; for (Class profile : mProfiles) { + if (profile == GattService.class) { + // GattService is no longer a service to be start independently + continue; + } for (int i = 0; i < NUM_REPEATS; i++) { setProfileState(profile, BluetoothAdapter.STATE_ON); ArgumentCaptor<ProfileService> start = diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/activityAttribution/ActivityAttributionServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/activityAttribution/ActivityAttributionServiceTest.java index 7f845b5dc8..8a4db9a7a4 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/activityAttribution/ActivityAttributionServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/activityAttribution/ActivityAttributionServiceTest.java @@ -16,12 +16,9 @@ package com.android.bluetooth.btservice.activityattribution; -import static com.google.common.truth.Truth.assertThat; - import android.os.Binder; import android.os.Process; -import org.junit.After; import org.junit.Assume; import org.junit.Before; import org.junit.Test; @@ -30,24 +27,12 @@ import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public final class ActivityAttributionServiceTest { - private static final String TAG = "ActivityAttributionServiceTest"; private ActivityAttributionService mActivityAttributionService; @Before public void setUp() { Assume.assumeTrue("Ignore test when the user is not primary.", isPrimaryUser()); mActivityAttributionService = new ActivityAttributionService(); - mActivityAttributionService.start(); - assertThat(mActivityAttributionService).isNotNull(); - } - - @After - public void tearDown() { - if (!isPrimaryUser()) { - return; - } - mActivityAttributionService.cleanup(); - mActivityAttributionService = null; } private boolean isPrimaryUser() { diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreServiceTest.java index f65ab82331..1e78e0c86b 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreServiceTest.java @@ -20,15 +20,6 @@ import android.os.Binder; import android.os.Process; import android.util.Log; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - import org.junit.After; import org.junit.Assert; import org.junit.Assume; @@ -36,12 +27,25 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; @RunWith(JUnit4.class) public final class BluetoothKeystoreServiceTest { private static final String TAG = "BluetoothKeystoreServiceTest"; private BluetoothKeystoreService mBluetoothKeystoreService; + @Mock private BluetoothKeystoreNativeInterface mMockNativeInterface; + // Please also check bt_stack string configuration if you want to change the content. private static final String CONFIG_FILE_PREFIX = "bt_config-origin"; private static final String CONFIG_BACKUP_PREFIX = "bt_config-backup"; @@ -119,8 +123,9 @@ public final class BluetoothKeystoreServiceTest { @Before public void setUp() { + MockitoAnnotations.initMocks(this); Assume.assumeTrue("Ignore test when the user is not primary.", isPrimaryUser()); - mBluetoothKeystoreService = new BluetoothKeystoreService(true); + mBluetoothKeystoreService = new BluetoothKeystoreService(mMockNativeInterface, true); Assert.assertNotNull(mBluetoothKeystoreService); // backup origin config data. try { @@ -280,7 +285,7 @@ public final class BluetoothKeystoreServiceTest { mBluetoothKeystoreService.cleanupForCommonCriteriaModeEnable(); // new mBluetoothKeystoreService and the Common Criteria mode is false. - mBluetoothKeystoreService = new BluetoothKeystoreService(false); + mBluetoothKeystoreService = new BluetoothKeystoreService(mMockNativeInterface, false); Assert.assertNotNull(mBluetoothKeystoreService); mBluetoothKeystoreService.loadConfigData(); @@ -304,7 +309,7 @@ public final class BluetoothKeystoreServiceTest { mBluetoothKeystoreService.cleanupForCommonCriteriaModeDisable(); // new mBluetoothKeystoreService and the Common Criteria mode is true. - mBluetoothKeystoreService = new BluetoothKeystoreService(true); + mBluetoothKeystoreService = new BluetoothKeystoreService(mMockNativeInterface, true); mBluetoothKeystoreService.loadConfigData(); Assert.assertTrue(mBluetoothKeystoreService.getCompareResult() == 0); diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseManagerTest.java index 74d0e64365..c7bf403325 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseManagerTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseManagerTest.java @@ -16,7 +16,6 @@ package com.android.bluetooth.gatt; -import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -59,6 +58,8 @@ public class AdvertiseManagerTest { @Mock private GattService.AdvertiserMap mAdvertiserMap; + @Mock private AdvertiseManagerNativeInterface mNativeInterface; + @Mock private IAdvertisingSetCallback mCallback; @@ -74,7 +75,9 @@ public class AdvertiseManagerTest { TestUtils.setAdapterService(mAdapterService); - mAdvertiseManager = new AdvertiseManager(mService, mAdapterService, mAdvertiserMap); + mAdvertiseManager = + new AdvertiseManager(mService, mNativeInterface, mAdapterService, mAdvertiserMap); + AdvertisingSetParameters parameters = new AdvertisingSetParameters.Builder().build(); AdvertiseData advertiseData = new AdvertiseData.Builder().build(); AdvertiseData scanResponse = new AdvertiseData.Builder().build(); diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/AppScanStatsTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/AppScanStatsTest.java index 359ad3104e..b1bed3da63 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/gatt/AppScanStatsTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/AppScanStatsTest.java @@ -18,9 +18,6 @@ package com.android.bluetooth.gatt; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.when; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanSettings; @@ -28,6 +25,7 @@ import android.content.Context; import android.location.LocationManager; import android.os.WorkSource; +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.rule.ServiceTestRule; import androidx.test.runner.AndroidJUnit4; @@ -64,28 +62,23 @@ public class AppScanStatsTest { @Mock private AdapterService mAdapterService; - @Mock private LocationManager mLocationManager; - @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); TestUtils.setAdapterService(mAdapterService); - doReturn(true).when(mAdapterService).isStartedProfile(anyString()); - when(mAdapterService.getSystemService(Context.LOCATION_SERVICE)) - .thenReturn(mLocationManager); - when(mAdapterService.getSystemServiceName(LocationManager.class)) - .thenReturn(Context.LOCATION_SERVICE); - - TestUtils.startService(mServiceRule, GattService.class); - mService = GattService.getGattService(); + + TestUtils.mockGetSystemService( + mAdapterService, Context.LOCATION_SERVICE, LocationManager.class); + + mService = new GattService(InstrumentationRegistry.getTargetContext()); + mService.start(); } @After public void tearDown() throws Exception { - doReturn(false).when(mAdapterService).isStartedProfile(anyString()); - TestUtils.stopService(mServiceRule, GattService.class); - mService = GattService.getGattService(); + mService.stop(); + mService = null; TestUtils.clearAdapterService(mAdapterService); } diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/ContextMapTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/ContextMapTest.java index 3ff84eea8d..e391a38c95 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/gatt/ContextMapTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/ContextMapTest.java @@ -18,10 +18,8 @@ package com.android.bluetooth.gatt; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.bluetooth.le.AdvertiseData; import android.bluetooth.le.AdvertisingSetParameters; @@ -30,6 +28,7 @@ import android.content.Context; import android.location.LocationManager; import android.os.Binder; +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.rule.ServiceTestRule; import androidx.test.runner.AndroidJUnit4; @@ -64,8 +63,6 @@ public class ContextMapTest { @Mock private AdapterService mAdapterService; - @Mock private LocationManager mLocationManager; - @Mock private AppAdvertiseStats appAdvertiseStats; @@ -78,23 +75,20 @@ public class ContextMapTest { BluetoothMethodProxy.setInstanceForTesting(mMapMethodProxy); TestUtils.setAdapterService(mAdapterService); - doReturn(true).when(mAdapterService).isStartedProfile(anyString()); - when(mAdapterService.getSystemService(Context.LOCATION_SERVICE)) - .thenReturn(mLocationManager); - when(mAdapterService.getSystemServiceName(LocationManager.class)) - .thenReturn(Context.LOCATION_SERVICE); - - TestUtils.startService(mServiceRule, GattService.class); - mService = GattService.getGattService(); + + TestUtils.mockGetSystemService( + mAdapterService, Context.LOCATION_SERVICE, LocationManager.class); + + mService = new GattService(InstrumentationRegistry.getTargetContext()); + mService.start(); } @After public void tearDown() throws Exception { BluetoothMethodProxy.setInstanceForTesting(null); - doReturn(false).when(mAdapterService).isStartedProfile(anyString()); - TestUtils.stopService(mServiceRule, GattService.class); - mService = GattService.getGattService(); + mService.stop(); + mService = null; TestUtils.clearAdapterService(mAdapterService); } diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java index 714e911a41..1c1fda0007 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java @@ -756,13 +756,6 @@ public class GattServiceBinderTest { } @Test - public void unregAll() throws Exception { - mBinder.unregAll(mAttributionSource); - - verify(mService).unregAll(mAttributionSource); - } - - @Test public void numHwTrackFiltersAvailable() throws Exception { mBinder.numHwTrackFiltersAvailable(mAttributionSource, SynchronousResultReceiver.get()); diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java index bf3c8364a9..6d092c0787 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java @@ -25,21 +25,17 @@ import static org.mockito.Mockito.verify; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothStatusCodes; import android.bluetooth.IBluetoothGattCallback; -import android.bluetooth.IBluetoothGattServerCallback; import android.bluetooth.le.AdvertiseData; import android.bluetooth.le.AdvertisingSetParameters; import android.bluetooth.le.DistanceMeasurementMethod; import android.bluetooth.le.DistanceMeasurementParams; -import android.bluetooth.le.IAdvertisingSetCallback; import android.bluetooth.le.IDistanceMeasurementCallback; import android.bluetooth.le.IPeriodicAdvertisingCallback; import android.bluetooth.le.IScannerCallback; import android.bluetooth.le.PeriodicAdvertisingParameters; -import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.content.AttributionSource; @@ -47,7 +43,6 @@ import android.content.Context; import android.content.res.Resources; import android.location.LocationManager; import android.os.Binder; -import android.os.ParcelUuid; import android.os.RemoteException; import android.os.WorkSource; @@ -56,14 +51,12 @@ import androidx.test.filters.SmallTest; import androidx.test.rule.ServiceTestRule; import androidx.test.runner.AndroidJUnit4; -import com.android.bluetooth.R; import com.android.bluetooth.TestUtils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.CompanionManager; import org.junit.After; import org.junit.Assert; -import org.junit.Assume; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; @@ -102,7 +95,6 @@ public class GattServiceTest { @Mock private Set<String> mReliableQueue; @Mock private GattService.ServerMap mServerMap; @Mock private DistanceMeasurementManager mDistanceMeasurementManager; - @Mock private LocationManager mLocationManager; @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule(); @@ -123,7 +115,6 @@ public class GattServiceTest { MockitoAnnotations.initMocks(this); TestUtils.setAdapterService(mAdapterService); - doReturn(true).when(mAdapterService).isStartedProfile(anyString()); GattObjectsFactory.setInstanceForTesting(mFactory); doReturn(mNativeInterface).when(mFactory).getNativeInterface(); @@ -141,17 +132,15 @@ public class GattServiceTest { when(mAdapterService.getSharedPreferences(anyString(), anyInt())) .thenReturn(InstrumentationRegistry.getTargetContext() .getSharedPreferences("GattServiceTestPrefs", Context.MODE_PRIVATE)); - when(mAdapterService.getSystemService(Context.LOCATION_SERVICE)) - .thenReturn(mLocationManager); - when(mAdapterService.getSystemServiceName(LocationManager.class)) - .thenReturn(Context.LOCATION_SERVICE); + + TestUtils.mockGetSystemService( + mAdapterService, Context.LOCATION_SERVICE, LocationManager.class); mBtCompanionManager = new CompanionManager(mAdapterService, null); doReturn(mBtCompanionManager).when(mAdapterService).getCompanionManager(); - TestUtils.startService(mServiceRule, GattService.class); - mService = GattService.getGattService(); - Assert.assertNotNull(mService); + mService = new GattService(InstrumentationRegistry.getTargetContext()); + mService.start(); mService.mClientMap = mClientMap; mService.mScannerMap = mScannerMap; @@ -161,40 +150,25 @@ public class GattServiceTest { @After public void tearDown() throws Exception { - doReturn(false).when(mAdapterService).isStartedProfile(anyString()); - TestUtils.stopService(mServiceRule, GattService.class); - mService = GattService.getGattService(); - Assert.assertNull(mService); + mService.stop(); + mService = null; + TestUtils.clearAdapterService(mAdapterService); GattObjectsFactory.setInstanceForTesting(null); } @Test - public void testInitialize() { - Assert.assertEquals(mService, GattService.getGattService()); - verify(mNativeInterface).init(eq(mService)); - } - - @Test public void testServiceUpAndDown() throws Exception { for (int i = 0; i < TIMES_UP_AND_DOWN; i++) { - GattService gattService = GattService.getGattService(); - doReturn(false).when(mAdapterService).isStartedProfile(anyString()); - TestUtils.stopService(mServiceRule, GattService.class); - mService = GattService.getGattService(); - Assert.assertNull(mService); - gattService.cleanup(); + mService.stop(); + mService = null; + TestUtils.clearAdapterService(mAdapterService); reset(mAdapterService); TestUtils.setAdapterService(mAdapterService); - doReturn(true).when(mAdapterService).isStartedProfile(anyString()); - when(mAdapterService.getSystemService(Context.LOCATION_SERVICE)) - .thenReturn(mLocationManager); - when(mAdapterService.getSystemServiceName(LocationManager.class)) - .thenReturn(Context.LOCATION_SERVICE); - TestUtils.startService(mServiceRule, GattService.class); - mService = GattService.getGattService(); - Assert.assertNotNull(mService); + + mService = new GattService(InstrumentationRegistry.getTargetContext()); + mService.start(); } } diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/ScanManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/ScanManagerTest.java index 9f6961e206..42d26f77b0 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/gatt/ScanManagerTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/ScanManagerTest.java @@ -29,7 +29,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.doReturn; @@ -118,17 +117,15 @@ public class ScanManagerTest { MockitoAnnotations.initMocks(this); TestUtils.setAdapterService(mAdapterService); - doReturn(true).when(mAdapterService).isStartedProfile(anyString()); when(mAdapterService.getScanTimeoutMillis()). thenReturn((long) DELAY_DEFAULT_SCAN_TIMEOUT_MS); when(mAdapterService.getNumOfOffloadedScanFilterSupported()) .thenReturn(DEFAULT_NUM_OFFLOAD_SCAN_FILTER); when(mAdapterService.getOffloadedScanResultStorage()) .thenReturn(DEFAULT_BYTES_OFFLOAD_SCAN_RESULT_STORAGE); - when(mAdapterService.getSystemService(Context.LOCATION_SERVICE)) - .thenReturn(mLocationManager); - when(mAdapterService.getSystemServiceName(LocationManager.class)) - .thenReturn(Context.LOCATION_SERVICE); + + TestUtils.mockGetSystemService( + mAdapterService, Context.LOCATION_SERVICE, LocationManager.class, mLocationManager); doReturn(true).when(mLocationManager).isLocationEnabled(); BluetoothAdapterProxy.setInstanceForTesting(mBluetoothAdapterProxy); @@ -143,9 +140,8 @@ public class ScanManagerTest { MetricsLogger.setInstanceForTesting(mMetricsLogger); - TestUtils.startService(mServiceRule, GattService.class); - mService = GattService.getGattService(); - assertThat(mService).isNotNull(); + mService = new GattService(InstrumentationRegistry.getTargetContext()); + mService.start(); mScanManager = mService.getScanManager(); assertThat(mScanManager).isNotNull(); @@ -161,10 +157,9 @@ public class ScanManagerTest { @After public void tearDown() throws Exception { - doReturn(false).when(mAdapterService).isStartedProfile(anyString()); - TestUtils.stopService(mServiceRule, GattService.class); - mService = GattService.getGattService(); - assertThat(mService).isNull(); + mService.stop(); + mService = null; + TestUtils.clearAdapterService(mAdapterService); BluetoothAdapterProxy.setInstanceForTesting(null); GattObjectsFactory.setInstanceForTesting(null); diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java index 008fc0d349..b689546d9b 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java @@ -56,6 +56,7 @@ import androidx.test.rule.ServiceTestRule; import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.TestUtils; +import com.android.bluetooth.btservice.ActiveDeviceManager; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.ServiceFactory; import com.android.bluetooth.btservice.storage.DatabaseManager; @@ -109,6 +110,7 @@ public class LeAudioServiceTest { private BroadcastReceiver mLeAudioIntentReceiver; @Mock private AdapterService mAdapterService; + @Mock private ActiveDeviceManager mActiveDeviceManager; @Mock private AudioManager mAudioManager; @Mock private DatabaseManager mDatabaseManager; @Mock private LeAudioNativeInterface mNativeInterface; @@ -169,6 +171,7 @@ public class LeAudioServiceTest { doReturn(MAX_LE_AUDIO_CONNECTIONS).when(mAdapterService).getMaxConnectedAudioDevices(); doReturn(new ParcelUuid[]{BluetoothUuid.LE_AUDIO}).when(mAdapterService) .getRemoteUuids(any(BluetoothDevice.class)); + doReturn(mActiveDeviceManager).when(mAdapterService).getActiveDeviceManager(); doReturn(mDatabaseManager).when(mAdapterService).getDatabase(); doReturn(true, false).when(mAdapterService).isStartedProfile(anyString()); diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioStateMachineTest.java index e75f2fda45..ac69b84dfa 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioStateMachineTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioStateMachineTest.java @@ -17,15 +17,17 @@ package com.android.bluetooth.le_audio; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.after; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; -import static com.google.common.truth.Truth.assertThat; - import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; @@ -45,7 +47,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -146,12 +147,10 @@ public class LeAudioStateMachineTest { connStCh.valueInt1 = LeAudioStackEvent.CONNECTION_STATE_CONNECTING; mLeAudioStateMachine.sendMessage(LeAudioStateMachine.STACK_EVENT, connStCh); - // Verify that one connection state broadcast is executed - ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class); - verify(mLeAudioService, timeout(TIMEOUT_MS).times(1)).sendBroadcast( - intentArgument1.capture(), anyString(), any(Bundle.class)); - assertThat(BluetoothProfile.STATE_CONNECTING).isEqualTo( - intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); + // Verify that one connection state change is notifyed + verify(mLeAudioService, timeout(TIMEOUT_MS)) + .notifyConnectionStateChanged( + any(), eq(BluetoothProfile.STATE_CONNECTING), anyInt()); // Check that we are in Connecting state assertThat(mLeAudioStateMachine.getCurrentState()) @@ -164,11 +163,14 @@ public class LeAudioStateMachineTest { connCompletedEvent.valueInt1 = LeAudioStackEvent.CONNECTION_STATE_CONNECTED; mLeAudioStateMachine.sendMessage(LeAudioStateMachine.STACK_EVENT, connCompletedEvent); - // Verify that the expected number of broadcasts are executed: - // - two calls to broadcastConnectionState(): Disconnected -> Conecting -> Connected - ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class); - verify(mLeAudioService, timeout(TIMEOUT_MS).times(2)).sendBroadcast( - intentArgument2.capture(), anyString(), any(Bundle.class)); + // Verify that the expected number of notification are called: + // - two calls to notifyConnectionStateChanged(): Disconnected -> Connecting -> Connected + verify(mLeAudioService, timeout(TIMEOUT_MS)) + .notifyConnectionStateChanged( + any(), eq(BluetoothProfile.STATE_CONNECTING), anyInt()); + verify(mLeAudioService, timeout(TIMEOUT_MS)) + .notifyConnectionStateChanged( + any(), eq(BluetoothProfile.STATE_CONNECTED), anyInt()); // Check that we are in Connected state assertThat(mLeAudioStateMachine.getCurrentState()) .isInstanceOf(LeAudioStateMachine.Connected.class); @@ -188,25 +190,19 @@ public class LeAudioStateMachineTest { // Send a connect request mLeAudioStateMachine.sendMessage(LeAudioStateMachine.CONNECT, mTestDevice); - // Verify that one connection state broadcast is executed - ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class); - verify(mLeAudioService, timeout(TIMEOUT_MS).times(1)).sendBroadcast( - intentArgument1.capture(), - anyString(), any(Bundle.class)); - assertThat(BluetoothProfile.STATE_CONNECTING).isEqualTo( - intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); + // Verify that one connection state change is notified + verify(mLeAudioService, timeout(TIMEOUT_MS)) + .notifyConnectionStateChanged( + any(), eq(BluetoothProfile.STATE_CONNECTING), anyInt()); // Check that we are in Connecting state assertThat(mLeAudioStateMachine.getCurrentState()) .isInstanceOf(LeAudioStateMachine.Connecting.class); - // Verify that one connection state broadcast is executed - ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class); - verify(mLeAudioService, timeout(LeAudioStateMachine.sConnectTimeoutMs * 2).times( - 2)).sendBroadcast(intentArgument2.capture(), anyString(), - any(Bundle.class)); - assertThat(BluetoothProfile.STATE_DISCONNECTED).isEqualTo( - intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); + // Verify that one connection state change is notified + verify(mLeAudioService, timeout(LeAudioStateMachine.sConnectTimeoutMs * 2)) + .notifyConnectionStateChanged( + any(), eq(BluetoothProfile.STATE_DISCONNECTED), anyInt()); // Check that we are in Disconnected state assertThat(mLeAudioStateMachine.getCurrentState()) @@ -231,25 +227,19 @@ public class LeAudioStateMachineTest { connStCh.valueInt1 = LeAudioStackEvent.CONNECTION_STATE_CONNECTING; mLeAudioStateMachine.sendMessage(LeAudioStateMachine.STACK_EVENT, connStCh); - // Verify that one connection state broadcast is executed - ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class); - verify(mLeAudioService, timeout(TIMEOUT_MS).times(1)).sendBroadcast( - intentArgument1.capture(), - anyString(), any(Bundle.class)); - assertThat(BluetoothProfile.STATE_CONNECTING).isEqualTo( - intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); + // Verify that one connection state change is notified + verify(mLeAudioService, timeout(TIMEOUT_MS)) + .notifyConnectionStateChanged( + any(), eq(BluetoothProfile.STATE_CONNECTING), anyInt()); // Check that we are in Connecting state assertThat(mLeAudioStateMachine.getCurrentState()) .isInstanceOf(LeAudioStateMachine.Connecting.class); - // Verify that one connection state broadcast is executed - ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class); - verify(mLeAudioService, timeout(LeAudioStateMachine.sConnectTimeoutMs * 2).times( - 2)).sendBroadcast(intentArgument2.capture(), anyString(), - any(Bundle.class)); - assertThat(intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)) - .isEqualTo(BluetoothProfile.STATE_DISCONNECTED); + // Verify that one connection state change is notified + verify(mLeAudioService, timeout(LeAudioStateMachine.sConnectTimeoutMs * 2)) + .notifyConnectionStateChanged( + any(), eq(BluetoothProfile.STATE_DISCONNECTED), anyInt()); // Check that we are in Disconnected state assertThat(mLeAudioStateMachine.getCurrentState()) diff --git a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppServiceTest.java index 953d93249a..d61d3de936 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppServiceTest.java @@ -49,7 +49,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; - @MediumTest @RunWith(AndroidJUnit4.class) public class BluetoothOppServiceTest { @@ -90,7 +89,11 @@ public class BluetoothOppServiceTest { // Since the update thread is not run (we mocked it), it will not clean itself on interrupt // (normally, the service will wait for the update thread to clean itself after // being interrupted). We clean it manually here - mService.mUpdateThread = null; + BluetoothOppService service = mService; + if (service != null) { + service.mUpdateThread = null; + } + BluetoothMethodProxy.setInstanceForTesting(null); TestUtils.stopService(mServiceRule, BluetoothOppService.class); TestUtils.clearAdapterService(mAdapterService); @@ -187,5 +190,4 @@ public class BluetoothOppServiceTest { eq(BluetoothShare._ID + " < " + 20), any()); } -} - +}
\ No newline at end of file diff --git a/android/pandora/test/AndroidTest.xml b/android/pandora/test/AndroidTest.xml index 9906aeac75..29353f27ae 100644 --- a/android/pandora/test/AndroidTest.xml +++ b/android/pandora/test/AndroidTest.xml @@ -23,9 +23,7 @@ <option name="install-arg" value="-r" /> <option name="install-arg" value="-g" /> </target_preparer> - <target_preparer class="com.android.tradefed.targetprep.RunHostCommandTargetPreparer"> - <option name="host-setup-command" value="adb -s $SERIAL forward tcp:6211 vsock:2:7300" /> - <option name="host-teardown-command" value="adb -s $SERIAL forward --remove tcp:6211" /> + <target_preparer class="com.android.tradefed.targetprep.RootcanalForwarderPreparer"> </target_preparer> <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> <option name="run-command" value="cmd bluetooth_manager enable" /> diff --git a/android/pandora/test/asha_test.py b/android/pandora/test/asha_test.py index 90493ce0ae..83b8d456d8 100644 --- a/android/pandora/test/asha_test.py +++ b/android/pandora/test/asha_test.py @@ -865,6 +865,9 @@ class AshaTest(base_test.BaseTestClass): # type: ignore[misc] Verify that DUT sends a correct AudioControlPoint `Stop` command. """ + # TODO(b/290204194) Re-activate this test ASAP + raise signals.TestSkip('TODO(b/290204194) Re-activate this test ASAP') + async def ref_device_connect(ref_device: BumblePandoraDevice, ear: Ear) -> Tuple[Connection, Connection]: advertisement = await self.ref_advertise_asha(ref_device=ref_device, ref_address_type=RANDOM, ear=ear) ref = await self.dut_scan_for_asha(dut_address_type=RANDOM, ear=ear) @@ -1061,6 +1064,9 @@ class AshaTest(base_test.BaseTestClass): # type: ignore[misc] Verify Refs cannot recevice audio data after DUT stops media streaming. """ + # TODO(b/290204194) Re-activate this test ASAP + raise signals.TestSkip('TODO(b/290204194) Re-activate this test ASAP') + async def ref_device_connect(ref_device: BumblePandoraDevice, ear: Ear) -> Tuple[Connection, Connection]: advertisement = await self.ref_advertise_asha(ref_device=ref_device, ref_address_type=RANDOM, ear=ear) ref = await self.dut_scan_for_asha(dut_address_type=RANDOM, ear=ear) diff --git a/android/pandora/test/config.yml b/android/pandora/test/config.yml index 3682981ff2..3dd993b15d 100644 --- a/android/pandora/test/config.yml +++ b/android/pandora/test/config.yml @@ -5,8 +5,8 @@ TestBeds: Controllers: AndroidDevice: '*' BumbleDevice: - - transport: 'tcp-client:127.0.0.1:6211' - - transport: 'tcp-client:127.0.0.1:6211' + - tcp: ${ROOTCANAL_HCI_ADDRESS} + - tcp: ${ROOTCANAL_HCI_ADDRESS} - Name: bumble.bumbles Controllers: BumbleDevice: diff --git a/floss/hcidoc/src/groups/informational.rs b/floss/hcidoc/src/groups/informational.rs index d908ce11e4..f3f38afb2d 100644 --- a/floss/hcidoc/src/groups/informational.rs +++ b/floss/hcidoc/src/groups/informational.rs @@ -4,6 +4,7 @@ use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; use std::convert::Into; use std::fmt; +use std::hash::Hash; use std::io::Write; use crate::engine::{Rule, RuleGroup, Signal}; @@ -18,6 +19,20 @@ type ConnectionHandle = u16; const INVALID_TS: NaiveDateTime = NaiveDateTime::MAX; +fn print_start_end_timestamps(start: NaiveDateTime, end: NaiveDateTime) -> String { + fn print_time(ts: NaiveDateTime) -> String { + if ts == INVALID_TS { + return "N/A".to_owned(); + } + return format!("{}", ts.time()); + } + + if start == end && start != INVALID_TS { + return format!("{} - Failed", start.time()); + } + return format!("{} to {}", print_time(start), print_time(end)); +} + #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] enum AddressType { None, @@ -110,6 +125,33 @@ impl DeviceInformation { } } + fn is_connection_active(&self) -> bool { + // not empty and last connection's end time is not set. + return !self.acls.is_empty() && self.acls.last().unwrap().end_time == INVALID_TS; + } + + fn get_or_allocate_connection(&mut self, handle: &ConnectionHandle) -> &mut AclInformation { + if !self.is_connection_active() { + let acl = AclInformation::new(*handle); + self.acls.push(acl); + } + return self.acls.last_mut().unwrap(); + } + + fn report_connection_start(&mut self, handle: ConnectionHandle, ts: NaiveDateTime) { + let mut acl = AclInformation::new(handle); + let initiator = self.acl_state.into(); + acl.report_start(initiator, ts); + self.acls.push(acl); + self.acl_state = AclState::Connected; + } + + fn report_connection_end(&mut self, handle: ConnectionHandle, ts: NaiveDateTime) { + let acl = self.get_or_allocate_connection(&handle); + acl.report_end(ts); + self.acl_state = AclState::None; + } + fn print_names(names: &HashSet<String>) -> String { if names.len() > 1 { format!("{:?}", names) @@ -143,6 +185,7 @@ struct AclInformation { end_time: NaiveDateTime, handle: ConnectionHandle, initiator: InitiatorType, + profiles: HashMap<ProfileType, Vec<ProfileInformation>>, } impl AclInformation { @@ -152,31 +195,128 @@ impl AclInformation { end_time: INVALID_TS, handle: handle, initiator: InitiatorType::Unknown, + profiles: HashMap::new(), + } + } + + fn get_or_allocate_profile(&mut self, profile_type: &ProfileType) -> &mut ProfileInformation { + if !self.profiles.contains_key(profile_type) + || self.profiles.get(profile_type).unwrap().last().unwrap().end_time != INVALID_TS + { + self.profiles.insert(*profile_type, vec![ProfileInformation::new(*profile_type)]); + } + + return self.profiles.get_mut(profile_type).unwrap().last_mut().unwrap(); + } + + fn report_start(&mut self, initiator: InitiatorType, ts: NaiveDateTime) { + self.initiator = initiator; + self.start_time = ts; + } + + fn report_end(&mut self, ts: NaiveDateTime) { + // disconnect the active profiles + let profile_types: Vec<ProfileType> = self.profiles.keys().cloned().collect(); + for profile_type in profile_types { + if let Some(profile) = self.profiles.get(&profile_type).unwrap().last() { + if profile.end_time != INVALID_TS { + self.report_profile_end(profile_type, ts); + } + } + } + self.end_time = ts; + } + + fn report_profile_start( + &mut self, + profile_type: ProfileType, + initiator: InitiatorType, + ts: NaiveDateTime, + ) { + let mut profile = ProfileInformation::new(profile_type); + profile.report_start(initiator, ts); + if !self.profiles.contains_key(&profile_type) { + self.profiles.insert(profile_type, vec![]); } + self.profiles.get_mut(&profile_type).unwrap().push(profile); + } + + fn report_profile_end(&mut self, profile_type: ProfileType, ts: NaiveDateTime) { + let profile = self.get_or_allocate_profile(&profile_type); + profile.report_end(ts); } } impl fmt::Display for AclInformation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fn print_time(ts: NaiveDateTime) -> String { - if ts == INVALID_TS { - return "N/A".to_owned(); + let _ = writeln!( + f, + " Handle: {handle}, {initiator}, {timestamp_info}", + handle = self.handle, + initiator = self.initiator, + timestamp_info = print_start_end_timestamps(self.start_time, self.end_time) + ); + + for (_profile_type, profiles) in self.profiles.iter() { + for profile in profiles { + let _ = write!(f, "{}", profile); } - return format!("{}", ts.time()); } - fn print_timestamps(start: NaiveDateTime, end: NaiveDateTime) -> String { - if start == end { - return format!("{} - Failed", start.time()); - } - return format!("{} to {}", print_time(start), print_time(end)); + + Ok(()) + } +} + +// Currently only HFP is possible to be detected. Other profiles needs us to parse L2CAP packets. +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +enum ProfileType { + HFP, +} + +impl fmt::Display for ProfileType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let str = match self { + ProfileType::HFP => "HFP", + }; + write!(f, "{}", str) + } +} + +struct ProfileInformation { + start_time: NaiveDateTime, + end_time: NaiveDateTime, + profile_type: ProfileType, + initiator: InitiatorType, +} + +impl ProfileInformation { + pub fn new(profile_type: ProfileType) -> Self { + ProfileInformation { + start_time: INVALID_TS, + end_time: INVALID_TS, + profile_type: profile_type, + initiator: InitiatorType::Unknown, } + } + + fn report_start(&mut self, initiator: InitiatorType, ts: NaiveDateTime) { + self.initiator = initiator; + self.start_time = ts; + } + + fn report_end(&mut self, ts: NaiveDateTime) { + self.end_time = ts; + } +} +impl fmt::Display for ProfileInformation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!( f, - " Handle: {handle}, {initiator}, {timestamp_info}", - handle = self.handle, + " {profile}, {initiator}, {timestamp_info}", + profile = self.profile_type, initiator = self.initiator, - timestamp_info = print_timestamps(self.start_time, self.end_time) + timestamp_info = print_start_end_timestamps(self.start_time, self.end_time) ) } } @@ -185,6 +325,7 @@ impl fmt::Display for AclInformation { struct InformationalRule { devices: HashMap<Address, DeviceInformation>, handles: HashMap<ConnectionHandle, Address>, + sco_handles: HashMap<ConnectionHandle, ConnectionHandle>, // unknownConnections store connections which is initiated before btsnoop starts. unknown_connections: HashMap<ConnectionHandle, AclInformation>, } @@ -194,6 +335,7 @@ impl InformationalRule { InformationalRule { devices: HashMap::new(), handles: HashMap::new(), + sco_handles: HashMap::new(), unknown_connections: HashMap::new(), } } @@ -215,19 +357,30 @@ impl InformationalRule { return self.unknown_connections.get_mut(handle).unwrap(); } + fn get_or_allocate_connection(&mut self, handle: &ConnectionHandle) -> &mut AclInformation { + if !self.handles.contains_key(&handle) { + let conn = self.get_or_allocate_unknown_connection(&handle); + return conn; + } + + let address = &self.handles.get(handle).unwrap().clone(); + let device = self.get_or_allocate_device(address); + return device.get_or_allocate_connection(handle); + } + fn report_address_type(&mut self, address: &Address, address_type: AddressType) { - let info = self.get_or_allocate_device(address); - info.address_type.update(address_type); + let device = self.get_or_allocate_device(address); + device.address_type.update(address_type); } fn report_name(&mut self, address: &Address, name: &String) { - let info = self.get_or_allocate_device(address); - info.names.insert(name.into()); + let device = self.get_or_allocate_device(address); + device.names.insert(name.into()); } fn report_acl_state(&mut self, address: &Address, state: AclState) { - let info = self.get_or_allocate_device(address); - info.acl_state = state; + let device = self.get_or_allocate_device(address); + device.acl_state = state; } fn report_connection_start( @@ -236,38 +389,62 @@ impl InformationalRule { handle: ConnectionHandle, ts: NaiveDateTime, ) { - let info = self.get_or_allocate_device(address); - info.acls.push(AclInformation { - start_time: ts, - end_time: INVALID_TS, - handle: handle, - initiator: info.acl_state.into(), - }); - info.acl_state = AclState::Connected; + let device = self.get_or_allocate_device(address); + device.report_connection_start(handle, ts); self.handles.insert(handle, *address); } + fn report_sco_connection_start( + &mut self, + address: &Address, + handle: ConnectionHandle, + ts: NaiveDateTime, + ) { + if !self.devices.contains_key(address) { + // To simplify things, let's not process unknown devices + return; + } + + let device = self.devices.get_mut(address).unwrap(); + if !device.is_connection_active() { + // SCO is connected, but ACL is not. This is weird, but let's ignore for simplicity. + eprintln!("[{}] SCO is connected, but ACL is not.", address); + return; + } + + // Whatever handle value works here - we aren't allocating a new one. + let acl = device.get_or_allocate_connection(&0); + let acl_handle = acl.handle; + // We need to listen the HCI commands to determine the correct initiator. + // Here we just assume host for simplicity. + acl.report_profile_start(ProfileType::HFP, InitiatorType::Host, ts); + + self.sco_handles.insert(handle, acl_handle); + } + fn report_connection_end(&mut self, handle: ConnectionHandle, ts: NaiveDateTime) { - if !self.handles.contains_key(&handle) { - let conn = self.get_or_allocate_unknown_connection(&handle); - conn.end_time = ts; + // This might be a SCO disconnection event, so check that first + if self.sco_handles.contains_key(&handle) { + let acl_handle = self.sco_handles[&handle]; + let conn = self.get_or_allocate_connection(&acl_handle); + conn.report_profile_end(ProfileType::HFP, ts); return; } - let info = self.get_or_allocate_device(&self.handles.get(&handle).unwrap().clone()); - - // If we can't find the matching acl connection, create one. - if info.acls.is_empty() || info.acls.last().unwrap().end_time != INVALID_TS { - info.acls.push(AclInformation { - start_time: INVALID_TS, - end_time: ts, - handle: handle, - initiator: InitiatorType::Unknown, - }); + + // Not recognized as SCO, assume it's an ACL handle. + if let Some(address) = self.handles.get(&handle) { + // This device is known + let device = self.devices.get_mut(address).unwrap(); + device.report_connection_end(handle, ts); + self.handles.remove(&handle); + + // remove the associated SCO handle, if any + self.sco_handles.retain(|_sco_handle, acl_handle| *acl_handle != handle); } else { - info.acls.last_mut().unwrap().end_time = ts; + // Unknown device. + let conn = self.get_or_allocate_unknown_connection(&handle); + conn.report_end(ts); } - info.acl_state = AclState::None; - self.handles.remove(&handle); } fn report_reset(&mut self, ts: NaiveDateTime) { @@ -276,6 +453,28 @@ impl InformationalRule { for handle in handles { self.report_connection_end(handle, ts); } + self.sco_handles.clear(); + } + + fn _report_profile_start( + &mut self, + handle: ConnectionHandle, + profile_type: ProfileType, + initiator: InitiatorType, + ts: NaiveDateTime, + ) { + let conn = self.get_or_allocate_connection(&handle); + conn.report_profile_start(profile_type, initiator, ts); + } + + fn _report_profile_end( + &mut self, + handle: ConnectionHandle, + profile_type: ProfileType, + ts: NaiveDateTime, + ) { + let conn = self.get_or_allocate_connection(&handle); + conn.report_profile_end(profile_type, ts); } fn process_gap_data(&mut self, address: &Address, data: &GapData) { @@ -325,6 +524,18 @@ impl Rule for InformationalRule { } } + EventChild::SynchronousConnectionComplete(ev) => { + self.report_sco_connection_start( + &ev.get_bd_addr(), + ev.get_connection_handle(), + packet.ts, + ); + // If failed, assume it's the end of connection. + if ev.get_status() != ErrorCode::Success { + self.report_connection_end(ev.get_connection_handle(), packet.ts); + } + } + EventChild::DisconnectionComplete(ev) => { self.report_connection_end(ev.get_connection_handle(), packet.ts); } @@ -487,7 +698,7 @@ impl Rule for InformationalRule { return Ordering::Equal; } - if self.devices.is_empty() { + if self.devices.is_empty() && self.unknown_connections.is_empty() { return; } diff --git a/framework/java/android/bluetooth/BluetoothGattServer.java b/framework/java/android/bluetooth/BluetoothGattServer.java index 05eaf1ac6a..03910657c1 100644 --- a/framework/java/android/bluetooth/BluetoothGattServer.java +++ b/framework/java/android/bluetooth/BluetoothGattServer.java @@ -668,7 +668,7 @@ public final class BluetoothGattServer implements BluetoothProfile { /** * Set the preferred connection PHY for this app. Please note that this is just a - * recommendation, whether the PHY change will happen depends on other applications peferences, + * recommendation, whether the PHY change will happen depends on other applications preferences, * local and remote controller capabilities. Controller can override these settings. <p> {@link * BluetoothGattServerCallback#onPhyUpdate} will be triggered as a result of this call, even if * no PHY change happens. It is also triggered when remote device updates the PHY. @@ -856,7 +856,7 @@ public final class BluetoothGattServer implements BluetoothProfile { /** * Add a service to the list of services to be hosted. * - * <p>Once a service has been addded to the list, the service and its + * <p>Once a service has been added to the list, the service and its * included characteristics will be provided by the local device. * * <p>If the local device has already exposed services when this function @@ -943,7 +943,7 @@ public final class BluetoothGattServer implements BluetoothProfile { /** * Returns a list of GATT services offered by this device. * - * <p>An application must call {@link #addService} to add a serice to the + * <p>An application must call {@link #addService} to add a service to the * list of services offered by this device. * * @return List of services. Returns an empty list if no services have been added yet. diff --git a/service/Android.bp b/service/Android.bp index 97715d825d..7211e68801 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -45,11 +45,6 @@ java_defaults { "-Xep:ReferenceEquality:ERROR", ], }, - product_variables: { - pdk: { - enabled: false, - }, - }, sdk_version: "system_server_current", diff --git a/service/src/com/android/server/bluetooth/BluetoothManagerService.java b/service/src/com/android/server/bluetooth/BluetoothManagerService.java index a9c16deeb2..f95ff2ac3f 100644 --- a/service/src/com/android/server/bluetooth/BluetoothManagerService.java +++ b/service/src/com/android/server/bluetooth/BluetoothManagerService.java @@ -67,6 +67,7 @@ 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.provider.DeviceConfig; @@ -113,10 +114,13 @@ class BluetoothManagerService { private static final int CRASH_LOG_MAX_SIZE = 100; private static final int DEFAULT_REBIND_COUNT = 3; - private static final int TIMEOUT_BIND_MS = 3000; // Maximum msec to wait for a bind + // Maximum msec to wait for a bind + private static final int TIMEOUT_BIND_MS = + 3000 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); // Timeout value for synchronous binder call - private static final Duration SYNC_CALLS_TIMEOUT = Duration.ofSeconds(3); + private static final Duration SYNC_CALLS_TIMEOUT = + Duration.ofSeconds(3 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1)); /** * @return timeout value for synchronous binder call @@ -126,15 +130,20 @@ class BluetoothManagerService { } // Maximum msec to wait for service restart - private static final int SERVICE_RESTART_TIME_MS = 400; + private static final int SERVICE_RESTART_TIME_MS + = 400 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); // Maximum msec to wait for restart due to error - private static final int ERROR_RESTART_TIME_MS = 3000; + private static final int ERROR_RESTART_TIME_MS + = 3000 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); // Maximum msec to delay MESSAGE_USER_SWITCHED - private static final int USER_SWITCHED_TIME_MS = 200; + private static final int USER_SWITCHED_TIME_MS + = 200 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); // Delay for the addProxy function in msec - private static final int ADD_PROXY_DELAY_MS = 100; + private static final int ADD_PROXY_DELAY_MS + = 100 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); // Delay for retrying enable and disable in msec - private static final int ENABLE_DISABLE_DELAY_MS = 300; + private static final int ENABLE_DISABLE_DELAY_MS + = 300 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); @VisibleForTesting static final int MESSAGE_ENABLE = 1; @VisibleForTesting static final int MESSAGE_DISABLE = 2; diff --git a/system/audio_hal_interface/fuzzer/Android.bp b/system/audio_hal_interface/fuzzer/Android.bp index eed40552e9..0fc5e26792 100644 --- a/system/audio_hal_interface/fuzzer/Android.bp +++ b/system/audio_hal_interface/fuzzer/Android.bp @@ -77,7 +77,6 @@ cc_defaults { "libchrome", "libcutils", "libevent", - "libflatbuffers-cpp", "libg722codec", "libhidlbase", "libjsoncpp", diff --git a/system/binder/android/bluetooth/IBluetoothGatt.aidl b/system/binder/android/bluetooth/IBluetoothGatt.aidl index 221deaa7b1..8c5305e02a 100644 --- a/system/binder/android/bluetooth/IBluetoothGatt.aidl +++ b/system/binder/android/bluetooth/IBluetoothGatt.aidl @@ -47,11 +47,6 @@ import com.android.modules.utils.SynchronousResultReceiver; */ oneway interface IBluetoothGatt { @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)") - void startService(); - @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)") - void stopService(); - - @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)") void getDevicesMatchingConnectionStates(in int[] states, in AttributionSource attributionSource, in SynchronousResultReceiver receiver); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)") @@ -181,8 +176,6 @@ oneway interface IBluetoothGatt { @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)") void disconnectAll(in AttributionSource attributionSource, in SynchronousResultReceiver receiver); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)") - void unregAll(in AttributionSource attributionSource); - @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)") void numHwTrackFiltersAvailable(in AttributionSource attributionSource, in SynchronousResultReceiver receiver); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)") void leSubrateRequest(in int clientIf, in String address, in int subrateMin, in int subrateMax, in int maxLatency, diff --git a/system/bta/Android.bp b/system/bta/Android.bp index 8a3cd65a37..0805b45f6e 100644 --- a/system/bta/Android.bp +++ b/system/bta/Android.bp @@ -9,7 +9,7 @@ package { cc_defaults { name: "fluoride_bta_defaults", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], local_include_dirs: [ "dm", "hd", @@ -131,6 +131,7 @@ cc_library_static { static_libs: [ "avrcp-target-service", "lib-bt-packets", + "libbluetooth_gd", "libbt-bta-core", "libcom.android.sysprop.bluetooth", ], @@ -147,6 +148,9 @@ cc_library_static { ], }, }, + apex_available: [ + "com.android.btservices", + ], host_supported: true, min_sdk_version: "Tiramisu", } @@ -189,6 +193,9 @@ cc_library_static { "lib-bt-packets", "libcom.android.sysprop.bluetooth", ], + apex_available: [ + "com.android.btservices", + ], host_supported: true, min_sdk_version: "Tiramisu", } @@ -233,11 +240,11 @@ cc_test { static_libs: [ "crypto_toolbox_for_tests", "libbluetooth-types", + "libbluetooth_gd", "libbt-audio-hal-interface", "libbt-bta", "libbt-bta-core", "libbt-common", - "libbt-protos-lite", "libbtcore", "libchrome", "libcom.android.sysprop.bluetooth", @@ -279,11 +286,11 @@ cc_test { static_libs: [ "crypto_toolbox_for_tests", "libbluetooth-types", + "libbluetooth_gd", "libbt-audio-hal-interface", "libbt-bta", "libbt-bta-core", "libbt-common", - "libbt-protos-lite", "libbtcore", "libchrome", "libosi", @@ -397,14 +404,13 @@ cc_test { ], static_libs: [ "libbluetooth-types", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libbtcore", "libbtdevice", "libchrome", "libcom.android.sysprop.bluetooth", "libevent", - "libflatbuffers-cpp", "libgmock", ], sanitize: { @@ -459,8 +465,8 @@ cc_test { ], static_libs: [ "crypto_toolbox_for_tests", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libgmock", "libosi", @@ -503,8 +509,8 @@ cc_test { ], static_libs: [ "crypto_toolbox_for_tests", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libgmock", "libosi", @@ -558,8 +564,8 @@ cc_test { ], static_libs: [ "crypto_toolbox_for_tests", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libgmock", "libosi", @@ -722,8 +728,8 @@ cc_test { "liblog", // __android_log_print ], static_libs: [ + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libevent", "libflatbuffers-cpp", @@ -793,9 +799,9 @@ cc_test { ], static_libs: [ "crypto_toolbox_for_tests", + "libbluetooth_gd", "libbt-audio-hal-interface", "libbt-common", - "libbt-protos-lite", "libchrome", "libevent", "libflatbuffers-cpp", @@ -857,8 +863,8 @@ cc_test { ], static_libs: [ "crypto_toolbox_for_tests", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libgmock", "libosi", @@ -910,8 +916,8 @@ cc_test { "liblog", ], static_libs: [ + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libgmock", "liblc3", @@ -975,7 +981,6 @@ cc_test { static_libs: [ "libbt-audio-hal-interface", "libbt-common", - "libbt-protos-lite", "libchrome", "libevent", "libgmock", @@ -1035,8 +1040,8 @@ cc_test { ], static_libs: [ "crypto_toolbox_for_tests", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libgmock", ], @@ -1097,8 +1102,8 @@ cc_test { ], static_libs: [ "crypto_toolbox_for_tests", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libcom.android.sysprop.bluetooth", "libevent", diff --git a/system/bta/dm/bta_dm_act.cc b/system/bta/dm/bta_dm_act.cc index 48a2bd6a46..0782e049c6 100644 --- a/system/bta/dm/bta_dm_act.cc +++ b/system/bta/dm/bta_dm_act.cc @@ -846,8 +846,11 @@ void bta_dm_close_acl(const RawAddress& bd_addr, bool remove_dev, break; } if (index != bta_dm_cb.device_list.count) { - if (remove_dev) + if (remove_dev) { + LOG_INFO("Setting remove_dev_pending for %s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); bta_dm_cb.device_list.peer_device[index].remove_dev_pending = true; + } } else { APPL_TRACE_ERROR("unknown device, remove ACL failed"); } @@ -1080,8 +1083,8 @@ static bool bta_dm_read_remote_device_name(const RawAddress& bd_addr, bta_dm_search_cb.peer_bdaddr = bd_addr; bta_dm_search_cb.peer_name[0] = 0; - btm_status = BTM_ReadRemoteDeviceName(bta_dm_search_cb.peer_bdaddr, - bta_dm_remname_cback, transport); + btm_status = get_btm_client_interface().peer.BTM_ReadRemoteDeviceName( + bta_dm_search_cb.peer_bdaddr, bta_dm_remname_cback, transport); if (btm_status == BTM_CMD_STARTED) { APPL_TRACE_DEBUG("%s: BTM_ReadRemoteDeviceName is started", __func__); @@ -1094,7 +1097,8 @@ static bool bta_dm_read_remote_device_name(const RawAddress& bd_addr, * "bta_dm_remname_cback" */ /* adding callback to get notified that current reading remote name done */ - BTM_SecAddRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + get_btm_client_interface().security.BTM_SecAddRmtNameNotifyCallback( + &bta_dm_service_search_remname_cback); return (true); } else { @@ -1420,7 +1424,8 @@ void bta_dm_sdp_result(tBTA_DM_MSG* p_data) { /* callbacks */ /* start next bd_addr if necessary */ - BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + get_btm_client_interface().security.BTM_SecDeleteRmtNameNotifyCallback( + &bta_dm_service_search_remname_cback); BTM_LogHistory( kBtmLogTag, bta_dm_search_cb.peer_bdaddr, "Discovery completed", @@ -1490,7 +1495,8 @@ void bta_dm_sdp_result(tBTA_DM_MSG* p_data) { if (bta_dm_search_cb.p_sdp_db) osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db); - BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + get_btm_client_interface().security.BTM_SecDeleteRmtNameNotifyCallback( + &bta_dm_service_search_remname_cback); p_msg = (tBTA_DM_MSG*)osi_calloc(sizeof(tBTA_DM_MSG)); p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; @@ -2053,8 +2059,8 @@ static void bta_dm_discover_device(const RawAddress& remote_bd_addr) { if connection exists, we don't have to wait for ACL link to go down to start search on next device */ if (transport == BT_TRANSPORT_BR_EDR) { - if (BTM_IsAclConnectionUp(bta_dm_search_cb.peer_bdaddr, - BT_TRANSPORT_BR_EDR)) + if (get_btm_client_interface().peer.BTM_IsAclConnectionUp( + bta_dm_search_cb.peer_bdaddr, BT_TRANSPORT_BR_EDR)) bta_dm_search_cb.wait_disc = false; else bta_dm_search_cb.wait_disc = true; @@ -2269,13 +2275,15 @@ static void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p_remote_name) { p_remote_name->remote_bd_name[0], p_remote_name->length); if (bta_dm_search_cb.peer_bdaddr == p_remote_name->bd_addr) { - BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + get_btm_client_interface().security.BTM_SecDeleteRmtNameNotifyCallback( + &bta_dm_service_search_remname_cback); } else { // if we got a different response, maybe ignore it // we will have made a request directly from BTM_ReadRemoteDeviceName so we // expect a dedicated response for us if (p_remote_name->hci_status == HCI_ERR_CONNECTION_EXISTS) { - BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + get_btm_client_interface().security.BTM_SecDeleteRmtNameNotifyCallback( + &bta_dm_service_search_remname_cback); LOG_INFO( "Assume command failed due to disconnection hci_status:%s peer:%s", hci_error_code_text(p_remote_name->hci_status).c_str(), @@ -2903,6 +2911,8 @@ static void bta_dm_acl_down(const RawAddress& bd_addr, } } if (remove_device) { + LOG_INFO("remove_dev_pending actually removing %s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); bta_dm_process_remove_device_no_callback(bd_addr); } @@ -3068,8 +3078,13 @@ static void bta_dm_delay_role_switch_cback(UNUSED_ATTR void* data) { ******************************************************************************/ static void bta_dm_reset_sec_dev_pending(const RawAddress& remote_bd_addr) { for (size_t i = 0; i < bta_dm_cb.device_list.count; i++) { - if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr == remote_bd_addr) { - bta_dm_cb.device_list.peer_device[i].remove_dev_pending = false; + auto& dev = bta_dm_cb.device_list.peer_device[i]; + if (dev.peer_bdaddr == remote_bd_addr) { + if (dev.remove_dev_pending) { + LOG_INFO("Clearing remove_dev_pending for %s", + ADDRESS_TO_LOGGABLE_CSTR(dev.peer_bdaddr)); + dev.remove_dev_pending = false; + } return; } } @@ -3096,8 +3111,11 @@ static void bta_dm_remove_sec_dev_entry(const RawAddress& remote_bd_addr) { __func__); BTM_SecClearSecurityFlags(remote_bd_addr); for (int i = 0; i < bta_dm_cb.device_list.count; i++) { - if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr == remote_bd_addr) { - bta_dm_cb.device_list.peer_device[i].remove_dev_pending = TRUE; + auto& dev = bta_dm_cb.device_list.peer_device[i]; + if (dev.peer_bdaddr == remote_bd_addr) { + LOG_INFO("Setting remove_dev_pending for %s", + ADDRESS_TO_LOGGABLE_CSTR(dev.peer_bdaddr)); + dev.remove_dev_pending = TRUE; break; } } @@ -3169,7 +3187,8 @@ static const char* bta_dm_get_remname(void) { /* If the name isn't already stored, try retrieving from BTM */ if (*p_name == '\0') { - const char* p_temp = BTM_SecReadDevName(bta_dm_search_cb.peer_bdaddr); + const char* p_temp = get_btm_client_interface().security.BTM_SecReadDevName( + bta_dm_search_cb.peer_bdaddr); if (p_temp != NULL) p_name = (const char*)p_temp; } @@ -3970,6 +3989,12 @@ static uint8_t bta_dm_ble_smp_cback(tBTM_LE_EVT event, const RawAddress& bda, sec_event.ble_key.key_type = p_data->key.key_type; sec_event.ble_key.p_key_value = p_data->key.p_key_value; bta_dm_cb.p_sec_cback(BTA_DM_BLE_KEY_EVT, &sec_event); + + // Setting remove_dev_pending flag to false, where it will avoid deleting + // the security device record when the ACL connection link goes down in + // case of reconnection. + if (bta_dm_cb.device_list.count) bta_dm_reset_sec_dev_pending(bda); + break; case BTM_LE_COMPLT_EVT: @@ -4450,7 +4475,7 @@ void btm_dm_start_gatt_discovery(const RawAddress& bd_addr) { * Parameters: * ******************************************************************************/ -void bta_dm_proc_open_evt(tBTA_GATTC_OPEN* p_data) { +static void bta_dm_proc_open_evt(tBTA_GATTC_OPEN* p_data) { VLOG(1) << "DM Search state= " << bta_dm_search_get_state() << " search_cb.peer_dbaddr:" << bta_dm_search_cb.peer_bdaddr << " connected_bda=" << p_data->remote_bda.address; diff --git a/system/bta/test/bta_dm_test.cc b/system/bta/test/bta_dm_test.cc index 43c3c2a794..f40bb815d7 100644 --- a/system/bta/test/bta_dm_test.cc +++ b/system/bta/test/bta_dm_test.cc @@ -42,6 +42,7 @@ #include "test/mock/mock_osi_alarm.h" #include "test/mock/mock_osi_allocator.h" #include "test/mock/mock_stack_acl.h" +#include "test/mock/mock_stack_btm.h" #include "test/mock/mock_stack_btm_ble.h" #include "test/mock/mock_stack_btm_inq.h" #include "test/mock/mock_stack_btm_sec.h" @@ -50,8 +51,6 @@ using namespace std::chrono_literals; using ::testing::ElementsAre; -extern struct btm_client_interface_t btm_client_interface; - namespace base { class MessageLoop; } // namespace base @@ -106,6 +105,7 @@ class BtaDmTest : public testing::Test { bluetooth::legacy::testing::bta_dm_deinit_cb(); post_on_bt_main([]() { LOG_INFO("Main thread shutting down"); }); main_thread_shut_down(); + btm_client_interface = {}; } std::unique_ptr<test::fake::FakeOsi> fake_osi_; @@ -392,6 +392,11 @@ TEST_F(BtaDmTest, bta_dm_remname_cback__typical) { strlcpy(reinterpret_cast<char*>(&name.remote_bd_name), kRemoteName, strlen(kRemoteName)); + btm_client_interface.security.BTM_SecDeleteRmtNameNotifyCallback = + [](tBTM_RMT_NAME_CALLBACK*) -> bool { + inc_func_call_count("BTM_SecDeleteRmtNameNotifyCallback"); + return true; + }; bluetooth::legacy::testing::bta_dm_remname_cback(&name); sync_main_handler(); @@ -416,6 +421,11 @@ TEST_F(BtaDmTest, bta_dm_remname_cback__wrong_address) { strlcpy(reinterpret_cast<char*>(&name.remote_bd_name), kRemoteName, strlen(kRemoteName)); + btm_client_interface.security.BTM_SecDeleteRmtNameNotifyCallback = + [](tBTM_RMT_NAME_CALLBACK*) -> bool { + inc_func_call_count("BTM_SecDeleteRmtNameNotifyCallback"); + return true; + }; bluetooth::legacy::testing::bta_dm_remname_cback(&name); sync_main_handler(); @@ -440,6 +450,11 @@ TEST_F(BtaDmTest, bta_dm_remname_cback__HCI_ERR_CONNECTION_EXISTS) { strlcpy(reinterpret_cast<char*>(&name.remote_bd_name), kRemoteName, strlen(kRemoteName)); + btm_client_interface.security.BTM_SecDeleteRmtNameNotifyCallback = + [](tBTM_RMT_NAME_CALLBACK*) -> bool { + inc_func_call_count("BTM_SecDeleteRmtNameNotifyCallback"); + return true; + }; bluetooth::legacy::testing::bta_dm_remname_cback(&name); sync_main_handler(); diff --git a/system/bta/test/bta_sdp_test.cc b/system/bta/test/bta_sdp_test.cc index b91c44d51a..52775f0cc2 100644 --- a/system/bta/test/bta_sdp_test.cc +++ b/system/bta/test/bta_sdp_test.cc @@ -30,6 +30,10 @@ void BTA_dm_on_hw_on(); void BTA_dm_on_hw_off(); +namespace { +const char kName[] = "Hello"; +} + class BtaSdpTest : public testing::Test { protected: void SetUp() override { @@ -100,5 +104,9 @@ TEST_F(BtaSdpRegisteredTest, bta_dm_sdp_result_SDP_SUCCESS) { .sdp_result = SDP_SUCCESS, }, }; + btm_client_interface.security.BTM_SecReadDevName = + [](const RawAddress& bd_addr) -> const char* { return kName; }; + btm_client_interface.security.BTM_SecDeleteRmtNameNotifyCallback = + [](tBTM_RMT_NAME_CALLBACK*) -> bool { return true; }; bta_dm_sdp_result(&msg); } diff --git a/system/btcore/Android.bp b/system/btcore/Android.bp index 0361a809c0..5e4b9de0dd 100644 --- a/system/btcore/Android.bp +++ b/system/btcore/Android.bp @@ -10,7 +10,7 @@ package { cc_defaults { name: "libbtcore_defaults", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], local_include_dirs: ["include"], include_dirs: [ "packages/modules/Bluetooth/system", @@ -36,7 +36,7 @@ cc_defaults { cc_library_static { name: "libbthalutils", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], srcs: [ "src/hal_util.cc", ], diff --git a/system/btif/Android.bp b/system/btif/Android.bp index 08df424495..097d66908d 100644 --- a/system/btif/Android.bp +++ b/system/btif/Android.bp @@ -39,9 +39,6 @@ cc_library { generated_sources: ["statslog_bt.cpp"], generated_headers: ["statslog_bt.h"], export_generated_headers: ["statslog_bt.h"], - shared_libs: [ - "libcutils", - ], apex_available: [ "com.android.btservices", ], @@ -57,6 +54,7 @@ cc_library { }, host: { static_libs: [ + "libbase", "libstatssocket", ], export_static_lib_headers: [ @@ -89,7 +87,7 @@ genrule { cc_library_static { name: "libbtif", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], include_dirs: btifCommonIncludes, srcs: [ // AVRCP Target Service @@ -162,13 +160,16 @@ cc_library_static { cflags: [ "-DBUILDCFG", ], + apex_available: [ + "com.android.btservices", + ], host_supported: true, min_sdk_version: "Tiramisu", } cc_library_static { name: "libbtif-core", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], include_dirs: btifCommonIncludes, srcs: [ // Callouts @@ -237,6 +238,9 @@ cc_library_static { "-DBUILDCFG", "-fvisibility=default", ], + apex_available: [ + "com.android.btservices", + ], host_supported: true, min_sdk_version: "Tiramisu", } @@ -269,7 +273,7 @@ cc_test { "libutils", ], static_libs: [ - "android.hardware.audio.common-V1-ndk", + "android.hardware.audio.common-V2-ndk", "android.hardware.bluetooth.a2dp@1.0", "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.bluetooth@1.0", @@ -286,7 +290,6 @@ cc_test { "libbt-bta-core", "libbt-common", "libbt-hci", - "libbt-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", "libbt-stack", @@ -342,8 +345,8 @@ cc_test { ], static_libs: [ "libbluetooth-types", + "libbluetooth_gd", "libchrome", - "libflatbuffers-cpp", "libosi", ], cflags: ["-DBUILDCFG"], @@ -376,7 +379,6 @@ cc_test { static_libs: [ "libbluetooth-types", "libchrome", - "libflatbuffers-cpp", "libosi", ], cflags: ["-DBUILDCFG"], @@ -412,8 +414,8 @@ cc_test { ], static_libs: [ "libbluetooth-types", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libevent", "libosi-AllocationTestHarness", @@ -595,6 +597,7 @@ cc_test { "lib-bt-packets-base", "libaudio-a2dp-hw-utils", "libbluetooth-types", + "libbluetooth_gd", "libbt-audio-hal-interface", "libbt-sbc-decoder", "libbt-sbc-encoder", @@ -607,14 +610,13 @@ cc_test { "libchrome", "libcom.android.sysprop.bluetooth", "libevent", - "libflatbuffers-cpp", "libgmock", ], cflags: ["-DBUILDCFG"], target: { android: { static_libs: [ - "android.hardware.audio.common-V1-ndk", + "android.hardware.audio.common-V2-ndk", "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.common-V2-ndk", "android.hardware.common.fmq-V1-ndk", @@ -729,6 +731,7 @@ cc_test { "lib-bt-packets-base", "libaudio-a2dp-hw-utils", "libbluetooth-types", + "libbluetooth_gd", "libbt-audio-hal-interface", "libbt-sbc-decoder", "libbt-sbc-encoder", @@ -739,14 +742,13 @@ cc_test { "libchrome", "libcom.android.sysprop.bluetooth", "libevent", - "libflatbuffers-cpp", "libgmock", ], cflags: ["-DBUILDCFG"], target: { android: { static_libs: [ - "android.hardware.audio.common-V1-ndk", + "android.hardware.audio.common-V2-ndk", "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.common-V2-ndk", "android.hardware.common.fmq-V1-ndk", diff --git a/system/btif/co/bta_av_co.cc b/system/btif/co/bta_av_co.cc index 42711010dc..e1724b21ea 100644 --- a/system/btif/co/bta_av_co.cc +++ b/system/btif/co/bta_av_co.cc @@ -406,13 +406,6 @@ class BtaAvCo { const tA2DP_ENCODER_INTERFACE* GetSourceEncoderInterface(); /** - * Get the Sink decoder interface for the current codec. - * - * @return the Sink decoder interface for the current codec - */ - const tA2DP_DECODER_INTERFACE* GetSinkDecoderInterface(); - - /** * Set the codec user configuration. * * @param peer_address the peer address @@ -1446,8 +1439,8 @@ void BtaAvCo::UpdateMtu(tBTA_AV_HNDL bta_av_handle, } bool BtaAvCo::SetActivePeer(const RawAddress& peer_address) { - VLOG(1) << __func__ << ": peer_address=" - << ADDRESS_TO_LOGGABLE_STR(peer_address); + LOG(INFO) << __func__ + << ": peer_address=" << ADDRESS_TO_LOGGABLE_STR(peer_address); std::lock_guard<std::recursive_mutex> lock(codec_lock_); @@ -1505,12 +1498,6 @@ const tA2DP_ENCODER_INTERFACE* BtaAvCo::GetSourceEncoderInterface() { return A2DP_GetEncoderInterface(codec_config_); } -const tA2DP_DECODER_INTERFACE* BtaAvCo::GetSinkDecoderInterface() { - std::lock_guard<std::recursive_mutex> lock(codec_lock_); - - return A2DP_GetDecoderInterface(codec_config_); -} - bool BtaAvCo::SetCodecUserConfig( const RawAddress& peer_address, const btav_a2dp_codec_config_t& codec_user_config, bool* p_restart_output) { @@ -2263,10 +2250,6 @@ const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void) { return bta_av_co_cb.GetSourceEncoderInterface(); } -const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void) { - return bta_av_co_cb.GetSinkDecoderInterface(); -} - bool bta_av_co_set_codec_user_config( const RawAddress& peer_address, const btav_a2dp_codec_config_t& codec_user_config, bool* p_restart_output) { diff --git a/system/btif/include/btif_av_co.h b/system/btif/include/btif_av_co.h index 1ce810f5e3..d7f80ab559 100644 --- a/system/btif/include/btif_av_co.h +++ b/system/btif/include/btif_av_co.h @@ -40,12 +40,6 @@ void bta_av_co_get_peer_params(const RawAddress& peer_addr, // otherwise NULL. const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void); -// Gets the current A2DP decoder interface that can be used to decode received -// A2DP packets - see |tA2DP_DECODER_INTERFACE|. -// Returns the A2DP decoder interface if the current codec is setup, otherwise -// NULL. -const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void); - // Sets the user preferred codec configuration. // The peer address is |peer_addr|. // |codec_user_config| contains the preferred codec configuration. diff --git a/system/btif/src/btif_a2dp_sink.cc b/system/btif/src/btif_a2dp_sink.cc index 9a03a3cd44..4340e48375 100644 --- a/system/btif/src/btif_a2dp_sink.cc +++ b/system/btif/src/btif_a2dp_sink.cc @@ -631,7 +631,8 @@ static void btif_a2dp_sink_decoder_update_event( btif_a2dp_sink_cb.rx_flush = false; APPL_TRACE_DEBUG("%s: reset to Sink role", __func__); - btif_a2dp_sink_cb.decoder_interface = bta_av_co_get_decoder_interface(); + btif_a2dp_sink_cb.decoder_interface = + A2DP_GetDecoderInterface(p_buf->codec_info); if (btif_a2dp_sink_cb.decoder_interface == nullptr) { LOG_ERROR("%s: cannot stream audio: no source decoder interface", __func__); return; diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc index 767279e724..23f78fd1e8 100644 --- a/system/btif/src/btif_av.cc +++ b/system/btif/src/btif_av.cc @@ -4035,9 +4035,9 @@ uint8_t btif_av_get_peer_sep(void) { } uint8_t peer_sep = peer->PeerSep(); - LOG_INFO("Peer %s SEP is %s (%d)", - ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), - (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", peer_sep); + BTIF_TRACE_DEBUG("Peer %s SEP is %s (%d)", + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", peer_sep); return peer_sep; } diff --git a/system/btif/src/btif_avrcp_audio_track.cc b/system/btif/src/btif_avrcp_audio_track.cc index 296c603c7f..2a732f372e 100644 --- a/system/btif/src/btif_avrcp_audio_track.cc +++ b/system/btif/src/btif_avrcp_audio_track.cc @@ -51,8 +51,8 @@ constexpr float kMinTrackGain = 0.0f; void* BtifAvrcpAudioTrackCreate(int trackFreq, int bitsPerSample, int channelCount) { - LOG_VERBOSE("%s Track.cpp: btCreateTrack freq %d bps %d channel %d ", - __func__, trackFreq, bitsPerSample, channelCount); + LOG_INFO("%s Track.cpp: btCreateTrack freq %d bps %d channel %d ", __func__, + trackFreq, bitsPerSample, channelCount); AAudioStreamBuilder* builder; AAudioStream* stream; diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc index 1521897450..bfe4c6f41a 100644 --- a/system/btif/src/btif_dm.cc +++ b/system/btif/src/btif_dm.cc @@ -602,11 +602,6 @@ static void bond_state_changed(bt_status_t status, const RawAddress& bd_addr, GetInterfaceToProfiles()->events->invoke_bond_state_changed_cb( status, bd_addr, state, pairing_cb.fail_reason); - int dev_type; - if (!btif_get_device_type(bd_addr, &dev_type)) { - dev_type = BT_DEVICE_TYPE_BREDR; - } - if ((state == BT_BOND_STATE_NONE) && (pairing_cb.bd_addr != bd_addr) && is_bonding_or_sdp()) { LOG_WARN("Ignoring bond state changed for unexpected device: %s pairing: %s", diff --git a/system/build/Android.bp b/system/build/Android.bp index 95b20a2ec7..52a5850179 100644 --- a/system/build/Android.bp +++ b/system/build/Android.bp @@ -19,7 +19,6 @@ cc_defaults { // struct BT_HDR is defined as a variable-size header in a struct. "-Wno-gnu-variable-sized-type-not-at-end", ], - c_std: "c99", product_variables: { debuggable: { cflags: [ @@ -57,7 +56,6 @@ cc_defaults { "libbt_shim_bridge", "libbt_shim_ffi", ], - cpp_std: "c++17", min_sdk_version: "current", } @@ -71,7 +69,6 @@ cc_defaults { ], static_libs: [ "libbt-common", - "libbt-protos-lite", "libcutils", "libgmock", "libosi", @@ -86,28 +83,11 @@ cc_defaults { } cc_defaults { - name: "fluoride_basic_defaults", - defaults: [ - "fluoride_defaults", - ], - apex_available: [ - "//apex_available:platform", - "com.android.btservices", - ], - static_libs: [ - "libbt-protos-lite", - "libflatbuffers-cpp", - "libprotobuf-cpp-lite", - ], -} - -cc_defaults { name: "fluoride_defaults", defaults: [ "fluoride_defaults_fuzzable", ], static_libs: [ - "libbluetooth_gd", "libstatslog_bt", ], target: { diff --git a/system/common/Android.bp b/system/common/Android.bp index 3c6a803dca..c40182d5b7 100644 --- a/system/common/Android.bp +++ b/system/common/Android.bp @@ -10,7 +10,7 @@ package { cc_library_static { name: "libbt-common", defaults: [ - "fluoride_basic_defaults", + "fluoride_defaults", ], host_supported: true, include_dirs: [ @@ -28,9 +28,17 @@ cc_library_static { "stop_watch_legacy.cc", "time_util.cc", ], + proto: { + type: "lite", + canonical_path_from_root: false, + export_proto_headers: true, + }, target: { android: { - srcs: ["metrics.cc"], + srcs: [ + ":bluetooth-metrics-proto", + "metrics.cc", + ], }, host: { srcs: ["metrics_linux.cc"], @@ -40,6 +48,9 @@ cc_library_static { "libcrypto", "libcutils", ], + apex_available: [ + "com.android.btservices", + ], min_sdk_version: "Tiramisu", } @@ -85,7 +96,6 @@ cc_test { ], static_libs: [ "libbt-common", - "libbt-protos-lite", "libchrome", "libevent", "libgmock", diff --git a/system/device/Android.bp b/system/device/Android.bp index 59b7a3d9b4..738db4f73f 100644 --- a/system/device/Android.bp +++ b/system/device/Android.bp @@ -10,7 +10,7 @@ package { cc_library_static { name: "libbtdevice", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], host_supported: true, local_include_dirs: [ "include", @@ -28,6 +28,9 @@ cc_library_static { "src/esco_parameters.cc", "src/interop.cc", ], + apex_available: [ + "com.android.btservices", + ], min_sdk_version: "Tiramisu", } @@ -50,6 +53,7 @@ cc_test { ], static_libs: [ "libbluetooth-types", + "libbluetooth_gd", "libbtcore", "libbtdevice", "libchrome", diff --git a/system/device/fuzzer/Android.bp b/system/device/fuzzer/Android.bp index 08aeaa971a..1f5193d948 100644 --- a/system/device/fuzzer/Android.bp +++ b/system/device/fuzzer/Android.bp @@ -35,6 +35,7 @@ cc_fuzz { ], static_libs: [ "libbluetooth-types", + "libbluetooth_gd", "libbtcore", "libbtdevice", "libchrome", diff --git a/system/doc/btsnoop_net.md b/system/doc/btsnoop_net.md deleted file mode 100644 index 6964a9add6..0000000000 --- a/system/doc/btsnoop_net.md +++ /dev/null @@ -1,16 +0,0 @@ -btsnoop_net -==== -btsnoop_net exposes Bluetooth snoop logs over a local TCP socket which enables -real-time debugging of HCI data with hcidump. - -This feature is enabled by enabling "Enable Bluetooth HCI snoop log" in the -Developer options and setting BT_NET_DEBUG flag to TRUE in the btsnoop_net.cc. -Once it has been enabled and the stack restarted, the stack will listen for -incoming TCP connections on port 8872. - -To use this feature with btmon on a Linux host, you can run: - -``` - $ adb forward tcp:8872 tcp:8872 - $ nc localhost 8872 | btmon -P -r /dev/stdin -``` diff --git a/system/doc/log_tags.md b/system/doc/log_tags.md deleted file mode 100644 index fe6a3e4dba..0000000000 --- a/system/doc/log_tags.md +++ /dev/null @@ -1,57 +0,0 @@ -Log Tags -=== -This document lists all of the log tags used by the Bluetooth stack. - -* audio_a2dp_hw -* BTA_AG_CO: -* bta_sys_main -* bt_btif -* bt_btif_config -* bt_btif_config_transcode -* bt_classic_peer -* bte_conf -* BtGatt.btif -* BtGatt.btif_test -* bt_hci -* bt_hci_h4 -* bt_hci_inject -* bt_hci_mct -* bt_hci_packet_fragmenter -* BTIF_AV -* BTIF_CORE -* BTIF_HF -* BTIF_HF_CLIENT -* BTIF_HH -* BTIF_HL -* BTIF-MEDIA -* BTIF_PAN -* BTIF_QUEUE -* BTIF_RC -* BTIF_SM -* btif_sock -* BTIF_SOCK -* btif_sock_rfcomm -* btif_sock_sco -* BTIF_SOCK_SDP -* BTIF_STORAGE -* BTIF_UTIL -* BTLD -* bt_module -* bt_osi_alarm -* bt_osi_config -* bt_osi_data_dispatcher -* bt_osi_reactor -* bt_osi_socket -* bt_profile_manager -* bt_sdp_client -* btsnoop -* btsnoop_net -* bt_stack_config -* bt_stack_manager -* bt_task -* btu_task -* BT_UTILS -* bt_vendor -* osi_future -* osi_semaphore -* osi_thread diff --git a/system/doc/network_ports.md b/system/doc/network_ports.md deleted file mode 100644 index 03e138e0df..0000000000 --- a/system/doc/network_ports.md +++ /dev/null @@ -1,8 +0,0 @@ -Network Ports -=== -This document lists all of the network ports used by the bluetooth stack. -It should be used as a reference and as a mechanism to avoid port -namespace conflicts. - -* TCP 8872 (hci/src/btsnoop_net.cc) - read live btsnoop logs -* TCP 8873 (hci/src/hci_inject.cc) - inject HCI packets into HCI stream diff --git a/system/doc/properties.md b/system/doc/properties.md deleted file mode 100644 index c4ab97c018..0000000000 --- a/system/doc/properties.md +++ /dev/null @@ -1,20 +0,0 @@ -Properties -=== -This document describes all of the Android properties used by the Bluetooth -stack. - -Please keep the following list in alphabetical order. - -* ``` bluetooth.enable_timeout_ms ``` - Maximum amount of time Bluetooth can take to start-up, upload firmware etc. - Used in hci/src/hci_layer.cc, default 8000. - -### TODO: write descriptions of what each property means and how -it's used. - -* ``` debug.sys.noschedgroups ``` -* ``` persist.service.bdroid.bdaddr ``` -* ``` ro.bluetooth.hfp.ver ``` -* ``` ro.bt.bdaddr_path ``` -* ``` ro.product.model ``` -* ``` service.brcm.bt.oob ``` diff --git a/system/doc/pts_guide.md b/system/doc/pts_guide.md deleted file mode 100644 index 1e13b9d07b..0000000000 --- a/system/doc/pts_guide.md +++ /dev/null @@ -1,43 +0,0 @@ -# Fluoride Bluetooth Profile Tuning Suite (PTS) Test Mode - -This document provides commands to enable PTS test mode for Fluoride stack. We -need special handling for some test cases as they are not applicable for the -Fluoride stack. - -## PTS Test Mode system property - -Profile services in packages/apps/Bluetooth uses system property -`persist.bluetooth.pts` to check if the PTS test mode is enabled. To enable it: - -```sh -adb shell setprop persist.bluetooth.pts true -``` - -To disable it: - -```sh -adb shell setprop persist.bluetooth.pts false -``` - -### Current use case - -- In `newavrcp`, we send active player update to remote device only in PTS test - mode (AVRCP/TG/MPS/BV-05-C AVRCP/TG/MPS/BV-07-C). - -## PTS Helpers in stack config - -Native stack also requires some special handling, and the config is stored in -`conf/bt_stack.conf`. To enable a flag, uncomment the corresponding line and -push the config file to `/etc/bluetooth/` in IUT. - -### Current use case - -- `PTS_SecurePairOnly` enables secure connections only mode. -- `PTS_DisableConnUpdates` disables LE Connection updates. -- `PTS_DisableSDPOnLEPair` disables BR/EDR discovery after LE pairing to avoid - cross key derivation errors. -- `PTS_SmpOptions` sets SMP Pair options (formatted as hex bytes) `auth, io, - ikey, rkey, ksize`. -- `PTS_AvrcpTest` enables AVRCP test mode. The UID is set to 0xffffffffffffffff - in `TrackChangedNotificationResponse` (AVRCP/TG/NFY/BV-04-C). -- `PTS_SmpFailureCase` enables handling for various SMP failure cases. diff --git a/system/doc/supported_features.md b/system/doc/supported_features.md deleted file mode 100644 index 50ca84d027..0000000000 --- a/system/doc/supported_features.md +++ /dev/null @@ -1,19 +0,0 @@ -# Fluoride 1.1 - -Declaration ID: [D024527](https://www.bluetooth.org/tpg/QLI_viewQDL.cfm?qid=24527) -Qualified Design ID: 83953 - -Protocol / Profile | Version | Roles --------------------+---------+------- -L2CAP | 4.2 | Initiator, Acceptor, LE Central, LE Peripheral -SDP | 4.2 | Server, Client -GAP | 4.2 | BR/EDR, LE Central, LE Periperhal, LE Observer, LE Broadcaster -GATT | 4.2 | Client, Server; LE and BR/EDR -ATT | 4.2 | Client, Server; LE and BR/EDR -SM | 4.2 | Central (Initiator), Peripheral (Responder) -AVCTP | 1.4 | Controller, Target -AVDTP | 1.2 | Source, Initiator, Acceptor -BNEP | 1.0 | -GAVDP | 1.2 | Initiator, Acceptor -RFCOMM | 1.2 | -SPP | 1.2 | A, B diff --git a/system/gd/Android.bp b/system/gd/Android.bp index cdf6ae2c7d..70e52fe37e 100644 --- a/system/gd/Android.bp +++ b/system/gd/Android.bp @@ -30,7 +30,6 @@ cc_defaults { enabled: false, }, }, - cpp_std: "c++17", cflags: [ "-DEXPORT_SYMBOL=__attribute__((visibility(\"default\")))", "-DGOOGLE_PROTOBUF_NO_RTTI", @@ -38,7 +37,6 @@ cc_defaults { "-Wno-unused-result", "-fvisibility=hidden", ], - c_std: "c99", header_libs: ["jni_headers"], } @@ -164,6 +162,9 @@ cc_defaults { "libcrypto", "libflatbuffers-cpp", ], + export_shared_lib_headers: [ + "libflatbuffers-cpp", + ], whole_static_libs: [ "libc++fs", ], @@ -470,7 +471,6 @@ cc_defaults { ], shared_libs: [ "libcrypto", - "libflatbuffers-cpp", "libgrpc++", "libgrpc_wrap", ], diff --git a/system/gd/btaa/activity_attribution.h b/system/gd/btaa/activity_attribution.h index 93f5549dd3..7ad4ad42b3 100644 --- a/system/gd/btaa/activity_attribution.h +++ b/system/gd/btaa/activity_attribution.h @@ -36,17 +36,6 @@ struct BtaaAggregationEntry { CreationTime creation_time; }; -class ActivityAttributionCallback { - public: - virtual ~ActivityAttributionCallback() = default; - - // Callback when Bluetooth woke up the system - virtual void OnWakeup(const Activity activity, const hci::Address& address) = 0; - - // Callback when Bluetooth activity logs are ready to be moved - virtual void OnActivityLogsReady(const std::vector<BtaaAggregationEntry> logs) = 0; -}; - class ActivityAttribution : public bluetooth::Module { public: ActivityAttribution() = default; @@ -59,7 +48,6 @@ class ActivityAttribution : public bluetooth::Module { void OnWakelockAcquired(); void OnWakelockReleased(); void OnWakeup(); - void RegisterActivityAttributionCallback(ActivityAttributionCallback* callback); void NotifyActivityAttributionInfo(int uid, const std::string& package_name, const std::string& device_address); static const ModuleFactory Factory; diff --git a/system/gd/btaa/android/activity_attribution.cc b/system/gd/btaa/android/activity_attribution.cc index 79e0cea62d..e7a15bd9d6 100644 --- a/system/gd/btaa/android/activity_attribution.cc +++ b/system/gd/btaa/android/activity_attribution.cc @@ -158,10 +158,6 @@ struct ActivityAttribution::impl { attribution_processor_.OnWakeup(); } - void register_callback(ActivityAttributionCallback* callback) { - callback_ = callback; - } - void notify_activity_attribution_info(int uid, const std::string& package_name, const std::string& device_address) { attribution_processor_.NotifyActivityAttributionInfo(uid, package_name, device_address); } @@ -171,7 +167,6 @@ struct ActivityAttribution::impl { attribution_processor_.Dump(std::move(promise), fb_builder); } - ActivityAttributionCallback* callback_; AttributionProcessor attribution_processor_; HciProcessor hci_processor_; WakelockProcessor wakelock_processor_; @@ -213,10 +208,6 @@ void ActivityAttribution::OnWakeup() { CallOn(pimpl_.get(), &impl::on_wakeup); } -void ActivityAttribution::RegisterActivityAttributionCallback(ActivityAttributionCallback* callback) { - CallOn(pimpl_.get(), &impl::register_callback, callback); -} - void ActivityAttribution::NotifyActivityAttributionInfo( int uid, const std::string& package_name, const std::string& device_address) { CallOn(pimpl_.get(), &impl::notify_activity_attribution_info, uid, package_name, device_address); diff --git a/system/gd/btaa/host/activity_attribution.cc b/system/gd/btaa/host/activity_attribution.cc index ec02daf108..20c7ac76cc 100644 --- a/system/gd/btaa/host/activity_attribution.cc +++ b/system/gd/btaa/host/activity_attribution.cc @@ -29,8 +29,6 @@ void ActivityAttribution::OnWakelockReleased() {} void ActivityAttribution::OnWakeup() {} -void ActivityAttribution::RegisterActivityAttributionCallback(ActivityAttributionCallback* callback) {} - void ActivityAttribution::NotifyActivityAttributionInfo( int uid, const std::string& package_name, const std::string& device_address) {} diff --git a/system/gd/btaa/linux/activity_attribution.cc b/system/gd/btaa/linux/activity_attribution.cc index c4a4eb0aab..c39186750a 100644 --- a/system/gd/btaa/linux/activity_attribution.cc +++ b/system/gd/btaa/linux/activity_attribution.cc @@ -26,14 +26,10 @@ struct ActivityAttribution::impl { impl(ActivityAttribution* module) {} void on_hci_packet(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) {} - - void register_callback(ActivityAttributionCallback* callback) {} }; void ActivityAttribution::Capture(const hal::HciPacket& packet, hal::SnoopLogger::PacketType type) {} -void ActivityAttribution::RegisterActivityAttributionCallback(ActivityAttributionCallback* callback) {} - void ActivityAttribution::NotifyActivityAttributionInfo( int uid, const std::string& package_name, const std::string& device_address) {} diff --git a/system/gd/dumpsys/bundler/Android.bp b/system/gd/dumpsys/bundler/Android.bp index f2f346a9ec..64059976bb 100644 --- a/system/gd/dumpsys/bundler/Android.bp +++ b/system/gd/dumpsys/bundler/Android.bp @@ -49,7 +49,6 @@ genrule { cc_defaults { name: "bluetooth_flatbuffer_bundler_defaults", defaults: ["bluetooth_cflags"], - cpp_std: "c++17", generated_headers: [ "BluetoothGeneratedBundlerSchema_h_bfbs", ], diff --git a/system/gd/proto/Android.bp b/system/gd/proto/Android.bp index 538d8df347..6136cf84f6 100644 --- a/system/gd/proto/Android.bp +++ b/system/gd/proto/Android.bp @@ -14,7 +14,6 @@ java_library_static { type: "lite", }, srcs: [ - "bluetooth/bluetoothKeystore/keystore.proto", "bluetooth/metrics/bluetooth.proto", ], apex_available: [ @@ -24,21 +23,11 @@ java_library_static { sdk_version: "current", } -cc_library_static { - name: "libbt-protos-lite", - host_supported: true, - proto: { - export_proto_headers: true, - type: "lite", - }, +filegroup { + name: "bluetooth-metrics-proto", srcs: [ - "bluetooth/bluetoothKeystore/keystore.proto", "bluetooth/metrics/bluetooth.proto", ], - apex_available: [ - "com.android.btservices", - ], - min_sdk_version: "30", } cc_library_static { @@ -50,7 +39,6 @@ cc_library_static { include_dirs: ["external/protobuf/src"], }, srcs: [ - "bluetooth/bluetoothKeystore/keystore.proto", "bluetooth/metrics/bluetooth.proto", ], apex_available: [ diff --git a/system/gd/rust/linux/client/src/dbus_iface.rs b/system/gd/rust/linux/client/src/dbus_iface.rs index 5b87b9e01c..98e2e0cc5d 100644 --- a/system/gd/rust/linux/client/src/dbus_iface.rs +++ b/system/gd/rust/linux/client/src/dbus_iface.rs @@ -731,7 +731,7 @@ impl IBluetooth for BluetoothDBus { dbus_generated!() } - fn init(&mut self, init_flags: Vec<String>) -> bool { + fn init(&mut self, _init_flags: Vec<String>) -> bool { // Not implemented by server true } diff --git a/system/gd/rust/linux/service/src/iface_bluetooth.rs b/system/gd/rust/linux/service/src/iface_bluetooth.rs index e006675743..ea651d5966 100644 --- a/system/gd/rust/linux/service/src/iface_bluetooth.rs +++ b/system/gd/rust/linux/service/src/iface_bluetooth.rs @@ -441,7 +441,7 @@ impl IBluetooth for IBluetoothDBus { } // Not exposed over D-Bus. The stack is automatically initialized when the daemon starts. - fn init(&mut self, init_flags: Vec<String>) -> bool { + fn init(&mut self, _init_flags: Vec<String>) -> bool { dbus_generated!() } diff --git a/system/gd/rust/linux/service/src/main.rs b/system/gd/rust/linux/service/src/main.rs index 0f00105a32..1f9a5864c1 100644 --- a/system/gd/rust/linux/service/src/main.rs +++ b/system/gd/rust/linux/service/src/main.rs @@ -431,7 +431,7 @@ fn main() -> Result<(), Box<dyn Error>> { lazy_static! { /// Data needed for signal handling. - static ref SIG_DATA: Mutex<Option<(Sender<Message>, Arc<(SigData)>)>> = Mutex::new(None); + static ref SIG_DATA: Mutex<Option<(Sender<Message>, Arc<SigData>)>> = Mutex::new(None); } extern "C" fn handle_sigterm(_signum: i32) { diff --git a/system/gd/rust/linux/stack/src/bluetooth.rs b/system/gd/rust/linux/stack/src/bluetooth.rs index a30f07c357..a62ec4ca54 100644 --- a/system/gd/rust/linux/stack/src/bluetooth.rs +++ b/system/gd/rust/linux/stack/src/bluetooth.rs @@ -509,7 +509,7 @@ pub struct Bluetooth { discoverable_timeout: Option<JoinHandle<()>>, /// Used to notify signal handler that we have turned off the stack. - sig_notifier: Arc<(SigData)>, + sig_notifier: Arc<SigData>, } impl Bluetooth { @@ -518,7 +518,7 @@ impl Bluetooth { adapter_index: i32, hci_index: i32, tx: Sender<Message>, - sig_notifier: Arc<(SigData)>, + sig_notifier: Arc<SigData>, intf: Arc<Mutex<BluetoothInterface>>, bluetooth_admin: Arc<Mutex<Box<BluetoothAdmin>>>, bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>, diff --git a/system/gd/rust/linux/stack/src/bluetooth_media.rs b/system/gd/rust/linux/stack/src/bluetooth_media.rs index f26cc91006..d05f02738b 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_media.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_media.rs @@ -1095,6 +1095,15 @@ impl BluetoothMedia { let sleep_duration = (first_conn_ts + total_duration).saturating_duration_since(now_ts); sleep(sleep_duration).await; + Self::async_disconnect(fallback_tasks, device_states, txl, addr).await; + } + + async fn async_disconnect( + fallback_tasks: &Arc<Mutex<HashMap<RawAddress, Option<(JoinHandle<()>, Instant)>>>>, + device_states: &Arc<Mutex<HashMap<RawAddress, DeviceConnectionStates>>>, + txl: &Sender<Message>, + addr: &RawAddress, + ) { device_states.lock().unwrap().insert(*addr, DeviceConnectionStates::Disconnecting); fallback_tasks.lock().unwrap().insert(*addr, None); @@ -1119,6 +1128,16 @@ impl BluetoothMedia { let _ = txl.send(Message::Media(MediaActions::ForceEnterConnected(addr.to_string()))).await; } + fn is_bonded(&self, addr: &RawAddress) -> bool { + match &self.adapter { + Some(adapter) => { + BtBondState::Bonded + == adapter.lock().unwrap().get_bond_state_by_addr(&addr.to_string()) + } + _ => false, + } + } + fn notify_media_capability_updated(&mut self, addr: RawAddress) { let mut guard = self.fallback_tasks.lock().unwrap(); let mut states = self.device_states.lock().unwrap(); @@ -1135,8 +1154,22 @@ impl BluetoothMedia { guard.insert(addr, None); } else { // The device is already added or is disconnecting. - // Ignore unless all profiles are cleared. + // Ignore unless all profiles are cleared, where we need to do some clean up. if !is_profile_cleared { + // Unbonded device is special, we need to reject the connection from them. + if !self.is_bonded(&addr) { + let tasks = self.fallback_tasks.clone(); + let states = self.device_states.clone(); + let txl = self.tx.clone(); + let task = topstack::get_runtime().spawn(async move { + warn!( + "[{}]: Rejecting an unbonded device's attempt to connect media", + DisplayAddress(&addr) + ); + BluetoothMedia::async_disconnect(&tasks, &states, &txl, &addr).await; + }); + guard.insert(addr, Some((task, first_conn_ts))); + } return; } } @@ -1222,39 +1255,18 @@ impl BluetoothMedia { } DeviceConnectionStates::FullyConnected => { // Rejecting the unbonded connection after we finished our profile - // reconnectinglogic to avoid a collision. - if let Some(adapter) = &self.adapter { - if BtBondState::Bonded - != adapter.lock().unwrap().get_bond_state_by_addr(&addr.to_string()) - { - warn!( - "[{}]: Rejecting a unbonded device's attempt to connect to media profiles", - DisplayAddress(&addr)); - let fallback_tasks = self.fallback_tasks.clone(); - let device_states = self.device_states.clone(); - let txl = self.tx.clone(); - let task = topstack::get_runtime().spawn(async move { - { - device_states - .lock() - .unwrap() - .insert(addr, DeviceConnectionStates::Disconnecting); - fallback_tasks.lock().unwrap().insert(addr, None); - } - - debug!( - "[{}]: Device connection state: {:?}.", - DisplayAddress(&addr), - DeviceConnectionStates::Disconnecting - ); + // reconnecting logic to avoid a collision. + if !self.is_bonded(&addr) { + warn!( + "[{}]: Rejecting a unbonded device's attempt to connect to media profiles", + DisplayAddress(&addr) + ); - let _ = txl - .send(Message::Media(MediaActions::Disconnect(addr.to_string()))) - .await; - }); - guard.insert(addr, Some((task, first_conn_ts))); - return; - } + let task = topstack::get_runtime().spawn(async move { + BluetoothMedia::async_disconnect(&tasks, &device_states, &txl, &addr).await; + }); + guard.insert(addr, Some((task, ts))); + return; } let cur_a2dp_caps = self.a2dp_caps.get(&addr); diff --git a/system/gd/rust/topshim/Android.bp b/system/gd/rust/topshim/Android.bp index 157f5dbd62..5f3e6e8f79 100644 --- a/system/gd/rust/topshim/Android.bp +++ b/system/gd/rust/topshim/Android.bp @@ -111,7 +111,7 @@ rust_bindgen { crate_name: "bt_topshim_wrapper_bindgen", source_stem: "bindings", defaults: ["bluetooth_cflags"], - cpp_std: "c++17", + c_std: "", host_supported: true, bindgen_flags: [ "--allowlist-function=bt_.*", diff --git a/system/gd/rust/topshim/facade/Android.bp b/system/gd/rust/topshim/facade/Android.bp index b18b4eb9c7..37d71e7cc2 100644 --- a/system/gd/rust/topshim/facade/Android.bp +++ b/system/gd/rust/topshim/facade/Android.bp @@ -52,7 +52,6 @@ rust_defaults { "libbt-bta-core", "libbt-common", "libbt-hci", - "libbt-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", "libbt-stack", diff --git a/system/hci/Android.bp b/system/hci/Android.bp index cf60675ee3..3212482c83 100644 --- a/system/hci/Android.bp +++ b/system/hci/Android.bp @@ -10,7 +10,7 @@ package { // HCI static library for target cc_library_static { name: "libbt-hci", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], srcs: [ "src/buffer_allocator.cc", "src/packet_fragmenter.cc", @@ -32,6 +32,9 @@ cc_library_static { "packages/modules/Bluetooth/system/stack/include", "system/libhwbinder/include", ], + apex_available: [ + "com.android.btservices", + ], host_supported: true, min_sdk_version: "Tiramisu", } @@ -42,7 +45,7 @@ cc_test { test_suites: ["device-tests"], defaults: [ "bluetooth_gtest_x86_asan_workaround", - "fluoride_basic_defaults", + "fluoride_defaults", "fluoride_test_defaults", "mts_defaults", ], diff --git a/system/include/hardware/bt_activity_attribution.h b/system/include/hardware/bt_activity_attribution.h index a9c37c4751..c8f56bc61a 100644 --- a/system/include/hardware/bt_activity_attribution.h +++ b/system/include/hardware/bt_activity_attribution.h @@ -24,51 +24,10 @@ namespace bluetooth { namespace activity_attribution { -class ActivityAttributionCallbacks { - public: - enum class Activity : uint8_t { - UNKNOWN = 0, - ACL, - ADVERTISE, - CONNECT, - CONTROL, - HFP, - ISO, - SCAN, - VENDOR, - }; - - struct BtaaAggregationEntry { - RawAddress address; - Activity activity; - uint16_t wakeup_count; - uint32_t byte_count; - uint32_t wakelock_duration; - }; - - virtual ~ActivityAttributionCallbacks() = default; - - /** Callback when Bluetooth woke up the system */ - virtual void OnWakeup(const Activity activity, const RawAddress& address) = 0; - - /** Callback when Bluetooth activity logs are ready to be moved */ - virtual void OnActivityLogsReady( - const std::vector<BtaaAggregationEntry> logs) = 0; -}; - class ActivityAttributionInterface { public: virtual ~ActivityAttributionInterface() = default; - /** Init the interface. */ - virtual void Init(void) = 0; - - /** Register JNI callbacks with the interface. */ - virtual void RegisterCallbacks(ActivityAttributionCallbacks* callbacks) = 0; - - /** Closes the interface. */ - virtual void Cleanup(void) = 0; - /** Notify the UID and package name of the app, and the address of associated * active device */ virtual void NotifyActivityAttributionInfo( diff --git a/system/main/Android.bp b/system/main/Android.bp index d84e98b03e..7db09bbab3 100644 --- a/system/main/Android.bp +++ b/system/main/Android.bp @@ -20,7 +20,7 @@ filegroup { cc_library_static { name: "libbte", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], srcs: [ ":LibBluetoothShimSources", ":LibBluetoothSources", @@ -52,8 +52,12 @@ cc_library_static { "BluetoothGeneratedDumpsysDataSchema_h", "BluetoothGeneratedPackets_h", ], + apex_available: [ + "com.android.btservices", + ], host_supported: true, min_sdk_version: "Tiramisu", + static_libs: ["libbluetooth_gd"], } cc_library { @@ -63,7 +67,7 @@ cc_library { "//packages/modules/Bluetooth:__subpackages__", "//vendor:__subpackages__", ], - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], header_libs: ["libbluetooth_headers"], export_header_lib_headers: ["libbluetooth_headers"], include_dirs: [ @@ -143,7 +147,6 @@ cc_library_static { "-DBUILDCFG", ], shared_libs: [ - "libflatbuffers-cpp", ], whole_static_libs: [ "libbluetooth_gd", // Gabeldorsche @@ -202,8 +205,8 @@ cc_test { ], static_libs: [ "libbluetooth-dumpsys", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libbtdevice", "libchrome", "libevent", diff --git a/system/main/shim/activity_attribution.cc b/system/main/shim/activity_attribution.cc index 4695309b74..12eed9de56 100644 --- a/system/main/shim/activity_attribution.cc +++ b/system/main/shim/activity_attribution.cc @@ -23,9 +23,7 @@ #include "main/shim/entry.h" #include "types/raw_address.h" -class ActivityAttributionInterfaceImpl - : public ActivityAttributionInterface, - public bluetooth::activity_attribution::ActivityAttributionCallback { +class ActivityAttributionInterfaceImpl : public ActivityAttributionInterface { public: ~ActivityAttributionInterfaceImpl() override = default; @@ -35,17 +33,6 @@ class ActivityAttributionInterfaceImpl return instance; } - void Init() override { - bluetooth::shim::GetActivityAttribution() - ->RegisterActivityAttributionCallback(this); - } - - void RegisterCallbacks(ActivityAttributionCallbacks* callbacks) override { - this->callbacks = callbacks; - } - - void Cleanup(void) override{}; - void NotifyActivityAttributionInfo( int uid, const std::string& package_name, const std::string& device_address) override { @@ -53,44 +40,12 @@ class ActivityAttributionInterfaceImpl uid, package_name, device_address); } - void OnWakeup(const Activity activity, - const bluetooth::hci::Address& address) override { - do_in_jni_thread( - FROM_HERE, base::Bind(&ActivityAttributionCallbacks::OnWakeup, - base::Unretained(callbacks), - (ActivityAttributionCallbacks::Activity)activity, - bluetooth::ToRawAddress(address))); - } - - void OnActivityLogsReady( - const std::vector<BtaaAggregationEntry> logs) override { - std::vector<ActivityAttributionCallbacks::BtaaAggregationEntry> - callback_logs; - for (auto& it : logs) { - ActivityAttributionCallbacks::BtaaAggregationEntry entry{ - bluetooth::ToRawAddress(it.address), - (ActivityAttributionCallbacks::Activity)it.activity, it.wakeup_count, - it.byte_count, it.wakelock_duration_ms}; - callback_logs.push_back(entry); - } - do_in_jni_thread( - FROM_HERE, - base::Bind(&ActivityAttributionCallbacks::OnActivityLogsReady, - base::Unretained(callbacks), callback_logs)); - } - private: // Private constructor to prevent construction. ActivityAttributionInterfaceImpl() {} - - ActivityAttributionCallbacks* callbacks; }; ActivityAttributionInterface* bluetooth::shim::get_activity_attribution_instance() { return ActivityAttributionInterfaceImpl::GetInstance(); } - -void bluetooth::shim::init_activity_attribution() { - bluetooth::shim::get_activity_attribution_instance()->Init(); -} diff --git a/system/main/shim/activity_attribution.h b/system/main/shim/activity_attribution.h index 00d8099971..0f1253415e 100644 --- a/system/main/shim/activity_attribution.h +++ b/system/main/shim/activity_attribution.h @@ -28,7 +28,5 @@ namespace shim { ActivityAttributionInterface* get_activity_attribution_instance(); -void init_activity_attribution(); - } // namespace shim } // namespace bluetooth diff --git a/system/main/shim/stack.cc b/system/main/shim/stack.cc index 40dc243024..017b954168 100644 --- a/system/main/shim/stack.cc +++ b/system/main/shim/stack.cc @@ -148,9 +148,6 @@ void Stack::StartEverything() { !common::init_flags::gd_core_is_enabled()) { L2CA_UseLegacySecurityModule(); } - if (common::init_flags::btaa_hci_is_enabled()) { - bluetooth::shim::init_activity_attribution(); - } } void Stack::Start(ModuleList* modules) { diff --git a/system/main/test/main_shim_test.cc b/system/main/test/main_shim_test.cc index fcaf32b4c5..83c6f4350f 100644 --- a/system/main/test/main_shim_test.cc +++ b/system/main/test/main_shim_test.cc @@ -345,8 +345,6 @@ class MockLeAclConnection namespace bluetooth { namespace shim { -void init_activity_attribution() {} - namespace testing { extern os::Handler* mock_handler_; diff --git a/system/osi/Android.bp b/system/osi/Android.bp index da4f9cf2e1..917fe1280a 100644 --- a/system/osi/Android.bp +++ b/system/osi/Android.bp @@ -65,7 +65,7 @@ cc_library_static { "include_internal", ], defaults: [ - "fluoride_basic_defaults", + "fluoride_defaults", "fluoride_osi_defaults", ], // TODO(mcchou): Remove socket_utils sources after platform specific @@ -159,8 +159,8 @@ cc_test { "test", ], static_libs: [ + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libc++fs", "libchrome", "libevent", diff --git a/system/osi/test/fuzzers/alarm/Android.bp b/system/osi/test/fuzzers/alarm/Android.bp index 4bcef92af9..4e09043cce 100644 --- a/system/osi/test/fuzzers/alarm/Android.bp +++ b/system/osi/test/fuzzers/alarm/Android.bp @@ -23,7 +23,6 @@ cc_fuzz { ], static_libs: [ "libbt-common", - "libbt-protos-lite", "libchrome", "libgmock", "libosi", diff --git a/system/profile/avrcp/Android.bp b/system/profile/avrcp/Android.bp index 8bb0912c73..19c5c1d3de 100644 --- a/system/profile/avrcp/Android.bp +++ b/system/profile/avrcp/Android.bp @@ -70,6 +70,7 @@ cc_test { "lib-bt-packets-avrcp", "lib-bt-packets-base", "libbase", + "libbluetooth_gd", "libbtdevice", "libchrome", "libcutils", diff --git a/system/rust/src/gatt/arbiter.rs b/system/rust/src/gatt/arbiter.rs index 52a0aa7207..66841bd977 100644 --- a/system/rust/src/gatt/arbiter.rs +++ b/system/rust/src/gatt/arbiter.rs @@ -52,6 +52,11 @@ pub fn with_arbiter<T>(f: impl FnOnce(&mut IsolationManager) -> T) -> T { f(ARBITER.read().unwrap().as_ref().expect("Rust stack is not started").lock().as_mut().unwrap()) } +/// Check if the Arbiter is initialized. +pub fn has_arbiter() -> bool { + ARBITER.read().unwrap().is_some() +} + /// Test to see if a buffer contains a valid ATT packet with an opcode we /// are interested in intercepting (those intended for servers that are isolated) fn try_parse_att_server_packet( @@ -89,6 +94,13 @@ fn on_le_connect(tcb_idx: u8, advertiser: u8) { } fn on_le_disconnect(tcb_idx: u8) { + // Disconnection events may be received after a FactoryReset + // is initiated for Bluetooth and the rust arbiter is taken + // down. + if !has_arbiter() { + return; + } + let tcb_idx = TransportIndex(tcb_idx); let was_isolated = with_arbiter(|arbiter| arbiter.is_connection_isolated(tcb_idx)); if was_isolated { diff --git a/system/stack/Android.bp b/system/stack/Android.bp index 97619c7269..197383a7ad 100644 --- a/system/stack/Android.bp +++ b/system/stack/Android.bp @@ -32,7 +32,7 @@ cc_test_library { // Bluetooth stack static library for target cc_library_static { name: "libbt-stack", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], local_include_dirs: [ "avct", "avdt", @@ -125,10 +125,10 @@ cc_library_static { "bnep/bnep_api.cc", "bnep/bnep_main.cc", "bnep/bnep_utils.cc", - "btm/hfp_msbc_decoder.cc", - "btm/hfp_msbc_encoder.cc", "btm/hfp_lc3_decoder.cc", "btm/hfp_lc3_encoder.cc", + "btm/hfp_msbc_decoder.cc", + "btm/hfp_msbc_encoder.cc", "hid/hidd_api.cc", "hid/hidd_conn.cc", "hid/hidh_api.cc", @@ -169,7 +169,7 @@ filegroup { cc_library_static { name: "libbt-stack-core", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], local_include_dirs: [ "avct", "avdt", @@ -292,6 +292,7 @@ cc_library_static { ], static_libs: [ "libbluetooth_core_rs", + "libbluetooth_gd", "libbt-hci", ], shared_libs: [ @@ -643,7 +644,7 @@ cc_test { "libz", ], static_libs: [ - "android.hardware.audio.common-V1-ndk", + "android.hardware.audio.common-V2-ndk", "android.hardware.bluetooth.a2dp@1.0", "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.bluetooth@1.0", @@ -660,7 +661,6 @@ cc_test { "libbt-bta-core", "libbt-common", "libbt-hci", - "libbt-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", "libbt-stack", @@ -738,11 +738,10 @@ cc_test { "libcutils", ], static_libs: [ + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libevent", - "libflatbuffers-cpp", "libgmock", "liblog", "libosi", @@ -816,9 +815,9 @@ cc_test { "libcutils", ], static_libs: [ + "libbluetooth_gd", "libchrome", "libevent", - "libflatbuffers-cpp", "libgmock", "liblog", "libosi", @@ -883,6 +882,7 @@ cc_test { ], static_libs: [ "libbluetooth-types", + "libbluetooth_gd", "libbt-common", "libchrome", "libevent", @@ -931,8 +931,8 @@ cc_test { "libcutils", ], static_libs: [ + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libevent", "libgmock", @@ -996,8 +996,8 @@ cc_test { "libcutils", ], static_libs: [ + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libevent", "liblog", @@ -1103,8 +1103,8 @@ cc_test { ], static_libs: [ "libFraunhoferAAC", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", "libchrome", @@ -1156,7 +1156,6 @@ cc_test { ], static_libs: [ "libbt-common", - "libbt-protos-lite", "libchrome", "liblog", "libosi", @@ -1211,8 +1210,8 @@ cc_test { "libcutils", ], static_libs: [ + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libevent", "libgmock", @@ -1318,8 +1317,8 @@ cc_test { "libcutils", ], static_libs: [ + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libchrome", "libevent", "libgmock", @@ -1417,28 +1416,28 @@ cc_test { "btm/btm_sco_hci.cc", "btm/btm_sco_hfp_hal.cc", "btm/btm_sec.cc", - "btm/hfp_msbc_decoder.cc", - "btm/hfp_msbc_encoder.cc", "btm/hfp_lc3_decoder.cc", "btm/hfp_lc3_encoder.cc", + "btm/hfp_msbc_decoder.cc", + "btm/hfp_msbc_encoder.cc", "metrics/stack_metrics_logging.cc", + "test/btm/btm_scn_test.cc", "test/btm/peer_packet_types_test.cc", "test/btm/sco_hci_test.cc", + "test/btm/sco_pkt_status_test.cc", "test/btm/stack_btm_regression_tests.cc", "test/btm/stack_btm_test.cc", - "test/btm/sco_pkt_status_test.cc", "test/common/mock_eatt.cc", "test/stack_include_test.cc", ], static_libs: [ + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", "libbtdevice", "libchrome", "libevent", - "libflatbuffers-cpp", "libgmock", "liblc3", "liblog", @@ -1486,7 +1485,6 @@ cc_test { ], static_libs: [ "libbt-common", - "libbt-protos-lite", "libbtdevice", "libbte", "libchrome", @@ -1542,7 +1540,6 @@ cc_test { ], static_libs: [ "libbt-common", - "libbt-protos-lite", "libbtdevice", "libbte", "libchrome", @@ -1613,12 +1610,11 @@ cc_test { "test/stack_btu_test.cc", ], static_libs: [ + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libbtdevice", "libchrome", "libevent", - "libflatbuffers-cpp", "libgmock", "liblog", "libosi", @@ -1695,12 +1691,11 @@ cc_test { "test/gatt/stack_gatt_test.cc", ], static_libs: [ + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libbtdevice", "libchrome", "libevent", - "libflatbuffers-cpp", "libgmock", "liblog", "libosi", @@ -1777,12 +1772,11 @@ cc_test { "test/stack_l2cap_test.cc", ], static_libs: [ + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libbtdevice", "libchrome", "libevent", - "libflatbuffers-cpp", "libgmock", "liblog", "libosi", @@ -1863,12 +1857,11 @@ cc_test { "test/stack_acl_test.cc", ], static_libs: [ + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libbtdevice", "libchrome", "libevent", - "libflatbuffers-cpp", "libgmock", "liblog", "libosi", @@ -1932,6 +1925,7 @@ cc_test { ], static_libs: [ "libbluetooth-types", + "libbluetooth_gd", "libbt-common", "libchrome", "libgmock", diff --git a/system/stack/btm/btm_int_types.h b/system/stack/btm/btm_int_types.h index 9ad5388ac6..ced48d04e3 100644 --- a/system/stack/btm/btm_int_types.h +++ b/system/stack/btm/btm_int_types.h @@ -18,6 +18,8 @@ #ifndef BTM_INT_TYPES_H #define BTM_INT_TYPES_H +#include <gtest/gtest_prod.h> + #include <cstdint> #include <memory> #include <string> @@ -396,6 +398,14 @@ typedef struct tBTM_CB { friend bool BTM_FreeSCN(uint8_t scn); uint8_t btm_scn[BTM_MAX_SCN_]; uint8_t btm_available_index; + + // give access to private method for test: + friend class BtmAllocateSCNTest; + FRIEND_TEST(BtmAllocateSCNTest, can_allocate_all_scns); + FRIEND_TEST(BtmAllocateSCNTest, only_last_scn_available); + FRIEND_TEST(BtmAllocateSCNTest, scn_available_after_available_index); + FRIEND_TEST(BtmAllocateSCNTest, scn_available_before_available_index); + FRIEND_TEST(BtmAllocateSCNTest, no_scn_available); } tBTM_CB; /* security action for L2CAP COC channels */ diff --git a/system/stack/btm/btm_scn.cc b/system/stack/btm/btm_scn.cc index feec0f5fe7..8e87ccc730 100644 --- a/system/stack/btm/btm_scn.cc +++ b/system/stack/btm/btm_scn.cc @@ -34,8 +34,11 @@ extern tBTM_CB btm_cb; uint8_t BTM_AllocateSCN(void) { BTM_TRACE_DEBUG("BTM_AllocateSCN"); - // stack reserves scn 1 for HFP, HSP we still do the correct way - for (uint8_t x = btm_cb.btm_available_index; x < PORT_MAX_RFC_PORTS; x++) { + // stack reserves scn 1 for HFP, HSP we still do the correct way. + // SCN can be allocated in the range of [1, PORT_MAX_RFC_PORTS). Since (x + 1) + // is returned, we iterate to less than PORT_MAX_RFC_PORTS - 1. + for (uint8_t x = btm_cb.btm_available_index; x < PORT_MAX_RFC_PORTS - 1; + x++) { if (!btm_cb.btm_scn[x]) { btm_cb.btm_scn[x] = true; btm_cb.btm_available_index = (x + 1); @@ -43,10 +46,10 @@ uint8_t BTM_AllocateSCN(void) { } } - // In order to avoid OOB, btm_available_index must be less than or equal to - // PORT_MAX_RFC_PORTS + // In order to avoid OOB, btm_available_index must be less than + // PORT_MAX_RFC_PORTS. btm_cb.btm_available_index = - std::min(btm_cb.btm_available_index, (uint8_t)PORT_MAX_RFC_PORTS); + std::min(btm_cb.btm_available_index, (uint8_t)(PORT_MAX_RFC_PORTS - 1)); // If there's no empty SCN from _last_index to BTM_MAX_SCN. for (uint8_t y = 1; y < btm_cb.btm_available_index; y++) { diff --git a/system/stack/btm/btm_scn.h b/system/stack/btm/btm_scn.h index fe9dcb7ad6..733173297b 100644 --- a/system/stack/btm/btm_scn.h +++ b/system/stack/btm/btm_scn.h @@ -18,6 +18,6 @@ #include <cstdint> +uint8_t BTM_AllocateSCN(void); bool BTM_FreeSCN(uint8_t scn); bool BTM_TryAllocateSCN(uint8_t scn); -bool BTM_TryAllocateSCN(uint8_t scn); diff --git a/system/stack/l2cap/l2c_csm.cc b/system/stack/l2cap/l2c_csm.cc index 32c8ab9a55..44c4c99076 100644 --- a/system/stack/l2cap/l2c_csm.cc +++ b/system/stack/l2cap/l2c_csm.cc @@ -100,9 +100,13 @@ static void l2c_csm_indicate_connection_open(tL2C_CCB* p_ccb) { if (p_ccb->connection_initiator == L2CAP_INITIATOR_LOCAL) { (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(p_ccb->local_cid, L2CAP_CONN_OK); } else { - (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb)( - p_ccb->p_lcb->remote_bd_addr, p_ccb->local_cid, p_ccb->p_rcb->psm, - p_ccb->remote_id); + if (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb) { + (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb)( + p_ccb->p_lcb->remote_bd_addr, p_ccb->local_cid, p_ccb->p_rcb->psm, + p_ccb->remote_id); + } else { + LOG_WARN("pL2CA_ConnectInd_Cb is null"); + } } if (p_ccb->chnl_state == CST_OPEN && !p_ccb->p_lcb->is_transport_ble()) { (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)( diff --git a/system/stack/test/btm/btm_scn_test.cc b/system/stack/test/btm/btm_scn_test.cc new file mode 100644 index 0000000000..38294e312d --- /dev/null +++ b/system/stack/test/btm/btm_scn_test.cc @@ -0,0 +1,91 @@ +/* + * + * Copyright 2023 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. + * + */ + +#include "stack/btm/btm_scn.h" + +#include <gtest/gtest.h> + +#include "stack/btm/btm_int_types.h" // tBTM_CB +#include "stack/include/rfcdefs.h" // PORT_MAX_RFC_PORTS + +extern tBTM_CB btm_cb; + +using testing::Test; + +class BtmAllocateSCNTest : public Test { + public: + protected: + void SetUp() override { + btm_cb.btm_available_index = 1; + for (int i = 0; i < PORT_MAX_RFC_PORTS; i++) { + btm_cb.btm_scn[i] = false; + } + } + + void TearDown() override {} +}; + +TEST_F(BtmAllocateSCNTest, scn_available_after_available_index) { + btm_cb.btm_available_index = 5; + uint8_t occupied_idx[] = {1, 2, 3, 4, 5, 6, 7}; + for (uint8_t idx : occupied_idx) { + btm_cb.btm_scn[idx] = true; + } + + uint8_t scn = BTM_AllocateSCN(); + ASSERT_EQ(scn, 9); // All indexes up to 7 are occupied; hence index 8 i.e. + // scn 9 should return +} + +TEST_F(BtmAllocateSCNTest, scn_available_before_available_index) { + btm_cb.btm_available_index = 28; + uint8_t occupied_idx[] = {26, 27, 28, 29}; + for (uint8_t idx : occupied_idx) { + btm_cb.btm_scn[idx] = true; + } + + uint8_t scn = BTM_AllocateSCN(); + ASSERT_EQ(scn, 2); // All SCN from available to 30 are occupied; hence cycle + // to beginning. +} + +TEST_F(BtmAllocateSCNTest, can_allocate_all_scns) { + for (uint8_t scn = 2; scn < PORT_MAX_RFC_PORTS; scn++) { + EXPECT_EQ(BTM_AllocateSCN(), scn); + } +} + +TEST_F(BtmAllocateSCNTest, only_last_scn_available) { + // Fill all relevants SCN except the last + for (uint8_t scn = 2; scn < PORT_MAX_RFC_PORTS - 1; scn++) { + btm_cb.btm_scn[scn - 1] = true; + } + + EXPECT_EQ(BTM_AllocateSCN(), PORT_MAX_RFC_PORTS - 1); +} + +TEST_F(BtmAllocateSCNTest, no_scn_available) { + btm_cb.btm_available_index = 2; + for (int i = 1; i < PORT_MAX_RFC_PORTS - 1; + i++) { // Fill all relevants SCN indexes (1 to 29) + btm_cb.btm_scn[i] = true; + } + + uint8_t scn = BTM_AllocateSCN(); + EXPECT_EQ(scn, 0) << "scn = " << scn << "and not 0"; +}
\ No newline at end of file diff --git a/system/stack/test/fuzzers/Android.bp b/system/stack/test/fuzzers/Android.bp index 822bc50312..d187b961ed 100644 --- a/system/stack/test/fuzzers/Android.bp +++ b/system/stack/test/fuzzers/Android.bp @@ -29,7 +29,6 @@ cc_defaults { "libbt-bta-core", "libbt-common", "libbt-hci", - "libbt-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", "libbt-stack", diff --git a/system/test/headless/Android.bp b/system/test/headless/Android.bp index aad71a9995..e1f667cc34 100644 --- a/system/test/headless/Android.bp +++ b/system/test/headless/Android.bp @@ -92,7 +92,6 @@ cc_binary { "libbt-bta-core", "libbt-common", "libbt-hci", - "libbt-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", "libbt-stack", diff --git a/system/test/mock/mock_bta_dm_act.cc b/system/test/mock/mock_bta_dm_act.cc index 0cf293fa1d..42365fbd72 100644 --- a/system/test/mock/mock_bta_dm_act.cc +++ b/system/test/mock/mock_bta_dm_act.cc @@ -80,7 +80,6 @@ struct bta_dm_free_sdp_db bta_dm_free_sdp_db; struct bta_dm_inq_cmpl bta_dm_inq_cmpl; struct bta_dm_is_search_request_queued bta_dm_is_search_request_queued; struct bta_dm_pin_reply bta_dm_pin_reply; -struct bta_dm_proc_open_evt bta_dm_proc_open_evt; struct bta_dm_process_remove_device bta_dm_process_remove_device; struct bta_dm_queue_disc bta_dm_queue_disc; struct bta_dm_queue_search bta_dm_queue_search; @@ -295,10 +294,6 @@ void bta_dm_pin_reply(std::unique_ptr<tBTA_DM_API_PIN_REPLY> msg) { inc_func_call_count(__func__); test::mock::bta_dm_act::bta_dm_pin_reply(std::move(msg)); } -void bta_dm_proc_open_evt(tBTA_GATTC_OPEN* p_data) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_proc_open_evt(p_data); -} void bta_dm_process_remove_device(const RawAddress& bd_addr) { inc_func_call_count(__func__); test::mock::bta_dm_act::bta_dm_process_remove_device(bd_addr); diff --git a/system/test/mock/mock_bta_dm_act.h b/system/test/mock/mock_bta_dm_act.h index 661a7537d5..e58a58d7c2 100644 --- a/system/test/mock/mock_bta_dm_act.h +++ b/system/test/mock/mock_bta_dm_act.h @@ -585,16 +585,6 @@ struct bta_dm_pin_reply { }; extern struct bta_dm_pin_reply bta_dm_pin_reply; -// Name: bta_dm_proc_open_evt -// Params: tBTA_GATTC_OPEN* p_data -// Return: void -struct bta_dm_proc_open_evt { - std::function<void(tBTA_GATTC_OPEN* p_data)> body{ - [](tBTA_GATTC_OPEN* p_data) {}}; - void operator()(tBTA_GATTC_OPEN* p_data) { body(p_data); }; -}; -extern struct bta_dm_proc_open_evt bta_dm_proc_open_evt; - // Name: bta_dm_process_remove_device // Params: const RawAddress& bd_addr // Return: void diff --git a/system/test/mock/mock_btif_co_bta_av_co.cc b/system/test/mock/mock_btif_co_bta_av_co.cc index 15612db986..0241237208 100644 --- a/system/test/mock/mock_btif_co_bta_av_co.cc +++ b/system/test/mock/mock_btif_co_bta_av_co.cc @@ -49,7 +49,6 @@ struct bta_av_co_audio_source_data_path bta_av_co_audio_source_data_path; struct bta_av_co_audio_start bta_av_co_audio_start; struct bta_av_co_audio_stop bta_av_co_audio_stop; struct bta_av_co_audio_update_mtu bta_av_co_audio_update_mtu; -struct bta_av_co_get_decoder_interface bta_av_co_get_decoder_interface; struct bta_av_co_get_encoder_effective_frame_size bta_av_co_get_encoder_effective_frame_size; struct bta_av_co_get_encoder_interface bta_av_co_get_encoder_interface; @@ -76,8 +75,6 @@ namespace btif_co_bta_av_co { tA2DP_STATUS bta_av_co_audio_getconfig::return_value = 0; bool bta_av_co_audio_init::return_value = false; BT_HDR* bta_av_co_audio_source_data_path::return_value = nullptr; -const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface::return_value = - nullptr; int bta_av_co_get_encoder_effective_frame_size::return_value = 0; const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface::return_value = nullptr; @@ -180,10 +177,6 @@ void bta_av_co_audio_update_mtu(tBTA_AV_HNDL bta_av_handle, test::mock::btif_co_bta_av_co::bta_av_co_audio_update_mtu(bta_av_handle, peer_address, mtu); } -const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void) { - inc_func_call_count(__func__); - return test::mock::btif_co_bta_av_co::bta_av_co_get_decoder_interface(); -} int bta_av_co_get_encoder_effective_frame_size() { inc_func_call_count(__func__); return test::mock::btif_co_bta_av_co:: diff --git a/system/test/mock/mock_btif_co_bta_av_co.h b/system/test/mock/mock_btif_co_bta_av_co.h index 9f977ce53f..c817f8359c 100644 --- a/system/test/mock/mock_btif_co_bta_av_co.h +++ b/system/test/mock/mock_btif_co_bta_av_co.h @@ -260,17 +260,6 @@ struct bta_av_co_audio_update_mtu { }; extern struct bta_av_co_audio_update_mtu bta_av_co_audio_update_mtu; -// Name: bta_av_co_get_decoder_interface -// Params: void -// Return: const tA2DP_DECODER_INTERFACE* -struct bta_av_co_get_decoder_interface { - static const tA2DP_DECODER_INTERFACE* return_value; - std::function<const tA2DP_DECODER_INTERFACE*(void)> body{ - [](void) { return return_value; }}; - const tA2DP_DECODER_INTERFACE* operator()(void) { return body(); }; -}; -extern struct bta_av_co_get_decoder_interface bta_av_co_get_decoder_interface; - // Name: bta_av_co_get_encoder_effective_frame_size // Params: // Return: int diff --git a/system/test/mock/mock_main_shim_activity_attribution.cc b/system/test/mock/mock_main_shim_activity_attribution.cc index 3b67f5aac9..83cfaa3872 100644 --- a/system/test/mock/mock_main_shim_activity_attribution.cc +++ b/system/test/mock/mock_main_shim_activity_attribution.cc @@ -36,6 +36,3 @@ bluetooth::shim::get_activity_attribution_instance() { inc_func_call_count(__func__); return nullptr; } -void bluetooth::shim::init_activity_attribution() { - inc_func_call_count(__func__); -} diff --git a/system/test/run_benchmarks.sh b/system/test/run_benchmarks.sh deleted file mode 100755 index 3ca1d0999b..0000000000 --- a/system/test/run_benchmarks.sh +++ /dev/null @@ -1,129 +0,0 @@ -#!/bin/sh -# A utility script that runs benchmark on Android device -# -# Note: Only one Android device can be connected when running this script -# -# Example usage: -# $ cd packages/modules/Bluetooth/system -# $ ./test/run_benchmarks.sh bluetooth_benchmark_example - -known_benchmarks=( - bluetooth_benchmark_thread_performance - bluetooth_benchmark_timer_performance -) - -usage() { - binary="$(basename "$0")" - echo "Usage: ${binary} --help" - echo " ${binary} [-i <iterations>] [-s <specific device>] [--all] [<benchmark name>[.<filter>] ...] [--<arg> ...]" - echo - echo "Unknown long arguments are passed to the benchmark." - echo - echo "Known benchmark names:" - - for name in "${known_benchmarks[@]}" - do - echo " ${name}" - done -} - -iterations=1 -device= -benchmarks=() -benchmark_args=() -while [ $# -gt 0 ] -do - case "$1" in - -h|--help) - usage - exit 0 - ;; - -i) - shift - if [ $# -eq 0 ]; then - echo "error: number of iterations expected" 1>&2 - usage - exit 2 - fi - iterations=$(( $1 )) - shift - ;; - -s) - shift - if [ $# -eq 0 ]; then - echo "error: no device specified" 1>&2 - usage - exit 2 - fi - device="$1" - shift - ;; - --all) - benchmarks+=( "${known_benchmarks[@]}" ) - shift - ;; - --*) - benchmark_args+=( "$1" ) - shift - ;; - *) - benchmarks+=( "$1" ) - shift - ;; - esac -done - -if [ "${#benchmarks[@]}" -eq 0 ]; then - benchmarks+=( "${known_benchmarks[@]}" ) -fi - -adb=( "adb" ) -if [ -n "${device}" ]; then - adb+=( "-s" "${device}" ) -fi - -source ${ANDROID_BUILD_TOP}/build/envsetup.sh -target_arch=$(gettargetarch) - -failed_benchmarks=() -for spec in "${benchmarks[@]}" -do - name="${spec%%.*}" - if [[ $target_arch == *"64"* ]]; then - binary="/data/benchmarktest64/${name}/${name}" - else - binary="/data/benchmarktest/${name}/${name}" - fi - - push_command=( "${adb[@]}" push {"${ANDROID_PRODUCT_OUT}",}"${binary}" ) - benchmark_command=( "${adb[@]}" shell "${binary}" ) - if [ "${name}" != "${spec}" ]; then - filter="${spec#*.}" - benchmark_command+=( "--benchmark_filter=${filter}" ) - fi - benchmark_command+=( "${benchmark_args[@]}" ) - - echo "--- ${name} ---" - echo "pushing..." - "${push_command[@]}" - echo "running..." - failed_count=0 - for i in $(seq 1 ${iterations}) - do - "${benchmark_command[@]}" || failed_count=$(( $failed_count + 1 )) - done - - if [ $failed_count != 0 ]; then - failed_benchmarks+=( "${name} ${failed_count}/${iterations}" ) - fi -done - -if [ "${#failed_benchmarks[@]}" -ne 0 ]; then - for failed_benchmark in "${failed_benchmarks[@]}" - do - echo "!!! FAILED TEST: ${failed_benchmark} !!!" - done - exit 1 -fi - -exit 0 diff --git a/system/test/run_host_unit_tests.py b/system/test/run_host_unit_tests.py deleted file mode 100755 index 5f70325fae..0000000000 --- a/system/test/run_host_unit_tests.py +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2017, 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. -import sys -import subprocess -import os -import argparse - -# Registered host based unit tests -# Must have 'host_supported: true' -HOST_TESTS = [ - 'bluetooth_test_common', - 'bluetoothtbd_test', - 'net_test_avrcp', - 'net_test_btcore', - 'net_test_types', - 'net_test_btm_iso', - 'net_test_btpackets', -] - -SOONG_UI_BASH = 'build/soong/soong_ui.bash' - - -def str2bool(argument, default=False): - """ Convert a string to a booleen value. """ - argument = str(argument) - if argument.lower() in ['0', 'f', 'false', 'off', 'no', 'n']: - return False - elif argument.lower() in ['1', 't', 'true', 'on', 'yes', 'y']: - return True - return default - - -def check_dir_exists(dir, dirname): - if not os.path.isdir(dir): - print "Couldn't find %s (%s)!" % (dirname, dir) - sys.exit(0) - - -def get_output_from_command(cmd): - try: - return subprocess.check_output(cmd).strip() - except subprocess.CalledProcessError as e: - print 'Failed to call {cmd}, return code {code}'.format(cmd=cmd, code=e.returncode) - print e - return None - - -def get_android_root_or_die(): - value = os.environ.get('ANDROID_BUILD_TOP') - if not value: - # Try to find build/soong/soong_ui.bash upwards until root directory - current_path = os.path.abspath(os.getcwd()) - while current_path and os.path.isdir(current_path): - soong_ui_bash_path = os.path.join(current_path, SOONG_UI_BASH) - if os.path.isfile(soong_ui_bash_path): - # Use value returned from Soong UI instead in case definition to TOP - # changes in the future - value = get_output_from_command((soong_ui_bash_path, '--dumpvar-mode', '--abs', 'TOP')) - break - parent_path = os.path.abspath(os.path.join(current_path, os.pardir)) - if parent_path == current_path: - current_path = None - else: - current_path = parent_path - if not value: - print 'Cannot determine ANDROID_BUILD_TOP' - sys.exit(1) - check_dir_exists(value, '$ANDROID_BUILD_TOP') - return value - - -def get_android_host_out_or_die(): - value = os.environ.get('ANDROID_HOST_OUT') - if not value: - ANDROID_BUILD_TOP = get_android_root_or_die() - value = get_output_from_command((os.path.join(ANDROID_BUILD_TOP, SOONG_UI_BASH), '--dumpvar-mode', '--abs', - 'HOST_OUT')) - if not value: - print 'Cannot determine ANDROID_HOST_OUT' - sys.exit(1) - check_dir_exists(value, '$ANDROID_HOST_OUT') - return value - - -def get_android_dist_dir_or_die(): - # Check if $DIST_DIR is predefined as environment variable - value = os.environ.get('DIST_DIR') - if not value: - # If not use the default path - ANDROID_BUILD_TOP = get_android_root_or_die() - value = os.path.join(os.path.join(ANDROID_BUILD_TOP, 'out'), 'dist') - if not os.path.isdir(value): - if os.path.exists(value): - print '%s is not a directory!' % (value) - sys.exit(1) - os.makedirs(value) - return value - - -def get_native_test_root_or_die(): - android_host_out = get_android_host_out_or_die() - test_root = os.path.join(android_host_out, 'nativetest64') - if not os.path.isdir(test_root): - test_root = os.path.join(android_host_out, 'nativetest') - if not os.path.isdir(test_root): - print 'Neither nativetest64 nor nativetest directory exist,' \ - ' please compile first' - sys.exit(1) - return test_root - - -def get_test_cmd_or_die(test_root, test_name, enable_xml, test_filter): - test_path = os.path.join(os.path.join(test_root, test_name), test_name) - if not os.path.isfile(test_path): - print 'Cannot find: ' + test_path - sys.exit(1) - cmd = [test_path] - if enable_xml: - dist_dir = get_android_dist_dir_or_die() - log_output_path = os.path.join(dist_dir, 'gtest/{0}_test_details.xml'.format(test_name)) - cmd.append('--gtest_output=xml:{0}'.format(log_output_path)) - if test_filter: - cmd.append('--gtest_filter=%s' % test_filter) - return cmd - - -# path is relative to Android build top -def build_target(target, num_tasks): - ANDROID_BUILD_TOP = get_android_root_or_die() - build_cmd = [SOONG_UI_BASH, '--make-mode'] - if num_tasks > 1: - build_cmd.append('-j' + str(num_tasks)) - build_cmd.append(target) - p = subprocess.Popen(build_cmd, cwd=ANDROID_BUILD_TOP, env=os.environ.copy()) - return_code = p.wait() - if return_code != 0: - print 'BUILD FAILED, return code: {0}'.format(str(return_code)) - sys.exit(1) - return - - -def main(): - """ run_host_unit_tests.py - Run registered host based unit tests - """ - parser = argparse.ArgumentParser(description='Run host based unit tests.') - parser.add_argument( - '--enable_xml', - type=str2bool, - dest='enable_xml', - nargs='?', - const=True, - default=False, - help='Whether to output structured XML log output in out/dist/gtest directory') - parser.add_argument( - '-j', - type=int, - nargs='?', - dest='num_tasks', - const=-1, - default=-1, - help='Number of tasks to run at the same time') - parser.add_argument( - 'rest', nargs=argparse.REMAINDER, help='-- args, other gtest arguments for each individual test') - args = parser.parse_args() - - build_target('MODULES-IN-system-bt', args.num_tasks) - TEST_ROOT = get_native_test_root_or_die() - test_results = [] - for test in HOST_TESTS: - test_cmd = get_test_cmd_or_die(TEST_ROOT, test, args.enable_xml, args.rest) - if subprocess.call(test_cmd) != 0: - test_results.append(False) - else: - test_results.append(True) - if not all(test_results): - failures = [i for i, x in enumerate(test_results) if not x] - for index in failures: - print 'TEST FAILLED: ' + HOST_TESTS[index] - sys.exit(0) - print 'TEST PASSED ' + str(len(test_results)) + ' tests were run' - - dist_dir = get_android_dist_dir_or_die() - log_output_path = os.path.join(dist_dir, 'gtest/coverage') - cmd_path = os.path.join(get_android_root_or_die(), 'packages/modules/Bluetooth/system/test') - print cmd_path - cmd = [ - os.path.join(cmd_path, 'gen_coverage.py'), - '--skip-html', - '--json-file', - '-o', - log_output_path, - ] - subprocess.call(cmd) - - sys.exit(0) - - -if __name__ == '__main__': - main() diff --git a/system/test/run_unit_tests.sh b/system/test/run_unit_tests.sh deleted file mode 100755 index 41c6016d2d..0000000000 --- a/system/test/run_unit_tests.sh +++ /dev/null @@ -1,161 +0,0 @@ -#!/bin/sh - -known_tests=( - audio_bluetooth_hw_test - bluetooth-test-audio-hal-interface - bluetooth_test_common - bluetoothtbd_test - net_test_audio_a2dp_hw - net_test_avrcp - net_test_bluetooth - net_test_btcore - net_test_bta - net_test_bta_security - net_test_btif - net_test_btif_profile_queue - net_test_btif_avrcp_audio_track - net_test_btif_config_cache - net_test_device - net_test_device_iot_config - net_test_eatt - net_test_hci - net_test_stack - net_test_stack_ad_parser - net_test_stack_smp - net_test_types - net_test_osi - net_test_performance - net_test_stack_rfcomm - net_test_gatt_conn_multiplexing -) - -known_remote_tests=( - net_test_rfcomm_suite -) - - -usage() { - binary="$(basename "$0")" - echo "Usage: ${binary} --help" - echo " ${binary} [-i <iterations>] [-s <specific device>] [--all] [<test name>[.<filter>] ...] [--<arg> ...]" - echo - echo "Unknown long arguments are passed to the test." - echo - echo "Known test names:" - - for name in "${known_tests[@]}" - do - echo " ${name}" - done - - echo - echo "Known tests that need a remote device:" - for name in "${known_remote_tests[@]}" - do - echo " ${name}" - done -} - -iterations=1 -device= -tests=() -test_args=() -while [ $# -gt 0 ] -do - case "$1" in - -h|--help) - usage - exit 0 - ;; - -i) - shift - if [ $# -eq 0 ]; then - echo "error: number of iterations expected" 1>&2 - usage - exit 2 - fi - iterations=$(( $1 )) - shift - ;; - -s) - shift - if [ $# -eq 0 ]; then - echo "error: no device specified" 1>&2 - usage - exit 2 - fi - device="$1" - shift - ;; - --all) - tests+=( "${known_tests[@]}" ) - shift - ;; - --*) - test_args+=( "$1" ) - shift - ;; - *) - tests+=( "$1" ) - shift - ;; - esac -done - -if [ "${#tests[@]}" -eq 0 ]; then - tests+=( "${known_tests[@]}" ) -fi - -adb=( "adb" ) -if [ -n "${device}" ]; then - adb+=( "-s" "${device}" ) -fi - -source ${ANDROID_BUILD_TOP}/build/envsetup.sh -target_arch=$(gettargetarch) - -failed_tests=() -for spec in "${tests[@]}" -do - name="${spec%%.*}" - if [[ $target_arch == *"64"* ]]; then - binary="/data/nativetest64/${name}/${name}" - if [ -e "${ANDROID_PRODUCT_OUT}${binary}64" ]; then - binary="/data/nativetest64/${name}/${name}64" - fi - else - binary="/data/nativetest/${name}/${name}" - fi - - push_command=( "${adb[@]}" push {"${ANDROID_PRODUCT_OUT}",}"${binary}" ) - test_command=( "${adb[@]}" shell "${binary}" ) - if [ "${name}" != "${spec}" ]; then - filter="${spec#*.}" - test_command+=( "--gtest_filter=${filter}" ) - fi - test_command+=( "${test_args[@]}" ) - - echo "--- ${name} ---" - echo "pushing..." - "${push_command[@]}" - echo "running..." - failed_count=0 - for i in $(seq 1 ${iterations}) - do - "${test_command[@]}" || failed_count=$(( $failed_count + 1 )) - done - - if [ $failed_count != 0 ]; then - failed_tests+=( "${name} ${failed_count}/${iterations}" ) - fi -done - -if [ "${#failed_tests[@]}" -ne 0 ]; then - for failed_test in "${failed_tests[@]}" - do - echo "!!! FAILED TEST: ${failed_test} !!!" - done - exit 1 -fi - -exit 0 diff --git a/system/test/suite/Android.bp b/system/test/suite/Android.bp index 29fe4ecc35..57988a356b 100644 --- a/system/test/suite/Android.bp +++ b/system/test/suite/Android.bp @@ -117,13 +117,14 @@ cc_test { "gatt/gatt_unittest.cc", ], static_libs: [ - "android.hardware.audio.common-V1-ndk", + "android.hardware.audio.common-V2-ndk", "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.bluetooth@1.0", "android.hardware.bluetooth@1.1", "android.hardware.common-V2-ndk", "android.hardware.common.fmq-V1-ndk", "android.media.audio.common.types-V2-ndk", + "libbluetooth_gd", "libchrome", "libevent", ], diff --git a/system/tools/Android.mk.disabled b/system/tools/Android.mk.disabled deleted file mode 100644 index 5053e7d643..0000000000 --- a/system/tools/Android.mk.disabled +++ /dev/null @@ -1 +0,0 @@ -include $(call all-subdir-makefiles) diff --git a/system/tools/bdtool/Android.mk.disabled b/system/tools/bdtool/Android.mk.disabled deleted file mode 100644 index 76b8dceb1a..0000000000 --- a/system/tools/bdtool/Android.mk.disabled +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright 2014 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. -# - -LOCAL_PATH := $(call my-dir) - -# Bluetooth tools for target -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := net_bdtool - -LOCAL_SRC_FILES := \ - adapter.c \ - bdtool.c \ - ../../test/suite/support/callbacks.c \ - ../../test/suite/support/gatt.c \ - ../../test/suite/support/hal.c \ - ../../test/suite/support/pan.c - -LOCAL_STATIC_LIBRARIES := \ - libbtcore \ - libosi - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/../../test/suite \ - $(LOCAL_PATH)/../.. - -LOCAL_SHARED_LIBRARIES := \ - libhardware liblog - -LOCAL_CFLAGS += $(bluetooth_CFLAGS) -LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS) -LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS) - -include $(BUILD_EXECUTABLE) diff --git a/system/tools/bdtool/adapter.c b/system/tools/bdtool/adapter.c deleted file mode 100644 index 3b964a0f78..0000000000 --- a/system/tools/bdtool/adapter.c +++ /dev/null @@ -1,276 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 Google, Inc. - * - * 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. - * - ******************************************************************************/ - -#include "support/adapter.h" - -#include "base.h" -#include "btcore/include/property.h" -#include "support/callbacks.h" -#include "types/bluetooth/uuid.h" -#include "types/raw_address.h" - -static bt_state_t state; -static int property_count = 0; -static bt_property_t* properties = NULL; -static bt_discovery_state_t discovery_state; -static bt_acl_state_t acl_state; -static bt_bond_state_t bond_state; - -static void parse_properties(int num_properties, bt_property_t* property); - -// Returns the current adapter state. -bt_state_t adapter_get_state() { return state; } - -// Returns the number of adapter properties. -int adapter_get_property_count() { return property_count; } - -// Returns the specified property. -bt_property_t* adapter_get_property(bt_property_type_t type) { - for (int i = 0; i < property_count; ++i) { - if (properties[i].type == type) { - return &properties[i]; - } - } - - return NULL; -} - -// Returns the device discovery state. -bt_discovery_state_t adapter_get_discovery_state() { return discovery_state; } - -// Returns the device acl state. -bt_acl_state_t adapter_get_acl_state() { return acl_state; } - -// Returns the device bond state. -bt_bond_state_t adapter_get_bond_state() { return bond_state; } - -// callback -void acl_state_changed(bt_status_t status, RawAddress* remote_bd_addr, - bt_acl_state_t state) { - acl_state = state; - CALLBACK_RET(); -} - -// callback -void adapter_properties(bt_status_t status, int num_properties, - bt_property_t* new_properties) { - property_free_array(properties, property_count); - properties = property_copy_array(new_properties, num_properties); - property_count = num_properties; - - CALLBACK_RET(); -} - -// callback -void adapter_state_changed(bt_state_t new_state) { - state = new_state; - CALLBACK_RET(); -} - -// callback -void bond_state_changed(bt_status_t status, RawAddress* bdaddr, - bt_bond_state_t state) { - char buf[18]; - bond_state = state; - - const char* state_name = "Bond state unknown"; - switch (bond_state) { - case BT_BOND_STATE_NONE: - state_name = "Bond state none"; - break; - - case BT_BOND_STATE_BONDING: - state_name = "Bond state bonding"; - break; - - case BT_BOND_STATE_BONDED: - state_name = "Bond state bonded"; - break; - - // default none - } - fprintf(stdout, "Bond state changed callback addr:%s state:%s\n", - bdaddr_to_string(bdaddr, buf, sizeof(buf)), state_name); - - CALLBACK_RET(); -} - -// callback -void device_found(int num_properties, bt_property_t* property) { - fprintf(stdout, "Device found num_properties:%d\n", num_properties); - parse_properties(num_properties, property); - - CALLBACK_RET(); -} - -// callback -void discovery_state_changed(bt_discovery_state_t state) { - const char* state_name = "Unknown"; - discovery_state = state; - - switch (discovery_state) { - case BT_DISCOVERY_STOPPED: - state_name = "Discovery stopped"; - break; - - case BT_DISCOVERY_STARTED: - state_name = "Discovery started"; - break; - - // default omitted - } - fprintf(stdout, "Discover state %s\n", state_name); - - CALLBACK_RET(); -} - -// callback -void remote_device_properties(bt_status_t status, RawAddress* bdaddr, - int num_properties, bt_property_t* properties) { - char buf[18]; - fprintf(stdout, "Device found bdaddr:%s num_properties:%d\n", - bdaddr_to_string(bdaddr, buf, sizeof(buf)), num_properties); - - parse_properties(num_properties, properties); - - CALLBACK_RET(); -} - -// callback -void ssp_request(RawAddress* remote_bd_addr, bt_bdname_t* bd_name, uint32_t cod, - bt_ssp_variant_t pairing_variant, uint32_t pass_key) { - char* pairing_variant_name = "Unknown"; - - switch (pairing_variant) { - case BT_SSP_VARIANT_PASSKEY_CONFIRMATION: - pairing_variant_name = "Passkey confirmation"; - break; - case BT_SSP_VARIANT_PASSKEY_ENTRY: - pairing_variant_name = "Passkey entry"; - break; - - case BT_SSP_VARIANT_CONSENT: - pairing_variant_name = "Passkey consent"; - break; - - case BT_SSP_VARIANT_PASSKEY_NOTIFICATION: - pairing_variant_name = "Passkey notification"; - break; - } - - fprintf(stdout, - "Got ssp request device_class:%u passkey:%x pairing_variant:%s\n", - cod, pass_key, pairing_variant_name); - char buf[18]; - fprintf(stdout, "Device found:%s %s\n", - bdaddr_to_string(remote_bd_addr, buf, sizeof(buf)), bd_name->name); - - fprintf(stdout, "auto-accepting bond\n"); - bool accept = true; - int rc = bt_interface->ssp_reply(remote_bd_addr, pairing_variant, - (uint8_t)accept, pass_key); - CALLBACK_RET(); -} - -// callback -void thread_evt(bt_cb_thread_evt evt) { CALLBACK_RET(); } - -static void parse_properties(int num_properties, bt_property_t* property) { - while (num_properties-- > 0) { - switch (property->type) { - case BT_PROPERTY_BDNAME: { - const bt_bdname_t* name = property_as_name(property); - if (name) fprintf(stdout, " name:%s\n", name->name); - } break; - - case BT_PROPERTY_BDADDR: { - char buf[18]; - const RawAddress* addr = property_as_addr(property); - if (addr) - fprintf(stdout, " addr:%s\n", - bdaddr_to_string(addr, buf, sizeof(buf))); - } break; - - case BT_PROPERTY_UUIDS: { - size_t num_uuid; - const Uuid* uuid = property_as_uuids(property, &num_uuid); - if (uuid) { - for (size_t i = 0; i < num_uuid; i++) { - fprintf(stdout, " uuid:%zd: ", i); - for (size_t j = 0; j < sizeof(uuid); j++) { - fprintf(stdout, "%02x", uuid->uu[j]); - } - fprintf(stdout, "\n"); - } - } - } break; - - case BT_PROPERTY_TYPE_OF_DEVICE: { - bt_device_type_t device_type = property_as_device_type(property); - if (device_type) { - const struct { - const char* device_type; - } device_type_lookup[] = { - {"Unknown"}, - {"Classic Only"}, - {"BLE Only"}, - {"Both Classic and BLE"}, - }; - int idx = (int)device_type; - if (idx > BT_DEVICE_DEVTYPE_DUAL) idx = 0; - fprintf(stdout, " device_type:%s\n", - device_type_lookup[idx].device_type); - } - } break; - - case BT_PROPERTY_CLASS_OF_DEVICE: { - const bt_device_class_t* dc = property_as_device_class(property); - int dc_int = device_class_to_int(dc); - fprintf(stdout, " device_class:0x%x\n", dc_int); - } break; - - case BT_PROPERTY_REMOTE_RSSI: { - int8_t rssi = property_as_rssi(property); - fprintf(stdout, " rssi:%d\n", rssi); - } break; - - case BT_PROPERTY_REMOTE_FRIENDLY_NAME: { - const bt_bdname_t* name = property_as_name(property); - if (name) fprintf(stdout, " remote_name:%s\n", name->name); - } break; - - case BT_PROPERTY_SERVICE_RECORD: - case BT_PROPERTY_ADAPTER_SCAN_MODE: - case BT_PROPERTY_ADAPTER_BONDED_DEVICES: - case BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT: - case BT_PROPERTY_REMOTE_VERSION_INFO: - case BT_PROPERTY_LOCAL_LE_FEATURES: - case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP: - default: { - fprintf(stderr, "Unhandled property type:%d len:%d\n", property->type, - property->len); - uint8_t* p = (uint8_t*)property->val; - for (int i = 0; i < property->len; ++i, p++) { - fprintf(stderr, " %02x", *p); - } - if (property->len != 0) fprintf(stderr, "\n"); - } - } - property++; - } -} diff --git a/system/tools/bdtool/bdtool.c b/system/tools/bdtool/bdtool.c deleted file mode 100644 index 07970a7744..0000000000 --- a/system/tools/bdtool/bdtool.c +++ /dev/null @@ -1,362 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 Google, Inc. - * - * 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. - * - ******************************************************************************/ - -#include <getopt.h> -#include <signal.h> -#include <stdlib.h> -#include <unistd.h> - -#include "btcore/include/property.h" -#include "osi/include/osi.h" -#include "test/suite/support/callbacks.h" -#include "test/suite/support/hal.h" -#include "types/bluetooth/uuid.h" -#include "types/raw_address.h" - -static const Uuid HFP_UUID = - Uuid::From128BitBE({{0x00, 0x00, 0x11, 0x1E, 0x00, 0x00, 0x10, 0x00, 0x80, - 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}}); -static const Uuid HFP_AG_UUID = - Uuid::From128BitBE({{0x00, 0x00, 0x11, 0x1F, 0x00, 0x00, 0x10, 0x00, 0x80, - 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}}); - -const bt_interface_t* bt_interface; - -RawAddress bt_remote_bdaddr; - -static int f_verbose; -static bool discover = false; -static bool discoverable = false; -static bool bond = false; -static bool up = false; -static bool get_name = false; -static bool set_name = false; -static bool sco_listen = false; -static bool sco_connect = false; - -static int timeout_in_sec = 30; -static char* bd_name; - -static struct option long_options[] = { - {"bdaddr", required_argument, 0, 0}, {"discover", no_argument, 0, 0}, - {"discoverable", no_argument, 0, 0}, {"time", required_argument, 0, 0}, - {"bond", no_argument, 0, 0}, {"up", no_argument, 0, 0}, - {"verbose", no_argument, 0, 0}, {"get_name", no_argument, 0, 0}, - {"set_name", required_argument, 0, 0}, {"sco_listen", no_argument, 0, 0}, - {"sco_connect", no_argument, 0, 0}, {0, 0, 0, 0}}; - -static void usage(const char* name); -static bool parse_args(int argc, char** argv); -static void sig_handler(int signo); - -bt_property_t* adapter_get_property(bt_property_type_t type); - -int main(int argc, char** argv) { - if (!parse_args(argc, argv)) { - usage(argv[0]); - } - - if (bond && discoverable) { - fprintf(stderr, "Can only select either bond or discoverable, not both\n"); - usage(argv[0]); - } - - if (sco_listen && sco_connect) { - fprintf(stderr, - "Can only select either sco_listen or sco_connect, not both\n"); - usage(argv[0]); - } - - if (!bond && !discover && !discoverable && !up && !get_name && !set_name && - !sco_listen && !sco_connect) { - fprintf(stderr, "Must specify one command\n"); - usage(argv[0]); - } - - if (signal(SIGINT, sig_handler) == SIG_ERR) { - fprintf(stderr, "Will be unable to catch signals\n"); - } - - fprintf(stdout, "Bringing up bluetooth adapter\n"); - if (!hal_open(callbacks_get_adapter_struct())) { - fprintf(stderr, "Unable to open Bluetooth HAL.\n"); - return 1; - } - - if (discover) { - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - fprintf(stdout, "Starting to start discovery\n"); - CALL_AND_WAIT(bt_interface->start_discovery(), discovery_state_changed); - fprintf(stdout, "Started discovery for %d seconds\n", timeout_in_sec); - - sleep(timeout_in_sec); - - fprintf(stdout, "Starting to cancel discovery\n"); - CALL_AND_WAIT(bt_interface->cancel_discovery(), discovery_state_changed); - fprintf(stdout, "Cancelled discovery after %d seconds\n", timeout_in_sec); - } - - if (discoverable) { - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - bt_property_t* property = - property_new_scan_mode(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE); - - int rc = bt_interface->set_adapter_property(property); - fprintf(stdout, "Set rc:%d device as discoverable for %d seconds\n", rc, - timeout_in_sec); - - sleep(timeout_in_sec); - - property_free(property); - } - - if (bond) { - if (bdaddr_is_empty(&bt_remote_bdaddr)) { - fprintf(stderr, - "Must specify a remote device address [ " - "--bdaddr=xx:yy:zz:aa:bb:cc ]\n"); - exit(1); - } - - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - int rc = bt_interface->create_bond( - &bt_remote_bdaddr, 0 /* UNKNOWN; Currently not documented :( */); - fprintf(stdout, "Started bonding:%d for %d seconds\n", rc, timeout_in_sec); - - sleep(timeout_in_sec); - } - - if (up) { - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - fprintf(stdout, "Waiting for %d seconds\n", timeout_in_sec); - sleep(timeout_in_sec); - } - - if (get_name) { - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - int error; - CALL_AND_WAIT( - error = bt_interface->get_adapter_property(BT_PROPERTY_BDNAME), - adapter_properties); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to get adapter property\n"); - exit(1); - } - bt_property_t* property = adapter_get_property(BT_PROPERTY_BDNAME); - const bt_bdname_t* name = property_as_name(property); - if (name) - printf("Queried bluetooth device name:%s\n", name->name); - else - printf("No name\n"); - } - - if (set_name) { - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - bt_property_t* property = property_new_name(bd_name); - printf("Setting bluetooth device name to:%s\n", bd_name); - int error; - CALL_AND_WAIT(error = bt_interface->set_adapter_property(property), - adapter_properties); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to set adapter property\n"); - exit(1); - } - CALL_AND_WAIT( - error = bt_interface->get_adapter_property(BT_PROPERTY_BDNAME), - adapter_properties); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to get adapter property\n"); - exit(1); - } - property_free(property); - sleep(timeout_in_sec); - } - - const int app_uid = 0; - - if (sco_listen) { - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - bt_property_t* property = - property_new_scan_mode(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE); - CALL_AND_WAIT(bt_interface->set_adapter_property(property), - adapter_properties); - property_free(property); - - const btsock_interface_t* sock = - bt_interface->get_profile_interface(BT_PROFILE_SOCKETS_ID); - - int rfcomm_fd = INVALID_FD; - int error = - sock->listen(BTSOCK_RFCOMM, "meow", (const uint8_t*)&HFP_AG_UUID, 0, - &rfcomm_fd, 0, app_uid); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to listen for incoming RFCOMM socket: %d\n", - error); - exit(1); - } - - int sock_fd = INVALID_FD; - error = sock->listen(BTSOCK_SCO, NULL, NULL, 5, &sock_fd, 0, app_uid); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to listen for incoming SCO sockets: %d\n", error); - exit(1); - } - fprintf(stdout, "Waiting for incoming SCO connections...\n"); - sleep(timeout_in_sec); - } - - if (sco_connect) { - if (bdaddr_is_empty(&bt_remote_bdaddr)) { - fprintf(stderr, - "Must specify a remote device address [ " - "--bdaddr=xx:yy:zz:aa:bb:cc ]\n"); - exit(1); - } - - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - const btsock_interface_t* sock = - bt_interface->get_profile_interface(BT_PROFILE_SOCKETS_ID); - - int rfcomm_fd = INVALID_FD; - int error = - sock->connect(&bt_remote_bdaddr, BTSOCK_RFCOMM, - (const uint8_t*)&HFP_AG_UUID, 0, &rfcomm_fd, 0, app_uid); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to connect to RFCOMM socket: %d.\n", error); - exit(1); - } - - WAIT(acl_state_changed); - - fprintf(stdout, "Establishing SCO connection...\n"); - - int sock_fd = INVALID_FD; - error = sock->connect(&bt_remote_bdaddr, BTSOCK_SCO, NULL, 5, &sock_fd, 0, - app_uid); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to connect to SCO socket: %d.\n", error); - exit(1); - } - sleep(timeout_in_sec); - } - - CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed); - fprintf(stdout, "BT adapter is down\n"); -} - -static void sig_handler(int signo) { - if (signo == SIGINT) { - fprintf(stderr, "Received SIGINT\n"); - CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed); - fprintf(stderr, "BT adapter is down\n"); - exit(1); - } -} - -static void usage(const char* name) { - fprintf(stderr, - "Usage: %s " - "[--bond|--discover|--discoverable|--up|--sco_listen|--sco_connect] " - "[--bdaddr=<bdaddr>] [--time=<time_in_sec>] --verbose\n", - name); - fprintf(stderr, " bond: Discover actively advertising devices\n"); - fprintf(stderr, " discover: Discover actively advertising devices\n"); - fprintf(stderr, - " discoverable: Set into a connectable and discoverable mode\n"); - fprintf(stderr, " up: Only bring up stack\n"); - fprintf(stderr, " sco_listen: Listen for incoming SCO connections\n"); - fprintf(stderr, - " sco_connect: Establish a SCO connection with another device\n"); - fprintf(stderr, " time: Time to hold in the specified mode\n"); - exit(1); -} - -static bool parse_args(int argc, char** argv) { - while (1) { - int option_index = 0; - int c = getopt_long_only(argc, argv, "", long_options, &option_index); - if (c != 0) break; - - switch (c) { - case 0: - if (option_index == 0) { - if (!string_to_bdaddr(optarg, &bt_remote_bdaddr)) { - return false; - } - } - if (option_index == 1) { - discover = true; - } - if (option_index == 2) { - discoverable = true; - } - if (option_index == 3) { - timeout_in_sec = atoi(optarg); - } - if (option_index == 4) { - bond = true; - } - if (option_index == 5) { - up = true; - } - if (option_index == 6) { - f_verbose++; - } - if (option_index == 7) { - get_name = true; - } - if (option_index == 8) { - bd_name = (char*)optarg; - set_name = true; - } - if (option_index == 9) { - sco_listen = true; - } - if (option_index == 10) { - sco_connect = true; - } - break; - - default: - fprintf(stderr, "?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) { - fprintf(stderr, "non-option ARGV-elements: "); - while (optind < argc) fprintf(stderr, "%s ", argv[optind++]); - fprintf(stderr, "\n"); - return false; - } - return true; -} diff --git a/system/tools/hci/Android.mk.disabled b/system/tools/hci/Android.mk.disabled deleted file mode 100644 index 9244f45a9d..0000000000 --- a/system/tools/hci/Android.mk.disabled +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright 2014 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. -# - -LOCAL_PATH := $(call my-dir) - -# Bluetooth HCI tools for target -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := net_hci - -LOCAL_SRC_FILES := main.c -LOCAL_STATIC_LIBRARIES := libosi -LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../ - -LOCAL_CFLAGS += $(bluetooth_CFLAGS) -LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS) -LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS) - -include $(BUILD_EXECUTABLE) diff --git a/system/tools/hci/main.c b/system/tools/hci/main.c deleted file mode 100644 index 093af6bb3a..0000000000 --- a/system/tools/hci/main.c +++ /dev/null @@ -1,216 +0,0 @@ -#include <hardware/bluetooth.h> -#include <netinet/in.h> -#include <stdio.h> -#include <string.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <unistd.h> - -#include "osi/include/osi.h" - -typedef int (*handler_t)(int argc, char** argv); - -typedef enum { - HCI_PACKET_COMMAND = 1, - HCI_PACKET_ACL_DATA = 2, - HCI_PACKET_SCO_DATA = 3, - HCI_PACKET_EVENT = 4, - HCI_PACKET_ISO = 5, -} hci_packet_t; - -typedef struct { - const char* name; - const char* help; - handler_t handler; -} command_t; - -static int help(int argc, char** argv); -static int set_discoverable(int argc, char** argv); -static int set_name(int argc, char** argv); -static int set_pcm_loopback(int argc, char** argv); -static int set_sco_route(int argc, char** argv); - -static bool write_hci_command(hci_packet_t type, const void* packet, - size_t length); -static const command_t* find_command(const char* name); -static void usage(const char* name); - -static const command_t commands[] = { - {"help", "<command> - shows help text for <command>.", help}, - {"setDiscoverable", - "(true|false) - whether the controller should be discoverable.", - set_discoverable}, - {"setName", "<name> - sets the device's Bluetooth name to <name>.", - set_name}, - {"setPcmLoopback", - "(true|false) - enables or disables PCM loopback on the controller.", - set_pcm_loopback}, - {"setScoRoute", - "(pcm|i2s|uart) - sets the SCO packet route to one of the specified " - "buses.", - set_sco_route}, -}; - -static int help(int argc, char** argv) { - if (!argc) { - printf("No help command specified.\n"); - return 1; - } - - const command_t* command = find_command(argv[0]); - if (!command) { - printf("No command named '%s'.\n", argv[0]); - return 2; - } - - printf("%s %s\n", argv[0], command->help); - return 0; -} - -static int set_discoverable(int argc, char** argv) { - if (argc != 1) { - printf("Discoverable mode not specified.\n"); - return 1; - } - - if (strcmp(argv[0], "true") && strcmp(argv[0], "false")) { - printf("Invalid discoverable mode '%s'.\n", argv[0]); - return 2; - } - - uint8_t packet[] = {0x1A, 0x0C, 0x01, 0x00}; - if (argv[0][0] == 't') packet[ARRAY_SIZE(packet) - 1] = 0x03; - - return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet)); -} - -static int set_name(int argc, char** argv) { - if (argc != 1) { - printf("Device name not specified.\n"); - return 1; - } - - size_t len = strlen(argv[0]); - if (len > 247) { - printf("Device name cannot exceed 247 bytes.\n"); - return 2; - } - - uint8_t packet[251] = {0x13, 0x0C, 248}; - memcpy(&packet[3], argv[0], len + 1); - - if (!write_hci_command(HCI_PACKET_COMMAND, packet, sizeof(packet))) return 1; - - memset(&packet[0], 0, sizeof(packet)); - packet[0] = 0x52; - packet[1] = 0x0C; - packet[2] = 0xF1; // HCI command packet length. - packet[3] = 0x01; // FEC required. - packet[4] = len + 1; - packet[5] = 0x09; // Device name field tag. - memcpy(&packet[6], argv[0], len); - return !write_hci_command(HCI_PACKET_COMMAND, packet, 0xF4); -} - -static int set_pcm_loopback(int argc, char** argv) { - if (argc != 1) { - printf("PCM loopback mode not specified.\n"); - return 1; - } - - if (strcmp(argv[0], "true") && strcmp(argv[0], "false")) { - printf("Invalid PCM mode '%s'.\n", argv[0]); - return 2; - } - - uint8_t packet[] = {0x24, 0xFC, 0x01, 0x00}; - if (argv[0][0] == 't') packet[ARRAY_SIZE(packet) - 1] = 0x01; - - return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet)); -} - -static int set_sco_route(int argc, char** argv) { - if (argc != 1) { - printf("SCO route parameter must be specified.\n"); - return 1; - } - - uint8_t route = 0xFF; - if (!strcmp(argv[0], "pcm")) - route = 0; - else if (!strcmp(argv[0], "i2s")) - route = 3; - else if (!strcmp(argv[0], "uart")) - route = 1; - - if (route == 0xFF) { - printf("Invalid SCO route specified: %s\n", argv[0]); - return 2; - } - - uint8_t packet[] = {0x1C, 0xFC, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00}; - packet[3] = route; - - return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet)); -} - -int main(int argc, char** argv) { - if (argc < 2) { - usage(argv[0]); - return -1; - } - - const command_t* command = find_command(argv[1]); - if (!command) { - printf("Unrecognized command '%s'.\n", argv[1]); - return -2; - } - - if (!command->handler) { - printf("Unhandled command '%s'.\n", argv[1]); - return -3; - } - - return command->handler(argc - 2, &argv[2]); -} - -static bool write_hci_command(hci_packet_t type, const void* packet, - size_t length) { - int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock == INVALID_FD) goto error; - - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(0x7F000001); - addr.sin_port = htons(8873); - int ret; - OSI_NO_INTR(ret = connect(sock, (const struct sockaddr*)&addr, sizeof(addr))); - if (ret == -1) goto error; - - if (send(sock, &type, 1, 0) != 1) goto error; - - if (send(sock, &length, 2, 0) != 2) goto error; - - if (send(sock, packet, length, 0) != (ssize_t)length) goto error; - - close(sock); - return true; - -error:; - close(sock); - return false; -} - -static const command_t* find_command(const char* name) { - for (size_t i = 0; i < ARRAY_SIZE(commands); ++i) - if (!strcmp(commands[i].name, name)) return &commands[i]; - return NULL; -} - -static void usage(const char* name) { - printf("Usage: %s <command> [options]\n", name); - printf("Commands:\n"); - for (size_t i = 0; i < ARRAY_SIZE(commands); ++i) - printf(" %s\n", commands[i].name); - printf("For detailed help on a command, run '%s help <command>'.\n", name); -} diff --git a/system/tools/scripts/change_types.sh b/system/tools/scripts/change_types.sh deleted file mode 100755 index 4467b89677..0000000000 --- a/system/tools/scripts/change_types.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash - -# This script will recursively search all |FILES| from the current -# directory and replace all |TYPES| according to the list below. - -# NOTE 1: -# If this script is run from .../packages/modules/Bluetooth/system (as it's intended to be), -# please edit stack/include/bt_types.h next and remove the typedef's -# near the top and restore the definitions of TRUE and FALSE. These -# are still used in the vnd_* files and device specific repositories. - -# NOTE 2: -# The list of files to be modified also includes "*.patch", which means -# this script can be used to help cherry-picking changes from older -# branches. Follow this workflow outline: -# 1. git format-patch [-1] <your sha1> -# 2. Run change_type script on patch[es] -# 3. git apply / git am - - -# Regular expression matching the file name -FILES="\.h$|\.c$|\.cpp$|\.cc$|\.patch$" - -# Search/replace terms, separated by ":" -TYPES=( - "UINT8 :uint8_t " - "UINT16 :uint16_t " - "UINT32 :uint32_t " - "UINT64 :uint64_t " - "INT8 :int8_t " - "INT16 :int16_t " - "INT32 :int32_t " - "INT64 :int64_t " - "UINT8:uint8_t" - "UINT16:uint16_t" - "UINT32:uint32_t" - "UINT64:uint64_t" - "INT8:int8_t" - "INT16:int16_t" - "INT32:int32_t" - "INT64:int64_t" - "BOOLEAN:bool " - "TRUE:true" - "FALSE:false" - "__FUNCTION__:__func__" -) - -function process_file -{ - echo -n "Processing file $1 " - - for tt in "${TYPES[@]}" ; - do - before=${tt%%:*} - after=${tt#*:} - - echo -n "." - sed -i -e "s/\b${before}/${after}/g; s/${after}_/${before}_/g;" "$1" - done - echo -} - -function process_files -{ - until [ -z "$1" ] - do - process_file "$1" - shift - done -} - - -# Let's do this ... -process_files `find ./ | grep -E "${FILES}"` - -# All done ... -echo -echo "All done." - -# Try to be helpful ... -PWD=`pwd` -if [[ "${PWD}" == */packages/modules/Bluetooth/system ]] -then - echo "Please edit ${PWD}/stack/include/bt_types.h next." -fi diff --git a/system/vendor_libs/linux/interface/Android.bp b/system/vendor_libs/linux/interface/Android.bp index 26e11fbcb8..a47a57dbd8 100644 --- a/system/vendor_libs/linux/interface/Android.bp +++ b/system/vendor_libs/linux/interface/Android.bp @@ -46,7 +46,6 @@ cc_binary { static_libs: [ "async_fd_watcher", ], - c_std: "c99", init_rc: ["android.hardware.bluetooth@1.1-service.btlinux.rc"], } diff --git a/tools/OWNERS b/tools/OWNERS index e950f0b0db..ec93a16eba 100644 --- a/tools/OWNERS +++ b/tools/OWNERS @@ -3,6 +3,7 @@ cmanton@google.com cncn@google.com jpawlowski@google.com +licorne@google.com mylesgw@google.com optedoblivion@google.com qasimj@google.com diff --git a/tools/bt-api-plumber/bt-api-plumber-9000.sh b/tools/bt-api-plumber/bt-api-plumber-9000.sh deleted file mode 100755 index e4e4e62e13..0000000000 --- a/tools/bt-api-plumber/bt-api-plumber-9000.sh +++ /dev/null @@ -1,559 +0,0 @@ -#!/bin/bash - -YELLOW="\033[1;33m" -NOCOLOR="\033[0m" -BLUE="\033[1;34m" -RED="\033[1;91m" - -# TODO(optedoblivion): Check for 'git' and 'clang' binary - -function check_environment { - if [[ -z "${ANDROID_BUILD_TOP}" ]] || [[ -z "${ANDROID_HOST_OUT}" ]] ; then - echo -e "${RED}ANDROID_BUILD_TOP${NOCOLOR} or ${RED}ANDROID_HOST_OUT${NOCOLOR} is not set for host run" - echo -e "Navigate to android root and run:" - echo -e "${YELLOW}" - echo -e ". build/envsetup.sh" - echo -e "lunch <fish>" - echo -e "${NOCOLOR}" - echo - exit 1 - fi -} - -QUOTES=( - "It's a-me, Martino!" - "Hello!" - "Wahoo!" - "Oh yeah!" - "Martino time!" - "Lucky!" - "Hui hew! Just what I needed!" - "Spin! Hammer! Fire! Jump!" - "Yiiiiiipeee!" - "Yeah, ha ha ha!" - "Waha!" - "Let's-a go!" - "Here we go!" - "Yes! I'm the winner!" - "Luigi!" - "Way to go!" - "Here I go!" - "Mama Mia!" -) - -VERBOSE=false - -# Controller -CONTROLLER=false -CONTROLLER_FILES=( - "system/gd/hci/controller.h" - "system/gd/hci/controller.cc" - "system/gd/hci/controller.cc" - "system/gd/hci/controller_mock.h" - "system/gd/hci/controller_test.cc" -) -CONTROLLER_FIND_PATTERNS=( - " LeRand(LeRandCallback cb);" - "Controller::impl::le_rand_cb<LeRandCompleteView>, cb));" - "impl::le_rand, cb);" - " (LeRandCallback cb));" - " le_rand_set.get_future().wait();" -) -CONTROLLER_CODE_TEMPLATES=( - " virtual void :CamelApiName:();" - " }\\\n\\\n void :snake_api_name:() {\\\n \\\\\/\\\\\/TODO(WHOAMI): Implement HCI Call" - "}\\\n\\\nvoid Controller:::CamelApiName:() {\\\n CallOn(impl_.get(), \\\\\&impl:::snake_api_name:);" - " MOCK_METHOD(void, :CamelApiName:, ());" - "}\\\n\\\nTEST_F(ControllerTest, :CamelApiName:Test) {\\\n controller->:CamelApiName:();" -) -CONTROLLER_REPLACEMENT_PATTERNS=( - "FIRST\n\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" -) - -# Controller shim -CONTROLLER_SHIM=false -CONTROLLER_SHIM_FILES=( - "system/device/include/controller.h" - "system/main/shim/controller.cc" - "system/main/shim/controller.cc" - "system/test/mock/mock_device_controller.cc" - "system/test/mock/mock_device_controller.cc" -) -CONTROLLER_SHIM_FIND_PATTERNS=( - " (\*le_rand)(LeRandCallback);" - " bluetooth::shim::GetController()->LeRand(cb);" - " controller_le_rand," - " le_rand(LeRandCallback cb) { return BTM_SUCCESS; }" - " le_rand," -) -CONTROLLER_SHIM_CODE_TEMPLATES=( - " uint8_t (*:snake_api_name:)(void);" - " return BTM_SUCCESS;\\\n}\\\n\\\nstatic uint8_t controller_:snake_api_name:() {\\\n bluetooth::shim::GetController()->:CamelApiName:();" - " .:snake_api_name: = controller_:snake_api_name:" - "tBTM_STATUS :snake_api_name:() { return BTM_SUCCESS; }" - " :snake_api_name:," -) -CONTROLLER_SHIM_REPLACEMENT_PATTERNS=( - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" -) - -## Files length must match templates and replacement pattern lengths! -# BTM -BTM_SHIM=false -BTM_SHIM_FILES=( - "system/main/shim/btm_api.h" - "system/main/shim/btm_api.cc" - "system/test/mock/mock_main_shim_btm_api.cc" -) -BTM_SHIM_FIND_PATTERNS=( - "TM_STATUS BTM_LeRand(LeRandCallback);" - "ontroller_get_interface()->le_rand(cb);" - " bluetooth::shim::BTM_LeRand(LeRandCallback cb) {" -) -BTM_SHIM_CODE_TEMPLATES=( - "\\\\\/*******************************************************************************\\\n *\\\n * Function BTM_:CamelApiName:\\\n *\\\n * Description :API_DESCRIPTION:\\\n *\\\n * Parameters\\\n *\\\n *******************************************************************************\\\\\/\\\ntBTM_STATUS BTM_:CamelApiName:(void);" - " return BTM_SUCCESS;\\\n}\\\n\\\ntBTM_STATUS bluetooth::shim::BTM_:CamelApiName:() {\\\n \\\\\/\\\\\/PLUMB: controller_get_interface()->:snake_api_name:();" - " inc_func_call_count(__func__);\\\n return BTM_SUCCESS;\\\n}\\\n\\\ntBTM_STATUS bluetooth::shim::BTM_:CamelApiName:() {" -) -BTM_SHIM_REPLACEMENT_PATTERNS=( - "FIRST\n\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" -) - -# BTA -BTA=false -BTA_FILES=( - # External BTA API - "system/bta/include/bta_api.h" - "system/bta/dm/bta_dm_api.cc" - # internal BTA API - "system/bta/dm/bta_dm_int.h" - "system/bta/dm/bta_dm_act.cc" -) -BTA_FIND_PATTERNS=( - "extern void BTA_DmLeRand(LeRandCallback cb);" - "do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_le_rand, cb));" - "extern void bta_dm_le_rand(LeRandCallback cb);" - "ooth::shim::BTM_LeRand(cb);" -) -BTA_CODE_TEMPLATES=( - "\\\\\/*******************************************************************************\\\n *\\\n * Function BTA_Dm:CamelApiName:\\\n *\\\n * Description :API_DESCRIPTION:\\\n *\\\n * Parameters\\\n *\\\n *******************************************************************************\\\\\/\\\nextern void BTA_Dm:CamelApiName:();" - "}\\\n\\\nvoid BTA_Dm:CamelApiName:() {\\\n APPL_TRACE_API(\"BTA_Dm:CamelApiName:\");\\\n do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_:snake_api_name:));" - "extern void bta_dm_:snake_api_name:();" - "}\\\n\\\n\\\\\/*******************************************************************************\\\n *\\\n * Function BTA_Dm:CamelApiName:\\\n *\\\n * Description :API_DESCRIPTION:\\\n *\\\n * Parameters\\\n *\\\n *******************************************************************************\\\\\/\\\nvoid bta_dm_:snake_api_name:() {\\\n \\\\\/\\\\\/PLUMB: bluetooth::shim::BTM_:CamelApiName:();" -) -BTA_REPLACEMENT_PATTERNS=( - "FIRST\n\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" -) - -# BTIF -BTIF=false -BTIF_FILES=( - # BTIF DM Layer - "system/btif/include/btif_dm.h" - "system/btif/src/btif_dm.cc" - # BTIF Layer - "system/include/hardware/bluetooth.h" - "system/btif/src/bluetooth.cc" - "system/btif/src/bluetooth.cc" - "system/service/hal/fake_bluetooth_interface.cc" - # Yes double it for two replacements - "system/test/mock/mock_bluetooth_interface.cc" - "system/test/mock/mock_bluetooth_interface.cc" -) -BTIF_FIND_PATTERNS=( - # BTIF DM Layer - "oid btif_dm_le_rand(LeRandCallback callback);" - "_dm_le_rand(callback);" - # BTIF Layer - "} bt_interface_t;" - " void dump(" - " le_rand," - " le_rand " - "EXPORT_SYMBOL" - " le_rand," -) -BTIF_CODE_TEMPLATES=( - # BTIF DM Layer - " void btif_dm_:snake_api_name:();" - "}\\\n\\\nvoid btif_dm_:snake_api_name:() {\\\n \\\\\/\\\\\/PLUMB: BTA_Dm:CamelApiName:();" - # BTIF Layer - " \\\n\\\\\/**\\\n *\\\n * :API_DESCRIPTION:\\\n *\\\n *\\\\\/\\\nint (*:snake_api_name:)();" - " int :snake_api_name:() {\\\n if(!interface_ready()) return BT_STATUS_NOT_READY;\\\n do_in_main_thread(FROM_HERE, base::BindOnce(btif_dm_:snake_api_name:));\\\n return BT_STATUS_SUCCESS;\\\n}\\\n\\\nstatic" - "\ \ \ \ :snake_api_name:," - "*\\\\\/\\\n\ \ \ \ nullptr, \\\\\/* :snake_api_name: " - "static int :snake_api_name:() { return 0; }\\\n\\\nE" - "\ \ \ \ :snake_api_name:," -) -BTIF_REPLACEMENT_PATTERNS=( - # BTIF DM Layer - "FIRST\nSECOND" - "FIRST\nSECOND" - # BTIF Layer - "SECOND\nFIRST" - "SECONDFIRST" - "FIRST\nSECOND" - "FIRSTSECOND" - "SECONDFIRST" - "FIRST\nSECOND" -) - -# Topshim -TOPSHIM=false -TOPSHIM_FILES=( - # Topshim API - "system/gd/rust/topshim/src/btif.rs" - "system/gd/rust/topshim/facade/src/adapter_service.rs" - # Topshim Test API - "system/blueberry/facade/topshim/facade.proto" - "system/blueberry/tests/gd/rust/topshim/facade/automation_helper.py" -) -TOPSHIM_FIND_PATTERNS=( - # Topshim API - " le_rand)" - ".le_rand();" - # Topshim Test API - " LeRand(google.protobuf.Empty) returns (google.protobuf.Empty) {}" - " self.adapter_stub.LeRand(empty_proto.Empty())" -) -TOPSHIM_CODE_TEMPLATES=( - # Topshim API - " }\\\n\\\n pub fn :snake_api_name:(\\\\\&self) -> i32 {\\\n ccall!(self, :snake_api_name:)" - " ctx.spawn(async move {\\\n sink.success(Empty::default()).await.unwrap();\\\n })\\\n }\\\n\\\n fn :snake_api_name:(\\\\\&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {\\\n self.btif_intf.lock().unwrap().:snake_api_name:();" - # Topshim Test API - " rpc :CamelApiName:(google.protobuf.Empty) returns (google.protobuf.Empty) {}" - " async def :snake_api_name:(self):\\\n await self.adapter_stub.:CamelApiName:(empty_proto.Empty())" -) -TOPSHIM_REPLACEMENT_PATTERNS=( - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\n\nSECOND" -) - -function help_menu { - echo - echo -e "${YELLOW}Help menu${NOCOLOR}" - echo -e "===================================" - echo -e "${BLUE} --controller${NOCOLOR}" - echo -e " Adds plumbing for the GD Controller Layer for the API." - echo -e " This includes test file changes required to build." - echo -e "${BLUE} --controller-shim${NOCOLOR}" - echo -e " Adds plumbing for the GD Controller Shim Layer for the API." - echo -e " This includes test file changes required to build." - echo -e " Will autoplumb to ONLY the GD controller if --controller flag is set. (as opposed to legacy controller btu_hcif)" - echo -e "${BLUE} --btm${NOCOLOR}" - echo -e " Adds plumbing for the BTM Shim Layer for the given API." - echo -e " Will autoplumb to ONLY the controller shim if --controller-shim flag is set. vs directly to legacy btu_hcif" - echo -e "${BLUE} --bta${NOCOLOR}" - echo -e " Adds plumbing for the BTA Layer for the given API." - echo -e " Will autoplumb to BTM if --btm set." - echo -e "${BLUE} --btif${NOCOLOR}" - echo -e " Adds plumbing for the BTIF Layer for the API." - echo -e " This currently includes JNI as it is a requirement for Android to build." - echo -e " Will autoplumb to BTA if --bta set." - echo -e "${BLUE} --topshim${NOCOLOR}" - echo -e " Adds plumbing for the topshim to BTIF Layer for the API." - echo -e " This will also include testing APIs callable from python tests." - echo -e " Will autoplumb to BTIF if --btif set." - echo -e "${BLUE} --verbose${NOCOLOR}" - echo -e " Prints verbose logging." - echo - echo -e "Usage: $0 [--controller|--controller-shim|--btm|--bta|--btif|--topshim] [CamelCaseApiName] [snake_case_api_name] (description)" - echo -e " ${YELLOW}e.g." - echo -e " $0 --controller --btm ClearEventMask clear_event_mask \"Clear out the event mask\"" - echo -e " $0 --controller --btm --bta --btif --topshim ClearEventMaskclear_event_mask \"Clear out the event mask\" ${NOCOLOR}" - echo -} - -## Start parsing arguments here -POSITIONAL=() -function parse_options { - while [[ $# -gt 0 ]] - do - key="$1" - case $key in - --verbose) - VERBOSE=true - shift - ;; - --help) - help_menu - shift - exit 0 - ;; - --controller) - CONTROLLER=true - shift - ;; - --controller-shim) - CONTROLLER_SHIM=true - shift - ;; - --btm) - # Actually we skip BTM here and just use the BTM Shim - BTM_SHIM=true - shift - ;; - --bta) - BTA=true - shift - ;; - --btif) - BTIF=true - shift - ;; - --topshim) - TOPSHIM=true - shift - ;; - --*) - echo "$0: unrecognized argument: '$1'" - echo "Try '$0 --help' for more information" - exit 1 - shift - ;; - *) - POSITIONAL+=("${1}") - shift - ;; - esac - done - set -- "${POSITIONAL[@]}" -} - -function show_mario { - MSG="$(mario_message)I'm plumbing the '${1}'" - echo - echo -e "${RED} ⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⣤⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ "⠀ - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⡾⣻⣿⣿⣿⣿⣯⣍⠛⠻⢷⣦⣀⠀⠀⠀⠀⠀⠀⠀ " - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⠟⢁⣾⠟⠋⣁⣀⣤⡉⠻⣷⡀⠀⠙⢿⣷⣄⠀⠀⠀⠀⠀ "⠀ - echo -e "${NOCOLOR}⠀⠀⠀⠀⠀⠀⠀⢀⡀${RED}⠀⠀⠀⠀⠀⠀⣰⣿⠏⠀⠀⢸⣿⠀⠼⢋⣉⣈⡳⢀⣿⠃⠀⠀⠀⠙⣿⣦⡀⠀⠀⠀ "⠀ - echo -e "${NOCOLOR}⠀⠀⠀⠀⠀⠀⢰⡿⠿⣷⡀⠀${RED}⠀⠀⣼⣿⠃⠀⠀⣀⣤⡿⠟⠛⠋⠉⠉⠙⢛⣻⠶⣦⣄⡀⠀⠘⣿⣷⡀⠀⠀ "⠀ - echo -e "${NOCOLOR}⢠⣾⠟⠳⣦⣄⢸⡇⠀⠈⣷⡀${RED}⠀⣼⣿⡏⢀⣤⡾${NOCOLOR}⢋⣵⠿⠻⢿⠋⠉⠉⢻⠟⠛⠻⣦⣝${RED}⠻⣷⣄⠸⣿⣿${NOCOLOR}⠀⠀ ( ${MSG} )"⠀ - echo -e "⠘⣧⠀⠀⠀⠙⢿⣿⠀⠀⢸⣷${RED}⠀⣿⣿⣧⣾⣏${NOCOLOR}⡴⠛⢡⠖⢛⣲⣅⠀⠀⣴⣋⡉⠳⡄⠈⠳${RED}⢬⣿⣿⣿⡿${NOCOLOR}⠀⠀ O"⠀ - echo -e "⠀⠘⠷⣤⣀⣀⣀⣽⡶⠛⠛⠛⢷⣿⣿⣿⣿⣏⠀⠀⡏⢰⡿⢿⣿⠀⠀⣿⠻⣿⠀⡷⠀⣠⣾⣿⡿⠛⠷⣦⠀ o"⠀ - echo -e "⠀⠀⢀⣾⠟⠉⠙⣿⣤⣄⠀⢀⣾⠉⠀⢹⣿⣿⣷⠀⠹⡘⣷⠾⠛⠋⠉⠛⠻⢿⡴⢃⣄⣻⣿⣿⣷⠀⠀⢹⡇ ."⠀ - echo -e "⠀⠀⢸⡇⠈⠉⠛⢦⣿⡏⠀⢸⣧⠀⠈⠻⣿⡿⢣⣾⣦⣽⠃⠀⠀⠀⠀⠀⠀⠀⣷⣾⣿⡇⠉⢿⡇⠀⢀⣼⠇ "⠀ - echo -e "⠀⠀⠘⣷⡠⣄⣀⣼⠇⠀⠀⠀⠻⣷⣤⣀⣸⡇⠀⠹⣿⣿⣦⣀⠀⠀⠀⠀⢀⣴⣿⣿⡟⠀⠀⢸⣷⣾⡿⠃⠀ "⠀ - echo -e "⠀⠀⠀⠈⠻⢦⣍⣀⣀⣀⡄⠀⣰⣿⡿⠿⢿⣇⠀⠀⠉⠛⠻⣿⣿⡷⠾⣿⣿⡿⠉⠁⠀⠀⢀⣾⠋⠁⠀⠀⠀ " - echo -e "⠀⠀⠀⠀⠀⠀⠈⠉⠉⠙⠿⢿⣿⣇⠀⠀⠈⢿⣧⣄⠀⠀⠀⢹⣷⣶⣶⣾⣿⡇⠀⠀⣀⣴⡿⣧⣄⡀⠀⠀⠀ "⠀ - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣷⡀⠀⠀⠙⢿⣿⣶⣤⡀⠻⢤⣀⡤⠞⢀⣴⣿⣿⠟⢷⡀⠙⠻⣦⣄⠀ "⠀ - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣦⠀⢠⡟⠁⠙⢻⣿⠷⠶⣶⠶⠾⠛⠙⣿⠇⠀⠀⢻⡄⠀⠀⠙⢷⡀ " - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⡀⣿⠁⣤⣤⡄⢻⡶⠶⠛⠛⠛⠛⠛⣿⢠⣾⣷⣆⢻⡀⠀⠀⠈⣷ " - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⢸⣿⣿⣿⡈⢿⡀⠀⠀⠀⠀⠀⡿⢸⣿⣿⣿⢸⡇⠀⠀⠀⡟ " - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠈⠉⠉⠉⠁⠈⠁⠀⠀⠀⠀⠈⠁⠈⠉⠉⠉⠀⠁⠀⠀⠈⠁ " - echo -} - -function mario_done { - echo -e "${YELLOW}Done.${NOCOLOR}" -} - -function mario_message { - I=$((0 + $RANDOM % ${#QUOTES[@]})) - echo -en "${BLUE}${QUOTES[$I]}! ${BLUE}${2}${YELLOW}${1} ${NOCOLOR}" -} - -# TODO: Pass in which patterns and templates to use -function plumbit { - layer="$1" - shift - camel_api_name="$1" - shift - snake_api_name="$1" - shift - api_description="$1" - shift - files_array=($@) - - WORKING_CODE_TEMPLATES=() - WORKING_PATTERNS=() - AUTOPLUMB=false - if [ "$layer" == "controller" ]; then - WORKING_PATTERNS=("${CONTROLLER_FIND_PATTERNS[@]}") - WORKING_CODE_TEMPLATES=("${CONTROLLER_CODE_TEMPLATES[@]}") - WORKING_REPLACEMENTS=("${CONTROLLER_REPLACEMENT_PATTERNS[@]}") - elif [ "$layer" == "controller_shim" ]; then - WORKING_PATTERNS=("${CONTROLLER_SHIM_FIND_PATTERNS[@]}") - WORKING_CODE_TEMPLATES=("${CONTROLLER_SHIM_CODE_TEMPLATES[@]}") - WORKING_REPLACEMENTS=("${CONTROLLER_SHIM_REPLACEMENT_PATTERNS[@]}") - AUTOPLUMB=$CONTROLLER - elif [ "$layer" == "btm_shim" ]; then - WORKING_PATTERNS=("${BTM_SHIM_FIND_PATTERNS[@]}") - WORKING_CODE_TEMPLATES=("${BTM_SHIM_CODE_TEMPLATES[@]}") - WORKING_REPLACEMENTS=("${BTM_SHIM_REPLACEMENT_PATTERNS[@]}") - AUTOPLUMB=$CONTROLLER_SHIM - elif [ "$layer" == "bta" ]; then - WORKING_PATTERNS=("${BTA_FIND_PATTERNS[@]}") - WORKING_CODE_TEMPLATES=("${BTA_CODE_TEMPLATES[@]}") - WORKING_REPLACEMENTS=("${BTA_REPLACEMENT_PATTERNS[@]}") - AUTOPLUMB=$BTM_SHIM - elif [ "$layer" == "btif" ]; then - WORKING_PATTERNS=("${BTIF_FIND_PATTERNS[@]}") - WORKING_CODE_TEMPLATES=("${BTIF_CODE_TEMPLATES[@]}") - WORKING_REPLACEMENTS=("${BTIF_REPLACEMENT_PATTERNS[@]}") - AUTOPLUMB=$BTA - elif [ "$layer" == "topshim" ]; then - WORKING_PATTERNS=("${TOPSHIM_FIND_PATTERNS[@]}") - WORKING_CODE_TEMPLATES=("${TOPSHIM_CODE_TEMPLATES[@]}") - WORKING_REPLACEMENTS=("${TOPSHIM_REPLACEMENT_PATTERNS[@]}") - AUTOPLUMB=$BTIF - fi - - for index in ${!files_array[@]}; do - CODE=$(echo "${WORKING_CODE_TEMPLATES[$index]}" | sed "s/:CamelApiName:/$camel_api_name/g" | sed "s/:snake_api_name:/$snake_api_name/g" | sed "s/WHOAMI/$(whoami)/g" | sed "s/:API_DESCRIPTION:/${api_description}/g") - if [ "$AUTOPLUMB" == true ]; then - CODE=$(echo "${CODE}" | sed "s/PLUMB:/ Autoplumbed\\\\\\\n /g") - fi - PATTERN="${WORKING_PATTERNS[$index]}" - REPLACEMENT=$(echo ${WORKING_REPLACEMENTS[$index]} | sed s/FIRST/"\\${PATTERN}"/g | sed s/SECOND/"${CODE}"/g) - if [ "$VERBOSE" == true ]; then - echo sed -i "s/\\${PATTERN}/\\${REPLACEMENT}/g" "${files_array[$index]}" - fi - sed -i "s/\\${PATTERN}/\\${REPLACEMENT}/g" "${files_array[$index]}" - done -} - -CL_COUNT=0 - -function commitit { - mario_message "${1}" "Committing the code..." - git commit -qam "${2} ${1} API" - mario_done - let CL_COUNT=$CL_COUNT+1 -} - -function clangit { - FORMATTER="${ANDROID_BUILD_TOP}/tools/repohooks/tools/clang-format.py" - FIX="--fix" - CLANG_FORMAT="--clang-format ${ANDROID_BUILD_TOP}/prebuilts/clang/host/linux-x86/clang-stable/bin/clang-format" - GIT_CLANG_FORMAT="--git-clang-format ${ANDROID_BUILD_TOP}/prebuilts/clang/host/linux-x86/clang-stable/bin/git-clang-format" - COMMIT="--commit" - STYLE="--style file" - EXTENSIONS="--extensions c,h,cc,cpp,hpp" - HASH="$1" - CMD="${FORMATTER} ${FIX} ${CLANG_FORMAT} ${GIT_CLANG_FORMAT} ${COMMIT} ${HASH} ${STYLE} ${EXTENSIONS}" - $(${CMD}) -} - -function rustfmtit { - echo "rusty rust" -# FORMATTER="${ANDROID_BUILD_TOP}/prebuilts/rust/linux-x86/stable/rustfmt" -# CONFIG="'--config-path=rustfmt.toml'" -# FILE="" -# CMD="${FORMATTER} ${CONFIG} ${FILE}" -# $(${CMD}) -} - - -function formatit { - mario_message "${1}" "Formatting the code..." - hash="$(git log -n 1 --pretty=oneline | awk '{ print $1 }')" - clangit $hash - rustfmtit $hash - git commit -a --amend --no-edit - mario_done -} - -function controller { - if [ "$CONTROLLER" == false ]; then - return - fi - mario_message "Controller" "Plumbing the '${1}' API..." - plumbit "controller" "${1}" "${2}" "${3}" "${CONTROLLER_FILES[@]}" - mario_done - commitit "Controller" "${3}" - formatit "Controller" -} - -function controller_shim { - if [ "$CONTROLLER_SHIM" == false ]; then - return - fi - mario_message "Controller shim" "Plumbing the '${1}' API..." - plumbit "controller_shim" "${1}" "${2}" "${3}" "${CONTROLLER_SHIM_FILES[@]}" - mario_done - commitit "Controller shim" "${3}" - formatit "Controller shim" -} - -function btm_shim { - if [ "$BTM_SHIM" == false ]; then - return - fi - mario_message "BTM" "Plumbing the '${1}' API..." - plumbit "btm_shim" "${1}" "${2}" "${3}" "${BTM_SHIM_FILES[@]}" - mario_done - commitit "BTM" "${3}" - formatit "BTM" -} - -function bta { - if [ "$BTA" == false ]; then - return - fi - mario_message "BTA" "Plumbing the '${1}' API..." - plumbit "bta" "${1}" "${2}" "${3}" "${BTA_FILES[@]}" - mario_done - commitit "BTA" "${3}" - formatit "BTA" -} - -function btif { - if [ "$BTIF" == false ]; then - return - fi - mario_message "BTIF" "Plumbing the '${1}' API..." - plumbit "btif" "${1}" "${2}" "${3}" "${BTIF_FILES[@]}" - mario_done - commitit "BTIF" "${3}" - formatit "BTIF" -} - -function topshim { - if [ "$TOPSHIM" == false ]; then - return - fi - mario_message "Topshim" "Plumbing the '${1}' API..." - plumbit "topshim" "${1}" "${2}" "${3}" "${TOPSHIM_FILES[@]}" - mario_done - commitit "Topshim" "${3}" - formatit "Topshim" -} - -function main { - check_environment - parse_options $@ - if [ "${#POSITIONAL[@]}" -lt 3 ]; then - echo -e "${RED}Error: Invalid argument count for API Names!${NOCOLOR}" - help_menu - exit 1 - fi - camel_api_name="${POSITIONAL[0]}" - snake_api_name="${POSITIONAL[1]}" - api_description="${POSITIONAL[@]:2}" - show_mario "${camel_api_name} API that ${api_description}!" - controller "${camel_api_name}" "${snake_api_name}" "${api_description}" - controller_shim "${camel_api_name}" "${snake_api_name}" "${api_description}" - btm_shim "${camel_api_name}" "${snake_api_name}" "${api_description}" - bta "${camel_api_name}" "${snake_api_name}" "${api_description}" - btif "${camel_api_name}" "${snake_api_name}" "${api_description}" - topshim "${camel_api_name}" "${snake_api_name}" "${api_description}" - git rebase -i HEAD~${CL_COUNT} -x 'git commit --amend' -} - -main $@ -#/usr/local/google/home/optedoblivion/workspace/AOSP/prebuilts/rust/linux-x86/stable/rustfmt '--config-path=rustfmt.toml' system/gd/rust/topshim/facade/src/adapter_service.rs diff --git a/tools/rootcanal/Android.bp b/tools/rootcanal/Android.bp index 188f425bd0..67dd3afa78 100644 --- a/tools/rootcanal/Android.bp +++ b/tools/rootcanal/Android.bp @@ -135,7 +135,6 @@ cc_library_static { static_libs: [ "libscriptedbeaconpayload-protos-lite", ], - include_dirs: ["packages/modules/Bluetooth/system/gd"], } // This library implements a foreigh function interface over DualModeController @@ -179,7 +178,6 @@ cc_library_host_shared { cflags: [ "-fexceptions", ], - include_dirs: ["packages/modules/Bluetooth/system/gd"], } // Generate the python parser+serializer backend for @@ -223,7 +221,7 @@ genrule { " $(location :pdl_python_generator)" + " --output $(out) --custom-type-location py.bluetooth", srcs: [ - "packets/hci/hci_packets.pdl", + "packets/hci_packets.pdl", ], out: [ "hci_packets.py", @@ -293,7 +291,6 @@ cc_test_host { static_libs: [ "libbt-rootcanal", ], - include_dirs: ["packages/modules/Bluetooth/system/gd"], } // Implement the Bluetooth official LL test suite for root-canal. @@ -313,8 +310,8 @@ python_test_host { "test/LL/CON_/PER/*.py", "test/LL/DDI/ADV/*.py", "test/LL/DDI/SCN/*.py", - "test/LMP/LIH/*.py", "test/LMP/*.py", + "test/LMP/LIH/*.py", "test/main.py", ], data: [ @@ -367,7 +364,6 @@ cc_test_host { enabled: false, }, }, - include_dirs: ["packages/modules/Bluetooth/system/gd"], } // Linux RootCanal Executable @@ -409,14 +405,13 @@ cc_binary_host { enabled: false, }, }, - include_dirs: ["packages/modules/Bluetooth/system/gd"], } genrule { name: "rootcanal_hci_packets_cxx_gen", tools: [ - ":pdlc", ":pdl_cxx_generator", + ":pdlc", ], cmd: "set -o pipefail;" + " $(location :pdlc) $(in) |" + @@ -425,7 +420,7 @@ genrule { " --include-header hci/address.h" + " --output $(out)", srcs: [ - "packets/hci/hci_packets.pdl", + "packets/hci_packets.pdl", ], out: [ "packets/hci_packets.h", @@ -435,8 +430,8 @@ genrule { genrule { name: "rootcanal_link_layer_packets_cxx_gen", tools: [ - ":pdlc", ":pdl_cxx_generator", + ":pdlc", ], cmd: "set -o pipefail;" + " $(location :pdlc) $(in) |" + @@ -456,8 +451,8 @@ genrule { genrule { name: "rootcanal_bredr_bb_packets_cxx_gen", tools: [ - ":pdlc", ":pdl_cxx_generator", + ":pdlc", ], cmd: "set -o pipefail;" + " $(location :pdlc) $(in) |" + @@ -477,6 +472,6 @@ genrule { genrule { name: "rootcanal_hci_packets_rust_gen", defaults: ["pdl_rust_generator_defaults"], - srcs: ["packets/hci/hci_packets.pdl"], + srcs: ["packets/hci_packets.pdl"], out: ["hci_packets.rs"], } diff --git a/tools/rootcanal/CMakeLists.txt b/tools/rootcanal/CMakeLists.txt index 91e3d7ff0e..53aec54b73 100644 --- a/tools/rootcanal/CMakeLists.txt +++ b/tools/rootcanal/CMakeLists.txt @@ -1,4 +1,4 @@ -set(BT_ROOT ${AOSP_ROOT}/packages/modules/Bluetooth/system) +set(BT_ROOT ${AOSP_ROOT}/packages/modules/Bluetooth) set(ROOTCANAL_ROOT ${AOSP_ROOT}/packages/modules/Bluetooth/tools/rootcanal) set(PDL_ROOT ${AOSP_ROOT}/external/rust/crates/pdl-compiler) @@ -109,7 +109,7 @@ endfunction() pdl_gen( NAME BluetoothGeneratedPackets_h - INPUT ${ROOTCANAL_ROOT}/packets/hci/hci_packets.pdl + INPUT ${ROOTCANAL_ROOT}/packets/hci_packets.pdl OUTPUT packets/hci_packets.h LANG c++ NAMESPACE "bluetooth::hci" @@ -166,7 +166,7 @@ target_include_directories(libbt-rootcanal.headers INTERFACE ${ROOTCANAL_ROOT}) target_link_libraries(libbt-rootcanal.headers INTERFACE android-emu-base-headers) android_license(TARGET "libbt-rootcanal.headers" LIBNAME None SPDX Apache-2.0 - LICENSE Apache-2.0 LOCAL "${BT_ROOT}/../NOTICE") + LICENSE Apache-2.0 LOCAL "${BT_ROOT}/NOTICE") android_add_library( TARGET librootcanal_log diff --git a/tools/rootcanal/hal/bluetooth_hci.cc b/tools/rootcanal/hal/bluetooth_hci.cc index bab7be1139..d63b870843 100644 --- a/tools/rootcanal/hal/bluetooth_hci.cc +++ b/tools/rootcanal/hal/bluetooth_hci.cc @@ -69,7 +69,7 @@ class BluetoothDeathRecipient : public hidl_death_recipient { void setHasDied(bool has_died) { has_died_ = has_died; } private: - bool has_died_; + bool has_died_{false}; }; BluetoothHci::BluetoothHci() diff --git a/tools/rootcanal/model/controller/dual_mode_controller.cc b/tools/rootcanal/model/controller/dual_mode_controller.cc index 346d0debd7..d2b8780c05 100644 --- a/tools/rootcanal/model/controller/dual_mode_controller.cc +++ b/tools/rootcanal/model/controller/dual_mode_controller.cc @@ -2055,10 +2055,10 @@ void DualModeController::LeCreateConnection(CommandView command) { command_view.GetPeerAddress(), command_view.GetPeerAddressType(), }, - command_view.GetOwnAddressType(), command_view.GetConnIntervalMin(), - command_view.GetConnIntervalMax(), command_view.GetConnLatency(), - command_view.GetSupervisionTimeout(), command_view.GetMinimumCeLength(), - command_view.GetMaximumCeLength()); + command_view.GetOwnAddressType(), command_view.GetConnectionIntervalMin(), + command_view.GetConnectionIntervalMax(), command_view.GetMaxLatency(), + command_view.GetSupervisionTimeout(), command_view.GetMinCeLength(), + command_view.GetMaxCeLength()); send_event_(bluetooth::hci::LeCreateConnectionStatusBuilder::Create( status, kNumCommandPackets)); } @@ -2083,8 +2083,9 @@ void DualModeController::LeConnectionUpdate(CommandView command) { DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); ErrorCode status = link_layer_controller_.LeConnectionUpdate( - command_view.GetConnectionHandle(), command_view.GetConnIntervalMin(), - command_view.GetConnIntervalMax(), command_view.GetConnLatency(), + command_view.GetConnectionHandle(), + command_view.GetConnectionIntervalMin(), + command_view.GetConnectionIntervalMax(), command_view.GetMaxLatency(), command_view.GetSupervisionTimeout()); send_event_(bluetooth::hci::LeConnectionUpdateStatusBuilder::Create( @@ -2602,7 +2603,7 @@ void DualModeController::LeSetExtendedScanParameters(CommandView command) { ErrorCode status = link_layer_controller_.LeSetExtendedScanParameters( command_view.GetOwnAddressType(), command_view.GetScanningFilterPolicy(), - command_view.GetScanningPhys(), command_view.GetParameters()); + command_view.GetScanningPhys(), command_view.GetScanningPhyParameters()); send_event_( bluetooth::hci::LeSetExtendedScanParametersCompleteBuilder::Create( kNumCommandPackets, status)); @@ -2633,18 +2634,30 @@ void DualModeController::LeExtendedCreateConnection(CommandView command) { DEBUG(id_, "<< LE Extended Create Connection"); DEBUG(id_, " peer_address={}", command_view.GetPeerAddress()); DEBUG(id_, " peer_address_type={}", - bluetooth::hci::AddressTypeText(command_view.GetPeerAddressType())); + bluetooth::hci::PeerAddressTypeText(command_view.GetPeerAddressType())); DEBUG(id_, " initiator_filter_policy={}", bluetooth::hci::InitiatorFilterPolicyText( command_view.GetInitiatorFilterPolicy())); + AddressType peer_address_type; + switch (command_view.GetPeerAddressType()) { + case PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS: + default: + peer_address_type = AddressType::PUBLIC_DEVICE_ADDRESS; + break; + case PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS: + peer_address_type = AddressType::RANDOM_DEVICE_ADDRESS; + break; + } + ErrorCode status = link_layer_controller_.LeExtendedCreateConnection( command_view.GetInitiatorFilterPolicy(), command_view.GetOwnAddressType(), AddressWithType{ command_view.GetPeerAddress(), - command_view.GetPeerAddressType(), + peer_address_type, }, - command_view.GetInitiatingPhys(), command_view.GetPhyScanParameters()); + command_view.GetInitiatingPhys(), + command_view.GetInitiatingPhyParameters()); send_event_(bluetooth::hci::LeExtendedCreateConnectionStatusBuilder::Create( status, kNumCommandPackets)); } diff --git a/tools/rootcanal/model/controller/link_layer_controller.cc b/tools/rootcanal/model/controller/link_layer_controller.cc index 96e3bfe845..ed92bc1f71 100644 --- a/tools/rootcanal/model/controller/link_layer_controller.cc +++ b/tools/rootcanal/model/controller/link_layer_controller.cc @@ -682,7 +682,7 @@ ErrorCode LinkLayerController::LeAddDeviceToResolvingList( for (auto const& entry : le_resolving_list_) { if ((entry.peer_identity_address_type == peer_identity_address_type && entry.peer_identity_address == peer_identity_address) || - entry.peer_irk == peer_irk) { + (entry.peer_irk == peer_irk && !irk_is_zero(peer_irk))) { INFO(id_, "device is already present in the resolving list"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1281,7 +1281,8 @@ ErrorCode LinkLayerController::LeSetExtendedScanParameters( bluetooth::hci::OwnAddressType own_address_type, bluetooth::hci::LeScanningFilterPolicy scanning_filter_policy, uint8_t scanning_phys, - std::vector<bluetooth::hci::PhyScanParameters> scanning_phy_parameters) { + std::vector<bluetooth::hci::ScanningPhyParameters> + scanning_phy_parameters) { uint8_t supported_phys = properties_.LeSupportedPhys(); // Extended advertising commands are disallowed when legacy advertising @@ -1676,7 +1677,7 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( bluetooth::hci::InitiatorFilterPolicy initiator_filter_policy, bluetooth::hci::OwnAddressType own_address_type, AddressWithType peer_address, uint8_t initiating_phys, - std::vector<bluetooth::hci::LeCreateConnPhyScanParameters> + std::vector<bluetooth::hci::InitiatingPhyParameters> initiating_phy_parameters) { // Extended advertising commands are disallowed when legacy advertising // commands were used since the last reset. @@ -1751,36 +1752,39 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( // Note: no explicit error code stated for invalid connection interval // values but assuming Unsupported Feature or Parameter Value (0x11) // error code based on similar advertising command. - if (parameter.conn_interval_min_ < 0x6 || - parameter.conn_interval_min_ > 0x0c80 || - parameter.conn_interval_max_ < 0x6 || - parameter.conn_interval_max_ > 0x0c80) { + if (parameter.connection_interval_min_ < 0x6 || + parameter.connection_interval_min_ > 0x0c80 || + parameter.connection_interval_max_ < 0x6 || + parameter.connection_interval_max_ > 0x0c80) { INFO(id_, "connection_interval_min (0x{:04x}) and/or " "connection_interval_max (0x{:04x}) are outside the range" " of supported values (0x6 - 0x0c80)", - parameter.conn_interval_min_, parameter.conn_interval_max_); + parameter.connection_interval_min_, + parameter.connection_interval_max_); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } // The Connection_Interval_Min parameter shall not be greater than the // Connection_Interval_Max parameter. - if (parameter.conn_interval_max_ < parameter.conn_interval_min_) { + if (parameter.connection_interval_max_ < + parameter.connection_interval_min_) { INFO(id_, "connection_interval_min (0x{:04x}) is larger than" " connection_interval_max (0x{:04x})", - parameter.conn_interval_min_, parameter.conn_interval_max_); + parameter.connection_interval_min_, + parameter.connection_interval_max_); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } // Note: no explicit error code stated for invalid max_latency // values but assuming Unsupported Feature or Parameter Value (0x11) // error code based on similar advertising command. - if (parameter.conn_latency_ > 0x01f3) { + if (parameter.max_latency_ > 0x01f3) { INFO(id_, "max_latency (0x{:04x}) is outside the range" " of supported values (0x0 - 0x01f3)", - parameter.conn_latency_); + parameter.max_latency_); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } @@ -1800,8 +1804,8 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( // (1 + Max_Latency) * Connection_Interval_Max * 2, where // Connection_Interval_Max is given in milliseconds. milliseconds min_supervision_timeout = duration_cast<milliseconds>( - (1 + parameter.conn_latency_) * - slots(2 * parameter.conn_interval_max_) * 2); + (1 + parameter.max_latency_) * + slots(2 * parameter.connection_interval_max_) * 2); if (parameter.supervision_timeout_ * 10ms < min_supervision_timeout) { INFO( id_, @@ -1862,10 +1866,10 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( .scan_interval = initiating_phy_parameters[offset].scan_interval_, .scan_window = initiating_phy_parameters[offset].scan_window_, .connection_interval_min = - initiating_phy_parameters[offset].conn_interval_min_, + initiating_phy_parameters[offset].connection_interval_min_, .connection_interval_max = - initiating_phy_parameters[offset].conn_interval_max_, - .max_latency = initiating_phy_parameters[offset].conn_latency_, + initiating_phy_parameters[offset].connection_interval_max_, + .max_latency = initiating_phy_parameters[offset].max_latency_, .supervision_timeout = initiating_phy_parameters[offset].supervision_timeout_, .min_ce_length = initiating_phy_parameters[offset].min_ce_length_, @@ -1880,10 +1884,10 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( .scan_interval = initiating_phy_parameters[offset].scan_interval_, .scan_window = initiating_phy_parameters[offset].scan_window_, .connection_interval_min = - initiating_phy_parameters[offset].conn_interval_min_, + initiating_phy_parameters[offset].connection_interval_min_, .connection_interval_max = - initiating_phy_parameters[offset].conn_interval_max_, - .max_latency = initiating_phy_parameters[offset].conn_latency_, + initiating_phy_parameters[offset].connection_interval_max_, + .max_latency = initiating_phy_parameters[offset].max_latency_, .supervision_timeout = initiating_phy_parameters[offset].supervision_timeout_, .min_ce_length = initiating_phy_parameters[offset].min_ce_length_, @@ -1898,10 +1902,10 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( .scan_interval = initiating_phy_parameters[offset].scan_interval_, .scan_window = initiating_phy_parameters[offset].scan_window_, .connection_interval_min = - initiating_phy_parameters[offset].conn_interval_min_, + initiating_phy_parameters[offset].connection_interval_min_, .connection_interval_max = - initiating_phy_parameters[offset].conn_interval_max_, - .max_latency = initiating_phy_parameters[offset].conn_latency_, + initiating_phy_parameters[offset].connection_interval_max_, + .max_latency = initiating_phy_parameters[offset].max_latency_, .supervision_timeout = initiating_phy_parameters[offset].supervision_timeout_, .min_ce_length = initiating_phy_parameters[offset].min_ce_length_, @@ -2833,6 +2837,10 @@ Address LinkLayerController::generate_rpa( return rpa; } +bool LinkLayerController::irk_is_zero(std::array<uint8_t, LinkLayerController::kIrkSize> irk) { + return std::all_of(irk.begin(), irk.end(), [](uint8_t b) { return b == 0; }); +} + // Handle legacy advertising PDUs while in the Scanning state. void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( model::packets::LeLegacyAdvertisingPduView& pdu, uint8_t rssi) { @@ -3280,6 +3288,7 @@ void LinkLayerController::ConnectIncomingLeLegacyAdvertisingPdu( } initiator_.pending_connect_request = advertising_address; + initiator_.initiating_address = initiating_address.GetAddress(); INFO(id_, "Sending LE Connect request to {} with initiating address {}", resolved_advertising_address, initiating_address); @@ -3706,6 +3715,7 @@ void LinkLayerController::ConnectIncomingLeExtendedAdvertisingPdu( } initiator_.pending_connect_request = advertising_address; + initiator_.initiating_address = initiating_address.GetAddress(); INFO(id_, "Sending LE Connect request to {} with initiating address {}", resolved_advertising_address, initiating_address); diff --git a/tools/rootcanal/model/controller/link_layer_controller.h b/tools/rootcanal/model/controller/link_layer_controller.h index c028424885..2e426a86fb 100644 --- a/tools/rootcanal/model/controller/link_layer_controller.h +++ b/tools/rootcanal/model/controller/link_layer_controller.h @@ -63,6 +63,9 @@ class LinkLayerController { static Address generate_rpa( std::array<uint8_t, LinkLayerController::kIrkSize> irk); + // Return true if the input IRK is all 0s. + static bool irk_is_zero(std::array<uint8_t, LinkLayerController::kIrkSize> irk); + LinkLayerController(const Address& address, const ControllerProperties& properties, uint32_t id = 0); ~LinkLayerController(); @@ -480,7 +483,8 @@ class LinkLayerController { bluetooth::hci::OwnAddressType own_address_type, bluetooth::hci::LeScanningFilterPolicy scanning_filter_policy, uint8_t scanning_phys, - std::vector<bluetooth::hci::PhyScanParameters> scanning_phy_parameters); + std::vector<bluetooth::hci::ScanningPhyParameters> + scanning_phy_parameters); // HCI command LE_Set_Extended_Scan_Enable (Vol 4, Part E § 7.8.65). ErrorCode LeSetExtendedScanEnable( @@ -509,7 +513,7 @@ class LinkLayerController { bluetooth::hci::InitiatorFilterPolicy initiator_filter_policy, bluetooth::hci::OwnAddressType own_address_type, AddressWithType peer_address, uint8_t initiating_phys, - std::vector<bluetooth::hci::LeCreateConnPhyScanParameters> + std::vector<bluetooth::hci::InitiatingPhyParameters> initiating_phy_parameters); // Periodic Advertising diff --git a/tools/rootcanal/model/devices/hci_device.cc b/tools/rootcanal/model/devices/hci_device.cc index 50263a0de7..710bd3a598 100644 --- a/tools/rootcanal/model/devices/hci_device.cc +++ b/tools/rootcanal/model/devices/hci_device.cc @@ -54,30 +54,38 @@ HciDevice::HciDevice(std::shared_ptr<HciTransport> transport, })); RegisterEventChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) { - transport_->SendEvent(*packet); + transport_->Send(PacketType::EVENT, *packet); }); RegisterAclChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) { - transport_->SendAcl(*packet); + transport_->Send(PacketType::ACL, *packet); }); RegisterScoChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) { - transport_->SendSco(*packet); + transport_->Send(PacketType::SCO, *packet); }); RegisterIsoChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) { - transport_->SendIso(*packet); + transport_->Send(PacketType::ISO, *packet); }); transport_->RegisterCallbacks( - [this](const std::shared_ptr<std::vector<uint8_t>> command) { - HandleCommand(command); - }, - [this](const std::shared_ptr<std::vector<uint8_t>> acl) { - HandleAcl(acl); - }, - [this](const std::shared_ptr<std::vector<uint8_t>> sco) { - HandleSco(sco); - }, - [this](const std::shared_ptr<std::vector<uint8_t>> iso) { - HandleIso(iso); + [this](PacketType packet_type, + const std::shared_ptr<std::vector<uint8_t>> packet) { + switch (packet_type) { + case PacketType::COMMAND: + HandleCommand(packet); + break; + case PacketType::ACL: + HandleAcl(packet); + break; + case PacketType::SCO: + HandleSco(packet); + break; + case PacketType::ISO: + HandleIso(packet); + break; + default: + ASSERT(false); + break; + } }, [this]() { INFO(id_, "HCI transport closed"); diff --git a/tools/rootcanal/model/hci/hci_sniffer.cc b/tools/rootcanal/model/hci/hci_sniffer.cc index f0dbc139f0..ea3e2cbeac 100644 --- a/tools/rootcanal/model/hci/hci_sniffer.cc +++ b/tools/rootcanal/model/hci/hci_sniffer.cc @@ -73,32 +73,14 @@ void HciSniffer::AppendRecord(PacketDirection packet_direction, output_->flush(); } -void HciSniffer::RegisterCallbacks(PacketCallback command_callback, - PacketCallback acl_callback, - PacketCallback sco_callback, - PacketCallback iso_callback, +void HciSniffer::RegisterCallbacks(PacketCallback packet_callback, CloseCallback close_callback) { transport_->RegisterCallbacks( - [this, - command_callback](const std::shared_ptr<std::vector<uint8_t>> command) { - AppendRecord(PacketDirection::HOST_TO_CONTROLLER, PacketType::COMMAND, - *command); - command_callback(command); - }, - [this, acl_callback](const std::shared_ptr<std::vector<uint8_t>> acl) { - AppendRecord(PacketDirection::HOST_TO_CONTROLLER, PacketType::ACL, - *acl); - acl_callback(acl); - }, - [this, sco_callback](const std::shared_ptr<std::vector<uint8_t>> sco) { - AppendRecord(PacketDirection::HOST_TO_CONTROLLER, PacketType::SCO, - *sco); - sco_callback(sco); - }, - [this, iso_callback](const std::shared_ptr<std::vector<uint8_t>> iso) { - AppendRecord(PacketDirection::HOST_TO_CONTROLLER, PacketType::ISO, - *iso); - iso_callback(iso); + [this, packet_callback]( + PacketType packet_type, + const std::shared_ptr<std::vector<uint8_t>> packet) { + AppendRecord(PacketDirection::HOST_TO_CONTROLLER, packet_type, *packet); + packet_callback(packet_type, packet); }, close_callback); } @@ -112,23 +94,10 @@ void HciSniffer::Close() { } } -void HciSniffer::SendEvent(const std::vector<uint8_t>& packet) { - AppendRecord(PacketDirection::CONTROLLER_TO_HOST, PacketType::EVENT, packet); - transport_->SendEvent(packet); -} - -void HciSniffer::SendAcl(const std::vector<uint8_t>& packet) { - AppendRecord(PacketDirection::CONTROLLER_TO_HOST, PacketType::ACL, packet); - transport_->SendAcl(packet); -} - -void HciSniffer::SendSco(const std::vector<uint8_t>& packet) { - AppendRecord(PacketDirection::CONTROLLER_TO_HOST, PacketType::SCO, packet); - transport_->SendSco(packet); +void HciSniffer::Send(PacketType packet_type, + const std::vector<uint8_t>& packet) { + AppendRecord(PacketDirection::CONTROLLER_TO_HOST, packet_type, packet); + transport_->Send(packet_type, packet); } -void HciSniffer::SendIso(const std::vector<uint8_t>& packet) { - AppendRecord(PacketDirection::CONTROLLER_TO_HOST, PacketType::ISO, packet); - transport_->SendIso(packet); -} } // namespace rootcanal diff --git a/tools/rootcanal/model/hci/hci_sniffer.h b/tools/rootcanal/model/hci/hci_sniffer.h index 206414e2f1..5ad47fbe7b 100644 --- a/tools/rootcanal/model/hci/hci_sniffer.h +++ b/tools/rootcanal/model/hci/hci_sniffer.h @@ -52,22 +52,13 @@ class HciSniffer : public HciTransport { void SetOutputStream(std::shared_ptr<std::ostream> outputStream); void SetPcapFilter(std::shared_ptr<PcapFilter> filter); - void SendEvent(const std::vector<uint8_t>& packet) override; + void Send(PacketType packet_type, + const std::vector<uint8_t>& packet) override; - void SendAcl(const std::vector<uint8_t>& packet) override; - - void SendSco(const std::vector<uint8_t>& packet) override; - - void SendIso(const std::vector<uint8_t>& packet) override; - - void RegisterCallbacks(PacketCallback command_callback, - PacketCallback acl_callback, - PacketCallback sco_callback, - PacketCallback iso_callback, + void RegisterCallbacks(PacketCallback packet_callback, CloseCallback close_callback) override; void Tick() override; - void Close() override; private: diff --git a/tools/rootcanal/model/hci/hci_socket_transport.cc b/tools/rootcanal/model/hci/hci_socket_transport.cc index c018b0ef1a..82632e466d 100644 --- a/tools/rootcanal/model/hci/hci_socket_transport.cc +++ b/tools/rootcanal/model/hci/hci_socket_transport.cc @@ -23,44 +23,41 @@ namespace rootcanal { HciSocketTransport::HciSocketTransport(std::shared_ptr<AsyncDataChannel> socket) : socket_(socket) {} -void HciSocketTransport::RegisterCallbacks(PacketCallback command_callback, - PacketCallback acl_callback, - PacketCallback sco_callback, - PacketCallback iso_callback, +void HciSocketTransport::RegisterCallbacks(PacketCallback packet_callback, CloseCallback close_callback) { // TODO: Avoid the copy here by using new buffer in H4DataChannel h4_ = H4DataChannelPacketizer( socket_, - [command_callback](const std::vector<uint8_t>& raw_command) { + [packet_callback](const std::vector<uint8_t>& raw_command) { std::shared_ptr<std::vector<uint8_t>> packet_copy = std::make_shared<std::vector<uint8_t>>(raw_command); - command_callback(packet_copy); + packet_callback(PacketType::COMMAND, packet_copy); }, [](const std::vector<uint8_t>&) { FATAL("Unexpected Event in HciSocketTransport!"); }, - [acl_callback](const std::vector<uint8_t>& raw_acl) { + [packet_callback](const std::vector<uint8_t>& raw_acl) { std::shared_ptr<std::vector<uint8_t>> packet_copy = std::make_shared<std::vector<uint8_t>>(raw_acl); - acl_callback(packet_copy); + packet_callback(PacketType::ACL, packet_copy); }, - [sco_callback](const std::vector<uint8_t>& raw_sco) { + [packet_callback](const std::vector<uint8_t>& raw_sco) { std::shared_ptr<std::vector<uint8_t>> packet_copy = std::make_shared<std::vector<uint8_t>>(raw_sco); - sco_callback(packet_copy); + packet_callback(PacketType::SCO, packet_copy); }, - [iso_callback](const std::vector<uint8_t>& raw_iso) { + [packet_callback](const std::vector<uint8_t>& raw_iso) { std::shared_ptr<std::vector<uint8_t>> packet_copy = std::make_shared<std::vector<uint8_t>>(raw_iso); - iso_callback(packet_copy); + packet_callback(PacketType::ISO, packet_copy); }, close_callback); } void HciSocketTransport::Tick() { h4_.OnDataReady(socket_); } -void HciSocketTransport::SendHci(PacketType packet_type, - const std::vector<uint8_t>& packet) { +void HciSocketTransport::Send(PacketType packet_type, + const std::vector<uint8_t>& packet) { if (!socket_ || !socket_->Connected()) { INFO("Closed socket. Dropping packet of type {}", packet_type); return; @@ -69,22 +66,6 @@ void HciSocketTransport::SendHci(PacketType packet_type, h4_.Send(type, packet.data(), packet.size()); } -void HciSocketTransport::SendEvent(const std::vector<uint8_t>& packet) { - SendHci(PacketType::EVENT, packet); -} - -void HciSocketTransport::SendAcl(const std::vector<uint8_t>& packet) { - SendHci(PacketType::ACL, packet); -} - -void HciSocketTransport::SendSco(const std::vector<uint8_t>& packet) { - SendHci(PacketType::SCO, packet); -} - -void HciSocketTransport::SendIso(const std::vector<uint8_t>& packet) { - SendHci(PacketType::ISO, packet); -} - void HciSocketTransport::Close() { socket_->Close(); } } // namespace rootcanal diff --git a/tools/rootcanal/model/hci/hci_socket_transport.h b/tools/rootcanal/model/hci/hci_socket_transport.h index 6bd2d8e7e5..e6e4a356ac 100644 --- a/tools/rootcanal/model/hci/hci_socket_transport.h +++ b/tools/rootcanal/model/hci/hci_socket_transport.h @@ -36,27 +36,16 @@ class HciSocketTransport : public HciTransport { return std::make_shared<HciSocketTransport>(socket); } - void SendEvent(const std::vector<uint8_t>& packet) override; + void Send(PacketType packet_type, + const std::vector<uint8_t>& packet) override; - void SendAcl(const std::vector<uint8_t>& packet) override; - - void SendSco(const std::vector<uint8_t>& packet) override; - - void SendIso(const std::vector<uint8_t>& packet) override; - - void RegisterCallbacks(PacketCallback command_callback, - PacketCallback acl_callback, - PacketCallback sco_callback, - PacketCallback iso_callback, + void RegisterCallbacks(PacketCallback packet_callback, CloseCallback close_callback) override; void Tick() override; - void Close() override; private: - void SendHci(PacketType packet_type, const std::vector<uint8_t>& packet); - std::shared_ptr<AsyncDataChannel> socket_; H4DataChannelPacketizer h4_{socket_, [](const std::vector<uint8_t>&) {}, diff --git a/tools/rootcanal/model/hci/hci_transport.h b/tools/rootcanal/model/hci/hci_transport.h index e682801255..5aa10f160c 100644 --- a/tools/rootcanal/model/hci/hci_transport.h +++ b/tools/rootcanal/model/hci/hci_transport.h @@ -20,32 +20,28 @@ #include <memory> #include <vector> +#include "model/hci/h4.h" + namespace rootcanal { -using PacketCallback = - std::function<void(const std::shared_ptr<std::vector<uint8_t>>)>; +using PacketCallback = std::function<void( + PacketType, const std::shared_ptr<std::vector<uint8_t>>)>; using CloseCallback = std::function<void()>; class HciTransport { public: virtual ~HciTransport() = default; - virtual void SendEvent(const std::vector<uint8_t>& packet) = 0; - - virtual void SendAcl(const std::vector<uint8_t>& packet) = 0; - - virtual void SendSco(const std::vector<uint8_t>& packet) = 0; + /// Send the input HCI packet with the selected H4 packet type. + /// The packet data contains the H4 header but not the IDC byte. + virtual void Send(PacketType packet_type, + std::vector<uint8_t> const& packet) = 0; - virtual void SendIso(const std::vector<uint8_t>& packet) = 0; - - virtual void RegisterCallbacks(PacketCallback command_callback, - PacketCallback acl_callback, - PacketCallback sco_callback, - PacketCallback iso_callback, + /// Register the handler for received HCI packets. + virtual void RegisterCallbacks(PacketCallback packet_callback, CloseCallback close_callback) = 0; virtual void Tick() = 0; - virtual void Close() = 0; }; diff --git a/tools/rootcanal/packets/hci/hci_packets.pdl b/tools/rootcanal/packets/hci_packets.pdl index 0743244999..a99774499b 100644 --- a/tools/rootcanal/packets/hci/hci_packets.pdl +++ b/tools/rootcanal/packets/hci_packets.pdl @@ -3279,12 +3279,12 @@ packet LeCreateConnection : Command (op_code = LE_CREATE_CONNECTION) { peer_address_type : AddressType, peer_address : Address, own_address_type : OwnAddressType, - conn_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s) - conn_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s) - conn_latency : 16, // 0x0006-0x01F3 + connection_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s) + connection_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s) + max_latency : 16, // 0x0006-0x01F3 supervision_timeout : 16, // 0x00A to 0x0C80 (100ms to 32s) - minimum_ce_length : 16, // 0.625ms - maximum_ce_length : 16, // 0.625ms + min_ce_length : 16, // 0.625ms + max_ce_length : 16, // 0.625ms } packet LeCreateConnectionStatus : CommandStatus (command_op_code = LE_CREATE_CONNECTION) { @@ -3347,12 +3347,12 @@ packet LeRemoveDeviceFromFilterAcceptListComplete : CommandComplete (command_op_ packet LeConnectionUpdate : Command (op_code = LE_CONNECTION_UPDATE) { connection_handle : 12, _reserved_ : 4, - conn_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s) - conn_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s) - conn_latency : 16, // 0x0006-0x01F3 + connection_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s) + connection_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s) + max_latency : 16, // 0x0006-0x01F3 supervision_timeout : 16, // 0x00A to 0x0C80 (100ms to 32s) - minimum_ce_length : 16, // 0.625ms - maximum_ce_length : 16, // 0.625ms + min_ce_length : 16, // 0.625ms + max_ce_length : 16, // 0.625ms } packet LeConnectionUpdateStatus : CommandStatus (command_op_code = LE_CONNECTION_UPDATE) { @@ -3988,7 +3988,7 @@ packet LeSetPeriodicAdvertisingEnableComplete : CommandComplete (command_op_code status : ErrorCode, } -struct PhyScanParameters { +struct ScanningPhyParameters { le_scan_type : LeScanType, le_scan_interval : 16, // 0x0004-0xFFFF Default 0x10 (10ms) le_scan_window : 16, // 0x004-0xFFFF Default 0x10 (10ms) @@ -3998,7 +3998,7 @@ packet LeSetExtendedScanParameters : Command (op_code = LE_SET_EXTENDED_SCAN_PAR own_address_type : OwnAddressType, scanning_filter_policy : LeScanningFilterPolicy, scanning_phys : 8, - parameters : PhyScanParameters[], + scanning_phy_parameters : ScanningPhyParameters[], } test LeSetExtendedScanParameters { @@ -4040,12 +4040,12 @@ test LeSetExtendedScanEnableComplete { "\x0e\x04\x01\x42\x20\x00", } -struct LeCreateConnPhyScanParameters { +struct InitiatingPhyParameters { scan_interval : 16, // 0x0004-0xFFFF scan_window : 16, // < = LeScanInterval - conn_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s) - conn_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s) - conn_latency : 16, // 0x0006-0x01F3 + connection_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s) + connection_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s) + max_latency : 16, // 0x0006-0x01F3 supervision_timeout : 16, // 0x00A to 0x0C80 (100ms to 32s) min_ce_length : 16, // 0.625ms max_ce_length : 16, // 0.625ms @@ -4054,10 +4054,10 @@ struct LeCreateConnPhyScanParameters { packet LeExtendedCreateConnection : Command (op_code = LE_EXTENDED_CREATE_CONNECTION) { initiator_filter_policy : InitiatorFilterPolicy, own_address_type : OwnAddressType, - peer_address_type : AddressType, + peer_address_type : PeerAddressType, peer_address : Address, initiating_phys : 8, - phy_scan_parameters : LeCreateConnPhyScanParameters[], + initiating_phy_parameters : InitiatingPhyParameters[], } test LeExtendedCreateConnection { @@ -5625,8 +5625,8 @@ packet LeConnectionComplete : LeMetaEvent (subevent_code = CONNECTION_COMPLETE) role : Role, peer_address_type : AddressType, peer_address : Address, - conn_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms) - conn_latency : 16, // Number of connection events + connection_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms) + peripheral_latency : 16, supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s) central_clock_accuracy : ClockAccuracy, } @@ -5657,8 +5657,8 @@ packet LeConnectionUpdateComplete : LeMetaEvent (subevent_code = CONNECTION_UPDA status : ErrorCode, connection_handle : 12, _reserved_ : 4, - conn_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms) - conn_latency : 16, // Number of connection events + connection_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms) + peripheral_latency : 16, // Number of connection events supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s) } @@ -5713,8 +5713,8 @@ packet LeEnhancedConnectionComplete : LeMetaEvent (subevent_code = ENHANCED_CONN peer_address : Address, local_resolvable_private_address : Address, peer_resolvable_private_address : Address, - conn_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms) - conn_latency : 16, // Number of connection events + connection_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms) + peripheral_latency : 16, supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s) central_clock_accuracy : ClockAccuracy, } diff --git a/tools/rootcanal/py/controller.py b/tools/rootcanal/py/controller.py index 9c3e2a85fd..b4bbecaac0 100644 --- a/tools/rootcanal/py/controller.py +++ b/tools/rootcanal/py/controller.py @@ -373,13 +373,13 @@ class ControllerTest(unittest.IsolatedAsyncioTestCase): peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, initiating_phys=0x1, - phy_scan_parameters=[ - hci.LeCreateConnPhyScanParameters( + initiating_phy_parameters=[ + hci.InitiatingPhyParameters( scan_interval=0x200, scan_window=0x100, - conn_interval_min=0x200, - conn_interval_max=0x200, - conn_latency=0x6, + connection_interval_min=0x200, + connection_interval_max=0x200, + max_latency=0x6, supervision_timeout=0xc80, min_ce_length=0, max_ce_length=0, @@ -418,8 +418,8 @@ class ControllerTest(unittest.IsolatedAsyncioTestCase): role=hci.Role.CENTRAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=0x200, - conn_latency=0x6, + connection_interval=0x200, + peripheral_latency=0x6, supervision_timeout=0xc80, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) @@ -470,8 +470,8 @@ class ControllerTest(unittest.IsolatedAsyncioTestCase): role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=0x200, - conn_latency=0x200, + connection_interval=0x200, + peripheral_latency=0x200, supervision_timeout=0x200, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/rust/CMakeLists.txt b/tools/rootcanal/rust/CMakeLists.txt index 48751eacff..2e7c7cbaa9 100644 --- a/tools/rootcanal/rust/CMakeLists.txt +++ b/tools/rootcanal/rust/CMakeLists.txt @@ -2,7 +2,7 @@ message(STATUS "Enabling bluetooth LMP module.") pdl_gen( NAME hci_packets_rs - INPUT ${ROOTCANAL_ROOT}/packets/hci/hci_packets.pdl + INPUT ${ROOTCANAL_ROOT}/packets/hci_packets.pdl OUTPUT hci_packets.rs LANG rust) diff --git a/tools/rootcanal/rust/build.rs b/tools/rootcanal/rust/build.rs index cd927f6ee2..793e1f93e1 100644 --- a/tools/rootcanal/rust/build.rs +++ b/tools/rootcanal/rust/build.rs @@ -31,7 +31,7 @@ fn main() { install_generated_module( "hci_packets.rs", "HCI_PACKETS_PREBUILT", - &PathBuf::from("../packets/hci/hci_packets.pdl").canonicalize().unwrap(), + &PathBuf::from("../packets/hci_packets.pdl").canonicalize().unwrap(), ); } @@ -60,8 +60,8 @@ fn generate_module(in_file: &PathBuf) { // Find the pdl tool. Expecting it at CARGO_HOME/bin let pdl = match env::var("CARGO_HOME") { - Ok(dir) => PathBuf::from(dir).join("bin").join("pdl"), - Err(_) => PathBuf::from("pdl"), + Ok(dir) => PathBuf::from(dir).join("bin").join("pdlc"), + Err(_) => PathBuf::from("pdlc"), }; if !Path::new(pdl.as_os_str()).exists() { diff --git a/tools/rootcanal/rust/src/lmp/procedure/secure_simple_pairing.rs b/tools/rootcanal/rust/src/lmp/procedure/secure_simple_pairing.rs index 0c3c4e31a8..543219691f 100644 --- a/tools/rootcanal/rust/src/lmp/procedure/secure_simple_pairing.rs +++ b/tools/rootcanal/rust/src/lmp/procedure/secure_simple_pairing.rs @@ -143,11 +143,14 @@ async fn receive_public_key(ctx: &impl Context, transaction_id: u8) -> PublicKey const COMMITMENT_VALUE_SIZE: usize = 16; const NONCE_SIZE: usize = 16; -async fn receive_commitment(ctx: &impl Context, skip_first: bool) { - let commitment_value = [0; COMMITMENT_VALUE_SIZE]; +fn build_commitment(_ctx: &impl Context) -> [u8; COMMITMENT_VALUE_SIZE] { + [0; COMMITMENT_VALUE_SIZE] +} + +async fn receive_commitment(ctx: &impl Context, confirm: Option<lmp::SimplePairingConfirm>) { + let commitment_value = build_commitment(ctx); - if !skip_first { - let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; + if let Some(confirm) = confirm { if confirm.get_commitment_value() != &commitment_value { todo!(); } @@ -177,16 +180,8 @@ async fn receive_commitment(ctx: &impl Context, skip_first: bool) { .await; } -async fn send_commitment(ctx: &impl Context, skip_first: bool) { - let commitment_value = [0; COMMITMENT_VALUE_SIZE]; - - if !skip_first { - ctx.send_lmp_packet( - lmp::SimplePairingConfirmBuilder { transaction_id: 0, commitment_value }.build(), - ); - } - - let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; +async fn send_commitment(ctx: &impl Context, confirm: lmp::SimplePairingConfirm) { + let commitment_value = build_commitment(ctx); if confirm.get_commitment_value() != &commitment_value { todo!(); @@ -437,14 +432,33 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { match auth_method { AuthenticationMethod::NumericComparisonJustWork | AuthenticationMethod::NumericComparisonUserConfirm => { - send_commitment(ctx, true).await; + let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; + send_commitment(ctx, confirm).await; - user_confirmation_request(ctx).await?; + if user_confirmation_request(ctx).await.is_err() { + ctx.send_lmp_packet( + lmp::NumericComparisonFailedBuilder { transaction_id: 0 }.build(), + ); + Err(())?; + } Ok(()) } AuthenticationMethod::PasskeyEntry => { - if initiator.io_capability == hci::IoCapability::KeyboardOnly { - user_passkey_request(ctx).await?; + let confirm = if initiator.io_capability == hci::IoCapability::KeyboardOnly { + if user_passkey_request(ctx).await.is_err() { + ctx.send_lmp_packet( + lmp::PasskeyFailedBuilder { transaction_id: 0 }.build(), + ); + Err(())?; + } + ctx.send_lmp_packet( + lmp::SimplePairingConfirmBuilder { + transaction_id: 0, + commitment_value: build_commitment(ctx), + } + .build(), + ); + ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await } else { ctx.send_hci_event( hci::UserPasskeyNotificationBuilder { @@ -453,9 +467,32 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { } .build(), ); - } - for _ in 0..PASSKEY_ENTRY_REPEAT_NUMBER { - send_commitment(ctx, false).await; + ctx.send_lmp_packet( + lmp::SimplePairingConfirmBuilder { + transaction_id: 0, + commitment_value: build_commitment(ctx), + } + .build(), + ); + match ctx + .receive_lmp_packet::<Either<lmp::SimplePairingConfirm, lmp::NotAccepted>>() + .await + { + Either::Left(confirm) => confirm, + Either::Right(_) => Err(())?, + } + }; + send_commitment(ctx, confirm).await; + for _ in 1..PASSKEY_ENTRY_REPEAT_NUMBER { + ctx.send_lmp_packet( + lmp::SimplePairingConfirmBuilder { + transaction_id: 0, + commitment_value: build_commitment(ctx), + } + .build(), + ); + let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; + send_commitment(ctx, confirm).await; } Ok(()) } @@ -464,7 +501,15 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { remote_oob_data_request(ctx).await?; } - send_commitment(ctx, false).await; + ctx.send_lmp_packet( + lmp::SimplePairingConfirmBuilder { + transaction_id: 0, + commitment_value: build_commitment(ctx), + } + .build(), + ); + let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; + send_commitment(ctx, confirm).await; Ok(()) } } @@ -472,7 +517,6 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { .await; if result.is_err() { - ctx.send_lmp_packet(lmp::NumericComparisonFailedBuilder { transaction_id: 0 }.build()); ctx.send_hci_event( hci::SimplePairingCompleteBuilder { status: hci::ErrorCode::AuthenticationFailure, @@ -644,37 +688,78 @@ pub async fn respond(ctx: &impl Context, request: lmp::IoCapabilityReq) -> Resul // Authentication Stage 1 let auth_method = authentication_method(initiator, responder); - let negative_user_confirmation = match auth_method { - AuthenticationMethod::NumericComparisonJustWork - | AuthenticationMethod::NumericComparisonUserConfirm => { - receive_commitment(ctx, true).await; + let result: Result<bool, ()> = async { + match auth_method { + AuthenticationMethod::NumericComparisonJustWork + | AuthenticationMethod::NumericComparisonUserConfirm => { + receive_commitment(ctx, None).await; - let user_confirmation = user_confirmation_request(ctx).await; - user_confirmation.is_err() - } - AuthenticationMethod::PasskeyEntry => { - if responder.io_capability == hci::IoCapability::KeyboardOnly { - // TODO: handle error - let _user_passkey = user_passkey_request(ctx).await; - } else { - ctx.send_hci_event( - hci::UserPasskeyNotificationBuilder { bd_addr: ctx.peer_address(), passkey: 0 } + let user_confirmation = user_confirmation_request(ctx).await; + Ok(user_confirmation.is_err()) + } + AuthenticationMethod::PasskeyEntry => { + let confirm = if responder.io_capability == hci::IoCapability::KeyboardOnly { + let user_passkey = user_passkey_request(ctx).await; + let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; + if user_passkey.is_err() { + ctx.send_lmp_packet( + lmp::NotAcceptedBuilder { + transaction_id: 0, + not_accepted_opcode: lmp::Opcode::SimplePairingConfirm, + error_code: hci::ErrorCode::AuthenticationFailure.into(), + }.build(), + ); + return Err(()); + } + confirm + } else { + ctx.send_hci_event( + hci::UserPasskeyNotificationBuilder { + bd_addr: ctx.peer_address(), + passkey: 0, + } .build(), - ); + ); + match ctx + .receive_lmp_packet::<Either<lmp::SimplePairingConfirm, lmp::PasskeyFailed>>() + .await + { + Either::Left(confirm) => confirm, + Either::Right(_) => Err(())?, + } + }; + receive_commitment(ctx, Some(confirm)).await; + for _ in 1..PASSKEY_ENTRY_REPEAT_NUMBER { + let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; + receive_commitment(ctx, Some(confirm)).await; + } + Ok(false) } - for _ in 0..PASSKEY_ENTRY_REPEAT_NUMBER { - receive_commitment(ctx, false).await; + AuthenticationMethod::OutOfBand => { + if responder.oob_data_present != hci::OobDataPresent::NotPresent { + // TODO: handle error + let _remote_oob_data = remote_oob_data_request(ctx).await; + } + + let confirm = ctx.receive_lmp_packet::<lmp::SimplePairingConfirm>().await; + receive_commitment(ctx, Some(confirm)).await; + Ok(false) } - false } - AuthenticationMethod::OutOfBand => { - if responder.oob_data_present != hci::OobDataPresent::NotPresent { - // TODO: handle error - let _remote_oob_data = remote_oob_data_request(ctx).await; - } + } + .await; - receive_commitment(ctx, false).await; - false + let negative_user_confirmation = match result { + Ok(negative_user_confirmation) => negative_user_confirmation, + Err(_) => { + ctx.send_hci_event( + hci::SimplePairingCompleteBuilder { + status: hci::ErrorCode::AuthenticationFailure, + bd_addr: ctx.peer_address(), + } + .build(), + ); + return Err(()); } }; @@ -867,8 +952,7 @@ mod tests { } #[test] - #[should_panic] // TODO: make the test pass - fn passkey_entry_initiator_failure_on_initiating_side() { + fn passkey_entry_initiator_negative_reply_on_initiating_side() { let context = TestContext::new(); let procedure = initiate; @@ -876,8 +960,15 @@ mod tests { } #[test] - #[should_panic] // TODO: make the test pass - fn passkey_entry_responder_failure_on_initiating_side() { + fn passkey_entry_responder_negative_reply_on_responding_side() { + let context = TestContext::new(); + let procedure = respond; + + include!("../../../test/SP/BV-14bis-C.in"); + } + + #[test] + fn passkey_entry_responder_negative_reply_on_initiating_side() { let context = TestContext::new(); let procedure = respond; @@ -885,6 +976,14 @@ mod tests { } #[test] + fn passkey_entry_initiator_negative_reply_on_responding_side() { + let context = TestContext::new(); + let procedure = initiate; + + include!("../../../test/SP/BV-15bis-C.in"); + } + + #[test] #[should_panic] // TODO: make the test pass fn passkey_entry_initiator_failure_on_responding_side() { let context = TestContext::new(); diff --git a/tools/rootcanal/rust/test/SP/BV-14bis-C.in b/tools/rootcanal/rust/test/SP/BV-14bis-C.in new file mode 100644 index 0000000000..b98f45096d --- /dev/null +++ b/tools/rootcanal/rust/test/SP/BV-14bis-C.in @@ -0,0 +1,106 @@ +// Passkey entry responder, negative reply on responding side: +// - Test case not present in LMP.TS, but other permutations are described in SP/BV-14-C, SP/BV-15-C +// - IUT is KeyboardOnly, responder +// - Lower Tester is Display, initiator +// - IUT fails passkey entry with User_Passkey_Request_NegativeReply, responds Not Accepted to the SimplePairingConfirm +sequence! { procedure, context, + // ACL Connection Established + Lower Tester -> IUT: IoCapabilityReq { + transaction_id: 0, + io_capabilities: 0x00, + oob_authentication_data: 0x00, + authentication_requirement: 0x01, + } + IUT -> Upper Tester: IoCapabilityResponse { + bd_addr: context.peer_address(), + io_capability: IoCapability::DisplayOnly, + oob_data_present: OobDataPresent::NotPresent, + authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, + } + IUT -> Upper Tester: IoCapabilityRequest { + bd_addr: context.peer_address(), + } + Upper Tester -> IUT: IoCapabilityRequestReply { + bd_addr: context.peer_address(), + io_capability: IoCapability::KeyboardOnly, + oob_present: OobDataPresent::NotPresent, + authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, + } + IUT -> Upper Tester: IoCapabilityRequestReplyComplete { + num_hci_command_packets: 1, + status: ErrorCode::Success, + bd_addr: context.peer_address(), + } + IUT -> Lower Tester: IoCapabilityRes { + transaction_id: 0, + io_capabilities: 0x02, + oob_authentication_data: 0x00, + authentication_requirement: 0x01, + } + // Public Key Exchange + Lower Tester -> IUT: EncapsulatedHeader { + transaction_id: 0, + major_type: 1, + minor_type: 1, + payload_length: 48, + } + IUT -> Lower Tester: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedHeader, + } + repeat 3 times with (part in peer_p192_public_key()) { + Lower Tester -> IUT: EncapsulatedPayload { + transaction_id: 0, + data: part, + } + IUT -> Lower Tester: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedPayload, + } + } + IUT -> Lower Tester: EncapsulatedHeader { + transaction_id: 0, + major_type: 1, + minor_type: 1, + payload_length: 48, + } + Lower Tester -> IUT: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedHeader, + } + repeat 3 times with (part in local_p192_public_key(&context)) { + IUT -> Lower Tester: EncapsulatedPayload { + transaction_id: 0, + data: part, + } + Lower Tester -> IUT: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedPayload, + } + } + // Authentication Stage 1: Passkey Entry Protocol + IUT -> Upper Tester: UserPasskeyRequest { + bd_addr: context.peer_address(), + } + Upper Tester -> IUT: UserPasskeyRequestNegativeReply { + bd_addr: context.peer_address(), + } + IUT -> Upper Tester: UserPasskeyRequestNegativeReplyComplete { + num_hci_command_packets: 1, + status: ErrorCode::Success, + bd_addr: context.peer_address(), + } + Lower Tester -> IUT: SimplePairingConfirm { + transaction_id: 0, + commitment_value: [0; 16], + } + IUT -> Lower Tester: NotAccepted { + transaction_id: 0, + not_accepted_opcode: Opcode::SimplePairingConfirm, + error_code: ErrorCode::AuthenticationFailure.into(), + } + IUT -> Upper Tester: SimplePairingComplete { + status: ErrorCode::AuthenticationFailure, + bd_addr: context.peer_address(), + } +} diff --git a/tools/rootcanal/rust/test/SP/BV-15bis-C.in b/tools/rootcanal/rust/test/SP/BV-15bis-C.in new file mode 100644 index 0000000000..f9fda299c8 --- /dev/null +++ b/tools/rootcanal/rust/test/SP/BV-15bis-C.in @@ -0,0 +1,118 @@ +// Passkey entry initiator, negative reply on responding side: +// - Test case not present in LMP.TS, but other permutations are described in SP/BV-14-C, SP/BV-15-C +// - IUT is DisplayOnly, initiator +// - Lower Tester is KeyboardOnly, responder +// - Lower Tester fails passkey entry with User_Passkey_Request_NegativeReply, responds Not Accepted to the SimplePairingConfirm +sequence! { procedure, context, + // ACL Connection Established + Upper Tester -> IUT: AuthenticationRequested { + connection_handle: context.peer_handle() + } + IUT -> Upper Tester: AuthenticationRequestedStatus { + num_hci_command_packets: 1, + status: ErrorCode::Success, + } + IUT -> Upper Tester: LinkKeyRequest { + bd_addr: context.peer_address(), + } + Upper Tester -> IUT: LinkKeyRequestNegativeReply { + bd_addr: context.peer_address(), + } + IUT -> Upper Tester: LinkKeyRequestNegativeReplyComplete { + num_hci_command_packets: 1, + status: ErrorCode::Success, + bd_addr: context.peer_address(), + } + IUT -> Upper Tester: IoCapabilityRequest { + bd_addr: context.peer_address(), + } + Upper Tester -> IUT: IoCapabilityRequestReply { + bd_addr: context.peer_address(), + io_capability: IoCapability::DisplayOnly, + oob_present: OobDataPresent::NotPresent, + authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, + } + IUT -> Upper Tester: IoCapabilityRequestReplyComplete { + num_hci_command_packets: 1, + status: ErrorCode::Success, + bd_addr: context.peer_address(), + } + IUT -> Lower Tester: IoCapabilityReq { + transaction_id: 0, + io_capabilities: 0x00, + oob_authentication_data: 0x00, + authentication_requirement: 0x01, + } + Lower Tester -> IUT: IoCapabilityRes { + transaction_id: 0, + io_capabilities: 0x02, + oob_authentication_data: 0x00, + authentication_requirement: 0x01, + } + IUT -> Upper Tester: IoCapabilityResponse { + bd_addr: context.peer_address(), + io_capability: IoCapability::KeyboardOnly, + oob_data_present: OobDataPresent::NotPresent, + authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, + } + // Public Key Exchange + IUT -> Lower Tester: EncapsulatedHeader { + transaction_id: 0, + major_type: 1, + minor_type: 1, + payload_length: 48, + } + Lower Tester -> IUT: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedHeader, + } + repeat 3 times with (part in local_p192_public_key(&context)) { + IUT -> Lower Tester: EncapsulatedPayload { + transaction_id: 0, + data: part, + } + Lower Tester -> IUT: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedPayload, + } + } + Lower Tester -> IUT: EncapsulatedHeader { + transaction_id: 0, + major_type: 1, + minor_type: 1, + payload_length: 48, + } + IUT -> Lower Tester: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedHeader, + } + repeat 3 times with (part in peer_p192_public_key()) { + Lower Tester -> IUT: EncapsulatedPayload { + transaction_id: 0, + data: part, + } + IUT -> Lower Tester: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedPayload, + } + } + // Authentication Stage 1: Passkey Entry Protocol + IUT -> Upper Tester: UserPasskeyNotification { bd_addr: context.peer_address(), passkey: 0 } + IUT -> Lower Tester: SimplePairingConfirm { + transaction_id: 0, + commitment_value: [0; 16], + } + Lower Tester -> IUT: NotAccepted { + transaction_id: 0, + not_accepted_opcode: Opcode::SimplePairingConfirm, + error_code: ErrorCode::AuthenticationFailure.into(), + } + IUT -> Upper Tester: SimplePairingComplete { + status: ErrorCode::AuthenticationFailure, + bd_addr: context.peer_address(), + } + IUT -> Upper Tester: AuthenticationComplete { + status: ErrorCode::AuthenticationFailure, + connection_handle: context.peer_handle(), + } +} diff --git a/tools/rootcanal/test/LL/CON_/CEN/BV_41_C.py b/tools/rootcanal/test/LL/CON_/CEN/BV_41_C.py index c3b719082e..9d377ef54a 100644 --- a/tools/rootcanal/test/LL/CON_/CEN/BV_41_C.py +++ b/tools/rootcanal/test/LL/CON_/CEN/BV_41_C.py @@ -46,13 +46,13 @@ class Test(ControllerTest): peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, initiating_phys=0x1, - phy_scan_parameters=[ - hci.LeCreateConnPhyScanParameters( + initiating_phy_parameters=[ + hci.InitiatingPhyParameters( scan_interval=0x200, scan_window=0x100, - conn_interval_min=0x200, - conn_interval_max=0x200, - conn_latency=0x6, + connection_interval_min=0x200, + connection_interval_max=0x200, + max_latency=0x6, supervision_timeout=0xc80, min_ce_length=0, max_ce_length=0, @@ -91,8 +91,8 @@ class Test(ControllerTest): role=hci.Role.CENTRAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=0x200, - conn_latency=0x6, + connection_interval=0x200, + peripheral_latency=0x6, supervision_timeout=0xc80, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/CON_/CEN/BV_43_C.py b/tools/rootcanal/test/LL/CON_/CEN/BV_43_C.py index ec5b68ba4a..914df4cfe9 100644 --- a/tools/rootcanal/test/LL/CON_/CEN/BV_43_C.py +++ b/tools/rootcanal/test/LL/CON_/CEN/BV_43_C.py @@ -43,13 +43,13 @@ class Test(ControllerTest): peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, initiating_phys=0x1, - phy_scan_parameters=[ - hci.LeCreateConnPhyScanParameters( + initiating_phy_parameters=[ + hci.InitiatingPhyParameters( scan_interval=0x200, scan_window=0x100, - conn_interval_min=0x200, - conn_interval_max=0x200, - conn_latency=0x6, + connection_interval_min=0x200, + connection_interval_max=0x200, + max_latency=0x6, supervision_timeout=0xc80, min_ce_length=0, max_ce_length=0, @@ -88,8 +88,8 @@ class Test(ControllerTest): role=hci.Role.CENTRAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=0x200, - conn_latency=0x6, + connection_interval=0x200, + peripheral_latency=0x6, supervision_timeout=0xc80, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/CON_/PER/BV_40_C.py b/tools/rootcanal/test/LL/CON_/PER/BV_40_C.py index 201beeb3cd..045bca32a3 100644 --- a/tools/rootcanal/test/LL/CON_/PER/BV_40_C.py +++ b/tools/rootcanal/test/LL/CON_/PER/BV_40_C.py @@ -77,8 +77,8 @@ class Test(ControllerTest): role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=0x200, - conn_latency=0x200, + connection_interval=0x200, + peripheral_latency=0x200, supervision_timeout=0x200, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/CON_/PER/BV_42_C.py b/tools/rootcanal/test/LL/CON_/PER/BV_42_C.py index 4f19d701c5..ae067c2269 100644 --- a/tools/rootcanal/test/LL/CON_/PER/BV_42_C.py +++ b/tools/rootcanal/test/LL/CON_/PER/BV_42_C.py @@ -77,8 +77,8 @@ class Test(ControllerTest): role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=0x200, - conn_latency=0x200, + connection_interval=0x200, + peripheral_latency=0x200, supervision_timeout=0x200, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py index f850c57143..f52edd3deb 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py @@ -95,8 +95,8 @@ class Test(ControllerTest): role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=LL_initiator_connInterval, - conn_latency=LL_initiator_connPeripheralLatency, + connection_interval=LL_initiator_connInterval, + peripheral_latency=LL_initiator_connPeripheralLatency, supervision_timeout=LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_07_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_07_C.py index c4b10cdc8e..271a4fc564 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_07_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_07_C.py @@ -125,8 +125,8 @@ class Test(ControllerTest): role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=LL_initiator_connInterval, - conn_latency=LL_initiator_connPeripheralLatency, + connection_interval=LL_initiator_connInterval, + peripheral_latency=LL_initiator_connPeripheralLatency, supervision_timeout=LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_09_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_09_C.py index d583ef4cf3..719ddc76e3 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_09_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_09_C.py @@ -310,8 +310,8 @@ class Test(ControllerTest): peer_address_type=(hci.AddressType.PUBLIC_DEVICE_ADDRESS if peer_address_type == ll.AddressType.PUBLIC else hci.AddressType.RANDOM_DEVICE_ADDRESS), peer_address=peer_address, - conn_interval=self.LL_initiator_connInterval, - conn_latency=self.LL_initiator_connPeripheralLatency, + connection_interval=self.LL_initiator_connInterval, + peripheral_latency=self.LL_initiator_connPeripheralLatency, supervision_timeout=self.LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) @@ -380,8 +380,8 @@ class Test(ControllerTest): peer_address_type=(hci.AddressType.PUBLIC_DEVICE_ADDRESS if peer_address_type == ll.AddressType.PUBLIC else hci.AddressType.RANDOM_DEVICE_ADDRESS), peer_address=peer_address, - conn_interval=self.LL_initiator_connInterval, - conn_latency=self.LL_initiator_connPeripheralLatency, + connection_interval=self.LL_initiator_connInterval, + peripheral_latency=self.LL_initiator_connPeripheralLatency, supervision_timeout=self.LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_11_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_11_C.py index 1b0953ac51..014417f9be 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_11_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_11_C.py @@ -137,8 +137,8 @@ class Test(ControllerTest): role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=self.LL_initiator_connInterval, - conn_latency=self.LL_initiator_connPeripheralLatency, + connection_interval=self.LL_initiator_connInterval, + peripheral_latency=self.LL_initiator_connPeripheralLatency, supervision_timeout=self.LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_19_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_19_C.py index ba996c7ad6..9247324a4f 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_19_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_19_C.py @@ -112,8 +112,8 @@ class Test(ControllerTest): role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=public_peer_address, - conn_interval=self.LL_initiator_connInterval, - conn_latency=self.LL_initiator_connPeripheralLatency, + connection_interval=self.LL_initiator_connInterval, + peripheral_latency=self.LL_initiator_connPeripheralLatency, supervision_timeout=self.LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/DDI/SCN/BV_19_C.py b/tools/rootcanal/test/LL/DDI/SCN/BV_19_C.py index 04bda10551..41c3db5b94 100644 --- a/tools/rootcanal/test/LL/DDI/SCN/BV_19_C.py +++ b/tools/rootcanal/test/LL/DDI/SCN/BV_19_C.py @@ -82,10 +82,10 @@ class Test(ControllerTest): hci.LeSetExtendedScanParameters(own_address_type=hci.OwnAddressType.PUBLIC_DEVICE_ADDRESS, scanning_filter_policy=hci.LeScanningFilterPolicy.ACCEPT_ALL, scanning_phys=0x1, - parameters=[ - hci.PhyScanParameters(le_scan_type=hci.LeScanType.PASSIVE, - le_scan_interval=0x0010, - le_scan_window=0x0010) + scanning_phy_parameters=[ + hci.ScanningPhyParameters(le_scan_type=hci.LeScanType.PASSIVE, + le_scan_interval=0x0010, + le_scan_window=0x0010) ])) await self.expect_evt( diff --git a/tools/rootcanal/test/LL/DDI/SCN/BV_79_C.py b/tools/rootcanal/test/LL/DDI/SCN/BV_79_C.py index a27b0a1058..80a6245c68 100644 --- a/tools/rootcanal/test/LL/DDI/SCN/BV_79_C.py +++ b/tools/rootcanal/test/LL/DDI/SCN/BV_79_C.py @@ -52,10 +52,10 @@ class Test(ControllerTest): hci.LeSetExtendedScanParameters(own_address_type=hci.OwnAddressType.PUBLIC_DEVICE_ADDRESS, scanning_filter_policy=hci.LeScanningFilterPolicy.ACCEPT_ALL, scanning_phys=0x1, - parameters=[ - hci.PhyScanParameters(le_scan_type=hci.LeScanType.PASSIVE, - le_scan_interval=0x0010, - le_scan_window=0x0010) + scanning_phy_parameters=[ + hci.ScanningPhyParameters(le_scan_type=hci.LeScanType.PASSIVE, + le_scan_interval=0x0010, + le_scan_window=0x0010) ])) await self.expect_evt( diff --git a/tools/rootcanal/test/controller/le/le_add_device_to_resolving_list_test.cc b/tools/rootcanal/test/controller/le/le_add_device_to_resolving_list_test.cc index 427861e0e9..b2a44d4812 100644 --- a/tools/rootcanal/test/controller/le/le_add_device_to_resolving_list_test.cc +++ b/tools/rootcanal/test/controller/le/le_add_device_to_resolving_list_test.cc @@ -130,4 +130,16 @@ TEST_F(LeAddDeviceToResolvingListTest, PeerIrkDuplicate) { ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); } +TEST_F(LeAddDeviceToResolvingListTest, EmptyPeerIrkDuplicate) { + ASSERT_EQ(controller_.LeAddDeviceToResolvingList( + PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS, Address{1}, + std::array<uint8_t, 16>{0}, std::array<uint8_t, 16>{1}), + ErrorCode::SUCCESS); + + ASSERT_EQ(controller_.LeAddDeviceToResolvingList( + PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, Address{1}, + std::array<uint8_t, 16>{0}, std::array<uint8_t, 16>{1}), + ErrorCode::SUCCESS); +} + } // namespace rootcanal diff --git a/tools/rootcanal/test/controller/le/le_scanning_filter_duplicates_test.cc b/tools/rootcanal/test/controller/le/le_scanning_filter_duplicates_test.cc index 3387c8ad21..feed4edcd7 100644 --- a/tools/rootcanal/test/controller/le/le_scanning_filter_duplicates_test.cc +++ b/tools/rootcanal/test/controller/le/le_scanning_filter_duplicates_test.cc @@ -71,7 +71,7 @@ class LeScanningFilterDuplicates : public ::testing::Test { void StartExtendedScan(FilterDuplicates filter_duplicates, uint16_t duration = 0, uint16_t period = 0) { - bluetooth::hci::PhyScanParameters param; + bluetooth::hci::ScanningPhyParameters param; param.le_scan_type_ = LeScanType::ACTIVE; param.le_scan_interval_ = 0x4; param.le_scan_window_ = 0x4; diff --git a/tools/rootcanal/test/controller/le/le_set_extended_scan_enable_test.cc b/tools/rootcanal/test/controller/le/le_set_extended_scan_enable_test.cc index 79b9663619..278b9d06aa 100644 --- a/tools/rootcanal/test/controller/le/le_set_extended_scan_enable_test.cc +++ b/tools/rootcanal/test/controller/le/le_set_extended_scan_enable_test.cc @@ -33,10 +33,10 @@ class LeSetExtendedScanEnableTest : public ::testing::Test { LinkLayerController controller_{address_, properties_}; }; -static PhyScanParameters MakePhyScanParameters(LeScanType scan_type, - uint16_t scan_interval, - uint16_t scan_window) { - PhyScanParameters parameters; +static ScanningPhyParameters MakeScanningPhyParameters(LeScanType scan_type, + uint16_t scan_interval, + uint16_t scan_window) { + ScanningPhyParameters parameters; parameters.le_scan_type_ = scan_type; parameters.le_scan_interval_ = scan_interval; parameters.le_scan_window_ = scan_window; @@ -44,22 +44,24 @@ static PhyScanParameters MakePhyScanParameters(LeScanType scan_type, } TEST_F(LeSetExtendedScanEnableTest, EnableUsingPublicAddress) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 0, 0), ErrorCode::SUCCESS); } TEST_F(LeSetExtendedScanEnableTest, EnableUsingRandomAddress) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::RANDOM_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::RANDOM_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetRandomAddress(Address{1}), ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 0, 0), @@ -67,11 +69,12 @@ TEST_F(LeSetExtendedScanEnableTest, EnableUsingRandomAddress) { } TEST_F(LeSetExtendedScanEnableTest, EnableUsingResolvableAddress) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetRandomAddress(Address{1}), ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 0, 0), @@ -79,11 +82,12 @@ TEST_F(LeSetExtendedScanEnableTest, EnableUsingResolvableAddress) { } TEST_F(LeSetExtendedScanEnableTest, ResetEachPeriod) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::RESET_EACH_PERIOD, 100, 1000), ErrorCode::SUCCESS); @@ -96,11 +100,12 @@ TEST_F(LeSetExtendedScanEnableTest, Disable) { } TEST_F(LeSetExtendedScanEnableTest, ValidDuration) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 127, 1), @@ -108,11 +113,12 @@ TEST_F(LeSetExtendedScanEnableTest, ValidDuration) { } TEST_F(LeSetExtendedScanEnableTest, InvalidDuration) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::RESET_EACH_PERIOD, 0, 0), @@ -123,20 +129,22 @@ TEST_F(LeSetExtendedScanEnableTest, InvalidDuration) { } TEST_F(LeSetExtendedScanEnableTest, NoRandomAddress) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::RANDOM_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::RANDOM_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 0, 0), ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 0, 0), ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); diff --git a/tools/rootcanal/test/controller/le/le_set_extended_scan_parameters_test.cc b/tools/rootcanal/test/controller/le/le_set_extended_scan_parameters_test.cc index 0c153ea1ac..3e1ab5390a 100644 --- a/tools/rootcanal/test/controller/le/le_set_extended_scan_parameters_test.cc +++ b/tools/rootcanal/test/controller/le/le_set_extended_scan_parameters_test.cc @@ -33,10 +33,10 @@ class LeSetExtendedScanParametersTest : public ::testing::Test { LinkLayerController controller_{address_, properties_}; }; -static PhyScanParameters MakePhyScanParameters(LeScanType scan_type, - uint16_t scan_interval, - uint16_t scan_window) { - PhyScanParameters parameters; +static ScanningPhyParameters MakeScanningPhyParameters(LeScanType scan_type, + uint16_t scan_interval, + uint16_t scan_window) { + ScanningPhyParameters parameters; parameters.le_scan_type_ = scan_type; parameters.le_scan_interval_ = scan_interval; parameters.le_scan_window_ = scan_window; @@ -47,8 +47,8 @@ TEST_F(LeSetExtendedScanParametersTest, Success) { ASSERT_EQ(controller_.LeSetExtendedScanParameters( OwnAddressType::PUBLIC_DEVICE_ADDRESS, LeScanningFilterPolicy::ACCEPT_ALL, 0x5, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200), - MakePhyScanParameters(LeScanType::ACTIVE, 0x2000, 0x200)}), + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200), + MakeScanningPhyParameters(LeScanType::ACTIVE, 0x2000, 0x200)}), ErrorCode::SUCCESS); } @@ -56,8 +56,8 @@ TEST_F(LeSetExtendedScanParametersTest, ScanningActive) { ASSERT_EQ(controller_.LeSetExtendedScanParameters( OwnAddressType::PUBLIC_DEVICE_ADDRESS, LeScanningFilterPolicy::ACCEPT_ALL, 0x5, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200), - MakePhyScanParameters(LeScanType::ACTIVE, 0x2000, 0x200)}), + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200), + MakeScanningPhyParameters(LeScanType::ACTIVE, 0x2000, 0x200)}), ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 0, 0), @@ -66,17 +66,18 @@ TEST_F(LeSetExtendedScanParametersTest, ScanningActive) { ASSERT_EQ(controller_.LeSetExtendedScanParameters( OwnAddressType::PUBLIC_DEVICE_ADDRESS, LeScanningFilterPolicy::ACCEPT_ALL, 0x5, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200), - MakePhyScanParameters(LeScanType::ACTIVE, 0x2000, 0x200)}), + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200), + MakeScanningPhyParameters(LeScanType::ACTIVE, 0x2000, 0x200)}), ErrorCode::COMMAND_DISALLOWED); } TEST_F(LeSetExtendedScanParametersTest, ReservedPhy) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x80, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x80, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); } TEST_F(LeSetExtendedScanParametersTest, InvalidPhyParameters) { @@ -85,19 +86,20 @@ TEST_F(LeSetExtendedScanParametersTest, InvalidPhyParameters) { LeScanningFilterPolicy::ACCEPT_ALL, 0x1, {}), ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200), - MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200), + MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); } TEST_F(LeSetExtendedScanParametersTest, InvalidScanInterval) { ASSERT_EQ(controller_.LeSetExtendedScanParameters( OwnAddressType::PUBLIC_DEVICE_ADDRESS, LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x0, 0x200)}), + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x0, 0x200)}), ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); } @@ -105,14 +107,15 @@ TEST_F(LeSetExtendedScanParametersTest, InvalidScanWindow) { ASSERT_EQ(controller_.LeSetExtendedScanParameters( OwnAddressType::PUBLIC_DEVICE_ADDRESS, LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x0)}), + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x0)}), ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x2001)}), - ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x2001)}), + ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); } } // namespace rootcanal diff --git a/tools/rootcanal/test/controller/le/test_helpers.h b/tools/rootcanal/test/controller/le/test_helpers.h index 074e258d5c..4c9016c22c 100644 --- a/tools/rootcanal/test/controller/le/test_helpers.h +++ b/tools/rootcanal/test/controller/le/test_helpers.h @@ -49,18 +49,18 @@ MakeAdvertisingEventProperties(unsigned mask = 0) { return set; } -[[maybe_unused]] static bluetooth::hci::LeCreateConnPhyScanParameters +[[maybe_unused]] static bluetooth::hci::InitiatingPhyParameters MakeInitiatingPhyParameters(uint16_t scan_interval, uint16_t scan_window, uint16_t connection_interval_min, uint16_t connection_interval_max, uint16_t max_latency, uint16_t supervision_timeout, uint16_t min_ce_length, uint16_t max_ce_length) { - bluetooth::hci::LeCreateConnPhyScanParameters parameters; + bluetooth::hci::InitiatingPhyParameters parameters; parameters.scan_interval_ = scan_interval; parameters.scan_window_ = scan_window; - parameters.conn_interval_min_ = connection_interval_min; - parameters.conn_interval_max_ = connection_interval_max; - parameters.conn_latency_ = max_latency; + parameters.connection_interval_min_ = connection_interval_min; + parameters.connection_interval_max_ = connection_interval_max; + parameters.max_latency_ = max_latency; parameters.supervision_timeout_ = supervision_timeout; parameters.min_ce_length_ = min_ce_length; parameters.max_ce_length_ = max_ce_length; |