OSDN Git Service

Add timer capability for shim stack
authorChris Manton <cmanton@google.com>
Mon, 16 Dec 2019 20:36:08 +0000 (12:36 -0800)
committerChris Manton <cmanton@google.com>
Wed, 18 Dec 2019 18:32:08 +0000 (10:32 -0800)
The le advertising and scanning features
require timers to stop functionality after the
requested interval.

Bug: 146367779
Test: bluetooth_legacy_test
Change-Id: If7223eaff30785c661bca7f90d94462772d576bc

main/shim/Android.bp
main/shim/stub/osi.cc
main/shim/timer.cc [new file with mode: 0644]
main/shim/timer.h [new file with mode: 0644]
main/shim/timer_test.cc [new file with mode: 0644]

index 62d8f98..1672063 100644 (file)
@@ -9,6 +9,7 @@ filegroup {
         "l2c_api.cc",
         "l2cap.cc",
         "shim.cc",
+        "timer.cc",
     ]
 }
 
@@ -16,6 +17,7 @@ filegroup {
     name: "LibBluetoothShimTestSources",
     srcs: [
         "l2cap_test.cc",
+        "timer_test.cc",
     ]
 }
 
index 34e29b6..96675d4 100644 (file)
 #include "main/shim/stub/osi.h"
 #include "osi/include/alarm.h"
 
-bool osi_property_get_int32(char const* n, int a) { return true; }
-
-const module_t* get_module(const char*) { return nullptr; };
-bool module_init(module_t const*) { return true; };
-void module_clean_up(module_t const*){};
+bool module_init(module_t const*) { return true; }
+bool module_start_up(module_t const*) { return true; }
+const module_t* get_module(const char*) { return nullptr; }
+void module_clean_up(module_t const*) {}
+void module_shut_down(module_t const*) {}
 
 void* osi_alloc(size_t size) { return malloc(size); }
 void* osi_calloc(size_t size) { return calloc(1, size); }
