Merge "Remove PowerHAL 1.0 from device manifest"
diff --git a/guest/hals/ril/libril/ril_service.cpp b/guest/hals/ril/libril/ril_service.cpp
index 43ccc6f..7349845 100755
--- a/guest/hals/ril/libril/ril_service.cpp
+++ b/guest/hals/ril/libril/ril_service.cpp
@@ -558,6 +558,7 @@
             bool preferredForEmergencyCall);
     Return<void> setIndicationFilter_1_5(int32_t serial,
             hidl_bitfield<::android::hardware::radio::V1_5::IndicationFilter> indicationFilter);
+    Return<void> getBarringInfo(int32_t serial);
 };
 
 struct OemHookImpl : public IOemHook {
@@ -3775,6 +3776,14 @@
     return Void();
 }
 
+Return<void> RadioImpl_1_5::getBarringInfo(int32_t /* serial */) {
+    // TODO implement
+#if VDBG
+    RLOGE("[%04d]< %s", serial, "Method is not implemented");
+#endif
+    return Void();
+}
+
 // OEM hook methods:
 Return<void> OemHookImpl::setResponseFunctions(
         const ::android::sp<IOemHookResponse>& oemHookResponseParam,
@@ -8141,6 +8150,28 @@
     return 0;
 }
 
