Add generic layer metadata to Composer 2.4

Bug: 139747351
Test: VtsHalGraphicsComposerV2_4TargetTest
Test: Manual verification with a modified Composer implementation
Change-Id: I800841ab1348a93c73c25c5f8bcf2254d9dc22e8
This commit is contained in:
Dan Stoza 2019-10-21 15:43:55 -07:00
parent fdb6b518e9
commit a4bea0eac9
9 changed files with 242 additions and 0 deletions

View file

@ -71,6 +71,51 @@ interface IComposerClient extends @2.3::IComposerClient {
* setClientTargetProperty(ClientTargetProperty clientTargetProperty);
*/
SET_CLIENT_TARGET_PROPERTY = 0x105 << @2.1::IComposerClient.Command:OPCODE_SHIFT,
/**
* SET_LAYER_GENERIC_METADATA has this pseudo prototype
*
* setLayerGenericMetadata(string key, bool mandatory, vec<uint8_t> value);
*
* Sets a piece of generic metadata for the given layer. If this
* function is called twice with the same key but different values, the
* newer value must override the older one. Calling this function with a
* 0-length value must reset that key's metadata as if it had not been
* set.
*
* A given piece of metadata may either be mandatory or a hint
* (non-mandatory) as indicated by the second parameter. Mandatory
* metadata may affect the composition result, which is to say that it
* may cause a visible change in the final image. By contrast, hints may
* only affect the composition strategy, such as which layers are
* composited by the client, but must not cause a visible change in the
* final image. The value of the mandatory flag shall match the value
* returned from getLayerGenericMetadataKeys for the given key.
*
* Only keys which have been returned from getLayerGenericMetadataKeys()
* shall be accepted. Any other keys must result in an UNSUPPORTED error.
*
* The value passed into this function shall be the binary
* representation of a HIDL type corresponding to the given key. For
* example, a key of 'com.example.V1_3.Foo' shall be paired with a
* value of type com.example@1.3::Foo, which would be defined in a
* vendor HAL extension.
*
* This function will be encoded in the command buffer in this order:
* 1) The key length, stored as a uint32_t
* 2) The key itself, padded to a uint32_t boundary if necessary
* 3) The mandatory flag, stored as a uint32_t
* 4) The value length in bytes, stored as a uint32_t
* 5) The value itself, padded to a uint32_t boundary if necessary
*
* @param key indicates which metadata value should be set on this layer
* @param mandatory indicates whether this particular key represents
* mandatory metadata or a hint (non-mandatory metadata), as
* described above
* @param value is a binary representation of a HIDL struct
* corresponding to the key as described above
*/
SET_LAYER_GENERIC_METADATA = 0x40e << @2.1::IComposerClient.Command:OPCODE_SHIFT,
};
/**
@ -271,4 +316,33 @@ interface IComposerClient extends @2.3::IComposerClient {
*/
setContentType(Display display, ContentType type)
generates (Error error);
struct LayerGenericMetadataKey {
/**
* Key names must comply with the requirements specified for
* getLayerGenericMetadataKeys below
*/
string name;
/**
* The mandatory flag is defined in the description of
* setLayerGenericMetadata above
*/
bool mandatory;
};
/**
* Retrieves the set of keys that may be passed into setLayerGenericMetadata
*
* Key names must meet the following requirements:
* - Must be specified in reverse domain name notation
* - Must not start with 'com.android' or 'android'
* - Must be unique within the returned vector
* - Must correspond to a matching HIDL struct type, which defines the
* structure of its values. For example, the key 'com.example.V1-3.Foo'
* should correspond to a value of type com.example@1.3::Foo, which is
* defined in a vendor HAL extension
*/
getLayerGenericMetadataKeys()
generates(Error error, vec<LayerGenericMetadataKey> keys);
};

View file

