From: Sanjay Ramankandath Date: Fri, 24 Apr 2020 14:40:59 +0000 (+0000) Subject: Support for reading playback file in scripted beacon X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=466f60ad97;p=android-x86%2Fsystem-bt.git Support for reading playback file in scripted beacon Bug: 154491371 Tag: #feature Test: Manual test on cuttlefish Test: gd/cert/run --host Change-Id: Ie0ce31796a0c28826002b0677d27e5db075dde6d --- diff --git a/test/rootcanal/Android.bp b/test/rootcanal/Android.bp index bd62e50c7..916b53c00 100644 --- a/test/rootcanal/Android.bp +++ b/test/rootcanal/Android.bp @@ -32,6 +32,7 @@ cc_binary { "libhidlbase", "liblog", "libutils", + "libprotobuf-cpp-lite", ], cflags: [ "-fvisibility=hidden", @@ -49,6 +50,7 @@ cc_binary { "android.hardware.bluetooth-hci", "libbt-rootcanal", "libbt-rootcanal-types", + "libscriptedbeaconpayload-protos-lite", ], include_dirs: [ "system/bt", @@ -78,6 +80,7 @@ cc_library_shared { "libhidlbase", "liblog", "libutils", + "libprotobuf-cpp-lite", ], cflags: [ "-Wall", @@ -94,6 +97,7 @@ cc_library_shared { "android.hardware.bluetooth-hci", "libbt-rootcanal", "libbt-rootcanal-types", + "libscriptedbeaconpayload-protos-lite", ], include_dirs: [ "system/bt", diff --git a/test/rootcanal/bluetooth_hci.cc b/test/rootcanal/bluetooth_hci.cc index 2363ce93e..17ae6e763 100644 --- a/test/rootcanal/bluetooth_hci.cc +++ b/test/rootcanal/bluetooth_hci.cc @@ -18,13 +18,13 @@ #include "bluetooth_hci.h" +#include "log/log.h" #include #include #include #include #include "hci_internals.h" -#include "os/log.h" namespace android { namespace hardware { @@ -85,7 +85,6 @@ Return BluetoothHci::initialize_impl( const sp& cb, const sp& cb_1_1) { LOG_INFO("%s", __func__); - if (cb == nullptr) { LOG_ERROR("cb == nullptr! -> Unable to call initializationComplete(ERR)"); return Void(); @@ -191,7 +190,8 @@ Return BluetoothHci::initialize_impl( test_channel_.Add({"beacon", "be:ac:10:00:00:02", "1000"}); test_channel_.AddDeviceToPhy({"3", "1"}); test_channel_.Add( - {"scripted_beacon", "5b:ea:c1:00:00:03", "path_to_config.log"}); + {"scripted_beacon", "5b:ea:c1:00:00:03", + "/data/vendor/bluetooth/bluetooth_sim_ble_playback_file"}); test_channel_.AddDeviceToPhy({"4", "1"}); unlink_cb_ = [this, cb](sp& death_recipient) { diff --git a/vendor_libs/test_vendor_lib/Android.bp b/vendor_libs/test_vendor_lib/Android.bp index 70bb09239..c3c08d84a 100644 --- a/vendor_libs/test_vendor_lib/Android.bp +++ b/vendor_libs/test_vendor_lib/Android.bp @@ -64,9 +64,21 @@ cc_library_static { ], static_libs: [ "libbt-rootcanal-types", + "libscriptedbeaconpayload-protos-lite", ], } +cc_library_static { + name: "libscriptedbeaconpayload-protos-lite", + host_supported: true, + proprietary: true, + proto: { + export_proto_headers: true, + type: "lite", + }, + srcs: ["model/devices/scripted_beacon_ble_payload.proto"], +} + // test-vendor unit tests for host // ======================================================== cc_test_host { @@ -133,6 +145,8 @@ cc_test_host { ], static_libs: [ "libbt-rootcanal-types", + "libprotobuf-cpp-lite", + "libscriptedbeaconpayload-protos-lite", "libbt-rootcanal", ], } diff --git a/vendor_libs/test_vendor_lib/model/devices/scripted_beacon.cc b/vendor_libs/test_vendor_lib/model/devices/scripted_beacon.cc index fff377b1c..490d0dfed 100644 --- a/vendor_libs/test_vendor_lib/model/devices/scripted_beacon.cc +++ b/vendor_libs/test_vendor_lib/model/devices/scripted_beacon.cc @@ -14,9 +14,20 @@ * limitations under the License. */ +#define OS_ANDROID +#include "os/log.h" +#undef OS_ANDROID #include "scripted_beacon.h" -// #include "hci/hci_packets.h" // To use error-checking packets +#include +#include +#include +#include +#include +#include +#include + +#include "model/devices/scripted_beacon_ble_payload.pb.h" #include "model/setup/device_boutique.h" using std::vector; @@ -24,10 +35,9 @@ using std::vector; namespace test_vendor_lib { bool ScriptedBeacon::registered_ = DeviceBoutique::Register("scripted_beacon", &ScriptedBeacon::Create); - ScriptedBeacon::ScriptedBeacon() { advertising_interval_ms_ = std::chrono::milliseconds(1280); - properties_.SetLeAdvertisementType(0x03 /* NON_CONNECT */); + properties_.SetLeAdvertisementType(0x02 /* SCANNABLE */); properties_.SetLeAdvertisement({ 0x18, // Length 0x09 /* TYPE_NAME_CMPL */, @@ -59,11 +69,45 @@ ScriptedBeacon::ScriptedBeacon() { 0x4 /* BREDR_NOT_SPT */ | 0x2 /* GEN_DISC_FLAG */, }); - properties_.SetLeScanResponse({0x06, // Length - 0x07, // TYPE_NAME_SHORT + properties_.SetLeScanResponse({0x05, // Length + 0x08, // TYPE_NAME_SHORT 'g', 'b', 'e', 'a'}); } +bool ScriptedBeacon::is_config_file_ready() { + static bool file_absence_logged = false; + if (access(config_file_.c_str(), F_OK) == -1) { + if (!file_absence_logged) { + LOG_INFO("%s: playback file %s not available", + __func__, + config_file_.c_str()); + file_absence_logged = true; + } + return false; + } + + if (access(config_file_.c_str(), R_OK) == -1) { + LOG_ERROR("%s: playback file %s is not readable", + __func__, + config_file_.c_str()); + return false; + } + LOG_INFO("%s: playback file %s is available and readable", + __func__, + config_file_.c_str()); + return true; +} + +bool has_time_elapsed(std::chrono::steady_clock::time_point time_point) { + std::chrono::steady_clock::time_point now = + std::chrono::steady_clock::now(); + if (now > time_point) { + return true; + } else { + return false; + } +} + void ScriptedBeacon::Initialize(const vector& args) { if (args.size() < 2) return; @@ -79,11 +123,41 @@ void ScriptedBeacon::TimerTick() { if (!scanned_once_) { Beacon::TimerTick(); } else { + static std::chrono::steady_clock::time_point next_check_time = + std::chrono::steady_clock::now(); + if (!play_back_on_) { + if (!has_time_elapsed(next_check_time)) { + return; + } + if (!is_config_file_ready()) { + next_check_time = std::chrono::steady_clock::now() + + std::chrono::steady_clock::duration(std::chrono::seconds(1)); + return; + } + // Give time for the file to be written completely before being read + { + static std::chrono::steady_clock::time_point write_delay_next_check_time = + std::chrono::steady_clock::now() + + std::chrono::steady_clock::duration(std::chrono::seconds(1)); + if (!has_time_elapsed(write_delay_next_check_time)) { + return; + } + } + + std::fstream input(config_file_, std::ios::in | std::ios::binary); + if (!ble_ad_list_.ParseFromIstream(&input)) { + LOG_ERROR("%s: Cannot parse playback file %s", __func__, config_file_.c_str()); + return; + } + LOG_INFO("%s: Starting Ble advertisement playback from file: %s", __func__, config_file_.c_str()); + play_back_on_ = true; + get_next_advertisement(); + } std::shared_ptr to_send; std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); elapsed_time_ += now - last_timer_tick_; - while (next_ad_.ad_time < now) { + while (play_back_on_ && !play_back_complete_ && next_ad_.ad_time < now) { auto ad = model::packets::LeAdvertisementBuilder::Create( next_ad_.address, Address::kEmpty /* Destination */, model::packets::AddressType::RANDOM, @@ -113,7 +187,6 @@ void ScriptedBeacon::IncomingPacket( std::move(scan_response); scanned_once_ = true; Address::FromString("12:34:56:78:9A:BC", next_ad_.address); - open_config_file(); for (auto phy : phy_layers_[Phy::Type::LOW_ENERGY]) { phy->Send(to_send); } @@ -122,55 +195,22 @@ void ScriptedBeacon::IncomingPacket( } void ScriptedBeacon::get_next_advertisement() { - next_ad_.address.address[2]++; - /* For more recent versions: - * using bluetooth::hci::GapData; - * using bluetooth::hci::GapDataType; - * GapData flags; - * flags.data_type_ = GapDataType::FLAGS; - * flags.data_ = {0x1A}; - * GapData service; - * service.data_type_ = GapDataType::COMPLETE_LIST_16_BIT_UUIDS; - * service.data_ = {0x6F, 0xFD}; // 0xFD6F Contact Detection Service - * GapData proximity_id; - * proximity_id.data_type = GapDataType::SERVICE_DATA_128_BIT_UUIDS; - * proximity_id.data_ = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - * 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - * }; - */ - // For older/all versions: - next_ad_.ad = { - 0x02, // Size - 0x01, // Flag - 0x1A, - 0x03, // Size - 0x03, // Complete 16-bit Service UUID - 0x6F, - 0xFD, - 0x13, // Size - 0x16, // Service Data - 16 bit UUID - 0x6F, // FD6F - 0xFD, - 0x00, // ID - 0x01, - next_ad_.address.address[2], // make it different from the others - 0x03, - 0x04, - 0x05, - 0x06, - 0x07, - 0x08, - 0x09, - 0x0a, - 0x0b, - 0x0c, - 0x0d, - 0x0e, - 0x0f, - }; -} + static int packet_num = 0; -void ScriptedBeacon::open_config_file() { - // Open the config file and read it all? + if (packet_num < ble_ad_list_.advertisements().size()) { + std::string payload = ble_ad_list_.advertisements(packet_num).payload(); + std::string mac_address = ble_ad_list_.advertisements(packet_num).mac_address(); + uint32_t delay_before_send_ms = + ble_ad_list_.advertisements(packet_num).delay_before_send_ms(); + next_ad_.ad.assign(payload.begin(), payload.end()); + Address::FromString(mac_address, next_ad_.address); + next_ad_.ad_time = std::chrono::steady_clock::now() + + std::chrono::steady_clock::duration( + std::chrono::milliseconds(delay_before_send_ms)); + packet_num++; + } else { + play_back_complete_ = true; + LOG_INFO("%s: Completed Ble advertisement playback from file: %s", __func__, config_file_.c_str()); + } } } // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/model/devices/scripted_beacon.h b/vendor_libs/test_vendor_lib/model/devices/scripted_beacon.h index a7c64e8c7..b9a39a525 100644 --- a/vendor_libs/test_vendor_lib/model/devices/scripted_beacon.h +++ b/vendor_libs/test_vendor_lib/model/devices/scripted_beacon.h @@ -19,10 +19,10 @@ #include #include +#include "model/devices/scripted_beacon_ble_payload.pb.h" #include "beacon.h" namespace test_vendor_lib { - // Pretend to be a lot of beacons by advertising from a file. class ScriptedBeacon : public Beacon { public: @@ -55,7 +55,6 @@ class ScriptedBeacon : public Beacon { std::chrono::steady_clock::duration elapsed_time_{}; std::chrono::steady_clock::time_point last_timer_tick_{}; std::string config_file_{}; - void open_config_file(); struct Advertisement { std::vector ad; Address address; @@ -64,7 +63,14 @@ class ScriptedBeacon : public Beacon { void get_next_advertisement(); + bool is_config_file_ready(); + Advertisement next_ad_{}; -}; + android::bluetooth::test_vendor_lib::model::devices::ScriptedBeaconBleAdProto::BleAdvertisementList ble_ad_list_; + + bool play_back_on_{false}; + + bool play_back_complete_{false}; +}; } // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/model/devices/scripted_beacon_ble_payload.proto b/vendor_libs/test_vendor_lib/model/devices/scripted_beacon_ble_payload.proto new file mode 100644 index 000000000..fd40eb7f0 --- /dev/null +++ b/vendor_libs/test_vendor_lib/model/devices/scripted_beacon_ble_payload.proto @@ -0,0 +1,15 @@ +syntax = "proto2"; + +package android.bluetooth.test_vendor_lib.model.devices.ScriptedBeaconBleAdProto; + +option optimize_for = LITE_RUNTIME; + +message BleAdvertisement { + optional bytes payload = 1; + optional bytes mac_address = 2; + optional uint32 delay_before_send_ms = 3; +} + +message BleAdvertisementList { + repeated BleAdvertisement advertisements = 1; +}