Merge "Add HAL for 5G bands"
diff --git a/bluetooth/audio/2.0/vts/functional/Android.bp b/bluetooth/audio/2.0/vts/functional/Android.bp
index b672fe4..b778b97 100644
--- a/bluetooth/audio/2.0/vts/functional/Android.bp
+++ b/bluetooth/audio/2.0/vts/functional/Android.bp
@@ -9,4 +9,5 @@
     shared_libs: [
         "libfmq",
     ],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp b/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp
index 9572d3f..b3cb6f7 100644
--- a/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp
+++ b/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp
@@ -21,12 +21,13 @@
 #include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvider.h>
 #include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h>
 #include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/MQDescriptor.h>
+#include <hidl/ServiceManagement.h>
 #include <utils/Log.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 
 using ::android::sp;
 using ::android::hardware::hidl_vec;
@@ -105,34 +106,13 @@
 }
 }  // namespace
 
-// Test environment for Bluetooth Audio HAL.
-class BluetoothAudioHidlEnvironment
-    : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static BluetoothAudioHidlEnvironment* Instance() {
-    static BluetoothAudioHidlEnvironment* instance =
-        new BluetoothAudioHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override {
-    registerTestService<IBluetoothAudioProvidersFactory>();
-  }
-
- private:
-  BluetoothAudioHidlEnvironment() {}
-};
-
 // The base test class for Bluetooth Audio HAL.
 class BluetoothAudioProvidersFactoryHidlTest
-    : public ::testing::VtsHalHidlTargetTestBase {
+    : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-    providers_factory_ = ::testing::VtsHalHidlTargetTestBase::getService<
-        IBluetoothAudioProvidersFactory>(
-        BluetoothAudioHidlEnvironment::Instance()
-            ->getServiceName<IBluetoothAudioProvidersFactory>());
+    providers_factory_ =
+        IBluetoothAudioProvidersFactory::getService(GetParam());
     ASSERT_NE(providers_factory_, nullptr);
   }
 
@@ -300,13 +280,13 @@
 /**
  * Test whether we can get the FactoryService from HIDL
  */
-TEST_F(BluetoothAudioProvidersFactoryHidlTest, GetProvidersFactoryService) {}
+TEST_P(BluetoothAudioProvidersFactoryHidlTest, GetProvidersFactoryService) {}
 
 /**
  * Test whether we can open a provider for each provider returned by
  * getProviderCapabilities() with non-empty capabalities
  */