@ -53,6 +53,27 @@ class CommandWriterBase : public V2_3::CommandWriterBase {
writeSigned(static_cast<int32_t>(clientTargetProperty.dataspace));
endCommand();
}
void setLayerGenericMetadata(const hidl_string& key, const bool mandatory,
const hidl_vec<uint8_t>& value) {
const size_t commandSize = 3 + sizeToElements(key.size()) + sizeToElements(value.size());
if (commandSize > std::numeric_limits<uint16_t>::max()) {
LOG_FATAL("Too much generic metadata (%zu elements)", commandSize);
return;
}
beginCommand(IComposerClient::Command::SET_LAYER_GENERIC_METADATA,
static_cast<uint16_t>(commandSize));
write(key.size());
writeBlob(key.size(), reinterpret_cast<const unsigned char*>(key.c_str()));
write(mandatory);
write(value.size());
writeBlob(value.size(), value.data());
endCommand();
}
protected:
uint32_t sizeToElements(uint32_t size) { return (size + 3) / 4; }
};
// This class helps parse a command queue. Note that all sizes/lengths are in

View file

@ -164,6 +164,14 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl<Interfac
return mHal->setContentType(display, contentType);
}
Return<void> getLayerGenericMetadataKeys(
IComposerClient::getLayerGenericMetadataKeys_cb hidl_cb) override {
std::vector<IComposerClient::LayerGenericMetadataKey> keys;
Error error = mHal->getLayerGenericMetadataKeys(&keys);
hidl_cb(error, keys);
return Void();
}
static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
auto client = std::make_unique<ComposerClientImpl>(hal);
return client->init() ? std::move(client) : nullptr;

View file

@ -74,6 +74,43 @@ class ComposerCommandEngine : public V2_3::hal::ComposerCommandEngine {
CommandWriterBase* getWriter() { return static_cast<CommandWriterBase*>(mWriter.get()); }
bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override {
switch (static_cast<IComposerClient::Command>(command)) {
case IComposerClient::Command::SET_LAYER_GENERIC_METADATA:
return executeSetLayerGenericMetadata(length);
default:
return BaseType2_3::executeCommand(command, length);
}
}
bool executeSetLayerGenericMetadata(uint16_t length) {
// We expect at least two buffer lengths and a mandatory flag
if (length < 3) {
return false;
}
const uint32_t keySize = read();
std::string key;
key.resize(keySize);
readBlob(keySize, key.data());
const bool mandatory = read();
const uint32_t valueSize = read();
std::vector<uint8_t> value(valueSize);
readBlob(valueSize, value.data());
auto error = mHal->setLayerGenericMetadata(mCurrentDisplay, mCurrentLayer, key, mandatory,
value);
if (error != Error::NONE) {
// The error cast is safe because setLayerGenericMetadata doesn't
// return any of the new values added in V2_4::Error
mWriter->setError(getCommandLoc(), static_cast<V2_1::Error>(error));
}
return true;
}
ComposerHal* mHal;
};

View file

@ -79,6 +79,10 @@ class ComposerHal : public V2_3::hal::ComposerHal {
uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
std::vector<uint32_t>* outRequestMasks,
IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0;
virtual Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
bool mandatory, const std::vector<uint8_t>& value) = 0;
virtual Error getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
};
} // namespace hal

View file

