OSDN Git Service

HAL: Add facade for fetching incoming HCI packets
authorChienyuan <chienyuanhuang@google.com>
Thu, 25 Apr 2019 22:11:54 +0000 (15:11 -0700)
committerHansong Zhang <hsz@google.com>
Mon, 29 Apr 2019 21:22:02 +0000 (14:22 -0700)
Adding the event stream primitives. General event stream request is
defined in facade/common.proto. "grpc/grpc_event_stream.h" provides
helper class templates GrpcEventStreamCallback and GrpcEventStream to
help user handle EventStream request without writing boilerplate code.

Test: cert/run_cert.sh
Change-Id: I00b51fc7b1faefb7c97cc647876f41854872a415

gd/Android.bp
gd/facade/common.proto [new file with mode: 0644]
gd/grpc/grpc_event_stream.h [new file with mode: 0644]
gd/hal/Android.bp
gd/hal/cert/simple_hal_test.cc [deleted file]
gd/hal/cert/simple_hal_test.py
gd/hal/facade/api.proto
gd/hal/facade/facade.cc

index da660ab..3dd849e 100644 (file)
@@ -154,34 +154,6 @@ cc_binary {
 }
 
 cc_test {
-    name: "bluetooth_cert_test",
-    defaults: [
-        "gd_defaults",
-    ],
-    host_supported: true,
-    srcs: [
-        ":BluetoothCertCppClient_hci_hal",
-    ],
-    static_libs : [
-        "libbluetooth_gd",
-    ],
-    shared_libs: [
-        "libgrpc++_unsecure",
-        "libprotobuf-cpp-full",
-    ],
-    generated_headers: [
-        "BluetoothGeneratedPackets_h",
-        "BluetoothCertFacadeGeneratedStub_h",
-    ],
-    generated_sources: [
-        "BluetoothCertFacadeGeneratedStub_cc",
-    ],
-    sanitize: {
-        address: true,
-    },
-}
-
-cc_test {
     name: "bluetooth_test_gd",
     test_suites: ["device-tests"],
     defaults: [
@@ -285,6 +257,7 @@ genrule {
 filegroup {
     name: "BluetoothCertFacadeProto",
     srcs: [
+        "facade/common.proto",
         "hal/facade/api.proto",
     ],
 }
@@ -300,6 +273,8 @@ genrule {
         ":BluetoothCertFacadeProto",
     ],
     out: [
+        "facade/common.grpc.pb.h",
+        "facade/common.pb.h",
         "hal/facade/api.grpc.pb.h",
         "hal/facade/api.pb.h",
     ],
@@ -316,6 +291,8 @@ genrule {
         ":BluetoothCertFacadeProto",
     ],
     out: [
+        "facade/common.grpc.pb.cc",
+        "facade/common.pb.cc",
         "hal/facade/api.grpc.pb.cc",
         "hal/facade/api.pb.cc",
     ],
@@ -329,6 +306,7 @@ genrule {
     ],
     cmd: "$(location aprotoc) -Isystem/bt/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-python-plugin) $(in) --grpc_out=$(genDir) --python_out=$(genDir); " +
         "touch $(genDir)/__init__.py; " +
+        "touch $(genDir)/facade/__init__.py; " +
         "touch $(genDir)/hal/__init__.py; " +
         "touch $(genDir)/hal/facade/__init__.py; ",
     srcs: [
@@ -336,6 +314,9 @@ genrule {
     ],
     out: [
         "__init__.py",
+        "facade/__init__.py",
+        "facade/common_pb2_grpc.py",
+        "facade/common_pb2.py",
         "hal/__init__.py",
         "hal/facade/__init__.py",
         "hal/facade/api_pb2_grpc.py",
diff --git a/gd/facade/common.proto b/gd/facade/common.proto
new file mode 100644 (file)
index 0000000..e3ee429
--- /dev/null
@@ -0,0 +1,20 @@
+syntax = "proto3";
+
+package bluetooth.facade;
+
+enum EventSubscriptionMode {
+  UNCHANGED = 0;
+  SUBSCRIBE = 1;
+  UNSUBSCRIBE = 2;
+}
+
+enum EventFetchMode {
+  NONE = 0;
+  ALL_CURRENT = 1;
+  AT_LEAST_ONE = 2;
+}
+
+message EventStreamRequest {
+  EventSubscriptionMode subscription_mode = 1;
+  EventFetchMode fetch_mode = 2;
+}
diff --git a/gd/grpc/grpc_event_stream.h b/gd/grpc/grpc_event_stream.h
new file mode 100644 (file)
index 0000000..0941ecc
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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 <grpc++/grpc++.h>
+
+#include "common/blocking_queue.h"
+#include "facade/common.pb.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace grpc {
+
+template <typename RES, typename EVENT>
+class GrpcEventStreamCallback {
+ public:
+  virtual ~GrpcEventStreamCallback() = default;
+  virtual void OnSubscribe() {}
+  virtual void OnUnsubscribe() {}
+  virtual void OnWriteResponse(RES* response, const EVENT& event) = 0;
+};
+
+template <typename RES, typename EVENT>
+class GrpcEventStream {
+ public:
+  explicit GrpcEventStream(GrpcEventStreamCallback<RES, EVENT>* callback) : callback_(callback) {}
+
+  void OnIncomingEvent(const EVENT& event) {
+    if (subscribed_) {
+      event_queue_.push(event);
+    }
+  }
+
+  ::grpc::Status HandleRequest(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+                               ::grpc::ServerWriter<RES>* writer) {
+    ::bluetooth::facade::EventSubscriptionMode subscription_mode = request->subscription_mode();
+    ::bluetooth::facade::EventFetchMode fetch_mode = request->fetch_mode();
+
+    if (subscription_mode == ::bluetooth::facade::SUBSCRIBE) {
+      callback_->OnSubscribe();
+      subscribed_ = true;
+    }
+
+    if (fetch_mode == ::bluetooth::facade::AT_LEAST_ONE) {
+      RES response;
+      EVENT event = event_queue_.take();
+      callback_->OnWriteResponse(&response, event);
+      writer->Write(response);
+    }
+
+    // fetch all current remaining items and append to AT_LEAST_ONE query if present
+    if (fetch_mode == ::bluetooth::facade::ALL_CURRENT || fetch_mode == ::bluetooth::facade::AT_LEAST_ONE) {
+      while (!event_queue_.empty()) {
+        RES response;
+        EVENT event = event_queue_.take();
+        callback_->OnWriteResponse(&response, event);
+        writer->Write(response);
+      }
+    }
+
+    if (subscription_mode == ::bluetooth::facade::UNSUBSCRIBE) {
+      subscribed_ = false;
+      event_queue_.clear();
+      callback_->OnUnsubscribe();
+    }
+
+    return ::grpc::Status::OK;
+  }
+
+ private:
+  common::BlockingQueue<EVENT> event_queue_;
+  GrpcEventStreamCallback<RES, EVENT>* callback_;
+  bool subscribed_ = false;
+};
+
+}  // namespace grpc
+}  // namespace bluetooth
index cb4ca82..9e10c2c 100644 (file)
@@ -39,10 +39,3 @@ filegroup {
         "facade/facade.cc",
     ],
 }
-
-filegroup {
-    name: "BluetoothCertCppClient_hci_hal",
-    srcs: [
-        "cert/simple_hal_test.cc",
-    ],
-}
diff --git a/gd/hal/cert/simple_hal_test.cc b/gd/hal/cert/simple_hal_test.cc
deleted file mode 100644 (file)
index 8804a23..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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 <grpc++/grpc++.h>
-#include <gtest/gtest.h>
-
-#include <chrono>
-#include <string>
-#include <thread>
-
-#include "hal/facade/api.grpc.pb.h"
-#include "hci/hci_packets.h"
-#include "os/log.h"
-
-using grpc::ClientContext;
-
-namespace bluetooth {
-namespace hal {
-namespace cert {
-
-using ::bluetooth::hal::facade::HciCmdPacket;
-using ::bluetooth::hal::facade::HciEvtPacket;
-using ::bluetooth::hal::facade::HciTransportation;
-using ::bluetooth::hal::facade::LoopbackModeSettings;
-
-class HalAdapterCertTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    int port = 8899;
-    std::string channel = "localhost:" + std::to_string(port);
-    stub_ = HciTransportation::NewStub(grpc::CreateChannel(channel, grpc::InsecureChannelCredentials()));
-  }
-  void TearDown() override {
-    stub_.reset();
-  }
-
-  std::unique_ptr<HciTransportation::Stub> stub_;
-};
-
-TEST_F(HalAdapterCertTest, enable_loopback_mode) {
-  ClientContext set_loopback_mode_context;
-  LoopbackModeSettings settings;
-  settings.set_enable(true);
-  ::google::protobuf::Empty empty;
-  ::grpc::Status status = stub_->SetLoopbackMode(&set_loopback_mode_context, settings, &empty);
-  EXPECT_EQ(status.ok(), true);
-
-  ClientContext register_hci_evt_context;
-
-  auto reader = stub_->RegisterHciEvt(&register_hci_evt_context, empty);
-
-  auto packet = hci::DisconnectBuilder::Create(2, hci::DisconnectReason::PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED);
-  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
-  hci::BitInserter it(*packet_bytes);
-  packet->Serialize(it);
-
-  std::string payload(packet_bytes->begin(), packet_bytes->end());
-
-  ClientContext send_hci_cmd_context;
-  HciCmdPacket cmd;
-  cmd.set_payload(payload);
-  status = stub_->SendHciCmd(&send_hci_cmd_context, cmd, &empty);
-  EXPECT_EQ(status.ok(), true);
-
-  HciEvtPacket received_packet;
-  reader->Read(&received_packet);
-
-  ClientContext unregister_hci_evt_context;
-
-  status = stub_->UnregisterHciEvt(&unregister_hci_evt_context, empty, &empty);
-  EXPECT_EQ(status.ok(), true);
-
-  //  EXPECT_EQ(reader->Read(&received_packet), false);
-}
-
-}  // namespace cert
-}  // namespace hal
-}  // namespace bluetooth
index f9b4547..8c019ce 100644 (file)
@@ -22,6 +22,7 @@ sys.path.append(os.environ['ANDROID_BUILD_TOP'] + '/system/bt/gd')
 
 from cert.gd_base_test import GdBaseTestClass
 
