gatekeeper vts tests

Change-Id: I51eadf624341f4e5399cd73fdaf222d19701e611
Signed-off-by: Alexey Polyudov <apolyudov@google.com>
diff --git a/gatekeeper/1.0/vts/Gatekeeper.vts b/gatekeeper/1.0/vts/Gatekeeper.vts
new file mode 100644
index 0000000..25dc32f
--- /dev/null
+++ b/gatekeeper/1.0/vts/Gatekeeper.vts
@@ -0,0 +1,93 @@
+component_class: HAL_HIDL
+component_type_version: 1.0
+component_name: "IGatekeeper"
+
+package: "android.hardware.gatekeeper"
+
+import: "android.hardware.gatekeeper@1.0::types"
+
+interface: {
+    api: {
+        name: "enroll"
+        return_type_hidl: {
+            type: TYPE_STRUCT
+            predefined_type: "::android::hardware::gatekeeper::V1_0::GatekeeperResponse"
+        }
+        arg: {
+            type: TYPE_SCALAR
+            scalar_type: "uint32_t"
+        }
+        arg: {
+            type: TYPE_VECTOR
+            vector_value: {
+                type: TYPE_SCALAR
+                scalar_type: "uint8_t"
+            }
+        }
+        arg: {
+            type: TYPE_VECTOR
+            vector_value: {
+                type: TYPE_SCALAR
+                scalar_type: "uint8_t"
+            }
+        }
+        arg: {
+            type: TYPE_VECTOR
+            vector_value: {
+                type: TYPE_SCALAR
+                scalar_type: "uint8_t"
+            }
+        }
+    }
+
+    api: {
+        name: "verify"
+        return_type_hidl: {
+            type: TYPE_STRUCT
+            predefined_type: "::android::hardware::gatekeeper::V1_0::GatekeeperResponse"
+        }
+        arg: {
+            type: TYPE_SCALAR
+            scalar_type: "uint32_t"
+        }
+        arg: {
+            type: TYPE_SCALAR
+            scalar_type: "uint64_t"
+        }
+        arg: {
+            type: TYPE_VECTOR
+            vector_value: {
+                type: TYPE_SCALAR
+                scalar_type: "uint8_t"
+            }
+        }
+        arg: {
+            type: TYPE_VECTOR
+            vector_value: {
+                type: TYPE_SCALAR
+                scalar_type: "uint8_t"
+            }
+        }
+    }
+
+    api: {
+        name: "deleteUser"
+        return_type_hidl: {
+            type: TYPE_STRUCT
+            predefined_type: "::android::hardware::gatekeeper::V1_0::GatekeeperResponse"
+        }
+        arg: {
+            type: TYPE_SCALAR
+            scalar_type: "uint32_t"
+        }
+    }
+
+    api: {
+        name: "deleteAllUsers"
+        return_type_hidl: {
+            type: TYPE_STRUCT
+            predefined_type: "::android::hardware::gatekeeper::V1_0::GatekeeperResponse"
+        }
+    }
+
+}
diff --git a/gatekeeper/1.0/vts/functional/Android.bp b/gatekeeper/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..9c72b81
--- /dev/null
+++ b/gatekeeper/1.0/vts/functional/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+    name: "gatekeeper_hidl_hal_test",
+    gtest: true,
+    srcs: ["gatekeeper_hidl_hal_test.cpp"],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libnativehelper",
+        "libutils",
+        "android.hardware.gatekeeper@1.0",
+    ],
+    static_libs: ["libgtest"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/gatekeeper/1.0/vts/functional/gatekeeper_hidl_hal_test.cpp b/gatekeeper/1.0/vts/functional/gatekeeper_hidl_hal_test.cpp
new file mode 100644
index 0000000..4dd9294
--- /dev/null
+++ b/gatekeeper/1.0/vts/functional/gatekeeper_hidl_hal_test.cpp
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2016 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 "gatekeeper_hidl_hal_test"
+
+#include <algorithm>
+#include <cmath>
+#include <string>
+#include <vector>
+
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <hardware/hw_auth_token.h>
+
+#include <android-base/logging.h>
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+#include <android/hardware/gatekeeper/1.0/types.h>
+
+#include <gtest/gtest.h>
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::gatekeeper::V1_0::IGatekeeper;
+using ::android::hardware::gatekeeper::V1_0::GatekeeperResponse;
+using ::android::hardware::gatekeeper::V1_0::GatekeeperStatusCode;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct GatekeeperRequest {
+  uint32_t uid;
+  uint64_t challenge;
+  hidl_vec<uint8_t> curPwdHandle;
+  hidl_vec<uint8_t> curPwd;
+  hidl_vec<uint8_t> newPwd;
+  GatekeeperRequest() : uid(0), challenge(0) {}
+};
+
+// ASSERT_* macros generate return "void" internally
+// we have to use EXPECT_* if we return anything but "void"
+static const hw_auth_token_t *toAuthToken(GatekeeperResponse &rsp) {
+  const hw_auth_token_t *auth_token =
+      reinterpret_cast<hw_auth_token_t *>(rsp.data.data());
+  const size_t auth_token_size = rsp.data.size();
+
+  EXPECT_NE(nullptr, auth_token);
+  EXPECT_EQ(sizeof(hw_auth_token_t), auth_token_size);
+
+  if (auth_token != nullptr && auth_token_size >= sizeof(*auth_token)) {
+    // these are in network order: translate to host
+    uint32_t auth_type = ntohl(auth_token->authenticator_type);
+    uint64_t auth_tstamp = ntohq(auth_token->timestamp);
+
+    EXPECT_EQ(HW_AUTH_PASSWORD, auth_type);
+    EXPECT_NE(UINT64_C(~0), auth_tstamp);
+    EXPECT_EQ(HW_AUTH_TOKEN_VERSION, auth_token->version);
+    //        EXPECT_NE(UINT64_C(0), auth_token->authenticator_id);
+    ALOGI("Authenticator ID: %016" PRIX64, auth_token->authenticator_id);
+    EXPECT_NE(UINT32_C(0), auth_token->user_id);
+  }
+  return auth_token;
+}
+
+// The main test class for Gatekeeper HIDL HAL.
+class GatekeeperHidlTest : public ::testing::Test {
+ protected:
+  void setUid(uint32_t uid) { uid_ = uid; }
+
+  void doEnroll(GatekeeperRequest &req, GatekeeperResponse &rsp) {
+    while (true) {
+      auto ret = gatekeeper_->enroll(
+          uid_, req.curPwdHandle, req.curPwd, req.newPwd,
+          [&rsp](const GatekeeperResponse &cbRsp) { rsp = cbRsp; });
+      ASSERT_TRUE(ret.getStatus().isOk());
+      if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break;
+      ALOGI("%s: got retry code; retrying in 1 sec", __func__);
+      sleep(1);
+    }
+  }
+
+  void doVerify(GatekeeperRequest &req, GatekeeperResponse &rsp) {
+    while (true) {
+      auto ret = gatekeeper_->verify(
+          uid_, req.challenge, req.curPwdHandle, req.newPwd,
+          [&rsp](const GatekeeperResponse &cb_rsp) { rsp = cb_rsp; });
+      ASSERT_TRUE(ret.getStatus().isOk());
+      if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break;
+      ALOGI("%s: got retry code; retrying in 1 sec", __func__);
+      sleep(1);
+    }
+  }
+
+  void doDeleteUser(GatekeeperResponse &rsp) {
+    while (true) {
+      auto ret = gatekeeper_->deleteUser(
+          uid_, [&rsp](const GatekeeperResponse &cb_rsp) { rsp = cb_rsp; });
+      ASSERT_TRUE(ret.getStatus().isOk());
+      if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break;
+      ALOGI("%s: got retry code; retrying in 1 sec", __func__);
+      sleep(1);
+    }
+  }
+
+  void doDeleteAllUsers(GatekeeperResponse &rsp) {
+    while (true) {
+      auto ret = gatekeeper_->deleteAllUsers(
+          [&rsp](const GatekeeperResponse &cb_rsp) { rsp = cb_rsp; });
+      ASSERT_TRUE(ret.getStatus().isOk());
+      if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break;
+      ALOGI("%s: got retry code; retrying in 1 sec", __func__);
+      sleep(1);
+    }
+  }
+
+  void generatePassword(hidl_vec<uint8_t> &password, uint8_t seed) {
+    password.resize(16);
+    memset(password.data(), seed, password.size());
+  }
+
+  void checkEnroll(GatekeeperResponse &rsp, bool expectSuccess) {
+    if (expectSuccess) {
+      EXPECT_EQ(GatekeeperStatusCode::STATUS_OK, rsp.code);
+      EXPECT_NE(nullptr, rsp.data.data());
+      EXPECT_GT(rsp.data.size(), UINT32_C(0));
+    } else {
+      EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE, rsp.code);
+      EXPECT_EQ(UINT32_C(0), rsp.data.size());
+    }
+  }
+
+  void checkVerify(GatekeeperResponse &rsp, uint64_t challenge,
+                   bool expectSuccess) {
+    if (expectSuccess) {
+      EXPECT_GE(rsp.code, GatekeeperStatusCode::STATUS_OK);
+      EXPECT_LE(rsp.code, GatekeeperStatusCode::STATUS_REENROLL);
+
+      const hw_auth_token_t *auth_token = toAuthToken(rsp);
+      ASSERT_NE(nullptr, auth_token);
+      EXPECT_EQ(challenge, auth_token->challenge);
+    } else {
+      EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE, rsp.code);
+      EXPECT_EQ(UINT32_C(0), rsp.data.size());
+    }
+  }
+
+  void enrollNewPassword(hidl_vec<uint8_t> &password, GatekeeperResponse &rsp,
+                         bool expectSuccess) {
+    GatekeeperRequest req;
+    req.newPwd.setToExternal(password.data(), password.size());
+    doEnroll(req, rsp);
+    checkEnroll(rsp, expectSuccess);
+  }
+
+  void verifyPassword(hidl_vec<uint8_t> &password,
+                      hidl_vec<uint8_t> &passwordHandle, uint64_t challenge,
+                      GatekeeperResponse &verifyRsp, bool expectSuccess) {
+    GatekeeperRequest verifyReq;
+
+    // build verify request for the same password (we want it to succeed)
+    verifyReq.newPwd = password;
+    // use enrolled password handle we've got
+    verifyReq.curPwdHandle = passwordHandle;
+    verifyReq.challenge = challenge;
+    doVerify(verifyReq, verifyRsp);
+    checkVerify(verifyRsp, challenge, expectSuccess);
+  }
+
+ protected:
+  sp<IGatekeeper> gatekeeper_;
+  uint32_t uid_;
+
+ public:
+  GatekeeperHidlTest() : uid_(0) {}
+  virtual void SetUp() override {
+    GatekeeperResponse rsp;
+    gatekeeper_ = IGatekeeper::getService("gatekeeper", false);
+    ASSERT_NE(nullptr, gatekeeper_.get());
+    doDeleteAllUsers(rsp);
+  }
+
+  virtual void TearDown() override {
+    GatekeeperResponse rsp;
+    doDeleteAllUsers(rsp);
+  }
+};
+
+/**
+ * Ensure we can enroll new password
+ */
+TEST_F(GatekeeperHidlTest, EnrollSuccess) {
+  hidl_vec<uint8_t> password;
+  GatekeeperResponse rsp;
+  ALOGI("Testing Enroll (expected success)");
+  generatePassword(password, 0);
+  enrollNewPassword(password, rsp, true);
+  ALOGI("Testing Enroll done");
+}
+
+/**
+ * Ensure we can not enroll empty password
+ */
+TEST_F(GatekeeperHidlTest, EnrollNoPassword) {
+  hidl_vec<uint8_t> password;
+  GatekeeperResponse rsp;
+  ALOGI("Testing Enroll (expected failure)");
+  enrollNewPassword(password, rsp, false);
+  ALOGI("Testing Enroll done");
+}
+
+/**
+ * Ensure we can successfully verify previously enrolled password
+ */
+TEST_F(GatekeeperHidlTest, VerifySuccess) {
+  GatekeeperResponse enrollRsp;
+  GatekeeperResponse verifyRsp;
+  hidl_vec<uint8_t> password;
+
+  ALOGI("Testing Enroll+Verify (expected success)");
+  generatePassword(password, 0);
+  enrollNewPassword(password, enrollRsp, true);
+  verifyPassword(password, enrollRsp.data, 1, verifyRsp, true);
+  ALOGI("Testing Enroll+Verify done");
+}
+
+/**
+ * Ensure we can securely update password (keep the same
+ * secure user_id) if we prove we know old password
+ */
+TEST_F(GatekeeperHidlTest, TrustedReenroll) {
+  GatekeeperResponse enrollRsp;
+  GatekeeperRequest reenrollReq;
+  GatekeeperResponse reenrollRsp;
+  GatekeeperResponse verifyRsp;
+  GatekeeperResponse reenrollVerifyRsp;
+  hidl_vec<uint8_t> password;
+  hidl_vec<uint8_t> newPassword;
+
+  generatePassword(password, 0);
+
+  ALOGI("Testing Trusted Reenroll (expected success)");
+  enrollNewPassword(password, enrollRsp, true);
+  verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+  ALOGI("Primary Enroll+Verify done");
+
+  generatePassword(newPassword, 1);
+  reenrollReq.newPwd.setToExternal(newPassword.data(), newPassword.size());
+  reenrollReq.curPwd.setToExternal(password.data(), password.size());
+  reenrollReq.curPwdHandle.setToExternal(enrollRsp.data.data(),
+                                         enrollRsp.data.size());
+
+  doEnroll(reenrollReq, reenrollRsp);
+  checkEnroll(reenrollRsp, true);
+  verifyPassword(newPassword, reenrollRsp.data, 0, reenrollVerifyRsp, true);
+  ALOGI("Trusted ReEnroll+Verify done");
+
+  const hw_auth_token_t *first = toAuthToken(verifyRsp);
+  const hw_auth_token_t *second = toAuthToken(reenrollVerifyRsp);
+  if (first != nullptr && second != nullptr) {
+    EXPECT_EQ(first->user_id, second->user_id);
+  }
+  ALOGI("Testing Trusted Reenroll done");
+}
+
+/**
+ * Ensure we can update password (and get new
+ * secure user_id) if we don't know old password
+ */
+TEST_F(GatekeeperHidlTest, UntrustedReenroll) {
+  GatekeeperResponse enrollRsp;
+  GatekeeperRequest reenrollReq;
+  GatekeeperResponse reenrollRsp;
+  GatekeeperResponse verifyRsp;
+  GatekeeperResponse reenrollVerifyRsp;
+  hidl_vec<uint8_t> password;
+  hidl_vec<uint8_t> newPassword;
+
+  ALOGI("Testing Untrusted Reenroll (expected success)");
+  generatePassword(password, 0);
+  enrollNewPassword(password, enrollRsp, true);
+  verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+  ALOGI("Primary Enroll+Verify done");
+
+  generatePassword(newPassword, 1);
+  enrollNewPassword(newPassword, reenrollRsp, true);
+  verifyPassword(newPassword, reenrollRsp.data, 0, reenrollVerifyRsp, true);
+  ALOGI("Untrusted ReEnroll+Verify done");
+
+  const hw_auth_token_t *first = toAuthToken(verifyRsp);
+  const hw_auth_token_t *second = toAuthToken(reenrollVerifyRsp);
+  if (first != nullptr && second != nullptr) {
+    EXPECT_NE(first->user_id, second->user_id);
+  }
+  ALOGI("Testing Untrusted Reenroll done");
+}
+
+/**
+ * Ensure we dont get successful verify with invalid data
+ */
+TEST_F(GatekeeperHidlTest, VerifyNoData) {
+  hidl_vec<uint8_t> password;
+  hidl_vec<uint8_t> passwordHandle;
+  GatekeeperResponse verifyRsp;
+
+  ALOGI("Testing Verify (expected failure)");
+  verifyPassword(password, passwordHandle, 0, verifyRsp, false);
+  EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE, verifyRsp.code);
+  ALOGI("Testing Verify done");
+}
+
+/**
+ * Ensure we can not verify password after we enrolled it and then deleted user
+ */
+TEST_F(GatekeeperHidlTest, DeleteUserTest) {
+  hidl_vec<uint8_t> password;
+  GatekeeperResponse enrollRsp;
+  GatekeeperResponse verifyRsp;
+  GatekeeperResponse delRsp;
+  ALOGI("Testing deleteUser (expected success)");
+  setUid(10001);
+  generatePassword(password, 0);
+  enrollNewPassword(password, enrollRsp, true);
+  verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+  ALOGI("Enroll+Verify done");
+  doDeleteUser(delRsp);
+  EXPECT_EQ(UINT32_C(0), delRsp.data.size());
+  EXPECT_TRUE(delRsp.code == GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED ||
+              delRsp.code == GatekeeperStatusCode::STATUS_OK);
+  ALOGI("DeleteUser done");
+  if (delRsp.code == GatekeeperStatusCode::STATUS_OK) {
+    verifyPassword(password, enrollRsp.data, 0, verifyRsp, false);
+    EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE, verifyRsp.code);
+    ALOGI("Verify after Delete done (must fail)");
+  }
+  ALOGI("Testing deleteUser done: rsp=%" PRIi32, delRsp.code);
+}
+
+/**
+ * Ensure we can not verify passwords after we enrolled them and then deleted
+ * all users
+ */
+TEST_F(GatekeeperHidlTest, DeleteAllUsersTest) {
+  struct UserData {
+    uint32_t userId;
+    hidl_vec<uint8_t> password;
+    GatekeeperResponse enrollRsp;
+    GatekeeperResponse verifyRsp;
+    UserData(int id) { userId = id; }
+  } users[3]{10001, 10002, 10003};
+  GatekeeperResponse delAllRsp;
+  ALOGI("Testing deleteAllUsers (expected success)");
+
+  // enroll multiple users
+  for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) {
+    setUid(users[i].userId);
+    generatePassword(users[i].password, (i % 255) + 1);
+    enrollNewPassword(users[i].password, users[i].enrollRsp, true);
+  }
+  ALOGI("Multiple users enrolled");
+
+  // verify multiple users
+  for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) {
+    setUid(users[i].userId);
+    verifyPassword(users[i].password, users[i].enrollRsp.data, 0,
+                   users[i].verifyRsp, true);
+  }
+  ALOGI("Multiple users verified");
+
+  doDeleteAllUsers(delAllRsp);
+  EXPECT_EQ(UINT32_C(0), delAllRsp.data.size());
+  EXPECT_TRUE(delAllRsp.code == GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED ||
+              delAllRsp.code == GatekeeperStatusCode::STATUS_OK);
+  ALOGI("All users deleted");
+
+  if (delAllRsp.code == GatekeeperStatusCode::STATUS_OK) {
+    // verify multiple users after they are deleted; all must fail
+    for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) {
+      setUid(users[i].userId);
+      verifyPassword(users[i].password, users[i].enrollRsp.data, 0,
+                     users[i].verifyRsp, false);
+      EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE,
+                users[i].verifyRsp.code);
+    }
+    ALOGI("Multiple users verified after delete (all must fail)");
+  }
+
+  ALOGI("Testing deleteAllUsers done: rsp=%" PRIi32, delAllRsp.code);
+}
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  ALOGI("Test result = %d", status);
+  return status;
+}
diff --git a/gatekeeper/1.0/vts/functional/vts/testcases/hal/gatekeeper/__init__.py b/gatekeeper/1.0/vts/functional/vts/testcases/hal/gatekeeper/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gatekeeper/1.0/vts/functional/vts/testcases/hal/gatekeeper/__init__.py
diff --git a/gatekeeper/1.0/vts/functional/vts/testcases/hal/gatekeeper/hidl/__init__.py b/gatekeeper/1.0/vts/functional/vts/testcases/hal/gatekeeper/hidl/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gatekeeper/1.0/vts/functional/vts/testcases/hal/gatekeeper/hidl/__init__.py
diff --git a/gatekeeper/1.0/vts/functional/vts/testcases/hal/gatekeeper/hidl/target/Android.mk b/gatekeeper/1.0/vts/functional/vts/testcases/hal/gatekeeper/hidl/target/Android.mk
new file mode 100644
index 0000000..59bfe17
--- /dev/null
+++ b/gatekeeper/1.0/vts/functional/vts/testcases/hal/gatekeeper/hidl/target/Android.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := HalGatekeeperHidlTargetBasicTest
+VTS_CONFIG_SRC_DIR := testcases/hal/gatekeeper/hidl/target
+include test/vts/tools/build/Android.host_config.mk
diff --git a/gatekeeper/1.0/vts/functional/vts/testcases/hal/gatekeeper/hidl/target/AndroidTest.xml b/gatekeeper/1.0/vts/functional/vts/testcases/hal/gatekeeper/hidl/target/AndroidTest.xml
new file mode 100644
index 0000000..9256823
--- /dev/null
+++ b/gatekeeper/1.0/vts/functional/vts/testcases/hal/gatekeeper/hidl/target/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<configuration description="Config for VTS Gatekeeper HIDL HAL's basic target-side test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+        <option name="push-group" value="HidlHalTest.push" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
+    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+        <option name="test-module-name" value="HalGatekeeperHidlTargetBasicTest" />
+        <option name="binary-test-sources" value="
+            _32bit::DATA/nativetest/gatekeeper_hidl_hal_test/gatekeeper_hidl_hal_test,
+            _64bit::DATA/nativetest64/gatekeeper_hidl_hal_test/gatekeeper_hidl_hal_test,
+            "/>
+        <option name="binary-test-type" value="gtest" />
+        <option name="test-timeout" value="1m" />
+    </test>
+</configuration>
diff --git a/gatekeeper/1.0/vts/types.vts b/gatekeeper/1.0/vts/types.vts
new file mode 100644
index 0000000..3de9a14
--- /dev/null
+++ b/gatekeeper/1.0/vts/types.vts
@@ -0,0 +1,59 @@
+component_class: HAL_HIDL
+component_type_version: 1.0
+component_name: "types"
+
+package: "android.hardware.gatekeeper"
+
+
+attribute: {
+    name: "::android::hardware::gatekeeper::V1_0::GatekeeperStatusCode"
+    type: TYPE_ENUM
+    enum_value: {
+        scalar_type: "int32_t"
+
+        enumerator: "STATUS_REENROLL"
+        scalar_value: {
+            int32_t: 1
+        }
+        enumerator: "STATUS_OK"
+        scalar_value: {
+            int32_t: 0
+        }
+        enumerator: "ERROR_GENERAL_FAILURE"
+        scalar_value: {
+            int32_t: -1
+        }
+        enumerator: "ERROR_RETRY_TIMEOUT"
+        scalar_value: {
+            int32_t: -2
+        }
+        enumerator: "ERROR_NOT_IMPLEMENTED"
+        scalar_value: {
+            int32_t: -3
+        }
+    }
+}
+
+attribute: {
+    name: "::android::hardware::gatekeeper::V1_0::GatekeeperResponse"
+    type: TYPE_STRUCT
+    struct_value: {
+        name: "code"
+        type: TYPE_ENUM
+        predefined_type: "::android::hardware::gatekeeper::V1_0::GatekeeperStatusCode"
+    }
+    struct_value: {
+        name: "timeout"
+        type: TYPE_SCALAR
+        scalar_type: "uint32_t"
+    }
+    struct_value: {
+        name: "data"
+        type: TYPE_VECTOR
+        vector_value: {
+            type: TYPE_SCALAR
+            scalar_type: "uint8_t"
+        }
+    }
+}
+
diff --git a/gatekeeper/Android.bp b/gatekeeper/Android.bp
index bbb3e4b..33f70eb 100644
--- a/gatekeeper/Android.bp
+++ b/gatekeeper/Android.bp
@@ -1,4 +1,5 @@
 // This is an autogenerated file, do not edit.
 subdirs = [
     "1.0",
+    "1.0/vts/functional",
 ]