@ -245,6 +245,61 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
return err;
}
Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
bool mandatory, const std::vector<uint8_t>& value) override {
if (!mDispatch.setLayerGenericMetadata) {
return Error::UNSUPPORTED;
}
if (key.size() > std::numeric_limits<uint32_t>::max()) {
return Error::BAD_PARAMETER;
}
if (value.size() > std::numeric_limits<uint32_t>::max()) {
return Error::BAD_PARAMETER;
}
int32_t error = mDispatch.setLayerGenericMetadata(
mDevice, display, layer, static_cast<uint32_t>(key.size()), key.c_str(), mandatory,
static_cast<uint32_t>(value.size()), value.data());
return static_cast<Error>(error);
}
Error getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override {
if (!mDispatch.getLayerGenericMetadataKey) {
return Error::UNSUPPORTED;
}
std::vector<IComposerClient::LayerGenericMetadataKey> keys;
uint32_t index = 0;
uint32_t keyLength = 0;
while (true) {
mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, nullptr, nullptr);
if (keyLength == 0) {
break;
}
IComposerClient::LayerGenericMetadataKey key;
std::string keyName;
keyName.resize(keyLength);
mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, keyName.data(),
&key.mandatory);
key.name = keyName;
keys.emplace_back(std::move(key));
// Only attempt to load the first 100 keys to avoid an infinite loop
// if something goes wrong
if (++index > 100) {
break;
}
}
*outKeys = std::move(keys);
return Error::NONE;
}
protected:
bool initDispatch() override {
if (!BaseType2_3::initDispatch()) {
@ -267,6 +322,11 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
this->initOptionalDispatch(HWC2_FUNCTION_SET_CONTENT_TYPE, &mDispatch.setContentType);
this->initOptionalDispatch(HWC2_FUNCTION_GET_CLIENT_TARGET_PROPERTY,
&mDispatch.getClientTargetProperty);
this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_GENERIC_METADATA,
&mDispatch.setLayerGenericMetadata);
this->initOptionalDispatch(HWC2_FUNCTION_GET_LAYER_GENERIC_METADATA_KEY,
&mDispatch.getLayerGenericMetadataKey);
return true;
}
@ -319,6 +379,8 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES getSupportedContentTypes;
HWC2_PFN_SET_CONTENT_TYPE setContentType;
HWC2_PFN_GET_CLIENT_TARGET_PROPERTY getClientTargetProperty;
HWC2_PFN_SET_LAYER_GENERIC_METADATA setLayerGenericMetadata;
HWC2_PFN_GET_LAYER_GENERIC_METADATA_KEY getLayerGenericMetadataKey;
} mDispatch = {};
hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr;

View file

@ -129,6 +129,16 @@ Error ComposerClient::setContentType(Display display, IComposerClient::ContentTy
return mClient->setContentType(display, contentType);
}
Error ComposerClient::getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) {
Error error = Error::NONE;
mClient->getLayerGenericMetadataKeys([&](const auto tmpError, const auto& tmpKeys) {
error = tmpError;
*outKeys = tmpKeys;
});
return error;
}
} // namespace vts
} // namespace V2_4
} // namespace composer

View file

@ -93,6 +93,9 @@ class ComposerClient : public V2_3::vts::ComposerClient {
Error setContentType(Display display, IComposerClient::ContentType contentType);
Error getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys);
private:
const sp<IComposerClient> mClient;
};

View file

@ -17,6 +17,7 @@
#define LOG_TAG "graphics_composer_hidl_hal_test@2.4"
#include <algorithm>
#include <regex>
#include <thread>
#include <android-base/logging.h>
@ -625,6 +626,28 @@ INSTANTIATE_TEST_SUITE_P(
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
android::hardware::PrintInstanceNameToString);
TEST_F(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) {
std::vector<IComposerClient::LayerGenericMetadataKey> keys;
mComposerClient->getLayerGenericMetadataKeys(&keys);
std::regex reverseDomainName("^[a-zA-Z-]{2,}(\\.[a-zA-Z0-9-]+)+$");
std::unordered_set<std::string> uniqueNames;
for (const auto& key : keys) {
std::string name(key.name.c_str());
// Keys must not start with 'android' or 'com.android'
ASSERT_FALSE(name.find("android") == 0);
ASSERT_FALSE(name.find("com.android") == 0);
// Keys must be in reverse domain name format
ASSERT_TRUE(std::regex_match(name, reverseDomainName));
// Keys must be unique within this list
const auto& [iter, inserted] = uniqueNames.insert(name);
ASSERT_TRUE(inserted);
}
}
} // namespace
} // namespace vts
} // namespace V2_4