-TEST_F(BluetoothAudioProvidersFactoryHidlTest,
+TEST_P(BluetoothAudioProvidersFactoryHidlTest,
        OpenProviderAndCheckCapabilitiesBySession) {
   for (auto session_type : session_types_) {
     GetProviderCapabilitiesHelper(session_type);
@@ -341,14 +321,14 @@
 /**
  * Test whether we can open a provider of type
  */
-TEST_F(BluetoothAudioProviderA2dpSoftwareHidlTest, OpenA2dpSoftwareProvider) {}
+TEST_P(BluetoothAudioProviderA2dpSoftwareHidlTest, OpenA2dpSoftwareProvider) {}
 
 /**
  * Test whether each provider of type
  * SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH can be started and stopped with
  * different PCM config
  */
-TEST_F(BluetoothAudioProviderA2dpSoftwareHidlTest,
+TEST_P(BluetoothAudioProviderA2dpSoftwareHidlTest,
        StartAndEndA2dpSoftwareSessionWithPossiblePcmConfig) {
   bool is_codec_config_valid;
   std::unique_ptr<DataMQ> tempDataMQ;
@@ -616,14 +596,14 @@
 /**
  * Test whether we can open a provider of type
  */
-TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest, OpenA2dpHardwareProvider) {}
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest, OpenA2dpHardwareProvider) {}
 
 /**
  * Test whether each provider of type
  * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
  * SBC hardware encoding config
  */
-TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
        StartAndEndA2dpSbcHardwareSession) {
   if (!IsOffloadSupported()) {
     return;
@@ -658,7 +638,7 @@
  * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
  * AAC hardware encoding config
  */
-TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
        StartAndEndA2dpAacHardwareSession) {
   if (!IsOffloadSupported()) {
     return;
@@ -693,7 +673,7 @@
  * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
  * LDAC hardware encoding config
  */
-TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
        StartAndEndA2dpLdacHardwareSession) {
   if (!IsOffloadSupported()) {
     return;
@@ -728,7 +708,7 @@
  * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
  * AptX hardware encoding config
  */
-TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
        StartAndEndA2dpAptxHardwareSession) {
   if (!IsOffloadSupported()) {
     return;
@@ -767,7 +747,7 @@
  * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
  * an invalid codec config
  */
-TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
        StartAndEndA2dpHardwareSessionInvalidCodecConfig) {
   if (!IsOffloadSupported()) {
     return;
@@ -857,7 +837,7 @@
  * SessionType::HEARING_AID_HARDWARE_ENCODING_DATAPATH can be started and
  * stopped with SBC hardware encoding config
  */
-TEST_F(BluetoothAudioProviderHearingAidSoftwareHidlTest,
+TEST_P(BluetoothAudioProviderHearingAidSoftwareHidlTest,
        OpenHearingAidSoftwareProvider) {}
 
 /**
@@ -865,7 +845,7 @@
  * SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH can be started and
  * stopped with different PCM config
  */
-TEST_F(BluetoothAudioProviderHearingAidSoftwareHidlTest,
+TEST_P(BluetoothAudioProviderHearingAidSoftwareHidlTest,
        StartAndEndHearingAidSessionWithPossiblePcmConfig) {
   bool is_codec_config_valid;
   std::unique_ptr<DataMQ> tempDataMQ;
@@ -904,12 +884,25 @@
   }      // SampleRate
 }
 
-int main(int argc, char** argv) {
-  ::testing::AddGlobalTestEnvironment(
-      BluetoothAudioHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  BluetoothAudioHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  LOG(INFO) << "Test result = " << status;
-  return status;
-}
+static const std::vector<std::string> kAudioInstances =
+    android::hardware::getAllHalInstanceNames(
+        IBluetoothAudioProvidersFactory::descriptor);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProvidersFactoryHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderA2dpSoftwareHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderA2dpHardwareHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderHearingAidSoftwareHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index c6fd76e..cf27a3f 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -155,7 +155,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.drm</name>
-        <version>1.0-2</version>
+        <version>1.0-3</version>
         <interface>
             <name>ICryptoFactory</name>
             <regex-instance>.*</regex-instance>
diff --git a/current.txt b/current.txt
index 3e2a5d1..5847f71 100644
--- a/current.txt
+++ b/current.txt
@@ -593,6 +593,8 @@
 9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener
 f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService
 4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types
+66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory
+994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory
 ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback
 db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types
diff --git a/drm/1.3/Android.bp b/drm/1.3/Android.bp
new file mode 100644
index 0000000..b0ffcb9
--- /dev/null
+++ b/drm/1.3/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.drm@1.3",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IDrmFactory.hal",
+        "ICryptoFactory.hal",
+    ],
+    interfaces: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "android.hardware.drm@1.2",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/drm/1.3/ICryptoFactory.hal b/drm/1.3/ICryptoFactory.hal
new file mode 100644
index 0000000..d7864eb
--- /dev/null
+++ b/drm/1.3/ICryptoFactory.hal
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+package android.hardware.drm@1.3;
+
+import @1.2::ICryptoFactory;
+
+/**
+ * ICryptoFactory is the main entry point for interacting with a vendor's
+ * crypto HAL to create crypto plugins. Crypto plugins create crypto sessions
+ * which are used by a codec to decrypt protected video content.
+ *
+ * The 1.3 factory must always create 1.2 ICryptoPlugin interfaces, which are
+ * returned via the 1.0 createPlugin method.
+ *
+ * The ICryptoFactory hal is required because all top-level interfaces
+ * have to be updated in a minor uprev.
+ */
+interface ICryptoFactory extends @1.2::ICryptoFactory {
+};
diff --git a/drm/1.3/IDrmFactory.hal b/drm/1.3/IDrmFactory.hal
new file mode 100644
index 0000000..5208028
--- /dev/null
+++ b/drm/1.3/IDrmFactory.hal
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+package android.hardware.drm@1.3;
+
+import @1.2::IDrmFactory;
+
+/**
+ * IDrmFactory is the main entry point for interacting with a vendor's
+ * drm HAL to create drm plugin instances. A drm plugin instance
+ * creates drm sessions which are used to obtain keys for a crypto
+ * session so it can decrypt protected video content.
+ *
+ * The 1.3 factory must always create 1.2 IDrmPlugin interfaces, which are
+ * returned via the 1.0 createPlugin method.
+ */
+
+interface IDrmFactory extends @1.2::IDrmFactory {
+    /**
+     * Return vector of uuids identifying crypto schemes supported by this HAL.
+     *
+     * @return schemes Vector of uuids for which isCryptoSchemeSupported is true;
+     *                 each uuid can be used as input to createPlugin.
+     */
+    getSupportedCryptoSchemes() generates(vec<uint8_t[16]> schemes);
+};
diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
index 162915e..3dfda19 100644
--- a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
+++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
@@ -79,6 +79,7 @@
 
     void setLayerPerFrameMetadataBlobs(
         const hidl_vec<IComposerClient::PerFrameMetadataBlob>& metadata) {
+        // in units of uint32_t's
         size_t commandLength = 0;
 
         if (metadata.size() > std::numeric_limits<uint32_t>::max()) {
@@ -86,12 +87,12 @@
             return;
         }
 
-        // number of blobs
-        commandLength += metadata.size();
+        // space for numElements
+        commandLength += 1;
 
         for (auto metadataBlob : metadata) {
-            commandLength += sizeof(int32_t);  // key of metadata blob
-            commandLength += 1;                // size information of metadata blob
+            commandLength += 1;  // key of metadata blob
+            commandLength += 1;  // size information of metadata blob
 
             // metadata content size
             size_t metadataSize = metadataBlob.blob.size() / sizeof(uint32_t);
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
index 5a7548a..a8030ab 100644
--- a/graphics/mapper/4.0/vts/functional/Android.bp
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -30,5 +30,8 @@
         "libgralloctypes",
         "vintf-graphics-common-ndk_platform",
     ],
+    header_libs: [
+        "libsystem_headers",
+    ],
     test_suites: ["general-tests"],
 }
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 870e6eb..d63b078 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -20,13 +20,13 @@
 #include <thread>
 #include <vector>
 
-//#include <aidl/android/hardware/graphics/common/BlendMode.h>
-//#include <aidl/android/hardware/graphics/common/Compression.h>
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
 #include <gralloctypes/Gralloc4.h>
 #include <mapper-vts/4.0/MapperVts.h>
+#include <system/graphics.h>
 
 namespace android {
 namespace hardware {
@@ -44,6 +44,7 @@
 using aidl::android::hardware::graphics::common::ExtendableType;
 using aidl::android::hardware::graphics::common::PlaneLayout;
 using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
 using aidl::android::hardware::graphics::common::StandardMetadataType;
 
 using DecodeFunction = std::function<void(const IMapper::BufferDescriptorInfo& descriptorInfo,
@@ -200,6 +201,78 @@
         EXPECT_EQ(sRequiredMetadataTypes, foundMetadataTypes);
     }
 
+    void getAndroidYCbCr(const native_handle_t* bufferHandle, uint8_t* data,
+                         android_ycbcr* outYCbCr) {
+        hidl_vec<uint8_t> vec;
+        ASSERT_EQ(Error::NONE,
+                  mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
+        std::vector<PlaneLayout> planeLayouts;
+        ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+
+        outYCbCr->y = nullptr;
+        outYCbCr->cb = nullptr;
+        outYCbCr->cr = nullptr;
+        outYCbCr->ystride = 0;
+        outYCbCr->cstride = 0;
+        outYCbCr->chroma_step = 0;
+
+        for (const auto& planeLayout : planeLayouts) {
+            for (const auto& planeLayoutComponent : planeLayout.components) {
+                std::string componentTypeName = planeLayoutComponent.type.name;
+                if (!std::strncmp(componentTypeName.c_str(), GRALLOC4_PLANE_LAYOUT_COMPONENT_TYPE,
+                                  componentTypeName.size())) {
+                    continue;
+                }
+                ASSERT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+
+                uint8_t* tmpData =
+                        data + planeLayout.offsetInBytes + (planeLayoutComponent.offsetInBits / 8);
+                uint64_t sampleIncrementInBytes;
+
+                auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
+                switch (type) {
+                    case PlaneLayoutComponentType::Y:
+                        ASSERT_EQ(nullptr, outYCbCr->y);
+                        ASSERT_EQ(8, planeLayoutComponent.sizeInBits);
+                        ASSERT_EQ(8, planeLayout.sampleIncrementInBits);
+                        outYCbCr->y = tmpData;
+                        outYCbCr->ystride = planeLayout.strideInBytes;
+                        break;
+
+                    case PlaneLayoutComponentType::CB:
+                    case PlaneLayoutComponentType::CR:
+                        ASSERT_EQ(0, planeLayout.sampleIncrementInBits % 8);
+
+                        sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
+                        ASSERT_TRUE(sampleIncrementInBytes == 1 || sampleIncrementInBytes == 2);
+
+                        if (outYCbCr->cstride == 0 && outYCbCr->chroma_step == 0) {
+                            outYCbCr->cstride = planeLayout.strideInBytes;
+                            outYCbCr->chroma_step = sampleIncrementInBytes;
+                        } else {
+                            ASSERT_EQ(outYCbCr->cstride, planeLayout.strideInBytes);
+                            ASSERT_EQ(outYCbCr->chroma_step, sampleIncrementInBytes);
+                        }
+
+                        if (type == PlaneLayoutComponentType::CB) {
+                            ASSERT_EQ(nullptr, outYCbCr->cb);
+                            outYCbCr->cb = tmpData;
+                        } else {
+                            ASSERT_EQ(nullptr, outYCbCr->cr);
+                            outYCbCr->cr = tmpData;
+                        }
+                        break;
+                    default:
+                        break;
+                };
+            }
+        }
+
+        ASSERT_NE(nullptr, outYCbCr->y);
+        ASSERT_NE(nullptr, outYCbCr->cb);
+        ASSERT_NE(nullptr, outYCbCr->cr);
+    }
+
     std::unique_ptr<Gralloc> mGralloc;
     IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
     static const std::set<StandardMetadataType> sRequiredMetadataTypes;
@@ -482,6 +555,76 @@
     }
 }
 
+TEST_F(GraphicsMapperHidlTest, Lock_YCBCR_420_888) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::YCBCR_420_888;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, false, &stride));
+
+    // lock buffer for writing
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    int fence = -1;
+    uint8_t* data;
+
+    ASSERT_NO_FATAL_FAILURE(
+            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
+
+    android_ycbcr yCbCr;
+    ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(bufferHandle, data, &yCbCr));
+
+    auto yData = static_cast<uint8_t*>(yCbCr.y);
+    auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+    auto crData = static_cast<uint8_t*>(yCbCr.cr);
+    auto yStride = yCbCr.ystride;
+    auto cStride = yCbCr.cstride;
+    auto chromaStep = yCbCr.chroma_step;
+
+    for (uint32_t y = 0; y < info.height; y++) {
+        for (uint32_t x = 0; x < info.width; x++) {
+            auto val = static_cast<uint8_t>(info.height * y + x);
+
+            yData[yStride * y + x] = val;
+
+            if (y % chromaStep && x % chromaStep == 0) {
+                cbData[cStride * y / chromaStep + x / chromaStep] = val;
+                crData[cStride * y / chromaStep + x / chromaStep] = val;
+            }
+        }
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+
+    // lock again for reading
+    ASSERT_NO_FATAL_FAILURE(
+            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
+
+    ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(bufferHandle, data, &yCbCr));
+
+    yData = static_cast<uint8_t*>(yCbCr.y);
+    cbData = static_cast<uint8_t*>(yCbCr.cb);
+    crData = static_cast<uint8_t*>(yCbCr.cr);
+    for (uint32_t y = 0; y < info.height; y++) {
+        for (uint32_t x = 0; x < info.width; x++) {
+            auto val = static_cast<uint8_t>(info.height * y + x);
+
+            EXPECT_EQ(val, yData[yStride * y + x]);
+
+            if (y % chromaStep == 0 && x % chromaStep == 0) {
+                EXPECT_EQ(val, cbData[cStride * y / chromaStep + x / chromaStep]);
+                EXPECT_EQ(val, crData[cStride * y / chromaStep + x / chromaStep]);
+            }
+        }
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+    if (fence >= 0) {
+        close(fence);
+    }
+}
+
 /**
  * Test IMapper::unlock with bad access region
  */
diff --git a/keymaster/4.0/vts/performance/Android.bp b/keymaster/4.0/vts/performance/Android.bp
new file mode 100644
index 0000000..9434bc9
--- /dev/null
+++ b/keymaster/4.0/vts/performance/Android.bp
@@ -0,0 +1,29 @@
+//
+// 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.
+//
+
+cc_benchmark {
+    name: "keymaster_benchmark",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "Benchmark.cpp",
+    ],
+    static_libs: [
+        "android.hardware.keymaster@4.0",
+        "libkeymaster4support",
+        "libsoftkeymasterdevice",
+        "libchrome"
+    ],
+}
diff --git a/keymaster/4.0/vts/performance/Benchmark.cpp b/keymaster/4.0/vts/performance/Benchmark.cpp
new file mode 100644
index 0000000..96ef5bf
--- /dev/null
+++ b/keymaster/4.0/vts/performance/Benchmark.cpp
@@ -0,0 +1,717 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "keymaster_benchmark"
+
+#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <keymaster/keymaster_configuration.h>
+#include <keymasterV4_0/authorization_set.h>
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <binder/IServiceManager.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <iostream>
+
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+
+#include <benchmark/benchmark.h>
+#include <hidl/Status.h>
+
+#include <base/command_line.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace test {
+
+// libutils:
+using android::OK;
+using android::sp;
+using android::status_t;
+
+// libhidl:
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+
+// IKeymaster:
+using android::IServiceManager;
+using android::hardware::hidl_string;
+using android::hardware::keymaster::V4_0::AuthorizationSet;
+using android::hardware::keymaster::V4_0::AuthorizationSetBuilder;
+using android::hardware::keymaster::V4_0::BlockMode;
+using android::hardware::keymaster::V4_0::ErrorCode;
+using android::hardware::keymaster::V4_0::IKeymasterDevice;
+using android::hardware::keymaster::V4_0::KeyCharacteristics;
+using android::hardware::keymaster::V4_0::SecurityLevel;
+
+// Standard library:
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::optional;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+class HidlBuf : public hidl_vec<uint8_t> {
+    typedef hidl_vec<uint8_t> super;
+
+  public:
+    HidlBuf() {}
+    HidlBuf(const super& other) : super(other) {}
+    HidlBuf(super&& other) : super(std::move(other)) {}
+    explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; }
+
+    HidlBuf& operator=(const super& other) {
+        super::operator=(other);
+        return *this;
+    }
+
+    HidlBuf& operator=(super&& other) {
+        super::operator=(std::move(other));
+        return *this;
+    }
+
+    HidlBuf& operator=(const string& other) {
+        resize(other.size());
+        std::copy(other.begin(), other.end(), begin());
+        return *this;
+    }
+
+    string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); }
+};
+
+#define SMALL_MESSAGE_SIZE 64
+#define MEDIUM_MESSAGE_SIZE 1024
+#define LARGE_MESSAGE_SIZE 131072
+
+class KeymasterWrapper {
+  private:
+    sp<IKeymasterDevice> keymaster_;
+    SecurityLevel securityLevel_;
+    hidl_string name_;
+    hidl_string author_;
+    HidlBuf key_blob_;
+    KeyCharacteristics key_characteristics_;
+    ErrorCode error_;
+    string key_transform_;
+    string keymaster_name_;
+    uint32_t os_version_;
+    uint32_t os_patch_level_;
+    std::vector<string> message_cache_;
+
+    bool GenerateKey(const AuthorizationSet& authSet) {
+        return (keymaster_
+                        ->generateKey(
+                                authSet.hidl_data(),
+                                [&](ErrorCode hidl_error, const hidl_vec<uint8_t>& hidl_key_blob,
+                                    const KeyCharacteristics& hidl_key_characteristics) {
+                                    error_ = hidl_error;
+                                    key_blob_ = hidl_key_blob;
+                                    key_characteristics_ = std::move(hidl_key_characteristics);
+                                })
+                        .isOk() &&
+                error_ == ErrorCode::OK);
+    }
+
+    bool GenerateKey(Algorithm algorithm, int keySize, Digest digest = Digest::NONE,
+                     PaddingMode padding = PaddingMode::NONE, optional<BlockMode> blockMode = {}) {
+        AuthorizationSetBuilder authSet = AuthorizationSetBuilder()
+                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                  .Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT)
+                                                  .Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT)
+                                                  .Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
+                                                  .Authorization(TAG_PURPOSE, KeyPurpose::VERIFY)
+                                                  .Authorization(TAG_KEY_SIZE, keySize)
+                                                  .Authorization(TAG_ALGORITHM, algorithm)
+                                                  .Digest(digest)
+                                                  .Authorization(TAG_MIN_MAC_LENGTH, 128)
+                                                  .Padding(padding);
+        if (blockMode) {
+            authSet.BlockMode(*blockMode);
+        }
+        if (algorithm == Algorithm::RSA) {
+            authSet.Authorization(TAG_RSA_PUBLIC_EXPONENT, 65537U);
+        }
+        return GenerateKey(authSet);
+    }
+
+    KeymasterWrapper(const sp<IKeymasterDevice> keymaster) {
+        os_version_ = ::keymaster::GetOsVersion();
+        os_patch_level_ = ::keymaster::GetOsPatchlevel();
+        keymaster_ = keymaster;
+        keymaster_->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
+                                        const hidl_string& author) {
+            securityLevel_ = securityLevel;
+            name_ = name;
+            author_ = author;
+        });
+
+        message_cache_.push_back(string(SMALL_MESSAGE_SIZE, 'x'));
+        message_cache_.push_back(string(MEDIUM_MESSAGE_SIZE, 'x'));
+        message_cache_.push_back(string(LARGE_MESSAGE_SIZE, 'x'));
+    }
+
+  public:
+    static KeymasterWrapper* newInstance(const std::string& keymaster_name) {
+        auto keymaster = IKeymasterDevice::getService(keymaster_name);
+        if (!keymaster) {
+            std::cerr << "Error: unable to find keymaster service named " << keymaster_name
+                      << std::endl;
+            return nullptr;
+        }
+        return new KeymasterWrapper(keymaster);
+    }
+
+    bool GenerateKey(string transform, int keySize, bool sign = false) {
+        if (transform == key_transform_) {
+            return true;
+        } else if (key_transform_ != "") {
+            // Deleting old key first
+            if (!DeleteKey()) {
+                return false;
+            }
+        }
+        optional<Algorithm> algorithm = getAlgorithm(transform);
+        if (!algorithm) {
+            cerr << "Error: invalid algorithm " << transform << endl;
+            return false;
+        }
+        key_transform_ = transform;
+        return GenerateKey(*algorithm, keySize, getDigest(transform), getPadding(transform, sign),
+                           getBlockMode(transform));
+    }
+
+    bool DeleteKey() {
+        key_blob_ = HidlBuf();
+        key_transform_ = "";
+        return keymaster_->deleteKey(key_blob_).isOk();
+    }
+
+    AuthorizationSet getOperationParams(string transform, bool sign = false) {
+        AuthorizationSetBuilder builder = AuthorizationSetBuilder()
+                                                  .Padding(getPadding(transform, sign))
+                                                  .Authorization(TAG_MAC_LENGTH, 128)
+                                                  .Digest(getDigest(transform));
+        optional<BlockMode> blockMode = getBlockMode(transform);
+        if (blockMode) {
+            builder.BlockMode(*blockMode);
+        }
+        return std::move(builder);
+    }
+
+    optional<OperationHandle> EncryptBegin(AuthorizationSet& in_params,
+                                           AuthorizationSet* out_params = new AuthorizationSet) {
+        return Begin(KeyPurpose::ENCRYPT, in_params, out_params);
+    }
+
+    optional<OperationHandle> DecryptBegin(AuthorizationSet& in_params,
+                                           AuthorizationSet* out_params = new AuthorizationSet) {
+        return Begin(KeyPurpose::DECRYPT, in_params, out_params);
+    }
+
+    optional<OperationHandle> SignBegin(AuthorizationSet& in_params,
+                                        AuthorizationSet* out_params = new AuthorizationSet) {
+        return Begin(KeyPurpose::SIGN, in_params, out_params);
+    }
+
+    optional<OperationHandle> VerifyBegin(AuthorizationSet& in_params,
+                                          AuthorizationSet* out_params = new AuthorizationSet) {
+        return Begin(KeyPurpose::VERIFY, in_params, out_params);
+    }
+
+    optional<OperationHandle> Begin(KeyPurpose operation, const AuthorizationSet& in_params,
+                                    AuthorizationSet* out_params) {
+        OperationHandle op_handle;
+        if (!keymaster_
+                     ->begin(operation, key_blob_, in_params.hidl_data(), HardwareAuthToken(),
+                             [&](ErrorCode hidl_error,
+                                 const hidl_vec<KeyParameter>& hidl_out_params,
+                                 uint64_t hidl_op_handle) {
+                                 error_ = hidl_error;
+                                 out_params->push_back(AuthorizationSet(hidl_out_params));
+                                 op_handle = hidl_op_handle;
+                             })
+                     .isOk() ||
+            error_ != ErrorCode::OK) {
+            keymaster_->abort(op_handle);
+            return {};
+        }
+        return op_handle;
+    }
+
+    optional<string> ProcessMessage(const OperationHandle& op_handle, const string& message,
+                                    const AuthorizationSet& in_params,
+                                    AuthorizationSet* out_params = new AuthorizationSet,
+                                    const string& signature = "") {
+        static const int HIDL_BUFFER_LIMIT = 1 << 14;  // 16KB
+
+        string output;
+        size_t input_consumed = 0;
+        while (message.length() - input_consumed > 0) {
+            if (!keymaster_
+                         ->update(op_handle, in_params.hidl_data(),
+                                  HidlBuf(message.substr(input_consumed, HIDL_BUFFER_LIMIT)),
+                                  HardwareAuthToken(), VerificationToken(),
+                                  [&](ErrorCode hidl_error, uint32_t hidl_input_consumed,
+                                      const hidl_vec<KeyParameter>& hidl_out_params,
+                                      const HidlBuf& hidl_output) {
+                                      error_ = hidl_error;
+                                      out_params->push_back(AuthorizationSet(hidl_out_params));
+                                      output.append(hidl_output.to_string());
+                                      input_consumed += hidl_input_consumed;
+                                  })
+                         .isOk() ||
+                error_ != ErrorCode::OK) {
+                keymaster_->abort(op_handle);
+                return {};
+            }
+        }
+
+        if (!keymaster_
+                     ->finish(op_handle, in_params.hidl_data(),
+                              HidlBuf(message.substr(input_consumed)), HidlBuf(signature),
+                              HardwareAuthToken(), VerificationToken(),
+                              [&](ErrorCode hidl_error,
+                                  const hidl_vec<KeyParameter>& hidl_out_params,
+                                  const HidlBuf& hidl_output) {
+                                  error_ = hidl_error;
+                                  out_params->push_back(AuthorizationSet(hidl_out_params));
+                                  output.append(hidl_output.to_string());
+                              })
+                     .isOk() ||
+            error_ != ErrorCode::OK) {
+            keymaster_->abort(op_handle);
+            return {};
+        }
+
+        return output;
+    }
+
+    int getError() { return static_cast<int>(error_); }
+
+    const string getHardwareName() { return name_; }
+
+    SecurityLevel getSecurityLevel() { return securityLevel_; }
+
+    const string& GenerateMessage(int size) {
+        for (const string& message : message_cache_) {
+            if (message.size() == size) {
+                return message;
+            }
+        }
+        string message = string(size, 'x');
+        message_cache_.push_back(message);
+        return std::move(message);
+    }
+
+    optional<BlockMode> getBlockMode(string transform) {
+        if (transform.find("/ECB") != string::npos) {
+            return BlockMode::ECB;
+        } else if (transform.find("/CBC") != string::npos) {
+            return BlockMode::CBC;
+        } else if (transform.find("/CTR") != string::npos) {
+            return BlockMode::CTR;
+        } else if (transform.find("/GCM") != string::npos) {
+            return BlockMode::GCM;
+        }
+        return {};
+    }
+
+    PaddingMode getPadding(string transform, bool sign) {
+        if (transform.find("/PKCS7") != string::npos) {
+            return PaddingMode::PKCS7;
+        } else if (transform.find("/PSS") != string::npos) {
+            return PaddingMode::RSA_PSS;
+        } else if (transform.find("/OAEP") != string::npos) {
+            return PaddingMode::RSA_OAEP;
+        } else if (transform.find("/PKCS1") != string::npos) {
+            return sign ? PaddingMode::RSA_PKCS1_1_5_SIGN : PaddingMode::RSA_PKCS1_1_5_ENCRYPT;
+        } else if (sign && transform.find("RSA") != string::npos) {
+            // RSA defaults to PKCS1 for sign
+            return PaddingMode::RSA_PKCS1_1_5_SIGN;
+        }
+        return PaddingMode::NONE;
+    }
+
+    optional<Algorithm> getAlgorithm(string transform) {
+        if (transform.find("AES") != string::npos) {
+            return Algorithm::AES;
+        } else if (transform.find("Hmac") != string::npos) {
+            return Algorithm::HMAC;
+        } else if (transform.find("DESede") != string::npos) {
+            return Algorithm::TRIPLE_DES;
+        } else if (transform.find("RSA") != string::npos) {
+            return Algorithm::RSA;
+        } else if (transform.find("EC") != string::npos) {
+            return Algorithm::EC;
+        }
+        cerr << "Can't find algorithm for " << transform << endl;
+        return {};
+    }
+
+    Digest getDigest(string transform) {
+        if (transform.find("MD5") != string::npos) {
+            return Digest::MD5;
+        } else if (transform.find("SHA1") != string::npos ||
+                   transform.find("SHA-1") != string::npos) {
+            return Digest::SHA1;
+        } else if (transform.find("SHA224") != string::npos) {
+            return Digest::SHA_2_224;
+        } else if (transform.find("SHA256") != string::npos) {
+            return Digest::SHA_2_256;
+        } else if (transform.find("SHA384") != string::npos) {
+            return Digest::SHA_2_384;
+        } else if (transform.find("SHA512") != string::npos) {
+            return Digest::SHA_2_512;
+        } else if (transform.find("RSA") != string::npos &&
+                   transform.find("OAEP") != string::npos) {
+            return Digest::SHA1;
+        }
+        return Digest::NONE;
+    }
+};
+
+KeymasterWrapper* keymaster;
+
+static void settings(benchmark::internal::Benchmark* benchmark) {
+    benchmark->Unit(benchmark::kMillisecond);
+}
+
+static void addDefaultLabel(benchmark::State& state) {
+    string secLevel;
+    switch (keymaster->getSecurityLevel()) {
+        case SecurityLevel::STRONGBOX:
+            secLevel = "STRONGBOX";
+            break;
+        case SecurityLevel::SOFTWARE:
+            secLevel = "SOFTWARE";
+            break;
+        case SecurityLevel::TRUSTED_ENVIRONMENT:
+            secLevel = "TEE";
+            break;
+    }
+    state.SetLabel("hardware_name:" + keymaster->getHardwareName() + " sec_level:" + secLevel);
+}
+
+// clang-format off
+#define BENCHMARK_KM(func, transform, keySize) \
+    BENCHMARK_CAPTURE(func, transform/keySize, #transform "/" #keySize, keySize)->Apply(settings);
+#define BENCHMARK_KM_MSG(func, transform, keySize, msgSize)                                      \
+    BENCHMARK_CAPTURE(func, transform/keySize/msgSize, #transform "/" #keySize "/" #msgSize, \
+                      keySize, msgSize)                                                          \
+            ->Apply(settings);
+
+#define BENCHMARK_KM_ALL_MSGS(func, transform, keySize)             \
+    BENCHMARK_KM_MSG(func, transform, keySize, SMALL_MESSAGE_SIZE)  \
+    BENCHMARK_KM_MSG(func, transform, keySize, MEDIUM_MESSAGE_SIZE) \
+    BENCHMARK_KM_MSG(func, transform, keySize, LARGE_MESSAGE_SIZE)
+
+#define BENCHMARK_KM_CIPHER(transform, keySize, msgSize)   \
+    BENCHMARK_KM_MSG(encrypt, transform, keySize, msgSize) \
+    BENCHMARK_KM_MSG(decrypt, transform, keySize, msgSize)
+
+#define BENCHMARK_KM_CIPHER_ALL_MSGS(transform, keySize) \
+    BENCHMARK_KM_ALL_MSGS(encrypt, transform, keySize)   \
+    BENCHMARK_KM_ALL_MSGS(decrypt, transform, keySize)
+
+#define BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, keySize) \
+    BENCHMARK_KM_ALL_MSGS(sign, transform, keySize)         \
+    BENCHMARK_KM_ALL_MSGS(verify, transform, keySize)
+// clang-format on
+
+/*
+ * ============= KeyGen TESTS ==================
+ */
+static void keygen(benchmark::State& state, string transform, int keySize) {
+    addDefaultLabel(state);
+    for (auto _ : state) {
+        keymaster->GenerateKey(transform, keySize);
+        state.PauseTiming();
+        keymaster->DeleteKey();
+        state.ResumeTiming();
+    }
+}
+
+BENCHMARK_KM(keygen, AES, 128);
+BENCHMARK_KM(keygen, AES, 256);
+
+BENCHMARK_KM(keygen, RSA, 2048);
+BENCHMARK_KM(keygen, RSA, 3072);
+BENCHMARK_KM(keygen, RSA, 4096);
+
+BENCHMARK_KM(keygen, EC, 224);
+BENCHMARK_KM(keygen, EC, 256);
+BENCHMARK_KM(keygen, EC, 384);
+BENCHMARK_KM(keygen, EC, 521);
+
+BENCHMARK_KM(keygen, DESede, 168);
+
+BENCHMARK_KM(keygen, Hmac, 64);
+BENCHMARK_KM(keygen, Hmac, 128);
+BENCHMARK_KM(keygen, Hmac, 256);
+BENCHMARK_KM(keygen, Hmac, 512);
+BENCHMARK_KM(keygen, Hmac, 1024);
+BENCHMARK_KM(keygen, Hmac, 2048);
+BENCHMARK_KM(keygen, Hmac, 4096);
+BENCHMARK_KM(keygen, Hmac, 8192);
+
+/*
+ * ============= SIGNATURE TESTS ==================
+ */
+
+static void sign(benchmark::State& state, string transform, int keySize, int msgSize) {
+    addDefaultLabel(state);
+    if (!keymaster->GenerateKey(transform, keySize, true)) {
+        state.SkipWithError(
+                ("Key generation error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    auto params = keymaster->getOperationParams(transform, true);
+    string message = keymaster->GenerateMessage(msgSize);
+
+    for (auto _ : state) {
+        state.PauseTiming();
+        auto opHandle = keymaster->SignBegin(params);
+        if (!opHandle) {
+            state.SkipWithError(
+                    ("Error beginning sign, " + std::to_string(keymaster->getError())).c_str());
+            return;
+        }
+        state.ResumeTiming();
+        if (!keymaster->ProcessMessage(*opHandle, message, params)) {
+            state.SkipWithError(("Sign error, " + std::to_string(keymaster->getError())).c_str());
+            break;
+        }
+    }
+}
+
+static void verify(benchmark::State& state, string transform, int keySize, int msgSize) {
+    addDefaultLabel(state);
+    if (!keymaster->GenerateKey(transform, keySize, true)) {
+        state.SkipWithError(
+                ("Key generation error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    AuthorizationSet out_params;
+    AuthorizationSet in_params = keymaster->getOperationParams(transform, true);
+    string message = keymaster->GenerateMessage(msgSize);
+    auto opHandle = keymaster->SignBegin(in_params, &out_params);
+    if (!opHandle) {
+        state.SkipWithError(
+                ("Error beginning sign, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    optional<string> signature =
+            keymaster->ProcessMessage(*opHandle, message, in_params, &out_params);
+    if (!signature) {
+        state.SkipWithError(("Sign error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    in_params.push_back(out_params);
+    for (auto _ : state) {
+        state.PauseTiming();
+        opHandle = keymaster->VerifyBegin(in_params);
+        if (!opHandle) {
+            state.SkipWithError(
+                    ("Verify begin error, " + std::to_string(keymaster->getError())).c_str());
+            return;
+        }
+        state.ResumeTiming();
+        if (!keymaster->ProcessMessage(*opHandle, message, in_params, &out_params, *signature)) {
+            state.SkipWithError(("Verify error, " + std::to_string(keymaster->getError())).c_str());
+            break;
+        }
+    }
+}
+
+// clang-format off
+#define BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(transform) \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 64)      \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 128)     \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 256)     \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 512)     \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 1024)    \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 2024)    \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 4096)    \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 8192)
+
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA1)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA256)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA224)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA256)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA384)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA512)
+
+#define BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(transform) \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 224)      \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 256)      \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 384)      \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 521)
+
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(NONEwithECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA1withECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA224withECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA256withECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA384withECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA512withECDSA);
+
+#define BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(transform) \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 2048)   \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 3072)   \
+    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 4096)
+
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(MD5withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA1withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA);
+
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(MD5withRSA/PSS);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA1withRSA/PSS);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA/PSS);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA/PSS);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA/PSS);
+// clang-format on
+
+/*
+ * ============= CIPHER TESTS ==================
+ */
+
+static void encrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+    addDefaultLabel(state);
+    if (!keymaster->GenerateKey(transform, keySize)) {
+        state.SkipWithError(
+                ("Key generation error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    auto params = keymaster->getOperationParams(transform);
+    string message = keymaster->GenerateMessage(msgSize);
+
+    for (auto _ : state) {
+        state.PauseTiming();
+        auto opHandle = keymaster->EncryptBegin(params);
+        if (!opHandle) {
+            state.SkipWithError(
+                    ("Encryption begin error, " + std::to_string(keymaster->getError())).c_str());
+            return;
+        }
+        state.ResumeTiming();
+        if (!keymaster->ProcessMessage(*opHandle, message, params)) {
+            state.SkipWithError(
+                    ("Encryption error, " + std::to_string(keymaster->getError())).c_str());
+            break;
+        }
+    }
+}
+
+static void decrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+    addDefaultLabel(state);
+    if (!keymaster->GenerateKey(transform, keySize)) {
+        state.SkipWithError(
+                ("Key generation error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    AuthorizationSet out_params;
+    AuthorizationSet in_params = keymaster->getOperationParams(transform);
+    string message = keymaster->GenerateMessage(msgSize);
+    auto opHandle = keymaster->EncryptBegin(in_params, &out_params);
+    if (!opHandle) {
+        state.SkipWithError(
+                ("Encryption begin error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    auto encryptedMessage = keymaster->ProcessMessage(*opHandle, message, in_params, &out_params);
+    if (!encryptedMessage) {
+        state.SkipWithError(("Encryption error, " + std::to_string(keymaster->getError())).c_str());
+        return;
+    }
+    in_params.push_back(out_params);
+    for (auto _ : state) {
+        state.PauseTiming();
+        opHandle = keymaster->DecryptBegin(in_params);
+        if (!opHandle) {
+            state.SkipWithError(
+                    ("Decryption begin error, " + std::to_string(keymaster->getError())).c_str());
+            return;
+        }
+        state.ResumeTiming();
+        if (!keymaster->ProcessMessage(*opHandle, *encryptedMessage, in_params)) {
+            state.SkipWithError(
+                    ("Decryption error, " + std::to_string(keymaster->getError())).c_str());
+            break;
+        }
+    }
+}
+
+// clang-format off
+// AES
+#define BENCHMARK_KM_CIPHER_ALL_AES_KEYS(transform) \
+    BENCHMARK_KM_CIPHER_ALL_MSGS(transform, 128)    \
+    BENCHMARK_KM_CIPHER_ALL_MSGS(transform, 256)
+
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/CBC/NoPadding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/CBC/PKCS7Padding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/CTR/NoPadding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/ECB/NoPadding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/ECB/PKCS7Padding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/GCM/NoPadding);
+
+// Triple DES
+BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/CBC/NoPadding, 168);
+BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/CBC/PKCS7Padding, 168);
+BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/ECB/NoPadding, 168);
+BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/ECB/PKCS7Padding, 168);
+
+#define BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(transform, msgSize) \
+    BENCHMARK_KM_CIPHER(transform, 2048, msgSize)            \
+    BENCHMARK_KM_CIPHER(transform, 3072, msgSize)            \
+    BENCHMARK_KM_CIPHER(transform, 4096, msgSize)
+
+BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/NoPadding, SMALL_MESSAGE_SIZE);
+BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/PKCS1Padding, SMALL_MESSAGE_SIZE);
+BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/OAEPPadding, SMALL_MESSAGE_SIZE);
+// clang-format on
+
+}  // namespace test
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    ::benchmark::Initialize(&argc, argv);
+    base::CommandLine::Init(argc, argv);
+    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+    auto service_name = command_line->GetSwitchValueASCII("service_name");
+    if (service_name.empty()) {
+        service_name = "default";
+    }
+    android::hardware::keymaster::V4_0::test::keymaster =
+            android::hardware::keymaster::V4_0::test::KeymasterWrapper::newInstance(service_name);
+    if (!android::hardware::keymaster::V4_0::test::keymaster) {
+        return 1;
+    }
+    ::benchmark::RunSpecifiedBenchmarks();
+}
\ No newline at end of file
diff --git a/keymaster/4.0/vts/performance/README b/keymaster/4.0/vts/performance/README
new file mode 100644
index 0000000..57d984a
--- /dev/null
+++ b/keymaster/4.0/vts/performance/README
@@ -0,0 +1,19 @@
+# Keymaster Benchmark
+
+The Keymaster Benchmark is a standalone tool for measuring the performance of keymaster implementations.
+
+## Building
+
+Build:
+`m  keymaster_benchmark`
+
+Transfer to device/emulator:
+`adb sync data`
+
+The benchmark executable should will be located at `data/benchmarktest/keymaster_benchmark/keymaster_benchmark` on the device.
+
+## Usage
+
+Keymaster Benchmark is built on [Google microbenchmark library](https://github.com/google/benchmark).
+All of the commandline arguments provided by the microbenchmark library are valid, such as `--benchmark_filter=<regex>` or `benchmark_out_format={json|console|csv}`.
+In addition to the command line arguments provided by microbenchmark, `--service_name=<service_name>` is provided allow specification of the keymaster service name, e.g. specify `--service_name=strongbox` to benchmark strongbox.