+int radio_1_5::getBarringInfoResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responselen) {
+#if VDBG
+    RLOGD("getBarringInfoResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        hidl_vec<::android::hardware::radio::V1_5::BarringInfo> barringInfo;
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponseV1_5->
+                        getBarringInfoResponse(responseInfo, barringInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getBarringInfoResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
 
 /***************************************************************************************************
  * INDICATION FUNCTIONS
@@ -9963,7 +9994,7 @@
         RLOGD("registerService: starting android::hardware::radio::V1_5::IRadio %s for slot %d",
                 serviceNames[i], i);
         android::status_t status = radioService[i]->registerAsService(serviceNames[i]);
-        assert(status == android::OK);
+        LOG_ALWAYS_FATAL_IF(status != android::OK, "status %d", status);
 
         RLOGD("registerService: OemHook is enabled = %s", kOemHookEnabled ? "true" : "false");
         if (kOemHookEnabled) {
diff --git a/guest/hals/ril/libril/ril_service.h b/guest/hals/ril/libril/ril_service.h
index 98ebfa2..7807004 100644
--- a/guest/hals/ril/libril/ril_service.h
+++ b/guest/hals/ril/libril/ril_service.h
@@ -804,6 +804,9 @@
 int setIndicationFilterResponse_1_5(int slotId, int responseType, int serial, RIL_Errno e,
                               void *response, size_t responselen);
 
+int getBarringInfoResponse(int slotId, int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responselen);
+
 pthread_rwlock_t * getRadioServiceRwlock(int slotId);
 
 void setNitzTimeReceived(int slotId, long timeReceived);
diff --git a/host/frontend/gcastv2/libsource/Android.bp b/host/frontend/gcastv2/libsource/Android.bp
index 569c1c7..671e4ba 100644
--- a/host/frontend/gcastv2/libsource/Android.bp
+++ b/host/frontend/gcastv2/libsource/Android.bp
@@ -16,6 +16,8 @@
     name: "libsource",
     srcs: [
         "AudioSource.cpp",
+        "InputSink.cpp",
+        "KeyboardSink.cpp",
         "TouchSink.cpp",
         "FrameBufferSource.cpp",
         "HostToGuestComms.cpp",
diff --git a/host/frontend/gcastv2/libsource/InputSink.cpp b/host/frontend/gcastv2/libsource/InputSink.cpp
new file mode 100644
index 0000000..e673358
--- /dev/null
+++ b/host/frontend/gcastv2/libsource/InputSink.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 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 <source/InputSink.h>
+
+#include <linux/input.h>
+
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <glog/logging.h>
+#include <https/SafeCallbackable.h>
+#include <https/Support.h>
+
+namespace android {
+
+namespace {
+
+// TODO de-dup this from vnc server and here
+struct virtio_input_event {
+  uint16_t type;
+  uint16_t code;
+  int32_t value;
+};
+
+template <typename T>
+struct InputEventBufferImpl : public InputEventBuffer {
+  InputEventBufferImpl() {
+    buffer_.reserve(6);  // 6 is usually enough even for multi-touch
+  }
+  void addEvent(uint16_t type, uint16_t code, int32_t value) override {
+    buffer_.push_back({.type = type, .code = code, .value = value});
+  }
+  T* data() { return buffer_.data(); }
+  const void* data() const override { return buffer_.data(); }
+  std::size_t size() const override { return buffer_.size() * sizeof(T); }
+
+ private:
+  std::vector<T> buffer_;
+};
+
+}  // namespace
+
+InputSink::InputSink(std::shared_ptr<RunLoop> runLoop, int serverFd,
+                     bool write_virtio_input)
+    : mRunLoop(runLoop),
+      mServerFd(serverFd),
+      mClientFd(-1),
+      mSendPending(false),
+      mWriteVirtioInput(write_virtio_input) {
+  if (mServerFd >= 0) {
+    makeFdNonblocking(mServerFd);
+  }
+}
+
+InputSink::~InputSink() {
+  if (mClientFd >= 0) {
+    mRunLoop->cancelSocket(mClientFd);
+
+    close(mClientFd);
+    mClientFd = -1;
+  }
+
+  if (mServerFd >= 0) {
+    mRunLoop->cancelSocket(mServerFd);
+
+    close(mServerFd);
+    mServerFd = -1;
+  }
+}
+
+void InputSink::start() {
+  if (mServerFd < 0) {
+    return;
+  }
+
+  mRunLoop->postSocketRecv(
+      mServerFd, makeSafeCallback(this, &InputSink::onServerConnection));
+}
+
+std::unique_ptr<InputEventBuffer> InputSink::getEventBuffer() const {
+  InputEventBuffer* raw_ptr;
+  if (mWriteVirtioInput) {
+    raw_ptr = new InputEventBufferImpl<virtio_input_event>();
+  } else {
+    raw_ptr = new InputEventBufferImpl<input_event>();
+  }
+  return std::unique_ptr<InputEventBuffer>(raw_ptr);
+}
+
+void InputSink::SendEvents(std::unique_ptr<InputEventBuffer> evt_buffer) {
+  sendRawEvents(evt_buffer->data(), evt_buffer->size());
+}
+
+void InputSink::onServerConnection() {
+  int s = accept(mServerFd, nullptr, nullptr);
+
+  if (s >= 0) {
+    if (mClientFd >= 0) {
+      LOG(INFO) << "Rejecting client, we already have one.";
+
+      // We already have a client.
+      close(s);
+      s = -1;
+    } else {
+      LOG(INFO) << "Accepted client socket " << s << ".";
+
+      makeFdNonblocking(s);
+
+      mClientFd = s;
+    }
+  }
+
+  mRunLoop->postSocketRecv(
+      mServerFd, makeSafeCallback(this, &InputSink::onServerConnection));
+}
+
+void InputSink::sendRawEvents(const void* evt_buffer, size_t size) {
+  if (size <= 0) return;
+
+  std::lock_guard autoLock(mLock);
+
+  if (mClientFd < 0) {
+    return;
+  }
+
+  size_t offset = mOutBuffer.size();
+  mOutBuffer.resize(offset + size);
+  memcpy(mOutBuffer.data() + offset, evt_buffer, size);
+
+  if (!mSendPending) {
+    mSendPending = true;
+
+    mRunLoop->postSocketSend(mClientFd,
+                             makeSafeCallback(this, &InputSink::onSocketSend));
+  }
+}
+
+void InputSink::onSocketSend() {
+  std::lock_guard autoLock(mLock);
+
+  CHECK(mSendPending);
+  mSendPending = false;
+
+  if (mClientFd < 0) {
+    return;
+  }
+
+  ssize_t n;
+  while (!mOutBuffer.empty()) {
+    do {
+      n = ::send(mClientFd, mOutBuffer.data(), mOutBuffer.size(), 0);
+    } while (n < 0 && errno == EINTR);
+
+    if (n <= 0) {
+      break;
+    }
+
+    mOutBuffer.erase(mOutBuffer.begin(), mOutBuffer.begin() + n);
+  }
+
+  if ((n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) || n == 0) {
+    LOG(ERROR) << "Client is gone.";
+
+    // Client is gone.
+    mRunLoop->cancelSocket(mClientFd);
+
+    close(mClientFd);
+    mClientFd = -1;
+    return;
+  }
+
+  if (!mOutBuffer.empty()) {
+    mSendPending = true;
+    mRunLoop->postSocketSend(mClientFd,
+                             makeSafeCallback(this, &InputSink::onSocketSend));
+  }
+}
+
+}  // namespace android
diff --git a/host/frontend/gcastv2/libsource/KeyboardSink.cpp b/host/frontend/gcastv2/libsource/KeyboardSink.cpp
new file mode 100644
index 0000000..526ade3
--- /dev/null
+++ b/host/frontend/gcastv2/libsource/KeyboardSink.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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 <source/KeyboardSink.h>
+
+#include <linux/input.h>
+
+#include <glog/logging.h>
+
+namespace android {
+
+KeyboardSink::KeyboardSink(std::shared_ptr<RunLoop> runLoop, int serverFd,
+                           bool write_virtio_input)
+    : sink_(
+          std::make_shared<InputSink>(runLoop, serverFd, write_virtio_input)) {}
+
+void KeyboardSink::injectEvent(bool down, uint16_t code) {
+    LOG(VERBOSE)
+        << "Received keyboard (down="
+        << down
+        << ", code="
+        << code;
+    auto buffer = sink_->getEventBuffer();
+    buffer->addEvent(EV_KEY, code, down);
+    buffer->addEvent(EV_SYN, 0, 0);
+    sink_->SendEvents(std::move(buffer));
+}
+
+}  // namespace android
+
diff --git a/host/frontend/gcastv2/libsource/TouchSink.cpp b/host/frontend/gcastv2/libsource/TouchSink.cpp
index dc0c309..a66744f 100644
--- a/host/frontend/gcastv2/libsource/TouchSink.cpp
+++ b/host/frontend/gcastv2/libsource/TouchSink.cpp
@@ -22,130 +22,18 @@
 #include <android-base/logging.h>
 
 #include <linux/input.h>
-#include <linux/uinput.h>
 
 #include <sys/socket.h>
 #include <unistd.h>
 
 namespace android {
 
-namespace {
-// TODO de-dup this from vnc server and here
-struct virtio_input_event {
-  uint16_t type;
-  uint16_t code;
-  int32_t value;
-};
-
-template <typename T>
-void SendEvent(int32_t x, int32_t y, int32_t down,
-               std::function<void(const void*, size_t)> sender) {
-  std::vector<T> events = {{.type = EV_ABS, .code = ABS_X, .value = x},
-                           {.type = EV_ABS, .code = ABS_Y, .value = y},
-                           {.type = EV_KEY, .code = BTN_TOUCH, .value = down},
-                           {.type = EV_SYN, .code = 0, .value = 0}};
-  sender(events.data(), events.size() * sizeof(T));
-}
-
-template <typename T>
-void SendMTEvent(int32_t /* id */, int32_t x, int32_t y, int32_t initial_down,
-                 int32_t /* slot */,
-                 std::function<void(const void*, size_t)> sender) {
-  // TODO(b/124121375): multitouch
-  SendEvent<T>(x, y, initial_down, sender);
-}
-}
-
 TouchSink::TouchSink(std::shared_ptr<RunLoop> runLoop, int serverFd,
                      bool write_virtio_input)
-    : mRunLoop(runLoop),
-      mServerFd(serverFd),
-      mClientFd(-1),
-      mSendPending(false) {
-  if (mServerFd >= 0) {
-    makeFdNonblocking(mServerFd);
-  }
-  if (write_virtio_input) {
-    send_event_ = [this](int32_t x, int32_t y, bool down) {
-      SendEvent<virtio_input_event>(
-          x, y, down, [this](const void* b, size_t l) { sendRawEvents(b, l); });
-    };
-    send_mt_event_ = [this](int32_t id, int32_t x, int32_t y, bool initialDown,
-                            int32_t slot) {
-      SendMTEvent<virtio_input_event>(
-          id, x, y, initialDown, slot,
-          [this](const void* b, size_t l) { sendRawEvents(b, l); });
-    };
-  } else {
-    send_event_ = [this](int32_t x, int32_t y, bool down) {
-      SendEvent<input_event>(
-          x, y, down, [this](const void* b, size_t l) { sendRawEvents(b, l); });
-    };
-    send_mt_event_ = [this](int32_t id, int32_t x, int32_t y, bool initialDown,
-                            int32_t slot) {
-      SendMTEvent<input_event>(
-          id, x, y, initialDown, slot,
-          [this](const void* b, size_t l) { sendRawEvents(b, l); });
-    };
-  }
-}
+    : sink_(
+          std::make_shared<InputSink>(runLoop, serverFd, write_virtio_input)) {}
 
-TouchSink::~TouchSink() {
-    if (mClientFd >= 0) {
-        mRunLoop->cancelSocket(mClientFd);
-
-        close(mClientFd);
-        mClientFd = -1;
-    }
-
-    if (mServerFd >= 0) {
-        mRunLoop->cancelSocket(mServerFd);
-
-        close(mServerFd);
-        mServerFd = -1;
-    }
-}
-
-void TouchSink::start() {
-    if (mServerFd < 0) {
-        return;
-    }
-
-    mRunLoop->postSocketRecv(
-            mServerFd,
-            makeSafeCallback(this, &TouchSink::onServerConnection));
-}
-
-void TouchSink::onServerConnection() {
-    int s = accept(mServerFd, nullptr, nullptr);
-
-    if (s >= 0) {
-        if (mClientFd >= 0) {
-            LOG(INFO) << "Rejecting client, we already have one.";
-
-            // We already have a client.
-            close(s);
-            s = -1;
-        } else {
-            LOG(INFO) << "Accepted client socket " << s << ".";
-
-            makeFdNonblocking(s);
-
-            mClientFd = s;
-        }
-    }
-
-    mRunLoop->postSocketRecv(
-            mServerFd,
-            makeSafeCallback(this, &TouchSink::onServerConnection));
-}
-
-
-void TouchSink::onAccessUnit(const std::shared_ptr<InputEvent> &accessUnit) {
-    bool down = accessUnit->down != 0;
-    int x = accessUnit->x;
-    int y = accessUnit->y;
-
+void TouchSink::injectTouchEvent(int32_t x, int32_t y, bool down) {
     LOG(VERBOSE)
         << "Received touch (down="
         << down
@@ -154,71 +42,18 @@
         << ", y="
         << y;
 
-    send_event_(x, y, down);
+    auto buffer = sink_->getEventBuffer();
+    buffer->addEvent(EV_ABS, ABS_X, x);
+    buffer->addEvent(EV_ABS, ABS_Y, y);
+    buffer->addEvent(EV_KEY, BTN_TOUCH, down);
+    buffer->addEvent(EV_SYN, 0, 0);
+    sink_->SendEvents(std::move(buffer));
 }
 
-void TouchSink::sendRawEvents(const void* evt_buffer, size_t size) {
-    if (size <= 0) return;
-
-    std::lock_guard autoLock(mLock);
-
-    if (mClientFd < 0) {
-        return;
-    }
-
-    size_t offset = mOutBuffer.size();
-    mOutBuffer.resize(offset + size);
-    memcpy(mOutBuffer.data() + offset, evt_buffer, size);
-
-    if (!mSendPending) {
-        mSendPending = true;
-
-        mRunLoop->postSocketSend(
-                mClientFd,
-                makeSafeCallback(this, &TouchSink::onSocketSend));
-    }
-}
-
-void TouchSink::onSocketSend() {
-    std::lock_guard autoLock(mLock);
-
-    CHECK(mSendPending);
-    mSendPending = false;
-
-    if (mClientFd < 0) {
-        return;
-    }
-
-    ssize_t n;
-    while (!mOutBuffer.empty()) {
-        do {
-            n = ::send(mClientFd, mOutBuffer.data(), mOutBuffer.size(), 0);
-        } while (n < 0 && errno == EINTR);
-
-        if (n <= 0) {
-            break;
-        }
-
-        mOutBuffer.erase(mOutBuffer.begin(), mOutBuffer.begin() + n);
-    }
-
-    if ((n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) || n == 0) {
-        LOG(ERROR) << "Client is gone.";
-
-        // Client is gone.
-        mRunLoop->cancelSocket(mClientFd);
-
-        close(mClientFd);
-        mClientFd = -1;
-        return;
-    }
-
-    if (!mOutBuffer.empty()) {
-        mSendPending = true;
-        mRunLoop->postSocketSend(
-                mClientFd,
-                makeSafeCallback(this, &TouchSink::onSocketSend));
-    }
+void TouchSink::injectMultiTouchEvent(int32_t /*id*/, int32_t /*slot*/,
+                                      int32_t x, int32_t y, bool initialDown) {
+  // TODO (muntsinger): Enable multitouch
+  return injectTouchEvent(x, y, initialDown);
 }
 
 }  // namespace android
diff --git a/host/frontend/gcastv2/libsource/include/source/InputSink.h b/host/frontend/gcastv2/libsource/include/source/InputSink.h
new file mode 100644
index 0000000..ba5af91
--- /dev/null
+++ b/host/frontend/gcastv2/libsource/include/source/InputSink.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 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 <array>
+#include <cinttypes>
+#include <functional>
+#include <memory>
+#include <vector>
+
+#include <https/RunLoop.h>
+
+namespace android {
+
+struct InputEventBuffer {
+  virtual ~InputEventBuffer() = default;
+  virtual void addEvent(uint16_t type, uint16_t code, int32_t value) = 0;
+  virtual size_t size() const = 0;
+  virtual const void* data() const = 0;
+};
+
+struct InputSink : public std::enable_shared_from_this<InputSink> {
+  explicit InputSink(std::shared_ptr<RunLoop> runLoop, int serverFd,
+                     bool write_virtio_input);
+  ~InputSink();
+  void start();
+
+  std::unique_ptr<InputEventBuffer> getEventBuffer() const;
+  void SendEvents(std::unique_ptr<InputEventBuffer> evt_buffer);
+
+ private:
+  std::shared_ptr<RunLoop> mRunLoop;
+  int mServerFd;
+
+  int mClientFd;
+
+  std::mutex mLock;
+  std::vector<uint8_t> mOutBuffer;
+  bool mSendPending;
+  bool mWriteVirtioInput;
+
+  void onServerConnection();
+  void onSocketSend();
+
+  void sendRawEvents(const void* evt_buffer, size_t length);
+};
+
+}  // namespace android
diff --git a/host/frontend/gcastv2/libsource/include/source/StreamingSink.h b/host/frontend/gcastv2/libsource/include/source/KeyboardSink.h
similarity index 60%
rename from host/frontend/gcastv2/libsource/include/source/StreamingSink.h
rename to host/frontend/gcastv2/libsource/include/source/KeyboardSink.h
index 2d308be..cbc9936 100644
--- a/host/frontend/gcastv2/libsource/include/source/StreamingSink.h
+++ b/host/frontend/gcastv2/libsource/include/source/KeyboardSink.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -19,21 +19,22 @@
 #include <cinttypes>
 #include <memory>
 
+#include <https/RunLoop.h>
+#include <source/InputSink.h>
+
 namespace android {
 
-// TODO(jemoreira): add support for multitouch
-struct InputEvent{
-    InputEvent(int32_t down, int32_t x, int32_t y) : down(down), x(x), y(y) {}
-    int32_t down;
-    int32_t x;
-    int32_t y;
-};
+struct KeyboardSink {
+  explicit KeyboardSink(std::shared_ptr<RunLoop> runLoop, int serverFd,
+                        bool write_virtio_input);
+  ~KeyboardSink() = default;
 
-struct StreamingSink {
-    explicit StreamingSink() = default;
-    virtual ~StreamingSink() = default;
+  void start() {sink_->start();}
 
-    virtual void onAccessUnit(const std::shared_ptr<InputEvent> &accessUnit) = 0;
+  void injectEvent(bool down, uint16_t code);
+
+ private:
+  std::shared_ptr<InputSink> sink_;
 };
 
 }  // namespace android
diff --git a/host/frontend/gcastv2/libsource/include/source/TouchSink.h b/host/frontend/gcastv2/libsource/include/source/TouchSink.h
index 048b523..d4490f0 100644
--- a/host/frontend/gcastv2/libsource/include/source/TouchSink.h
+++ b/host/frontend/gcastv2/libsource/include/source/TouchSink.h
@@ -17,41 +17,26 @@
 #pragma once
 
 #include <https/RunLoop.h>
-#include <source/StreamingSink.h>
 
-#include <functional>
 #include <memory>
-#include <vector>
+
+#include <source/InputSink.h>
 
 namespace android {
 
-struct TouchSink
-    : public StreamingSink, public std::enable_shared_from_this<TouchSink> {
+struct TouchSink {
     explicit TouchSink(std::shared_ptr<RunLoop> runLoop, int serverFd,
                        bool write_virtio_input);
-    ~TouchSink() override;
+    ~TouchSink() = default;
 
-    void start();
+    void start() {sink_->start();}
 
-    void onAccessUnit(const std::shared_ptr<InputEvent> &accessUnit) override;
+    void injectTouchEvent(int32_t x, int32_t y, bool down);
+    void injectMultiTouchEvent(int32_t id, int32_t slot, int32_t x, int32_t y,
+                               bool initialDown);
 
-private:
-    std::shared_ptr<RunLoop> mRunLoop;
-    int mServerFd;
-
-    int mClientFd;
-
-    std::mutex mLock;
-    std::vector<uint8_t> mOutBuffer;
-    bool mSendPending;
-
-    std::function<void(int32_t, int32_t, bool)> send_event_;
-    std::function<void(int32_t, int32_t, int32_t, bool, int32_t)> send_mt_event_;
-
-    void onServerConnection();
-    void onSocketSend();
-
-    void sendRawEvents(const void* evt_buffer, size_t length);
+   private:
+    std::shared_ptr<InputSink> sink_;
 };
 
 }  // namespace android
diff --git a/host/frontend/gcastv2/webrtc/Android.bp b/host/frontend/gcastv2/webrtc/Android.bp
index c048ff4..85e0644 100644
--- a/host/frontend/gcastv2/webrtc/Android.bp
+++ b/host/frontend/gcastv2/webrtc/Android.bp
@@ -19,6 +19,7 @@
         "AdbWebSocketHandler.cpp",
         "DTLS.cpp",
         "G711Packetizer.cpp",
+        "Keyboard.cpp",
         "MyWebSocketHandler.cpp",
         "OpusPacketizer.cpp",
         "Packetizer.cpp",
diff --git a/host/frontend/gcastv2/webrtc/Keyboard.cpp b/host/frontend/gcastv2/webrtc/Keyboard.cpp
new file mode 100644
index 0000000..052f300
--- /dev/null
+++ b/host/frontend/gcastv2/webrtc/Keyboard.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2020 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 <webrtc/Keyboard.h>
+
+#include <linux/input.h>
+
+#include <map>
+
+static const std::map<std::string, uint16_t> kDomToLinuxMapping = {
+    {"Backquote", KEY_GRAVE},
+    {"Backslash", KEY_BACKSLASH},
+    {"Backspace", KEY_BACKSPACE},
+    {"BracketLeft", KEY_LEFTBRACE},
+    {"BracketRight", KEY_RIGHTBRACE},
+    {"Comma", KEY_COMMA},
+    {"Digit0", KEY_0},
+    {"Digit1", KEY_1},
+    {"Digit2", KEY_2},
+    {"Digit3", KEY_3},
+    {"Digit4", KEY_4},
+    {"Digit5", KEY_5},
+    {"Digit6", KEY_6},
+    {"Digit7", KEY_7},
+    {"Digit8", KEY_8},
+    {"Digit9", KEY_9},
+    {"Equal", KEY_EQUAL},
+    {"IntlBackslash", KEY_BACKSLASH},
+    {"IntlRo", KEY_RO},
+    {"IntlYen", KEY_BACKSLASH},
+    {"KeyA", KEY_A},
+    {"KeyB", KEY_B},
+    {"KeyC", KEY_C},
+    {"KeyD", KEY_D},
+    {"KeyE", KEY_E},
+    {"KeyF", KEY_F},
+    {"KeyG", KEY_G},
+    {"KeyH", KEY_H},
+    {"KeyI", KEY_I},
+    {"KeyJ", KEY_J},
+    {"KeyK", KEY_K},
+    {"KeyL", KEY_L},
+    {"KeyM", KEY_M},
+    {"KeyN", KEY_N},
+    {"KeyO", KEY_O},
+    {"KeyP", KEY_P},
+    {"KeyQ", KEY_Q},
+    {"KeyR", KEY_R},
+    {"KeyS", KEY_S},
+    {"KeyT", KEY_T},
+    {"KeyU", KEY_U},
+    {"KeyV", KEY_V},
+    {"KeyW", KEY_W},
+    {"KeyX", KEY_X},
+    {"KeyY", KEY_Y},
+    {"KeyZ", KEY_Z},
+    {"Minus", KEY_MINUS},
+    {"Period", KEY_DOT},
+    {"Quote", KEY_APOSTROPHE},
+    {"Semicolon", KEY_SEMICOLON},
+    {"Slash", KEY_SLASH},
+    {"AltLeft", KEY_LEFTALT},
+    {"AltRight", KEY_RIGHTALT},
+    {"CapsLock", KEY_CAPSLOCK},
+    {"ContextMenu", KEY_CONTEXT_MENU},
+    {"ControlLeft", KEY_LEFTCTRL},
+    {"ControlRight", KEY_RIGHTCTRL},
+    {"Enter", KEY_ENTER},
+    {"MetaLeft", KEY_LEFTMETA},
+    {"MetaRight", KEY_RIGHTMETA},
+    {"ShiftLeft", KEY_LEFTSHIFT},
+    {"ShiftRight", KEY_RIGHTSHIFT},
+    {"Space", KEY_SPACE},
+    {"Tab", KEY_TAB},
+    {"Delete", KEY_DELETE},
+    {"End", KEY_END},
+    {"Help", KEY_HELP},
+    {"Home", KEY_HOME},
+    {"Insert", KEY_INSERT},
+    {"PageDown", KEY_PAGEDOWN},
+    {"PageUp", KEY_PAGEUP},
+    {"ArrowDown", KEY_DOWN},
+    {"ArrowLeft", KEY_LEFT},
+    {"ArrowRight", KEY_RIGHT},
+    {"ArrowUp", KEY_UP},
+
+    {"NumLock", KEY_NUMLOCK},
+    {"Numpad0", KEY_KP0},
+    {"Numpad1", KEY_KP1},
+    {"Numpad2", KEY_KP2},
+    {"Numpad3", KEY_KP3},
+    {"Numpad4", KEY_KP4},
+    {"Numpad5", KEY_KP5},
+    {"Numpad6", KEY_KP6},
+    {"Numpad7", KEY_KP7},
+    {"Numpad8", KEY_KP8},
+    {"Numpad9", KEY_KP9},
+    {"NumpadAdd", KEY_KPPLUS},
+    {"NumpadBackspace", KEY_BACKSPACE},
+    {"NumpadClear", KEY_CLEAR},
+    {"NumpadComma", KEY_KPCOMMA},
+    {"NumpadDecimal", KEY_KPDOT},
+    {"NumpadDivide", KEY_KPSLASH},
+    {"NumpadEnter", KEY_KPENTER},
+    {"NumpadEqual", KEY_KPEQUAL},
+    /*
+    {"NumpadClearEntry", },
+    {"NumpadHash", },
+    {"NumpadMemoryAdd", },
+    {"NumpadMemoryClear", },
+    {"NumpadMemoryRecall", },
+    {"NumpadMemoryStore", },
+    {"NumpadMemorySubtract", },
+    */
+    {"NumpadMultiply", KEY_KPASTERISK},
+    {"NumpadParenLeft", KEY_KPLEFTPAREN},
+    {"NumpadParenRight", KEY_KPRIGHTPAREN},
+    {"NumpadStar", KEY_KPASTERISK},
+    {"NumpadSubtract", KEY_KPMINUS},
+
+    {"Escape", KEY_ESC},
+    {"F1", KEY_F1},
+    {"F2", KEY_F2},
+    {"F3", KEY_F3},
+    {"F4", KEY_F4},
+    {"F5", KEY_F5},
+    {"F6", KEY_F6},
+    {"F7", KEY_F7},
+    {"F8", KEY_F8},
+    {"F9", KEY_F9},
+    {"F10", KEY_F10},
+    {"F11", KEY_F11},
+    {"F12", KEY_F12},
+    {"Fn", KEY_FN},
+    /*{"FnLock", },*/
+    {"PrintScreen", KEY_SYSRQ},
+    {"ScrollLock", KEY_SCROLLLOCK},
+    {"Pause", KEY_PAUSE}};
+
+uint16_t DomKeyCodeToLinux(const std::string& dom_KEY_code) {
+  const auto it = kDomToLinuxMapping.find(dom_KEY_code);
+  if (it == kDomToLinuxMapping.end()) {
+    return 0;
+  }
+  return it->second;
+}
diff --git a/host/frontend/gcastv2/webrtc/MyWebSocketHandler.cpp b/host/frontend/gcastv2/webrtc/MyWebSocketHandler.cpp
index c167197..7faf9af 100644
--- a/host/frontend/gcastv2/webrtc/MyWebSocketHandler.cpp
+++ b/host/frontend/gcastv2/webrtc/MyWebSocketHandler.cpp
@@ -23,7 +23,7 @@
 #include <netdb.h>
 #include <openssl/rand.h>
 
-using android::InputEvent;
+#include <webrtc/Keyboard.h>
 
 MyWebSocketHandler::MyWebSocketHandler(
         std::shared_ptr<RunLoop> runLoop,
@@ -33,7 +33,8 @@
       mServerState(serverState),
       mId(handlerId),
       mOptions(OptionBits::useSingleCertificateForAllTracks),
-      mTouchSink(mServerState->getTouchSink()) {
+      mTouchSink(mServerState->getTouchSink()),
+      mKeyboardSink(mServerState->getKeyboardSink()) {
 }
 
 MyWebSocketHandler::~MyWebSocketHandler() {
@@ -242,9 +243,7 @@
         LOG(VERBOSE)
             << "set-mouse-position(" << down << ", " << x << ", " << y << ")";
 
-        std::shared_ptr<InputEvent> accessUnit(new InputEvent(down, x, y));
-
-        mTouchSink->onAccessUnit(accessUnit);
+        mTouchSink->injectTouchEvent(x, y, down != 0);
     } else if (type == "inject-multi-touch") {
         CHECK(obj.isMember("id"));
         CHECK(obj.isMember("initialDown"));
@@ -269,19 +268,14 @@
             << ", slot="
             << slot;
 
-        std::shared_ptr<InputEvent> accessUnit(new InputEvent(initialDown != 0, x, y));
-        accessUnit->down = (initialDown != 0);
-        accessUnit->x = x;
-        accessUnit->y = y;
-        // TODO(jemoreira): revive for multitouch
-        // int32_t *data = reinterpret_cast<int32_t *>(accessUnit->data());
-        // data[0] = id;
-        // data[1] = (initialDown != 0);
-        // data[2] = x;
-        // data[3] = y;
-        // data[4] = slot;
-
-        mTouchSink->onAccessUnit(accessUnit);
+        mTouchSink->injectMultiTouchEvent(id, slot, x, y, initialDown);
+    } else if (type == "key-event") {
+        CHECK(obj.isMember("event_type"));
+        auto down = obj["event_type"].asString() == std::string("keydown");
+        CHECK(obj.isMember("keycode"));
+        auto code = DomKeyCodeToLinux(obj["keycode"].asString());
+        CHECK(code);
+        mKeyboardSink->injectEvent(down, code);
     }
 
     return 0;
diff --git a/host/frontend/gcastv2/webrtc/ServerState.cpp b/host/frontend/gcastv2/webrtc/ServerState.cpp
index 8f5fbbb..e713135 100644
--- a/host/frontend/gcastv2/webrtc/ServerState.cpp
+++ b/host/frontend/gcastv2/webrtc/ServerState.cpp
@@ -27,6 +27,7 @@
 
 #include <gflags/gflags.h>
 
+DECLARE_int32(keyboard_fd);
 DECLARE_int32(touch_fd);
 DECLARE_int32(frame_server_fd);
 DECLARE_bool(write_virtio_input);
@@ -84,15 +85,22 @@
             });
 
     mAudioComms->start();
-    
+
     CHECK_GE(FLAGS_touch_fd, 0);
 
-    auto touchSink =
-        std::make_shared<android::TouchSink>(mRunLoop, FLAGS_touch_fd, FLAGS_write_virtio_input);
+    auto touchSink = std::make_shared<android::TouchSink>(
+        mRunLoop, FLAGS_touch_fd, FLAGS_write_virtio_input);
 
     touchSink->start();
 
     mTouchSink = touchSink;
+
+    auto keyboardSink = std::make_shared<android::KeyboardSink>(
+        mRunLoop, FLAGS_keyboard_fd, FLAGS_write_virtio_input);
+
+    keyboardSink->start();
+
+    mKeyboardSink = keyboardSink;
 }
 
 void ServerState::MonitorScreenConnector() {
@@ -158,6 +166,10 @@
     CHECK_EQ(mAllocatedHandlerIds.erase(id), 1);
 }
 
-std::shared_ptr<android::StreamingSink> ServerState::getTouchSink() {
+std::shared_ptr<android::TouchSink> ServerState::getTouchSink() {
     return mTouchSink;
 }
+
+std::shared_ptr<android::KeyboardSink> ServerState::getKeyboardSink() {
+    return mKeyboardSink;
+}
diff --git a/host/frontend/gcastv2/webrtc/assets/index.html b/host/frontend/gcastv2/webrtc/assets/index.html
index 69995fc..252c98e 100644
--- a/host/frontend/gcastv2/webrtc/assets/index.html
+++ b/host/frontend/gcastv2/webrtc/assets/index.html
@@ -7,6 +7,7 @@
 
     <body>
         <button id="receiveButton">Receive Media</button>
+        <button id="keyboardCaptureBtn">Capture Keyboard</button>
         <hr>
         <section class="noscroll">
             <div class="one" >
diff --git a/host/frontend/gcastv2/webrtc/assets/js/receive.js b/host/frontend/gcastv2/webrtc/assets/js/receive.js
index 25b1c71..3e3ab58 100644
--- a/host/frontend/gcastv2/webrtc/assets/js/receive.js
+++ b/host/frontend/gcastv2/webrtc/assets/js/receive.js
@@ -2,6 +2,8 @@
 
 const receiveButton = document.getElementById('receiveButton');
 receiveButton.addEventListener('click', onReceive);
+const keyboardCaptureButton = document.getElementById('keyboardCaptureBtn');
+keyboardCaptureButton.addEventListener('click', onKeyboardCaptureClick);
 
 const videoElement = document.getElementById('video');
 
@@ -47,6 +49,17 @@
     console.log('handleDataChannelMessage data="' + event.data + '"');
 }
 
+function onKeyboardCaptureClick(e) {
+    const selectedClass = 'selected';
+    if (keyboardCaptureButton.classList.contains(selectedClass)) {
+        stopKeyboardTracking();
+        keyboardCaptureButton.classList.remove(selectedClass);
+    } else {
+        startKeyboardTracking();
+        keyboardCaptureButton.classList.add(selectedClass);
+    }
+}
+
 async function onReceive() {
     console.log('onReceive');
     receiveButton.disabled = true;
@@ -401,6 +414,16 @@
     }
 }
 
+function startKeyboardTracking() {
+    document.addEventListener('keydown', onKeyEvent);
+    document.addEventListener('keyup', onKeyEvent);
+}
+
+function stopKeyboardTracking() {
+    document.removeEventListener('keydown', onKeyEvent);
+    document.removeEventListener('keyup', onKeyEvent);
+}
+
 function onStartDrag(e) {
     e.preventDefault();
 
@@ -467,3 +490,7 @@
         +   '}');
 }
 
+function onKeyEvent(e) {
+    e.preventDefault();
+    ws.send('{"type": "key-event","keycode": "'+e.code+'", "event_type": "'+e.type+'"}');
+}
\ No newline at end of file
diff --git a/host/frontend/gcastv2/webrtc/assets/style.css b/host/frontend/gcastv2/webrtc/assets/style.css
index 96b27e6..a782b0a 100644
--- a/host/frontend/gcastv2/webrtc/assets/style.css
+++ b/host/frontend/gcastv2/webrtc/assets/style.css
@@ -22,3 +22,8 @@
     padding: 10px;
 }
 