diff --git a/main/shim/timer.cc b/main/shim/timer.cc
new file mode 100644 (file)
index 0000000..7e21deb
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "bt_shim_timer"
+
+#include <base/bind.h>
+#include <cstdint>
+#include <functional>
+
+#include "main/shim/shim.h"
+#include "main/shim/timer.h"
+#include "osi/include/alarm.h"
+#include "osi/include/log.h"
+
+static void timer_timeout(void* data) {
+  CHECK(data != nullptr);
+  bluetooth::shim::Timer* timeout = static_cast<bluetooth::shim::Timer*>(data);
+  bluetooth::shim::Post(
+      base::Bind(&bluetooth::shim::Timer::Pop, base::Unretained(timeout)));
+}
+
+void bluetooth::shim::Timer::Set(uint64_t duration_ms,
+                                 std::function<void()> func) {
+  CHECK(duration_ms != 0);
+  callback_ = func;
+  alarm_set_on_mloop(timer_, duration_ms, timer_timeout, (void*)this);
+}
+
+void bluetooth::shim::Timer::Cancel() {
+  alarm_cancel(timer_);
+  callback_ = {};
+}
+
+bool bluetooth::shim::Timer::IsActive() { return callback_ != nullptr; }
+
+bluetooth::shim::Timer::Timer(const char* name) {
+  timer_ = alarm_new(name);
+  CHECK(timer_ != nullptr);
+}
+
+bluetooth::shim::Timer::~Timer() { alarm_free(timer_); }
+
+void bluetooth::shim::Timer::Pop(Timer* timer) {
+  timer->callback_();
+  timer->callback_ = {};
+}
diff --git a/main/shim/timer.h b/main/shim/timer.h
new file mode 100644 (file)
index 0000000..16d35c4
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <functional>
+#include "osi/include/alarm.h"
+
+namespace bluetooth {
+namespace shim {
+
+class Timer {
+ public:
+  /**
+   * Set this timer using the osi timer alarm functionality.
+   *
+   * The alarm duration *must not* be zero.  The timer is set
+   * on the bluetooth main message loop thread.
+   *
+   * @param duration_ms Duration in milliseconds (>0) before alarm pops
+   * @param func Function to execute upon alarm pop.
+   */
+  void Set(uint64_t duration_ms, std::function<void()> func);
+
+  /**
+   * Cancel this previously set timer.
+   *
+   * The associated function call will *not* be executed.
+   */
+  void Cancel();
+
+  /**
+   * Determine if a given timer has been set or not.
+   *
+   * @return |true| if timer has been set, |false| otherwise.
+   */
+  bool IsActive();
+
+  /**
+   * @param name Arbitrary name passed to the osi module.
+   */
+  Timer(const char* name);
+  ~Timer();
+
+  /**
+   * Pop this timer.
+   *
+   * Called from an internal trampoline timeout global function registered
+   * with osi alarm.  This trampoline function will then post
+   * the execution of the callback function onto the shim thread.
+   */
+  static void Pop(Timer* timer);
+
+ private:
+  std::function<void()> callback_{};
+  alarm_t* timer_{nullptr};
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/main/shim/timer_test.cc b/main/shim/timer_test.cc
new file mode 100644 (file)
index 0000000..1d83eb9
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <cstdint>
+#include <future>
+
+#define LOG_TAG "bt_shim_test"
+
+#include <base/logging.h>
+#include "osi/include/log.h"
+#include "shim/timer.h"
+#include "stub/osi.h"
+
+#include <stdlib.h>
+
+namespace bluetooth {
+namespace legacy {
+
+constexpr uint64_t kDurationMs = 3;
+
+static const char* kTimer0 = "TestTimer00";
+static const char* kTimer1 = "TestTimer01";
+
+namespace {
+
+class TimerTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Ensure expected global state default initial conditions
+    bluetooth::shim::stub::name_to_alarm_map_.clear();
+  }
+
+  void TearDown() override {
+    // Reset global state to defaults
+    bluetooth::shim::stub::name_to_alarm_map_.clear();
+  }
+};
+
+TEST_F(TimerTest, Set) {
+  std::promise<void> promise;
+  auto future = promise.get_future();
+
+  shim::Timer* timer = new shim::Timer(kTimer0);
+
+  timer->Set(kDurationMs, [&promise]() { promise.set_value(); });
+
+  CHECK(bluetooth::shim::stub::alarm_is_set(kTimer0) == true);
+  CHECK(bluetooth::shim::stub::alarm_interval_ms(kTimer0) == kDurationMs);
+  CHECK(bluetooth::shim::stub::alarm_data(kTimer0));
+
+  {
+    shim::Timer* timer =
+        static_cast<shim::Timer*>(bluetooth::shim::stub::alarm_data(kTimer0));
+    bluetooth::shim::Timer::Pop(timer);
+  }
+  future.wait();
+
+  delete timer;
+  CHECK(bluetooth::shim::stub::name_to_alarm_map_.empty());
+}
+
+TEST_F(TimerTest, Set2) {
+  std::promise<void> promise0;
+  std::promise<void> promise1;
+  auto future0 = promise0.get_future();
+  auto future1 = promise1.get_future();
+
+  shim::Timer* timer0 = new shim::Timer(kTimer0);
+  CHECK(bluetooth::shim::stub::name_to_alarm_map_.size() == 1);
+
+  shim::Timer* timer1 = new shim::Timer(kTimer1);
+  CHECK(bluetooth::shim::stub::name_to_alarm_map_.size() == 2);
+
+  timer0->Set(kDurationMs, [&promise0]() { promise0.set_value(); });
+
+  timer1->Set(kDurationMs * 2, [&promise1]() { promise1.set_value(); });
+
+  CHECK(bluetooth::shim::stub::alarm_is_set(kTimer0) == true);
+  CHECK(bluetooth::shim::stub::alarm_interval_ms(kTimer0) == kDurationMs);
+  CHECK(bluetooth::shim::stub::alarm_data(kTimer0));
+
+  CHECK(bluetooth::shim::stub::alarm_is_set(kTimer1) == true);
+  CHECK(bluetooth::shim::stub::alarm_interval_ms(kTimer1) == kDurationMs * 2);
+  CHECK(bluetooth::shim::stub::alarm_data(kTimer1));
+
+  {
+    shim::Timer* timer =
+        static_cast<shim::Timer*>(bluetooth::shim::stub::alarm_data(kTimer0));
+    bluetooth::shim::Timer::Pop(timer);
+  }
+
+  {
+    shim::Timer* timer =
+        static_cast<shim::Timer*>(bluetooth::shim::stub::alarm_data(kTimer1));
+    bluetooth::shim::Timer::Pop(timer);
+  }
+
+  future0.wait();
+  future1.wait();
+
+  delete timer0;
+  delete timer1;
+
+  CHECK(bluetooth::shim::stub::name_to_alarm_map_.empty());
+}
+
+TEST_F(TimerTest, Cancel) {
+  std::promise<void> promise;
+  auto future = promise.get_future();
+
+  shim::Timer* timer = new shim::Timer(kTimer0);
+
+  timer->Set(kDurationMs, [&promise]() { promise.set_value(); });
+
+  CHECK(bluetooth::shim::stub::alarm_is_set(kTimer0) == true);
+  CHECK(bluetooth::shim::stub::alarm_interval_ms(kTimer0) == kDurationMs);
+  CHECK(bluetooth::shim::stub::alarm_data(kTimer0));
+
+  timer->Cancel();
+
+  CHECK(bluetooth::shim::stub::alarm_is_set(kTimer0) == false);
+  CHECK(bluetooth::shim::stub::alarm_interval_ms(kTimer0) == 0);
+  CHECK(bluetooth::shim::stub::alarm_data(kTimer0) == nullptr);
+
+  delete timer;
+  CHECK(bluetooth::shim::stub::name_to_alarm_map_.empty());
+}
+
+}  // namespace
+}  // namespace legacy
+}  // namespace bluetooth