+from facade import common_pb2
 from hal.facade import api_pb2
 
 class SimpleHalTest(GdBaseTestClass):
@@ -29,3 +30,23 @@ class SimpleHalTest(GdBaseTestClass):
         response = self.gd_devices[0].hal.SetLoopbackMode(api_pb2.LoopbackModeSettings(enable=True))
         print("Response " + str(response))
 
+    def test_fetch_hci_event(self):
+        response = self.gd_devices[0].hal.SetLoopbackMode(api_pb2.LoopbackModeSettings(enable=True))
+
+        request = common_pb2.EventStreamRequest(subscription_mode=common_pb2.SUBSCRIBE,
+                                                fetch_mode=common_pb2.NONE)
+        response = self.gd_devices[0].hal.FetchHciEvent(request)
+
+        inquiry_string = b'\x01\x04\x05\x33\x8b\x9e\x30\x01'
+        response = self.gd_devices[0].hal.SendHciCommand(api_pb2.HciCmdPacket(payload=inquiry_string))
+
+        request = common_pb2.EventStreamRequest(subscription_mode=common_pb2.UNCHANGED,
+                                                fetch_mode=common_pb2.AT_LEAST_ONE)
+        response = self.gd_devices[0].hal.FetchHciEvent(request)
+
+        for event in response:
+            print(event.payload)
+
+        request = common_pb2.EventStreamRequest(subscription_mode=common_pb2.UNSUBSCRIBE,
+                                                fetch_mode=common_pb2.NONE)
+        response = self.gd_devices[0].hal.FetchHciEvent(request)
index 8790467..c49bb1b 100644 (file)
@@ -3,20 +3,19 @@ syntax = "proto3";
 package bluetooth.hal.facade;
 
 import "google/protobuf/empty.proto";