+button.selected {
+    background-color: #aaaaaa;
+    border-style: solid;
+    border-color: #aaaaaa;
+}
\ No newline at end of file
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/Keyboard.h b/host/frontend/gcastv2/webrtc/include/webrtc/Keyboard.h
new file mode 100644
index 0000000..84c4876
--- /dev/null
+++ b/host/frontend/gcastv2/webrtc/include/webrtc/Keyboard.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 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 <cinttypes>
+#include <string>
+
+uint16_t DomKeyCodeToLinux(const std::string& dom_key_code);
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/MyWebSocketHandler.h b/host/frontend/gcastv2/webrtc/include/webrtc/MyWebSocketHandler.h
index a89b257..fef87cb 100644
--- a/host/frontend/gcastv2/webrtc/include/webrtc/MyWebSocketHandler.h
+++ b/host/frontend/gcastv2/webrtc/include/webrtc/MyWebSocketHandler.h
@@ -23,7 +23,8 @@
 
 #include <https/WebSocketHandler.h>
 #include <https/RunLoop.h>
-#include <source/StreamingSink.h>
+#include <source/KeyboardSink.h>
+#include <source/TouchSink.h>
 
 #include <memory>
 #include <optional>
@@ -53,7 +54,8 @@
         useSingleCertificateForAllTracks    = 8,
     };
 
