Merge "Use queue and unique_ptr for pooled events"
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 28ffa48..8d72a6b 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -38,12 +38,32 @@
// ----------------------------------------------------------------------
+/**
+ * If this is a local object and the descriptor matches, this will return the
+ * actual local object which is implementing the interface. Otherwise, this will
+ * return a proxy to the interface without checking the interface descriptor.
+ * This means that subsequent calls may fail with BAD_TYPE.
+ */
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
+/**
+ * This is the same as interface_cast, except that it always checks to make sure
+ * the descriptor matches, and if it doesn't match, it will return nullptr.
+ */
+template<typename INTERFACE>
+inline sp<INTERFACE> checked_interface_cast(const sp<IBinder>& obj)
+{
+ if (obj->getInterfaceDescriptor() != INTERFACE::descriptor) {
+ return nullptr;
+ }
+
+ return interface_cast<INTERFACE>(obj);
+}
+
// ----------------------------------------------------------------------
template<typename INTERFACE>
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index 3bded7f..0330dac 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -39,77 +39,210 @@
namespace gralloc4 {
-bool isStandardMetadataType(const MetadataType& metadataType) {
- return !std::strncmp(metadataType.name.c_str(), GRALLOC4_STANDARD_METADATA_TYPE, metadataType.name.size());
+static inline bool hasAdditionOverflow(size_t a, size_t b) {
+ return a > SIZE_MAX - b;
}
-StandardMetadataType getStandardMetadataTypeValue(const MetadataType& metadataType) {
- return static_cast<StandardMetadataType>(metadataType.value);
-}
+/**
+ * OutputHidlVec represents the hidl_vec that is outputed when a type is encoded into a byte stream.
+ * This class is used to track the current state of a hidl_vec as it is filled with the encoded
+ * byte stream.
+ *
+ * This type is needed because hidl_vec's resize() allocates a new backing array every time.
+ * This type does not need an copies and only needs one resize operation.
+ */
+class OutputHidlVec {
+public:
+ OutputHidlVec(hidl_vec<uint8_t>* vec)
+ : mVec(vec) {}
-status_t copyToHidlVec(const std::vector<uint8_t>& vec, hidl_vec<uint8_t>* hidlVec) {
- if (!hidlVec) {
- return BAD_VALUE;
+ status_t resize() {
+ if (!mVec) {
+ return BAD_VALUE;
+ }
+ mVec->resize(mNeededResize);
+ return NO_ERROR;
}
- hidlVec->setToExternal(const_cast<uint8_t*>(vec.data()), vec.size(), false /*shouldOwn*/);
+ status_t encode(const uint8_t* data, size_t size) {
+ if (!mVec) {
+ return BAD_VALUE;
+ }
+ if (mVec->size() == 0) {
+ if (hasAdditionOverflow(mNeededResize, size)) {
+ clear();
+ return BAD_VALUE;
+ }
+ mNeededResize += size;
+ return NO_ERROR;
+ }
+
+ if (hasAdditionOverflow(mOffset, size) || (mVec->size() < size + mOffset)) {
+ clear();
+ return BAD_VALUE;
+ }
+
+ std::copy(data, data + size, mVec->data() + mOffset);
+
+ mOffset += size;
+ return NO_ERROR;
+ }
+
+ void clear() {
+ if (mVec) {
+ mVec->resize(0);
+ }
+ mNeededResize = 0;
+ mOffset = 0;
+ }
+
+private:
+ hidl_vec<uint8_t>* mVec;
+ size_t mNeededResize = 0;
+ size_t mOffset = 0;
+};
+
+/**
+ * InputHidlVec represents the hidl_vec byte stream that is inputed when a type is decoded.
+ * This class is used to track the current index of the byte stream of the hidl_vec as it is
+ * decoded.
+ */
+class InputHidlVec {
+public:
+ InputHidlVec(const hidl_vec<uint8_t>* vec)
+ : mVec(vec) {}
+
+ status_t decode(uint8_t* data, size_t size) {
+ if (!mVec || hasAdditionOverflow(mOffset, size) || mOffset + size > mVec->size()) {
+ return BAD_VALUE;
+ }
+
+ std::copy(mVec->data() + mOffset, mVec->data() + mOffset + size, data);
+
+ mOffset += size;
+ return NO_ERROR;
+ }
+
+ status_t decode(std::string* string, size_t size) {
+ if (!mVec || hasAdditionOverflow(mOffset, size) || mOffset + size > mVec->size()) {
+ return BAD_VALUE;
+ }
+
+ string->assign(mVec->data() + mOffset, mVec->data() + mOffset + size);
+
+ mOffset += size;
+ return NO_ERROR;
+ }
+
+ bool hasRemainingData() {
+ if (!mVec) {
+ return false;
+ }
+ return mVec->size() - mOffset;
+ }
+
+private:
+ const hidl_vec<uint8_t>* mVec;
+ size_t mOffset = 0;
+};
+
+/**
+ * EncodeHelper is a function type that encodes T into the OutputHidlVec.
+ */
+template<class T>
+using EncodeHelper = status_t(*)(const T&, OutputHidlVec*);
+
+/**
+ * DecodeHelper is a function type that decodes InputHidlVec into T.
+ */
+template<class T>
+using DecodeHelper = status_t(*)(InputHidlVec*, T*);
+
+/**
+ * ErrorHandler is a function type that is called when the corresponding DecodeHelper function
+ * fails. ErrorHandler cleans up the object T so the caller doesn't receive a partially created
+ * T.
+ */
+template<class T>
+using ErrorHandler = void(*)(T*);
+
+/**
+ * encode is the main encoding function. It takes in T and uses the encodeHelper function to turn T
+ * into the hidl_vec byte stream.
+ *
+ * This function first calls the encodeHelper function to determine how large the hidl_vec
+ * needs to be. It resizes the hidl_vec. Finally, it reruns the encodeHelper function which
+ * encodes T into the hidl_vec byte stream.
+ */
+template <class T>
+status_t encode(const T& input, hidl_vec<uint8_t>* output, EncodeHelper<T> encodeHelper) {
+ OutputHidlVec outputHidlVec{output};
+ status_t err = encodeHelper(input, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+
+ err = outputHidlVec.resize();
+ if (err) {
+ return err;
+ }
+
+ return encodeHelper(input, &outputHidlVec);
+}
+
+/**
+ * decode is the main decode function. It takes in a hidl_vec and uses the decodeHelper function to
+ * turn the hidl_vec byte stream into T. If an error occurs, the errorHandler function cleans up
+ * T.
+ */
+template <class T>
+status_t decode(const hidl_vec<uint8_t>& input, T* output, DecodeHelper<T> decodeHelper,
+ ErrorHandler<T> errorHandler = nullptr) {
+ InputHidlVec inputHidlVec{&input};
+ status_t err = decodeHelper(&inputHidlVec, output);
+ if (err) {
+ return err;
+ }
+
+ err = inputHidlVec.hasRemainingData();
+ if (err) {
+ if (errorHandler) {
+ errorHandler(output);
+ }
+ return BAD_VALUE;
+ }
return NO_ERROR;
}
+/**
+ * Private helper functions
+ */
template <class T>
-status_t encodeInteger(T input, std::vector<uint8_t>* output) {
- static_assert(std::is_same<T, uint32_t>::value ||
- std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value ||
- std::is_same<T, int64_t>::value);
+status_t encodeInteger(const T& input, OutputHidlVec* output) {
+ static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value);
if (!output) {
return BAD_VALUE;
}
- size_t outputOffset = output->size();
- size_t size = sizeof(input);
-
- if (outputOffset > UINT_MAX - size) {
- return BAD_VALUE;
- }
- output->resize(size + outputOffset);
-
- uint8_t* tmp = reinterpret_cast<uint8_t*>(&input);
- std::copy(tmp, tmp + size, output->data() + outputOffset);
-
- return NO_ERROR;
+ const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
+ return output->encode(tmp, sizeof(input));
}
template <class T>
-status_t decodeInteger(const hidl_vec<uint8_t>& input, T* output, size_t* inputOffset = nullptr) {
+status_t decodeInteger(InputHidlVec* input, T* output) {
+ static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value);
if (!output) {
return BAD_VALUE;
}
- size_t offset = (inputOffset)? *inputOffset: 0;
- if (offset >= input.size()) {
- return BAD_VALUE;
- }
- size_t inputMaxSize = input.size() - offset;
- size_t outputSize = sizeof(*output);
-
- if (inputMaxSize < outputSize) {
- return BAD_VALUE;
- }
-
uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
- const uint8_t* data = input.data() + offset;
- std::copy(data, data + outputSize, tmp);
-
- if (inputOffset) {
- *inputOffset += outputSize;
- }
-
- return NO_ERROR;
+ return input->decode(tmp, sizeof(*output));
}
-status_t encodeString(const std::string& input, std::vector<uint8_t>* output) {
+status_t encodeString(const std::string& input, OutputHidlVec* output) {
if (!output) {
return BAD_VALUE;
}
@@ -119,66 +252,60 @@
return err;
}
- size_t outputOffset = output->size();
- size_t size = input.size();
- output->resize(size + outputOffset);
-
- std::copy(input.c_str(), input.c_str() + size, output->data() + outputOffset);
-
- return NO_ERROR;
+ return output->encode(reinterpret_cast<const uint8_t*>(input.c_str()), input.size());
}
-status_t decodeString(const hidl_vec<uint8_t>& input, std::string* output, size_t* inputOffset = nullptr) {
+status_t decodeString(InputHidlVec* input, std::string* output) {
if (!output) {
return BAD_VALUE;
}
int64_t size = 0;
- status_t err = decodeInteger<int64_t>(input, &size, inputOffset);
+ status_t err = decodeInteger<int64_t>(input, &size);
if (err || size < 0) {
return err;
}
- size_t offset = (inputOffset)? *inputOffset + sizeof(size): sizeof(size);
- if ((offset > UINT_MAX - size) || (offset + size > input.size())) {
- return BAD_VALUE;
- }
-
- auto data = input.data() + offset;
- output->assign(data, data + size);
-
- if (inputOffset) {
- *inputOffset += size;
- }
-
- return NO_ERROR;
+ return input->decode(output, size);
}
-status_t encodeExtendableType(const ExtendableType& input, std::vector<uint8_t>* output) {
+status_t encodeExtendableType(const ExtendableType& input, OutputHidlVec* output) {
status_t err = encodeString(input.name, output);
if (err) {
return err;
}
- return encodeInteger<int64_t>(input.value, output);
-}
-
-status_t decodeExtendableType(const hidl_vec<uint8_t>& input, ExtendableType* output, size_t* inputOffset = nullptr) {
- status_t err = decodeString(input, &output->name, inputOffset);
+ err = encodeInteger<int64_t>(input.value, output);
if (err) {
return err;
}
- err = decodeInteger<int64_t>(input, &output->value, inputOffset);
- if (err) {
- output->name.clear();
- return err;
- }
-
return NO_ERROR;
}
-status_t encodeRect(const Rect& input, std::vector<uint8_t>* output) {
+status_t decodeExtendableType(InputHidlVec* input, ExtendableType* output) {
+ status_t err = decodeString(input, &output->name);
+ if (err) {
+ return err;
+ }
+
+ err = decodeInteger<int64_t>(input, &output->value);
+ if (err) {
+ return err;
+ }
+
+ return NO_ERROR;
+}
+
+void clearExtendableType(ExtendableType* output) {
+ if (!output) {
+ return;
+ }
+ output->name.clear();
+ output->value = 0;
+}
+
+status_t encodeRect(const Rect& input, OutputHidlVec* output) {
status_t err = encodeInteger<int32_t>(static_cast<int32_t>(input.left), output);
if (err) {
return err;
@@ -194,23 +321,23 @@
return encodeInteger<int32_t>(static_cast<int32_t>(input.bottom), output);
}
-status_t decodeRect(const hidl_vec<uint8_t>& input, Rect* output, size_t* inputOffset = nullptr) {
- status_t err = decodeInteger<int32_t>(input, &output->left, inputOffset);
+status_t decodeRect(InputHidlVec* input, Rect* output) {
+ status_t err = decodeInteger<int32_t>(input, &output->left);
if (err) {
return err;
}
- err = decodeInteger<int32_t>(input, &output->top, inputOffset);
+ err = decodeInteger<int32_t>(input, &output->top);
if (err) {
return err;
}
- err = decodeInteger<int32_t>(input, &output->right, inputOffset);
+ err = decodeInteger<int32_t>(input, &output->right);
if (err) {
return err;
}
- return decodeInteger<int32_t>(input, &output->bottom, inputOffset);
+ return decodeInteger<int32_t>(input, &output->bottom);
}
-status_t encodePlaneLayoutComponent(const PlaneLayoutComponent& input, std::vector<uint8_t>* output) {
+status_t encodePlaneLayoutComponent(const PlaneLayoutComponent& input, OutputHidlVec* output) {
if (!output) {
return BAD_VALUE;
}
@@ -226,23 +353,23 @@
return encodeInteger<int64_t>(static_cast<int64_t>(input.sizeInBits), output);
}
-status_t decodePlaneLayoutComponent(const hidl_vec<uint8_t>& input, PlaneLayoutComponent* output, size_t* inputOffset = nullptr) {
+status_t decodePlaneLayoutComponent(InputHidlVec* input, PlaneLayoutComponent* output) {
if (!output) {
return BAD_VALUE;
}
- status_t err = decodeExtendableType(input, &output->type, inputOffset);
+ status_t err = decodeExtendableType(input, &output->type);
if (err) {
return err;
}
- err = decodeInteger<int64_t>(input, &output->offsetInBits, inputOffset);
+ err = decodeInteger<int64_t>(input, &output->offsetInBits);
if (err) {
return err;
}
- return decodeInteger<int64_t>(input, &output->sizeInBits, inputOffset);
+ return decodeInteger<int64_t>(input, &output->sizeInBits);
}
-status_t encodePlaneLayoutComponents(const std::vector<PlaneLayoutComponent>& input, std::vector<uint8_t>* output) {
+status_t encodePlaneLayoutComponents(const std::vector<PlaneLayoutComponent>& input, OutputHidlVec* output) {
if (!output) {
return BAD_VALUE;
}
@@ -262,20 +389,20 @@
return NO_ERROR;
}
-status_t decodePlaneLayoutComponents(const hidl_vec<uint8_t>& input, std::vector<PlaneLayoutComponent>* output, size_t* inputOffset = nullptr) {
+status_t decodePlaneLayoutComponents(InputHidlVec* input, std::vector<PlaneLayoutComponent>* output) {
if (!output) {
return BAD_VALUE;
}
int64_t size = 0;
- status_t err = decodeInteger<int64_t>(input, &size, inputOffset);
+ status_t err = decodeInteger<int64_t>(input, &size);
if (err || size < 0) {
return err;
}
for (int i = 0; i < size; i++) {
output->emplace_back();
- err = decodePlaneLayoutComponent(input, &output->back(), inputOffset);
+ err = decodePlaneLayoutComponent(input, &output->back());
if (err) {
return err;
}
@@ -283,7 +410,7 @@
return NO_ERROR;
}
-status_t encodePlaneLayout(const PlaneLayout& input, std::vector<uint8_t>* output) {
+status_t encodePlaneLayout(const PlaneLayout& input, OutputHidlVec* output) {
if (!output) {
return BAD_VALUE;
}
@@ -329,307 +456,239 @@
return encodeRect(input.crop, output);
}
-status_t decodePlaneLayout(const hidl_vec<uint8_t>& input, PlaneLayout* output, size_t* inputOffset = nullptr) {
+status_t decodePlaneLayout(InputHidlVec* input, PlaneLayout* output) {
if (!output) {
return BAD_VALUE;
}
- status_t err = decodePlaneLayoutComponents(input, &output->components, inputOffset);
+ status_t err = decodePlaneLayoutComponents(input, &output->components);
if (err) {
return err;
}
- err = decodeInteger<int64_t>(input, &output->offsetInBytes, inputOffset);
+ err = decodeInteger<int64_t>(input, &output->offsetInBytes);
if (err) {
return err;
}
- err = decodeInteger<int64_t>(input, &output->sampleIncrementInBits, inputOffset);
+ err = decodeInteger<int64_t>(input, &output->sampleIncrementInBits);
if (err) {
return err;
}
- err = decodeInteger<int64_t>(input, &output->strideInBytes, inputOffset);
+ err = decodeInteger<int64_t>(input, &output->strideInBytes);
if (err) {
return err;
}
- err = decodeInteger<int64_t>(input, &output->widthInSamples, inputOffset);
+ err = decodeInteger<int64_t>(input, &output->widthInSamples);
if (err) {
return err;
}
- err = decodeInteger<int64_t>(input, &output->heightInSamples, inputOffset);
+ err = decodeInteger<int64_t>(input, &output->heightInSamples);
if (err) {
return err;
}
- err = decodeInteger<int64_t>(input, &output->totalSizeInBytes, inputOffset);
+ err = decodeInteger<int64_t>(input, &output->totalSizeInBytes);
if (err) {
return err;
}
- err = decodeInteger<int64_t>(input, &output->horizontalSubsampling, inputOffset);
+ err = decodeInteger<int64_t>(input, &output->horizontalSubsampling);
if (err) {
return err;
}
- err = decodeInteger<int64_t>(input, &output->verticalSubsampling, inputOffset);
+ err = decodeInteger<int64_t>(input, &output->verticalSubsampling);
if (err) {
return err;
}
- return decodeRect(input, &output->crop, inputOffset);
+ return decodeRect(input, &output->crop);
}
-status_t encodePlaneLayouts(const std::vector<PlaneLayout>& planeLayouts, hidl_vec<uint8_t>* outPlaneLayouts) {
- if (!outPlaneLayouts) {
- return BAD_VALUE;
- }
-
- std::vector<uint8_t> tmpOutPlaneLayouts;
-
- status_t err = encodeInteger<int64_t>(static_cast<int64_t>(planeLayouts.size()), &tmpOutPlaneLayouts);
+status_t encodePlaneLayoutsHelper(const std::vector<PlaneLayout>& planeLayouts, OutputHidlVec* outOutputHidlVec) {
+ status_t err = encodeInteger<int64_t>(static_cast<int64_t>(planeLayouts.size()), outOutputHidlVec);
if (err) {
return err;
}
for (const auto& planeLayout : planeLayouts) {
- err = encodePlaneLayout(planeLayout, &tmpOutPlaneLayouts);
+ err = encodePlaneLayout(planeLayout, outOutputHidlVec);
if (err) {
return err;
}
}
- return copyToHidlVec(tmpOutPlaneLayouts, outPlaneLayouts);
+ return NO_ERROR;
}
-status_t decodePlaneLayouts(const hidl_vec<uint8_t>& planeLayouts, std::vector<PlaneLayout>* outPlaneLayouts) {
- if (!outPlaneLayouts) {
- return BAD_VALUE;
- }
-
- size_t offset = 0;
+status_t decodePlaneLayoutsHelper(InputHidlVec* inputHidlVec, std::vector<PlaneLayout>* outPlaneLayouts) {
int64_t size = 0;
- status_t err = decodeInteger<int64_t>(planeLayouts, &size, &offset);
+ status_t err = decodeInteger<int64_t>(inputHidlVec, &size);
if (err || size < 0) {
return err;
}
for (size_t i = 0; i < size; i++) {
outPlaneLayouts->emplace_back();
- err = decodePlaneLayout(planeLayouts, &outPlaneLayouts->back(), &offset);
+ err = decodePlaneLayout(inputHidlVec, &outPlaneLayouts->back());
if (err) {
- outPlaneLayouts->resize(0);
return err;
}
}
- if (offset < planeLayouts.size()) {
- return BAD_VALUE;
- }
-
return NO_ERROR;
}
-status_t encodeBufferId(uint64_t bufferId, hidl_vec<uint8_t>* outBufferId) {
- std::vector<uint8_t> tmpOutBufferId;
- status_t err = encodeInteger<uint64_t>(bufferId, &tmpOutBufferId);
- if (err) {
- return err;
+void clearPlaneLayouts(std::vector<PlaneLayout>* output) {
+ if (!output) {
+ return;
}
- return copyToHidlVec(tmpOutBufferId, outBufferId);
+ output->clear();
+}
+
+/**
+ * Public API functions
+ */
+bool isStandardMetadataType(const MetadataType& metadataType) {
+ return !std::strncmp(metadataType.name.c_str(), GRALLOC4_STANDARD_METADATA_TYPE, metadataType.name.size());
+}
+
+StandardMetadataType getStandardMetadataTypeValue(const MetadataType& metadataType) {
+ return static_cast<StandardMetadataType>(metadataType.value);
+}
+
+status_t encodeBufferId(uint64_t bufferId, hidl_vec<uint8_t>* outBufferId) {
+ return encode(bufferId, outBufferId, encodeInteger);
}
status_t decodeBufferId(const hidl_vec<uint8_t>& bufferId, uint64_t* outBufferId) {
- return decodeInteger<uint64_t>(bufferId, outBufferId);
+ return decode(bufferId, outBufferId, decodeInteger);
}
status_t encodeName(const std::string& name, hidl_vec<uint8_t>* outName) {
- std::vector<uint8_t> tmpOutName;
- status_t err = encodeString(name, &tmpOutName);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutName, outName);
+ return encode(name, outName, encodeString);
}
status_t decodeName(const hidl_vec<uint8_t>& name, std::string* outName) {
- return decodeString(name, outName);
+ return decode(name, outName, decodeString);
}
status_t encodeWidth(uint64_t width, hidl_vec<uint8_t>* outWidth) {
- std::vector<uint8_t> tmpOutWidth;
- status_t err = encodeInteger<uint64_t>(width, &tmpOutWidth);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutWidth, outWidth);
+ return encode(width, outWidth, encodeInteger);
}
status_t decodeWidth(const hidl_vec<uint8_t>& width, uint64_t* outWidth) {
- return decodeInteger<uint64_t>(width, outWidth);
+ return decode(width, outWidth, decodeInteger);
}
status_t encodeHeight(uint64_t height, hidl_vec<uint8_t>* outHeight) {
- std::vector<uint8_t> tmpOutHeight;
- status_t err = encodeInteger<uint64_t>(height, &tmpOutHeight);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutHeight, outHeight);
+ return encode(height, outHeight, encodeInteger);
}
status_t decodeHeight(const hidl_vec<uint8_t>& height, uint64_t* outHeight) {
- return decodeInteger<uint64_t>(height, outHeight);
+ return decode(height, outHeight, decodeInteger);
}
status_t encodeLayerCount(uint64_t layerCount, hidl_vec<uint8_t>* outLayerCount) {
- std::vector<uint8_t> tmpOutLayerCount;
- status_t err = encodeInteger<uint64_t>(layerCount, &tmpOutLayerCount);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutLayerCount, outLayerCount);
+ return encode(layerCount, outLayerCount, encodeInteger);
}
status_t decodeLayerCount(const hidl_vec<uint8_t>& layerCount, uint64_t* outLayerCount) {
- return decodeInteger<uint64_t>(layerCount, outLayerCount);
+ return decode(layerCount, outLayerCount, decodeInteger);
}
-status_t encodePixelFormatRequested(const hardware::graphics::common::V1_2::PixelFormat& pixelFormatRequested, hidl_vec<uint8_t>* outPixelFormatRequested) {
- std::vector<uint8_t> tmpOutPixelFormatRequested;
- status_t err = encodeInteger<int32_t>(static_cast<int32_t>(pixelFormatRequested), &tmpOutPixelFormatRequested);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutPixelFormatRequested, outPixelFormatRequested);
+status_t encodePixelFormatRequested(const hardware::graphics::common::V1_2::PixelFormat& pixelFormatRequested,
+ hidl_vec<uint8_t>* outPixelFormatRequested) {
+ return encode(static_cast<int32_t>(pixelFormatRequested), outPixelFormatRequested, encodeInteger);
}
-status_t decodePixelFormatRequested(const hidl_vec<uint8_t>& pixelFormatRequested, hardware::graphics::common::V1_2::PixelFormat* outPixelFormatRequested) {
- return decodeInteger<int32_t>(pixelFormatRequested, reinterpret_cast<int32_t*>(outPixelFormatRequested));
+status_t decodePixelFormatRequested(const hidl_vec<uint8_t>& pixelFormatRequested,
+ hardware::graphics::common::V1_2::PixelFormat* outPixelFormatRequested) {
+ return decode(pixelFormatRequested, reinterpret_cast<int32_t*>(outPixelFormatRequested), decodeInteger);
}
status_t encodePixelFormatFourCC(uint32_t pixelFormatFourCC, hidl_vec<uint8_t>* outPixelFormatFourCC) {
- std::vector<uint8_t> tmpOutPixelFormatFourCC;
- status_t err = encodeInteger<uint32_t>(pixelFormatFourCC, &tmpOutPixelFormatFourCC);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutPixelFormatFourCC, outPixelFormatFourCC);
+ return encode(pixelFormatFourCC, outPixelFormatFourCC, encodeInteger);
}
status_t decodePixelFormatFourCC(const hidl_vec<uint8_t>& pixelFormatFourCC, uint32_t* outPixelFormatFourCC) {
- return decodeInteger<uint32_t>(pixelFormatFourCC, outPixelFormatFourCC);
+ return decode(pixelFormatFourCC, outPixelFormatFourCC, decodeInteger);
}
status_t encodePixelFormatModifier(uint64_t pixelFormatModifier, hidl_vec<uint8_t>* outPixelFormatModifier) {
- std::vector<uint8_t> tmpOutPixelFormatModifier;
- status_t err = encodeInteger<uint64_t>(pixelFormatModifier, &tmpOutPixelFormatModifier);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutPixelFormatModifier, outPixelFormatModifier);
+ return encode(pixelFormatModifier, outPixelFormatModifier, encodeInteger);
}
status_t decodePixelFormatModifier(const hidl_vec<uint8_t>& pixelFormatModifier, uint64_t* outPixelFormatModifier) {
- return decodeInteger<uint64_t>(pixelFormatModifier, outPixelFormatModifier);
+ return decode(pixelFormatModifier, outPixelFormatModifier, decodeInteger);
}
status_t encodeUsage(uint64_t usage, hidl_vec<uint8_t>* outUsage) {
- std::vector<uint8_t> tmpOutUsage;
- status_t err = encodeInteger<uint64_t>(usage, &tmpOutUsage);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutUsage, outUsage);
+ return encode(usage, outUsage, encodeInteger);
}
status_t decodeUsage(const hidl_vec<uint8_t>& usage, uint64_t* outUsage) {
- return decodeInteger<uint64_t>(usage, outUsage);
+ return decode(usage, outUsage, decodeInteger);
}
status_t encodeAllocationSize(uint64_t allocationSize, hidl_vec<uint8_t>* outAllocationSize) {
- std::vector<uint8_t> tmpOutAllocationSize;
- status_t err = encodeInteger<uint64_t>(allocationSize, &tmpOutAllocationSize);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutAllocationSize, outAllocationSize);
+ return encode(allocationSize, outAllocationSize, encodeInteger);
}
status_t decodeAllocationSize(const hidl_vec<uint8_t>& allocationSize, uint64_t* outAllocationSize) {
- return decodeInteger<uint64_t>(allocationSize, outAllocationSize);
+ return decode(allocationSize, outAllocationSize, decodeInteger);
}
status_t encodeProtectedContent(uint64_t protectedContent, hidl_vec<uint8_t>* outProtectedContent) {
- std::vector<uint8_t> tmpOutProtectedContent;
- status_t err = encodeInteger<uint64_t>(protectedContent, &tmpOutProtectedContent);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutProtectedContent, outProtectedContent);
+ return encode(protectedContent, outProtectedContent, encodeInteger);
}
status_t decodeProtectedContent(const hidl_vec<uint8_t>& protectedContent, uint64_t* outProtectedContent) {
- return decodeInteger<uint64_t>(protectedContent, outProtectedContent);
+ return decode(protectedContent, outProtectedContent, decodeInteger);
}
status_t encodeCompression(const ExtendableType& compression, hidl_vec<uint8_t>* outCompression) {
- std::vector<uint8_t> tmpOutCompression;
- status_t err = encodeExtendableType(compression, &tmpOutCompression);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutCompression, outCompression);
+ return encode(compression, outCompression, encodeExtendableType);
}
status_t decodeCompression(const hidl_vec<uint8_t>& compression, ExtendableType* outCompression) {
- return decodeExtendableType(compression, outCompression);
+ return decode(compression, outCompression, decodeExtendableType, clearExtendableType);
}
status_t encodeInterlaced(const ExtendableType& interlaced, hidl_vec<uint8_t>* outInterlaced) {
- std::vector<uint8_t> tmpOutInterlaced;
- status_t err = encodeExtendableType(interlaced, &tmpOutInterlaced);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutInterlaced, outInterlaced);
+ return encode(interlaced, outInterlaced, encodeExtendableType);
}
status_t decodeInterlaced(const hidl_vec<uint8_t>& interlaced, ExtendableType* outInterlaced) {
- return decodeExtendableType(interlaced, outInterlaced);
+ return decode(interlaced, outInterlaced, decodeExtendableType, clearExtendableType);
}
status_t encodeChromaSiting(const ExtendableType& chromaSiting, hidl_vec<uint8_t>* outChromaSiting) {
- std::vector<uint8_t> tmpOutChromaSiting;
- status_t err = encodeExtendableType(chromaSiting, &tmpOutChromaSiting);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutChromaSiting, outChromaSiting);
+ return encode(chromaSiting, outChromaSiting, encodeExtendableType);
}
status_t decodeChromaSiting(const hidl_vec<uint8_t>& chromaSiting, ExtendableType* outChromaSiting) {
- return decodeExtendableType(chromaSiting, outChromaSiting);
+ return decode(chromaSiting, outChromaSiting, decodeExtendableType, clearExtendableType);
+}
+
+status_t encodePlaneLayouts(const std::vector<PlaneLayout>& planeLayouts, hidl_vec<uint8_t>* outPlaneLayouts) {
+ return encode(planeLayouts, outPlaneLayouts, encodePlaneLayoutsHelper);
+}
+
+status_t decodePlaneLayouts(const hidl_vec<uint8_t>& planeLayouts, std::vector<PlaneLayout>* outPlaneLayouts) {
+ return decode(planeLayouts, outPlaneLayouts, decodePlaneLayoutsHelper, clearPlaneLayouts);
}
status_t encodeDataspace(const Dataspace& dataspace, hidl_vec<uint8_t>* outDataspace) {
- std::vector<uint8_t> tmpOutDataspace;
- status_t err = encodeInteger<int32_t>(static_cast<int32_t>(dataspace), &tmpOutDataspace);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutDataspace, outDataspace);
+ return encode(static_cast<int32_t>(dataspace), outDataspace, encodeInteger);
}
status_t decodeDataspace(const hidl_vec<uint8_t>& dataspace, Dataspace* outDataspace) {
- return decodeInteger<int32_t>(dataspace, reinterpret_cast<int32_t*>(outDataspace));
+ return decode(dataspace, reinterpret_cast<int32_t*>(outDataspace), decodeInteger);
}
status_t encodeBlendMode(const BlendMode& blendMode, hidl_vec<uint8_t>* outBlendMode) {
- std::vector<uint8_t> tmpOutBlendMode;
- status_t err = encodeInteger<int32_t>(static_cast<int32_t>(blendMode), &tmpOutBlendMode);
- if (err) {
- return err;
- }
- return copyToHidlVec(tmpOutBlendMode, outBlendMode);
+ return encode(static_cast<int32_t>(blendMode), outBlendMode, encodeInteger);
}
status_t decodeBlendMode(const hidl_vec<uint8_t>& blendMode, BlendMode* outBlendMode) {
- return decodeInteger<int32_t>(blendMode, reinterpret_cast<int32_t*>(outBlendMode));
+ return decode(blendMode, reinterpret_cast<int32_t*>(outBlendMode), decodeInteger);
}
} // namespace gralloc4
diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp
new file mode 100644
index 0000000..8444883
--- /dev/null
+++ b/libs/gralloc/types/fuzzer/Android.bp
@@ -0,0 +1,32 @@
+cc_fuzz {
+ name: "libgralloctypes_fuzzer",
+ defaults: ["libbinder_ndk_host_user"],
+ host_supported: true,
+
+ fuzz_config: {
+ cc: ["marissaw@google.com"],
+ },
+
+ srcs: [
+ "gralloctypes.cpp",
+ "main.cpp",
+ "util.cpp",
+ ],
+ static_libs: [
+ "libbase",
+ "libcgrouprc",
+ "libcgrouprc_format",
+ "libcutils",
+ "libgralloctypes",
+ "libhidlbase",
+ "liblog",
+ "libprocessgroup",
+ "libjsoncpp",
+ "libutils",
+ ],
+
+ // This flag enables verbose output in the fuzz target, and is very useful
+ // for debugging a failure. If you are trying to diagnose how a crash was
+ // produced, you may find uncommenting the below line very useful.
+ // cflags: ["-DENABLE_LOG_FUZZ"],
+}
diff --git a/libs/gralloc/types/fuzzer/gralloctypes.cpp b/libs/gralloc/types/fuzzer/gralloctypes.cpp
new file mode 100644
index 0000000..23c90b8
--- /dev/null
+++ b/libs/gralloc/types/fuzzer/gralloctypes.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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 FUZZ_LOG_TAG "gralloctypes"
+
+#include <cstdint>
+
+#include <aidl/android/hardware/graphics/common/BlendMode.h>
+#include <aidl/android/hardware/graphics/common/Dataspace.h>
+#include <aidl/android/hardware/graphics/common/ExtendableType.h>
+#include <aidl/android/hardware/graphics/common/PlaneLayout.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <gralloctypes/Gralloc4.h>
+#include <hidl/HidlSupport.h>
+#include <utils/Errors.h>
+
+#include "gralloctypes.h"
+#include "util.h"
+
+using ::android::status_t;
+
+#define GRALLOCTYPES_DECODE(T, FUNC) \
+ [] (const ::android::hardware::hidl_vec<uint8_t>& vec, uint8_t /*data*/) {\
+ FUZZ_LOG() << "about to read " #T " using " #FUNC;\
+ T t;\
+ status_t err = FUNC(vec, &t);\
+ (void) err;\
+ FUZZ_LOG() << #T " done " /* << "err: " << err*/;\
+ }
+
+
+// clang-format off
+std::vector<GrallocTypesDecode> GRALLOCTYPES_DECODE_FUNCTIONS {
+ GRALLOCTYPES_DECODE(uint64_t, ::android::gralloc4::decodeBufferId),
+ GRALLOCTYPES_DECODE(std::string, ::android::gralloc4::decodeName),
+ GRALLOCTYPES_DECODE(uint64_t, ::android::gralloc4::decodeWidth),
+ GRALLOCTYPES_DECODE(uint64_t, ::android::gralloc4::decodeHeight),
+ GRALLOCTYPES_DECODE(uint64_t, ::android::gralloc4::decodeLayerCount),
+ GRALLOCTYPES_DECODE(::android::hardware::graphics::common::V1_2::PixelFormat, ::android::gralloc4::decodePixelFormatRequested),
+ GRALLOCTYPES_DECODE(uint32_t, ::android::gralloc4::decodePixelFormatFourCC),
+ GRALLOCTYPES_DECODE(uint64_t, ::android::gralloc4::decodePixelFormatModifier),
+ GRALLOCTYPES_DECODE(uint64_t, ::android::gralloc4::decodeUsage),
+ GRALLOCTYPES_DECODE(uint64_t, ::android::gralloc4::decodeAllocationSize),
+ GRALLOCTYPES_DECODE(uint64_t, ::android::gralloc4::decodeProtectedContent),
+ GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::ExtendableType, ::android::gralloc4::decodeCompression),
+ GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::ExtendableType, ::android::gralloc4::decodeInterlaced),
+ GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::ExtendableType, ::android::gralloc4::decodeChromaSiting),
+ GRALLOCTYPES_DECODE(std::vector<aidl::android::hardware::graphics::common::PlaneLayout>, ::android::gralloc4::decodePlaneLayouts),
+ GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::Dataspace, ::android::gralloc4::decodeDataspace),
+ GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::BlendMode, ::android::gralloc4::decodeBlendMode),
+};
+// clang-format on
diff --git a/libs/gralloc/types/fuzzer/gralloctypes.h b/libs/gralloc/types/fuzzer/gralloctypes.h
new file mode 100644
index 0000000..b995fce
--- /dev/null
+++ b/libs/gralloc/types/fuzzer/gralloctypes.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <gralloctypes/Gralloc4.h>
+#include <hidl/HidlSupport.h>
+
+#include <vector>
+
+using GrallocTypesDecode = std::function<void(const ::android::hardware::hidl_vec<uint8_t>& vec, uint8_t data)>;
+
+extern std::vector<GrallocTypesDecode> GRALLOCTYPES_DECODE_FUNCTIONS;
diff --git a/libs/gralloc/types/fuzzer/main.cpp b/libs/gralloc/types/fuzzer/main.cpp
new file mode 100644
index 0000000..2807878
--- /dev/null
+++ b/libs/gralloc/types/fuzzer/main.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 FUZZ_LOG_TAG "main"
+
+#include "gralloctypes.h"
+#include "util.h"
+
+#include <android-base/logging.h>
+#include <log/log.h>
+
+#include <cstdlib>
+#include <ctime>
+
+void doFuzz(
+ const std::vector<GrallocTypesDecode>& decodes,
+ const std::vector<uint8_t>& input,
+ const std::vector<uint8_t>& instructions) {
+
+ ::android::hardware::hidl_vec<uint8_t> vec;
+ vec.setToExternal(const_cast<uint8_t*>(input.data()), input.size(), false /*shouldOwn*/);
+
+ // since we are only using a byte to index
+ CHECK(decodes.size() <= 255) << decodes.size();
+
+ for (size_t i = 0; i < instructions.size() - 1; i += 2) {
+ uint8_t a = instructions[i];
+ uint8_t decodeIdx = a % decodes.size();
+
+ uint8_t b = instructions[i + 1];
+
+ FUZZ_LOG() << "Instruction: " << (i / 2) + 1 << "/" << instructions.size() / 2
+ << " cmd: " << static_cast<size_t>(a) << " (" << static_cast<size_t>(decodeIdx)
+ << ") arg: " << static_cast<size_t>(b) << " size: " << vec.size();
+
+ decodes[decodeIdx](vec, b);
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size <= 1) return 0; // no use
+
+ // data to fill out parcel
+ size_t inputLen = size / 2;
+ std::vector<uint8_t> input(data, data + inputLen);
+ data += inputLen;
+ size -= inputLen;
+
+ // data to use to determine what to do
+ size_t instructionLen = size;
+ std::vector<uint8_t> instructions(data, data + instructionLen);
+ data += instructionLen;
+ size -= instructionLen;
+
+ CHECK(size == 0) << "size: " << size;
+
+ FUZZ_LOG() << "inputLen: " << inputLen << " instructionLen: " << instructionLen;
+ FUZZ_LOG() << "input: " << hexString(input);
+ FUZZ_LOG() << "instructions: " << hexString(instructions);
+
+ doFuzz(GRALLOCTYPES_DECODE_FUNCTIONS, input, instructions);
+ return 0;
+}
diff --git a/libs/gralloc/types/fuzzer/util.cpp b/libs/gralloc/types/fuzzer/util.cpp
new file mode 100644
index 0000000..479f406
--- /dev/null
+++ b/libs/gralloc/types/fuzzer/util.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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 FUZZ_LOG_TAG "util"
+#include "util.h"
+
+#include <android-base/logging.h>
+
+#include <iomanip>
+#include <sstream>
+
+std::string hexString(const void* bytes, size_t len) {
+ if (bytes == nullptr) return "<null>";
+
+ const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
+ char chars[] = "0123456789abcdef";
+ std::string result;
+ result.resize(len * 2);
+
+ for (size_t i = 0; i < len; i++) {
+ result[2 * i] = chars[bytes8[i] >> 4];
+ result[2 * i + 1] = chars[bytes8[i] & 0xf];
+ }
+
+ return result;
+}
+std::string hexString(const std::vector<uint8_t>& bytes) {
+ return hexString(bytes.data(), bytes.size());
+}
diff --git a/libs/gralloc/types/fuzzer/util.h b/libs/gralloc/types/fuzzer/util.h
new file mode 100644
index 0000000..aa504d2
--- /dev/null
+++ b/libs/gralloc/types/fuzzer/util.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#ifndef FUZZ_LOG_TAG
+#error "Must define FUZZ_LOG_TAG"
+#endif
+
+#define FUZZ_LOG() FuzzLog(FUZZ_LOG_TAG).log()
+
+#ifdef ENABLE_LOG_FUZZ
+class FuzzLog {
+public:
+ FuzzLog(const char* tag) : mTag(tag) {}
+ ~FuzzLog() { std::cout << mTag << ": " << mOs.str() << std::endl; }
+
+ std::stringstream& log() { return mOs; }
+
+private:
+ const char* mTag = nullptr;
+ std::stringstream mOs;
+};
+#else
+class FuzzLog {
+public:
+ FuzzLog(const char* /*tag*/) {}
+ template <typename T>
+ FuzzLog& operator<<(const T& /*t*/) {
+ return *this;
+ }
+ FuzzLog& log() { return *this; }
+};
+#endif
+
+std::string hexString(const void* bytes, size_t len);
+std::string hexString(const std::vector<uint8_t>& bytes);
diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp
index 6665635..6566538 100644
--- a/libs/nativedisplay/ADisplay.cpp
+++ b/libs/nativedisplay/ADisplay.cpp
@@ -18,6 +18,7 @@
#include <gui/SurfaceComposerClient.h>
#include <ui/DisplayInfo.h>
#include <ui/GraphicTypes.h>
+#include <ui/PixelFormat.h>
#include <algorithm>
#include <optional>
@@ -82,6 +83,16 @@
ADisplayType type;
/**
+ * The preferred WCG dataspace
+ */
+ ADataSpace wcgDataspace;
+
+ /**
+ * The preferred WCG pixel format
+ */
+ AHardwareBuffer_Format wcgPixelFormat;
+
+ /**
* Number of supported configs
*/
size_t numConfigs;
@@ -151,6 +162,17 @@
const std::optional<PhysicalDisplayId> internalId =
SurfaceComposerClient::getInternalDisplayId();
+ ui::Dataspace defaultDataspace;
+ ui::PixelFormat defaultPixelFormat;
+ ui::Dataspace wcgDataspace;
+ ui::PixelFormat wcgPixelFormat;
+
+ const status_t status =
+ SurfaceComposerClient::getCompositionPreference(&defaultDataspace, &defaultPixelFormat,
+ &wcgDataspace, &wcgPixelFormat);
+ if (status != NO_ERROR) {
+ return status;
+ }
// Here we allocate all our required memory in one block. The layout is as
// follows:
@@ -176,7 +198,12 @@
const std::vector<DisplayConfigImpl>& configs = configsPerDisplay[i];
memcpy(configData, configs.data(), sizeof(DisplayConfigImpl) * configs.size());
- displayData[i] = DisplayImpl{id, type, configs.size(), configData};
+ displayData[i] = DisplayImpl{id,
+ type,
+ static_cast<ADataSpace>(wcgDataspace),
+ static_cast<AHardwareBuffer_Format>(wcgPixelFormat),
+ configs.size(),
+ configData};
impls[i] = displayData + i;
// Advance the configData pointer so that future configs are written to
// the correct display.
@@ -210,6 +237,17 @@
return reinterpret_cast<DisplayImpl*>(display)->type;
}
+void ADisplay_getPreferredWideColorFormat(ADisplay* display, ADataSpace* outDataspace,
+ AHardwareBuffer_Format* outPixelFormat) {
+ CHECK_NOT_NULL(display);
+ CHECK_NOT_NULL(outDataspace);
+ CHECK_NOT_NULL(outPixelFormat);
+
+ DisplayImpl* impl = reinterpret_cast<DisplayImpl*>(display);
+ *outDataspace = impl->wcgDataspace;
+ *outPixelFormat = impl->wcgPixelFormat;
+}
+
int ADisplay_getCurrentConfig(ADisplay* display, ADisplayConfig** outConfig) {
CHECK_NOT_NULL(display);
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index 45b935a..a9b8d66 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -49,6 +49,7 @@
"libandroidfw",
"libgui",
"liblog",
+ "libnativewindow",
"libui",
"libutils",
],
diff --git a/libs/nativedisplay/include/apex/display.h b/libs/nativedisplay/include/apex/display.h
index 7af452a..9be401e 100644
--- a/libs/nativedisplay/include/apex/display.h
+++ b/libs/nativedisplay/include/apex/display.h
@@ -16,6 +16,8 @@
#pragma once
+#include <android/data_space.h>
+#include <android/hardware_buffer.h>
#include <inttypes.h>
__BEGIN_DECLS
@@ -72,6 +74,12 @@
ADisplayType ADisplay_getDisplayType(ADisplay* display);
/**
+ * Queries the display's preferred WCG format
+ */
+void ADisplay_getPreferredWideColorFormat(ADisplay* display, ADataSpace* outDataspace,
+ AHardwareBuffer_Format* outPixelFormat);
+
+/**
* Gets the current display configuration for the given display.
*
* Memory is *not* allocated for the caller. As such, the returned output
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index dc105c0..73945cf 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -32,7 +32,6 @@
using android::hardware::graphics::mapper::V4_0::BufferDescriptor;
using android::hardware::graphics::mapper::V4_0::Error;
using android::hardware::graphics::mapper::V4_0::IMapper;
-using android::hardware::graphics::mapper::V4_0::YCbCrLayout;
namespace android {
@@ -190,6 +189,16 @@
status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
int acquireFence, void** outData, int32_t* outBytesPerPixel,
int32_t* outBytesPerStride) const {
+ // In Gralloc 4 we can get this info per plane. Clients should check per plane.
+ if (outBytesPerPixel) {
+ // TODO add support to check per plane
+ *outBytesPerPixel = -1;
+ }
+ if (outBytesPerStride) {
+ // TODO add support to check per plane
+ *outBytesPerStride = -1;
+ }
+
auto buffer = const_cast<native_handle_t*>(bufferHandle);
IMapper::Rect accessRegion = sGralloc4Rect(bounds);
@@ -205,19 +214,12 @@
Error error;
auto ret = mMapper->lock(buffer, usage, accessRegion, acquireFenceHandle,
- [&](const auto& tmpError, const auto& tmpData,
- const auto& tmpBytesPerPixel, const auto& tmpBytesPerStride) {
+ [&](const auto& tmpError, const auto& tmpData) {
error = tmpError;
if (error != Error::NONE) {
return;
}
*outData = tmpData;
- if (outBytesPerPixel) {
- *outBytesPerPixel = tmpBytesPerPixel;
- }
- if (outBytesPerStride) {
- *outBytesPerStride = tmpBytesPerStride;
- }
});
// we own acquireFence even on errors
@@ -232,48 +234,11 @@
return static_cast<status_t>(error);
}
-status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
- int acquireFence, android_ycbcr* ycbcr) const {
- auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
- IMapper::Rect accessRegion = sGralloc4Rect(bounds);
-
- // put acquireFence in a hidl_handle
- hardware::hidl_handle acquireFenceHandle;
- NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
- if (acquireFence >= 0) {
- auto h = native_handle_init(acquireFenceStorage, 1, 0);
- h->data[0] = acquireFence;
- acquireFenceHandle = h;
- }
-
- YCbCrLayout layout;
- Error error;
- auto ret = mMapper->lockYCbCr(buffer, usage, accessRegion, acquireFenceHandle,
- [&](const auto& tmpError, const auto& tmpLayout) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- layout = tmpLayout;
- });
-
- if (error == Error::NONE) {
- ycbcr->y = layout.y;
- ycbcr->cb = layout.cb;
- ycbcr->cr = layout.cr;
- ycbcr->ystride = static_cast<size_t>(layout.yStride);
- ycbcr->cstride = static_cast<size_t>(layout.cStride);
- ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
- }
-
- // we own acquireFence even on errors
- if (acquireFence >= 0) {
- close(acquireFence);
- }
-
- return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+status_t Gralloc4Mapper::lock(buffer_handle_t /*bufferHandle*/, uint64_t /*usage*/,
+ const Rect& /*bounds*/, int /*acquireFence*/,
+ android_ycbcr* /*ycbcr*/) const {
+ // TODO add lockYCbCr support
+ return static_cast<status_t>(Error::UNSUPPORTED);
}
int Gralloc4Mapper::unlock(buffer_handle_t bufferHandle) const {
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 3c16070..23c08b2 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -58,7 +58,6 @@
"liblog",
"libui",
"libutils",
- "libhardware_legacy",
],
header_libs: [
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index c8da0ab..264d287 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -37,8 +37,6 @@
#include "EventHub.h"
-#include <hardware_legacy/power.h>
-
#include <android-base/stringprintf.h>
#include <cutils/properties.h>
#include <openssl/sha.h>
@@ -71,7 +69,6 @@
static constexpr bool DEBUG = false;
-static const char* WAKE_LOCK_ID = "KeyEvents";
static const char* DEVICE_PATH = "/dev/input";
// v4l2 devices go directly into /dev
static const char* VIDEO_DEVICE_PATH = "/dev";
@@ -296,7 +293,6 @@
mPendingEventIndex(0),
mPendingINotify(false) {
ensureProcessCanBlockSuspend();
- acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
mEpollFd = epoll_create1(EPOLL_CLOEXEC);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
@@ -354,8 +350,6 @@
::close(mINotifyFd);
::close(mWakeReadPipeFd);
::close(mWakeWritePipeFd);
-
- release_wake_lock(WAKE_LOCK_ID);
}
InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
@@ -1046,26 +1040,24 @@
break;
}
- // Poll for events. Mind the wake lock dance!
- // We hold a wake lock at all times except during epoll_wait(). This works due to some
- // subtle choreography. When a device driver has pending (unread) events, it acquires
- // a kernel wake lock. However, once the last pending event has been read, the device
- // driver will release the kernel wake lock. To prevent the system from going to sleep
- // when this happens, the EventHub holds onto its own user wake lock while the client
- // is processing events. Thus the system can only sleep if there are no events
- // pending or currently being processed.
+ // Poll for events.
+ // When a device driver has pending (unread) events, it acquires
+ // a kernel wake lock. Once the last pending event has been read, the device
+ // driver will release the kernel wake lock, but the epoll will hold the wakelock,
+ // since we are using EPOLLWAKEUP. The wakelock is released by the epoll when epoll_wait
+ // is called again for the same fd that produced the event.
+ // Thus the system can only sleep if there are no events pending or
+ // currently being processed.
//
// The timeout is advisory only. If the device is asleep, it will not wake just to
// service the timeout.
mPendingEventIndex = 0;
- mLock.unlock(); // release lock before poll, must be before release_wake_lock
- release_wake_lock(WAKE_LOCK_ID);
+ mLock.unlock(); // release lock before poll
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
- acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
- mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock
+ mLock.lock(); // reacquire lock after poll
if (pollResult == 0) {
// Timed out.
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 963d755..127a3da 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -167,6 +167,7 @@
"Scheduler/LayerInfo.cpp",
"Scheduler/MessageQueue.cpp",
"Scheduler/PhaseOffsets.cpp",
+ "Scheduler/RefreshRateConfigs.cpp",
"Scheduler/Scheduler.cpp",
"Scheduler/SchedulerUtils.cpp",
"Scheduler/Timer.cpp",
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
new file mode 100644
index 0000000..7dc98cc
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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 "RefreshRateConfigs.h"
+
+namespace android::scheduler {
+using RefreshRate = RefreshRateConfigs::RefreshRate;
+using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+
+// Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access
+// from multiple threads. This can only be called if refreshRateSwitching() returns true.
+// TODO(b/122916473): Get this information from configs prepared by vendors, instead of
+// baking them in.
+const std::map<RefreshRateType, RefreshRate>& RefreshRateConfigs::getRefreshRateMap() const {
+ LOG_ALWAYS_FATAL_IF(!mRefreshRateSwitchingSupported);
+ return mRefreshRateMap;
+}
+
+const RefreshRate& RefreshRateConfigs::getRefreshRateFromType(RefreshRateType type) const {
+ if (!mRefreshRateSwitchingSupported) {
+ return getCurrentRefreshRate().second;
+ } else {
+ auto refreshRate = mRefreshRateMap.find(type);
+ LOG_ALWAYS_FATAL_IF(refreshRate == mRefreshRateMap.end());
+ return refreshRate->second;
+ }
+}
+
+std::pair<RefreshRateType, const RefreshRate&> RefreshRateConfigs::getCurrentRefreshRate() const {
+ int currentConfig = mCurrentConfig;
+ if (mRefreshRateSwitchingSupported) {
+ for (const auto& [type, refresh] : mRefreshRateMap) {
+ if (refresh.configId == currentConfig) {
+ return {type, refresh};
+ }
+ }
+ LOG_ALWAYS_FATAL();
+ }
+ return {RefreshRateType::DEFAULT, mRefreshRates[currentConfig]};
+}
+
+const RefreshRate& RefreshRateConfigs::getRefreshRateFromConfigId(int configId) const {
+ LOG_ALWAYS_FATAL_IF(configId >= mRefreshRates.size());
+ return mRefreshRates[configId];
+}
+
+RefreshRateType RefreshRateConfigs::getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const {
+ if (!mRefreshRateSwitchingSupported) return RefreshRateType::DEFAULT;
+
+ for (const auto& [type, refreshRate] : mRefreshRateMap) {
+ if (refreshRate.hwcId == hwcId) {
+ return type;
+ }
+ }
+
+ return RefreshRateType::DEFAULT;
+}
+
+void RefreshRateConfigs::setCurrentConfig(int config) {
+ LOG_ALWAYS_FATAL_IF(config >= mRefreshRates.size());
+ mCurrentConfig = config;
+}
+
+RefreshRateConfigs::RefreshRateConfigs(bool refreshRateSwitching,
+ const std::vector<InputConfig>& configs, int currentConfig) {
+ init(refreshRateSwitching, configs, currentConfig);
+}
+
+RefreshRateConfigs::RefreshRateConfigs(
+ bool refreshRateSwitching,
+ const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
+ int currentConfig) {
+ std::vector<InputConfig> inputConfigs;
+ for (const auto& config : configs) {
+ inputConfigs.push_back({config->getId(), config->getVsyncPeriod()});
+ }
+ init(refreshRateSwitching, inputConfigs, currentConfig);
+}
+
+void RefreshRateConfigs::init(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
+ int currentConfig) {
+ mRefreshRateSwitchingSupported = refreshRateSwitching;
+ LOG_ALWAYS_FATAL_IF(configs.empty());
+ LOG_ALWAYS_FATAL_IF(currentConfig >= configs.size());
+ mCurrentConfig = currentConfig;
+
+ auto buildRefreshRate = [&](int configId) -> RefreshRate {
+ const nsecs_t vsyncPeriod = configs[configId].vsyncPeriod;
+ const float fps = 1e9 / vsyncPeriod;
+ return {configId, base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps),
+ vsyncPeriod, configs[configId].hwcId};
+ };
+
+ for (int i = 0; i < configs.size(); ++i) {
+ mRefreshRates.push_back(buildRefreshRate(i));
+ }
+
+ if (!mRefreshRateSwitchingSupported) return;
+
+ auto findDefaultAndPerfConfigs = [&]() -> std::optional<std::pair<int, int>> {
+ if (configs.size() < 2) {
+ return {};
+ }
+
+ std::vector<const RefreshRate*> sortedRefreshRates;
+ for (const auto& refreshRate : mRefreshRates) {
+ sortedRefreshRates.push_back(&refreshRate);
+ }
+ std::sort(sortedRefreshRates.begin(), sortedRefreshRates.end(),
+ [](const RefreshRate* refreshRate1, const RefreshRate* refreshRate2) {
+ return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
+ });
+
+ // When the configs are ordered by the resync rate, we assume that
+ // the first one is DEFAULT and the second one is PERFORMANCE,
+ // i.e. the higher rate.
+ if (sortedRefreshRates[0]->vsyncPeriod == 0 || sortedRefreshRates[1]->vsyncPeriod == 0) {
+ return {};
+ }
+
+ return std::pair<int, int>(sortedRefreshRates[0]->configId,
+ sortedRefreshRates[1]->configId);
+ };
+
+ auto defaultAndPerfConfigs = findDefaultAndPerfConfigs();
+ if (!defaultAndPerfConfigs) {
+ mRefreshRateSwitchingSupported = false;
+ return;
+ }
+
+ mRefreshRateMap[RefreshRateType::DEFAULT] = mRefreshRates[defaultAndPerfConfigs->first];
+ mRefreshRateMap[RefreshRateType::PERFORMANCE] = mRefreshRates[defaultAndPerfConfigs->second];
+}
+
+} // namespace android::scheduler
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 2fd100f..90bba24 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -66,55 +66,17 @@
// from multiple threads. This can only be called if refreshRateSwitching() returns true.
// TODO(b/122916473): Get this information from configs prepared by vendors, instead of
// baking them in.
- const std::map<RefreshRateType, RefreshRate>& getRefreshRateMap() const {
- LOG_ALWAYS_FATAL_IF(!mRefreshRateSwitchingSupported);
- return mRefreshRateMap;
- }
+ const std::map<RefreshRateType, RefreshRate>& getRefreshRateMap() const;
- const RefreshRate& getRefreshRateFromType(RefreshRateType type) const {
- if (!mRefreshRateSwitchingSupported) {
- return getCurrentRefreshRate().second;
- } else {
- auto refreshRate = mRefreshRateMap.find(type);
- LOG_ALWAYS_FATAL_IF(refreshRate == mRefreshRateMap.end());
- return refreshRate->second;
- }
- }
+ const RefreshRate& getRefreshRateFromType(RefreshRateType type) const;
- std::pair<RefreshRateType, const RefreshRate&> getCurrentRefreshRate() const {
- int currentConfig = mCurrentConfig;
- if (mRefreshRateSwitchingSupported) {
- for (const auto& [type, refresh] : mRefreshRateMap) {
- if (refresh.configId == currentConfig) {
- return {type, refresh};
- }
- }
- LOG_ALWAYS_FATAL();
- }
- return {RefreshRateType::DEFAULT, mRefreshRates[currentConfig]};
- }
+ std::pair<RefreshRateType, const RefreshRate&> getCurrentRefreshRate() const;
- const RefreshRate& getRefreshRateFromConfigId(int configId) const {
- LOG_ALWAYS_FATAL_IF(configId >= mRefreshRates.size());
- return mRefreshRates[configId];
- }
+ const RefreshRate& getRefreshRateFromConfigId(int configId) const;
- RefreshRateType getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const {
- if (!mRefreshRateSwitchingSupported) return RefreshRateType::DEFAULT;
+ RefreshRateType getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const;
- for (const auto& [type, refreshRate] : mRefreshRateMap) {
- if (refreshRate.hwcId == hwcId) {
- return type;
- }
- }
-
- return RefreshRateType::DEFAULT;
- }
-
- void setCurrentConfig(int config) {
- LOG_ALWAYS_FATAL_IF(config >= mRefreshRates.size());
- mCurrentConfig = config;
- }
+ void setCurrentConfig(int config);
struct InputConfig {
hwc2_config_t hwcId = 0;
@@ -122,78 +84,15 @@
};
RefreshRateConfigs(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
- int currentConfig) {
- init(refreshRateSwitching, configs, currentConfig);
- }
+ int currentConfig);
RefreshRateConfigs(bool refreshRateSwitching,
const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
- int currentConfig) {
- std::vector<InputConfig> inputConfigs;
- for (const auto& config : configs) {
- inputConfigs.push_back({config->getId(), config->getVsyncPeriod()});
- }
- init(refreshRateSwitching, inputConfigs, currentConfig);
- }
+ int currentConfig);
private:
void init(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
- int currentConfig) {
- mRefreshRateSwitchingSupported = refreshRateSwitching;
- LOG_ALWAYS_FATAL_IF(configs.empty());
- LOG_ALWAYS_FATAL_IF(currentConfig >= configs.size());
- mCurrentConfig = currentConfig;
-
- auto buildRefreshRate = [&](int configId) -> RefreshRate {
- const nsecs_t vsyncPeriod = configs[configId].vsyncPeriod;
- const float fps = 1e9 / vsyncPeriod;
- return {configId, base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps),
- vsyncPeriod, configs[configId].hwcId};
- };
-
- for (int i = 0; i < configs.size(); ++i) {
- mRefreshRates.push_back(buildRefreshRate(i));
- }
-
- if (!mRefreshRateSwitchingSupported) return;
-
- auto findDefaultAndPerfConfigs = [&]() -> std::optional<std::pair<int, int>> {
- if (configs.size() < 2) {
- return {};
- }
-
- std::vector<const RefreshRate*> sortedRefreshRates;
- for (const auto& refreshRate : mRefreshRates) {
- sortedRefreshRates.push_back(&refreshRate);
- }
- std::sort(sortedRefreshRates.begin(), sortedRefreshRates.end(),
- [](const RefreshRate* refreshRate1, const RefreshRate* refreshRate2) {
- return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
- });
-
- // When the configs are ordered by the resync rate, we assume that
- // the first one is DEFAULT and the second one is PERFORMANCE,
- // i.e. the higher rate.
- if (sortedRefreshRates[0]->vsyncPeriod == 0 ||
- sortedRefreshRates[1]->vsyncPeriod == 0) {
- return {};
- }
-
- return std::pair<int, int>(sortedRefreshRates[0]->configId,
- sortedRefreshRates[1]->configId);
- };
-
- auto defaultAndPerfConfigs = findDefaultAndPerfConfigs();
- if (!defaultAndPerfConfigs) {
- mRefreshRateSwitchingSupported = false;
- return;
- }
-
- mRefreshRateMap[RefreshRateType::DEFAULT] = mRefreshRates[defaultAndPerfConfigs->first];
- mRefreshRateMap[RefreshRateType::PERFORMANCE] =
- mRefreshRates[defaultAndPerfConfigs->second];
- }
-
+ int currentConfig);
// Whether this device is doing refresh rate switching or not. This must not change after this
// object is initialized.
bool mRefreshRateSwitchingSupported;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c555f79..bf3b4c9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1610,6 +1610,7 @@
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
+ const nsecs_t frameStart = systemTime();
// calculate the expected present time once and use the cached
// value throughout this frame to make sure all layers are
// seeing this same value.
@@ -1674,6 +1675,13 @@
// Signal a refresh if a transaction modified the window state,
// a new buffer was latched, or if HWC has requested a full
// repaint
+ if (mFrameStartTime <= 0) {
+ // We should only use the time of the first invalidate
+ // message that signals a refresh as the beginning of the
+ // frame. Otherwise the real frame time will be
+ // underestimated.
+ mFrameStartTime = frameStart;
+ }
signalRefresh();
}
break;
@@ -1752,6 +1760,9 @@
mGeometryInvalid = false;
mCompositionEngine->present(refreshArgs);
+ mTimeStats->recordFrameDuration(mFrameStartTime, systemTime());
+ // Reset the frame start time now that we've recorded this frame.
+ mFrameStartTime = 0;
postFrame();
postComposition();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 5b1853c..8e1199c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1152,6 +1152,9 @@
bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
Hwc2::impl::PowerAdvisor mPowerAdvisor;
+ // This should only be accessed on the main thread.
+ nsecs_t mFrameStartTime = 0;
+
std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
// Flag used to set override allowed display configs from backdoor
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 611afce..626efb8 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -20,14 +20,13 @@
#include "TimeStats.h"
#include <android-base/stringprintf.h>
-
#include <log/log.h>
-
#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
#include <algorithm>
+#include <chrono>
namespace android {
@@ -113,6 +112,23 @@
mTimeStats.clientCompositionFrames++;
}
+static int32_t msBetween(nsecs_t start, nsecs_t end) {
+ int64_t delta = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::nanoseconds(end - start))
+ .count();
+ delta = std::clamp(delta, int64_t(INT32_MIN), int64_t(INT32_MAX));
+ return static_cast<int32_t>(delta);
+}
+
+void TimeStats::recordFrameDuration(nsecs_t startTime, nsecs_t endTime) {
+ if (!mEnabled.load()) return;
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mPowerTime.powerMode == HWC_POWER_MODE_NORMAL) {
+ mTimeStats.frameDuration.insert(msBetween(startTime, endTime));
+ }
+}
+
bool TimeStats::recordReadyLocked(int32_t layerId, TimeRecord* timeRecord) {
if (!timeRecord->ready) {
ALOGV("[%d]-[%" PRIu64 "]-presentFence is still not received", layerId,
@@ -149,12 +165,6 @@
return true;
}
-static int32_t msBetween(nsecs_t start, nsecs_t end) {
- int64_t delta = (end - start) / 1000000;
- delta = std::clamp(delta, int64_t(INT32_MIN), int64_t(INT32_MAX));
- return static_cast<int32_t>(delta);
-}
-
void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId) {
ATRACE_CALL();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 6e71f5a..670bc8e 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -44,6 +44,13 @@
virtual void incrementMissedFrames() = 0;
virtual void incrementClientCompositionFrames() = 0;
+ // Records the start and end times for a frame.
+ // The start time is the same as the beginning of a SurfaceFlinger
+ // invalidate message.
+ // The end time corresponds to when SurfaceFlinger finishes submitting the
+ // request to HWC to present a frame.
+ virtual void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) = 0;
+
virtual void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
nsecs_t postTime) = 0;
virtual void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) = 0;
@@ -116,6 +123,8 @@
void incrementMissedFrames() override;
void incrementClientCompositionFrames() override;
+ void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override;
+
void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
nsecs_t postTime) override;
void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) override;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 16d2da0..83cd45a 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -111,6 +111,8 @@
StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
StringAppendF(&result, "presentToPresent histogram is as below:\n");
result.append(presentToPresent.toString());
+ StringAppendF(&result, "frameDuration histogram is as below:\n");
+ result.append(frameDuration.toString());
const auto dumpStats = generateDumpStats(maxLayers);
for (const auto& ele : dumpStats) {
result.append(ele->toString());
@@ -158,6 +160,11 @@
histProto->set_time_millis(histEle.first);
histProto->set_frame_count(histEle.second);
}
+ for (const auto& histEle : frameDuration.hist) {
+ SFTimeStatsHistogramBucketProto* histProto = globalProto.add_frame_duration();
+ histProto->set_time_millis(histEle.first);
+ histProto->set_frame_count(histEle.second);
+ }
const auto dumpStats = generateDumpStats(maxLayers);
for (const auto& ele : dumpStats) {
SFTimeStatsLayerProto* layerProto = globalProto.add_stats();
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index f2ac7ff..6b28970 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -61,6 +61,7 @@
int32_t clientCompositionFrames = 0;
int64_t displayOnTime = 0;
Histogram presentToPresent;
+ Histogram frameDuration;
std::unordered_map<std::string, TimeStatsLayer> stats;
std::unordered_map<uint32_t, nsecs_t> refreshRateStats;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
index 0dacbeb..96430b3 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
+++ b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
@@ -25,7 +25,7 @@
// changes to these messages, and keep google3 side proto messages in sync if
// the end to end pipeline needs to be updated.
-// Next tag: 10
+// Next tag: 11
message SFTimeStatsGlobalProto {
// The stats start time in UTC as seconds since January 1, 1970
optional int64 stats_start = 1;
@@ -43,6 +43,8 @@
repeated SFTimeStatsDisplayConfigBucketProto display_config_stats = 9;
// Present to present histogram.
repeated SFTimeStatsHistogramBucketProto present_to_present = 8;
+ // Frame CPU duration histogram.
+ repeated SFTimeStatsHistogramBucketProto frame_duration = 10;
// Stats per layer. Apps could have multiple layers.
repeated SFTimeStatsLayerProto stats = 6;
}
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 51b20cb..049c872 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -260,7 +260,7 @@
prop {
api_name: "color_space_agnostic_dataspace"
type: Long
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.color_space_agnostic_dataspace"
}
@@ -339,7 +339,7 @@
prop {
api_name: "set_display_power_timer_ms"
type: Integer
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.set_display_power_timer_ms"
}
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index d021fc2..6b0737c 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -18,6 +18,7 @@
test_suites: ["device-tests"],
srcs: [
"BufferGenerator.cpp",
+ "CommonTypes_test.cpp",
"Credentials_test.cpp",
"DereferenceSurfaceControl_test.cpp",
"DisplayActiveConfig_test.cpp",
@@ -41,6 +42,8 @@
"libtrace_proto",
],
shared_libs: [
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.composer@2.1",
"libandroid",
"libbinder",
"libcutils",
@@ -53,6 +56,7 @@
"libtimestats_proto",
"libui",
"libutils",
+ "vintf-graphics-common-ndk_platform",
]
}
diff --git a/services/surfaceflinger/tests/CommonTypes_test.cpp b/services/surfaceflinger/tests/CommonTypes_test.cpp
new file mode 100644
index 0000000..a3e16f9
--- /dev/null
+++ b/services/surfaceflinger/tests/CommonTypes_test.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <aidl/android/hardware/graphics/common/BlendMode.h>
+#include <aidl/android/hardware/graphics/common/Dataspace.h>
+
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <android/hardware/graphics/composer/2.1/IComposerClient.h>
+
+using AidlBlendMode = aidl::android::hardware::graphics::common::BlendMode;
+using AidlDataspace = aidl::android::hardware::graphics::common::Dataspace;
+
+using HidlBlendMode = android::hardware::graphics::composer::V2_1::IComposerClient::BlendMode;
+using HidlDataspace = android::hardware::graphics::common::V1_2::Dataspace;
+
+static_assert(static_cast<uint32_t>(AidlBlendMode::INVALID) ==
+ static_cast<uint32_t>(HidlBlendMode::INVALID));
+static_assert(static_cast<uint32_t>(AidlBlendMode::NONE) ==
+ static_cast<uint32_t>(HidlBlendMode::NONE));
+static_assert(static_cast<uint32_t>(AidlBlendMode::PREMULTIPLIED) ==
+ static_cast<uint32_t>(HidlBlendMode::PREMULTIPLIED));
+static_assert(static_cast<uint32_t>(AidlBlendMode::COVERAGE) ==
+ static_cast<uint32_t>(HidlBlendMode::COVERAGE));
+
+static_assert(static_cast<uint32_t>(AidlDataspace::UNKNOWN) ==
+ static_cast<uint32_t>(HidlDataspace::UNKNOWN));
+static_assert(static_cast<uint32_t>(AidlDataspace::ARBITRARY) ==
+ static_cast<uint32_t>(HidlDataspace::ARBITRARY));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_SHIFT) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_SHIFT));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_MASK) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_MASK));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_UNSPECIFIED) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_UNSPECIFIED));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT709) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT709));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT601_625) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT601_625));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT601_625_UNADJUSTED) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT601_625_UNADJUSTED));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT601_525) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT601_525));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT601_525_UNADJUSTED) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT601_525_UNADJUSTED));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT2020) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT2020));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT2020_CONSTANT_LUMINANCE) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT2020_CONSTANT_LUMINANCE));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT470M) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT470M));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_FILM) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_FILM));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_DCI_P3) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_DCI_P3));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_ADOBE_RGB) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_ADOBE_RGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_SHIFT) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_SHIFT));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_MASK) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_MASK));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_UNSPECIFIED) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_UNSPECIFIED));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_SRGB) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_SRGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_SMPTE_170M) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_SMPTE_170M));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_GAMMA2_2) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_GAMMA2_2));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_GAMMA2_6) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_GAMMA2_6));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_GAMMA2_8) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_GAMMA2_8));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_ST2084) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_ST2084));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_HLG) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_HLG));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_SHIFT) ==
+ static_cast<uint32_t>(HidlDataspace::RANGE_SHIFT));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_MASK) ==
+ static_cast<uint32_t>(HidlDataspace::RANGE_MASK));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_UNSPECIFIED) ==
+ static_cast<uint32_t>(HidlDataspace::RANGE_UNSPECIFIED));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_FULL) ==
+ static_cast<uint32_t>(HidlDataspace::RANGE_FULL));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_LIMITED) ==
+ static_cast<uint32_t>(HidlDataspace::RANGE_LIMITED));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_EXTENDED) ==
+ static_cast<uint32_t>(HidlDataspace::RANGE_EXTENDED));
+static_assert(static_cast<uint32_t>(AidlDataspace::V0_SRGB_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SRGB_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::V0_SCRGB_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SCRGB_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::V0_SRGB) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SRGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::V0_SCRGB) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SCRGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::V0_JFIF) ==
+ static_cast<uint32_t>(HidlDataspace::V0_JFIF));
+static_assert(static_cast<uint32_t>(AidlDataspace::V0_BT601_625) ==
+ static_cast<uint32_t>(HidlDataspace::V0_BT601_625));
+static_assert(static_cast<uint32_t>(AidlDataspace::V0_BT601_525) ==
+ static_cast<uint32_t>(HidlDataspace::V0_BT601_525));
+static_assert(static_cast<uint32_t>(AidlDataspace::V0_BT709) ==
+ static_cast<uint32_t>(HidlDataspace::V0_BT709));
+static_assert(static_cast<uint32_t>(AidlDataspace::DCI_P3_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::DCI_P3_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::DCI_P3) ==
+ static_cast<uint32_t>(HidlDataspace::DCI_P3));
+static_assert(static_cast<uint32_t>(AidlDataspace::DISPLAY_P3_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::DISPLAY_P3_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::DISPLAY_P3) ==
+ static_cast<uint32_t>(HidlDataspace::DISPLAY_P3));
+static_assert(static_cast<uint32_t>(AidlDataspace::ADOBE_RGB) ==
+ static_cast<uint32_t>(HidlDataspace::ADOBE_RGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_PQ) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_PQ));
+static_assert(static_cast<uint32_t>(AidlDataspace::DEPTH) ==
+ static_cast<uint32_t>(HidlDataspace::DEPTH));
+static_assert(static_cast<uint32_t>(AidlDataspace::SENSOR) ==
+ static_cast<uint32_t>(HidlDataspace::SENSOR));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_ITU) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_ITU));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_ITU_PQ) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_ITU_PQ));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_ITU_HLG) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_ITU_HLG));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_HLG) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_HLG));
+static_assert(static_cast<uint32_t>(AidlDataspace::DISPLAY_BT2020) ==
+ static_cast<uint32_t>(HidlDataspace::DISPLAY_BT2020));
+static_assert(static_cast<uint32_t>(AidlDataspace::DYNAMIC_DEPTH) ==
+ static_cast<uint32_t>(HidlDataspace::DYNAMIC_DEPTH));
+static_assert(static_cast<uint32_t>(AidlDataspace::JPEG_APP_SEGMENTS) ==
+ static_cast<uint32_t>(HidlDataspace::JPEG_APP_SEGMENTS));
+static_assert(static_cast<uint32_t>(AidlDataspace::HEIF) ==
+ static_cast<uint32_t>(HidlDataspace::HEIF));
+
+// Below are the dataspaces that have been deprecated for sometime. They are required to behave
+// the same as their V0_* counterparts. We redefined them in AIDL to be the same as the
+// their V0_* counterparts.
+static_assert(static_cast<uint32_t>(AidlDataspace::SRGB_LINEAR) ==
+ static_cast<uint32_t>(AidlDataspace::V0_SRGB_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::SRGB) ==
+ static_cast<uint32_t>(AidlDataspace::V0_SRGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::JFIF) ==
+ static_cast<uint32_t>(AidlDataspace::V0_JFIF));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT601_625) ==
+ static_cast<uint32_t>(AidlDataspace::V0_BT601_625));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT601_525) ==
+ static_cast<uint32_t>(AidlDataspace::V0_BT601_525));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT709) ==
+ static_cast<uint32_t>(AidlDataspace::V0_BT709));
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 7b60fa2..069344a 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -20,11 +20,11 @@
#include <TimeStats/TimeStats.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <log/log.h>
#include <utils/String16.h>
#include <utils/Vector.h>
+#include <chrono>
#include <random>
#include <unordered_set>
@@ -278,6 +278,31 @@
EXPECT_EQ(2, histogramProto.time_millis());
}
+TEST_F(TimeStatsTest, canInsertGlobalFrameDuration) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ using namespace std::chrono_literals;
+
+ mTimeStats->setPowerMode(HWC_POWER_MODE_OFF);
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
+ .count());
+ mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+ .count());
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+ ASSERT_EQ(1, globalProto.frame_duration_size());
+ const SFTimeStatsHistogramBucketProto& histogramProto = globalProto.frame_duration().Get(0);
+ EXPECT_EQ(1, histogramProto.frame_count());
+ EXPECT_EQ(3, histogramProto.time_millis());
+}
+
TEST_F(TimeStatsTest, canInsertOneLayerTimeStats) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index b1634a8..e94af49 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -34,6 +34,7 @@
MOCK_METHOD0(incrementTotalFrames, void());
MOCK_METHOD0(incrementMissedFrames, void());
MOCK_METHOD0(incrementClientCompositionFrames, void());
+ MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD4(setPostTime, void(int32_t, uint64_t, const std::string&, nsecs_t));
MOCK_METHOD3(setLatchTime, void(int32_t, uint64_t, nsecs_t));
MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t));