+import "facade/common.proto";
 
 // The HCI HAL transportation layer certification API surface definition
 
 service HciTransportation {
   rpc SetLoopbackMode(LoopbackModeSettings) returns (google.protobuf.Empty) {}
-  rpc SendHciCmd(HciCmdPacket) returns (google.protobuf.Empty) {}
+  rpc SendHciCommand(HciCmdPacket) returns (google.protobuf.Empty) {}
   rpc SendHciAcl(HciAclPacket) returns (google.protobuf.Empty) {}
   rpc SendHciSco(HciScoPacket) returns (google.protobuf.Empty) {}
-  rpc RegisterHciEvt(google.protobuf.Empty) returns (stream HciEvtPacket) {}
-  rpc RegisterHciAcl(google.protobuf.Empty) returns (stream HciAclPacket) {}
-  rpc RegisterHciSco(google.protobuf.Empty) returns (stream HciScoPacket) {}
-  rpc UnregisterHciEvt(google.protobuf.Empty) returns (google.protobuf.Empty) {}
-  rpc UnregisterHciAcl(google.protobuf.Empty) returns (google.protobuf.Empty) {}
-  rpc UnregisterHciSco(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+
+  rpc FetchHciEvent(bluetooth.facade.EventStreamRequest) returns (stream HciEvtPacket) {}
+  rpc FetchHciAcl(bluetooth.facade.EventStreamRequest) returns (stream HciAclPacket) {}
+  rpc FetchHciSco(bluetooth.facade.EventStreamRequest) returns (stream HciScoPacket) {}
 }
 
 message LoopbackModeSettings {
index 815ff8f..32d7e0b 100644 (file)
@@ -18,9 +18,9 @@
 
 #include <memory>
 #include <mutex>
-#include <thread>
 
-#include "grpc/async_grpc.h"
+#include "common/blocking_queue.h"
+#include "grpc/grpc_event_stream.h"
 #include "hal/facade/api.grpc.pb.h"
 #include "hal/hci_hal.h"
 #include "hci/hci_packets.h"
@@ -39,8 +39,9 @@ class HciTransportationService
     : public HciTransportation::Service,
       public ::bluetooth::hal::HciHalCallbacks {
  public:
-  HciTransportationService(HciHal* hal) : hal_(hal) {
-  }
+  HciTransportationService(HciHal* hal)
+      : hal_(hal), hci_event_stream_(&hci_event_stream_callback_), hci_acl_stream_(&hci_acl_stream_callback_),
+        hci_sco_stream_(&hci_sco_stream_callback_) {}
 
   ::grpc::Status SetLoopbackMode(::grpc::ServerContext* context,
                                  const ::bluetooth::hal::facade::LoopbackModeSettings* request,
@@ -55,8 +56,8 @@ class HciTransportationService
     return ::grpc::Status::OK;
   }
 
-  ::grpc::Status SendHciCmd(::grpc::ServerContext* context, const ::bluetooth::hal::facade::HciCmdPacket* request,
-                            ::google::protobuf::Empty* response) override {
+  ::grpc::Status SendHciCommand(::grpc::ServerContext* context, const ::bluetooth::hal::facade::HciCmdPacket* request,
+                                ::google::protobuf::Empty* response) override {
     std::string req_string = request->payload();
     hal_->sendHciCommand(std::vector<uint8_t>(req_string.begin(), req_string.end()));
     return ::grpc::Status::OK;
@@ -76,19 +77,61 @@ class HciTransportationService
     return ::grpc::Status::OK;
   }
 
+  ::grpc::Status FetchHciEvent(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+                               ::grpc::ServerWriter<HciEvtPacket>* writer) override {
+    return hci_event_stream_.HandleRequest(context, request, writer);
+  };
+
+  ::grpc::Status FetchHciAcl(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+                             ::grpc::ServerWriter<HciAclPacket>* writer) override {
+    return hci_acl_stream_.HandleRequest(context, request, writer);
+  };
+
+  ::grpc::Status FetchHciSco(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+                             ::grpc::ServerWriter<HciScoPacket>* writer) override {
+    return hci_sco_stream_.HandleRequest(context, request, writer);
+  };
+
   void hciEventReceived(bluetooth::hal::HciPacket event) override {
-    // TODO
+    std::string response_str = std::string(event.begin(), event.end());
+    hci_event_stream_.OnIncomingEvent(event);
   }
 
   void aclDataReceived(bluetooth::hal::HciPacket data) override {
-    // TODO
+    hci_acl_stream_.OnIncomingEvent(data);
   }
 
   void scoDataReceived(bluetooth::hal::HciPacket data) override {
-    // TODO
+    hci_sco_stream_.OnIncomingEvent(data);
   }
+
  private:
   HciHal* hal_;
+
+  class HciEventStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciEvtPacket, HciPacket> {
+   public:
+    void OnWriteResponse(HciEvtPacket* response, const HciPacket& event) override {
+      std::string response_str = std::string(event.begin(), event.end());
+      response->set_payload(std::string(event.begin(), event.end()));
+    }
+  } hci_event_stream_callback_;
+  ::bluetooth::grpc::GrpcEventStream<HciEvtPacket, HciPacket> hci_event_stream_;
+
+  class HciAclStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciAclPacket, HciPacket> {
+   public:
+    void OnWriteResponse(HciAclPacket* response, const HciPacket& event) override {
+      response->set_payload(std::string(event.begin(), event.end()));
+    }
+  } hci_acl_stream_callback_;
+  ::bluetooth::grpc::GrpcEventStream<HciAclPacket, HciPacket> hci_acl_stream_;
+
+  class HciScoStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciScoPacket, HciPacket> {
+   public:
+    void OnWriteResponse(HciScoPacket* response, const HciPacket& event) override {
+      response->set_payload(std::string(event.begin(), event.end()));
+    }
+  } hci_sco_stream_callback_;
+  ::bluetooth::grpc::GrpcEventStream<HciScoPacket, HciPacket> hci_sco_stream_;
 };
 
 void HalFacadeModule::ListDependencies(ModuleList* list) {