Merge "Merge "VTS: stop network scan once trigger network scan success" into qt-dev am: 6a660a6d7b am: 094d43cf68" into qt-r1-dev-plus-aosp
am: f83d597331
Change-Id: I2d960c9cfa8b14548bad7d1dc3b57b94b3253f07
diff --git a/gatekeeper/1.0/default/OWNERS b/gatekeeper/1.0/default/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/gatekeeper/1.0/default/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/gatekeeper/1.0/software/Android.bp b/gatekeeper/1.0/software/Android.bp
new file mode 100644
index 0000000..148c989
--- /dev/null
+++ b/gatekeeper/1.0/software/Android.bp
@@ -0,0 +1,28 @@
+cc_binary {
+ name: "android.hardware.gatekeeper@1.0-service.software",
+ defaults: ["hidl_defaults"],
+ relative_install_path: "hw",
+ vendor: true,
+ init_rc: ["android.hardware.gatekeeper@1.0-service.software.rc"],
+
+ srcs: [
+ "service.cpp",
+ "SoftGateKeeperDevice.cpp",
+ ],
+
+ shared_libs: [
+ "android.hardware.gatekeeper@1.0",
+ "libbase",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ "liblog",
+ "libcrypto",
+ "libgatekeeper",
+ ],
+
+ static_libs: ["libscrypt_static"],
+
+ vintf_fragments: ["android.hardware.gatekeeper@1.0-service.software.xml"],
+}
diff --git a/gatekeeper/1.0/software/OWNERS b/gatekeeper/1.0/software/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/gatekeeper/1.0/software/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/gatekeeper/1.0/software/SoftGateKeeper.h b/gatekeeper/1.0/software/SoftGateKeeper.h
new file mode 100644
index 0000000..3276d1e
--- /dev/null
+++ b/gatekeeper/1.0/software/SoftGateKeeper.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2015 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.
+ *
+ */
+
+#ifndef SOFT_GATEKEEPER_H_
+#define SOFT_GATEKEEPER_H_
+
+extern "C" {
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+
+#include <crypto_scrypt.h>
+}
+
+#include <android-base/memory.h>
+#include <gatekeeper/gatekeeper.h>
+
+#include <iostream>
+#include <memory>
+#include <unordered_map>
+
+namespace gatekeeper {
+
+struct fast_hash_t {
+ uint64_t salt;
+ uint8_t digest[SHA256_DIGEST_LENGTH];
+};
+
+class SoftGateKeeper : public GateKeeper {
+ public:
+ static const uint32_t SIGNATURE_LENGTH_BYTES = 32;
+
+ // scrypt params
+ static const uint64_t N = 16384;
+ static const uint32_t r = 8;
+ static const uint32_t p = 1;
+
+ static const int MAX_UINT_32_CHARS = 11;
+
+ SoftGateKeeper() {
+ key_.reset(new uint8_t[SIGNATURE_LENGTH_BYTES]);
+ memset(key_.get(), 0, SIGNATURE_LENGTH_BYTES);
+ }
+
+ virtual ~SoftGateKeeper() {}
+
+ virtual bool GetAuthTokenKey(const uint8_t** auth_token_key, uint32_t* length) const {
+ if (auth_token_key == NULL || length == NULL) return false;
+ *auth_token_key = key_.get();
+ *length = SIGNATURE_LENGTH_BYTES;
+ return true;
+ }
+
+ virtual void GetPasswordKey(const uint8_t** password_key, uint32_t* length) {
+ if (password_key == NULL || length == NULL) return;
+ *password_key = key_.get();
+ *length = SIGNATURE_LENGTH_BYTES;
+ }
+
+ virtual void ComputePasswordSignature(uint8_t* signature, uint32_t signature_length,
+ const uint8_t*, uint32_t, const uint8_t* password,
+ uint32_t password_length, salt_t salt) const {
+ if (signature == NULL) return;
+ crypto_scrypt(password, password_length, reinterpret_cast<uint8_t*>(&salt), sizeof(salt), N,
+ r, p, signature, signature_length);
+ }
+
+ virtual void GetRandom(void* random, uint32_t requested_length) const {
+ if (random == NULL) return;
+ RAND_pseudo_bytes((uint8_t*)random, requested_length);
+ }
+
+ virtual void ComputeSignature(uint8_t* signature, uint32_t signature_length, const uint8_t*,
+ uint32_t, const uint8_t*, const uint32_t) const {
+ if (signature == NULL) return;
+ memset(signature, 0, signature_length);
+ }
+
+ virtual uint64_t GetMillisecondsSinceBoot() const {
+ struct timespec time;
+ int res = clock_gettime(CLOCK_BOOTTIME, &time);
+ if (res < 0) return 0;
+ return (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000);
+ }
+
+ virtual bool IsHardwareBacked() const { return false; }
+
+ virtual bool GetFailureRecord(uint32_t uid, secure_id_t user_id, failure_record_t* record,
+ bool /* secure */) {
+ failure_record_t* stored = &failure_map_[uid];
+ if (user_id != stored->secure_user_id) {
+ stored->secure_user_id = user_id;
+ stored->last_checked_timestamp = 0;
+ stored->failure_counter = 0;
+ }
+ memcpy(record, stored, sizeof(*record));
+ return true;
+ }
+
+ virtual bool ClearFailureRecord(uint32_t uid, secure_id_t user_id, bool /* secure */) {
+ failure_record_t* stored = &failure_map_[uid];
+ stored->secure_user_id = user_id;
+ stored->last_checked_timestamp = 0;
+ stored->failure_counter = 0;
+ return true;
+ }
+
+ virtual bool WriteFailureRecord(uint32_t uid, failure_record_t* record, bool /* secure */) {
+ failure_map_[uid] = *record;
+ return true;
+ }
+
+ fast_hash_t ComputeFastHash(const SizedBuffer& password, uint64_t salt) {
+ fast_hash_t fast_hash;
+ size_t digest_size = password.size() + sizeof(salt);
+ std::unique_ptr<uint8_t[]> digest(new uint8_t[digest_size]);
+ memcpy(digest.get(), &salt, sizeof(salt));
+ memcpy(digest.get() + sizeof(salt), password.Data<uint8_t>(), password.size());
+
+ SHA256(digest.get(), digest_size, (uint8_t*)&fast_hash.digest);
+
+ fast_hash.salt = salt;
+ return fast_hash;
+ }
+
+ bool VerifyFast(const fast_hash_t& fast_hash, const SizedBuffer& password) {
+ fast_hash_t computed = ComputeFastHash(password, fast_hash.salt);
+ return memcmp(computed.digest, fast_hash.digest, SHA256_DIGEST_LENGTH) == 0;
+ }
+
+ bool DoVerify(const password_handle_t* expected_handle, const SizedBuffer& password) {
+ uint64_t user_id = android::base::get_unaligned<secure_id_t>(&expected_handle->user_id);
+ FastHashMap::const_iterator it = fast_hash_map_.find(user_id);
+ if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) {
+ return true;
+ } else {
+ if (GateKeeper::DoVerify(expected_handle, password)) {
+ uint64_t salt;
+ GetRandom(&salt, sizeof(salt));
+ fast_hash_map_[user_id] = ComputeFastHash(password, salt);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private:
+ typedef std::unordered_map<uint32_t, failure_record_t> FailureRecordMap;
+ typedef std::unordered_map<uint64_t, fast_hash_t> FastHashMap;
+
+ std::unique_ptr<uint8_t[]> key_;
+ FailureRecordMap failure_map_;
+ FastHashMap fast_hash_map_;
+};
+} // namespace gatekeeper
+
+#endif // SOFT_GATEKEEPER_H_
diff --git a/gatekeeper/1.0/software/SoftGateKeeperDevice.cpp b/gatekeeper/1.0/software/SoftGateKeeperDevice.cpp
new file mode 100644
index 0000000..d7a0b46
--- /dev/null
+++ b/gatekeeper/1.0/software/SoftGateKeeperDevice.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 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 "SoftGateKeeperDevice.h"
+#include "SoftGateKeeper.h"
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::gatekeeper::V1_0::GatekeeperStatusCode;
+using ::gatekeeper::EnrollRequest;
+using ::gatekeeper::EnrollResponse;
+using ::gatekeeper::ERROR_INVALID;
+using ::gatekeeper::ERROR_MEMORY_ALLOCATION_FAILED;
+using ::gatekeeper::ERROR_NONE;
+using ::gatekeeper::ERROR_RETRY;
+using ::gatekeeper::SizedBuffer;
+using ::gatekeeper::VerifyRequest;
+using ::gatekeeper::VerifyResponse;
+
+#include <limits>
+
+namespace android {
+
+inline SizedBuffer hidl_vec2sized_buffer(const hidl_vec<uint8_t>& vec) {
+ if (vec.size() == 0 || vec.size() > std::numeric_limits<uint32_t>::max()) return {};
+ auto dummy = new uint8_t[vec.size()];
+ std::copy(vec.begin(), vec.end(), dummy);
+ return {dummy, static_cast<uint32_t>(vec.size())};
+}
+
+Return<void> SoftGateKeeperDevice::enroll(uint32_t uid,
+ const hidl_vec<uint8_t>& currentPasswordHandle,
+ const hidl_vec<uint8_t>& currentPassword,
+ const hidl_vec<uint8_t>& desiredPassword,
+ enroll_cb _hidl_cb) {
+ if (desiredPassword.size() == 0) {
+ _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+ return {};
+ }
+
+ EnrollRequest request(uid, hidl_vec2sized_buffer(currentPasswordHandle),
+ hidl_vec2sized_buffer(desiredPassword),
+ hidl_vec2sized_buffer(currentPassword));
+ EnrollResponse response;
+ impl_->Enroll(request, &response);
+
+ if (response.error == ERROR_RETRY) {
+ _hidl_cb({GatekeeperStatusCode::ERROR_RETRY_TIMEOUT, response.retry_timeout, {}});
+ } else if (response.error != ERROR_NONE) {
+ _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+ } else {
+ hidl_vec<uint8_t> new_handle(response.enrolled_password_handle.Data<uint8_t>(),
+ response.enrolled_password_handle.Data<uint8_t>() +
+ response.enrolled_password_handle.size());
+ _hidl_cb({GatekeeperStatusCode::STATUS_OK, response.retry_timeout, new_handle});
+ }
+ return {};
+}
+
+Return<void> SoftGateKeeperDevice::verify(
+ uint32_t uid, uint64_t challenge,
+ const ::android::hardware::hidl_vec<uint8_t>& enrolledPasswordHandle,
+ const ::android::hardware::hidl_vec<uint8_t>& providedPassword, verify_cb _hidl_cb) {
+ if (enrolledPasswordHandle.size() == 0) {
+ _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+ return {};
+ }
+
+ VerifyRequest request(uid, challenge, hidl_vec2sized_buffer(enrolledPasswordHandle),
+ hidl_vec2sized_buffer(providedPassword));
+ VerifyResponse response;
+
+ impl_->Verify(request, &response);
+
+ if (response.error == ERROR_RETRY) {
+ _hidl_cb({GatekeeperStatusCode::ERROR_RETRY_TIMEOUT, response.retry_timeout, {}});
+ } else if (response.error != ERROR_NONE) {
+ _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+ } else {
+ hidl_vec<uint8_t> auth_token(
+ response.auth_token.Data<uint8_t>(),
+ response.auth_token.Data<uint8_t>() + response.auth_token.size());
+
+ _hidl_cb({response.request_reenroll ? GatekeeperStatusCode::STATUS_REENROLL
+ : GatekeeperStatusCode::STATUS_OK,
+ response.retry_timeout, auth_token});
+ }
+ return {};
+}
+
+Return<void> SoftGateKeeperDevice::deleteUser(uint32_t /*uid*/, deleteUser_cb _hidl_cb) {
+ _hidl_cb({GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED, 0, {}});
+ return {};
+}
+
+Return<void> SoftGateKeeperDevice::deleteAllUsers(deleteAllUsers_cb _hidl_cb) {
+ _hidl_cb({GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED, 0, {}});
+ return {};
+}
+
+} // namespace android
diff --git a/gatekeeper/1.0/software/SoftGateKeeperDevice.h b/gatekeeper/1.0/software/SoftGateKeeperDevice.h
new file mode 100644
index 0000000..17b474e
--- /dev/null
+++ b/gatekeeper/1.0/software/SoftGateKeeperDevice.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2015 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.
+ */
+
+#ifndef SOFT_GATEKEEPER_DEVICE_H_
+#define SOFT_GATEKEEPER_DEVICE_H_
+
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+#include <hidl/Status.h>
+
+#include <memory>
+#include "SoftGateKeeper.h"
+
+namespace android {
+
+/**
+ * Software based GateKeeper implementation
+ */
+class SoftGateKeeperDevice : public ::android::hardware::gatekeeper::V1_0::IGatekeeper {
+ public:
+ SoftGateKeeperDevice() { impl_.reset(new ::gatekeeper::SoftGateKeeper()); }
+
+ // Wrappers to translate the gatekeeper HAL API to the Kegyuard Messages API.
+
+ /**
+ * Enrolls password_payload, which should be derived from a user selected pin or password,
+ * with the authentication factor private key used only for enrolling authentication
+ * factor data.
+ *
+ * Returns: 0 on success or an error code less than 0 on error.
+ * On error, enrolled_password_handle will not be allocated.
+ */
+ ::android::hardware::Return<void> enroll(
+ uint32_t uid, const ::android::hardware::hidl_vec<uint8_t>& currentPasswordHandle,
+ const ::android::hardware::hidl_vec<uint8_t>& currentPassword,
+ const ::android::hardware::hidl_vec<uint8_t>& desiredPassword,
+ enroll_cb _hidl_cb) override;
+
+ /**
+ * Verifies provided_password matches enrolled_password_handle.
+ *
+ * Implementations of this module may retain the result of this call
+ * to attest to the recency of authentication.
+ *
+ * On success, writes the address of a verification token to auth_token,
+ * usable to attest password verification to other trusted services. Clients
+ * may pass NULL for this value.
+ *
+ * Returns: 0 on success or an error code less than 0 on error
+ * On error, verification token will not be allocated
+ */
+ ::android::hardware::Return<void> verify(
+ uint32_t uid, uint64_t challenge,
+ const ::android::hardware::hidl_vec<uint8_t>& enrolledPasswordHandle,
+ const ::android::hardware::hidl_vec<uint8_t>& providedPassword,
+ verify_cb _hidl_cb) override;
+
+ ::android::hardware::Return<void> deleteUser(uint32_t uid, deleteUser_cb _hidl_cb) override;
+
+ ::android::hardware::Return<void> deleteAllUsers(deleteAllUsers_cb _hidl_cb) override;
+
+ private:
+ std::unique_ptr<::gatekeeper::SoftGateKeeper> impl_;
+};
+
+} // namespace android
+
+#endif // SOFT_GATEKEEPER_DEVICE_H_
diff --git a/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.rc b/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.rc
new file mode 100644
index 0000000..60cb96c
--- /dev/null
+++ b/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.rc
@@ -0,0 +1,4 @@
+service vendor.gatekeeper-1-0 /vendor/bin/hw/android.hardware.gatekeeper@1.0-service.software
+ class hal
+ user system
+ group system
diff --git a/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.xml b/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.xml
new file mode 100644
index 0000000..19714a8
--- /dev/null
+++ b/gatekeeper/1.0/software/android.hardware.gatekeeper@1.0-service.software.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.gatekeeper</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IGatekeeper</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/gatekeeper/1.0/software/service.cpp b/gatekeeper/1.0/software/service.cpp
new file mode 100644
index 0000000..a48a964
--- /dev/null
+++ b/gatekeeper/1.0/software/service.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "android.hardware.gatekeeper@1.0-service"
+
+#include <android-base/logging.h>
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+
+#include <hidl/LegacySupport.h>
+
+#include "SoftGateKeeperDevice.h"
+
+// Generated HIDL files
+using android::SoftGateKeeperDevice;
+using android::hardware::gatekeeper::V1_0::IGatekeeper;
+
+int main() {
+ ::android::hardware::configureRpcThreadpool(1, true /* willJoinThreadpool */);
+ android::sp<SoftGateKeeperDevice> gatekeeper(new SoftGateKeeperDevice());
+ auto status = gatekeeper->registerAsService();
+ if (status != android::OK) {
+ LOG(FATAL) << "Could not register service for Gatekeeper 1.0 (software) (" << status << ")";
+ }
+
+ android::hardware::joinRpcThreadpool();
+ return -1; // Should never get here.
+}
diff --git a/gatekeeper/1.0/software/tests/Android.bp b/gatekeeper/1.0/software/tests/Android.bp
new file mode 100644
index 0000000..3f0300d
--- /dev/null
+++ b/gatekeeper/1.0/software/tests/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2015 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-software-device-unit-tests",
+
+ cflags: [
+ "-g",
+ "-Wall",
+ "-Werror",
+ "-Wno-missing-field-initializers",
+ ],
+ shared_libs: [
+ "libgatekeeper",
+ "libcrypto",
+ "libbase",
+ ],
+ static_libs: ["libscrypt_static"],
+
+ srcs: ["gatekeeper_test.cpp"],
+}
diff --git a/gatekeeper/1.0/software/tests/gatekeeper_test.cpp b/gatekeeper/1.0/software/tests/gatekeeper_test.cpp
new file mode 100644
index 0000000..bf4a8bc
--- /dev/null
+++ b/gatekeeper/1.0/software/tests/gatekeeper_test.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2015 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 <arpa/inet.h>
+#include <iostream>
+
+#include <gtest/gtest.h>
+#include <hardware/hw_auth_token.h>
+
+#include "../SoftGateKeeper.h"
+
+using ::gatekeeper::EnrollRequest;
+using ::gatekeeper::EnrollResponse;
+using ::gatekeeper::secure_id_t;
+using ::gatekeeper::SizedBuffer;
+using ::gatekeeper::SoftGateKeeper;
+using ::gatekeeper::VerifyRequest;
+using ::gatekeeper::VerifyResponse;
+using ::testing::Test;
+
+static SizedBuffer makePasswordBuffer(int init = 0) {
+ constexpr const uint32_t pw_buffer_size = 16;
+ auto pw_buffer = new uint8_t[pw_buffer_size];
+ memset(pw_buffer, init, pw_buffer_size);
+
+ return {pw_buffer, pw_buffer_size};
+}
+
+static SizedBuffer makeAndInitializeSizedBuffer(const uint8_t* data, uint32_t size) {
+ auto buffer = new uint8_t[size];
+ memcpy(buffer, data, size);
+ return {buffer, size};
+}
+
+static SizedBuffer copySizedBuffer(const SizedBuffer& rhs) {
+ return makeAndInitializeSizedBuffer(rhs.Data<uint8_t>(), rhs.size());
+}
+
+static void do_enroll(SoftGateKeeper& gatekeeper, EnrollResponse* response) {
+ EnrollRequest request(0, {}, makePasswordBuffer(), {});
+
+ gatekeeper.Enroll(request, response);
+}
+
+TEST(GateKeeperTest, EnrollSuccess) {
+ SoftGateKeeper gatekeeper;
+ EnrollResponse response;
+ do_enroll(gatekeeper, &response);
+ ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+}
+
+TEST(GateKeeperTest, EnrollBogusData) {
+ SoftGateKeeper gatekeeper;
+ EnrollResponse response;
+
+ EnrollRequest request(0, {}, {}, {});
+
+ gatekeeper.Enroll(request, &response);
+
+ ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_INVALID, response.error);
+}
+
+TEST(GateKeeperTest, VerifySuccess) {
+ SoftGateKeeper gatekeeper;
+ EnrollResponse enroll_response;
+
+ do_enroll(gatekeeper, &enroll_response);
+ ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+ VerifyRequest request(0, 1, std::move(enroll_response.enrolled_password_handle),
+ makePasswordBuffer());
+ VerifyResponse response;
+
+ gatekeeper.Verify(request, &response);
+
+ ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+
+ auto auth_token = response.auth_token.Data<hw_auth_token_t>();
+
+ ASSERT_NE(nullptr, auth_token);
+ ASSERT_EQ((uint32_t)HW_AUTH_PASSWORD, ntohl(auth_token->authenticator_type));
+ ASSERT_EQ((uint64_t)1, auth_token->challenge);
+ ASSERT_NE(~((uint32_t)0), auth_token->timestamp);
+ ASSERT_NE((uint64_t)0, auth_token->user_id);
+ ASSERT_NE((uint64_t)0, auth_token->authenticator_id);
+}
+
+TEST(GateKeeperTest, TrustedReEnroll) {
+ SoftGateKeeper gatekeeper;
+ EnrollResponse enroll_response;
+
+ // do_enroll enrolls an all 0 password
+ do_enroll(gatekeeper, &enroll_response);
+ ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+ // verify first password
+ VerifyRequest request(0, 0, copySizedBuffer(enroll_response.enrolled_password_handle),
+ makePasswordBuffer());
+ VerifyResponse response;
+ gatekeeper.Verify(request, &response);
+ ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+ auto auth_token = response.auth_token.Data<hw_auth_token_t>();
+ ASSERT_NE(nullptr, auth_token);
+
+ secure_id_t secure_id = auth_token->user_id;
+
+ // enroll new password
+ EnrollRequest enroll_request(0, std::move(enroll_response.enrolled_password_handle),
+ makePasswordBuffer(1) /* new password */,
+ makePasswordBuffer() /* old password */);
+ gatekeeper.Enroll(enroll_request, &enroll_response);
+ ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+ // verify new password
+ VerifyRequest new_request(0, 0, std::move(enroll_response.enrolled_password_handle),
+ makePasswordBuffer(1));
+ gatekeeper.Verify(new_request, &response);
+ ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+ ASSERT_NE(nullptr, response.auth_token.Data<hw_auth_token_t>());
+ ASSERT_EQ(secure_id, response.auth_token.Data<hw_auth_token_t>()->user_id);
+}
+
+TEST(GateKeeperTest, UntrustedReEnroll) {
+ SoftGateKeeper gatekeeper;
+ SizedBuffer provided_password;
+ EnrollResponse enroll_response;
+
+ // do_enroll enrolls an all 0 password
+ provided_password = makePasswordBuffer();
+ do_enroll(gatekeeper, &enroll_response);
+ ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+ // verify first password
+ VerifyRequest request(0, 0, std::move(enroll_response.enrolled_password_handle),
+ std::move(provided_password));
+ VerifyResponse response;
+ gatekeeper.Verify(request, &response);
+ ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+ auto auth_token = response.auth_token.Data<hw_auth_token_t>();
+ ASSERT_NE(nullptr, auth_token);
+
+ secure_id_t secure_id = auth_token->user_id;
+
+ EnrollRequest enroll_request(0, {}, makePasswordBuffer(1), {});
+ gatekeeper.Enroll(enroll_request, &enroll_response);
+ ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+ // verify new password
+ VerifyRequest new_request(0, 0, std::move(enroll_response.enrolled_password_handle),
+ makePasswordBuffer(1));
+ gatekeeper.Verify(new_request, &response);
+ ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+ ASSERT_NE(nullptr, response.auth_token.Data<hw_auth_token_t>());
+ ASSERT_NE(secure_id, response.auth_token.Data<hw_auth_token_t>()->user_id);
+}
+
+TEST(GateKeeperTest, VerifyBogusData) {
+ SoftGateKeeper gatekeeper;
+ VerifyResponse response;
+
+ VerifyRequest request(0, 0, {}, {});
+
+ gatekeeper.Verify(request, &response);
+
+ ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_INVALID, response.error);
+}
diff --git a/gatekeeper/1.0/vts/OWNERS b/gatekeeper/1.0/vts/OWNERS
new file mode 100644
index 0000000..738c710
--- /dev/null
+++ b/gatekeeper/1.0/vts/OWNERS
@@ -0,0 +1,3 @@
+jdanis@google.com
+swillden@google.com
+guangzhu@google.com
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index 846cfdf..fcb327f 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -25,6 +25,8 @@
static_libs: [
"VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.mapper@2.0-vts",
+ "android.hardware.graphics.mapper@3.0-vts",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index 7ba67d4..c5d5823 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -315,6 +315,77 @@
writer->reset();
}
+Gralloc::Gralloc() {
+ [this] {
+ ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+ /*errOnFailure=*/false));
+ if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) {
+ mGralloc3 = nullptr;
+ ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+ }
+ }();
+}
+
+const native_handle_t* Gralloc::allocate(uint32_t width, uint32_t height, uint32_t layerCount,
+ PixelFormat format, uint64_t usage, bool import,
+ uint32_t* outStride) {
+ if (mGralloc3) {
+ IMapper3::BufferDescriptorInfo info{};
+ info.width = width;
+ info.height = height;
+ info.layerCount = layerCount;
+ info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
+ info.usage = usage;
+ return mGralloc3->allocate(info, import, outStride);
+ } else {
+ IMapper2::BufferDescriptorInfo info{};
+ info.width = width;
+ info.height = height;
+ info.layerCount = layerCount;
+ info.format = format;
+ info.usage = usage;
+ return mGralloc2->allocate(info, import, outStride);
+ }
+}
+
+void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+ const AccessRegion& accessRegionRect, int acquireFence) {
+ if (mGralloc3) {
+ IMapper3::Rect accessRegion;
+ accessRegion.left = accessRegionRect.left;
+ accessRegion.top = accessRegionRect.top;
+ accessRegion.width = accessRegionRect.width;
+ accessRegion.height = accessRegionRect.height;
+ int32_t bytesPerPixel;
+ int32_t bytesPerStride;
+ return mGralloc3->lock(bufferHandle, cpuUsage, accessRegion, acquireFence, &bytesPerPixel,
+ &bytesPerStride);
+ } else {
+ IMapper2::Rect accessRegion;
+ accessRegion.left = accessRegionRect.left;
+ accessRegion.top = accessRegionRect.top;
+ accessRegion.width = accessRegionRect.width;
+ accessRegion.height = accessRegionRect.height;
+ return mGralloc2->lock(bufferHandle, cpuUsage, accessRegion, acquireFence);
+ }
+}
+
+int Gralloc::unlock(const native_handle_t* bufferHandle) {
+ if (mGralloc3) {
+ return mGralloc3->unlock(bufferHandle);
+ } else {
+ return mGralloc2->unlock(bufferHandle);
+ }
+}
+
+void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
+ if (mGralloc3) {
+ mGralloc3->freeBuffer(bufferHandle);
+ } else {
+ mGralloc2->freeBuffer(bufferHandle);
+ }
+}
+
} // namespace vts
} // namespace V2_1
} // namespace composer
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
index c97be76..7811048 100644
--- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
@@ -25,8 +25,12 @@
#include <android/hardware/graphics/composer/2.1/IComposer.h>
#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
#include <composer-vts/2.1/TestCommandReader.h>
+#include <mapper-vts/2.0/MapperVts.h>
+#include <mapper-vts/3.0/MapperVts.h>
#include <utils/StrongPointer.h>
+#include "gtest/gtest.h"
+
namespace android {
namespace hardware {
namespace graphics {
@@ -38,6 +42,10 @@
using android::hardware::graphics::common::V1_0::Dataspace;
using android::hardware::graphics::common::V1_0::Hdr;
using android::hardware::graphics::common::V1_0::PixelFormat;
+using IMapper2 = android::hardware::graphics::mapper::V2_0::IMapper;
+using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc;
+using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
class ComposerClient;
@@ -119,6 +127,34 @@
const sp<IComposerClient> mClient;
};
+class AccessRegion {
+ public:
+ int32_t left;
+ int32_t top;
+ int32_t width;
+ int32_t height;
+};
+
+class Gralloc {
+ public:
+ explicit Gralloc();
+
+ const native_handle_t* allocate(uint32_t width, uint32_t height, uint32_t layerCount,
+ PixelFormat format, uint64_t usage, bool import = true,
+ uint32_t* outStride = nullptr);
+
+ void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+ const AccessRegion& accessRegionRect, int acquireFence);
+
+ int unlock(const native_handle_t* bufferHandle);
+
+ void freeBuffer(const native_handle_t* bufferHandle);
+
+ protected:
+ std::shared_ptr<Gralloc2> mGralloc2 = nullptr;
+ std::shared_ptr<Gralloc3> mGralloc3 = nullptr;
+};
+
} // namespace vts
} // namespace V2_1
} // namespace composer
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index c98cc0d..d54da60 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -26,10 +26,13 @@
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.0-vts",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@3.0-vts",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 3c408b7..30b9694 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -21,6 +21,7 @@
#include <composer-vts/2.1/GraphicsComposerCallback.h>
#include <composer-vts/2.1/TestCommandReader.h>
#include <mapper-vts/2.0/MapperVts.h>
+#include <mapper-vts/3.0/MapperVts.h>
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
@@ -47,8 +48,6 @@
using android::hardware::graphics::common::V1_0::Dataspace;
using android::hardware::graphics::common::V1_0::PixelFormat;
using android::hardware::graphics::common::V1_0::Transform;
-using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::vts::Gralloc;
using GrallocError = android::hardware::graphics::mapper::V2_0::Error;
// Test environment for graphics.composer
@@ -669,7 +668,6 @@
ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
-
Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay);
mDisplayWidth = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig,
IComposerClient::Attribute::WIDTH);
@@ -685,16 +683,10 @@
}
const native_handle_t* allocate() {
- IMapper::BufferDescriptorInfo info{};
- info.width = mDisplayWidth;
- info.height = mDisplayHeight;
- info.layerCount = 1;
- info.format = PixelFormat::RGBA_8888;
- info.usage =
- static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN |
- BufferUsage::COMPOSER_OVERLAY);
-
- return mGralloc->allocate(info);
+ uint64_t usage =
+ static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY);
+ return mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage);
}
void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
@@ -705,7 +697,7 @@
int32_t mDisplayHeight;
private:
- std::unique_ptr<Gralloc> mGralloc;
+ std::unique_ptr<Gralloc> mGralloc;
};
/**
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index c6b524d..56b12f5 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -19,12 +19,17 @@
defaults: ["hidl_defaults"],
srcs: [
"ComposerVts.cpp",
+ "ReadbackVts.cpp",
],
static_libs: [
"VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.mapper@2.1",
+ "android.hardware.graphics.mapper@2.1-vts",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@3.0-vts",
],
export_static_lib_headers: [
"android.hardware.graphics.composer@2.1-vts",
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index da99460..a380fc0 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -180,6 +180,48 @@
return matrix;
}
+Gralloc::Gralloc() {
+ [this] {
+ ALOGD("Attempting to initialize gralloc3");
+ ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+ /*errOnFailure=*/false));
+ if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) {
+ mGralloc3 = nullptr;
+ ALOGD("Failed to initialize gralloc3, initializing gralloc2_1");
+ mGralloc2_1 = std::make_shared<Gralloc2_1>(/*errOnFailure*/ false);
+ if (!mGralloc2_1->getMapper()) {
+ mGralloc2_1 = nullptr;
+ ALOGD("Failed to initialize gralloc2_1, initializing gralloc2");
+ ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+ }
+ }
+ }();
+}
+
+bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle, uint32_t width,
+ uint32_t height, uint32_t layerCount, PixelFormat format,
+ uint64_t usage, uint32_t stride) {
+ if (mGralloc3) {
+ IMapper3::BufferDescriptorInfo info{};
+ info.width = width;
+ info.height = height;
+ info.layerCount = layerCount;
+ info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
+ info.usage = usage;
+ return mGralloc3->validateBufferSize(bufferHandle, info, stride);
+ } else if (mGralloc2_1) {
+ IMapper2_1::BufferDescriptorInfo info{};
+ info.width = width;
+ info.height = height;
+ info.layerCount = layerCount;
+ info.format = static_cast<android::hardware::graphics::common::V1_1::PixelFormat>(format);
+ info.usage = usage;
+ return mGralloc2_1->validateBufferSize(bufferHandle, info, stride);
+ } else {
+ return true;
+ }
+}
+
} // namespace vts
} // namespace V2_2
} // namespace composer
diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
new file mode 100644
index 0000000..81a6452
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <composer-vts/2.2/ReadbackVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+
+void TestLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
+ writer->selectLayer(mLayer);
+ writer->setLayerDisplayFrame(mDisplayFrame);
+ writer->setLayerSourceCrop(mSourceCrop);
+ writer->setLayerZOrder(mZOrder);
+ writer->setLayerSurfaceDamage(mSurfaceDamage);
+ writer->setLayerTransform(mTransform);
+ writer->setLayerPlaneAlpha(mAlpha);
+ writer->setLayerBlendMode(mBlendMode);
+}
+
+int32_t ReadbackHelper::GetBytesPerPixel(PixelFormat pixelFormat) {
+ switch (pixelFormat) {
+ case PixelFormat::RGBA_8888:
+ return 4;
+ case PixelFormat::RGB_888:
+ return 3;
+ default:
+ return -1;
+ }
+}
+
+void ReadbackHelper::fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
+ PixelFormat pixelFormat,
+ std::vector<IComposerClient::Color> desiredPixelColors) {
+ ASSERT_TRUE(pixelFormat == PixelFormat::RGB_888 || pixelFormat == PixelFormat::RGBA_8888);
+ int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
+ ASSERT_NE(-1, bytesPerPixel);
+ for (int row = 0; row < height; row++) {
+ for (int col = 0; col < width; col++) {
+ int pixel = row * width + col;
+ IComposerClient::Color srcColor = desiredPixelColors[pixel];
+
+ int offset = (row * stride + col) * bytesPerPixel;
+ uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+ pixelColor[0] = srcColor.r;
+ pixelColor[1] = srcColor.g;
+ pixelColor[2] = srcColor.b;
+
+ if (bytesPerPixel == 4) {
+ pixelColor[3] = srcColor.a;
+ }
+ }
+ }
+}
+
+void ReadbackHelper::clearColors(std::vector<IComposerClient::Color>& expectedColors, int32_t width,
+ int32_t height, int32_t displayWidth) {
+ for (int row = 0; row < height; row++) {
+ for (int col = 0; col < width; col++) {
+ int pixel = row * displayWidth + col;
+ expectedColors[pixel] = BLACK;
+ }
+ }
+}
+
+void ReadbackHelper::fillColorsArea(std::vector<IComposerClient::Color>& expectedColors,
+ int32_t stride, IComposerClient::Rect area,
+ IComposerClient::Color color) {
+ for (int row = area.top; row < area.bottom; row++) {
+ for (int col = area.left; col < area.right; col++) {
+ int pixel = row * stride + col;
+ expectedColors[pixel] = color;
+ }
+ }
+}
+
+bool ReadbackHelper::readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
+ const Error error) {
+ if (error != Error::NONE) {
+ return false;
+ }
+ // TODO: add support for RGBA_1010102
+ if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) {
+ return false;
+ }
+ if (dataspace != Dataspace::V0_SRGB) {
+ return false;
+ }
+ return true;
+}
+
+ReadbackBuffer::ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
+ const std::shared_ptr<Gralloc>& gralloc, uint32_t width,
+ uint32_t height, PixelFormat pixelFormat, Dataspace dataspace) {
+ mDisplay = display;
+
+ mComposerClient = client;
+ mGralloc = gralloc;
+
+ mPixelFormat = pixelFormat;
+ mDataspace = dataspace;
+
+ mWidth = width;
+ mHeight = height;
+ mLayerCount = 1;
+ mFormat = mPixelFormat;
+ mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE);
+
+ mAccessRegion.top = 0;
+ mAccessRegion.left = 0;
+ mAccessRegion.width = width;
+ mAccessRegion.height = height;
+}
+
+ReadbackBuffer::~ReadbackBuffer() {
+ if (mBufferHandle != nullptr) {
+ mGralloc->freeBuffer(mBufferHandle);
+ }
+}
+
+void ReadbackBuffer::setReadbackBuffer() {
+ if (mBufferHandle != nullptr) {
+ mGralloc->freeBuffer(mBufferHandle);
+ mBufferHandle = nullptr;
+ }
+ mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
+ /*import*/ true, &mStride);
+ ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount,
+ mFormat, mUsage, mStride));
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle, -1));
+}
+
+void ReadbackBuffer::checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors) {
+ // lock buffer for reading
+ int32_t fenceHandle;
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle));
+
+ void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, fenceHandle);
+ ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
+ int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(mPixelFormat);
+ ASSERT_NE(-1, bytesPerPixel);
+ for (int row = 0; row < mHeight; row++) {
+ for (int col = 0; col < mWidth; col++) {
+ int pixel = row * mWidth + col;
+ int offset = (row * mStride + col) * bytesPerPixel;
+ uint8_t* pixelColor = (uint8_t*)bufData + offset;
+
+ ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]);
+ ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]);
+ ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]);
+ }
+ }
+ int32_t unlockFence = mGralloc->unlock(mBufferHandle);
+ if (unlockFence != -1) {
+ sync_wait(unlockFence, -1);
+ close(unlockFence);
+ }
+}
+
+void TestColorLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
+ TestLayer::write(writer);
+ writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
+ writer->setLayerColor(mColor);
+}
+
+TestBufferLayer::TestBufferLayer(const std::shared_ptr<ComposerClient>& client,
+ const std::shared_ptr<Gralloc>& gralloc, Display display,
+ int32_t width, int32_t height, PixelFormat format,
+ IComposerClient::Composition composition)
+ : TestLayer{client, display} {
+ mGralloc = gralloc;
+ mComposition = composition;
+ mWidth = width;
+ mHeight = height;
+ mLayerCount = 1;
+ mFormat = format;
+ mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY);
+
+ mAccessRegion.top = 0;
+ mAccessRegion.left = 0;
+ mAccessRegion.width = width;
+ mAccessRegion.height = height;
+
+ setSourceCrop({0, 0, (float)width, (float)height});
+}
+
+TestBufferLayer::~TestBufferLayer() {
+ if (mBufferHandle != nullptr) {
+ mGralloc->freeBuffer(mBufferHandle);
+ }
+}
+
+void TestBufferLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
+ TestLayer::write(writer);
+ writer->setLayerCompositionType(mComposition);
+ writer->setLayerDataspace(Dataspace::UNKNOWN);
+ writer->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, mDisplayFrame));
+ if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence);
+}
+
+void TestBufferLayer::fillBuffer(std::vector<IComposerClient::Color> expectedColors) {
+ void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, -1);
+ ASSERT_NO_FATAL_FAILURE(
+ ReadbackHelper::fillBuffer(mWidth, mHeight, mStride, bufData, mFormat, expectedColors));
+ mFillFence = mGralloc->unlock(mBufferHandle);
+ if (mFillFence != -1) {
+ sync_wait(mFillFence, -1);
+ close(mFillFence);
+ }
+}
+void TestBufferLayer::setBuffer(std::vector<IComposerClient::Color> colors) {
+ if (mBufferHandle != nullptr) {
+ mGralloc->freeBuffer(mBufferHandle);
+ mBufferHandle = nullptr;
+ }
+ mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
+ /*import*/ true, &mStride);
+ ASSERT_NE(nullptr, mBufferHandle);
+ ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
+ ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount,
+ mFormat, mUsage, mStride));
+}
+
+void TestBufferLayer::setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer) {
+ writer->selectLayer(mLayer);
+ writer->setLayerCompositionType(IComposerClient::Composition::CLIENT);
+}
+
+} // namespace vts
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index 2633021..8fa9b7b 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -27,6 +27,7 @@
#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
#include <composer-vts/2.1/ComposerVts.h>
+#include <mapper-vts/2.1/MapperVts.h>
#include <utils/StrongPointer.h>
namespace android {
@@ -41,6 +42,11 @@
using common::V1_1::Dataspace;
using common::V1_1::PixelFormat;
using common::V1_1::RenderIntent;
+using IMapper2_1 = android::hardware::graphics::mapper::V2_1::IMapper;
+using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc;
+using Gralloc2_1 = android::hardware::graphics::mapper::V2_1::vts::Gralloc;
+using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
class ComposerClient;
@@ -84,6 +90,26 @@
const sp<IComposerClient> mClient;
};
+class Gralloc : public V2_1::vts::Gralloc {
+ public:
+ Gralloc();
+ const native_handle_t* allocate(uint32_t width, uint32_t height, uint32_t layerCount,
+ PixelFormat format, uint64_t usage, bool import = true,
+ uint32_t* outStride = nullptr) {
+ return V2_1::vts::Gralloc::allocate(
+ width, height, layerCount,
+ static_cast<android::hardware::graphics::common::V1_0::PixelFormat>(format), usage,
+ import, outStride);
+ }
+
+ bool validateBufferSize(const native_handle_t* bufferHandle, uint32_t width, uint32_t height,
+ uint32_t layerCount, PixelFormat format, uint64_t usage,
+ uint32_t stride);
+
+ protected:
+ std::shared_ptr<Gralloc2_1> mGralloc2_1 = nullptr;
+};
+
} // namespace vts
} // namespace V2_2
} // namespace composer
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
new file mode 100644
index 0000000..7e93167
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+#include <composer-vts/2.2/ComposerVts.h>
+#include <mapper-vts/2.1/MapperVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+
+using android::hardware::hidl_handle;
+using common::V1_1::BufferUsage;
+using common::V1_1::Dataspace;
+using common::V1_1::PixelFormat;
+using IMapper2_1 = mapper::V2_1::IMapper;
+using Gralloc2_1 = mapper::V2_1::vts::Gralloc;
+using V2_1::Display;
+using V2_1::Layer;
+using V2_1::vts::AccessRegion;
+using V2_1::vts::TestCommandReader;
+
+static const IComposerClient::Color BLACK = {0, 0, 0, 0xff};
+static const IComposerClient::Color RED = {0xff, 0, 0, 0xff};
+static const IComposerClient::Color TRANSLUCENT_RED = {0xff, 0, 0, 0x33};
+static const IComposerClient::Color GREEN = {0, 0xff, 0, 0xff};
+static const IComposerClient::Color BLUE = {0, 0, 0xff, 0xff};
+
+class TestLayer {
+ public:
+ TestLayer(const std::shared_ptr<ComposerClient>& client, Display display)
+ : mLayer(client->createLayer(display, kBufferSlotCount)), mComposerClient(client) {}
+
+ // ComposerClient will take care of destroying layers, no need to explicitly
+ // call destroyLayers here
+ virtual ~TestLayer(){};
+
+ virtual void write(const std::shared_ptr<CommandWriterBase>& writer);
+
+ void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; }
+ void setSourceCrop(IComposerClient::FRect crop) { mSourceCrop = crop; }
+ void setZOrder(uint32_t z) { mZOrder = z; }
+
+ void setSurfaceDamage(std::vector<IComposerClient::Rect> surfaceDamage) {
+ mSurfaceDamage = surfaceDamage;
+ }
+
+ void setTransform(Transform transform) { mTransform = transform; }
+ void setAlpha(float alpha) { mAlpha = alpha; }
+ void setBlendMode(IComposerClient::BlendMode blendMode) { mBlendMode = blendMode; }
+
+ static constexpr uint32_t kBufferSlotCount = 64;
+
+ IComposerClient::Rect mDisplayFrame = {0, 0, 0, 0};
+ uint32_t mZOrder = 0;
+ std::vector<IComposerClient::Rect> mSurfaceDamage;
+ Transform mTransform = static_cast<Transform>(0);
+ IComposerClient::FRect mSourceCrop = {0, 0, 0, 0};
+ float mAlpha = 1.0;
+ IComposerClient::BlendMode mBlendMode = IComposerClient::BlendMode::NONE;
+
+ protected:
+ Layer mLayer;
+
+ private:
+ std::shared_ptr<ComposerClient> const mComposerClient;
+};
+
+class TestColorLayer : public TestLayer {
+ public:
+ TestColorLayer(const std::shared_ptr<ComposerClient>& client, Display display)
+ : TestLayer{client, display} {}
+
+ void write(const std::shared_ptr<CommandWriterBase>& writer) override;
+
+ void setColor(IComposerClient::Color color) { mColor = color; }
+
+ private:
+ IComposerClient::Color mColor = {0xff, 0xff, 0xff, 0xff};
+};
+
+class TestBufferLayer : public TestLayer {
+ public:
+ TestBufferLayer(
+ const std::shared_ptr<ComposerClient>& client, const std::shared_ptr<Gralloc>& gralloc,
+ Display display, int32_t width, int32_t height, PixelFormat format,
+ IComposerClient::Composition composition = IComposerClient::Composition::DEVICE);
+
+ ~TestBufferLayer();
+
+ void write(const std::shared_ptr<CommandWriterBase>& writer) override;
+
+ void fillBuffer(std::vector<IComposerClient::Color> expectedColors);
+
+ void setBuffer(std::vector<IComposerClient::Color> colors);
+
+ void setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer);
+
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mLayerCount;
+ PixelFormat mFormat;
+ uint64_t mUsage;
+ AccessRegion mAccessRegion;
+ uint32_t mStride;
+
+ protected:
+ IComposerClient::Composition mComposition;
+ std::shared_ptr<Gralloc> mGralloc;
+ int32_t mFillFence;
+ const native_handle_t* mBufferHandle = nullptr;
+};
+
+class ReadbackHelper : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
+
+ static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
+ PixelFormat pixelFormat,
+ std::vector<IComposerClient::Color> desiredPixelColors);
+
+ static void clearColors(std::vector<IComposerClient::Color>& expectedColors, int32_t width,
+ int32_t height, int32_t displayWidth);
+
+ static void fillColorsArea(std::vector<IComposerClient::Color>& expectedColors, int32_t stride,
+ IComposerClient::Rect area, IComposerClient::Color color);
+
+ static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
+ const Error error);
+};
+
+class ReadbackBuffer {
+ public:
+ ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
+ const std::shared_ptr<Gralloc>& gralloc, uint32_t width, uint32_t height,
+ PixelFormat pixelFormat, Dataspace dataspace);
+ ~ReadbackBuffer();
+
+ void setReadbackBuffer();
+
+ void checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors);
+
+ protected:
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mLayerCount;
+ PixelFormat mFormat;
+ uint64_t mUsage;
+ AccessRegion mAccessRegion;
+ uint32_t mStride;
+ const native_handle_t* mBufferHandle = nullptr;
+ PixelFormat mPixelFormat;
+ Dataspace mDataspace;
+ Display mDisplay;
+ std::shared_ptr<Gralloc> mGralloc;
+ std::shared_ptr<ComposerClient> mComposerClient;
+};
+
+} // namespace vts
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index 4cb0bdf..9f7e1cd 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -31,6 +31,7 @@
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.1-vts",
@@ -40,6 +41,8 @@
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@2.1-vts",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@3.0-vts",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index da8858e..eef0433 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -18,13 +18,10 @@
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
-#include <android-base/unique_fd.h>
-#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
#include <composer-vts/2.1/GraphicsComposerCallback.h>
#include <composer-vts/2.1/TestCommandReader.h>
-#include <composer-vts/2.2/ComposerVts.h>
-#include <mapper-vts/2.1/MapperVts.h>
+#include <composer-vts/2.2/ReadbackVts.h>
namespace android {
namespace hardware {
@@ -39,17 +36,10 @@
using common::V1_1::Dataspace;
using common::V1_1::PixelFormat;
using mapper::V2_1::IMapper;
-using mapper::V2_1::vts::Gralloc;
using V2_1::Display;
using V2_1::Layer;
using V2_1::vts::TestCommandReader;
-static const IComposerClient::Color BLACK = {0, 0, 0, 0xff};
-static const IComposerClient::Color RED = {0xff, 0, 0, 0xff};
-static const IComposerClient::Color TRANSLUCENT_RED = {0xff, 0, 0, 0x33};
-static const IComposerClient::Color GREEN = {0, 0xff, 0, 0xff};
-static const IComposerClient::Color BLUE = {0, 0, 0xff, 0xff};
-
// Test environment for graphics.composer
class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
public:
@@ -65,92 +55,7 @@
GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
};
-class TestLayer {
- public:
- TestLayer(const std::shared_ptr<ComposerClient>& client, Display display)
- : mLayer(client->createLayer(display, kBufferSlotCount)), mComposerClient(client) {}
-
- // ComposerClient will take care of destroying layers, no need to explicitly
- // call destroyLayers here
- virtual ~TestLayer(){};
-
- virtual void write(const std::shared_ptr<CommandWriterBase>& writer) {
- writer->selectLayer(mLayer);
- writer->setLayerDisplayFrame(mDisplayFrame);
- writer->setLayerSourceCrop(mSourceCrop);
- writer->setLayerZOrder(mZOrder);
- writer->setLayerSurfaceDamage(mSurfaceDamage);
- writer->setLayerTransform(mTransform);
- writer->setLayerPlaneAlpha(mAlpha);
- writer->setLayerBlendMode(mBlendMode);
- }
-
- void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; }
- void setSourceCrop(IComposerClient::FRect crop) { mSourceCrop = crop; }
- void setZOrder(uint32_t z) { mZOrder = z; }
-
- void setSurfaceDamage(std::vector<IComposerClient::Rect> surfaceDamage) {
- mSurfaceDamage = surfaceDamage;
- }
-
- void setTransform(Transform transform) { mTransform = transform; }
- void setAlpha(float alpha) { mAlpha = alpha; }
- void setBlendMode(IComposerClient::BlendMode blendMode) { mBlendMode = blendMode; }
-
- static constexpr uint32_t kBufferSlotCount = 64;
-
- IComposerClient::Rect mDisplayFrame = {0, 0, 0, 0};
- uint32_t mZOrder = 0;
- std::vector<IComposerClient::Rect> mSurfaceDamage;
- Transform mTransform = static_cast<Transform>(0);
- IComposerClient::FRect mSourceCrop = {0, 0, 0, 0};
- float mAlpha = 1.0;
- IComposerClient::BlendMode mBlendMode = IComposerClient::BlendMode::NONE;
-
- protected:
- Layer mLayer;
-
- private:
- std::shared_ptr<ComposerClient> const mComposerClient;
-};
-
class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
- static int32_t GetBytesPerPixel(PixelFormat pixelFormat) {
- switch (pixelFormat) {
- case PixelFormat::RGBA_8888:
- return 4;
- case PixelFormat::RGB_888:
- return 3;
- default:
- return -1;
- }
- }
-
- static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
- PixelFormat pixelFormat,
- std::vector<IComposerClient::Color> desiredPixelColors) {
- ASSERT_TRUE(pixelFormat == PixelFormat::RGB_888 || pixelFormat == PixelFormat::RGBA_8888);
- int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
- ASSERT_NE(-1, bytesPerPixel);
- for (int row = 0; row < height; row++) {
- for (int col = 0; col < width; col++) {
- int pixel = row * width + col;
- IComposerClient::Color srcColor = desiredPixelColors[pixel];
-
- int offset = (row * stride + col) * bytesPerPixel;
- uint8_t* pixelColor = (uint8_t*)bufferData + offset;
- pixelColor[0] = srcColor.r;
- pixelColor[1] = srcColor.g;
- pixelColor[2] = srcColor.b;
-
- if (bytesPerPixel == 4) {
- pixelColor[3] = srcColor.a;
- }
- }
- }
- }
-
protected:
using PowerMode = V2_1::IComposerClient::PowerMode;
void SetUp() override {
@@ -183,12 +88,13 @@
mGralloc = std::make_shared<Gralloc>();
mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = readbackSupported(tmpPixelFormat, tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON));
}
@@ -209,10 +115,6 @@
mReader->mErrors.clear();
}
- void execute() {
- ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get()));
- }
-
void writeLayers(const std::vector<std::shared_ptr<TestLayer>>& layers) {
for (auto layer : layers) {
layer->write(mWriter);
@@ -220,42 +122,10 @@
execute();
}
- void clearColors(std::vector<IComposerClient::Color>& expectedColors, int32_t width,
- int32_t height) {
- for (int row = 0; row < height; row++) {
- for (int col = 0; col < width; col++) {
- int pixel = row * mDisplayWidth + col;
- expectedColors[pixel] = BLACK;
- }
- }
+ void execute() {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get()));
}
- void fillColorsArea(std::vector<IComposerClient::Color>& expectedColors, int32_t stride,
- IComposerClient::Rect area, IComposerClient::Color color) {
- for (int row = area.top; row < area.bottom; row++) {
- for (int col = area.left; col < area.right; col++) {
- int pixel = row * stride + col;
- expectedColors[pixel] = color;
- }
- }
- }
-
- bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
- const Error error) {
- if (error != Error::NONE) {
- return false;
- }
- // TODO: add support for RGBA_1010102
- if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) {
- return false;
- }
- if (dataspace != Dataspace::V0_SRGB) {
- return false;
- }
- return true;
- }
-
-
std::unique_ptr<Composer> mComposer;
std::shared_ptr<ComposerClient> mComposerClient;
@@ -286,178 +156,6 @@
}
}
};
-class ReadbackBuffer {
- public:
- ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
- const std::shared_ptr<Gralloc>& gralloc, uint32_t width, uint32_t height,
- PixelFormat pixelFormat, Dataspace dataspace) {
- mDisplay = display;
-
- mComposerClient = client;
- mGralloc = gralloc;
-
- mPixelFormat = pixelFormat;
- mDataspace = dataspace;
-
- mInfo.width = width;
- mInfo.height = height;
- mInfo.layerCount = 1;
- mInfo.format = mPixelFormat;
- mInfo.usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE);
-
- mAccessRegion.top = 0;
- mAccessRegion.left = 0;
- mAccessRegion.width = width;
- mAccessRegion.height = height;
- };
-
- ~ReadbackBuffer() {
- if (mBufferHandle != nullptr) {
- mGralloc->freeBuffer(mBufferHandle);
- }
- }
-
- void setReadbackBuffer() {
- if (mBufferHandle != nullptr) {
- mGralloc->freeBuffer(mBufferHandle);
- mBufferHandle = nullptr;
- }
- mBufferHandle = mGralloc->allocate(mInfo, /*import*/ true, &mStride);
- ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mInfo, mStride));
- ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle, -1));
- }
-
- void checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors) {
- // lock buffer for reading
- int32_t fenceHandle;
- ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle));
-
- void* bufData = mGralloc->lock(mBufferHandle, mInfo.usage, mAccessRegion, fenceHandle);
- ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
- int32_t bytesPerPixel = GraphicsComposerReadbackTest::GetBytesPerPixel(mPixelFormat);
- ASSERT_NE(-1, bytesPerPixel);
- for (int row = 0; row < mInfo.height; row++) {
- for (int col = 0; col < mInfo.width; col++) {
- int pixel = row * mInfo.width + col;
- int offset = (row * mStride + col) * bytesPerPixel;
- uint8_t* pixelColor = (uint8_t*)bufData + offset;
-
- ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]);
- ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]);
- ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]);
- }
- }
- int32_t unlockFence = mGralloc->unlock(mBufferHandle);
- if (unlockFence != -1) {
- sync_wait(unlockFence, -1);
- close(unlockFence);
- }
- }
-
- protected:
- IMapper::BufferDescriptorInfo mInfo;
- IMapper::Rect mAccessRegion;
- uint32_t mStride;
- const native_handle_t* mBufferHandle = nullptr;
- PixelFormat mPixelFormat;
- Dataspace mDataspace;
- Display mDisplay;
- std::shared_ptr<Gralloc> mGralloc;
- std::shared_ptr<ComposerClient> mComposerClient;
-};
-
-class TestColorLayer : public TestLayer {
- public:
- TestColorLayer(const std::shared_ptr<ComposerClient>& client, Display display)
- : TestLayer{client, display} {}
-
- void write(const std::shared_ptr<CommandWriterBase>& writer) override {
- TestLayer::write(writer);
- writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
- writer->setLayerColor(mColor);
- }
-
- void setColor(IComposerClient::Color color) { mColor = color; }
-
- private:
- IComposerClient::Color mColor = {0xff, 0xff, 0xff, 0xff};
-};
-
-class TestBufferLayer : public TestLayer {
- public:
- TestBufferLayer(const std::shared_ptr<ComposerClient>& client,
- const std::shared_ptr<Gralloc>& gralloc, Display display, int32_t width,
- int32_t height, PixelFormat format,
- IComposerClient::Composition composition = IComposerClient::Composition::DEVICE)
- : TestLayer{client, display} {
- mGralloc = gralloc;
- mComposition = composition;
- mInfo.width = width;
- mInfo.height = height;
- mInfo.layerCount = 1;
- mInfo.format = format;
- mInfo.usage =
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY);
-
- mAccessRegion.top = 0;
- mAccessRegion.left = 0;
- mAccessRegion.width = width;
- mAccessRegion.height = height;
-
- setSourceCrop({0, 0, (float)width, (float)height});
- }
-
- ~TestBufferLayer() {
- if (mBufferHandle != nullptr) {
- mGralloc->freeBuffer(mBufferHandle);
- }
- }
-
- void write(const std::shared_ptr<CommandWriterBase>& writer) override {
- TestLayer::write(writer);
- writer->setLayerCompositionType(mComposition);
- writer->setLayerDataspace(Dataspace::UNKNOWN);
- writer->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, mDisplayFrame));
- if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence);
- }
-
- void fillBuffer(std::vector<IComposerClient::Color> expectedColors) {
- void* bufData = mGralloc->lock(mBufferHandle, mInfo.usage, mAccessRegion, -1);
- ASSERT_NO_FATAL_FAILURE(GraphicsComposerReadbackTest::fillBuffer(
- mInfo.width, mInfo.height, mStride, bufData, mInfo.format, expectedColors));
- mFillFence = mGralloc->unlock(mBufferHandle);
- if (mFillFence != -1) {
- sync_wait(mFillFence, -1);
- close(mFillFence);
- }
- }
- void setBuffer(std::vector<IComposerClient::Color> colors) {
- if (mBufferHandle != nullptr) {
- mGralloc->freeBuffer(mBufferHandle);
- mBufferHandle = nullptr;
- }
- mBufferHandle = mGralloc->allocate(mInfo, /*import*/ true, &mStride);
- ASSERT_NE(nullptr, mBufferHandle);
- ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
- ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mInfo, mStride));
- }
-
- void setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer) {
- writer->selectLayer(mLayer);
- writer->setLayerCompositionType(IComposerClient::Composition::CLIENT);
- }
-
- IMapper::BufferDescriptorInfo mInfo;
- IMapper::Rect mAccessRegion;
- uint32_t mStride;
-
- protected:
- IComposerClient::Composition mComposition;
- std::shared_ptr<Gralloc> mGralloc;
- int32_t mFillFence;
- const native_handle_t* mBufferHandle = nullptr;
-};
TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) {
if (!mHasReadbackBuffer) {
@@ -478,7 +176,7 @@
// expected color for each pixel
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
mDisplayHeight, mPixelFormat, mDataspace);
@@ -515,11 +213,13 @@
mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, GREEN);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2},
+ GREEN);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
auto layer =
std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
@@ -568,19 +268,16 @@
layer->write(mWriter);
// This following buffer call should have no effect
- IMapper::BufferDescriptorInfo bufferInfo{};
- bufferInfo.width = mDisplayWidth;
- bufferInfo.height = mDisplayHeight;
- bufferInfo.layerCount = 1;
- bufferInfo.format = PixelFormat::RGBA_8888;
- bufferInfo.usage =
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN);
- const native_handle_t* bufferHandle = mGralloc->allocate(bufferInfo);
+ PixelFormat format = PixelFormat::RGBA_8888;
+ uint64_t usage =
+ static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN);
+ const native_handle_t* bufferHandle =
+ mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, format, usage);
mWriter->setLayerBuffer(0, bufferHandle, -1);
// expected color for each pixel
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
mDisplayHeight, mPixelFormat, mDataspace);
@@ -611,11 +308,13 @@
mWriter->selectDisplay(mPrimaryDisplay);
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, GREEN);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2},
+ GREEN);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
auto layer =
std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
@@ -642,23 +341,21 @@
// create client target buffer
uint32_t clientStride;
- IMapper::BufferDescriptorInfo clientInfo;
- clientInfo.width = layer->mInfo.width;
- clientInfo.height = layer->mInfo.height;
- clientInfo.layerCount = layer->mInfo.layerCount;
- clientInfo.format = PixelFormat::RGBA_8888;
- clientInfo.usage =
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_CLIENT_TARGET);
+ PixelFormat clientFormat = PixelFormat::RGBA_8888;
+ uint64_t clientUsage =
+ static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_CLIENT_TARGET);
const native_handle_t* clientBufferHandle =
- mGralloc->allocate(clientInfo, /*import*/ true, &clientStride);
+ mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount, clientFormat,
+ clientUsage, /*import*/ true, &clientStride);
ASSERT_NE(nullptr, clientBufferHandle);
void* clientBufData =
- mGralloc->lock(clientBufferHandle, clientInfo.usage, layer->mAccessRegion, -1);
+ mGralloc->lock(clientBufferHandle, clientUsage, layer->mAccessRegion, -1);
- ASSERT_NO_FATAL_FAILURE(fillBuffer(clientInfo.width, clientInfo.height, clientStride,
- clientBufData, clientInfo.format, expectedColors));
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(layer->mWidth, layer->mHeight,
+ clientStride, clientBufData,
+ clientFormat, expectedColors));
int clientFence = mGralloc->unlock(clientBufferHandle);
if (clientFence != -1) {
sync_wait(clientFence, -1);
@@ -695,9 +392,10 @@
mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
mDisplayHeight, mPixelFormat, mDataspace);
@@ -706,14 +404,13 @@
auto deviceLayer =
std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
mDisplayHeight / 2, PixelFormat::RGBA_8888);
- std::vector<IComposerClient::Color> deviceColors(deviceLayer->mInfo.width *
- deviceLayer->mInfo.height);
- fillColorsArea(deviceColors, deviceLayer->mInfo.width,
- {0, 0, static_cast<int32_t>(deviceLayer->mInfo.width),
- static_cast<int32_t>(deviceLayer->mInfo.height)},
- GREEN);
- deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->mInfo.width),
- static_cast<int32_t>(deviceLayer->mInfo.height)});
+ std::vector<IComposerClient::Color> deviceColors(deviceLayer->mWidth * deviceLayer->mHeight);
+ ReadbackHelper::fillColorsArea(deviceColors, deviceLayer->mWidth,
+ {0, 0, static_cast<int32_t>(deviceLayer->mWidth),
+ static_cast<int32_t>(deviceLayer->mHeight)},
+ GREEN);
+ deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->mWidth),
+ static_cast<int32_t>(deviceLayer->mHeight)});
deviceLayer->setZOrder(10);
ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
deviceLayer->write(mWriter);
@@ -728,30 +425,26 @@
execute();
ASSERT_EQ(0, mReader->mErrors.size());
- IMapper::BufferDescriptorInfo clientInfo;
- clientInfo.width = mDisplayWidth;
- clientInfo.height = mDisplayHeight;
- clientInfo.layerCount = 1;
- clientInfo.format = PixelFormat::RGBA_8888;
- clientInfo.usage =
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_CLIENT_TARGET);
-
+ uint64_t clientUsage =
+ static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_CLIENT_TARGET);
uint32_t clientStride;
const native_handle_t* clientBufferHandle =
- mGralloc->allocate(clientInfo, /*import*/ true, &clientStride);
+ mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888,
+ clientUsage, /*import*/ true, &clientStride);
ASSERT_NE(nullptr, clientBufferHandle);
- IMapper::Rect clientAccessRegion;
+ AccessRegion clientAccessRegion;
clientAccessRegion.left = 0;
clientAccessRegion.top = 0;
clientAccessRegion.width = mDisplayWidth;
clientAccessRegion.height = mDisplayHeight;
- void* clientData = mGralloc->lock(clientBufferHandle, clientInfo.usage, clientAccessRegion, -1);
- std::vector<IComposerClient::Color> clientColors(clientInfo.width * clientInfo.height);
- fillColorsArea(clientColors, clientInfo.width, clientFrame, RED);
- ASSERT_NO_FATAL_FAILURE(fillBuffer(clientInfo.width, clientInfo.height, clientStride,
- clientData, clientInfo.format, clientColors));
+ void* clientData = mGralloc->lock(clientBufferHandle, clientUsage, clientAccessRegion, -1);
+ std::vector<IComposerClient::Color> clientColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED);
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mDisplayWidth, mDisplayHeight, clientStride,
+ clientData, PixelFormat::RGBA_8888,
+ clientColors));
int clientFence = mGralloc->unlock(clientBufferHandle);
if (clientFence != -1) {
sync_wait(clientFence, -1);
@@ -787,7 +480,7 @@
IComposerClient::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4};
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
auto layer =
std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
@@ -820,8 +513,8 @@
// update surface damage and recheck
redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2};
- clearColors(expectedColors, mDisplayWidth, mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+ ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors));
layer->setSurfaceDamage(
@@ -895,9 +588,10 @@
mWriter->selectDisplay(mPrimaryDisplay);
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
auto layer =
std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
@@ -911,7 +605,8 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
// update expected colors to match crop
- fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
mDisplayHeight, mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
@@ -959,8 +654,8 @@
redLayer->setZOrder(10);
// fill blue first so that red will overwrite on overlap
- fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
- fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
mDisplayHeight, mPixelFormat, mDataspace);
@@ -982,9 +677,9 @@
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
redLayer->setZOrder(1);
- clearColors(expectedColors, mDisplayWidth, mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
- fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
+ ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
@@ -1019,8 +714,8 @@
void setUpLayers(IComposerClient::BlendMode blendMode) {
mLayers.clear();
std::vector<IComposerClient::Color> topLayerPixelColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(topLayerPixelColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight},
- mTopLayerColor);
+ ReadbackHelper::fillColorsArea(topLayerPixelColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight}, mTopLayerColor);
auto backgroundLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
backgroundLayer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
@@ -1043,7 +738,7 @@
void setExpectedColors(std::vector<IComposerClient::Color>& expectedColors) {
ASSERT_EQ(2, mLayers.size());
- clearColors(expectedColors, mDisplayWidth, mDisplayHeight);
+ ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
auto layer = mLayers[1];
IComposerClient::BlendMode blendMode = layer->mBlendMode;
@@ -1216,8 +911,8 @@
mLayer->setZOrder(10);
std::vector<IComposerClient::Color> baseColors(mSideLength * mSideLength);
- fillColorsArea(baseColors, mSideLength, redRect, RED);
- fillColorsArea(baseColors, mSideLength, blueRect, BLUE);
+ ReadbackHelper::fillColorsArea(baseColors, mSideLength, redRect, RED);
+ ReadbackHelper::fillColorsArea(baseColors, mSideLength, blueRect, BLUE);
ASSERT_NO_FATAL_FAILURE(mLayer->setBuffer(baseColors));
mLayers = {backgroundLayer, mLayer};
@@ -1240,10 +935,10 @@
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::FLIP_H);
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth,
- {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE);
writeLayers(mLayers);
ASSERT_EQ(0, mReader->mErrors.size());
@@ -1274,10 +969,10 @@
mLayer->setTransform(Transform::FLIP_V);
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED);
- fillColorsArea(expectedColors, mDisplayWidth,
- {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE);
writeLayers(mLayers);
ASSERT_EQ(0, mReader->mErrors.size());
@@ -1307,9 +1002,11 @@
mLayer->setTransform(Transform::ROT_180);
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth,
- {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength}, RED);
- fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mSideLength / 2, mSideLength / 2}, BLUE);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength},
+ RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mSideLength / 2, mSideLength / 2}, BLUE);
writeLayers(mLayers);
ASSERT_EQ(0, mReader->mErrors.size());
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 9c80f4d..51832f9 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -40,7 +40,6 @@
using common::V1_1::PixelFormat;
using common::V1_1::RenderIntent;
using mapper::V2_0::IMapper;
-using mapper::V2_0::vts::Gralloc;
// Test environment for graphics.composer
class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
@@ -171,15 +170,10 @@
}
const native_handle_t* allocate() {
- IMapper::BufferDescriptorInfo info{};
- info.width = 64;
- info.height = 64;
- info.layerCount = 1;
- info.format = static_cast<common::V1_0::PixelFormat>(PixelFormat::RGBA_8888);
- info.usage =
- static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
-
- return mGralloc->allocate(info);
+ uint64_t usage =
+ static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+ return mGralloc->allocate(/*width*/ 64, /*height*/ 64, /*layerCount*/ 1,
+ PixelFormat::RGBA_8888, usage);
}
void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
@@ -456,18 +450,15 @@
return;
}
- IMapper::BufferDescriptorInfo info{};
- info.width = mDisplayWidth;
- info.height = mDisplayHeight;
- info.layerCount = 1;
- info.format = static_cast<common::V1_0::PixelFormat>(mReadbackPixelFormat);
// BufferUsage::COMPOSER_OUTPUT is missing
- info.usage = static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
+ uint64_t usage =
+ static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
std::unique_ptr<Gralloc> gralloc;
const native_handle_t* buffer;
ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique<Gralloc>());
- ASSERT_NO_FATAL_FAILURE(buffer = gralloc->allocate(info));
+ ASSERT_NO_FATAL_FAILURE(buffer = gralloc->allocate(mDisplayWidth, mDisplayHeight, 1,
+ mReadbackPixelFormat, usage));
mComposerClient->setReadbackBuffer(mPrimaryDisplay, buffer, -1);
}
@@ -483,17 +474,14 @@
return;
}
- IMapper::BufferDescriptorInfo info{};
- info.width = mDisplayWidth;
- info.height = mDisplayHeight;
- info.layerCount = 1;
- info.format = static_cast<common::V1_0::PixelFormat>(mReadbackPixelFormat);
- info.usage = static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
+ uint64_t usage =
+ static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
std::unique_ptr<Gralloc> gralloc;
const native_handle_t* buffer;
ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique<Gralloc>());
- ASSERT_NO_FATAL_FAILURE(buffer = gralloc->allocate(info));
+ ASSERT_NO_FATAL_FAILURE(buffer = gralloc->allocate(mDisplayWidth, mDisplayHeight, 1,
+ mReadbackPixelFormat, usage));
Error error = mComposerClient->getRaw()->setReadbackBuffer(mInvalidDisplayId, buffer, nullptr);
ASSERT_EQ(Error::BAD_DISPLAY, error);
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
index 19438cb..036ef69 100644
--- a/graphics/composer/2.3/utils/vts/Android.bp
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -27,6 +27,12 @@
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.2-vts",
"android.hardware.graphics.composer@2.3",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@2.0-vts",
+ "android.hardware.graphics.mapper@2.1",
+ "android.hardware.graphics.mapper@2.1-vts",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@3.0-vts",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index ce675ee..2766638 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -28,6 +28,7 @@
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
@@ -37,6 +38,9 @@
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@2.1",
+ "android.hardware.graphics.mapper@2.1-vts",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@3.0-vts",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index d51c30a..dafe587 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -41,7 +41,7 @@
using common::V1_2::Dataspace;
using common::V1_2::PixelFormat;
using mapper::V2_0::IMapper;
-using mapper::V2_0::vts::Gralloc;
+using V2_2::vts::Gralloc;
// Test environment for graphics.composer
class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
@@ -156,15 +156,9 @@
}
const native_handle_t* allocate() {
- IMapper::BufferDescriptorInfo info{};
- info.width = 64;
- info.height = 64;
- info.layerCount = 1;
- info.format = static_cast<common::V1_0::PixelFormat>(PixelFormat::RGBA_8888);
- info.usage =
- static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
-
- return mGralloc->allocate(info);
+ return mGralloc->allocate(
+ 64, 64, 1, static_cast<common::V1_1::PixelFormat>(PixelFormat::RGBA_8888),
+ static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN));
}
void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
diff --git a/graphics/mapper/2.1/utils/vts/MapperVts.cpp b/graphics/mapper/2.1/utils/vts/MapperVts.cpp
index 078068e..36f9cbb 100644
--- a/graphics/mapper/2.1/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/2.1/utils/vts/MapperVts.cpp
@@ -43,24 +43,25 @@
offsetof(IMapper::BufferDescriptorInfo, usage),
"");
-Gralloc::Gralloc() : V2_0::vts::Gralloc() {
+Gralloc::Gralloc(bool errOnFailure) : V2_0::vts::Gralloc() {
if (::testing::Test::HasFatalFailure()) {
return;
}
- init();
+ init(errOnFailure);
}
-Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName)
+Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName,
+ bool errOnFailure)
: V2_0::vts::Gralloc(allocatorServiceName, mapperServiceName) {
if (::testing::Test::HasFatalFailure()) {
return;
}
- init();
+ init(errOnFailure);
}
-void Gralloc::init() {
+void Gralloc::init(bool errOnFailure) {
mMapperV2_1 = IMapper::castFrom(V2_0::vts::Gralloc::getMapper());
- ASSERT_NE(nullptr, mMapperV2_1.get()) << "failed to get mapper 2.1 service";
+ if (errOnFailure) ASSERT_NE(nullptr, mMapperV2_1.get()) << "failed to get mapper 2.1 service";
}
sp<IMapper> Gralloc::getMapper() const {
diff --git a/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h b/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h
index 423d4b3..bc683bb 100644
--- a/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h
+++ b/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h
@@ -32,25 +32,26 @@
// A wrapper to IAllocator and IMapper.
class Gralloc : public V2_0::vts::Gralloc {
public:
- Gralloc();
- Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName);
+ Gralloc(bool errOnFailure = true);
+ Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName,
+ bool errOnFailure = true);
- sp<IMapper> getMapper() const;
+ sp<IMapper> getMapper() const;
- bool validateBufferSize(const native_handle_t* bufferHandle,
- const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride);
- void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
- uint32_t* outNumInts);
+ bool validateBufferSize(const native_handle_t* bufferHandle,
+ const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride);
+ void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts);
- BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
+ BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
- const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
- bool import = true, uint32_t* outStride = nullptr);
+ const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+ bool import = true, uint32_t* outStride = nullptr);
protected:
- void init();
+ void init(bool errOnFailure = true);
- sp<IMapper> mMapperV2_1;
+ sp<IMapper> mMapperV2_1;
};
} // namespace vts
diff --git a/graphics/mapper/3.0/utils/vts/MapperVts.cpp b/graphics/mapper/3.0/utils/vts/MapperVts.cpp
index f2b7594..c94e8db 100644
--- a/graphics/mapper/3.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/3.0/utils/vts/MapperVts.cpp
@@ -25,8 +25,13 @@
namespace V3_0 {
namespace vts {
-Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
- init(allocatorServiceName, mapperServiceName);
+Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName,
+ bool errOnFailure) {
+ if (errOnFailure) {
+ init(allocatorServiceName, mapperServiceName);
+ } else {
+ initNoErr(allocatorServiceName, mapperServiceName);
+ }
}
void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
@@ -38,6 +43,16 @@
ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
}
+void Gralloc::initNoErr(const std::string& allocatorServiceName,
+ const std::string& mapperServiceName) {
+ mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+
+ mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(mapperServiceName);
+ if (mMapper.get()) {
+ ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
+ }
+}
+
Gralloc::~Gralloc() {
for (auto bufferHandle : mClonedBuffers) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
diff --git a/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h b/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h
index ba79ca4..1141a88 100644
--- a/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h
+++ b/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h
@@ -36,62 +36,66 @@
// A wrapper to IAllocator and IMapper.
class Gralloc {
public:
- Gralloc(const std::string& allocatorServiceName = "default",
- const std::string& mapperServiceName = "default");
- ~Gralloc();
+ Gralloc(const std::string& allocatorServiceName = "default",
+ const std::string& mapperServiceName = "default", bool errOnFailure = true);
+ ~Gralloc();
- // IAllocator methods
+ // IAllocator methods
- sp<IAllocator> getAllocator() const;
+ sp<IAllocator> getAllocator() const;
- std::string dumpDebugInfo();
+ std::string dumpDebugInfo();
- // When import is false, this simply calls IAllocator::allocate. When import
- // is true, the returned buffers are also imported into the mapper.
- //
- // Either case, the returned buffers must be freed with freeBuffer.
- std::vector<const native_handle_t*> allocate(const BufferDescriptor& descriptor, uint32_t count,
- bool import = true, uint32_t* outStride = nullptr);
- const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
- bool import = true, uint32_t* outStride = nullptr);
+ // When import is false, this simply calls IAllocator::allocate. When import
+ // is true, the returned buffers are also imported into the mapper.
+ //
+ // Either case, the returned buffers must be freed with freeBuffer.
+ std::vector<const native_handle_t*> allocate(const BufferDescriptor& descriptor,
+ uint32_t count, bool import = true,
+ uint32_t* outStride = nullptr);
+ const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+ bool import = true, uint32_t* outStride = nullptr);
- // IMapper methods
+ // IMapper methods
- sp<IMapper> getMapper() const;
+ sp<IMapper> getMapper() const;
- BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
+ BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
- const native_handle_t* importBuffer(const hidl_handle& rawHandle);
- void freeBuffer(const native_handle_t* bufferHandle);
+ const native_handle_t* importBuffer(const hidl_handle& rawHandle);
+ void freeBuffer(const native_handle_t* bufferHandle);
- // We use fd instead of hidl_handle in these functions to pass fences
- // in and out of the mapper. The ownership of the fd is always transferred
- // with each of these functions.
- void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
- const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel,
- int32_t* outBytesPerStride);
- YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
- const IMapper::Rect& accessRegion, int acquireFence);
- int unlock(const native_handle_t* bufferHandle);
+ // We use fd instead of hidl_handle in these functions to pass fences
+ // in and out of the mapper. The ownership of the fd is always transferred
+ // with each of these functions.
+ void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride);
+ YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int acquireFence);
+ int unlock(const native_handle_t* bufferHandle);
- bool validateBufferSize(const native_handle_t* bufferHandle,
- const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride);
- void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
- uint32_t* outNumInts);
+ bool validateBufferSize(const native_handle_t* bufferHandle,
+ const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride);
+ void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts);
- bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo);
+ bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo);
private:
- void init(const std::string& allocatorServiceName, const std::string& mapperServiceName);
- const native_handle_t* cloneBuffer(const hidl_handle& rawHandle);
+ void init(const std::string& allocatorServiceName, const std::string& mapperServiceName);
- sp<IAllocator> mAllocator;
- sp<IMapper> mMapper;
+ // initialize without checking for failure to get service
+ void initNoErr(const std::string& allocatorServiceName, const std::string& mapperServiceName);
+ const native_handle_t* cloneBuffer(const hidl_handle& rawHandle);
- // Keep track of all cloned and imported handles. When a test fails with
- // ASSERT_*, the destructor will free the handles for the test.
- std::unordered_set<const native_handle_t*> mClonedBuffers;
- std::unordered_set<const native_handle_t*> mImportedBuffers;
+ sp<IAllocator> mAllocator;
+ sp<IMapper> mMapper;
+
+ // Keep track of all cloned and imported handles. When a test fails with
+ // ASSERT_*, the destructor will free the handles for the test.
+ std::unordered_set<const native_handle_t*> mClonedBuffers;
+ std::unordered_set<const native_handle_t*> mImportedBuffers;
};
} // namespace vts
diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.0/support/Keymaster.cpp
index 1eb9a68..f20f951 100644
--- a/keymaster/4.0/support/Keymaster.cpp
+++ b/keymaster/4.0/support/Keymaster.cpp
@@ -80,8 +80,7 @@
}
template <typename Wrapper>
-std::vector<std::unique_ptr<Keymaster>> enumerateDevices(
- const sp<IServiceManager>& serviceManager) {
+Keymaster::KeymasterSet enumerateDevices(const sp<IServiceManager>& serviceManager) {
Keymaster::KeymasterSet result;
bool foundDefault = false;
@@ -92,7 +91,7 @@
auto device = Wrapper::WrappedIKeymasterDevice::getService(name);
CHECK(device) << "Failed to get service for " << descriptor << " with interface name "
<< name;
- result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, name)));
+ result.push_back(new Wrapper(device, name));
}
});
@@ -100,7 +99,7 @@
// "default" wasn't provided by listManifestByInterface. Maybe there's a passthrough
// implementation.
auto device = Wrapper::WrappedIKeymasterDevice::getService("default");
- if (device) result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, "default")));
+ if (device) result.push_back(new Wrapper(device, "default"));
}
return result;
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
index 43a34b0..ad83f17 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
@@ -39,8 +39,8 @@
* while still having to use only the latest interface.
*/
class Keymaster : public IKeymasterDevice {
- public:
- using KeymasterSet = std::vector<std::unique_ptr<Keymaster>>;
+ public:
+ using KeymasterSet = std::vector<android::sp<Keymaster>>;
Keymaster(const hidl_string& descriptor, const hidl_string& instanceName)
: descriptor_(descriptor), instanceName_(instanceName) {}
@@ -86,7 +86,7 @@
*/
static void performHmacKeyAgreement(const KeymasterSet& keymasters);
- private:
+ private:
hidl_string descriptor_;
hidl_string instanceName_;
};
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp
index 2c3287a..5af3255 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp
@@ -44,6 +44,21 @@
// in frameworks/ml/nn/runtime/tests/generated/
#include "all_generated_V1_2_vts_tests.cpp"
+// Generated from spec/strided_slice_invalid_output_dims.mod.py.
+// TODO(b/132155416): Make this part of all_generated_V1_2_vts_tests.cpp.
+namespace strided_slice_invalid_output_dims {
+#include "generated/strided_slice_invalid_output_dims.example.cpp"
+#include "generated/strided_slice_invalid_output_dims.model.cpp"
+} // namespace strided_slice_invalid_output_dims
+
+// TODO(b/132155416): Make this part of all_generated_V1_2_vts_tests.cpp.
+TEST_F(ValidationTest, strided_slice_invalid_output_dims) {
+ const Model model = strided_slice_invalid_output_dims::createTestModel();
+ const std::vector<Request> requests =
+ createRequests(strided_slice_invalid_output_dims::get_examples());
+ validateFailure(model, requests);
+}
+
} // namespace functional
} // namespace vts
} // namespace V1_2
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index f87ca89..a0b6d9a 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -508,15 +508,15 @@
}
}
}
- // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have
- // either one or two outputs depending on their mergeOutputs parameter.
+ // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have either one or two
+ // outputs depending on their mergeOutputs parameter.
if (operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_LSTM ||
operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) {
- for (const size_t outOprand : operation.outputs) {
- if (operand == outOprand) {
- return true;
+ for (const size_t outOprand : operation.outputs) {
+ if (operand == outOprand) {
+ return true;
+ }
}
- }
}
}
return false;
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index 9703c2d..e935aaa 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -274,6 +274,22 @@
}
}
+void ValidationTest::validateRequestFailure(const sp<IPreparedModel>& preparedModel,
+ const std::vector<Request>& requests) {
+ for (const Request& request : requests) {
+ SCOPED_TRACE("Expecting request to fail [executeSynchronously]");
+ Return<void> executeStatus = preparedModel->executeSynchronously(
+ request, MeasureTiming::NO,
+ [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing) {
+ ASSERT_NE(ErrorStatus::NONE, error);
+ EXPECT_EQ(outputShapes.size(), 0);
+ EXPECT_TRUE(badTiming(timing));
+ });
+ ASSERT_TRUE(executeStatus.isOk());
+ }
+}
+
} // namespace functional
} // namespace vts
} // namespace V1_2
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
index 4ddefe8..666f9b5 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
@@ -140,6 +140,20 @@
validateBurst(preparedModel, requests);
}
+void ValidationTest::validateFailure(const Model& model, const std::vector<Request>& requests) {
+ // TODO: Should this always succeed?
+ // What if the invalid input is part of the model (i.e., a parameter).
+ validateModel(model);
+
+ sp<IPreparedModel> preparedModel;
+ ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel));
+ if (preparedModel == nullptr) {
+ return;
+ }
+
+ validateRequestFailure(preparedModel, requests);
+}
+
sp<IPreparedModel> getPreparedModel_1_2(
const sp<V1_2::implementation::PreparedModelCallback>& callback) {
sp<V1_0::IPreparedModel> preparedModelV1_0 = callback->getPreparedModel();
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
index 8d1acbe..80e810a 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
@@ -73,11 +73,14 @@
class ValidationTest : public NeuralnetworksHidlTest {
protected:
void validateEverything(const Model& model, const std::vector<Request>& requests);
+ void validateFailure(const Model& model, const std::vector<Request>& requests);
private:
void validateModel(const Model& model);
void validateRequests(const sp<IPreparedModel>& preparedModel,
const std::vector<Request>& requests);
+ void validateRequestFailure(const sp<IPreparedModel>& preparedModel,
+ const std::vector<Request>& requests);
void validateBurst(const sp<IPreparedModel>& preparedModel,
const std::vector<Request>& requests);
};
diff --git a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp
new file mode 100644
index 0000000..0640833
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp
@@ -0,0 +1,116 @@
+// clang-format off
+// Generated file (from: strided_slice_invalid_output_dims.mod.py). Do not edit
+std::vector<MixedTypedExample>& get_examples() {
+static std::vector<MixedTypedExample> examples = {
+// Begin of an example
+{
+.operands = {
+//Input(s)
+{ // See tools/test_generator/include/TestHarness.h:MixedTyped
+ // int -> Dimensions map
+ .operandDimensions = {{0, {2, 3}}},
+ // int -> FLOAT32 map
+ .float32Operands = {{0, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}}},
+ // int -> INT32 map
+ .int32Operands = {},
+ // int -> QUANT8_ASYMM map
+ .quant8AsymmOperands = {},
+ // int -> QUANT16_SYMM map
+ .quant16SymmOperands = {},
+ // int -> FLOAT16 map
+ .float16Operands = {},
+ // int -> BOOL8 map
+ .bool8Operands = {},
+ // int -> QUANT8_SYMM_PER_CHANNEL map
+ .quant8ChannelOperands = {},
+ // int -> QUANT16_ASYMM map
+ .quant16AsymmOperands = {},
+ // int -> QUANT8_SYMM map
+ .quant8SymmOperands = {},
+},
+//Output(s)
+{ // See tools/test_generator/include/TestHarness.h:MixedTyped
+ // int -> Dimensions map
+ .operandDimensions = {{0, {3}}},
+ // int -> FLOAT32 map
+ .float32Operands = {{0, {1.0f, 2.0f, 3.0f}}},
+ // int -> INT32 map
+ .int32Operands = {},
+ // int -> QUANT8_ASYMM map
+ .quant8AsymmOperands = {},
+ // int -> QUANT16_SYMM map
+ .quant16SymmOperands = {},
+ // int -> FLOAT16 map
+ .float16Operands = {},
+ // int -> BOOL8 map
+ .bool8Operands = {},
+ // int -> QUANT8_SYMM_PER_CHANNEL map
+ .quant8ChannelOperands = {},
+ // int -> QUANT16_ASYMM map
+ .quant16AsymmOperands = {},
+ // int -> QUANT8_SYMM map
+ .quant8SymmOperands = {},
+}
+},
+}, // End of an example
+};
+return examples;
+};
+
+std::vector<MixedTypedExample>& get_examples_dynamic_output_shape() {
+static std::vector<MixedTypedExample> examples_dynamic_output_shape = {
+// Begin of an example
+{
+.operands = {
+//Input(s)
+{ // See tools/test_generator/include/TestHarness.h:MixedTyped
+ // int -> Dimensions map
+ .operandDimensions = {{0, {2, 3}}},
+ // int -> FLOAT32 map
+ .float32Operands = {{0, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}}},
+ // int -> INT32 map
+ .int32Operands = {},
+ // int -> QUANT8_ASYMM map
+ .quant8AsymmOperands = {},
+ // int -> QUANT16_SYMM map
+ .quant16SymmOperands = {},
+ // int -> FLOAT16 map
+ .float16Operands = {},
+ // int -> BOOL8 map
+ .bool8Operands = {},
+ // int -> QUANT8_SYMM_PER_CHANNEL map
+ .quant8ChannelOperands = {},
+ // int -> QUANT16_ASYMM map
+ .quant16AsymmOperands = {},
+ // int -> QUANT8_SYMM map
+ .quant8SymmOperands = {},
+},
+//Output(s)
+{ // See tools/test_generator/include/TestHarness.h:MixedTyped
+ // int -> Dimensions map
+ .operandDimensions = {{0, {3}}},
+ // int -> FLOAT32 map
+ .float32Operands = {{0, {1.0f, 2.0f, 3.0f}}},
+ // int -> INT32 map
+ .int32Operands = {},
+ // int -> QUANT8_ASYMM map
+ .quant8AsymmOperands = {},
+ // int -> QUANT16_SYMM map
+ .quant16SymmOperands = {},
+ // int -> FLOAT16 map
+ .float16Operands = {},
+ // int -> BOOL8 map
+ .bool8Operands = {},
+ // int -> QUANT8_SYMM_PER_CHANNEL map
+ .quant8ChannelOperands = {},
+ // int -> QUANT16_ASYMM map
+ .quant16AsymmOperands = {},
+ // int -> QUANT8_SYMM map
+ .quant8SymmOperands = {},
+}
+},
+}, // End of an example
+};
+return examples_dynamic_output_shape;
+};
+
diff --git a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp
new file mode 100644
index 0000000..106655a
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp
@@ -0,0 +1,216 @@
+// clang-format off
+// Generated file (from: strided_slice_invalid_output_dims.mod.py). Do not edit
+// Create the model
+Model createTestModel() {
+ const std::vector<Operand> operands = {
+ {
+ .type = OperandType::TENSOR_FLOAT32,
+ .dimensions = {2, 3},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::MODEL_INPUT,
+ .location = {.poolIndex = 0, .offset = 0, .length = 0},
+ },
+ {
+ .type = OperandType::TENSOR_INT32,
+ .dimensions = {2},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::CONSTANT_COPY,
+ .location = {.poolIndex = 0, .offset = 0, .length = 8},
+ },
+ {
+ .type = OperandType::TENSOR_INT32,
+ .dimensions = {2},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::CONSTANT_COPY,
+ .location = {.poolIndex = 0, .offset = 8, .length = 8},
+ },
+ {
+ .type = OperandType::TENSOR_INT32,
+ .dimensions = {2},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::CONSTANT_COPY,
+ .location = {.poolIndex = 0, .offset = 16, .length = 8},
+ },
+ {
+ .type = OperandType::INT32,
+ .dimensions = {},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::CONSTANT_COPY,
+ .location = {.poolIndex = 0, .offset = 24, .length = 4},
+ },
+ {
+ .type = OperandType::INT32,
+ .dimensions = {},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::CONSTANT_COPY,
+ .location = {.poolIndex = 0, .offset = 28, .length = 4},
+ },
+ {
+ .type = OperandType::INT32,
+ .dimensions = {},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::CONSTANT_COPY,
+ .location = {.poolIndex = 0, .offset = 32, .length = 4},
+ },
+ {
+ .type = OperandType::TENSOR_FLOAT32,
+ .dimensions = {3},
+ .numberOfConsumers = 0,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::MODEL_OUTPUT,
+ .location = {.poolIndex = 0, .offset = 0, .length = 0},
+ }
+ };
+
+ const std::vector<Operation> operations = {
+ {
+ .type = OperationType::STRIDED_SLICE,
+ .inputs = {0, 1, 2, 3, 4, 5, 6},
+ .outputs = {7},
+ }
+ };
+
+ const std::vector<uint32_t> inputIndexes = {0};
+ const std::vector<uint32_t> outputIndexes = {7};
+ std::vector<uint8_t> operandValues = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0
+ };
+ const std::vector<hidl_memory> pools = {};
+
+ return {
+ .operands = operands,
+ .operations = operations,
+ .inputIndexes = inputIndexes,
+ .outputIndexes = outputIndexes,
+ .operandValues = operandValues,
+ .pools = pools,
+ };
+}
+
+inline bool is_ignored(int i) {
+ static std::set<int> ignore = {};
+ return ignore.find(i) != ignore.end();
+}
+
+// Create the model
+Model createTestModel_dynamic_output_shape() {
+ const std::vector<Operand> operands = {
+ {
+ .type = OperandType::TENSOR_FLOAT32,
+ .dimensions = {2, 3},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::MODEL_INPUT,
+ .location = {.poolIndex = 0, .offset = 0, .length = 0},
+ },
+ {
+ .type = OperandType::TENSOR_INT32,
+ .dimensions = {2},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::CONSTANT_COPY,
+ .location = {.poolIndex = 0, .offset = 0, .length = 8},
+ },
+ {
+ .type = OperandType::TENSOR_INT32,
+ .dimensions = {2},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::CONSTANT_COPY,
+ .location = {.poolIndex = 0, .offset = 8, .length = 8},
+ },
+ {
+ .type = OperandType::TENSOR_INT32,
+ .dimensions = {2},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::CONSTANT_COPY,
+ .location = {.poolIndex = 0, .offset = 16, .length = 8},
+ },
+ {
+ .type = OperandType::INT32,
+ .dimensions = {},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::CONSTANT_COPY,
+ .location = {.poolIndex = 0, .offset = 24, .length = 4},
+ },
+ {
+ .type = OperandType::INT32,
+ .dimensions = {},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::CONSTANT_COPY,
+ .location = {.poolIndex = 0, .offset = 28, .length = 4},
+ },
+ {
+ .type = OperandType::INT32,
+ .dimensions = {},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::CONSTANT_COPY,
+ .location = {.poolIndex = 0, .offset = 32, .length = 4},
+ },
+ {
+ .type = OperandType::TENSOR_FLOAT32,
+ .dimensions = {0},
+ .numberOfConsumers = 0,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::MODEL_OUTPUT,
+ .location = {.poolIndex = 0, .offset = 0, .length = 0},
+ }
+ };
+
+ const std::vector<Operation> operations = {
+ {
+ .type = OperationType::STRIDED_SLICE,
+ .inputs = {0, 1, 2, 3, 4, 5, 6},
+ .outputs = {7},
+ }
+ };
+
+ const std::vector<uint32_t> inputIndexes = {0};
+ const std::vector<uint32_t> outputIndexes = {7};
+ std::vector<uint8_t> operandValues = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0
+ };
+ const std::vector<hidl_memory> pools = {};
+
+ return {
+ .operands = operands,
+ .operations = operations,
+ .inputIndexes = inputIndexes,
+ .outputIndexes = outputIndexes,
+ .operandValues = operandValues,
+ .pools = pools,
+ };
+}
+
+inline bool is_ignored_dynamic_output_shape(int i) {
+ static std::set<int> ignore = {};
+ return ignore.find(i) != ignore.end();
+}
+
diff --git a/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py b/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py
new file mode 100644
index 0000000..e8d30f3
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+# This test makes sure that executing STRIDED_SLICE results in a failure when
+# the output dimensions do not match shrinkAxisMask.
+#
+# The test generator does not support generating tests resulting in execution
+# failure, so the gTest part of this test has been written by hand.
+# TODO(b/132155416): Move this under frameworks/ml/nn/runtime/test/specs/V1_2.
+#
+# Based on strided_slice_float_11.mod.py.
+
+model = Model()
+i1 = Input("input", "TENSOR_FLOAT32", "{2, 3}")
+begins = Parameter("begins", "TENSOR_INT32", "{2}", [0, 0])
+# The value "2" below makes the test invalid. See http://b/79856511#comment2.
+ends = Parameter("ends", "TENSOR_INT32", "{2}", [2, 3])
+strides = Parameter("strides", "TENSOR_INT32", "{2}", [1, 1])
+beginMask = Int32Scalar("beginMask", 0)
+endMask = Int32Scalar("endMask", 0)
+shrinkAxisMask = Int32Scalar("shrinkAxisMask", 1)
+
+output = Output("output", "TENSOR_FLOAT32", "{3}")
+
+model = model.Operation("STRIDED_SLICE", i1, begins, ends, strides, beginMask, endMask, shrinkAxisMask).To(output)
+
+Example({
+ i1: [1, 2, 3, 4, 5, 6],
+ output: [1, 2, 3],
+})