-    using StreamingSink = android::StreamingSink;
+    using TouchSink = android::TouchSink;
+    using KeyboardSink = android::KeyboardSink;
 
     std::shared_ptr<RunLoop> mRunLoop;
     std::shared_ptr<ServerState> mServerState;
@@ -68,7 +70,8 @@
     SDP mOfferedSDP;
     std::vector<std::shared_ptr<RTPSocketHandler>> mRTPs;
 
-    std::shared_ptr<StreamingSink> mTouchSink;
+    std::shared_ptr<TouchSink> mTouchSink;
+    std::shared_ptr<KeyboardSink> mKeyboardSink;
 
     std::pair<std::shared_ptr<X509>, std::shared_ptr<EVP_PKEY>>
         mCertificateAndKey;
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/ServerState.h b/host/frontend/gcastv2/webrtc/include/webrtc/ServerState.h
index b56a7f9..a0702f6 100644
--- a/host/frontend/gcastv2/webrtc/include/webrtc/ServerState.h
+++ b/host/frontend/gcastv2/webrtc/include/webrtc/ServerState.h
@@ -22,7 +22,8 @@
 
 #include <source/HostToGuestComms.h>
 
-#include <source/StreamingSink.h>
+#include <source/KeyboardSink.h>
+#include <source/TouchSink.h>
 #include <source/StreamingSource.h>
 
 #include <memory>
