OSDN Git Service

Support for reading playback file in scripted beacon
authorSanjay Ramankandath <sanjayram@google.com>
Fri, 24 Apr 2020 14:40:59 +0000 (14:40 +0000)
committerSanjay Ramankandath <sanjayram@google.com>
Mon, 11 May 2020 14:20:20 +0000 (14:20 +0000)
Bug: 154491371
Tag: #feature
Test: Manual test on cuttlefish
Test: gd/cert/run --host
Change-Id: Ie0ce31796a0c28826002b0677d27e5db075dde6d

test/rootcanal/Android.bp
test/rootcanal/bluetooth_hci.cc
vendor_libs/test_vendor_lib/Android.bp
vendor_libs/test_vendor_lib/model/devices/scripted_beacon.cc
vendor_libs/test_vendor_lib/model/devices/scripted_beacon.h
vendor_libs/test_vendor_lib/model/devices/scripted_beacon_ble_payload.proto [new file with mode: 0644]

index bd62e50..916b53c 100644 (file)
@@ -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",
index 2363ce9..17ae6e7 100644 (file)
 
 #include "bluetooth_hci.h"
 
+#include "log/log.h"
 #include <cutils/properties.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <string.h>
 
 #include "hci_internals.h"
-#include "os/log.h"
 
 namespace android {
 namespace hardware {
@@ -85,7 +85,6 @@ Return<void> BluetoothHci::initialize_impl(
     const sp<V1_0::IBluetoothHciCallbacks>& cb,
     const sp<V1_1::IBluetoothHciCallbacks>& 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<void> 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<BluetoothDeathRecipient>& death_recipient) {
index 70bb092..c3c08d8 100644 (file)
@@ -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",
     ],
 }
index fff377b..490d0df 100644 (file)
  * 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 <fstream>
+#include <cstdint>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/inotify.h>
+
+#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<std::string>& 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<model::packets::LinkLayerPacketBuilder> 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
index a7c64e8..b9a39a5 100644 (file)
 #include <cstdint>
 #include <vector>
 
+#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<uint8_t> 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 (file)
index 0000000..fd40eb7
--- /dev/null
@@ -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;
+}