@@ -32,7 +33,8 @@
 #include <host/libs/screen_connector/screen_connector.h>
 
 struct ServerState {
-    using StreamingSink = android::StreamingSink;
+    using TouchSink = android::TouchSink;
+    using KeyboardSink = android::KeyboardSink;
 
     enum class VideoFormat {
         VP8,
@@ -43,7 +45,8 @@
 
     std::shared_ptr<Packetizer> getVideoPacketizer();
     std::shared_ptr<Packetizer> getAudioPacketizer();
-    std::shared_ptr<StreamingSink> getTouchSink();
+    std::shared_ptr<TouchSink> getTouchSink();
+    std::shared_ptr<KeyboardSink> getKeyboardSink();
 
     VideoFormat videoFormat() const { return mVideoFormat; }
 
@@ -68,7 +71,8 @@
     std::shared_ptr<cvd::ScreenConnector> mScreenConnector;
     std::shared_ptr<std::thread> mScreenConnectorMonitor;
 
-    std::shared_ptr<StreamingSink> mTouchSink;
+    std::shared_ptr<TouchSink> mTouchSink;
+    std::shared_ptr<KeyboardSink> mKeyboardSink;
 
     std::set<size_t> mAllocatedHandlerIds;
 
diff --git a/shared/config/manifest.xml b/shared/config/manifest.xml
index 6dc737a..cde4e443 100644
--- a/shared/config/manifest.xml
+++ b/shared/config/manifest.xml
@@ -185,6 +185,15 @@
     </hal>
     -->
     <hal format="hidl">
+        <name>android.hardware.identity</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IIdentityCredentialStore</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
         <name>android.hardware.keymaster</name>
         <transport>hwbinder</transport>
         <version>4.1</version>
diff --git a/shared/device.mk b/shared/device.mk
index 99c9df9..955232a 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -260,6 +260,10 @@
 PRODUCT_PACKAGES += \
     android.hardware.health.storage@1.0-service.cuttlefish
 
+# Identity Credential
+PRODUCT_PACKAGES += \
+    android.hardware.identity@1.0-service.example
+
 # Input Classifier HAL
 PRODUCT_PACKAGES += \
     android.hardware.input.classifier@1.0-service.default
diff --git a/shared/sepolicy/vendor/file_contexts b/shared/sepolicy/vendor/file_contexts
index 5000e6f..a5ed5b7 100644
--- a/shared/sepolicy/vendor/file_contexts
+++ b/shared/sepolicy/vendor/file_contexts
@@ -56,10 +56,10 @@
 /vendor/bin/hw/libcuttlefish-rild  u:object_r:libcuttlefish_rild_exec:s0
 /vendor/bin/hw/android\.hardware\.power\.stats@1\.0-service\.mock  u:object_r:hal_power_stats_default_exec:s0
 /vendor/bin/hw/android\.hardware\.bluetooth@1\.1-service\.sim  u:object_r:hal_bluetooth_sim_exec:s0
-/vendor/bin/hw/android\.hardware\.drm@1\.2-service\.clearkey  u:object_r:hal_drm_clearkey_exec:s0
-/vendor/bin/hw/android\.hardware\.drm@1\.2-service-lazy\.clearkey  u:object_r:hal_drm_clearkey_exec:s0
-/vendor/bin/hw/android\.hardware\.drm@1\.2-service\.widevine  u:object_r:hal_drm_widevine_exec:s0
-/vendor/bin/hw/android\.hardware\.drm@1\.2-service-lazy\.widevine  u:object_r:hal_drm_widevine_exec:s0
+/vendor/bin/hw/android\.hardware\.drm@[0-9]+\.[0-9]+-service\.clearkey  u:object_r:hal_drm_clearkey_exec:s0
+/vendor/bin/hw/android\.hardware\.drm@[0-9]+\.[0-9]+-service-lazy\.clearkey  u:object_r:hal_drm_clearkey_exec:s0
+/vendor/bin/hw/android\.hardware\.drm@[0-9]+\.[0-9]+-service\.widevine  u:object_r:hal_drm_widevine_exec:s0
+/vendor/bin/hw/android\.hardware\.drm@[0-9]+\.[0-9]+-service-lazy\.widevine  u:object_r:hal_drm_widevine_exec:s0
 /vendor/bin/hw/android\.hardware\.dumpstate@1\.0-service\.cuttlefish  u:object_r:hal_dumpstate_impl_exec:s0
 /vendor/bin/hw/android\.hardware\.gatekeeper@1\.0-service\.software  u:object_r:hal_gatekeeper_default_exec:s0
 /vendor/bin/hw/android\.hardware\.health\.storage@1\.0-service\.cuttlefish u:object_r:hal_health_storage_default_exec:s0