diff options
57 files changed, 4476 insertions, 847 deletions
diff --git a/cmds/installd/view_compiler.cpp b/cmds/installd/view_compiler.cpp index f1ac7178f6..60d6492e70 100644 --- a/cmds/installd/view_compiler.cpp +++ b/cmds/installd/view_compiler.cpp @@ -45,7 +45,7 @@ bool view_compiler(const char* apk_path, const char* package_name, const char* o // and pass file descriptors. // Open input file - unique_fd infd{open(apk_path, 0)}; + unique_fd infd{open(apk_path, O_RDONLY)}; // NOLINT(android-cloexec-open) if (infd.get() < 0) { PLOG(ERROR) << "Could not open input file: " << apk_path; return false; @@ -53,7 +53,7 @@ bool view_compiler(const char* apk_path, const char* package_name, const char* o // Set up output file. viewcompiler can't open outputs by fd, but it can write to stdout, so // we close stdout and open it towards the right output. - unique_fd outfd{open(out_dex_file, O_CREAT | O_TRUNC | O_WRONLY, 0644)}; + unique_fd outfd{open(out_dex_file, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644)}; if (outfd.get() < 0) { PLOG(ERROR) << "Could not open output file: " << out_dex_file; return false; @@ -62,10 +62,6 @@ bool view_compiler(const char* apk_path, const char* package_name, const char* o PLOG(ERROR) << "Could not change output file permissions"; return false; } - if (close(STDOUT_FILENO) != 0) { - PLOG(ERROR) << "Could not close stdout"; - return false; - } if (dup2(outfd, STDOUT_FILENO) < 0) { PLOG(ERROR) << "Could not duplicate output file descriptor"; return false; @@ -96,4 +92,4 @@ bool view_compiler(const char* apk_path, const char* package_name, const char* o } } // namespace installd -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/cmds/installd/view_compiler.h b/cmds/installd/view_compiler.h index f7c6e57722..aa141ca257 100644 --- a/cmds/installd/view_compiler.h +++ b/cmds/installd/view_compiler.h @@ -26,4 +26,4 @@ bool view_compiler(const char* apk_path, const char* package_name, const char* o } // namespace installd } // namespace android -#endif // VIEW_COMPILER_H_
\ No newline at end of file +#endif // VIEW_COMPILER_H_ diff --git a/include/OWNERS b/include/OWNERS index 22be776c2a..db52850fe8 100644 --- a/include/OWNERS +++ b/include/OWNERS @@ -1,8 +1,10 @@ alexeykuzmin@google.com dangittik@google.com +jreck@google.com lajos@google.com mathias@google.com michaelwr@google.com +nona@google.com racarr@google.com romainguy@android.com santoscordon@google.com diff --git a/include/android/font.h b/include/android/font.h new file mode 100644 index 0000000000..7e5a945b63 --- /dev/null +++ b/include/android/font.h @@ -0,0 +1,281 @@ +/* + * 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. + */ + +/** + * @file font.h + * @brief Provides some constants used in system_fonts.h or fonts_matcher.h + * + * Available since API level 29. + */ + +#ifndef ANDROID_FONT_H +#define ANDROID_FONT_H + +#include <stdbool.h> +#include <stddef.h> +#include <sys/cdefs.h> + +/****************************************************************** + * + * IMPORTANT NOTICE: + * + * This file is part of Android's set of stable system headers + * exposed by the Android NDK (Native Development Kit). + * + * Third-party source AND binary code relies on the definitions + * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. + * + * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) + * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS + * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY + * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES + */ + +__BEGIN_DECLS + +#if __ANDROID_API__ >= 29 + +enum { + /** The minimum value fot the font weight value. */ + AFONT_WEIGHT_MIN = 0, + + /** A font weight value for the thin weight. */ + AFONT_WEIGHT_THIN = 100, + + /** A font weight value for the extra-light weight. */ + AFONT_WEIGHT_EXTRA_LIGHT = 200, + + /** A font weight value for the light weight. */ + AFONT_WEIGHT_LIGHT = 300, + + /** A font weight value for the normal weight. */ + AFONT_WEIGHT_NORMAL = 400, + + /** A font weight value for the medium weight. */ + AFONT_WEIGHT_MEDIUM = 500, + + /** A font weight value for the semi-bold weight. */ + AFONT_WEIGHT_SEMI_BOLD = 600, + + /** A font weight value for the bold weight. */ + AFONT_WEIGHT_BOLD = 700, + + /** A font weight value for the extra-bold weight. */ + AFONT_WEIGHT_EXTRA_BOLD = 800, + + /** A font weight value for the black weight. */ + AFONT_WEIGHT_BLACK = 900, + + /** The maximum value for the font weight value. */ + AFONT_WEIGHT_MAX = 1000 +}; + +/** + * AFont provides information of the single font configuration. + */ +struct AFont; + +/** + * Close an AFont. + * + * \param font a font returned by ASystemFontIterator_next or AFontMatchert_match. + * Do nothing if NULL is passed. + */ +void AFont_close(AFont* _Nullable font) __INTRODUCED_IN(29); + +/** + * Return an absolute path to the current font file. + * + * Here is a list of font formats returned by this method: + * <ul> + * <li>OpenType</li> + * <li>OpenType Font Collection</li> + * <li>TrueType</li> + * <li>TrueType Collection</li> + * </ul> + * The file extension could be one of *.otf, *.ttf, *.otc or *.ttc. + * + * The font file returned is guaranteed to be opend with O_RDONLY. + * Note that the returned pointer is valid until AFont_close() is called for the given font. + * + * \param font a font object. Passing NULL is not allowed. + * \return a string of the font file path. + */ +const char* _Nonnull AFont_getFontFilePath(const AFont* _Nonnull font) __INTRODUCED_IN(29); + +/** + * Return a weight value associated with the current font. + * + * The weight values are positive and less than or equal to 1000. + * Here are pairs of the common names and their values. + * <p> + * <table> + * <tr> + * <th align="center">Value</th> + * <th align="center">Name</th> + * <th align="center">NDK Definition</th> + * </tr> + * <tr> + * <td align="center">100</td> + * <td align="center">Thin</td> + * <td align="center">{@link AFONT_WEIGHT_THIN}</td> + * </tr> + * <tr> + * <td align="center">200</td> + * <td align="center">Extra Light (Ultra Light)</td> + * <td align="center">{@link AFONT_WEIGHT_EXTRA_LIGHT}</td> + * </tr> + * <tr> + * <td align="center">300</td> + * <td align="center">Light</td> + * <td align="center">{@link AFONT_WEIGHT_LIGHT}</td> + * </tr> + * <tr> + * <td align="center">400</td> + * <td align="center">Normal (Regular)</td> + * <td align="center">{@link AFONT_WEIGHT_NORMAL}</td> + * </tr> + * <tr> + * <td align="center">500</td> + * <td align="center">Medium</td> + * <td align="center">{@link AFONT_WEIGHT_MEDIUM}</td> + * </tr> + * <tr> + * <td align="center">600</td> + * <td align="center">Semi Bold (Demi Bold)</td> + * <td align="center">{@link AFONT_WEIGHT_SEMI_BOLD}</td> + * </tr> + * <tr> + * <td align="center">700</td> + * <td align="center">Bold</td> + * <td align="center">{@link AFONT_WEIGHT_BOLD}</td> + * </tr> + * <tr> + * <td align="center">800</td> + * <td align="center">Extra Bold (Ultra Bold)</td> + * <td align="center">{@link AFONT_WEIGHT_EXTRA_BOLD}</td> + * </tr> + * <tr> + * <td align="center">900</td> + * <td align="center">Black (Heavy)</td> + * <td align="center">{@link AFONT_WEIGHT_BLACK}</td> + * </tr> + * </table> + * </p> + * Note that the weight value may fall in between above values, e.g. 250 weight. + * + * For more information about font weight, read [OpenType usWeightClass](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass) + * + * \param font a font object. Passing NULL is not allowed. + * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned. + */ +uint16_t AFont_getWeight(const AFont* _Nonnull font) __INTRODUCED_IN(29); + +/** + * Return true if the current font is italic, otherwise returns false. + * + * \param font a font object. Passing NULL is not allowed. + * \return true if italic, otherwise false. + */ +bool AFont_isItalic(const AFont* _Nonnull font) __INTRODUCED_IN(29); + +/** + * Return a IETF BCP47 compliant language tag associated with the current font. + * + * For information about IETF BCP47, read [Locale.forLanguageTag(java.lang.String)](https://developer.android.com/reference/java/util/Locale.html#forLanguageTag(java.lang.String)") + * + * Note that the returned pointer is valid until AFont_close() is called. + * + * \param font a font object. Passing NULL is not allowed. + * \return a IETF BCP47 compliant language tag or nullptr if not available. + */ +const char* _Nullable AFont_getLocale(const AFont* _Nonnull font) __INTRODUCED_IN(29); + +/** + * Return a font collection index value associated with the current font. + * + * In case the target font file is a font collection (e.g. .ttc or .otc), this + * returns a non-negative value as an font offset in the collection. This + * always returns 0 if the target font file is a regular font. + * + * \param font a font object. Passing NULL is not allowed. + * \return a font collection index. + */ +size_t AFont_getCollectionIndex(const AFont* _Nonnull font) __INTRODUCED_IN(29); + +/** + * Return a count of font variation settings associated with the current font + * + * The font variation settings are provided as multiple tag-values pairs. + * + * For example, bold italic font may have following font variation settings: + * 'wght' 700, 'slnt' -12 + * In this case, AFont_getAxisCount returns 2 and AFont_getAxisTag + * and AFont_getAxisValue will return following values. + * \code{.cpp} + * AFont* font = AFontIterator_next(ite); + * + * // Returns the number of axes + * AFont_getAxisCount(font); // Returns 2 + * + * // Returns the tag-value pair for the first axis. + * AFont_getAxisTag(font, 0); // Returns 'wght'(0x77676874) + * AFont_getAxisValue(font, 0); // Returns 700.0 + * + * // Returns the tag-value pair for the second axis. + * AFont_getAxisTag(font, 1); // Returns 'slnt'(0x736c6e74) + * AFont_getAxisValue(font, 1); // Returns -12.0 + * \endcode + * + * For more information about font variation settings, read [Font Variations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/fvar) + * + * \param font a font object. Passing NULL is not allowed. + * \return a number of font variation settings. + */ +size_t AFont_getAxisCount(const AFont* _Nonnull font) __INTRODUCED_IN(29); + + +/** + * Return an OpenType axis tag associated with the current font. + * + * See AFont_getAxisCount for more details. + * + * \param font a font object. Passing NULL is not allowed. + * \param axisIndex an index to the font variation settings. Passing value larger than or + * equal to {@link AFont_getAxisCount} is not allowed. + * \return an OpenType axis tag value for the given font variation setting. + */ +uint32_t AFont_getAxisTag(const AFont* _Nonnull font, uint32_t axisIndex) + __INTRODUCED_IN(29); + +/** + * Return an OpenType axis value associated with the current font. + * + * See AFont_getAxisCount for more details. + * + * \param font a font object. Passing NULL is not allowed. + * \param axisIndex an index to the font variation settings. Passing value larger than or + * equal to {@link ASYstemFont_getAxisCount} is not allwed. + * \return a float value for the given font variation setting. + */ +float AFont_getAxisValue(const AFont* _Nonnull font, uint32_t axisIndex) + __INTRODUCED_IN(29); + +#endif // __ANDROID_API__ >= 29 + +__END_DECLS + +#endif // ANDROID_FONT_H diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h new file mode 100644 index 0000000000..ad5a4da76d --- /dev/null +++ b/include/android/font_matcher.h @@ -0,0 +1,207 @@ +/* + * 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. + */ + +/** + * @file font_matcher.h + * @brief Provides the font matching logic with various inputs. + * + * You can use this class for deciding what font is to be used for drawing text. + * + * A matcher is created from text style, locales and UI compatibility. The match function for + * matcher object can be called multiple times until close function is called. + * + * Even if no font can render the given text, the match function will return a non-null result for + * drawing Tofu character. + * + * Examples: + * \code{.cpp} + * // Simple font query for the ASCII character. + * std::vector<uint16_t> text = { 'A' }; + * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); + * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * // runLength will be 1 and the font will points a valid font file. + * AFontMatcher_destroy(matcher); + * + * // Querying font for CJK characters + * std::vector<uint16_t> text = { 0x9AA8 }; + * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); + * AFontMatcher_setLocales(matcher, "zh-CN,ja-JP"); + * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * // runLength will be 1 and the font will points a Simplified Chinese font. + * AFontMatcher_setLocales(matcher, "ja-JP,zh-CN"); + * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * // runLength will be 1 and the font will points a Japanese font. + * AFontMatcher_destroy(matcher); + * + * // Querying font for text/color emoji + * std::vector<uint16_t> text = { 0xD83D, 0xDC68, 0x200D, 0x2764, 0xFE0F, 0x200D, 0xD83D, 0xDC68 }; + * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); + * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * // runLength will be 8 and the font will points a color emoji font. + * AFontMatcher_destroy(matcher); + * + * // Mixture of multiple script of characters. + * // 0x05D0 is a Hebrew character and 0x0E01 is a Thai character. + * std::vector<uint16_t> text = { 0x05D0, 0x0E01 }; + * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); + * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * // runLength will be 1 and the font will points a Hebrew font. + * AFontMatcher_destroy(matcher); + * \endcode + * + * Available since API level 29. + */ + +#ifndef ANDROID_FONT_MATCHER_H +#define ANDROID_FONT_MATCHER_H + +#include <stdbool.h> +#include <stddef.h> +#include <sys/cdefs.h> + +#include <android/font.h> + +/****************************************************************** + * + * IMPORTANT NOTICE: + * + * This file is part of Android's set of stable system headers + * exposed by the Android NDK (Native Development Kit). + * + * Third-party source AND binary code relies on the definitions + * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. + * + * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) + * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS + * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY + * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES + */ + +__BEGIN_DECLS + +#if __ANDROID_API__ >= 29 + +enum { + /** A family variant value for the system default variant. */ + AFAMILY_VARIANT_DEFAULT = 0, + + /** + * A family variant value for the compact font family variant. + * + * The compact font family has Latin-based vertical metrics. + */ + AFAMILY_VARIANT_COMPACT = 1, + + /** + * A family variant value for the elegant font family variant. + * + * The elegant font family may have larger vertical metrics than Latin font. + */ + AFAMILY_VARIANT_ELEGANT = 2, +}; + +/** + * AFontMatcher performs match operation on given parameters and available font files. + * This matcher is not a thread-safe object. Do not pass this matcher to other threads. + */ +struct AFontMatcher; + +/** + * Select the best font from given parameters. + * + */ + +/** + * Creates a new AFontMatcher object + */ +AFontMatcher* _Nonnull AFontMatcher_create() __INTRODUCED_IN(29); + +/** + * Destroy the matcher object. + * + * \param matcher a matcher object. Passing NULL is not allowed. + */ +void AFontMatcher_destroy(AFontMatcher* _Nonnull matcher) __INTRODUCED_IN(29); + +/** + * Set font style to matcher. + * + * If this function is not called, the matcher performs with {@link ASYSTEM_FONT_WEIGHT_NORMAL} + * with non-italic style. + * + * \param matcher a matcher object. Passing NULL is not allowed. + * \param weight a font weight value. Only from 0 to 1000 value is valid + * \param italic true if italic, otherwise false. + */ +void AFontMatcher_setStyle( + AFontMatcher* _Nonnull matcher, + uint16_t weight, + bool italic) __INTRODUCED_IN(29); + +/** + * Set font locales to matcher. + * + * If this function is not called, the matcher performs with empty locale list. + * + * \param matcher a matcher object. Passing NULL is not allowed. + * \param languageTags a null character terminated comma separated IETF BCP47 compliant language + * tags. + */ +void AFontMatcher_setLocales( + AFontMatcher* _Nonnull matcher, + const char* _Nonnull languageTags) __INTRODUCED_IN(29); + +/** + * Set family variant to matcher. + * + * If this function is not called, the matcher performs with {@link AFAMILY_VARIANT_DEFAULT}. + * + * \param matcher a matcher object. Passing NULL is not allowed. + * \param familyVariant Must be one of {@link AFAMILY_VARIANT_DEFAULT}, + * {@link AFAMILY_VARIANT_COMPACT} or {@link AFAMILY_VARIANT_ELEGANT} is valid. + */ +void AFontMatcher_setFamilyVariant( + AFontMatcher* _Nonnull matcher, + uint32_t familyVariant) __INTRODUCED_IN(29); + +/** + * Performs the matching from the generic font family for the text and select one font. + * + * For more information about generic font families, read [W3C spec](https://www.w3.org/TR/css-fonts-4/#generic-font-families) + * + * Even if no font can render the given text, this function will return a non-null result for + * drawing Tofu character. + * + * \param matcher a matcher object. Passing NULL is not allowed. + * \param familyName a null character terminated font family name + * \param text a UTF-16 encoded text buffer to be rendered. Do not pass empty string. + * \param textLength a length of the given text buffer. This must not be zero. + * \param runLengthOut if not null, the font run length will be filled. + * \return a font to be used for given text and params. You need to release the returned font by + * ASystemFont_close when it is no longer needed. + */ +AFont* _Nonnull AFontMatcher_match( + const AFontMatcher* _Nonnull matcher, + const char* _Nonnull familyName, + const uint16_t* _Nonnull text, + const uint32_t textLength, + uint32_t* _Nullable runLengthOut) __INTRODUCED_IN(29); + +#endif // __ANDROID_API__ >= 29 + +__END_DECLS + +#endif // ANDROID_FONT_MATCHER_H diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h index 38f036e4c0..3facf82617 100644 --- a/include/android/system_fonts.h +++ b/include/android/system_fonts.h @@ -62,6 +62,8 @@ #include <stddef.h> #include <sys/cdefs.h> +#include <android/font.h> + /****************************************************************** * * IMPORTANT NOTICE: @@ -82,41 +84,6 @@ __BEGIN_DECLS #if __ANDROID_API__ >= 29 -enum { - /** The minimum value fot the font weight value. */ - ASYSTEM_FONT_WEIGHT_MIN = 0, - - /** A font weight value for the thin weight. */ - ASYSTEM_FONT_WEIGHT_THIN = 100, - - /** A font weight value for the extra-light weight. */ - ASYSTEM_FONT_WEIGHT_EXTRA_LIGHT = 200, - - /** A font weight value for the light weight. */ - ASYSTEM_FONT_WEIGHT_LIGHT = 300, - - /** A font weight value for the normal weight. */ - ASYSTEM_FONT_WEIGHT_NORMAL = 400, - - /** A font weight value for the medium weight. */ - ASYSTEM_FONT_WEIGHT_MEDIUM = 500, - - /** A font weight value for the semi-bold weight. */ - ASYSTEM_FONT_WEIGHT_SEMI_BOLD = 600, - - /** A font weight value for the bold weight. */ - ASYSTEM_FONT_WEIGHT_BOLD = 700, - - /** A font weight value for the extra-bold weight. */ - ASYSTEM_FONT_WEIGHT_EXTRA_BOLD = 800, - - /** A font weight value for the black weight. */ - ASYSTEM_FONT_WEIGHT_BLACK = 900, - - /** The maximum value for the font weight value. */ - ASYSTEM_FONT_WEIGHT_MAX = 1000 -}; - /** * ASystemFontIterator provides access to the system font configuration. * @@ -126,11 +93,6 @@ enum { struct ASystemFontIterator; /** - * ASystemFont provides information of the single system font configuration. - */ -struct ASystemFont; - -/** * Create a system font iterator. * * Use ASystemFont_close() to close the iterator. @@ -153,254 +115,7 @@ void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTROD * \return a font. If no more font is available, returns nullptr. You need to release the returned * font by ASystemFont_close when it is no longer needed. */ -ASystemFont* _Nullable ASystemFontIterator_next(ASystemFontIterator* _Nonnull iterator) __INTRODUCED_IN(29); - -/** - * Close an ASystemFont returned by ASystemFontIterator_next. - * - * \param font a font returned by ASystemFontIterator_next or ASystemFont_matchFamilyStyleCharacter. - * Do nothing if NULL is passed. - */ -void ASystemFont_close(ASystemFont* _Nullable font) __INTRODUCED_IN(29); - - -/** - * Select the best font from given parameters. - * - * Only generic font families are supported. - * For more information about generic font families, read [W3C spec](https://www.w3.org/TR/css-fonts-4/#generic-font-families) - * - * Even if no font can render the given text, this function will return a non-null result for - * drawing Tofu character. - * - * Examples: - * \code{.cpp} - * // Simple font query for the ASCII character. - * std::vector<uint16_t> text = { 'A' }; - * ASystemFont font = ASystemFont_matchFamilyStyleCharacter( - * "sans", 400, false, "en-US", text.data(), text.length(), &runLength); - * // runLength will be 1 and the font will points a valid font file. - * - * // Querying font for CJK characters - * std::vector<uint16_t> text = { 0x9AA8 }; - * ASystemFont font = ASystemFont_matchFamilyStyleCharacter( - * "sans", 400, false, "zh-CN,ja-JP", text.data(), text.length(), &runLength); - * // runLength will be 1 and the font will points a Simplified Chinese font. - * ASystemFont font = ASystemFont_matchFamilyStyleCharacter( - * "sans", 400, false, "ja-JP,zh-CN", text.data(), text.length(), &runLength); - * // runLength will be 1 and the font will points a Japanese font. - * - * // Querying font for text/color emoji - * std::vector<uint16_t> text = { 0xD83D, 0xDC68, 0x200D, 0x2764, 0xFE0F, 0x200D, 0xD83D, 0xDC68 }; - * ASystemFont font = ASystemFont_matchFamilyStyleCharacter( - * "sans", 400, false, "en-US", text.data(), text.length(), &runLength); - * // runLength will be 8 and the font will points a color emoji font. - * - * // Mixture of multiple script of characters. - * // 0x05D0 is a Hebrew character and 0x0E01 is a Thai character. - * std::vector<uint16_t> text = { 0x05D0, 0x0E01 }; - * ASystemFont font = ASystemFont_matchFamilyStyleCharacter( - * "sans", 400, false, "en-US", text.data(), text.length(), &runLength); - * // runLength will be 1 and the font will points a Hebrew font. - * \endcode - * - * \param familyName a null character terminated font family name - * \param weight a font weight value. Only from 0 to 1000 value is valid - * \param italic true if italic, otherwise false. - * \param languageTags a null character terminated comma separated IETF BCP47 compliant language - * tags. - * \param text a UTF-16 encoded text buffer to be rendered. Do not pass empty string. - * \param textLength a length of the given text buffer. This must not be zero. - * \param runLengthOut if not null, the font run length will be filled. - * \return a font to be used for given text and params. You need to release the returned font by - * ASystemFont_close when it is no longer needed. - */ -ASystemFont* _Nonnull ASystemFont_matchFamilyStyleCharacter( - const char* _Nonnull familyName, - uint16_t weight, - bool italic, - const char* _Nonnull languageTags, - const uint16_t* _Nonnull text, - uint32_t textLength, - uint32_t* _Nullable runLengthOut) __INTRODUCED_IN(29); - -/** - * Return an absolute path to the current font file. - * - * Here is a list of font formats returned by this method: - * <ul> - * <li>OpenType</li> - * <li>OpenType Font Collection</li> - * <li>TrueType</li> - * <li>TrueType Collection</li> - * </ul> - * The file extension could be one of *.otf, *.ttf, *.otc or *.ttc. - * - * The font file returned is guaranteed to be opend with O_RDONLY. - * Note that the returned pointer is valid until ASystemFont_close() is called for the given font. - * - * \param font a font object. Passing NULL is not allowed. - * \return a string of the font file path. - */ -const char* _Nonnull ASystemFont_getFontFilePath(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29); - -/** - * Return a weight value associated with the current font. - * - * The weight values are positive and less than or equal to 1000. - * Here are pairs of the common names and their values. - * <p> - * <table> - * <tr> - * <th align="center">Value</th> - * <th align="center">Name</th> - * <th align="center">NDK Definition</th> - * </tr> - * <tr> - * <td align="center">100</td> - * <td align="center">Thin</td> - * <td align="center">{@link ASYSTEM_FONT_WEIGHT_THIN}</td> - * </tr> - * <tr> - * <td align="center">200</td> - * <td align="center">Extra Light (Ultra Light)</td> - * <td align="center">{@link ASYSTEM_FONT_WEIGHT_EXTRA_LIGHT}</td> - * </tr> - * <tr> - * <td align="center">300</td> - * <td align="center">Light</td> - * <td align="center">{@link ASYSTEM_FONT_WEIGHT_LIGHT}</td> - * </tr> - * <tr> - * <td align="center">400</td> - * <td align="center">Normal (Regular)</td> - * <td align="center">{@link ASYSTEM_FONT_WEIGHT_NORMAL}</td> - * </tr> - * <tr> - * <td align="center">500</td> - * <td align="center">Medium</td> - * <td align="center">{@link ASYSTEM_FONT_WEIGHT_MEDIUM}</td> - * </tr> - * <tr> - * <td align="center">600</td> - * <td align="center">Semi Bold (Demi Bold)</td> - * <td align="center">{@link ASYSTEM_FONT_WEIGHT_SEMI_BOLD}</td> - * </tr> - * <tr> - * <td align="center">700</td> - * <td align="center">Bold</td> - * <td align="center">{@link ASYSTEM_FONT_WEIGHT_BOLD}</td> - * </tr> - * <tr> - * <td align="center">800</td> - * <td align="center">Extra Bold (Ultra Bold)</td> - * <td align="center">{@link ASYSTEM_FONT_WEIGHT_EXTRA_BOLD}</td> - * </tr> - * <tr> - * <td align="center">900</td> - * <td align="center">Black (Heavy)</td> - * <td align="center">{@link ASYSTEM_FONT_WEIGHT_BLACK}</td> - * </tr> - * </table> - * </p> - * Note that the weight value may fall in between above values, e.g. 250 weight. - * - * For more information about font weight, read [OpenType usWeightClass](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass) - * - * \param font a font object. Passing NULL is not allowed. - * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned. - */ -uint16_t ASystemFont_getWeight(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29); - -/** - * Return true if the current font is italic, otherwise returns false. - * - * \param font a font object. Passing NULL is not allowed. - * \return true if italic, otherwise false. - */ -bool ASystemFont_isItalic(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29); - -/** - * Return a IETF BCP47 compliant language tag associated with the current font. - * - * For information about IETF BCP47, read [Locale.forLanguageTag(java.lang.String)](https://developer.android.com/reference/java/util/Locale.html#forLanguageTag(java.lang.String)") - * - * Note that the returned pointer is valid until ASystemFont_close() is called. - * - * \param font a font object. Passing NULL is not allowed. - * \return a IETF BCP47 compliant langauge tag or nullptr if not available. - */ -const char* _Nullable ASystemFont_getLocale(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29); - -/** - * Return a font collection index value associated with the current font. - * - * In case the target font file is a font collection (e.g. .ttc or .otc), this - * returns a non-negative value as an font offset in the collection. This - * always returns 0 if the target font file is a regular font. - * - * \param font a font object. Passing NULL is not allowed. - * \return a font collection index. - */ -size_t ASystemFont_getCollectionIndex(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29); - -/** - * Return a count of font variation settings associated with the current font - * - * The font variation settings are provided as multiple tag-values pairs. - * - * For example, bold italic font may have following font variation settings: - * 'wght' 700, 'slnt' -12 - * In this case, ASystemFont_getAxisCount returns 2 and ASystemFont_getAxisTag - * and ASystemFont_getAxisValue will return following values. - * \code{.cpp} - * ASystemFont* font = ASystemFontIterator_next(ite); - * - * // Returns the number of axes - * ASystemFont_getAxisCount(font); // Returns 2 - * - * // Returns the tag-value pair for the first axis. - * ASystemFont_getAxisTag(font, 0); // Returns 'wght'(0x77676874) - * ASystemFont_getAxisValue(font, 0); // Returns 700.0 - * - * // Returns the tag-value pair for the second axis. - * ASystemFont_getAxisTag(font, 1); // Returns 'slnt'(0x736c6e74) - * ASystemFont_getAxisValue(font, 1); // Returns -12.0 - * \endcode - * - * For more information about font variation settings, read [Font Variations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/fvar) - * - * \param font a font object. Passing NULL is not allowed. - * \return a number of font variation settings. - */ -size_t ASystemFont_getAxisCount(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29); - - -/** - * Return an OpenType axis tag associated with the current font. - * - * See ASystemFont_getAxisCount for more details. - * - * \param font a font object. Passing NULL is not allowed. - * \param axisIndex an index to the font variation settings. Passing value larger than or - * equal to {@link ASystemFont_getAxisCount} is not allowed. - * \return an OpenType axis tag value for the given font variation setting. - */ -uint32_t ASystemFont_getAxisTag(const ASystemFont* _Nonnull font, uint32_t axisIndex) - __INTRODUCED_IN(29); - -/** - * Return an OpenType axis value associated with the current font. - * - * See ASystemFont_getAxisCount for more details. - * - * \param font a font object. Passing NULL is not allowed. - * \param axisIndex an index to the font variation settings. Passing value larger than or - * equal to {@link ASYstemFont_getAxisCount} is not allwed. - * \return a float value for the given font variation setting. - */ -float ASystemFont_getAxisValue(const ASystemFont* _Nonnull font, uint32_t axisIndex) - __INTRODUCED_IN(29); +AFont* _Nullable ASystemFontIterator_next(ASystemFontIterator* _Nonnull iterator) __INTRODUCED_IN(29); #endif // __ANDROID_API__ >= 29 diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index a494e22392..525685c35e 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -93,6 +93,14 @@ int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingP : APP_OPS_MANAGER_UNAVAILABLE_MODE; } +int32_t AppOpsManager::checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid, + const String16& callingPackage) { + sp<IAppOpsService> service = getService(); + return service != nullptr + ? service->checkAudioOperation(op, usage, uid, callingPackage) + : APP_OPS_MANAGER_UNAVAILABLE_MODE; +} + int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) { sp<IAppOpsService> service = getService(); return service != nullptr diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp index f38bbb2f32..a1c2a8be08 100644 --- a/libs/binder/Debug.cpp +++ b/libs/binder/Debug.cpp @@ -221,7 +221,11 @@ void printHexData(int32_t indent, const void *buf, size_t length, for (word = 0; word < bytesPerLine; ) { - const size_t startIndex = word+(alignment-(alignment?1:0)); + size_t align_offset = alignment-(alignment?1:0); + if (remain > 0 && (size_t)remain <= align_offset) { + align_offset = remain - 1; + } + const size_t startIndex = word+align_offset; for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) { diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index fb0d521cac..66d6e31902 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -123,6 +123,22 @@ public: if (reply.readExceptionCode() != 0) return -1; return reply.readInt32(); } + + virtual int32_t checkAudioOperation(int32_t code, int32_t usage, + int32_t uid, const String16& packageName) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + data.writeInt32(code); + data.writeInt32(usage); + data.writeInt32(uid); + data.writeString16(packageName); + remote()->transact(CHECK_AUDIO_OPERATION_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) { + return MODE_ERRORED; + } + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService"); @@ -209,6 +225,17 @@ status_t BnAppOpsService::onTransact( reply->writeInt32(opCode); return NO_ERROR; } break; + case CHECK_AUDIO_OPERATION_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + const int32_t code = data.readInt32(); + const int32_t usage = data.readInt32(); + const int32_t uid = data.readInt32(); + const String16 packageName = data.readString16(); + const int32_t res = checkAudioOperation(code, usage, uid, packageName); + reply->writeNoException(); + reply->writeInt32(res); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp index 6b7729186e..59d51ed94a 100644 --- a/libs/binder/IInterface.cpp +++ b/libs/binder/IInterface.cpp @@ -47,21 +47,3 @@ sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface) // --------------------------------------------------------------------------- }; // namespace android - -extern "C" { - -void _ZN7android10IInterface8asBinderEv(void *retval, void* self) { - ALOGW("deprecated asBinder call, please update your code"); - //ALOGI("self: %p, retval: %p", self, retval); - android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>; - *ret = android::IInterface::asBinder((android::IInterface*)self); -} - -void _ZNK7android10IInterface8asBinderEv(void *retval, void *self) { - ALOGW("deprecated asBinder call, please update your code"); - //ALOGI("self: %p, retval: %p", self, retval); - android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>; - *ret = android::IInterface::asBinder((android::IInterface*)self); -} - -} // extern "C" diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index a595c013ca..5427ff8e4c 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -76,14 +76,6 @@ static size_t pad_size(size_t s) { // Note: must be kept in sync with android/os/StrictMode.java's PENALTY_GATHER #define STRICT_MODE_PENALTY_GATHER (1 << 31) -// XXX This can be made public if we want to provide -// support for typed data. -struct small_flat_data -{ - uint32_t type; - uint32_t data; -}; - namespace android { static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER; diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 79db0cb71e..63f49ddba7 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -214,15 +214,6 @@ bool ProcessState::becomeContextManager(context_check_func checkFunc, void* user // already be invalid. ssize_t ProcessState::getKernelReferences(size_t buf_count, uintptr_t* buf) { - // TODO: remove these when they are defined by bionic's binder.h - struct binder_node_debug_info { - binder_uintptr_t ptr; - binder_uintptr_t cookie; - __u32 has_strong_ref; - __u32 has_weak_ref; - }; -#define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) - binder_node_debug_info info = {}; uintptr_t* end = buf ? buf + buf_count : nullptr; diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h index 7b086d0775..5f324c7965 100644 --- a/libs/binder/include/binder/ActivityManager.h +++ b/libs/binder/include/binder/ActivityManager.h @@ -47,23 +47,24 @@ public: PROCESS_STATE_PERSISTENT_UI = 1, PROCESS_STATE_TOP = 2, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION = 3, - PROCESS_STATE_FOREGROUND_SERVICE = 4, - PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 5, - PROCESS_STATE_IMPORTANT_FOREGROUND = 6, - PROCESS_STATE_IMPORTANT_BACKGROUND = 7, - PROCESS_STATE_TRANSIENT_BACKGROUND = 8, - PROCESS_STATE_BACKUP = 9, - PROCESS_STATE_SERVICE = 10, - PROCESS_STATE_RECEIVER = 11, - PROCESS_STATE_TOP_SLEEPING = 12, - PROCESS_STATE_HEAVY_WEIGHT = 13, - PROCESS_STATE_HOME = 14, - PROCESS_STATE_LAST_ACTIVITY = 15, - PROCESS_STATE_CACHED_ACTIVITY = 16, - PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 17, - PROCESS_STATE_CACHED_RECENT = 18, - PROCESS_STATE_CACHED_EMPTY = 19, - PROCESS_STATE_NONEXISTENT = 20, + PROCESS_STATE_BOUND_TOP = 4, + PROCESS_STATE_FOREGROUND_SERVICE = 5, + PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 6, + PROCESS_STATE_IMPORTANT_FOREGROUND = 7, + PROCESS_STATE_IMPORTANT_BACKGROUND = 8, + PROCESS_STATE_TRANSIENT_BACKGROUND = 9, + PROCESS_STATE_BACKUP = 10, + PROCESS_STATE_SERVICE = 11, + PROCESS_STATE_RECEIVER = 12, + PROCESS_STATE_TOP_SLEEPING = 13, + PROCESS_STATE_HEAVY_WEIGHT = 14, + PROCESS_STATE_HOME = 15, + PROCESS_STATE_LAST_ACTIVITY = 16, + PROCESS_STATE_CACHED_ACTIVITY = 17, + PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 18, + PROCESS_STATE_CACHED_RECENT = 19, + PROCESS_STATE_CACHED_EMPTY = 20, + PROCESS_STATE_NONEXISTENT = 21, }; ActivityManager(); diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index 37237dfd48..17493b4252 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -114,6 +114,8 @@ public: AppOpsManager(); int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage); + int32_t checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid, + const String16& callingPackage); int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage); int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, bool startIfModeDefault); diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index 78078513ff..3dbd0d9f7a 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -43,6 +43,8 @@ public: virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0; virtual sp<IBinder> getToken(const sp<IBinder>& clientToken) = 0; virtual int32_t permissionToOpCode(const String16& permission) = 0; + virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid, + const String16& packageName) = 0; enum { CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, @@ -53,6 +55,7 @@ public: STOP_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+5, GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6, PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7, + CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8, }; enum { diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 4c2e6532ff..fcbfba98af 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -83,8 +83,10 @@ cc_library_shared { "SyncFeatures.cpp", "view/Surface.cpp", "bufferqueue/1.0/B2HProducerListener.cpp", + "bufferqueue/1.0/Conversion.cpp", "bufferqueue/1.0/H2BGraphicBufferProducer.cpp", "bufferqueue/1.0/H2BProducerListener.cpp", + "bufferqueue/1.0/WProducerListener.cpp", "bufferqueue/2.0/B2HGraphicBufferProducer.cpp", "bufferqueue/2.0/B2HProducerListener.cpp", "bufferqueue/2.0/H2BGraphicBufferProducer.cpp", diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index f2d5c8edd8..776c6e6c11 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -58,7 +58,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, int numDroppedBuffers = 0; sp<IProducerListener> listener; { - Mutex::Autolock lock(mCore->mMutex); + std::unique_lock<std::mutex> lock(mCore->mMutex); // Check that the consumer doesn't currently have the maximum number of // buffers acquired. We allow the max buffer count to be exceeded by one @@ -203,7 +203,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, if (sharedBufferAvailable && mCore->mQueue.empty()) { // make sure the buffer has finished allocating before acquiring it - mCore->waitWhileAllocatingLocked(); + mCore->waitWhileAllocatingLocked(lock); slot = mCore->mSharedBufferSlot; @@ -264,7 +264,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, // We might have freed a slot while dropping old buffers, or the producer // may be blocked waiting for the number of buffers in the queue to // decrease. - mCore->mDequeueCondition.broadcast(); + mCore->mDequeueCondition.notify_all(); ATRACE_INT(mCore->mConsumerName.string(), static_cast<int32_t>(mCore->mQueue.size())); @@ -286,7 +286,7 @@ status_t BufferQueueConsumer::detachBuffer(int slot) { ATRACE_CALL(); ATRACE_BUFFER_INDEX(slot); BQ_LOGV("detachBuffer: slot %d", slot); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("detachBuffer: BufferQueue has been abandoned"); @@ -312,7 +312,7 @@ status_t BufferQueueConsumer::detachBuffer(int slot) { mCore->mActiveBuffers.erase(slot); mCore->mFreeSlots.insert(slot); mCore->clearBufferSlotLocked(slot); - mCore->mDequeueCondition.broadcast(); + mCore->mDequeueCondition.notify_all(); VALIDATE_CONSISTENCY(); return NO_ERROR; @@ -330,7 +330,7 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, return BAD_VALUE; } - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (mCore->mSharedBufferMode) { BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode"); @@ -422,7 +422,7 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, sp<IProducerListener> listener; { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); // If the frame number has changed because the buffer has been reallocated, // we can ignore this releaseBuffer for the old buffer. @@ -461,7 +461,7 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, listener = mCore->mConnectedProducerListener; BQ_LOGV("releaseBuffer: releasing slot %d", slot); - mCore->mDequeueCondition.broadcast(); + mCore->mDequeueCondition.notify_all(); VALIDATE_CONSISTENCY(); } // Autolock scope @@ -485,7 +485,7 @@ status_t BufferQueueConsumer::connect( BQ_LOGV("connect: controlledByApp=%s", controlledByApp ? "true" : "false"); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("connect: BufferQueue has been abandoned"); @@ -503,7 +503,7 @@ status_t BufferQueueConsumer::disconnect() { BQ_LOGV("disconnect"); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (mCore->mConsumerListener == nullptr) { BQ_LOGE("disconnect: no consumer is connected"); @@ -515,7 +515,7 @@ status_t BufferQueueConsumer::disconnect() { mCore->mQueue.clear(); mCore->freeAllBuffersLocked(); mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; - mCore->mDequeueCondition.broadcast(); + mCore->mDequeueCondition.notify_all(); return NO_ERROR; } @@ -527,7 +527,7 @@ status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { return BAD_VALUE; } - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("getReleasedBuffers: BufferQueue has been abandoned"); @@ -569,7 +569,7 @@ status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width, BQ_LOGV("setDefaultBufferSize: width=%u height=%u", width, height); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mCore->mDefaultWidth = width; mCore->mDefaultHeight = height; return NO_ERROR; @@ -583,7 +583,7 @@ status_t BufferQueueConsumer::setMaxBufferCount(int bufferCount) { return BAD_VALUE; } - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("setMaxBufferCount: producer is already connected"); @@ -623,8 +623,8 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( sp<IConsumerListener> listener; { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); + std::unique_lock<std::mutex> lock(mCore->mMutex); + mCore->waitWhileAllocatingLocked(lock); if (mCore->mIsAbandoned) { BQ_LOGE("setMaxAcquiredBufferCount: consumer is abandoned"); @@ -684,7 +684,7 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( status_t BufferQueueConsumer::setConsumerName(const String8& name) { ATRACE_CALL(); BQ_LOGV("setConsumerName: '%s'", name.string()); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mCore->mConsumerName = name; mConsumerName = name; return NO_ERROR; @@ -693,7 +693,7 @@ status_t BufferQueueConsumer::setConsumerName(const String8& name) { status_t BufferQueueConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) { ATRACE_CALL(); BQ_LOGV("setDefaultBufferFormat: %u", defaultFormat); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mCore->mDefaultBufferFormat = defaultFormat; return NO_ERROR; } @@ -702,7 +702,7 @@ status_t BufferQueueConsumer::setDefaultBufferDataSpace( android_dataspace defaultDataSpace) { ATRACE_CALL(); BQ_LOGV("setDefaultBufferDataSpace: %u", defaultDataSpace); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mCore->mDefaultBufferDataSpace = defaultDataSpace; return NO_ERROR; } @@ -710,7 +710,7 @@ status_t BufferQueueConsumer::setDefaultBufferDataSpace( status_t BufferQueueConsumer::setConsumerUsageBits(uint64_t usage) { ATRACE_CALL(); BQ_LOGV("setConsumerUsageBits: %#" PRIx64, usage); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mCore->mConsumerUsageBits = usage; return NO_ERROR; } @@ -718,7 +718,7 @@ status_t BufferQueueConsumer::setConsumerUsageBits(uint64_t usage) { status_t BufferQueueConsumer::setConsumerIsProtected(bool isProtected) { ATRACE_CALL(); BQ_LOGV("setConsumerIsProtected: %s", isProtected ? "true" : "false"); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mCore->mConsumerIsProtected = isProtected; return NO_ERROR; } @@ -726,26 +726,26 @@ status_t BufferQueueConsumer::setConsumerIsProtected(bool isProtected) { status_t BufferQueueConsumer::setTransformHint(uint32_t hint) { ATRACE_CALL(); BQ_LOGV("setTransformHint: %#x", hint); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mCore->mTransformHint = hint; return NO_ERROR; } status_t BufferQueueConsumer::getSidebandStream(sp<NativeHandle>* outStream) const { - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); *outStream = mCore->mSidebandStream; return NO_ERROR; } status_t BufferQueueConsumer::getOccupancyHistory(bool forceFlush, std::vector<OccupancyTracker::Segment>* outHistory) { - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); *outHistory = mCore->mOccupancyTracker.getSegmentHistory(forceFlush); return NO_ERROR; } status_t BufferQueueConsumer::discardFreeBuffers() { - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mCore->discardFreeBuffersLocked(); return NO_ERROR; } diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 960b1948c2..96c55acdb0 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -110,7 +110,7 @@ BufferQueueCore::BufferQueueCore() : BufferQueueCore::~BufferQueueCore() {} void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const { - Mutex::Autolock lock(mMutex); + std::lock_guard<std::mutex> lock(mMutex); outResult->appendFormat("%s- BufferQueue ", prefix.string()); outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n", @@ -306,10 +306,10 @@ bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) { return true; } -void BufferQueueCore::waitWhileAllocatingLocked() const { +void BufferQueueCore::waitWhileAllocatingLocked(std::unique_lock<std::mutex>& lock) const { ATRACE_CALL(); while (mIsAllocating) { - mIsAllocatingCondition.wait(mMutex); + mIsAllocatingCondition.wait(lock); } } diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index e657488969..72ae3758c8 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -59,14 +59,15 @@ BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core, mNextCallbackTicket(0), mCurrentCallbackTicket(0), mCallbackCondition(), - mDequeueTimeout(-1) {} + mDequeueTimeout(-1), + mDequeueWaitingForAllocation(false) {} BufferQueueProducer::~BufferQueueProducer() {} status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { ATRACE_CALL(); BQ_LOGV("requestBuffer: slot %d", slot); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("requestBuffer: BufferQueue has been abandoned"); @@ -101,8 +102,8 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount( sp<IConsumerListener> listener; { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); + std::unique_lock<std::mutex> lock(mCore->mMutex); + mCore->waitWhileAllocatingLocked(lock); if (mCore->mIsAbandoned) { BQ_LOGE("setMaxDequeuedBufferCount: BufferQueue has been " @@ -163,7 +164,7 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount( if (delta < 0) { listener = mCore->mConsumerListener; } - mCore->mDequeueCondition.broadcast(); + mCore->mDequeueCondition.notify_all(); } // Autolock scope // Call back without lock held @@ -180,8 +181,8 @@ status_t BufferQueueProducer::setAsyncMode(bool async) { sp<IConsumerListener> listener; { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); + std::unique_lock<std::mutex> lock(mCore->mMutex); + mCore->waitWhileAllocatingLocked(lock); if (mCore->mIsAbandoned) { BQ_LOGE("setAsyncMode: BufferQueue has been abandoned"); @@ -215,7 +216,7 @@ status_t BufferQueueProducer::setAsyncMode(bool async) { } mCore->mAsyncMode = async; VALIDATE_CONSISTENCY(); - mCore->mDequeueCondition.broadcast(); + mCore->mDequeueCondition.notify_all(); if (delta < 0) { listener = mCore->mConsumerListener; } @@ -247,7 +248,7 @@ int BufferQueueProducer::getFreeSlotLocked() const { } status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, - int* found) const { + std::unique_lock<std::mutex>& lock, int* found) const { auto callerString = (caller == FreeSlotCaller::Dequeue) ? "dequeueBuffer" : "attachBuffer"; bool tryAgain = true; @@ -334,13 +335,13 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, return WOULD_BLOCK; } if (mDequeueTimeout >= 0) { - status_t result = mCore->mDequeueCondition.waitRelative( - mCore->mMutex, mDequeueTimeout); - if (result == TIMED_OUT) { - return result; + std::cv_status result = mCore->mDequeueCondition.wait_for(lock, + std::chrono::nanoseconds(mDequeueTimeout)); + if (result == std::cv_status::timeout) { + return TIMED_OUT; } } else { - mCore->mDequeueCondition.wait(mCore->mMutex); + mCore->mDequeueCondition.wait(lock); } } } // while (tryAgain) @@ -354,7 +355,7 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou FrameEventHistoryDelta* outTimestamps) { ATRACE_CALL(); { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mConsumerName = mCore->mConsumerName; if (mCore->mIsAbandoned) { @@ -381,7 +382,16 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou bool attachedByConsumer = false; { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); + std::unique_lock<std::mutex> lock(mCore->mMutex); + + // If we don't have a free buffer, but we are currently allocating, we wait until allocation + // is finished such that we don't allocate in parallel. + if (mCore->mFreeBuffers.empty() && mCore->mIsAllocating) { + mDequeueWaitingForAllocation = true; + mCore->waitWhileAllocatingLocked(lock); + mDequeueWaitingForAllocation = false; + mDequeueWaitingForAllocationCondition.notify_all(); + } if (format == 0) { format = mCore->mDefaultBufferFormat; @@ -398,8 +408,7 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou int found = BufferItem::INVALID_BUFFER_SLOT; while (found == BufferItem::INVALID_BUFFER_SLOT) { - status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, - &found); + status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found); if (status != NO_ERROR) { return status; } @@ -506,7 +515,7 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou status_t error = graphicBuffer->initCheck(); { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (error == NO_ERROR && !mCore->mIsAbandoned) { graphicBuffer->setGenerationNumber(mCore->mGenerationNumber); @@ -514,7 +523,7 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou } mCore->mIsAllocating = false; - mCore->mIsAllocatingCondition.broadcast(); + mCore->mIsAllocatingCondition.notify_all(); if (error != NO_ERROR) { mCore->mFreeSlots.insert(*outSlot); @@ -580,7 +589,7 @@ status_t BufferQueueProducer::detachBuffer(int slot) { sp<IConsumerListener> listener; { - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("detachBuffer: BufferQueue has been abandoned"); @@ -615,7 +624,7 @@ status_t BufferQueueProducer::detachBuffer(int slot) { mCore->mActiveBuffers.erase(slot); mCore->mFreeSlots.insert(slot); mCore->clearBufferSlotLocked(slot); - mCore->mDequeueCondition.broadcast(); + mCore->mDequeueCondition.notify_all(); VALIDATE_CONSISTENCY(); listener = mCore->mConsumerListener; } @@ -641,7 +650,7 @@ status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<IConsumerListener> listener; { - Mutex::Autolock lock(mCore->mMutex); + std::unique_lock<std::mutex> lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned"); @@ -659,7 +668,7 @@ status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer, return BAD_VALUE; } - mCore->waitWhileAllocatingLocked(); + mCore->waitWhileAllocatingLocked(lock); if (mCore->mFreeBuffers.empty()) { return NO_MEMORY; @@ -697,7 +706,7 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, return BAD_VALUE; } - Mutex::Autolock lock(mCore->mMutex); + std::unique_lock<std::mutex> lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("attachBuffer: BufferQueue has been abandoned"); @@ -721,11 +730,11 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, return BAD_VALUE; } - mCore->waitWhileAllocatingLocked(); + mCore->waitWhileAllocatingLocked(lock); status_t returnFlags = NO_ERROR; int found; - status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Attach, &found); + status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Attach, lock, &found); if (status != NO_ERROR) { return status; } @@ -798,7 +807,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, uint64_t currentFrameNumber = 0; BufferItem item; { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("queueBuffer: BufferQueue has been abandoned"); @@ -939,7 +948,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, } mCore->mBufferHasBeenQueued = true; - mCore->mDequeueCondition.broadcast(); + mCore->mDequeueCondition.notify_all(); mCore->mLastQueuedSlot = slot; output->width = mCore->mDefaultWidth; @@ -975,9 +984,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, sp<Fence> lastQueuedFence; { // scope for the lock - Mutex::Autolock lock(mCallbackMutex); + std::unique_lock<std::mutex> lock(mCallbackMutex); while (callbackTicket != mCurrentCallbackTicket) { - mCallbackCondition.wait(mCallbackMutex); + mCallbackCondition.wait(lock); } if (frameAvailableListener != nullptr) { @@ -994,7 +1003,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, mLastQueuedTransform = item.mTransform; ++mCurrentCallbackTicket; - mCallbackCondition.broadcast(); + mCallbackCondition.notify_all(); } // Wait without lock held @@ -1022,7 +1031,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { ATRACE_CALL(); BQ_LOGV("cancelBuffer: slot %d", slot); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("cancelBuffer: BufferQueue has been abandoned"); @@ -1067,7 +1076,7 @@ status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { } mSlots[slot].mFence = fence; - mCore->mDequeueCondition.broadcast(); + mCore->mDequeueCondition.notify_all(); VALIDATE_CONSISTENCY(); return NO_ERROR; @@ -1075,7 +1084,7 @@ status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { int BufferQueueProducer::query(int what, int *outValue) { ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (outValue == nullptr) { BQ_LOGE("query: outValue was NULL"); @@ -1143,7 +1152,7 @@ int BufferQueueProducer::query(int what, int *outValue) { status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, int api, bool producerControlledByApp, QueueBufferOutput *output) { ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mConsumerName = mCore->mConsumerName; BQ_LOGV("connect: api=%d producerControlledByApp=%s", api, producerControlledByApp ? "true" : "false"); @@ -1238,7 +1247,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { int status = NO_ERROR; sp<IConsumerListener> listener; { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); + std::unique_lock<std::mutex> lock(mCore->mMutex); if (mode == DisconnectMode::AllLocal) { if (BufferQueueThreadState::getCallingPid() != mCore->mConnectedPid) { @@ -1247,7 +1256,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { api = BufferQueueCore::CURRENTLY_CONNECTED_API; } - mCore->waitWhileAllocatingLocked(); + mCore->waitWhileAllocatingLocked(lock); if (mCore->mIsAbandoned) { // It's not really an error to disconnect after the surface has @@ -1291,7 +1300,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API; mCore->mConnectedPid = -1; mCore->mSidebandStream.clear(); - mCore->mDequeueCondition.broadcast(); + mCore->mDequeueCondition.notify_all(); listener = mCore->mConsumerListener; } else if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("disconnect: not connected (req=%d)", api); @@ -1321,7 +1330,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) { sp<IConsumerListener> listener; { // Autolock scope - Mutex::Autolock _l(mCore->mMutex); + std::lock_guard<std::mutex> _l(mCore->mMutex); mCore->mSidebandStream = stream; listener = mCore->mConsumerListener; } // Autolock scope @@ -1343,8 +1352,8 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, uint64_t allocUsage = 0; std::string allocName; { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); + std::unique_lock<std::mutex> lock(mCore->mMutex); + mCore->waitWhileAllocatingLocked(lock); if (!mCore->mAllowAllocation) { BQ_LOGE("allocateBuffers: allocation is not allowed for this " @@ -1379,16 +1388,16 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, if (result != NO_ERROR) { BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format" " %u, usage %#" PRIx64 ")", width, height, format, usage); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mCore->mIsAllocating = false; - mCore->mIsAllocatingCondition.broadcast(); + mCore->mIsAllocatingCondition.notify_all(); return; } buffers.push_back(graphicBuffer); } { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); + std::unique_lock<std::mutex> lock(mCore->mMutex); uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth; uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight; PixelFormat checkFormat = format != 0 ? @@ -1399,7 +1408,7 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, // Something changed while we released the lock. Retry. BQ_LOGV("allocateBuffers: size/format/usage changed while allocating. Retrying."); mCore->mIsAllocating = false; - mCore->mIsAllocatingCondition.broadcast(); + mCore->mIsAllocatingCondition.notify_all(); continue; } @@ -1434,8 +1443,14 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, } mCore->mIsAllocating = false; - mCore->mIsAllocatingCondition.broadcast(); + mCore->mIsAllocatingCondition.notify_all(); VALIDATE_CONSISTENCY(); + + // If dequeue is waiting for to allocate a buffer, release the lock until it's not + // waiting anymore so it can use the buffer we just allocated. + while (mDequeueWaitingForAllocation) { + mDequeueWaitingForAllocationCondition.wait(lock); + } } // Autolock scope } } @@ -1444,7 +1459,7 @@ status_t BufferQueueProducer::allowAllocation(bool allow) { ATRACE_CALL(); BQ_LOGV("allowAllocation: %s", allow ? "true" : "false"); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mCore->mAllowAllocation = allow; return NO_ERROR; } @@ -1453,14 +1468,14 @@ status_t BufferQueueProducer::setGenerationNumber(uint32_t generationNumber) { ATRACE_CALL(); BQ_LOGV("setGenerationNumber: %u", generationNumber); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mCore->mGenerationNumber = generationNumber; return NO_ERROR; } String8 BufferQueueProducer::getConsumerName() const { ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); BQ_LOGV("getConsumerName: %s", mConsumerName.string()); return mConsumerName; } @@ -1469,7 +1484,7 @@ status_t BufferQueueProducer::setSharedBufferMode(bool sharedBufferMode) { ATRACE_CALL(); BQ_LOGV("setSharedBufferMode: %d", sharedBufferMode); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (!sharedBufferMode) { mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; } @@ -1481,7 +1496,7 @@ status_t BufferQueueProducer::setAutoRefresh(bool autoRefresh) { ATRACE_CALL(); BQ_LOGV("setAutoRefresh: %d", autoRefresh); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); mCore->mAutoRefresh = autoRefresh; return NO_ERROR; @@ -1491,7 +1506,7 @@ status_t BufferQueueProducer::setDequeueTimeout(nsecs_t timeout) { ATRACE_CALL(); BQ_LOGV("setDequeueTimeout: %" PRId64, timeout); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, false, mCore->mMaxBufferCount) - mCore->getMaxBufferCountLocked(); if (!mCore->adjustAvailableSlotsLocked(delta)) { @@ -1512,7 +1527,7 @@ status_t BufferQueueProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, ATRACE_CALL(); BQ_LOGV("getLastQueuedBuffer"); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); if (mCore->mLastQueuedSlot == BufferItem::INVALID_BUFFER_SLOT) { *outBuffer = nullptr; *outFence = Fence::NO_FENCE; @@ -1548,7 +1563,7 @@ void BufferQueueProducer::addAndGetFrameTimestamps( BQ_LOGV("addAndGetFrameTimestamps"); sp<IConsumerListener> listener; { - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); listener = mCore->mConsumerListener; } if (listener != nullptr) { @@ -1575,7 +1590,7 @@ status_t BufferQueueProducer::getUniqueId(uint64_t* outId) const { status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const { BQ_LOGV("getConsumerUsage"); - Mutex::Autolock lock(mCore->mMutex); + std::lock_guard<std::mutex> lock(mCore->mMutex); *outUsage = mCore->mConsumerUsageBits; return NO_ERROR; } diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 14eca43918..bf44121677 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -360,7 +360,7 @@ public: data.writeUint32(height); data.writeInt32(static_cast<int32_t>(format)); data.writeUint64(usage); - status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply, TF_ONE_WAY); + status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply, IBinder::FLAG_ONEWAY); if (result != NO_ERROR) { ALOGE("allocateBuffers failed to transact: %d", result); } diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index b74d675e4d..b586bf3989 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -551,8 +551,8 @@ public: ALOGE("enableVSyncInjections failed to writeBool: %d", result); return result; } - result = remote()->transact(BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS, - data, &reply, TF_ONE_WAY); + result = remote()->transact(BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS, data, &reply, + IBinder::FLAG_ONEWAY); if (result != NO_ERROR) { ALOGE("enableVSyncInjections failed to transact: %d", result); return result; @@ -572,7 +572,8 @@ public: ALOGE("injectVSync failed to writeInt64: %d", result); return result; } - result = remote()->transact(BnSurfaceComposer::INJECT_VSYNC, data, &reply, TF_ONE_WAY); + result = remote()->transact(BnSurfaceComposer::INJECT_VSYNC, data, &reply, + IBinder::FLAG_ONEWAY); if (result != NO_ERROR) { ALOGE("injectVSync failed to transact: %d", result); return result; diff --git a/libs/gui/bufferqueue/1.0/Conversion.cpp b/libs/gui/bufferqueue/1.0/Conversion.cpp new file mode 100644 index 0000000000..5cb35933e9 --- /dev/null +++ b/libs/gui/bufferqueue/1.0/Conversion.cpp @@ -0,0 +1,1542 @@ +/* + * Copyright 2018, 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 <gui/bufferqueue/1.0/Conversion.h> + +namespace android { +namespace conversion { + +// native_handle_t helper functions. + +/** + * \brief Take an fd and create a native handle containing only the given fd. + * The created handle will need to be deleted manually with + * `native_handle_delete()`. + * + * \param[in] fd The source file descriptor (of type `int`). + * \return The create `native_handle_t*` that contains the given \p fd. If the + * supplied \p fd is negative, the created native handle will contain no file + * descriptors. + * + * If the native handle cannot be created, the return value will be + * `nullptr`. + * + * This function does not duplicate the file descriptor. + */ +native_handle_t* native_handle_create_from_fd(int fd) { + if (fd < 2) { + return native_handle_create(0, 0); + } + native_handle_t* nh = native_handle_create(1, 0); + if (nh == nullptr) { + return nullptr; + } + nh->data[0] = fd; + return nh; +} + +/** + * \brief Extract a file descriptor from a native handle. + * + * \param[in] nh The source `native_handle_t*`. + * \param[in] index The index of the file descriptor in \p nh to read from. This + * input has the default value of `0`. + * \return The `index`-th file descriptor in \p nh. If \p nh does not have + * enough file descriptors, the returned value will be `-1`. + * + * This function does not duplicate the file descriptor. + */ +int native_handle_read_fd(native_handle_t const* nh, int index) { + return ((nh == nullptr) || (nh->numFds == 0) || + (nh->numFds <= index) || (index < 0)) ? + -1 : nh->data[index]; +} + +/** + * Conversion functions + * ==================== + * + * There are two main directions of conversion: + * - `inTargetType(...)`: Create a wrapper whose lifetime depends on the + * input. The wrapper has type `TargetType`. + * - `toTargetType(...)`: Create a standalone object of type `TargetType` that + * corresponds to the input. The lifetime of the output does not depend on the + * lifetime of the input. + * - `wrapIn(TargetType*, ...)`: Same as `inTargetType()`, but for `TargetType` + * that cannot be copied and/or moved efficiently, or when there are multiple + * output arguments. + * - `convertTo(TargetType*, ...)`: Same as `toTargetType()`, but for + * `TargetType` that cannot be copied and/or moved efficiently, or when there + * are multiple output arguments. + * + * `wrapIn()` and `convertTo()` functions will take output arguments before + * input arguments. Some of these functions might return a value to indicate + * success or error. + * + * In converting or wrapping something as a Treble type that contains a + * `hidl_handle`, `native_handle_t*` will need to be created and returned as + * an additional output argument, hence only `wrapIn()` or `convertTo()` would + * be available. The caller must call `native_handle_delete()` to deallocate the + * returned native handle when it is no longer needed. + * + * For types that contain file descriptors, `inTargetType()` and `wrapAs()` do + * not perform duplication of file descriptors, while `toTargetType()` and + * `convertTo()` do. + */ + +/** + * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls. + * + * \param[in] t The source `Return<void>`. + * \return The corresponding `status_t`. + */ +// convert: Return<void> -> status_t +status_t toStatusT(Return<void> const& t) { + return t.isOk() ? OK : (t.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR); +} + +/** + * \brief Convert `Return<void>` to `binder::Status`. + * + * \param[in] t The source `Return<void>`. + * \return The corresponding `binder::Status`. + */ +// convert: Return<void> -> ::android::binder::Status +::android::binder::Status toBinderStatus( + Return<void> const& t) { + return ::android::binder::Status::fromExceptionCode( + toStatusT(t), + t.description().c_str()); +} + +/** + * \brief Wrap `native_handle_t*` in `hidl_handle`. + * + * \param[in] nh The source `native_handle_t*`. + * \return The `hidl_handle` that points to \p nh. + */ +// wrap: native_handle_t* -> hidl_handle +hidl_handle inHidlHandle(native_handle_t const* nh) { + return hidl_handle(nh); +} + +/** + * \brief Convert `int32_t` to `Dataspace`. + * + * \param[in] l The source `int32_t`. + * \result The corresponding `Dataspace`. + */ +// convert: int32_t -> Dataspace +Dataspace toHardwareDataspace(int32_t l) { + return static_cast<Dataspace>(l); +} + +/** + * \brief Convert `Dataspace` to `int32_t`. + * + * \param[in] t The source `Dataspace`. + * \result The corresponding `int32_t`. + */ +// convert: Dataspace -> int32_t +int32_t toRawDataspace(Dataspace const& t) { + return static_cast<int32_t>(t); +} + +/** + * \brief Wrap an opaque buffer inside a `hidl_vec<uint8_t>`. + * + * \param[in] l The pointer to the beginning of the opaque buffer. + * \param[in] size The size of the buffer. + * \return A `hidl_vec<uint8_t>` that points to the buffer. + */ +// wrap: void*, size_t -> hidl_vec<uint8_t> +hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size) { + hidl_vec<uint8_t> t; + t.setToExternal(static_cast<uint8_t*>(const_cast<void*>(l)), size, false); + return t; +} + +/** + * \brief Create a `hidl_vec<uint8_t>` that is a copy of an opaque buffer. + * + * \param[in] l The pointer to the beginning of the opaque buffer. + * \param[in] size The size of the buffer. + * \return A `hidl_vec<uint8_t>` that is a copy of the input buffer. + */ +// convert: void*, size_t -> hidl_vec<uint8_t> +hidl_vec<uint8_t> toHidlBytes(void const* l, size_t size) { + hidl_vec<uint8_t> t; + t.resize(size); + uint8_t const* src = static_cast<uint8_t const*>(l); + std::copy(src, src + size, t.data()); + return t; +} + +/** + * \brief Wrap `GraphicBuffer` in `AnwBuffer`. + * + * \param[out] t The wrapper of type `AnwBuffer`. + * \param[in] l The source `GraphicBuffer`. + */ +// wrap: GraphicBuffer -> AnwBuffer +void wrapAs(AnwBuffer* t, GraphicBuffer const& l) { + t->attr.width = l.getWidth(); + t->attr.height = l.getHeight(); + t->attr.stride = l.getStride(); + t->attr.format = static_cast<PixelFormat>(l.getPixelFormat()); + t->attr.layerCount = l.getLayerCount(); + t->attr.usage = static_cast<uint32_t>(l.getUsage()); + t->attr.id = l.getId(); + t->attr.generationNumber = l.getGenerationNumber(); + t->nativeHandle = hidl_handle(l.handle); +} + +/** + * \brief Convert `AnwBuffer` to `GraphicBuffer`. + * + * \param[out] l The destination `GraphicBuffer`. + * \param[in] t The source `AnwBuffer`. + * + * This function will duplicate all file descriptors in \p t. + */ +// convert: AnwBuffer -> GraphicBuffer +// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten +bool convertTo(GraphicBuffer* l, AnwBuffer const& t) { + native_handle_t* handle = t.nativeHandle == nullptr ? + nullptr : native_handle_clone(t.nativeHandle); + + size_t const numInts = 12 + static_cast<size_t>(handle ? handle->numInts : 0); + int32_t* ints = new int32_t[numInts]; + + size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0); + int* fds = new int[numFds]; + + ints[0] = 'GBFR'; + ints[1] = static_cast<int32_t>(t.attr.width); + ints[2] = static_cast<int32_t>(t.attr.height); + ints[3] = static_cast<int32_t>(t.attr.stride); + ints[4] = static_cast<int32_t>(t.attr.format); + ints[5] = static_cast<int32_t>(t.attr.layerCount); + ints[6] = static_cast<int32_t>(t.attr.usage); + ints[7] = static_cast<int32_t>(t.attr.id >> 32); + ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF); + ints[9] = static_cast<int32_t>(t.attr.generationNumber); + ints[10] = 0; + ints[11] = 0; + if (handle) { + ints[10] = static_cast<int32_t>(handle->numFds); + ints[11] = static_cast<int32_t>(handle->numInts); + int* intsStart = handle->data + handle->numFds; + std::copy(handle->data, intsStart, fds); + std::copy(intsStart, intsStart + handle->numInts, &ints[12]); + } + + void const* constBuffer = static_cast<void const*>(ints); + size_t size = numInts * sizeof(int32_t); + int const* constFds = static_cast<int const*>(fds); + status_t status = l->unflatten(constBuffer, size, constFds, numFds); + + delete [] fds; + delete [] ints; + native_handle_delete(handle); + return status == NO_ERROR; +} + +/** + * Conversion functions for types outside media + * ============================================ + * + * Some objects in libui and libgui that were made to go through binder calls do + * not expose ways to read or write their fields to the public. To pass an + * object of this kind through the HIDL boundary, translation functions need to + * work around the access restriction by using the publicly available + * `flatten()` and `unflatten()` functions. + * + * All `flatten()` and `unflatten()` overloads follow the same convention as + * follows: + * + * status_t flatten(ObjectType const& object, + * [OtherType const& other, ...] + * void*& buffer, size_t& size, + * int*& fds, size_t& numFds) + * + * status_t unflatten(ObjectType* object, + * [OtherType* other, ...,] + * void*& buffer, size_t& size, + * int*& fds, size_t& numFds) + * + * The number of `other` parameters varies depending on the `ObjectType`. For + * example, in the process of unflattening an object that contains + * `hidl_handle`, `other` is needed to hold `native_handle_t` objects that will + * be created. + * + * The last four parameters always work the same way in all overloads of + * `flatten()` and `unflatten()`: + * - For `flatten()`, `buffer` is the pointer to the non-fd buffer to be filled, + * `size` is the size (in bytes) of the non-fd buffer pointed to by `buffer`, + * `fds` is the pointer to the fd buffer to be filled, and `numFds` is the + * size (in ints) of the fd buffer pointed to by `fds`. + * - For `unflatten()`, `buffer` is the pointer to the non-fd buffer to be read + * from, `size` is the size (in bytes) of the non-fd buffer pointed to by + * `buffer`, `fds` is the pointer to the fd buffer to be read from, and + * `numFds` is the size (in ints) of the fd buffer pointed to by `fds`. + * - After a successful call to `flatten()` or `unflatten()`, `buffer` and `fds` + * will be advanced, while `size` and `numFds` will be decreased to reflect + * how much storage/data of the two buffers (fd and non-fd) have been used. + * - After an unsuccessful call, the values of `buffer`, `size`, `fds` and + * `numFds` are invalid. + * + * The return value of a successful `flatten()` or `unflatten()` call will be + * `OK` (also aliased as `NO_ERROR`). Any other values indicate a failure. + * + * For each object type that supports flattening, there will be two accompanying + * functions: `getFlattenedSize()` and `getFdCount()`. `getFlattenedSize()` will + * return the size of the non-fd buffer that the object will need for + * flattening. `getFdCount()` will return the size of the fd buffer that the + * object will need for flattening. + * + * The set of these four functions, `getFlattenedSize()`, `getFdCount()`, + * `flatten()` and `unflatten()`, are similar to functions of the same name in + * the abstract class `Flattenable`. The only difference is that functions in + * this file are not member functions of the object type. For example, we write + * + * flatten(x, buffer, size, fds, numFds) + * + * instead of + * + * x.flatten(buffer, size, fds, numFds) + * + * because we cannot modify the type of `x`. + * + * There is one exception to the naming convention: `hidl_handle` that + * represents a fence. The four functions for this "Fence" type have the word + * "Fence" attched to their names because the object type, which is + * `hidl_handle`, does not carry the special meaning that the object itself can + * only contain zero or one file descriptor. + */ + +// Ref: frameworks/native/libs/ui/Fence.cpp + +/** + * \brief Return the size of the non-fd buffer required to flatten a fence. + * + * \param[in] fence The input fence of type `hidl_handle`. + * \return The required size of the flat buffer. + * + * The current version of this function always returns 4, which is the number of + * bytes required to store the number of file descriptors contained in the fd + * part of the flat buffer. + */ +size_t getFenceFlattenedSize(hidl_handle const& /* fence */) { + return 4; +}; + +/** + * \brief Return the number of file descriptors contained in a fence. + * + * \param[in] fence The input fence of type `hidl_handle`. + * \return `0` if \p fence does not contain a valid file descriptor, or `1` + * otherwise. + */ +size_t getFenceFdCount(hidl_handle const& fence) { + return native_handle_read_fd(fence) == -1 ? 0 : 1; +} + +/** + * \brief Unflatten `Fence` to `hidl_handle`. + * + * \param[out] fence The destination `hidl_handle`. + * \param[out] nh The underlying native handle. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * If the return value is `NO_ERROR`, \p nh will point to a newly created + * native handle, which needs to be deleted with `native_handle_delete()` + * afterwards. + */ +status_t unflattenFence(hidl_handle* fence, native_handle_t** nh, + void const*& buffer, size_t& size, int const*& fds, size_t& numFds) { + if (size < 4) { + return NO_MEMORY; + } + + uint32_t numFdsInHandle; + FlattenableUtils::read(buffer, size, numFdsInHandle); + + if (numFdsInHandle > 1) { + return BAD_VALUE; + } + + if (numFds < numFdsInHandle) { + return NO_MEMORY; + } + + if (numFdsInHandle) { + *nh = native_handle_create_from_fd(*fds); + if (*nh == nullptr) { + return NO_MEMORY; + } + *fence = *nh; + ++fds; + --numFds; + } else { + *nh = nullptr; + *fence = hidl_handle(); + } + + return NO_ERROR; +} + +/** + * \brief Flatten `hidl_handle` as `Fence`. + * + * \param[in] t The source `hidl_handle`. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + */ +status_t flattenFence(hidl_handle const& fence, + void*& buffer, size_t& size, int*& fds, size_t& numFds) { + if (size < getFenceFlattenedSize(fence) || + numFds < getFenceFdCount(fence)) { + return NO_MEMORY; + } + // Cast to uint32_t since the size of a size_t can vary between 32- and + // 64-bit processes + FlattenableUtils::write(buffer, size, + static_cast<uint32_t>(getFenceFdCount(fence))); + int fd = native_handle_read_fd(fence); + if (fd != -1) { + *fds = fd; + ++fds; + --numFds; + } + return NO_ERROR; +} + +/** + * \brief Wrap `Fence` in `hidl_handle`. + * + * \param[out] t The wrapper of type `hidl_handle`. + * \param[out] nh The native handle pointed to by \p t. + * \param[in] l The source `Fence`. + * + * On success, \p nh will hold a newly created native handle, which must be + * deleted manually with `native_handle_delete()` afterwards. + */ +// wrap: Fence -> hidl_handle +bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l) { + size_t const baseSize = l.getFlattenedSize(); + std::unique_ptr<uint8_t[]> baseBuffer( + new (std::nothrow) uint8_t[baseSize]); + if (!baseBuffer) { + return false; + } + + size_t const baseNumFds = l.getFdCount(); + std::unique_ptr<int[]> baseFds( + new (std::nothrow) int[baseNumFds]); + if (!baseFds) { + return false; + } + + void* buffer = static_cast<void*>(baseBuffer.get()); + size_t size = baseSize; + int* fds = static_cast<int*>(baseFds.get()); + size_t numFds = baseNumFds; + if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) { + return false; + } + + void const* constBuffer = static_cast<void const*>(baseBuffer.get()); + size = baseSize; + int const* constFds = static_cast<int const*>(baseFds.get()); + numFds = baseNumFds; + if (unflattenFence(t, nh, constBuffer, size, constFds, numFds) + != NO_ERROR) { + return false; + } + + return true; +} + +/** + * \brief Convert `hidl_handle` to `Fence`. + * + * \param[out] l The destination `Fence`. `l` must not have been used + * (`l->isValid()` must return `false`) before this function is called. + * \param[in] t The source `hidl_handle`. + * + * If \p t contains a valid file descriptor, it will be duplicated. + */ +// convert: hidl_handle -> Fence +bool convertTo(Fence* l, hidl_handle const& t) { + int fd = native_handle_read_fd(t); + if (fd != -1) { + fd = dup(fd); + if (fd == -1) { + return false; + } + } + native_handle_t* nh = native_handle_create_from_fd(fd); + if (nh == nullptr) { + if (fd != -1) { + close(fd); + } + return false; + } + + size_t const baseSize = getFenceFlattenedSize(t); + std::unique_ptr<uint8_t[]> baseBuffer( + new (std::nothrow) uint8_t[baseSize]); + if (!baseBuffer) { + native_handle_delete(nh); + return false; + } + + size_t const baseNumFds = getFenceFdCount(t); + std::unique_ptr<int[]> baseFds( + new (std::nothrow) int[baseNumFds]); + if (!baseFds) { + native_handle_delete(nh); + return false; + } + + void* buffer = static_cast<void*>(baseBuffer.get()); + size_t size = baseSize; + int* fds = static_cast<int*>(baseFds.get()); + size_t numFds = baseNumFds; + if (flattenFence(hidl_handle(nh), buffer, size, fds, numFds) != NO_ERROR) { + native_handle_delete(nh); + return false; + } + native_handle_delete(nh); + + void const* constBuffer = static_cast<void const*>(baseBuffer.get()); + size = baseSize; + int const* constFds = static_cast<int const*>(baseFds.get()); + numFds = baseNumFds; + if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) { + return false; + } + + return true; +} + +// Ref: frameworks/native/libs/ui/FenceTime.cpp: FenceTime::Snapshot + +/** + * \brief Return the size of the non-fd buffer required to flatten + * `FenceTimeSnapshot`. + * + * \param[in] t The input `FenceTimeSnapshot`. + * \return The required size of the flat buffer. + */ +size_t getFlattenedSize( + HGraphicBufferProducer::FenceTimeSnapshot const& t) { + constexpr size_t min = sizeof(t.state); + switch (t.state) { + case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY: + return min; + case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE: + return min + getFenceFlattenedSize(t.fence); + case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME: + return min + sizeof( + ::android::FenceTime::Snapshot::signalTime); + } + return 0; +} + +/** + * \brief Return the number of file descriptors contained in + * `FenceTimeSnapshot`. + * + * \param[in] t The input `FenceTimeSnapshot`. + * \return The number of file descriptors contained in \p snapshot. + */ +size_t getFdCount( + HGraphicBufferProducer::FenceTimeSnapshot const& t) { + return t.state == + HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE ? + getFenceFdCount(t.fence) : 0; +} + +/** + * \brief Flatten `FenceTimeSnapshot`. + * + * \param[in] t The source `FenceTimeSnapshot`. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * This function will duplicate the file descriptor in `t.fence` if `t.state == + * FENCE`. + */ +status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t, + void*& buffer, size_t& size, int*& fds, size_t& numFds) { + if (size < getFlattenedSize(t)) { + return NO_MEMORY; + } + + switch (t.state) { + case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY: + FlattenableUtils::write(buffer, size, + ::android::FenceTime::Snapshot::State::EMPTY); + return NO_ERROR; + case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE: + FlattenableUtils::write(buffer, size, + ::android::FenceTime::Snapshot::State::FENCE); + return flattenFence(t.fence, buffer, size, fds, numFds); + case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME: + FlattenableUtils::write(buffer, size, + ::android::FenceTime::Snapshot::State::SIGNAL_TIME); + FlattenableUtils::write(buffer, size, t.signalTimeNs); + return NO_ERROR; + } + return NO_ERROR; +} + +/** + * \brief Unflatten `FenceTimeSnapshot`. + * + * \param[out] t The destination `FenceTimeSnapshot`. + * \param[out] nh The underlying native handle. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * If the return value is `NO_ERROR` and the constructed snapshot contains a + * file descriptor, \p nh will be created to hold that file descriptor. In this + * case, \p nh needs to be deleted with `native_handle_delete()` afterwards. + */ +status_t unflatten( + HGraphicBufferProducer::FenceTimeSnapshot* t, native_handle_t** nh, + void const*& buffer, size_t& size, int const*& fds, size_t& numFds) { + if (size < sizeof(t->state)) { + return NO_MEMORY; + } + + *nh = nullptr; + ::android::FenceTime::Snapshot::State state; + FlattenableUtils::read(buffer, size, state); + switch (state) { + case ::android::FenceTime::Snapshot::State::EMPTY: + t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY; + return NO_ERROR; + case ::android::FenceTime::Snapshot::State::FENCE: + t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE; + return unflattenFence(&t->fence, nh, buffer, size, fds, numFds); + case ::android::FenceTime::Snapshot::State::SIGNAL_TIME: + t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME; + if (size < sizeof(t->signalTimeNs)) { + return NO_MEMORY; + } + FlattenableUtils::read(buffer, size, t->signalTimeNs); + return NO_ERROR; + } + return NO_ERROR; +} + +// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventsDelta + +/** + * \brief Return a lower bound on the size of the non-fd buffer required to + * flatten `FrameEventsDelta`. + * + * \param[in] t The input `FrameEventsDelta`. + * \return A lower bound on the size of the flat buffer. + */ +constexpr size_t minFlattenedSize( + HGraphicBufferProducer::FrameEventsDelta const& /* t */) { + return sizeof(uint64_t) + // mFrameNumber + sizeof(uint8_t) + // mIndex + sizeof(uint8_t) + // mAddPostCompositeCalled + sizeof(uint8_t) + // mAddRetireCalled + sizeof(uint8_t) + // mAddReleaseCalled + sizeof(nsecs_t) + // mPostedTime + sizeof(nsecs_t) + // mRequestedPresentTime + sizeof(nsecs_t) + // mLatchTime + sizeof(nsecs_t) + // mFirstRefreshStartTime + sizeof(nsecs_t); // mLastRefreshStartTime +} + +/** + * \brief Return the size of the non-fd buffer required to flatten + * `FrameEventsDelta`. + * + * \param[in] t The input `FrameEventsDelta`. + * \return The required size of the flat buffer. + */ +size_t getFlattenedSize( + HGraphicBufferProducer::FrameEventsDelta const& t) { + return minFlattenedSize(t) + + getFlattenedSize(t.gpuCompositionDoneFence) + + getFlattenedSize(t.displayPresentFence) + + getFlattenedSize(t.displayRetireFence) + + getFlattenedSize(t.releaseFence); +}; + +/** + * \brief Return the number of file descriptors contained in + * `FrameEventsDelta`. + * + * \param[in] t The input `FrameEventsDelta`. + * \return The number of file descriptors contained in \p t. + */ +size_t getFdCount( + HGraphicBufferProducer::FrameEventsDelta const& t) { + return getFdCount(t.gpuCompositionDoneFence) + + getFdCount(t.displayPresentFence) + + getFdCount(t.displayRetireFence) + + getFdCount(t.releaseFence); +}; + +/** + * \brief Unflatten `FrameEventsDelta`. + * + * \param[out] t The destination `FrameEventsDelta`. + * \param[out] nh The underlying array of native handles. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * If the return value is `NO_ERROR`, \p nh will have length 4, and it will be + * populated with `nullptr` or newly created handles. Each non-null slot in \p + * nh will need to be deleted manually with `native_handle_delete()`. + */ +status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t, + std::vector<native_handle_t*>* nh, + void const*& buffer, size_t& size, int const*& fds, size_t& numFds) { + if (size < minFlattenedSize(*t)) { + return NO_MEMORY; + } + FlattenableUtils::read(buffer, size, t->frameNumber); + + // These were written as uint8_t for alignment. + uint8_t temp = 0; + FlattenableUtils::read(buffer, size, temp); + size_t index = static_cast<size_t>(temp); + if (index >= ::android::FrameEventHistory::MAX_FRAME_HISTORY) { + return BAD_VALUE; + } + t->index = static_cast<uint32_t>(index); + + FlattenableUtils::read(buffer, size, temp); + t->addPostCompositeCalled = static_cast<bool>(temp); + FlattenableUtils::read(buffer, size, temp); + t->addRetireCalled = static_cast<bool>(temp); + FlattenableUtils::read(buffer, size, temp); + t->addReleaseCalled = static_cast<bool>(temp); + + FlattenableUtils::read(buffer, size, t->postedTimeNs); + FlattenableUtils::read(buffer, size, t->requestedPresentTimeNs); + FlattenableUtils::read(buffer, size, t->latchTimeNs); + FlattenableUtils::read(buffer, size, t->firstRefreshStartTimeNs); + FlattenableUtils::read(buffer, size, t->lastRefreshStartTimeNs); + FlattenableUtils::read(buffer, size, t->dequeueReadyTime); + + // Fences + HGraphicBufferProducer::FenceTimeSnapshot* tSnapshot[4]; + tSnapshot[0] = &t->gpuCompositionDoneFence; + tSnapshot[1] = &t->displayPresentFence; + tSnapshot[2] = &t->displayRetireFence; + tSnapshot[3] = &t->releaseFence; + nh->resize(4); + for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) { + status_t status = unflatten( + tSnapshot[snapshotIndex], &((*nh)[snapshotIndex]), + buffer, size, fds, numFds); + if (status != NO_ERROR) { + while (snapshotIndex > 0) { + --snapshotIndex; + if ((*nh)[snapshotIndex] != nullptr) { + native_handle_delete((*nh)[snapshotIndex]); + } + } + return status; + } + } + return NO_ERROR; +} + +/** + * \brief Flatten `FrameEventsDelta`. + * + * \param[in] t The source `FrameEventsDelta`. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * This function will duplicate file descriptors contained in \p t. + */ +// Ref: frameworks/native/libs/gui/FrameTimestamp.cpp: +// FrameEventsDelta::flatten +status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t, + void*& buffer, size_t& size, int*& fds, size_t numFds) { + // Check that t.index is within a valid range. + if (t.index >= static_cast<uint32_t>(FrameEventHistory::MAX_FRAME_HISTORY) + || t.index > std::numeric_limits<uint8_t>::max()) { + return BAD_VALUE; + } + + FlattenableUtils::write(buffer, size, t.frameNumber); + + // These are static_cast to uint8_t for alignment. + FlattenableUtils::write(buffer, size, static_cast<uint8_t>(t.index)); + FlattenableUtils::write( + buffer, size, static_cast<uint8_t>(t.addPostCompositeCalled)); + FlattenableUtils::write( + buffer, size, static_cast<uint8_t>(t.addRetireCalled)); + FlattenableUtils::write( + buffer, size, static_cast<uint8_t>(t.addReleaseCalled)); + + FlattenableUtils::write(buffer, size, t.postedTimeNs); + FlattenableUtils::write(buffer, size, t.requestedPresentTimeNs); + FlattenableUtils::write(buffer, size, t.latchTimeNs); + FlattenableUtils::write(buffer, size, t.firstRefreshStartTimeNs); + FlattenableUtils::write(buffer, size, t.lastRefreshStartTimeNs); + FlattenableUtils::write(buffer, size, t.dequeueReadyTime); + + // Fences + HGraphicBufferProducer::FenceTimeSnapshot const* tSnapshot[4]; + tSnapshot[0] = &t.gpuCompositionDoneFence; + tSnapshot[1] = &t.displayPresentFence; + tSnapshot[2] = &t.displayRetireFence; + tSnapshot[3] = &t.releaseFence; + for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) { + status_t status = flatten( + *(tSnapshot[snapshotIndex]), buffer, size, fds, numFds); + if (status != NO_ERROR) { + return status; + } + } + return NO_ERROR; +} + +// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventHistoryDelta + +/** + * \brief Return the size of the non-fd buffer required to flatten + * `HGraphicBufferProducer::FrameEventHistoryDelta`. + * + * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`. + * \return The required size of the flat buffer. + */ +size_t getFlattenedSize( + HGraphicBufferProducer::FrameEventHistoryDelta const& t) { + size_t size = 4 + // mDeltas.size() + sizeof(t.compositorTiming); + for (size_t i = 0; i < t.deltas.size(); ++i) { + size += getFlattenedSize(t.deltas[i]); + } + return size; +} + +/** + * \brief Return the number of file descriptors contained in + * `HGraphicBufferProducer::FrameEventHistoryDelta`. + * + * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`. + * \return The number of file descriptors contained in \p t. + */ +size_t getFdCount( + HGraphicBufferProducer::FrameEventHistoryDelta const& t) { + size_t numFds = 0; + for (size_t i = 0; i < t.deltas.size(); ++i) { + numFds += getFdCount(t.deltas[i]); + } + return numFds; +} + +/** + * \brief Unflatten `FrameEventHistoryDelta`. + * + * \param[out] t The destination `FrameEventHistoryDelta`. + * \param[out] nh The underlying array of arrays of native handles. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * If the return value is `NO_ERROR`, \p nh will be populated with `nullptr` or + * newly created handles. The second dimension of \p nh will be 4. Each non-null + * slot in \p nh will need to be deleted manually with `native_handle_delete()`. + */ +status_t unflatten( + HGraphicBufferProducer::FrameEventHistoryDelta* t, + std::vector<std::vector<native_handle_t*> >* nh, + void const*& buffer, size_t& size, int const*& fds, size_t& numFds) { + if (size < 4) { + return NO_MEMORY; + } + + FlattenableUtils::read(buffer, size, t->compositorTiming); + + uint32_t deltaCount = 0; + FlattenableUtils::read(buffer, size, deltaCount); + if (static_cast<size_t>(deltaCount) > + ::android::FrameEventHistory::MAX_FRAME_HISTORY) { + return BAD_VALUE; + } + t->deltas.resize(deltaCount); + nh->resize(deltaCount); + for (size_t deltaIndex = 0; deltaIndex < deltaCount; ++deltaIndex) { + status_t status = unflatten( + &(t->deltas[deltaIndex]), &((*nh)[deltaIndex]), + buffer, size, fds, numFds); + if (status != NO_ERROR) { + return status; + } + } + return NO_ERROR; +} + +/** + * \brief Flatten `FrameEventHistoryDelta`. + * + * \param[in] t The source `FrameEventHistoryDelta`. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * This function will duplicate file descriptors contained in \p t. + */ +status_t flatten( + HGraphicBufferProducer::FrameEventHistoryDelta const& t, + void*& buffer, size_t& size, int*& fds, size_t& numFds) { + if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) { + return BAD_VALUE; + } + if (size < getFlattenedSize(t)) { + return NO_MEMORY; + } + + FlattenableUtils::write(buffer, size, t.compositorTiming); + + FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.deltas.size())); + for (size_t deltaIndex = 0; deltaIndex < t.deltas.size(); ++deltaIndex) { + status_t status = flatten(t.deltas[deltaIndex], buffer, size, fds, numFds); + if (status != NO_ERROR) { + return status; + } + } + return NO_ERROR; +} + +/** + * \brief Wrap `::android::FrameEventHistoryData` in + * `HGraphicBufferProducer::FrameEventHistoryDelta`. + * + * \param[out] t The wrapper of type + * `HGraphicBufferProducer::FrameEventHistoryDelta`. + * \param[out] nh The array of array of native handles that are referred to by + * members of \p t. + * \param[in] l The source `::android::FrameEventHistoryDelta`. + * + * On success, each member of \p nh will be either `nullptr` or a newly created + * native handle. All the non-`nullptr` elements must be deleted individually + * with `native_handle_delete()`. + */ +bool wrapAs(HGraphicBufferProducer::FrameEventHistoryDelta* t, + std::vector<std::vector<native_handle_t*> >* nh, + ::android::FrameEventHistoryDelta const& l) { + + size_t const baseSize = l.getFlattenedSize(); + std::unique_ptr<uint8_t[]> baseBuffer( + new (std::nothrow) uint8_t[baseSize]); + if (!baseBuffer) { + return false; + } + + size_t const baseNumFds = l.getFdCount(); + std::unique_ptr<int[]> baseFds( + new (std::nothrow) int[baseNumFds]); + if (!baseFds) { + return false; + } + + void* buffer = static_cast<void*>(baseBuffer.get()); + size_t size = baseSize; + int* fds = baseFds.get(); + size_t numFds = baseNumFds; + if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) { + return false; + } + + void const* constBuffer = static_cast<void const*>(baseBuffer.get()); + size = baseSize; + int const* constFds = static_cast<int const*>(baseFds.get()); + numFds = baseNumFds; + if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) { + return false; + } + + return true; +} + +/** + * \brief Convert `HGraphicBufferProducer::FrameEventHistoryDelta` to + * `::android::FrameEventHistoryDelta`. + * + * \param[out] l The destination `::android::FrameEventHistoryDelta`. + * \param[in] t The source `HGraphicBufferProducer::FrameEventHistoryDelta`. + * + * This function will duplicate all file descriptors contained in \p t. + */ +bool convertTo( + ::android::FrameEventHistoryDelta* l, + HGraphicBufferProducer::FrameEventHistoryDelta const& t) { + + size_t const baseSize = getFlattenedSize(t); + std::unique_ptr<uint8_t[]> baseBuffer( + new (std::nothrow) uint8_t[baseSize]); + if (!baseBuffer) { + return false; + } + + size_t const baseNumFds = getFdCount(t); + std::unique_ptr<int[]> baseFds( + new (std::nothrow) int[baseNumFds]); + if (!baseFds) { + return false; + } + + void* buffer = static_cast<void*>(baseBuffer.get()); + size_t size = baseSize; + int* fds = static_cast<int*>(baseFds.get()); + size_t numFds = baseNumFds; + if (flatten(t, buffer, size, fds, numFds) != NO_ERROR) { + return false; + } + + void const* constBuffer = static_cast<void const*>(baseBuffer.get()); + size = baseSize; + int const* constFds = static_cast<int const*>(baseFds.get()); + numFds = baseNumFds; + if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) { + return false; + } + + return true; +} + +// Ref: frameworks/native/libs/ui/Region.cpp + +/** + * \brief Return the size of the buffer required to flatten `Region`. + * + * \param[in] t The input `Region`. + * \return The required size of the flat buffer. + */ +size_t getFlattenedSize(Region const& t) { + return sizeof(uint32_t) + t.size() * sizeof(::android::Rect); +} + +/** + * \brief Unflatten `Region`. + * + * \param[out] t The destination `Region`. + * \param[in,out] buffer The pointer to the flat buffer. + * \param[in,out] size The size of the flat buffer. + * \return `NO_ERROR` on success; other value on failure. + */ +status_t unflatten(Region* t, void const*& buffer, size_t& size) { + if (size < sizeof(uint32_t)) { + return NO_MEMORY; + } + + uint32_t numRects = 0; + FlattenableUtils::read(buffer, size, numRects); + if (size < numRects * sizeof(Rect)) { + return NO_MEMORY; + } + if (numRects > (UINT32_MAX / sizeof(Rect))) { + return NO_MEMORY; + } + + t->resize(numRects); + for (size_t r = 0; r < numRects; ++r) { + ::android::Rect rect(::android::Rect::EMPTY_RECT); + status_t status = rect.unflatten(buffer, size); + if (status != NO_ERROR) { + return status; + } + FlattenableUtils::advance(buffer, size, sizeof(rect)); + (*t)[r] = Rect{ + static_cast<int32_t>(rect.left), + static_cast<int32_t>(rect.top), + static_cast<int32_t>(rect.right), + static_cast<int32_t>(rect.bottom)}; + } + return NO_ERROR; +} + +/** + * \brief Flatten `Region`. + * + * \param[in] t The source `Region`. + * \param[in,out] buffer The pointer to the flat buffer. + * \param[in,out] size The size of the flat buffer. + * \return `NO_ERROR` on success; other value on failure. + */ +status_t flatten(Region const& t, void*& buffer, size_t& size) { + if (size < getFlattenedSize(t)) { + return NO_MEMORY; + } + + FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.size())); + for (size_t r = 0; r < t.size(); ++r) { + ::android::Rect rect( + static_cast<int32_t>(t[r].left), + static_cast<int32_t>(t[r].top), + static_cast<int32_t>(t[r].right), + static_cast<int32_t>(t[r].bottom)); + status_t status = rect.flatten(buffer, size); + if (status != NO_ERROR) { + return status; + } + FlattenableUtils::advance(buffer, size, sizeof(rect)); + } + return NO_ERROR; +} + +/** + * \brief Convert `::android::Region` to `Region`. + * + * \param[out] t The destination `Region`. + * \param[in] l The source `::android::Region`. + */ +// convert: ::android::Region -> Region +bool convertTo(Region* t, ::android::Region const& l) { + size_t const baseSize = l.getFlattenedSize(); + std::unique_ptr<uint8_t[]> baseBuffer( + new (std::nothrow) uint8_t[baseSize]); + if (!baseBuffer) { + return false; + } + + void* buffer = static_cast<void*>(baseBuffer.get()); + size_t size = baseSize; + if (l.flatten(buffer, size) != NO_ERROR) { + return false; + } + + void const* constBuffer = static_cast<void const*>(baseBuffer.get()); + size = baseSize; + if (unflatten(t, constBuffer, size) != NO_ERROR) { + return false; + } + + return true; +} + +/** + * \brief Convert `Region` to `::android::Region`. + * + * \param[out] l The destination `::android::Region`. + * \param[in] t The source `Region`. + */ +// convert: Region -> ::android::Region +bool convertTo(::android::Region* l, Region const& t) { + size_t const baseSize = getFlattenedSize(t); + std::unique_ptr<uint8_t[]> baseBuffer( + new (std::nothrow) uint8_t[baseSize]); + if (!baseBuffer) { + return false; + } + + void* buffer = static_cast<void*>(baseBuffer.get()); + size_t size = baseSize; + if (flatten(t, buffer, size) != NO_ERROR) { + return false; + } + + void const* constBuffer = static_cast<void const*>(baseBuffer.get()); + size = baseSize; + if (l->unflatten(constBuffer, size) != NO_ERROR) { + return false; + } + + return true; +} + +// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp: +// BGraphicBufferProducer::QueueBufferInput + +/** + * \brief Return a lower bound on the size of the buffer required to flatten + * `HGraphicBufferProducer::QueueBufferInput`. + * + * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`. + * \return A lower bound on the size of the flat buffer. + */ +constexpr size_t minFlattenedSize( + HGraphicBufferProducer::QueueBufferInput const& /* t */) { + return sizeof(int64_t) + // timestamp + sizeof(int) + // isAutoTimestamp + sizeof(android_dataspace) + // dataSpace + sizeof(::android::Rect) + // crop + sizeof(int) + // scalingMode + sizeof(uint32_t) + // transform + sizeof(uint32_t) + // stickyTransform + sizeof(bool); // getFrameTimestamps +} + +/** + * \brief Return the size of the buffer required to flatten + * `HGraphicBufferProducer::QueueBufferInput`. + * + * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`. + * \return The required size of the flat buffer. + */ +size_t getFlattenedSize(HGraphicBufferProducer::QueueBufferInput const& t) { + return minFlattenedSize(t) + + getFenceFlattenedSize(t.fence) + + getFlattenedSize(t.surfaceDamage) + + sizeof(HdrMetadata::validTypes); +} + +/** + * \brief Return the number of file descriptors contained in + * `HGraphicBufferProducer::QueueBufferInput`. + * + * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`. + * \return The number of file descriptors contained in \p t. + */ +size_t getFdCount( + HGraphicBufferProducer::QueueBufferInput const& t) { + return getFenceFdCount(t.fence); +} + +/** + * \brief Flatten `HGraphicBufferProducer::QueueBufferInput`. + * + * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`. + * \param[out] nh The native handle cloned from `t.fence`. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * This function will duplicate the file descriptor in `t.fence`. */ +status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t, + native_handle_t** nh, + void*& buffer, size_t& size, int*& fds, size_t& numFds) { + if (size < getFlattenedSize(t)) { + return NO_MEMORY; + } + + FlattenableUtils::write(buffer, size, t.timestamp); + FlattenableUtils::write(buffer, size, static_cast<int>(t.isAutoTimestamp)); + FlattenableUtils::write(buffer, size, + static_cast<android_dataspace_t>(t.dataSpace)); + FlattenableUtils::write(buffer, size, ::android::Rect( + static_cast<int32_t>(t.crop.left), + static_cast<int32_t>(t.crop.top), + static_cast<int32_t>(t.crop.right), + static_cast<int32_t>(t.crop.bottom))); + FlattenableUtils::write(buffer, size, static_cast<int>(t.scalingMode)); + FlattenableUtils::write(buffer, size, t.transform); + FlattenableUtils::write(buffer, size, t.stickyTransform); + FlattenableUtils::write(buffer, size, t.getFrameTimestamps); + + *nh = t.fence.getNativeHandle() == nullptr ? + nullptr : native_handle_clone(t.fence); + status_t status = flattenFence(hidl_handle(*nh), buffer, size, fds, numFds); + if (status != NO_ERROR) { + return status; + } + status = flatten(t.surfaceDamage, buffer, size); + if (status != NO_ERROR) { + return status; + } + FlattenableUtils::write(buffer, size, decltype(HdrMetadata::validTypes)(0)); + return NO_ERROR; +} + +/** + * \brief Unflatten `HGraphicBufferProducer::QueueBufferInput`. + * + * \param[out] t The destination `HGraphicBufferProducer::QueueBufferInput`. + * \param[out] nh The underlying native handle for `t->fence`. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * If the return value is `NO_ERROR` and `t->fence` contains a valid file + * descriptor, \p nh will be a newly created native handle holding that file + * descriptor. \p nh needs to be deleted with `native_handle_delete()` + * afterwards. + */ +status_t unflatten( + HGraphicBufferProducer::QueueBufferInput* t, native_handle_t** nh, + void const*& buffer, size_t& size, int const*& fds, size_t& numFds) { + if (size < minFlattenedSize(*t)) { + return NO_MEMORY; + } + + FlattenableUtils::read(buffer, size, t->timestamp); + int lIsAutoTimestamp; + FlattenableUtils::read(buffer, size, lIsAutoTimestamp); + t->isAutoTimestamp = static_cast<int32_t>(lIsAutoTimestamp); + android_dataspace_t lDataSpace; + FlattenableUtils::read(buffer, size, lDataSpace); + t->dataSpace = static_cast<Dataspace>(lDataSpace); + Rect lCrop; + FlattenableUtils::read(buffer, size, lCrop); + t->crop = Rect{ + static_cast<int32_t>(lCrop.left), + static_cast<int32_t>(lCrop.top), + static_cast<int32_t>(lCrop.right), + static_cast<int32_t>(lCrop.bottom)}; + int lScalingMode; + FlattenableUtils::read(buffer, size, lScalingMode); + t->scalingMode = static_cast<int32_t>(lScalingMode); + FlattenableUtils::read(buffer, size, t->transform); + FlattenableUtils::read(buffer, size, t->stickyTransform); + FlattenableUtils::read(buffer, size, t->getFrameTimestamps); + + status_t status = unflattenFence(&(t->fence), nh, + buffer, size, fds, numFds); + if (status != NO_ERROR) { + return status; + } + // HdrMetadata ignored + return unflatten(&(t->surfaceDamage), buffer, size); +} + +/** + * \brief Wrap `BGraphicBufferProducer::QueueBufferInput` in + * `HGraphicBufferProducer::QueueBufferInput`. + * + * \param[out] t The wrapper of type + * `HGraphicBufferProducer::QueueBufferInput`. + * \param[out] nh The underlying native handle for `t->fence`. + * \param[in] l The source `BGraphicBufferProducer::QueueBufferInput`. + * + * If the return value is `true` and `t->fence` contains a valid file + * descriptor, \p nh will be a newly created native handle holding that file + * descriptor. \p nh needs to be deleted with `native_handle_delete()` + * afterwards. + */ +bool wrapAs( + HGraphicBufferProducer::QueueBufferInput* t, + native_handle_t** nh, + BGraphicBufferProducer::QueueBufferInput const& l) { + + size_t const baseSize = l.getFlattenedSize(); + std::unique_ptr<uint8_t[]> baseBuffer( + new (std::nothrow) uint8_t[baseSize]); + if (!baseBuffer) { + return false; + } + + size_t const baseNumFds = l.getFdCount(); + std::unique_ptr<int[]> baseFds( + new (std::nothrow) int[baseNumFds]); + if (!baseFds) { + return false; + } + + void* buffer = static_cast<void*>(baseBuffer.get()); + size_t size = baseSize; + int* fds = baseFds.get(); + size_t numFds = baseNumFds; + if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) { + return false; + } + + void const* constBuffer = static_cast<void const*>(baseBuffer.get()); + size = baseSize; + int const* constFds = static_cast<int const*>(baseFds.get()); + numFds = baseNumFds; + if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) { + return false; + } + + return true; +} + +/** + * \brief Convert `HGraphicBufferProducer::QueueBufferInput` to + * `BGraphicBufferProducer::QueueBufferInput`. + * + * \param[out] l The destination `BGraphicBufferProducer::QueueBufferInput`. + * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`. + * + * If `t.fence` has a valid file descriptor, it will be duplicated. + */ +bool convertTo( + BGraphicBufferProducer::QueueBufferInput* l, + HGraphicBufferProducer::QueueBufferInput const& t) { + + size_t const baseSize = getFlattenedSize(t); + std::unique_ptr<uint8_t[]> baseBuffer( + new (std::nothrow) uint8_t[baseSize]); + if (!baseBuffer) { + return false; + } + + size_t const baseNumFds = getFdCount(t); + std::unique_ptr<int[]> baseFds( + new (std::nothrow) int[baseNumFds]); + if (!baseFds) { + return false; + } + + void* buffer = static_cast<void*>(baseBuffer.get()); + size_t size = baseSize; + int* fds = baseFds.get(); + size_t numFds = baseNumFds; + native_handle_t* nh; + if (flatten(t, &nh, buffer, size, fds, numFds) != NO_ERROR) { + return false; + } + + void const* constBuffer = static_cast<void const*>(baseBuffer.get()); + size = baseSize; + int const* constFds = static_cast<int const*>(baseFds.get()); + numFds = baseNumFds; + if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) { + if (nh != nullptr) { + native_handle_close(nh); + native_handle_delete(nh); + } + return false; + } + + native_handle_delete(nh); + return true; +} + +// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp: +// BGraphicBufferProducer::QueueBufferOutput + +/** + * \brief Wrap `BGraphicBufferProducer::QueueBufferOutput` in + * `HGraphicBufferProducer::QueueBufferOutput`. + * + * \param[out] t The wrapper of type + * `HGraphicBufferProducer::QueueBufferOutput`. + * \param[out] nh The array of array of native handles that are referred to by + * members of \p t. + * \param[in] l The source `BGraphicBufferProducer::QueueBufferOutput`. + * + * On success, each member of \p nh will be either `nullptr` or a newly created + * native handle. All the non-`nullptr` elements must be deleted individually + * with `native_handle_delete()`. + */ +// wrap: BGraphicBufferProducer::QueueBufferOutput -> +// HGraphicBufferProducer::QueueBufferOutput +bool wrapAs(HGraphicBufferProducer::QueueBufferOutput* t, + std::vector<std::vector<native_handle_t*> >* nh, + BGraphicBufferProducer::QueueBufferOutput const& l) { + if (!wrapAs(&(t->frameTimestamps), nh, l.frameTimestamps)) { + return false; + } + t->width = l.width; + t->height = l.height; + t->transformHint = l.transformHint; + t->numPendingBuffers = l.numPendingBuffers; + t->nextFrameNumber = l.nextFrameNumber; + t->bufferReplaced = l.bufferReplaced; + return true; +} + +/** + * \brief Convert `HGraphicBufferProducer::QueueBufferOutput` to + * `BGraphicBufferProducer::QueueBufferOutput`. + * + * \param[out] l The destination `BGraphicBufferProducer::QueueBufferOutput`. + * \param[in] t The source `HGraphicBufferProducer::QueueBufferOutput`. + * + * This function will duplicate all file descriptors contained in \p t. + */ +// convert: HGraphicBufferProducer::QueueBufferOutput -> +// BGraphicBufferProducer::QueueBufferOutput +bool convertTo( + BGraphicBufferProducer::QueueBufferOutput* l, + HGraphicBufferProducer::QueueBufferOutput const& t) { + if (!convertTo(&(l->frameTimestamps), t.frameTimestamps)) { + return false; + } + l->width = t.width; + l->height = t.height; + l->transformHint = t.transformHint; + l->numPendingBuffers = t.numPendingBuffers; + l->nextFrameNumber = t.nextFrameNumber; + l->bufferReplaced = t.bufferReplaced; + return true; +} + +/** + * \brief Convert `BGraphicBufferProducer::DisconnectMode` to + * `HGraphicBufferProducer::DisconnectMode`. + * + * \param[in] l The source `BGraphicBufferProducer::DisconnectMode`. + * \return The corresponding `HGraphicBufferProducer::DisconnectMode`. + */ +HGraphicBufferProducer::DisconnectMode toHidlDisconnectMode( + BGraphicBufferProducer::DisconnectMode l) { + switch (l) { + case BGraphicBufferProducer::DisconnectMode::Api: + return HGraphicBufferProducer::DisconnectMode::API; + case BGraphicBufferProducer::DisconnectMode::AllLocal: + return HGraphicBufferProducer::DisconnectMode::ALL_LOCAL; + } + return HGraphicBufferProducer::DisconnectMode::API; +} + +/** + * \brief Convert `HGraphicBufferProducer::DisconnectMode` to + * `BGraphicBufferProducer::DisconnectMode`. + * + * \param[in] l The source `HGraphicBufferProducer::DisconnectMode`. + * \return The corresponding `BGraphicBufferProducer::DisconnectMode`. + */ +BGraphicBufferProducer::DisconnectMode toGuiDisconnectMode( + HGraphicBufferProducer::DisconnectMode t) { + switch (t) { + case HGraphicBufferProducer::DisconnectMode::API: + return BGraphicBufferProducer::DisconnectMode::Api; + case HGraphicBufferProducer::DisconnectMode::ALL_LOCAL: + return BGraphicBufferProducer::DisconnectMode::AllLocal; + } + return BGraphicBufferProducer::DisconnectMode::Api; +} + +} // namespace conversion +} // namespace android + diff --git a/libs/gui/bufferqueue/1.0/WProducerListener.cpp b/libs/gui/bufferqueue/1.0/WProducerListener.cpp new file mode 100644 index 0000000000..78dc4e8b18 --- /dev/null +++ b/libs/gui/bufferqueue/1.0/WProducerListener.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 2016, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gui/bufferqueue/1.0/WProducerListener.h> + +namespace android { + +// TWProducerListener +TWProducerListener::TWProducerListener( + sp<BProducerListener> const& base): + mBase(base) { +} + +Return<void> TWProducerListener::onBufferReleased() { + mBase->onBufferReleased(); + return Void(); +} + +Return<bool> TWProducerListener::needsReleaseNotify() { + return mBase->needsReleaseNotify(); +} + +// LWProducerListener +LWProducerListener::LWProducerListener( + sp<HProducerListener> const& base): + mBase(base) { +} + +void LWProducerListener::onBufferReleased() { + mBase->onBufferReleased(); +} + +bool LWProducerListener::needsReleaseNotify() { + return static_cast<bool>(mBase->needsReleaseNotify()); +} + +} // namespace android diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index b377a412bc..0e80283804 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -22,8 +22,6 @@ #include <gui/BufferSlot.h> #include <gui/OccupancyTracker.h> -#include <utils/Condition.h> -#include <utils/Mutex.h> #include <utils/NativeHandle.h> #include <utils/RefBase.h> #include <utils/String8.h> @@ -33,6 +31,8 @@ #include <list> #include <set> +#include <mutex> +#include <condition_variable> #define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) #define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) @@ -134,7 +134,7 @@ private: bool adjustAvailableSlotsLocked(int delta); // waitWhileAllocatingLocked blocks until mIsAllocating is false. - void waitWhileAllocatingLocked() const; + void waitWhileAllocatingLocked(std::unique_lock<std::mutex>& lock) const; #if DEBUG_ONLY_CODE // validateConsistencyLocked ensures that the free lists are in sync with @@ -145,7 +145,7 @@ private: // mMutex is the mutex used to prevent concurrent access to the member // variables of BufferQueueCore objects. It must be locked whenever any // member variable is accessed. - mutable Mutex mMutex; + mutable std::mutex mMutex; // mIsAbandoned indicates that the BufferQueue will no longer be used to // consume image buffers pushed to it using the IGraphicBufferProducer @@ -219,7 +219,7 @@ private: // mDequeueCondition is a condition variable used for dequeueBuffer in // synchronous mode. - mutable Condition mDequeueCondition; + mutable std::condition_variable mDequeueCondition; // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to // block. This flag is set during connect when both the producer and @@ -282,7 +282,7 @@ private: // mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating // becomes false. - mutable Condition mIsAllocatingCondition; + mutable std::condition_variable mIsAllocatingCondition; // mAllowAllocation determines whether dequeueBuffer is allowed to allocate // new buffers diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index 73bc5dd318..415e2a616e 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -211,7 +211,8 @@ private: Dequeue, Attach, }; - status_t waitForFreeSlotThenRelock(FreeSlotCaller caller, int* found) const; + status_t waitForFreeSlotThenRelock(FreeSlotCaller caller, std::unique_lock<std::mutex>& lock, + int* found) const; sp<BufferQueueCore> mCore; @@ -243,15 +244,22 @@ private: // (mCore->mMutex) is held, a ticket is retained by the producer. After // dropping the BufferQueue lock, the producer must wait on the condition // variable until the current callback ticket matches its retained ticket. - Mutex mCallbackMutex; + std::mutex mCallbackMutex; int mNextCallbackTicket; // Protected by mCore->mMutex int mCurrentCallbackTicket; // Protected by mCallbackMutex - Condition mCallbackCondition; + std::condition_variable mCallbackCondition; // Sets how long dequeueBuffer or attachBuffer will block if a buffer or // slot is not yet available. nsecs_t mDequeueTimeout; + // If set to true, dequeueBuffer() is currently waiting for buffer allocation to complete. + bool mDequeueWaitingForAllocation; + + // Condition variable to signal allocateBuffers() that dequeueBuffer() is no longer waiting for + // allocation to complete. + std::condition_variable mDequeueWaitingForAllocationCondition; + }; // class BufferQueueProducer } // namespace android diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 2f538adebc..9f7e22bac5 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -25,6 +25,7 @@ #include <binder/IInterface.h> +#include <ui/BufferQueueDefs.h> #include <ui/Fence.h> #include <ui/GraphicBuffer.h> #include <ui/Rect.h> @@ -75,10 +76,10 @@ public: enum { // A flag returned by dequeueBuffer when the client needs to call // requestBuffer immediately thereafter. - BUFFER_NEEDS_REALLOCATION = 0x1, + BUFFER_NEEDS_REALLOCATION = BufferQueueDefs::BUFFER_NEEDS_REALLOCATION, // A flag returned by dequeueBuffer when all mirrored slots should be // released by the client. This flag should always be processed first. - RELEASE_ALL_BUFFERS = 0x2, + RELEASE_ALL_BUFFERS = BufferQueueDefs::RELEASE_ALL_BUFFERS, }; enum { diff --git a/libs/gui/include/gui/bufferqueue/1.0/Conversion.h b/libs/gui/include/gui/bufferqueue/1.0/Conversion.h new file mode 100644 index 0000000000..627845c0ea --- /dev/null +++ b/libs/gui/include/gui/bufferqueue/1.0/Conversion.h @@ -0,0 +1,765 @@ +/* + * Copyright 2016, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_CONVERSION_H_ +#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_CONVERSION_H_ + +#include <vector> +#include <list> + +#include <unistd.h> + +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> + +#include <binder/Binder.h> +#include <binder/Status.h> +#include <ui/FenceTime.h> +#include <cutils/native_handle.h> +#include <gui/IGraphicBufferProducer.h> + +#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h> + +namespace android { +namespace conversion { + +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_handle; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; +using ::android::status_t; + +using ::android::String8; + +using ::android::hardware::media::V1_0::Rect; +using ::android::hardware::media::V1_0::Region; + +using ::android::hardware::graphics::common::V1_0::Dataspace; + +using ::android::hardware::graphics::common::V1_0::PixelFormat; + +using ::android::hardware::media::V1_0::AnwBuffer; +using ::android::GraphicBuffer; + +typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer + HGraphicBufferProducer; +typedef ::android::IGraphicBufferProducer + BGraphicBufferProducer; + +// native_handle_t helper functions. + +/** + * \brief Take an fd and create a native handle containing only the given fd. + * The created handle will need to be deleted manually with + * `native_handle_delete()`. + * + * \param[in] fd The source file descriptor (of type `int`). + * \return The create `native_handle_t*` that contains the given \p fd. If the + * supplied \p fd is negative, the created native handle will contain no file + * descriptors. + * + * If the native handle cannot be created, the return value will be + * `nullptr`. + * + * This function does not duplicate the file descriptor. + */ +native_handle_t* native_handle_create_from_fd(int fd); + +/** + * \brief Extract a file descriptor from a native handle. + * + * \param[in] nh The source `native_handle_t*`. + * \param[in] index The index of the file descriptor in \p nh to read from. This + * input has the default value of `0`. + * \return The `index`-th file descriptor in \p nh. If \p nh does not have + * enough file descriptors, the returned value will be `-1`. + * + * This function does not duplicate the file descriptor. + */ +int native_handle_read_fd(native_handle_t const* nh, int index = 0); + +/** + * Conversion functions + * ==================== + * + * There are two main directions of conversion: + * - `inTargetType(...)`: Create a wrapper whose lifetime depends on the + * input. The wrapper has type `TargetType`. + * - `toTargetType(...)`: Create a standalone object of type `TargetType` that + * corresponds to the input. The lifetime of the output does not depend on the + * lifetime of the input. + * - `wrapIn(TargetType*, ...)`: Same as `inTargetType()`, but for `TargetType` + * that cannot be copied and/or moved efficiently, or when there are multiple + * output arguments. + * - `convertTo(TargetType*, ...)`: Same as `toTargetType()`, but for + * `TargetType` that cannot be copied and/or moved efficiently, or when there + * are multiple output arguments. + * + * `wrapIn()` and `convertTo()` functions will take output arguments before + * input arguments. Some of these functions might return a value to indicate + * success or error. + * + * In converting or wrapping something as a Treble type that contains a + * `hidl_handle`, `native_handle_t*` will need to be created and returned as + * an additional output argument, hence only `wrapIn()` or `convertTo()` would + * be available. The caller must call `native_handle_delete()` to deallocate the + * returned native handle when it is no longer needed. + * + * For types that contain file descriptors, `inTargetType()` and `wrapAs()` do + * not perform duplication of file descriptors, while `toTargetType()` and + * `convertTo()` do. + */ + +/** + * \brief Convert `Return<void>` to `binder::Status`. + * + * \param[in] t The source `Return<void>`. + * \return The corresponding `binder::Status`. + */ +// convert: Return<void> -> ::android::binder::Status +::android::binder::Status toBinderStatus(Return<void> const& t); + +/** + * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls. + * + * \param[in] t The source `Return<void>`. + * \return The corresponding `status_t`. + */ +// convert: Return<void> -> status_t +status_t toStatusT(Return<void> const& t); + +/** + * \brief Wrap `native_handle_t*` in `hidl_handle`. + * + * \param[in] nh The source `native_handle_t*`. + * \return The `hidl_handle` that points to \p nh. + */ +// wrap: native_handle_t* -> hidl_handle +hidl_handle inHidlHandle(native_handle_t const* nh); + +/** + * \brief Convert `int32_t` to `Dataspace`. + * + * \param[in] l The source `int32_t`. + * \result The corresponding `Dataspace`. + */ +// convert: int32_t -> Dataspace +Dataspace toHardwareDataspace(int32_t l); + +/** + * \brief Convert `Dataspace` to `int32_t`. + * + * \param[in] t The source `Dataspace`. + * \result The corresponding `int32_t`. + */ +// convert: Dataspace -> int32_t +int32_t toRawDataspace(Dataspace const& t); + +/** + * \brief Wrap an opaque buffer inside a `hidl_vec<uint8_t>`. + * + * \param[in] l The pointer to the beginning of the opaque buffer. + * \param[in] size The size of the buffer. + * \return A `hidl_vec<uint8_t>` that points to the buffer. + */ +// wrap: void*, size_t -> hidl_vec<uint8_t> +hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size); + +/** + * \brief Create a `hidl_vec<uint8_t>` that is a copy of an opaque buffer. + * + * \param[in] l The pointer to the beginning of the opaque buffer. + * \param[in] size The size of the buffer. + * \return A `hidl_vec<uint8_t>` that is a copy of the input buffer. + */ +// convert: void*, size_t -> hidl_vec<uint8_t> +hidl_vec<uint8_t> toHidlBytes(void const* l, size_t size); + +/** + * \brief Wrap `GraphicBuffer` in `AnwBuffer`. + * + * \param[out] t The wrapper of type `AnwBuffer`. + * \param[in] l The source `GraphicBuffer`. + */ +// wrap: GraphicBuffer -> AnwBuffer +void wrapAs(AnwBuffer* t, GraphicBuffer const& l); + +/** + * \brief Convert `AnwBuffer` to `GraphicBuffer`. + * + * \param[out] l The destination `GraphicBuffer`. + * \param[in] t The source `AnwBuffer`. + * + * This function will duplicate all file descriptors in \p t. + */ +// convert: AnwBuffer -> GraphicBuffer +// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten +bool convertTo(GraphicBuffer* l, AnwBuffer const& t); + +/** + * Conversion functions for types outside media + * ============================================ + * + * Some objects in libui and libgui that were made to go through binder calls do + * not expose ways to read or write their fields to the public. To pass an + * object of this kind through the HIDL boundary, translation functions need to + * work around the access restriction by using the publicly available + * `flatten()` and `unflatten()` functions. + * + * All `flatten()` and `unflatten()` overloads follow the same convention as + * follows: + * + * status_t flatten(ObjectType const& object, + * [OtherType const& other, ...] + * void*& buffer, size_t& size, + * int*& fds, size_t& numFds) + * + * status_t unflatten(ObjectType* object, + * [OtherType* other, ...,] + * void*& buffer, size_t& size, + * int*& fds, size_t& numFds) + * + * The number of `other` parameters varies depending on the `ObjectType`. For + * example, in the process of unflattening an object that contains + * `hidl_handle`, `other` is needed to hold `native_handle_t` objects that will + * be created. + * + * The last four parameters always work the same way in all overloads of + * `flatten()` and `unflatten()`: + * - For `flatten()`, `buffer` is the pointer to the non-fd buffer to be filled, + * `size` is the size (in bytes) of the non-fd buffer pointed to by `buffer`, + * `fds` is the pointer to the fd buffer to be filled, and `numFds` is the + * size (in ints) of the fd buffer pointed to by `fds`. + * - For `unflatten()`, `buffer` is the pointer to the non-fd buffer to be read + * from, `size` is the size (in bytes) of the non-fd buffer pointed to by + * `buffer`, `fds` is the pointer to the fd buffer to be read from, and + * `numFds` is the size (in ints) of the fd buffer pointed to by `fds`. + * - After a successful call to `flatten()` or `unflatten()`, `buffer` and `fds` + * will be advanced, while `size` and `numFds` will be decreased to reflect + * how much storage/data of the two buffers (fd and non-fd) have been used. + * - After an unsuccessful call, the values of `buffer`, `size`, `fds` and + * `numFds` are invalid. + * + * The return value of a successful `flatten()` or `unflatten()` call will be + * `OK` (also aliased as `NO_ERROR`). Any other values indicate a failure. + * + * For each object type that supports flattening, there will be two accompanying + * functions: `getFlattenedSize()` and `getFdCount()`. `getFlattenedSize()` will + * return the size of the non-fd buffer that the object will need for + * flattening. `getFdCount()` will return the size of the fd buffer that the + * object will need for flattening. + * + * The set of these four functions, `getFlattenedSize()`, `getFdCount()`, + * `flatten()` and `unflatten()`, are similar to functions of the same name in + * the abstract class `Flattenable`. The only difference is that functions in + * this file are not member functions of the object type. For example, we write + * + * flatten(x, buffer, size, fds, numFds) + * + * instead of + * + * x.flatten(buffer, size, fds, numFds) + * + * because we cannot modify the type of `x`. + * + * There is one exception to the naming convention: `hidl_handle` that + * represents a fence. The four functions for this "Fence" type have the word + * "Fence" attched to their names because the object type, which is + * `hidl_handle`, does not carry the special meaning that the object itself can + * only contain zero or one file descriptor. + */ + +// Ref: frameworks/native/libs/ui/Fence.cpp + +/** + * \brief Return the size of the non-fd buffer required to flatten a fence. + * + * \param[in] fence The input fence of type `hidl_handle`. + * \return The required size of the flat buffer. + * + * The current version of this function always returns 4, which is the number of + * bytes required to store the number of file descriptors contained in the fd + * part of the flat buffer. + */ +size_t getFenceFlattenedSize(hidl_handle const& fence); + +/** + * \brief Return the number of file descriptors contained in a fence. + * + * \param[in] fence The input fence of type `hidl_handle`. + * \return `0` if \p fence does not contain a valid file descriptor, or `1` + * otherwise. + */ +size_t getFenceFdCount(hidl_handle const& fence); + +/** + * \brief Unflatten `Fence` to `hidl_handle`. + * + * \param[out] fence The destination `hidl_handle`. + * \param[out] nh The underlying native handle. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * If the return value is `NO_ERROR`, \p nh will point to a newly created + * native handle, which needs to be deleted with `native_handle_delete()` + * afterwards. + */ +status_t unflattenFence(hidl_handle* fence, native_handle_t** nh, + void const*& buffer, size_t& size, int const*& fds, size_t& numFds); + +/** + * \brief Flatten `hidl_handle` as `Fence`. + * + * \param[in] t The source `hidl_handle`. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + */ +status_t flattenFence(hidl_handle const& fence, + void*& buffer, size_t& size, int*& fds, size_t& numFds); + +/** + * \brief Wrap `Fence` in `hidl_handle`. + * + * \param[out] t The wrapper of type `hidl_handle`. + * \param[out] nh The native handle pointed to by \p t. + * \param[in] l The source `Fence`. + * + * On success, \p nh will hold a newly created native handle, which must be + * deleted manually with `native_handle_delete()` afterwards. + */ +// wrap: Fence -> hidl_handle +bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l); + +/** + * \brief Convert `hidl_handle` to `Fence`. + * + * \param[out] l The destination `Fence`. `l` must not have been used + * (`l->isValid()` must return `false`) before this function is called. + * \param[in] t The source `hidl_handle`. + * + * If \p t contains a valid file descriptor, it will be duplicated. + */ +// convert: hidl_handle -> Fence +bool convertTo(Fence* l, hidl_handle const& t); + +// Ref: frameworks/native/libs/ui/FenceTime.cpp: FenceTime::Snapshot + +/** + * \brief Return the size of the non-fd buffer required to flatten + * `FenceTimeSnapshot`. + * + * \param[in] t The input `FenceTimeSnapshot`. + * \return The required size of the flat buffer. + */ +size_t getFlattenedSize(HGraphicBufferProducer::FenceTimeSnapshot const& t); + +/** + * \brief Return the number of file descriptors contained in + * `FenceTimeSnapshot`. + * + * \param[in] t The input `FenceTimeSnapshot`. + * \return The number of file descriptors contained in \p snapshot. + */ +size_t getFdCount(HGraphicBufferProducer::FenceTimeSnapshot const& t); + +/** + * \brief Flatten `FenceTimeSnapshot`. + * + * \param[in] t The source `FenceTimeSnapshot`. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * This function will duplicate the file descriptor in `t.fence` if `t.state == + * FENCE`. + */ +status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t, + void*& buffer, size_t& size, int*& fds, size_t& numFds); + +/** + * \brief Unflatten `FenceTimeSnapshot`. + * + * \param[out] t The destination `FenceTimeSnapshot`. + * \param[out] nh The underlying native handle. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * If the return value is `NO_ERROR` and the constructed snapshot contains a + * file descriptor, \p nh will be created to hold that file descriptor. In this + * case, \p nh needs to be deleted with `native_handle_delete()` afterwards. + */ +status_t unflatten( + HGraphicBufferProducer::FenceTimeSnapshot* t, native_handle_t** nh, + void const*& buffer, size_t& size, int const*& fds, size_t& numFds); + +// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventsDelta + +/** + * \brief Return the size of the non-fd buffer required to flatten + * `FrameEventsDelta`. + * + * \param[in] t The input `FrameEventsDelta`. + * \return The required size of the flat buffer. + */ +size_t getFlattenedSize(HGraphicBufferProducer::FrameEventsDelta const& t); + +/** + * \brief Return the number of file descriptors contained in + * `FrameEventsDelta`. + * + * \param[in] t The input `FrameEventsDelta`. + * \return The number of file descriptors contained in \p t. + */ +size_t getFdCount(HGraphicBufferProducer::FrameEventsDelta const& t); + +/** + * \brief Unflatten `FrameEventsDelta`. + * + * \param[out] t The destination `FrameEventsDelta`. + * \param[out] nh The underlying array of native handles. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * If the return value is `NO_ERROR`, \p nh will have length 4, and it will be + * populated with `nullptr` or newly created handles. Each non-null slot in \p + * nh will need to be deleted manually with `native_handle_delete()`. + */ +status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t, + std::vector<native_handle_t*>* nh, + void const*& buffer, size_t& size, int const*& fds, size_t& numFds); + +/** + * \brief Flatten `FrameEventsDelta`. + * + * \param[in] t The source `FrameEventsDelta`. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * This function will duplicate file descriptors contained in \p t. + */ +// Ref: frameworks/native/libs/gui/FrameTimestamp.cpp: +// FrameEventsDelta::flatten +status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t, + void*& buffer, size_t& size, int*& fds, size_t numFds); + +// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventHistoryDelta + +/** + * \brief Return the size of the non-fd buffer required to flatten + * `HGraphicBufferProducer::FrameEventHistoryDelta`. + * + * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`. + * \return The required size of the flat buffer. + */ +size_t getFlattenedSize( + HGraphicBufferProducer::FrameEventHistoryDelta const& t); + +/** + * \brief Return the number of file descriptors contained in + * `HGraphicBufferProducer::FrameEventHistoryDelta`. + * + * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`. + * \return The number of file descriptors contained in \p t. + */ +size_t getFdCount( + HGraphicBufferProducer::FrameEventHistoryDelta const& t); + +/** + * \brief Unflatten `FrameEventHistoryDelta`. + * + * \param[out] t The destination `FrameEventHistoryDelta`. + * \param[out] nh The underlying array of arrays of native handles. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * If the return value is `NO_ERROR`, \p nh will be populated with `nullptr` or + * newly created handles. The second dimension of \p nh will be 4. Each non-null + * slot in \p nh will need to be deleted manually with `native_handle_delete()`. + */ +status_t unflatten( + HGraphicBufferProducer::FrameEventHistoryDelta* t, + std::vector<std::vector<native_handle_t*> >* nh, + void const*& buffer, size_t& size, int const*& fds, size_t& numFds); + +/** + * \brief Flatten `FrameEventHistoryDelta`. + * + * \param[in] t The source `FrameEventHistoryDelta`. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * This function will duplicate file descriptors contained in \p t. + */ +status_t flatten( + HGraphicBufferProducer::FrameEventHistoryDelta const& t, + void*& buffer, size_t& size, int*& fds, size_t& numFds); + +/** + * \brief Wrap `::android::FrameEventHistoryData` in + * `HGraphicBufferProducer::FrameEventHistoryDelta`. + * + * \param[out] t The wrapper of type + * `HGraphicBufferProducer::FrameEventHistoryDelta`. + * \param[out] nh The array of array of native handles that are referred to by + * members of \p t. + * \param[in] l The source `::android::FrameEventHistoryDelta`. + * + * On success, each member of \p nh will be either `nullptr` or a newly created + * native handle. All the non-`nullptr` elements must be deleted individually + * with `native_handle_delete()`. + */ +bool wrapAs(HGraphicBufferProducer::FrameEventHistoryDelta* t, + std::vector<std::vector<native_handle_t*> >* nh, + ::android::FrameEventHistoryDelta const& l); + +/** + * \brief Convert `HGraphicBufferProducer::FrameEventHistoryDelta` to + * `::android::FrameEventHistoryDelta`. + * + * \param[out] l The destination `::android::FrameEventHistoryDelta`. + * \param[in] t The source `HGraphicBufferProducer::FrameEventHistoryDelta`. + * + * This function will duplicate all file descriptors contained in \p t. + */ +bool convertTo( + ::android::FrameEventHistoryDelta* l, + HGraphicBufferProducer::FrameEventHistoryDelta const& t); + +// Ref: frameworks/native/libs/ui/Region.cpp + +/** + * \brief Return the size of the buffer required to flatten `Region`. + * + * \param[in] t The input `Region`. + * \return The required size of the flat buffer. + */ +size_t getFlattenedSize(Region const& t); + +/** + * \brief Unflatten `Region`. + * + * \param[out] t The destination `Region`. + * \param[in,out] buffer The pointer to the flat buffer. + * \param[in,out] size The size of the flat buffer. + * \return `NO_ERROR` on success; other value on failure. + */ +status_t unflatten(Region* t, void const*& buffer, size_t& size); + +/** + * \brief Flatten `Region`. + * + * \param[in] t The source `Region`. + * \param[in,out] buffer The pointer to the flat buffer. + * \param[in,out] size The size of the flat buffer. + * \return `NO_ERROR` on success; other value on failure. + */ +status_t flatten(Region const& t, void*& buffer, size_t& size); + +/** + * \brief Convert `::android::Region` to `Region`. + * + * \param[out] t The destination `Region`. + * \param[in] l The source `::android::Region`. + */ +// convert: ::android::Region -> Region +bool convertTo(Region* t, ::android::Region const& l); + +/** + * \brief Convert `Region` to `::android::Region`. + * + * \param[out] l The destination `::android::Region`. + * \param[in] t The source `Region`. + */ +// convert: Region -> ::android::Region +bool convertTo(::android::Region* l, Region const& t); + +// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp: +// BGraphicBufferProducer::QueueBufferInput + +/** + * \brief Return the size of the buffer required to flatten + * `HGraphicBufferProducer::QueueBufferInput`. + * + * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`. + * \return The required size of the flat buffer. + */ +size_t getFlattenedSize(HGraphicBufferProducer::QueueBufferInput const& t); + +/** + * \brief Return the number of file descriptors contained in + * `HGraphicBufferProducer::QueueBufferInput`. + * + * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`. + * \return The number of file descriptors contained in \p t. + */ +size_t getFdCount( + HGraphicBufferProducer::QueueBufferInput const& t); +/** + * \brief Flatten `HGraphicBufferProducer::QueueBufferInput`. + * + * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`. + * \param[out] nh The native handle cloned from `t.fence`. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * This function will duplicate the file descriptor in `t.fence`. */ +status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t, + native_handle_t** nh, + void*& buffer, size_t& size, int*& fds, size_t& numFds); + +/** + * \brief Unflatten `HGraphicBufferProducer::QueueBufferInput`. + * + * \param[out] t The destination `HGraphicBufferProducer::QueueBufferInput`. + * \param[out] nh The underlying native handle for `t->fence`. + * \param[in,out] buffer The pointer to the flat non-fd buffer. + * \param[in,out] size The size of the flat non-fd buffer. + * \param[in,out] fds The pointer to the flat fd buffer. + * \param[in,out] numFds The size of the flat fd buffer. + * \return `NO_ERROR` on success; other value on failure. + * + * If the return value is `NO_ERROR` and `t->fence` contains a valid file + * descriptor, \p nh will be a newly created native handle holding that file + * descriptor. \p nh needs to be deleted with `native_handle_delete()` + * afterwards. + */ +status_t unflatten( + HGraphicBufferProducer::QueueBufferInput* t, native_handle_t** nh, + void const*& buffer, size_t& size, int const*& fds, size_t& numFds); + +/** + * \brief Wrap `BGraphicBufferProducer::QueueBufferInput` in + * `HGraphicBufferProducer::QueueBufferInput`. + * + * \param[out] t The wrapper of type + * `HGraphicBufferProducer::QueueBufferInput`. + * \param[out] nh The underlying native handle for `t->fence`. + * \param[in] l The source `BGraphicBufferProducer::QueueBufferInput`. + * + * If the return value is `true` and `t->fence` contains a valid file + * descriptor, \p nh will be a newly created native handle holding that file + * descriptor. \p nh needs to be deleted with `native_handle_delete()` + * afterwards. + */ +bool wrapAs( + HGraphicBufferProducer::QueueBufferInput* t, + native_handle_t** nh, + BGraphicBufferProducer::QueueBufferInput const& l); + +/** + * \brief Convert `HGraphicBufferProducer::QueueBufferInput` to + * `BGraphicBufferProducer::QueueBufferInput`. + * + * \param[out] l The destination `BGraphicBufferProducer::QueueBufferInput`. + * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`. + * + * If `t.fence` has a valid file descriptor, it will be duplicated. + */ +bool convertTo( + BGraphicBufferProducer::QueueBufferInput* l, + HGraphicBufferProducer::QueueBufferInput const& t); + +// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp: +// BGraphicBufferProducer::QueueBufferOutput + +/** + * \brief Wrap `BGraphicBufferProducer::QueueBufferOutput` in + * `HGraphicBufferProducer::QueueBufferOutput`. + * + * \param[out] t The wrapper of type + * `HGraphicBufferProducer::QueueBufferOutput`. + * \param[out] nh The array of array of native handles that are referred to by + * members of \p t. + * \param[in] l The source `BGraphicBufferProducer::QueueBufferOutput`. + * + * On success, each member of \p nh will be either `nullptr` or a newly created + * native handle. All the non-`nullptr` elements must be deleted individually + * with `native_handle_delete()`. + */ +// wrap: BGraphicBufferProducer::QueueBufferOutput -> +// HGraphicBufferProducer::QueueBufferOutput +bool wrapAs(HGraphicBufferProducer::QueueBufferOutput* t, + std::vector<std::vector<native_handle_t*> >* nh, + BGraphicBufferProducer::QueueBufferOutput const& l); + +/** + * \brief Convert `HGraphicBufferProducer::QueueBufferOutput` to + * `BGraphicBufferProducer::QueueBufferOutput`. + * + * \param[out] l The destination `BGraphicBufferProducer::QueueBufferOutput`. + * \param[in] t The source `HGraphicBufferProducer::QueueBufferOutput`. + * + * This function will duplicate all file descriptors contained in \p t. + */ +// convert: HGraphicBufferProducer::QueueBufferOutput -> +// BGraphicBufferProducer::QueueBufferOutput +bool convertTo( + BGraphicBufferProducer::QueueBufferOutput* l, + HGraphicBufferProducer::QueueBufferOutput const& t); + +/** + * \brief Convert `BGraphicBufferProducer::DisconnectMode` to + * `HGraphicBufferProducer::DisconnectMode`. + * + * \param[in] l The source `BGraphicBufferProducer::DisconnectMode`. + * \return The corresponding `HGraphicBufferProducer::DisconnectMode`. + */ +HGraphicBufferProducer::DisconnectMode toHidlDisconnectMode( + BGraphicBufferProducer::DisconnectMode l); + +/** + * \brief Convert `HGraphicBufferProducer::DisconnectMode` to + * `BGraphicBufferProducer::DisconnectMode`. + * + * \param[in] l The source `HGraphicBufferProducer::DisconnectMode`. + * \return The corresponding `BGraphicBufferProducer::DisconnectMode`. + */ +BGraphicBufferProducer::DisconnectMode toGuiDisconnectMode( + HGraphicBufferProducer::DisconnectMode t); + +} // namespace conversion +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_CONVERSION_H_ diff --git a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h new file mode 100644 index 0000000000..0e57f208f8 --- /dev/null +++ b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h @@ -0,0 +1,380 @@ +/* + * Copyright 2016, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_WGRAPHICBUFFERPRODUCER_H_ +#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_WGRAPHICBUFFERPRODUCER_H_ + +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> + +#include <binder/Binder.h> +#include <gui/IGraphicBufferProducer.h> +#include <gui/IProducerListener.h> +#include <gui/bufferqueue/1.0/Conversion.h> +#include <gui/bufferqueue/1.0/WProducerListener.h> +#include <system/window.h> + +#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h> + +namespace android { + +using ::android::hardware::media::V1_0::AnwBuffer; +using ::android::hidl::base::V1_0::IBase; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +typedef ::android::hardware::graphics::bufferqueue::V1_0:: + IGraphicBufferProducer HGraphicBufferProducer; +typedef ::android::hardware::graphics::bufferqueue::V1_0:: + IProducerListener HProducerListener; + +typedef ::android::IGraphicBufferProducer BGraphicBufferProducer; +typedef ::android::IProducerListener BProducerListener; +using ::android::BnGraphicBufferProducer; + +#ifndef LOG +struct LOG_dummy { + template <typename T> + LOG_dummy& operator<< (const T&) { return *this; } +}; + +#define LOG(x) LOG_dummy() +#endif + +// Instantiate only if HGraphicBufferProducer is base of BASE. +template <typename BASE, + typename = typename std::enable_if<std::is_base_of<HGraphicBufferProducer, BASE>::value>::type> +struct TWGraphicBufferProducer : public BASE { + TWGraphicBufferProducer(sp<BGraphicBufferProducer> const& base) : mBase(base) {} + Return<void> requestBuffer(int32_t slot, HGraphicBufferProducer::requestBuffer_cb _hidl_cb) override { + sp<GraphicBuffer> buf; + status_t status = mBase->requestBuffer(slot, &buf); + AnwBuffer anwBuffer; + if (buf != nullptr) { + ::android::conversion::wrapAs(&anwBuffer, *buf); + } + _hidl_cb(static_cast<int32_t>(status), anwBuffer); + return Void(); + } + + Return<int32_t> setMaxDequeuedBufferCount(int32_t maxDequeuedBuffers) override { + return static_cast<int32_t>(mBase->setMaxDequeuedBufferCount( + static_cast<int>(maxDequeuedBuffers))); + } + + Return<int32_t> setAsyncMode(bool async) override { + return static_cast<int32_t>(mBase->setAsyncMode(async)); + } + + Return<void> dequeueBuffer( + uint32_t width, uint32_t height, + ::android::hardware::graphics::common::V1_0::PixelFormat format, uint32_t usage, + bool getFrameTimestamps, HGraphicBufferProducer::dequeueBuffer_cb _hidl_cb) override { + int slot; + sp<Fence> fence; + ::android::FrameEventHistoryDelta outTimestamps; + status_t status = mBase->dequeueBuffer( + &slot, &fence, width, height, + static_cast<::android::PixelFormat>(format), usage, nullptr, + getFrameTimestamps ? &outTimestamps : nullptr); + hidl_handle tFence; + HGraphicBufferProducer::FrameEventHistoryDelta tOutTimestamps; + + native_handle_t* nh = nullptr; + if ((fence == nullptr) || !::android::conversion::wrapAs(&tFence, &nh, *fence)) { + LOG(ERROR) << "TWGraphicBufferProducer::dequeueBuffer - " + "Invalid output fence"; + _hidl_cb(static_cast<int32_t>(status), + static_cast<int32_t>(slot), + tFence, + tOutTimestamps); + return Void(); + } + std::vector<std::vector<native_handle_t*> > nhAA; + if (getFrameTimestamps && !::android::conversion::wrapAs(&tOutTimestamps, &nhAA, outTimestamps)) { + LOG(ERROR) << "TWGraphicBufferProducer::dequeueBuffer - " + "Invalid output timestamps"; + _hidl_cb(static_cast<int32_t>(status), + static_cast<int32_t>(slot), + tFence, + tOutTimestamps); + native_handle_delete(nh); + return Void(); + } + + _hidl_cb(static_cast<int32_t>(status), + static_cast<int32_t>(slot), + tFence, + tOutTimestamps); + native_handle_delete(nh); + if (getFrameTimestamps) { + for (auto& nhA : nhAA) { + for (auto& handle : nhA) { + native_handle_delete(handle); + } + } + } + return Void(); + } + + Return<int32_t> detachBuffer(int32_t slot) override { + return static_cast<int32_t>(mBase->detachBuffer(slot)); + } + + Return<void> detachNextBuffer(HGraphicBufferProducer::detachNextBuffer_cb _hidl_cb) override { + sp<GraphicBuffer> outBuffer; + sp<Fence> outFence; + status_t status = mBase->detachNextBuffer(&outBuffer, &outFence); + AnwBuffer tBuffer; + hidl_handle tFence; + + if (outBuffer == nullptr) { + LOG(ERROR) << "TWGraphicBufferProducer::detachNextBuffer - " + "Invalid output buffer"; + _hidl_cb(static_cast<int32_t>(status), tBuffer, tFence); + return Void(); + } + ::android::conversion::wrapAs(&tBuffer, *outBuffer); + native_handle_t* nh = nullptr; + if ((outFence != nullptr) && !::android::conversion::wrapAs(&tFence, &nh, *outFence)) { + LOG(ERROR) << "TWGraphicBufferProducer::detachNextBuffer - " + "Invalid output fence"; + _hidl_cb(static_cast<int32_t>(status), tBuffer, tFence); + return Void(); + } + + _hidl_cb(static_cast<int32_t>(status), tBuffer, tFence); + native_handle_delete(nh); + return Void(); + } + + Return<void> attachBuffer(const AnwBuffer& buffer, HGraphicBufferProducer::attachBuffer_cb _hidl_cb) override { + int outSlot; + sp<GraphicBuffer> lBuffer = new GraphicBuffer(); + if (!::android::conversion::convertTo(lBuffer.get(), buffer)) { + LOG(ERROR) << "TWGraphicBufferProducer::attachBuffer - " + "Invalid input native window buffer"; + _hidl_cb(static_cast<int32_t>(BAD_VALUE), -1); + return Void(); + } + status_t status = mBase->attachBuffer(&outSlot, lBuffer); + + _hidl_cb(static_cast<int32_t>(status), static_cast<int32_t>(outSlot)); + return Void(); + } + + Return<void> queueBuffer( + int32_t slot, const HGraphicBufferProducer::QueueBufferInput& input, + HGraphicBufferProducer::queueBuffer_cb _hidl_cb) override { + HGraphicBufferProducer::QueueBufferOutput tOutput; + BGraphicBufferProducer::QueueBufferInput lInput( + 0, false, HAL_DATASPACE_UNKNOWN, + ::android::Rect(0, 0, 1, 1), + NATIVE_WINDOW_SCALING_MODE_FREEZE, + 0, ::android::Fence::NO_FENCE); + if (!::android::conversion::convertTo(&lInput, input)) { + LOG(ERROR) << "TWGraphicBufferProducer::queueBuffer - " + "Invalid input"; + _hidl_cb(static_cast<int32_t>(BAD_VALUE), tOutput); + return Void(); + } + BGraphicBufferProducer::QueueBufferOutput lOutput; + status_t status = mBase->queueBuffer( + static_cast<int>(slot), lInput, &lOutput); + + std::vector<std::vector<native_handle_t*> > nhAA; + if (!::android::conversion::wrapAs(&tOutput, &nhAA, lOutput)) { + LOG(ERROR) << "TWGraphicBufferProducer::queueBuffer - " + "Invalid output"; + _hidl_cb(static_cast<int32_t>(BAD_VALUE), tOutput); + return Void(); + } + + _hidl_cb(static_cast<int32_t>(status), tOutput); + for (auto& nhA : nhAA) { + for (auto& nh : nhA) { + native_handle_delete(nh); + } + } + return Void(); + } + + Return<int32_t> cancelBuffer(int32_t slot, const hidl_handle& fence) override { + sp<Fence> lFence = new Fence(); + if (!::android::conversion::convertTo(lFence.get(), fence)) { + LOG(ERROR) << "TWGraphicBufferProducer::cancelBuffer - " + "Invalid input fence"; + return static_cast<int32_t>(BAD_VALUE); + } + return static_cast<int32_t>(mBase->cancelBuffer(static_cast<int>(slot), lFence)); + } + + Return<void> query(int32_t what, HGraphicBufferProducer::query_cb _hidl_cb) override { + int lValue; + int lReturn = mBase->query(static_cast<int>(what), &lValue); + _hidl_cb(static_cast<int32_t>(lReturn), static_cast<int32_t>(lValue)); + return Void(); + } + + Return<void> connect(const sp<HProducerListener>& listener, + int32_t api, bool producerControlledByApp, + HGraphicBufferProducer::connect_cb _hidl_cb) override { + sp<BProducerListener> lListener = listener == nullptr ? + nullptr : new LWProducerListener(listener); + BGraphicBufferProducer::QueueBufferOutput lOutput; + status_t status = mBase->connect(lListener, + static_cast<int>(api), + producerControlledByApp, + &lOutput); + + HGraphicBufferProducer::QueueBufferOutput tOutput; + std::vector<std::vector<native_handle_t*> > nhAA; + if (!::android::conversion::wrapAs(&tOutput, &nhAA, lOutput)) { + LOG(ERROR) << "TWGraphicBufferProducer::connect - " + "Invalid output"; + _hidl_cb(static_cast<int32_t>(status), tOutput); + return Void(); + } + + _hidl_cb(static_cast<int32_t>(status), tOutput); + for (auto& nhA : nhAA) { + for (auto& nh : nhA) { + native_handle_delete(nh); + } + } + return Void(); + } + + Return<int32_t> disconnect( + int32_t api, + HGraphicBufferProducer::DisconnectMode mode) override { + return static_cast<int32_t>(mBase->disconnect( + static_cast<int>(api), + ::android::conversion::toGuiDisconnectMode(mode))); + } + + Return<int32_t> setSidebandStream(const hidl_handle& stream) override { + return static_cast<int32_t>(mBase->setSidebandStream(NativeHandle::create( + stream ? native_handle_clone(stream) : NULL, true))); + } + + Return<void> allocateBuffers( + uint32_t width, uint32_t height, + ::android::hardware::graphics::common::V1_0::PixelFormat format, + uint32_t usage) override { + mBase->allocateBuffers( + width, height, + static_cast<::android::PixelFormat>(format), + usage); + return Void(); + } + + Return<int32_t> allowAllocation(bool allow) override { + return static_cast<int32_t>(mBase->allowAllocation(allow)); + } + + Return<int32_t> setGenerationNumber(uint32_t generationNumber) override { + return static_cast<int32_t>(mBase->setGenerationNumber(generationNumber)); + } + + Return<void> getConsumerName(HGraphicBufferProducer::getConsumerName_cb _hidl_cb) override { + _hidl_cb(mBase->getConsumerName().string()); + return Void(); + } + + Return<int32_t> setSharedBufferMode(bool sharedBufferMode) override { + return static_cast<int32_t>(mBase->setSharedBufferMode(sharedBufferMode)); + } + + Return<int32_t> setAutoRefresh(bool autoRefresh) override { + return static_cast<int32_t>(mBase->setAutoRefresh(autoRefresh)); + } + + Return<int32_t> setDequeueTimeout(int64_t timeoutNs) override { + return static_cast<int32_t>(mBase->setDequeueTimeout(timeoutNs)); + } + + Return<void> getLastQueuedBuffer(HGraphicBufferProducer::getLastQueuedBuffer_cb _hidl_cb) override { + sp<GraphicBuffer> lOutBuffer = new GraphicBuffer(); + sp<Fence> lOutFence = new Fence(); + float lOutTransformMatrix[16]; + status_t status = mBase->getLastQueuedBuffer( + &lOutBuffer, &lOutFence, lOutTransformMatrix); + + AnwBuffer tOutBuffer; + if (lOutBuffer != nullptr) { + ::android::conversion::wrapAs(&tOutBuffer, *lOutBuffer); + } + hidl_handle tOutFence; + native_handle_t* nh = nullptr; + if ((lOutFence == nullptr) || !::android::conversion::wrapAs(&tOutFence, &nh, *lOutFence)) { + LOG(ERROR) << "TWGraphicBufferProducer::getLastQueuedBuffer - " + "Invalid output fence"; + _hidl_cb(static_cast<int32_t>(status), + tOutBuffer, + tOutFence, + hidl_array<float, 16>()); + return Void(); + } + hidl_array<float, 16> tOutTransformMatrix(lOutTransformMatrix); + + _hidl_cb(static_cast<int32_t>(status), tOutBuffer, tOutFence, tOutTransformMatrix); + native_handle_delete(nh); + return Void(); + } + + Return<void> getFrameTimestamps(HGraphicBufferProducer::getFrameTimestamps_cb _hidl_cb) override { + ::android::FrameEventHistoryDelta lDelta; + mBase->getFrameTimestamps(&lDelta); + + HGraphicBufferProducer::FrameEventHistoryDelta tDelta; + std::vector<std::vector<native_handle_t*> > nhAA; + if (!::android::conversion::wrapAs(&tDelta, &nhAA, lDelta)) { + LOG(ERROR) << "TWGraphicBufferProducer::getFrameTimestamps - " + "Invalid output frame timestamps"; + _hidl_cb(tDelta); + return Void(); + } + + _hidl_cb(tDelta); + for (auto& nhA : nhAA) { + for (auto& nh : nhA) { + native_handle_delete(nh); + } + } + return Void(); + } + + Return<void> getUniqueId(HGraphicBufferProducer::getUniqueId_cb _hidl_cb) override { + uint64_t outId; + status_t status = mBase->getUniqueId(&outId); + _hidl_cb(static_cast<int32_t>(status), outId); + return Void(); + } + +private: + sp<BGraphicBufferProducer> mBase; +}; + +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_WGRAPHICBUFFERPRODUCER_H_ diff --git a/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h new file mode 100644 index 0000000000..51dff5b8be --- /dev/null +++ b/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h @@ -0,0 +1,62 @@ +/* + * Copyright 2016, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_WPRODUCERLISTENER_H_ +#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_WPRODUCERLISTENER_H_ + +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> + +#include <binder/IBinder.h> +#include <gui/IProducerListener.h> + +#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h> + +namespace android { + +using ::android::hidl::base::V1_0::IBase; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +typedef ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener + HProducerListener; +typedef ::android::IProducerListener + BProducerListener; +using ::android::BnProducerListener; + +struct TWProducerListener : public HProducerListener { + sp<BProducerListener> mBase; + TWProducerListener(sp<BProducerListener> const& base); + Return<void> onBufferReleased() override; + Return<bool> needsReleaseNotify() override; +}; + +class LWProducerListener : public BnProducerListener { +public: + sp<HProducerListener> mBase; + LWProducerListener(sp<HProducerListener> const& base); + void onBufferReleased() override; + bool needsReleaseNotify() override; +}; + +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_WPRODUCERLISTENER_H_ diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index e13b40ef24..2a5a6048ed 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -27,12 +27,16 @@ #include <sys/types.h> #include <unistd.h> +#include <android-base/stringprintf.h> +#include <binder/Parcel.h> #include <cutils/properties.h> #include <log/log.h> +#include <utils/Trace.h> -#include <binder/Parcel.h> #include <input/InputTransport.h> +using android::base::StringPrintf; + namespace android { // Socket buffer size. The default is typically about 128KB, which is much larger than @@ -420,6 +424,11 @@ status_t InputPublisher::publishKeyEvent( int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime) { + if (ATRACE_ENABLED()) { + std::string message = StringPrintf("publishKeyEvent(inputChannel=%s, keyCode=%" PRId32 ")", + mChannel->getName().c_str(), keyCode); + ATRACE_NAME(message.c_str()); + } #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, " "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d," @@ -472,6 +481,12 @@ status_t InputPublisher::publishMotionEvent( uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { + if (ATRACE_ENABLED()) { + std::string message = StringPrintf( + "publishMotionEvent(inputChannel=%s, action=%" PRId32 ")", + mChannel->getName().c_str(), action); + ATRACE_NAME(message.c_str()); + } #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, " "displayId=%" PRId32 ", " diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index d0127b8178..faf6d2a824 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -248,7 +248,8 @@ std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(int hwcFormat, uint32 bool useContextPriority = extensions.hasContextPriority() && (featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT); EGLContext protectedContext = EGL_NO_CONTEXT; - if (extensions.hasProtectedContent()) { + if ((featureFlags & RenderEngine::ENABLE_PROTECTED_CONTEXT) && + extensions.hasProtectedContent()) { protectedContext = createEglContext(display, config, nullptr, useContextPriority, Protection::PROTECTED); ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context"); @@ -743,6 +744,9 @@ void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display, // We separate the layer into 3 parts essentially, such that we only turn on blending for the // top rectangle and the bottom rectangle, and turn off blending for the middle rectangle. FloatRect bounds = layer.geometry.roundedCornersCrop; + + // Firstly, we need to convert the coordination from layer native coordination space to + // device coordination space. const auto transformMatrix = display.globalTransform * layer.geometry.positionTransform; const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0); const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0); @@ -750,8 +754,28 @@ void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display, const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate; bounds = FloatRect(leftTopCoordinateInBuffer[0], leftTopCoordinateInBuffer[1], rightBottomCoordinateInBuffer[0], rightBottomCoordinateInBuffer[1]); - const int32_t radius = ceil(layer.geometry.roundedCornersRadius); + // Secondly, if the display is rotated, we need to undo the rotation on coordination and + // align the (left, top) and (right, bottom) coordination with the device coordination + // space. + switch (display.orientation) { + case ui::Transform::ROT_90: + std::swap(bounds.left, bounds.right); + break; + case ui::Transform::ROT_180: + std::swap(bounds.left, bounds.right); + std::swap(bounds.top, bounds.bottom); + break; + case ui::Transform::ROT_270: + std::swap(bounds.top, bounds.bottom); + break; + default: + break; + } + + // Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners + // and the middle part without rounded corners. + const int32_t radius = ceil(layer.geometry.roundedCornersRadius); const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius); setScissor(topRect); drawMesh(mesh); diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index af8de2363c..9c9884a35c 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -20,6 +20,7 @@ #include <ui/GraphicTypes.h> #include <ui/Rect.h> #include <ui/Region.h> +#include <ui/Transform.h> namespace android { namespace renderengine { @@ -56,6 +57,9 @@ struct DisplaySettings { // globalTransform, so that it will be in the same coordinate space as the // rendered layers. Region clearRegion = Region::INVALID_REGION; + + // The orientation of the physical display. + uint32_t orientation = ui::Transform::ROT_0; }; } // namespace renderengine diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index bf614fd055..e7070041f2 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -63,6 +63,9 @@ public: enum FeatureFlag { USE_COLOR_MANAGEMENT = 1 << 0, // Device manages color USE_HIGH_PRIORITY_CONTEXT = 1 << 1, // Use high priority context + + // Create a protected context when if possible + ENABLE_PROTECTED_CONTEXT = 1 << 2, }; static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags, diff --git a/libs/ui/include/ui/BufferQueueDefs.h b/libs/ui/include/ui/BufferQueueDefs.h index 56de181bca..0fecda9cf1 100644 --- a/libs/ui/include/ui/BufferQueueDefs.h +++ b/libs/ui/include/ui/BufferQueueDefs.h @@ -23,6 +23,16 @@ namespace android { // Attempts at runtime to increase the number of buffers past this // will fail. static constexpr int NUM_BUFFER_SLOTS = 64; + + enum { + // A flag returned by dequeueBuffer when the client needs to call + // requestBuffer immediately thereafter. + BUFFER_NEEDS_REALLOCATION = 0x1, + // A flag returned by dequeueBuffer when all mirrored slots should be + // released by the client. This flag should always be processed first. + RELEASE_ALL_BUFFERS = 0x2, + }; + } // namespace BufferQueueDefs } // namespace android diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index 54fa89feda..12947b241c 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -340,6 +340,17 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { mVersionString = sVersionString15; cnx->driverVersion = EGL_MAKE_VERSION(1, 5, 0); } else if ((cnx->major == 1) && (cnx->minor == 4)) { + /* Querying extension strings for type Client */ + std::string typesExtString; + static const char* clientExtensions = + cnx->egl.eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (clientExtensions != nullptr && strlen(clientExtensions) > 0) { + typesExtString.append(clientExtensions); + typesExtString.append(" "); + } + + /* Adding extension strings for type Display */ + typesExtString.append(disp.queryString.extensions); mVersionString = sVersionString14; // Extensions needed for an EGL 1.4 implementation to be // able to support EGL 1.5 functionality @@ -356,9 +367,9 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { }; bool extensionsFound = true; for (const auto& name : egl15extensions) { - extensionsFound &= findExtension(disp.queryString.extensions, name); + extensionsFound &= findExtension(typesExtString.c_str(), name); ALOGV("Extension %s: %s", name, - findExtension(disp.queryString.extensions, name) ? "Found" : "Missing"); + findExtension(typesExtString.c_str(), name) ? "Found" : "Missing"); } // NOTE: From the spec: // Creation of fence sync objects requires support from the bound diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 0d5bc15577..2549d9b3f0 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -17,7 +17,7 @@ #define LOG_TAG "InputDispatcher" #define ATRACE_TAG ATRACE_TAG_INPUT -//#define LOG_NDEBUG 0 +#define LOG_NDEBUG 0 // Log detailed debug messages about each inbound event notification to the dispatcher. #define DEBUG_INBOUND_EVENT_DETAILS 0 @@ -58,7 +58,6 @@ #include <log/log.h> #include <utils/Trace.h> #include <powermanager/PowerManager.h> -#include <ui/Region.h> #include <binder/Binder.h> #define INDENT " " @@ -129,7 +128,7 @@ static std::string motionActionToString(int32_t action) { static std::string keyActionToString(int32_t action) { // Convert KeyEvent action to string - switch(action) { + switch (action) { case AKEY_EVENT_ACTION_DOWN: return "DOWN"; case AKEY_EVENT_ACTION_UP: @@ -140,6 +139,24 @@ static std::string keyActionToString(int32_t action) { return StringPrintf("%" PRId32, action); } +static std::string dispatchModeToString(int32_t dispatchMode) { + switch (dispatchMode) { + case InputTarget::FLAG_DISPATCH_AS_IS: + return "DISPATCH_AS_IS"; + case InputTarget::FLAG_DISPATCH_AS_OUTSIDE: + return "DISPATCH_AS_OUTSIDE"; + case InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER: + return "DISPATCH_AS_HOVER_ENTER"; + case InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT: + return "DISPATCH_AS_HOVER_EXIT"; + case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT: + return "DISPATCH_AS_SLIPPERY_EXIT"; + case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER: + return "DISPATCH_AS_SLIPPERY_ENTER"; + } + return StringPrintf("%" PRId32, dispatchMode); +} + static inline int32_t getMotionEventActionPointerIndex(int32_t action) { return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; @@ -560,6 +577,32 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display return nullptr; } +std::vector<InputDispatcher::TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked( + int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) { + std::vector<TouchedMonitor> touchedMonitors; + + std::vector<Monitor> monitors = getValueByKey(mGestureMonitorsByDisplay, displayId); + addGestureMonitors(monitors, touchedMonitors); + for (const sp<InputWindowHandle>& portalWindow : portalWindows) { + const InputWindowInfo* windowInfo = portalWindow->getInfo(); + monitors = getValueByKey(mGestureMonitorsByDisplay, windowInfo->portalToDisplayId); + addGestureMonitors(monitors, touchedMonitors, + -windowInfo->frameLeft, -windowInfo->frameTop); + } + return touchedMonitors; +} + +void InputDispatcher::addGestureMonitors(const std::vector<Monitor>& monitors, + std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset, float yOffset) { + if (monitors.empty()) { + return; + } + outTouchedMonitors.reserve(monitors.size() + outTouchedMonitors.size()); + for (const Monitor& monitor : monitors) { + outTouchedMonitors.emplace_back(monitor, xOffset, yOffset); + } +} + void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { const char* reason; switch (dropReason) { @@ -870,7 +913,7 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, } // Add monitor channels from event's or focused display. - addMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry)); + addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry)); // Dispatch the key. dispatchEventLocked(currentTime, entry, inputTargets); @@ -891,6 +934,7 @@ void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry* bool InputDispatcher::dispatchMotionLocked( nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { + ATRACE_CALL(); // Preprocessing. if (! entry->dispatchInProgress) { entry->dispatchInProgress = true; @@ -938,7 +982,7 @@ bool InputDispatcher::dispatchMotionLocked( } // Add monitor channels from event's or focused display. - addMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry)); + addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry)); if (isPointerEvent) { ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(entry->displayId); @@ -949,7 +993,7 @@ bool InputDispatcher::dispatchMotionLocked( // the corresponding displays as well. for (size_t i = 0; i < state.portalWindows.size(); i++) { const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo(); - addMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId, + addGlobalMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId, -windowInfo->frameLeft, -windowInfo->frameTop); } } @@ -1003,6 +1047,7 @@ void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionE void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, const std::vector<InputTarget>& inputTargets) { + ATRACE_CALL(); #if DEBUG_DISPATCH_CYCLE ALOGD("dispatchEventToCurrentInputTargets"); #endif @@ -1242,6 +1287,7 @@ Unresponsive: int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) { + ATRACE_CALL(); enum InjectionPermission { INJECTION_PERMISSION_UNKNOWN, INJECTION_PERMISSION_GRANTED, @@ -1320,8 +1366,13 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(entry->pointerCoords[pointerIndex]. getAxisValue(AMOTION_EVENT_AXIS_Y)); + bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN; sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked( - displayId, x, y, maskedAction == AMOTION_EVENT_ACTION_DOWN, true); + displayId, x, y, isDown /*addOutsideTargets*/, true /*addPortalWindows*/); + + std::vector<TouchedMonitor> newGestureMonitors = isDown + ? findTouchedGestureMonitorsLocked(displayId, mTempTouchState.portalWindows) + : std::vector<TouchedMonitor>{}; // Figure out whether splitting will be allowed for this window. if (newTouchedWindowHandle != nullptr @@ -1338,39 +1389,44 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (newTouchedWindowHandle == nullptr) { // Try to assign the pointer to the first foreground window we find, if there is one. newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); - if (newTouchedWindowHandle == nullptr) { - ALOGI("Dropping event because there is no touchable window at (%d, %d) in display " - "%" PRId32 ".", x, y, displayId); - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } } - // Set target flags. - int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS; - if (isSplit) { - targetFlags |= InputTarget::FLAG_SPLIT; - } - if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { - targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; - } else if (isWindowObscuredLocked(newTouchedWindowHandle)) { - targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) { + ALOGI("Dropping event because there is no touchable window or gesture monitor at " + "(%d, %d) in display %" PRId32 ".", x, y, displayId); + injectionResult = INPUT_EVENT_INJECTION_FAILED; + goto Failed; } - // Update hover state. - if (isHoverAction) { - newHoverWindowHandle = newTouchedWindowHandle; - } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { - newHoverWindowHandle = mLastHoverWindowHandle; - } + if (newTouchedWindowHandle != nullptr) { + // Set target flags. + int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS; + if (isSplit) { + targetFlags |= InputTarget::FLAG_SPLIT; + } + if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { + targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; + } else if (isWindowObscuredLocked(newTouchedWindowHandle)) { + targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + } + + // Update hover state. + if (isHoverAction) { + newHoverWindowHandle = newTouchedWindowHandle; + } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { + newHoverWindowHandle = mLastHoverWindowHandle; + } - // Update the temporary touch state. - BitSet32 pointerIds; - if (isSplit) { - uint32_t pointerId = entry->pointerProperties[pointerIndex].id; - pointerIds.markBit(pointerId); + // Update the temporary touch state. + BitSet32 pointerIds; + if (isSplit) { + uint32_t pointerId = entry->pointerProperties[pointerIndex].id; + pointerIds.markBit(pointerId); + } + mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); } - mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); + + mTempTouchState.addGestureMonitors(newGestureMonitors); } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ @@ -1396,6 +1452,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); if (oldTouchedWindowHandle != newTouchedWindowHandle + && oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32, @@ -1467,10 +1524,11 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } } } - if (! haveForegroundWindow) { + bool hasGestureMonitor = !mTempTouchState.gestureMonitors.empty(); + if (!haveForegroundWindow && !hasGestureMonitor) { #if DEBUG_FOCUS - ALOGD("Dropping event because there is no touched foreground window in display %" PRId32 - " to receive it.", displayId); + ALOGD("Dropping event because there is no touched foreground window in display %" + PRId32 " or gesture monitor to receive it.", displayId); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; @@ -1485,13 +1543,15 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { sp<InputWindowHandle> foregroundWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); - const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid; - for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { - if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { - sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle; - if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) { - mTempTouchState.addOrUpdateWindow(inputWindowHandle, - InputTarget::FLAG_ZERO_COORDS, BitSet32(0)); + if (foregroundWindowHandle) { + const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid; + for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { + if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { + sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle; + if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) { + mTempTouchState.addOrUpdateWindow(inputWindowHandle, + InputTarget::FLAG_ZERO_COORDS, BitSet32(0)); + } } } } @@ -1520,7 +1580,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { sp<InputWindowHandle> foregroundWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); - if (foregroundWindowHandle->getInfo()->hasWallpaper) { + if (foregroundWindowHandle && foregroundWindowHandle->getInfo()->hasWallpaper) { const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId); for (const sp<InputWindowHandle>& windowHandle : windowHandles) { @@ -1546,6 +1606,11 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, touchedWindow.pointerIds, inputTargets); } + for (const TouchedMonitor& touchedMonitor : mTempTouchState.gestureMonitors) { + addMonitoringTargetLocked(touchedMonitor.monitor, touchedMonitor.xOffset, + touchedMonitor.yOffset, inputTargets); + } + // Drop the outside or hover touch windows since we will not care about them // in the next iteration. mTempTouchState.filterNonAsIsTouchWindows(); @@ -1675,31 +1740,32 @@ void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowH inputTargets.push_back(target); } -void InputDispatcher::addMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, - int32_t displayId, float xOffset, float yOffset) { - std::unordered_map<int32_t, std::vector<sp<InputChannel>>>::const_iterator it = - mMonitoringChannelsByDisplay.find(displayId); +void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, + int32_t displayId, float xOffset, float yOffset) { - if (it != mMonitoringChannelsByDisplay.end()) { - const std::vector<sp<InputChannel>>& monitoringChannels = it->second; - const size_t numChannels = monitoringChannels.size(); - for (size_t i = 0; i < numChannels; i++) { - InputTarget target; - target.inputChannel = monitoringChannels[i]; - target.flags = InputTarget::FLAG_DISPATCH_AS_IS; - target.xOffset = xOffset; - target.yOffset = yOffset; - target.pointerIds.clear(); - target.globalScaleFactor = 1.0f; - inputTargets.push_back(target); + std::unordered_map<int32_t, std::vector<Monitor>>::const_iterator it = + mGlobalMonitorsByDisplay.find(displayId); + + if (it != mGlobalMonitorsByDisplay.end()) { + const std::vector<Monitor>& monitors = it->second; + for (const Monitor& monitor : monitors) { + addMonitoringTargetLocked(monitor, xOffset, yOffset, inputTargets); } - } else { - // If there is no monitor channel registered or all monitor channel unregistered, - // the display can't detect the extra system gesture by a copy of input events. - ALOGW("There is no monitor channel found in display %" PRId32, displayId); } } +void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, + float xOffset, float yOffset, std::vector<InputTarget>& inputTargets) { + InputTarget target; + target.inputChannel = monitor.inputChannel; + target.flags = InputTarget::FLAG_DISPATCH_AS_IS; + target.xOffset = xOffset; + target.yOffset = yOffset; + target.pointerIds.clear(); + target.globalScaleFactor = 1.0f; + inputTargets.push_back(target); +} + bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, const InjectionState* injectionState) { if (injectionState @@ -1905,6 +1971,12 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { + if (ATRACE_ENABLED()) { + std::string message = StringPrintf( + "prepareDispatchCycleLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")", + connection->getInputChannelName().c_str(), eventEntry->sequenceNum); + ATRACE_NAME(message.c_str()); + } #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, " "xOffset=%f, yOffset=%f, globalScaleFactor=%f, " @@ -1955,6 +2027,13 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { + if (ATRACE_ENABLED()) { + std::string message = StringPrintf( + "enqueueDispatchEntriesLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")", + connection->getInputChannelName().c_str(), eventEntry->sequenceNum); + ATRACE_NAME(message.c_str()); + } + bool wasEmpty = connection->outboundQueue.isEmpty(); // Enqueue dispatch entries for the requested modes. @@ -1980,6 +2059,13 @@ void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, void InputDispatcher::enqueueDispatchEntryLocked( const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode) { + if (ATRACE_ENABLED()) { + std::string message = StringPrintf( + "enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)", + connection->getInputChannelName().c_str(), + dispatchModeToString(dispatchMode).c_str()); + ATRACE_NAME(message.c_str()); + } int32_t inputTargetFlags = inputTarget->flags; if (!(inputTargetFlags & dispatchMode)) { return; @@ -2055,7 +2141,7 @@ void InputDispatcher::enqueueDispatchEntryLocked( return; // skip the inconsistent event } - dispatchPointerDownOutsideFocusIfNecessary(motionEntry->source, + dispatchPointerDownOutsideFocus(motionEntry->source, dispatchEntry->resolvedAction, inputTarget->inputChannel->getToken()); break; @@ -2073,10 +2159,11 @@ void InputDispatcher::enqueueDispatchEntryLocked( } -void InputDispatcher::dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action, +void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, const sp<IBinder>& newToken) { int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; - if (source != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) { + uint32_t maskedSource = source & AINPUT_SOURCE_CLASS_MASK; + if (maskedSource != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) { return; } @@ -2095,11 +2182,18 @@ void InputDispatcher::dispatchPointerDownOutsideFocusIfNecessary(uint32_t source return; } - // Dispatch onPointerDownOutsideFocus to the policy. + CommandEntry* commandEntry = postCommandLocked( + & InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible); + commandEntry->newToken = newToken; } void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection) { + if (ATRACE_ENABLED()) { + std::string message = StringPrintf("startDispatchCycleLocked(inputChannel=%s)", + connection->getInputChannelName().c_str()); + ATRACE_NAME(message.c_str()); + } #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str()); @@ -2347,11 +2441,17 @@ void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked ( void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked ( const CancelationOptions& options) { - for (auto& it : mMonitoringChannelsByDisplay) { - const std::vector<sp<InputChannel>>& monitoringChannels = it.second; - const size_t numChannels = monitoringChannels.size(); - for (size_t i = 0; i < numChannels; i++) { - synthesizeCancelationEventsForInputChannelLocked(monitoringChannels[i], options); + synthesizeCancelationEventsForMonitorsLocked(options, mGlobalMonitorsByDisplay); + synthesizeCancelationEventsForMonitorsLocked(options, mGestureMonitorsByDisplay); +} + +void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked( + const CancelationOptions& options, + std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) { + for (const auto& it : monitorsByDisplay) { + const std::vector<Monitor>& monitors = it.second; + for (const Monitor& monitor : monitors) { + synthesizeCancelationEventsForInputChannelLocked(monitor.inputChannel, options); } } } @@ -3293,8 +3393,9 @@ void InputDispatcher::setFocusedDisplay(int32_t displayId) { getInputChannelLocked(oldFocusedWindowHandle->getToken()); if (inputChannel != nullptr) { CancelationOptions options( - CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS, + CancelationOptions::CANCEL_NON_POINTER_EVENTS, "The display which contains this window no longer has focus."); + options.displayId = ADISPLAY_ID_NONE; synthesizeCancelationEventsForInputChannelLocked(inputChannel, options); } } @@ -3604,18 +3705,19 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT "Displays: <none>\n"; } - if (!mMonitoringChannelsByDisplay.empty()) { - for (auto& it : mMonitoringChannelsByDisplay) { - const std::vector<sp<InputChannel>>& monitoringChannels = it.second; - dump += StringPrintf(INDENT "MonitoringChannels in display %" PRId32 ":\n", it.first); - const size_t numChannels = monitoringChannels.size(); - for (size_t i = 0; i < numChannels; i++) { - const sp<InputChannel>& channel = monitoringChannels[i]; - dump += StringPrintf(INDENT2 "%zu: '%s'\n", i, channel->getName().c_str()); - } + if (!mGlobalMonitorsByDisplay.empty() || !mGestureMonitorsByDisplay.empty()) { + for (auto& it : mGlobalMonitorsByDisplay) { + const std::vector<Monitor>& monitors = it.second; + dump += StringPrintf(INDENT "Global monitors in display %" PRId32 ":\n", it.first); + dumpMonitors(dump, monitors); + } + for (auto& it : mGestureMonitorsByDisplay) { + const std::vector<Monitor>& monitors = it.second; + dump += StringPrintf(INDENT "Gesture monitors in display %" PRId32 ":\n", it.first); + dumpMonitors(dump, monitors); } } else { - dump += INDENT "MonitoringChannels: <none>\n"; + dump += INDENT "Monitors: <none>\n"; } nsecs_t currentTime = now(); @@ -3730,7 +3832,18 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { mConfig.keyRepeatTimeout * 0.000001f); } -status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, int32_t displayId) { +void InputDispatcher::dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors) { + const size_t numMonitors = monitors.size(); + for (size_t i = 0; i < numMonitors; i++) { + const Monitor& monitor = monitors[i]; + const sp<InputChannel>& channel = monitor.inputChannel; + dump += StringPrintf(INDENT2 "%zu: '%s', ", i, channel->getName().c_str()); + dump += "\n"; + } +} + +status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, + int32_t displayId) { #if DEBUG_REGISTRATION ALOGD("channel '%s' ~ registerInputChannel - displayId=%" PRId32, inputChannel->getName().c_str(), displayId); @@ -3739,35 +3852,55 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan { // acquire lock std::scoped_lock _l(mLock); - // If InputWindowHandle is null and displayId is not ADISPLAY_ID_NONE, - // treat inputChannel as monitor channel for displayId. - bool monitor = inputChannel->getToken() == nullptr && displayId != ADISPLAY_ID_NONE; - if (monitor) { - inputChannel->setToken(new BBinder()); - } - if (getConnectionIndexLocked(inputChannel) >= 0) { ALOGW("Attempted to register already registered input channel '%s'", inputChannel->getName().c_str()); return BAD_VALUE; } - sp<Connection> connection = new Connection(inputChannel, monitor); + sp<Connection> connection = new Connection(inputChannel, false /*monitor*/); int fd = inputChannel->getFd(); mConnectionsByFd.add(fd, connection); mInputChannelsByToken[inputChannel->getToken()] = inputChannel; - // Store monitor channel by displayId. - if (monitor) { - std::vector<sp<InputChannel>>& monitoringChannels = - mMonitoringChannelsByDisplay[displayId]; - monitoringChannels.push_back(inputChannel); + mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); + } // release lock + + // Wake the looper because some connections have changed. + mLooper->wake(); + return OK; +} + +status_t InputDispatcher::registerInputMonitor(const sp<InputChannel>& inputChannel, + int32_t displayId, bool isGestureMonitor) { + { // acquire lock + std::scoped_lock _l(mLock); + + if (displayId < 0) { + ALOGW("Attempted to register input monitor without a specified display."); + return BAD_VALUE; + } + + if (inputChannel->getToken() == nullptr) { + ALOGW("Attempted to register input monitor without an identifying token."); + return BAD_VALUE; } + sp<Connection> connection = new Connection(inputChannel, true /*monitor*/); + + const int fd = inputChannel->getFd(); + mConnectionsByFd.add(fd, connection); + mInputChannelsByToken[inputChannel->getToken()] = inputChannel; + + auto& monitorsByDisplay = isGestureMonitor + ? mGestureMonitorsByDisplay + : mGlobalMonitorsByDisplay; + monitorsByDisplay[displayId].emplace_back(inputChannel); + mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); - } // release lock + } // Wake the looper because some connections have changed. mLooper->wake(); return OK; @@ -3821,24 +3954,89 @@ status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& i } void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) { - for (auto it = mMonitoringChannelsByDisplay.begin(); - it != mMonitoringChannelsByDisplay.end(); ) { - std::vector<sp<InputChannel>>& monitoringChannels = it->second; - const size_t numChannels = monitoringChannels.size(); - for (size_t i = 0; i < numChannels; i++) { - if (monitoringChannels[i] == inputChannel) { - monitoringChannels.erase(monitoringChannels.begin() + i); + removeMonitorChannelLocked(inputChannel, mGlobalMonitorsByDisplay); + removeMonitorChannelLocked(inputChannel, mGestureMonitorsByDisplay); +} + +void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel, + std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) { + for (auto it = monitorsByDisplay.begin(); it != monitorsByDisplay.end(); ) { + std::vector<Monitor>& monitors = it->second; + const size_t numMonitors = monitors.size(); + for (size_t i = 0; i < numMonitors; i++) { + if (monitors[i].inputChannel == inputChannel) { + monitors.erase(monitors.begin() + i); break; } } - if (monitoringChannels.empty()) { - it = mMonitoringChannelsByDisplay.erase(it); + if (monitors.empty()) { + it = monitorsByDisplay.erase(it); } else { ++it; } } } +status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { + { // acquire lock + std::scoped_lock _l(mLock); + std::optional<int32_t> foundDisplayId = findGestureMonitorDisplayByTokenLocked(token); + + if (!foundDisplayId) { + ALOGW("Attempted to pilfer pointers from an un-registered monitor or invalid token"); + return BAD_VALUE; + } + int32_t displayId = foundDisplayId.value(); + + ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId); + if (stateIndex < 0) { + ALOGW("Failed to pilfer pointers: no pointers on display %" PRId32 ".", displayId); + return BAD_VALUE; + } + + TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex); + std::optional<int32_t> foundDeviceId; + for (const TouchedMonitor& touchedMonitor : state.gestureMonitors) { + if (touchedMonitor.monitor.inputChannel->getToken() == token) { + foundDeviceId = state.deviceId; + } + } + if (!foundDeviceId || !state.down) { + ALOGW("Attempted to pilfer points from a monitor without any on-going pointer streams." + " Ignoring."); + return BAD_VALUE; + } + int32_t deviceId = foundDeviceId.value(); + + // Send cancel events to all the input channels we're stealing from. + CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, + "gesture monitor stole pointer stream"); + options.deviceId = deviceId; + options.displayId = displayId; + for (const TouchedWindow& window : state.windows) { + sp<InputChannel> channel = getInputChannelLocked(window.windowHandle->getToken()); + synthesizeCancelationEventsForInputChannelLocked(channel, options); + } + // Then clear the current touch state so we stop dispatching to them as well. + state.filterNonMonitors(); + } + return OK; +} + + +std::optional<int32_t> InputDispatcher::findGestureMonitorDisplayByTokenLocked( + const sp<IBinder>& token) { + for (const auto& it : mGestureMonitorsByDisplay) { + const std::vector<Monitor>& monitors = it.second; + for (const Monitor& monitor : monitors) { + if (monitor.inputChannel->getToken() == token) { + return it.first; + } + } + } + return std::nullopt; +} + ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) { if (inputChannel == nullptr) { return -1; @@ -3997,6 +4195,12 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( entry->release(); } +void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) { + mLock.unlock(); + mPolicy->onPointerDownOutsideFocus(commandEntry->newToken); + mLock.lock(); +} + void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( CommandEntry* commandEntry) { sp<Connection> connection = commandEntry->connection; @@ -4807,11 +5011,15 @@ void InputDispatcher::InputState::removeFallbackKey(int32_t originalKeyCode) { bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options) { - if (options.keyCode != -1 && memento.keyCode != options.keyCode) { + if (options.keyCode && memento.keyCode != options.keyCode.value()) { return false; } - if (options.deviceId != -1 && memento.deviceId != options.deviceId) { + if (options.deviceId && memento.deviceId != options.deviceId.value()) { + return false; + } + + if (options.displayId && memento.displayId != options.displayId.value()) { return false; } @@ -4821,8 +5029,6 @@ bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, return true; case CancelationOptions::CANCEL_FALLBACK_EVENTS: return memento.flags & AKEY_EVENT_FLAG_FALLBACK; - case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS: - return memento.displayId == ADISPLAY_ID_NONE; default: return false; } @@ -4830,7 +5036,11 @@ bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options) { - if (options.deviceId != -1 && memento.deviceId != options.deviceId) { + if (options.deviceId && memento.deviceId != options.deviceId.value()) { + return false; + } + + if (options.displayId && memento.displayId != options.displayId.value()) { return false; } @@ -4841,8 +5051,6 @@ bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& mement return memento.source & AINPUT_SOURCE_CLASS_POINTER; case CancelationOptions::CANCEL_NON_POINTER_EVENTS: return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); - case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS: - return memento.displayId == ADISPLAY_ID_NONE; default: return false; } @@ -4895,9 +5103,14 @@ InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry( return nullptr; } +// --- InputDispatcher::Monitor +InputDispatcher::Monitor::Monitor(const sp<InputChannel>& inputChannel) : + inputChannel(inputChannel) { +} -// --- InputDispatcher::CommandEntry --- +// --- InputDispatcher::CommandEntry --- +// InputDispatcher::CommandEntry::CommandEntry(Command command) : command(command), eventTime(0), keyEntry(nullptr), userActivityEventType(0), seq(0), handled(false) { @@ -4906,6 +5119,10 @@ InputDispatcher::CommandEntry::CommandEntry(Command command) : InputDispatcher::CommandEntry::~CommandEntry() { } +// --- InputDispatcher::TouchedMonitor --- +InputDispatcher::TouchedMonitor::TouchedMonitor(const Monitor& monitor, float xOffset, + float yOffset) : monitor(monitor), xOffset(xOffset), yOffset(yOffset) { +} // --- InputDispatcher::TouchState --- @@ -4924,6 +5141,7 @@ void InputDispatcher::TouchState::reset() { displayId = ADISPLAY_ID_NONE; windows.clear(); portalWindows.clear(); + gestureMonitors.clear(); } void InputDispatcher::TouchState::copyFrom(const TouchState& other) { @@ -4934,6 +5152,7 @@ void InputDispatcher::TouchState::copyFrom(const TouchState& other) { displayId = other.displayId; windows = other.windows; portalWindows = other.portalWindows; + gestureMonitors = other.gestureMonitors; } void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, @@ -4971,6 +5190,14 @@ void InputDispatcher::TouchState::addPortalWindow(const sp<InputWindowHandle>& w portalWindows.push_back(windowHandle); } +void InputDispatcher::TouchState::addGestureMonitors( + const std::vector<TouchedMonitor>& newMonitors) { + const size_t newSize = gestureMonitors.size() + newMonitors.size(); + gestureMonitors.reserve(newSize); + gestureMonitors.insert(std::end(gestureMonitors), + std::begin(newMonitors), std::end(newMonitors)); +} + void InputDispatcher::TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) { for (size_t i = 0; i < windows.size(); i++) { if (windows[i].windowHandle == windowHandle) { @@ -5003,6 +5230,11 @@ void InputDispatcher::TouchState::filterNonAsIsTouchWindows() { } } +void InputDispatcher::TouchState::filterNonMonitors() { + windows.clear(); + portalWindows.clear(); +} + sp<InputWindowHandle> InputDispatcher::TouchState::getFirstForegroundWindowHandle() const { for (size_t i = 0; i < windows.size(); i++) { const TouchedWindow& window = windows[i]; diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 3735a0bcc6..753b748884 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -23,6 +23,8 @@ #include <input/InputTransport.h> #include <input/InputWindow.h> #include <input/ISetInputWindowsListener.h> +#include <optional> +#include <ui/Region.h> #include <utils/threads.h> #include <utils/Timers.h> #include <utils/RefBase.h> @@ -272,6 +274,13 @@ public: */ virtual bool checkInjectEventsPermissionNonReentrant( int32_t injectorPid, int32_t injectorUid) = 0; + + /* Notifies the policy that a pointer down event has occurred outside the current focused + * window. + * + * The touchedToken passed as an argument is the window that received the input event. + */ + virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) = 0; }; @@ -351,19 +360,35 @@ public: virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0; /* Registers input channels that may be used as targets for input events. - * If inputWindowHandle is null, and displayId is not ADISPLAY_ID_NONE, - * the channel will receive a copy of all input events form the specific displayId. * * This method may be called on any thread (usually by the input manager). */ virtual status_t registerInputChannel( const sp<InputChannel>& inputChannel, int32_t displayId) = 0; + /* Registers input channels to be used to monitor input events. + * + * Each monitor must target a specific display and will only receive input events sent to that + * display. If the monitor is a gesture monitor, it will only receive pointer events on the + * targeted display. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual status_t registerInputMonitor( + const sp<InputChannel>& inputChannel, int32_t displayId, bool gestureMonitor) = 0; + /* Unregister input channels that will no longer receive input events. * * This method may be called on any thread (usually by the input manager). */ virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0; + + /* Allows an input monitor steal the current pointer stream away from normal input windows. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual status_t pilferPointers(const sp<IBinder>& token) = 0; + }; /* Dispatches events to input targets. Some functions of the input dispatcher, such as @@ -390,35 +415,39 @@ protected: public: explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy); - virtual void dump(std::string& dump); - virtual void monitor(); + virtual void dump(std::string& dump) override; + virtual void monitor() override; - virtual void dispatchOnce(); + virtual void dispatchOnce() override; - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args); - virtual void notifyKey(const NotifyKeyArgs* args); - virtual void notifyMotion(const NotifyMotionArgs* args); - virtual void notifySwitch(const NotifySwitchArgs* args); - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); + virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; + virtual void notifyKey(const NotifyKeyArgs* args) override; + virtual void notifyMotion(const NotifyMotionArgs* args) override; + virtual void notifySwitch(const NotifySwitchArgs* args) override; + virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags); + uint32_t policyFlags) override; virtual void setInputWindows(const std::vector<sp<InputWindowHandle> >& inputWindowHandles, int32_t displayId, - const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr); + const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) override; virtual void setFocusedApplication(int32_t displayId, - const sp<InputApplicationHandle>& inputApplicationHandle); - virtual void setFocusedDisplay(int32_t displayId); - virtual void setInputDispatchMode(bool enabled, bool frozen); - virtual void setInputFilterEnabled(bool enabled); + const sp<InputApplicationHandle>& inputApplicationHandle) override; + virtual void setFocusedDisplay(int32_t displayId) override; + virtual void setInputDispatchMode(bool enabled, bool frozen) override; + virtual void setInputFilterEnabled(bool enabled) override; - virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken); + virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) + override; virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, - int32_t displayId); - virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel); + int32_t displayId) override; + virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel, + int32_t displayId, bool isGestureMonitor) override; + virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) override; + virtual status_t pilferPointers(const sp<IBinder>& token) override; private: template <typename T> @@ -712,10 +741,6 @@ private: CANCEL_POINTER_EVENTS = 1, CANCEL_NON_POINTER_EVENTS = 2, CANCEL_FALLBACK_EVENTS = 3, - - /* Cancel events where the display not specified. These events would go to the focused - * display. */ - CANCEL_DISPLAY_UNSPECIFIED_EVENTS = 4, }; // The criterion to use to determine which events should be canceled. @@ -724,14 +749,16 @@ private: // Descriptive reason for the cancelation. const char* reason; - // The specific keycode of the key event to cancel, or -1 to cancel any key event. - int32_t keyCode; + // The specific keycode of the key event to cancel, or nullopt to cancel any key event. + std::optional<int32_t> keyCode = std::nullopt; - // The specific device id of events to cancel, or -1 to cancel events from any device. - int32_t deviceId; + // The specific device id of events to cancel, or nullopt to cancel events from any device. + std::optional<int32_t> deviceId = std::nullopt; + + // The specific display id of events to cancel, or nullopt to cancel events on any display. + std::optional<int32_t> displayId = std::nullopt; - CancelationOptions(Mode mode, const char* reason) : - mode(mode), reason(reason), keyCode(-1), deviceId(-1) { } + CancelationOptions(Mode mode, const char* reason) : mode(mode), reason(reason) { } }; /* Tracks dispatched key and motion event state so that cancelation events can be @@ -871,6 +898,12 @@ private: DispatchEntry* findWaitQueueEntry(uint32_t seq); }; + struct Monitor { + sp<InputChannel> inputChannel; // never null + + explicit Monitor(const sp<InputChannel>& inputChannel); + }; + enum DropReason { DROP_REASON_NOT_DROPPED = 0, DROP_REASON_POLICY = 1, @@ -936,12 +969,24 @@ private: std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken GUARDED_BY(mLock); + // Finds the display ID of the gesture monitor identified by the provided token. + std::optional<int32_t> findGestureMonitorDisplayByTokenLocked(const sp<IBinder>& token) + REQUIRES(mLock); + ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock); // Input channels that will receive a copy of all input events sent to the provided display. - std::unordered_map<int32_t, std::vector<sp<InputChannel>>> mMonitoringChannelsByDisplay + std::unordered_map<int32_t, std::vector<Monitor>> mGlobalMonitorsByDisplay + GUARDED_BY(mLock); + + // Input channels that will receive pointer events that start within the corresponding display. + // These are a bit special when compared to global monitors since they'll cause gesture streams + // to continue even when there isn't a touched window,and have the ability to steal the rest of + // the pointer stream in order to claim it for a system gesture. + std::unordered_map<int32_t, std::vector<Monitor>> mGestureMonitorsByDisplay GUARDED_BY(mLock); + // Event injection and synchronization. std::condition_variable mInjectionResultAvailable; bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); @@ -1016,6 +1061,16 @@ private: int32_t targetFlags; BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set }; + + // For tracking the offsets we need to apply when adding gesture monitor targets. + struct TouchedMonitor { + Monitor monitor; + float xOffset = 0.f; + float yOffset = 0.f; + + explicit TouchedMonitor(const Monitor& monitor, float xOffset, float yOffset); + }; + struct TouchState { bool down; bool split; @@ -1029,6 +1084,8 @@ private: // monitoring channels of the displays touched. std::vector<sp<InputWindowHandle>> portalWindows; + std::vector<TouchedMonitor> gestureMonitors; + TouchState(); ~TouchState(); void reset(); @@ -1036,9 +1093,11 @@ private: void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags, BitSet32 pointerIds); void addPortalWindow(const sp<InputWindowHandle>& windowHandle); + void addGestureMonitors(const std::vector<TouchedMonitor>& monitors); void removeWindow(const sp<InputWindowHandle>& windowHandle); void removeWindowByToken(const sp<IBinder>& token); void filterNonAsIsTouchWindows(); + void filterNonMonitors(); sp<InputWindowHandle> getFirstForegroundWindowHandle() const; bool isSlippery() const; }; @@ -1108,12 +1167,18 @@ private: int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) REQUIRES(mLock); + std::vector<TouchedMonitor> findTouchedGestureMonitorsLocked(int32_t displayId, + const std::vector<sp<InputWindowHandle>>& portalWindows) REQUIRES(mLock); + void addGestureMonitors(const std::vector<Monitor>& monitors, + std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset = 0, float yOffset = 0); void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) REQUIRES(mLock); - void addMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId, - float xOffset = 0, float yOffset = 0) REQUIRES(mLock); + void addMonitoringTargetLocked(const Monitor& monitor, float xOffset, float yOffset, + std::vector<InputTarget>& inputTargets) REQUIRES(mLock); + void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, + int32_t displayId, float xOffset = 0, float yOffset = 0) REQUIRES(mLock); void pokeUserActivityLocked(const EventEntry* eventEntry) REQUIRES(mLock); bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, @@ -1149,13 +1214,15 @@ private: void releaseDispatchEntry(DispatchEntry* dispatchEntry); static int handleReceiveCallback(int fd, int events, void* data); // The action sent should only be of type AMOTION_EVENT_* - void dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action, + void dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, const sp<IBinder>& newToken) REQUIRES(mLock); void synthesizeCancelationEventsForAllConnectionsLocked( const CancelationOptions& options) REQUIRES(mLock); void synthesizeCancelationEventsForMonitorsLocked( const CancelationOptions& options) REQUIRES(mLock); + void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options, + std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock); void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel, const CancelationOptions& options) REQUIRES(mLock); void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection, @@ -1169,10 +1236,14 @@ private: // Dump state. void dumpDispatchStateLocked(std::string& dump) REQUIRES(mLock); + void dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors); void logDispatchStateLocked() REQUIRES(mLock); // Registration. void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock); + void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel, + std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) + REQUIRES(mLock); status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify) REQUIRES(mLock); @@ -1204,6 +1275,8 @@ private: DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) REQUIRES(mLock); void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry); + void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) + REQUIRES(mLock); // Statistics gathering. void updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry, diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 745fac0b1f..9fe6481ca0 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -52,6 +52,7 @@ public: mTime = -1; mAction = -1; mDisplayId = -1; + mOnPointerDownToken.clear(); } void assertFilterInputEventWasCalledWithExpectedArgs(const NotifyMotionArgs* args) { @@ -87,11 +88,18 @@ public: << "Expected filterInputEvent() to not have been called."; } + void assertOnPointerDownEquals(const sp<IBinder>& touchedToken) { + ASSERT_EQ(mOnPointerDownToken, touchedToken) + << "Expected token from onPointerDownOutsideFocus was not matched"; + reset(); + } + private: bool mInputEventFiltered; nsecs_t mTime; int32_t mAction; int32_t mDisplayId; + sp<IBinder> mOnPointerDownToken; virtual void notifyConfigurationChanged(nsecs_t) { } @@ -161,11 +169,16 @@ private: return false; } + virtual void onPointerDownOutsideFocus(const sp<IBinder>& newToken) { + mOnPointerDownToken = newToken; + } + void reset() { mInputEventFiltered = false; mTime = -1; mAction = -1; mDisplayId = -1; + mOnPointerDownToken.clear(); } }; @@ -416,7 +429,6 @@ protected: sp<InputDispatcher> mDispatcher; sp<InputChannel> mServerChannel, mClientChannel; - sp<IBinder> mToken; InputConsumer *mConsumer; PreallocatedInputEventFactory mEventFactory; @@ -432,10 +444,10 @@ public: FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle, const sp<InputDispatcher>& dispatcher, const std::string name, int32_t displayId) : FakeInputReceiver(dispatcher, name, displayId), - mFocused(false) { + mFocused(false), mFrame(Rect(0, 0, WIDTH, HEIGHT)), mLayoutParamFlags(0) { mServerChannel->setToken(new BBinder()); mDispatcher->registerInputChannel(mServerChannel, displayId); - + inputApplicationHandle->updateInfo(); mInfo.applicationInfo = *inputApplicationHandle->getInfo(); } @@ -443,15 +455,15 @@ public: virtual bool updateInfo() { mInfo.token = mServerChannel ? mServerChannel->getToken() : nullptr; mInfo.name = mName; - mInfo.layoutParamsFlags = 0; + mInfo.layoutParamsFlags = mLayoutParamFlags; mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION; mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; - mInfo.frameLeft = 0; - mInfo.frameTop = 0; - mInfo.frameRight = WIDTH; - mInfo.frameBottom = HEIGHT; + mInfo.frameLeft = mFrame.left; + mInfo.frameTop = mFrame.top; + mInfo.frameRight = mFrame.right; + mInfo.frameBottom = mFrame.bottom; mInfo.globalScaleFactor = 1.0; - mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT)); + mInfo.addTouchableRegion(mFrame); mInfo.visible = true; mInfo.canReceiveKeys = true; mInfo.hasFocus = mFocused; @@ -470,6 +482,14 @@ public: mFocused = true; } + void setFrame(const Rect& frame) { + mFrame.set(frame); + } + + void setLayoutParamFlags(int32_t flags) { + mLayoutParamFlags = flags; + } + void releaseChannel() { mServerChannel.clear(); InputWindowHandle::releaseChannel(); @@ -480,6 +500,8 @@ protected: } bool mFocused; + Rect mFrame; + int32_t mLayoutParamFlags; }; static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher, @@ -500,7 +522,7 @@ static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher, } static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t source, - int32_t displayId) { + int32_t displayId, int32_t x = 100, int32_t y = 200) { MotionEvent event; PointerProperties pointerProperties[1]; PointerCoords pointerCoords[1]; @@ -510,13 +532,13 @@ static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t s pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; pointerCoords[0].clear(); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 200); + pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); + pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid motion down event. event.initialize(DEVICE_ID, source, displayId, - AMOTION_EVENT_ACTION_DOWN, /* actionButton */0, /* flags */ 0, /* edgeFlags */ 0, + AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0, /* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties, @@ -776,8 +798,10 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) class FakeMonitorReceiver : public FakeInputReceiver, public RefBase { public: FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name, - int32_t displayId) : FakeInputReceiver(dispatcher, name, displayId) { - mDispatcher->registerInputChannel(mServerChannel, displayId); + int32_t displayId, bool isGestureMonitor = false) + : FakeInputReceiver(dispatcher, name, displayId) { + mServerChannel->setToken(new BBinder()); + mDispatcher->registerInputMonitor(mServerChannel, displayId, isGestureMonitor); } }; @@ -907,4 +931,98 @@ TEST_F(InputFilterTest, KeyEvent_InputFilter) { testNotifyKey(/*expectToBeFiltered*/ false); } +class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { + virtual void SetUp() { + InputDispatcherTest::SetUp(); + + sp<FakeApplicationHandle> application = new FakeApplicationHandle(); + mUnfocusedWindow = new FakeWindowHandle(application, mDispatcher, "Top", + ADISPLAY_ID_DEFAULT); + mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); + // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this + // window. + mUnfocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL); + + mWindowFocused = new FakeWindowHandle(application, mDispatcher, "Second", + ADISPLAY_ID_DEFAULT); + mWindowFocused->setFrame(Rect(50, 50, 100, 100)); + mWindowFocused->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL); + mWindowFocusedTouchPoint = 60; + + // Set focused application. + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + mWindowFocused->setFocus(); + + // Expect one focus window exist in display. + std::vector<sp<InputWindowHandle>> inputWindowHandles; + inputWindowHandles.push_back(mUnfocusedWindow); + inputWindowHandles.push_back(mWindowFocused); + mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT); + } + + virtual void TearDown() { + InputDispatcherTest::TearDown(); + + mUnfocusedWindow.clear(); + mWindowFocused.clear(); + } + +protected: + sp<FakeWindowHandle> mUnfocusedWindow; + sp<FakeWindowHandle> mWindowFocused; + int32_t mWindowFocusedTouchPoint; +}; + +// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action +// DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received +// the onPointerDownOutsideFocus callback. +TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) { + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20, 20)) + << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; + // Call monitor to wait for the command queue to get flushed. + mDispatcher->monitor(); + + mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken()); +} + +// Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action +// DOWN on the window that doesn't have focus. Ensure no window received the +// onPointerDownOutsideFocus callback. +TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) { + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, + AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, 20, 20)) + << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; + // Call monitor to wait for the command queue to get flushed. + mDispatcher->monitor(); + + mFakePolicy->assertOnPointerDownEquals(nullptr); +} + +// Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't +// have focus. Ensure no window received the onPointerDownOutsideFocus callback. +TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) { + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)) + << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED"; + // Call monitor to wait for the command queue to get flushed. + mDispatcher->monitor(); + + mFakePolicy->assertOnPointerDownEquals(nullptr); +} + +// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action +// DOWN on the window that already has focus. Ensure no window received the +// onPointerDownOutsideFocus callback. +TEST_F(InputDispatcherOnPointerDownOutsideFocus, + OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) { + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, mWindowFocusedTouchPoint, + mWindowFocusedTouchPoint)) + << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; + // Call monitor to wait for the command queue to get flushed. + mDispatcher->monitor(); + + mFakePolicy->assertOnPointerDownEquals(nullptr); +} + } // namespace android diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index d3b36fe354..b623991742 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -23,6 +23,7 @@ #include "BufferQueueLayer.h" #include "LayerRejecter.h" +#include "SurfaceInterceptor.h" #include "TimeStats/TimeStats.h" diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 024ed45906..0c47eb5a01 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -18,6 +18,7 @@ #include <cstdint> +#include <math/mat4.h> #include <ui/GraphicTypes.h> #include <ui/Rect.h> #include <ui/Region.h> @@ -78,6 +79,9 @@ struct OutputCompositionState { // The color transform to apply android_color_transform_t colorTransform{HAL_COLOR_TRANSFORM_IDENTITY}; + // The color transform matrix to apply, corresponding with colorTransform. + mat4 colorTransformMat; + // Current active color mode ui::ColorMode colorMode{ui::ColorMode::NATIVE}; diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index d22bdaf625..2893031ad9 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -98,6 +98,7 @@ void Output::setColorTransform(const mat4& transform) { } mState.colorTransform = newColorTransform; + mState.colorTransformMat = transform; dirtyEntireOutput(); } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index c80925ee78..0067b505e3 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -288,16 +288,21 @@ public: } Rect getSourceCrop() const override { - // use the (projected) logical display viewport by default + // use the projected display viewport by default. if (mSourceCrop.isEmpty()) { return mDevice->getScissor(); } - const int orientation = mDevice->getInstallOrientation(); - if (orientation == DisplayState::eOrientationDefault) { - return mSourceCrop; - } + // Recompute the device transformation for the source crop. + ui::Transform rotation; + ui::Transform translatePhysical; + ui::Transform translateLogical; + ui::Transform scale; + const Rect& viewport = mDevice->getViewport(); + const Rect& scissor = mDevice->getScissor(); + const Rect& frame = mDevice->getFrame(); + const int orientation = mDevice->getInstallOrientation(); // Install orientation is transparent to the callers. Apply it now. uint32_t flags = 0x00; switch (orientation) { @@ -310,10 +315,17 @@ public: case DisplayState::eOrientation270: flags = ui::Transform::ROT_270; break; + default: + break; } - ui::Transform tr; - tr.set(flags, getWidth(), getHeight()); - return tr.transform(mSourceCrop); + rotation.set(flags, getWidth(), getHeight()); + translateLogical.set(-viewport.left, -viewport.top); + translatePhysical.set(scissor.left, scissor.top); + scale.set(frame.getWidth() / float(viewport.getWidth()), 0, 0, + frame.getHeight() / float(viewport.getHeight())); + const ui::Transform finalTransform = + rotation * translatePhysical * scale * translateLogical; + return finalTransform.transform(mSourceCrop); } private: diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 62073b6ef4..12a94a70d6 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -26,7 +26,6 @@ #include <ui/Fence.h> #include <ui/FloatRect.h> #include <ui/GraphicBuffer.h> -#include <ui/Region.h> #include <android/configuration.h> @@ -826,6 +825,11 @@ Error Layer::setCursorPosition(int32_t x, int32_t y) Error Layer::setBuffer(uint32_t slot, const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence) { + if (buffer == nullptr && mBufferSlot == slot) { + return Error::None; + } + mBufferSlot = slot; + int32_t fenceFd = acquireFence->dup(); auto intError = mComposer.setLayerBuffer(mDisplayId, mId, slot, buffer, fenceFd); @@ -834,6 +838,12 @@ Error Layer::setBuffer(uint32_t slot, const sp<GraphicBuffer>& buffer, Error Layer::setSurfaceDamage(const Region& damage) { + if (damage.isRect() && mDamageRegion.isRect() && + (damage.getBounds() == mDamageRegion.getBounds())) { + return Error::None; + } + mDamageRegion = damage; + // We encode default full-screen damage as INVALID_RECT upstream, but as 0 // rects for HWC Hwc2::Error intError = Hwc2::Error::NONE; @@ -988,6 +998,12 @@ Error Layer::setTransform(Transform transform) Error Layer::setVisibleRegion(const Region& region) { + if (region.isRect() && mVisibleRegion.isRect() && + (region.getBounds() == mVisibleRegion.getBounds())) { + return Error::None; + } + mVisibleRegion = region; + size_t rectCount = 0; auto rectArray = region.getArray(&rectCount); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 4209e45175..e0a5ef14dd 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -27,6 +27,7 @@ #include <math/mat4.h> #include <ui/GraphicTypes.h> #include <ui/HdrCapabilities.h> +#include <ui/Region.h> #include <utils/Log.h> #include <utils/StrongPointer.h> #include <utils/Timers.h> @@ -42,8 +43,6 @@ namespace android { class Fence; class FloatRect; class GraphicBuffer; - class Rect; - class Region; namespace Hwc2 { class Composer; } @@ -438,9 +437,15 @@ private: hwc2_display_t mDisplayId; hwc2_layer_t mId; + + // Cached HWC2 data, to ensure the same commands aren't sent to the HWC + // multiple times. + android::Region mVisibleRegion = android::Region::INVALID_REGION; + android::Region mDamageRegion = android::Region::INVALID_REGION; android::ui::Dataspace mDataSpace = android::ui::Dataspace::UNKNOWN; android::HdrMetadata mHdrMetadata; android::mat4 mColorMatrix; + uint32_t mBufferSlot; }; } // namespace impl diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 718e996dae..35f11fc494 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -266,6 +266,7 @@ float getLuma(float r, float g, float b) { constexpr auto rec709_blue_primary = 0.0722f; return rec709_red_primary * r + rec709_green_primary * g + rec709_blue_primary * b; } +} // anonymous namespace float sampleArea(const uint32_t* data, int32_t stride, const Rect& area) { std::array<int32_t, 256> brightnessBuckets = {}; @@ -286,14 +287,13 @@ float sampleArea(const uint32_t* data, int32_t stride, const Rect& area) { int32_t accumulated = 0; size_t bucket = 0; - while (bucket++ < brightnessBuckets.size()) { + for (; bucket < brightnessBuckets.size(); bucket++) { accumulated += brightnessBuckets[bucket]; if (accumulated > majoritySampleNum) break; } return bucket / 255.0f; } -} // anonymous namespace std::vector<float> RegionSamplingThread::sampleBuffer( const sp<GraphicBuffer>& buffer, const Point& leftTop, diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h index d4e57bfc7b..979642912b 100644 --- a/services/surfaceflinger/RegionSamplingThread.h +++ b/services/surfaceflinger/RegionSamplingThread.h @@ -37,6 +37,8 @@ class Scheduler; class SurfaceFlinger; struct SamplingOffsetCallback; +float sampleArea(const uint32_t* data, int32_t stride, const Rect& area); + class RegionSamplingThread : public IBinder::DeathRecipient { public: struct TimingTunables { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1e343550b2..5676c59834 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -75,6 +75,7 @@ #include "BufferLayer.h" #include "BufferQueueLayer.h" #include "BufferStateLayer.h" +#include "BufferStateLayerCache.h" #include "Client.h" #include "ColorLayer.h" #include "Colorizer.h" @@ -95,12 +96,14 @@ #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/VirtualDisplaySurface.h" #include "Effects/Daltonizer.h" +#include "RegionSamplingThread.h" #include "Scheduler/DispSync.h" #include "Scheduler/DispSyncSource.h" #include "Scheduler/EventControlThread.h" #include "Scheduler/EventThread.h" #include "Scheduler/InjectVSyncSource.h" #include "Scheduler/MessageQueue.h" +#include "Scheduler/PhaseOffsets.h" #include "Scheduler/Scheduler.h" #include "TimeStats/TimeStats.h" @@ -266,49 +269,17 @@ std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { } } -SurfaceFlingerBE::SurfaceFlingerBE() - : mHwcServiceName(getHwcServiceName()), - mFrameBuckets(), - mTotalTime(0), - mLastSwapTime(0), - mComposerSequenceId(0) { -} - -SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory, - SurfaceFlinger::SkipInitializationTag) - : BnSurfaceComposer(), - mFactory(factory), - mTransactionPending(false), - mAnimTransactionPending(false), - mTraversalNeededMainThread(false), - mLayersRemoved(false), - mLayersAdded(false), - mBootTime(systemTime()), - mPhaseOffsets{getFactory().createPhaseOffsets()}, - mVisibleRegionsDirty(false), - mGeometryInvalid(false), - mAnimCompositionPending(false), - mBootStage(BootStage::BOOTLOADER), - mDebugRegion(0), - mDebugDisableHWC(0), - mDebugDisableTransformHint(0), - mDebugEnableProtectedContent(false), - mDebugInTransaction(0), - mLastTransactionTime(0), - mForceFullDamage(false), - mTracing(*this), - mTimeStats(factory.createTimeStats()), - mRefreshStartTime(0), - mHasPoweredOff(false), - mNumLayers(0), - mVrFlingerRequestsDisplay(false), - mMainThreadId(std::this_thread::get_id()), - mCompositionEngine{getFactory().createCompositionEngine()} { - mSetInputWindowsListener = new SetInputWindowsListener(this); -} - -SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory) - : SurfaceFlinger(factory, SkipInitialization) { +SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {} + +SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) + : mFactory(factory), + mPhaseOffsets(mFactory.createPhaseOffsets()), + mInterceptor(mFactory.createSurfaceInterceptor(this)), + mTimeStats(mFactory.createTimeStats()), + mEventQueue(mFactory.createMessageQueue()), + mCompositionEngine(mFactory.createCompositionEngine()) {} + +SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) { ALOGI("SurfaceFlinger is starting"); hasSyncFramework = running_without_sync_framework(true); @@ -427,9 +398,7 @@ void SurfaceFlinger::onFirstRef() mEventQueue->init(this); } -SurfaceFlinger::~SurfaceFlinger() -{ -} +SurfaceFlinger::~SurfaceFlinger() = default; void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */) { @@ -667,6 +636,9 @@ void SurfaceFlinger::init() { renderengine::RenderEngine::USE_COLOR_MANAGEMENT : 0); renderEngineFeature |= (useContextPriority ? renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0); + renderEngineFeature |= + (enable_protected_contents(false) ? renderengine::RenderEngine::ENABLE_PROTECTED_CONTEXT + : 0); // TODO(b/77156734): We need to stop casting and use HAL types when possible. // Sending maxFrameBufferAcquiredBuffers as the cache size is tightly tuned to single-display. @@ -1485,12 +1457,13 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::Co return; } + mPhaseOffsets->setRefreshRateType(refreshRate); + const auto display = getDisplayDeviceLocked(displayToken); if (desiredConfigId == display->getActiveConfig()) { return; } - mPhaseOffsets->setRefreshRateType(refreshRate); setDesiredActiveConfig({refreshRate, desiredConfigId, getInternalDisplayTokenLocked(), event}); } @@ -1704,22 +1677,22 @@ bool SurfaceFlinger::handleMessageTransaction() { ATRACE_CALL(); uint32_t transactionFlags = peekTransactionFlags(); - // Apply any ready transactions in the queues if there are still transactions that have not been - // applied, wake up during the next vsync period and check again - bool transactionNeeded = false; - if (!flushTransactionQueues()) { - transactionNeeded = true; - } + bool flushedATransaction = flushTransactionQueues(); - if (transactionFlags) { - handleTransaction(transactionFlags); + bool runHandleTransaction = transactionFlags && + ((transactionFlags != eTransactionFlushNeeded) || flushedATransaction); + + if (runHandleTransaction) { + handleTransaction(eTransactionMask); + } else { + getTransactionFlags(eTransactionFlushNeeded); } - if (transactionNeeded) { - setTransactionFlags(eTransactionNeeded); + if (transactionFlushNeeded()) { + setTransactionFlags(eTransactionFlushNeeded); } - return transactionFlags; + return runHandleTransaction; } void SurfaceFlinger::handleMessageRefresh() { @@ -2412,8 +2385,6 @@ void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& displayDevice) { const auto& displayState = display->getState(); const auto displayId = display->getId(); - mPostFramebufferTime = systemTime(); - if (displayState.isEnabled) { if (displayId) { getHwComposer().presentAndGetReleaseFences(*displayId); @@ -2476,8 +2447,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) State drawingState(mDrawingState); Mutex::Autolock _l(mStateLock); - const nsecs_t now = systemTime(); - mDebugInTransaction = now; + mDebugInTransaction = systemTime(); // Here we're guaranteed that some transaction flags are set // so we can call handleTransactionLocked() unconditionally. @@ -2489,7 +2459,6 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) transactionFlags = getTransactionFlags(eTransactionMask); handleTransactionLocked(transactionFlags); - mLastTransactionTime = systemTime() - now; mDebugInTransaction = 0; invalidateHwcGeometry(); // here the transaction has been committed @@ -3275,15 +3244,13 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice, const auto& displayState = display->getState(); const auto displayId = display->getId(); auto& renderEngine = getRenderEngine(); - const bool supportProtectedContent = - mDebugEnableProtectedContent && renderEngine.supportsProtectedContent(); + const bool supportProtectedContent = renderEngine.supportsProtectedContent(); const Region bounds(displayState.bounds); const DisplayRenderArea renderArea(displayDevice); const bool hasClientComposition = getHwComposer().hasClientComposition(displayId); ATRACE_INT("hasClientComposition", hasClientComposition); - mat4 colorMatrix; bool applyColorMatrix = false; renderengine::DisplaySettings clientCompositionDisplay; @@ -3322,6 +3289,7 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice, clientCompositionDisplay.clip = displayState.scissor; const ui::Transform& displayTransform = displayState.transform; clientCompositionDisplay.globalTransform = displayTransform.asMatrix4(); + clientCompositionDisplay.orientation = displayState.orientation; const auto* profile = display->getDisplayColorProfile(); Dataspace outputDataspace = Dataspace::UNKNOWN; @@ -3341,7 +3309,7 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice, // Compute the global color transform matrix. applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform; if (applyColorMatrix) { - clientCompositionDisplay.colorTransform = colorMatrix; + clientCompositionDisplay.colorTransform = displayState.colorTransformMat; } } @@ -3513,6 +3481,8 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, bool SurfaceFlinger::flushTransactionQueues() { Mutex::Autolock _l(mStateLock); + bool flushedATransaction = false; + auto it = mTransactionQueues.begin(); while (it != mTransactionQueues.end()) { auto& [applyToken, transactionQueue] = *it; @@ -3522,17 +3492,23 @@ bool SurfaceFlinger::flushTransactionQueues() { [states, displays, flags, desiredPresentTime, uncacheBuffer, listenerCallbacks, postTime, privileged] = transactionQueue.front(); if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) { + setTransactionFlags(eTransactionFlushNeeded); break; } applyTransactionState(states, displays, flags, mPendingInputWindowCommands, desiredPresentTime, uncacheBuffer, listenerCallbacks, postTime, privileged, /*isMainThread*/ true); transactionQueue.pop(); + flushedATransaction = true; } it = (transactionQueue.empty()) ? mTransactionQueues.erase(it) : std::next(it, 1); } - return mTransactionQueues.empty(); + return flushedATransaction; +} + +bool SurfaceFlinger::transactionFlushNeeded() { + return !mTransactionQueues.empty(); } bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>& states) { @@ -3604,7 +3580,7 @@ void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& states, mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime, uncacheBuffer, listenerCallbacks, postTime, privileged); - setTransactionFlags(eTransactionNeeded); + setTransactionFlags(eTransactionFlushNeeded); return; } @@ -5098,13 +5074,13 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } case 1008: // toggle use of hw composer n = data.readInt32(); - mDebugDisableHWC = n ? 1 : 0; + mDebugDisableHWC = n != 0; invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; case 1009: // toggle use of transform hint n = data.readInt32(); - mDebugDisableTransformHint = n ? 1 : 0; + mDebugDisableTransformHint = n != 0; invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; @@ -5186,7 +5162,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } case 1017: { n = data.readInt32(); - mForceFullDamage = static_cast<bool>(n); + mForceFullDamage = n != 0; return NO_ERROR; } case 1018: { // Modify Choreographer's phase offset @@ -5344,11 +5320,6 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } return NO_ERROR; } - case 1032: { - n = data.readInt32(); - mDebugEnableProtectedContent = n; - return NO_ERROR; - } // Set trace flags case 1033: { n = data.readUint32(); @@ -5666,8 +5637,9 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, const auto reqWidth = renderArea.getReqWidth(); const auto reqHeight = renderArea.getReqHeight(); - const auto sourceCrop = renderArea.getSourceCrop(); const auto rotation = renderArea.getRotationFlags(); + const auto transform = renderArea.getTransform(); + const auto sourceCrop = renderArea.getSourceCrop(); renderengine::DisplaySettings clientCompositionDisplay; std::vector<renderengine::LayerSettings> clientCompositionLayers; @@ -5675,31 +5647,34 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, // assume that bounds are never offset, and that they are the same as the // buffer bounds. clientCompositionDisplay.physicalDisplay = Rect(reqWidth, reqHeight); - ui::Transform transform = renderArea.getTransform(); + clientCompositionDisplay.clip = sourceCrop; clientCompositionDisplay.globalTransform = transform.asMatrix4(); + + // Now take into account the rotation flag. We append a transform that + // rotates the layer stack about the origin, then translate by buffer + // boundaries to be in the right quadrant. mat4 rotMatrix; - // Displacement for repositioning the clipping rectangle after rotating it - // with the rotation hint. int displacementX = 0; int displacementY = 0; float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f; switch (rotation) { case ui::Transform::ROT_90: rotMatrix = mat4::rotate(rot90InRadians, vec3(0, 0, 1)); - displacementX = reqWidth; + displacementX = renderArea.getBounds().getHeight(); break; case ui::Transform::ROT_180: rotMatrix = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)); - displacementX = reqWidth; - displacementY = reqHeight; + displacementY = renderArea.getBounds().getWidth(); + displacementX = renderArea.getBounds().getHeight(); break; case ui::Transform::ROT_270: rotMatrix = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)); - displacementY = reqHeight; + displacementY = renderArea.getBounds().getWidth(); break; default: break; } + // We need to transform the clipping window into the right spot. // First, rotate the clipping rectangle by the rotation hint to get the // right orientation @@ -5715,15 +5690,14 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, // Now reposition the clipping rectangle with the displacement vector // computed above. const mat4 displacementMat = mat4::translate(vec4(displacementX, displacementY, 0, 1)); - clientCompositionDisplay.clip = Rect(newClipLeft + displacementX, newClipTop + displacementY, newClipRight + displacementX, newClipBottom + displacementY); - // We need to perform the same transformation in layer space, so propagate - // it to the global transform. mat4 clipTransform = displacementMat * rotMatrix; - clientCompositionDisplay.globalTransform *= clipTransform; + clientCompositionDisplay.globalTransform = + clipTransform * clientCompositionDisplay.globalTransform; + clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace(); clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance; @@ -5913,14 +5887,11 @@ status_t SurfaceFlinger::getAllowedDisplayConfigs(const android::sp<android::IBi return NO_ERROR; } -// ---------------------------------------------------------------------------- - -void SetInputWindowsListener::onSetInputWindowsFinished() { +void SurfaceFlinger::SetInputWindowsListener::onSetInputWindowsFinished() { mFlinger->setInputWindowsFinished(); } -}; // namespace android - +} // namespace android #if defined(__gl_h_) #error "don't include gl/gl.h in this file" diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 3d8b6b791a..5cd0f213da 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_SURFACE_FLINGER_H -#define ANDROID_SURFACE_FLINGER_H +#pragma once #include <sys/types.h> @@ -48,27 +47,18 @@ #include <utils/threads.h> #include "AllowedDisplayConfigs.h" -#include "Barrier.h" -#include "BufferStateLayerCache.h" #include "DisplayDevice.h" #include "DisplayHardware/HWC2.h" -#include "DisplayHardware/HWComposer.h" #include "DisplayHardware/PowerAdvisor.h" #include "Effects/Daltonizer.h" #include "FrameTracker.h" #include "LayerStats.h" #include "LayerVector.h" -#include "RegionSamplingThread.h" -#include "Scheduler/DispSync.h" -#include "Scheduler/EventThread.h" -#include "Scheduler/MessageQueue.h" -#include "Scheduler/PhaseOffsets.h" #include "Scheduler/RefreshRateConfigs.h" #include "Scheduler/RefreshRateStats.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VSyncModulator.h" #include "SurfaceFlingerFactory.h" -#include "SurfaceInterceptor.h" #include "SurfaceTracing.h" #include "TransactionCompletedThread.h" @@ -90,56 +80,37 @@ using namespace android::surfaceflinger; namespace android { -using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; - -// --------------------------------------------------------------------------- - class Client; -class ColorLayer; -class DisplayEventConnection; -class EventControlThread; class EventThread; -class IGraphicBufferConsumer; +class HWComposer; class IGraphicBufferProducer; class IInputFlinger; class InjectVSyncSource; class Layer; +class MessageBase; class RefreshRateOverlay; -class Surface; -class SurfaceFlingerBE; +class RegionSamplingThread; class TimeStats; -class VSyncSource; namespace compositionengine { class DisplaySurface; } // namespace compositionengine -namespace impl { -class EventThread; -} // namespace impl - namespace renderengine { class RenderEngine; -} - -typedef std::function<void(const LayerVector::Visitor&)> TraverseLayersFunction; +} // namespace renderengine namespace dvr { class VrFlinger; } // namespace dvr -namespace surfaceflinger { -class NativeWindowSurface; -} // namespace surfaceflinger - -// --------------------------------------------------------------------------- - enum { - eTransactionNeeded = 0x01, - eTraversalNeeded = 0x02, + eTransactionNeeded = 0x01, + eTraversalNeeded = 0x02, eDisplayTransactionNeeded = 0x04, eDisplayLayerStackChanged = 0x08, - eTransactionMask = 0x0f, + eTransactionFlushNeeded = 0x10, + eTransactionMask = 0x1f, }; enum class DisplayColorSetting : int32_t { @@ -164,35 +135,28 @@ public: // Only accessed from the main thread. struct CompositePresentTime { - nsecs_t composite { -1 }; - std::shared_ptr<FenceTime> display { FenceTime::NO_FENCE }; + nsecs_t composite = -1; + std::shared_ptr<FenceTime> display = FenceTime::NO_FENCE; }; std::queue<CompositePresentTime> mCompositePresentTimes; static const size_t NUM_BUCKETS = 8; // < 1-7, 7+ - nsecs_t mFrameBuckets[NUM_BUCKETS]; - nsecs_t mTotalTime; - std::atomic<nsecs_t> mLastSwapTime; + nsecs_t mFrameBuckets[NUM_BUCKETS] = {}; + nsecs_t mTotalTime = 0; + std::atomic<nsecs_t> mLastSwapTime = 0; // Double- vs. triple-buffering stats struct BufferingStats { - BufferingStats() - : numSegments(0), - totalTime(0), - twoBufferTime(0), - doubleBufferedTime(0), - tripleBufferedTime(0) {} - - size_t numSegments; - nsecs_t totalTime; + size_t numSegments = 0; + nsecs_t totalTime = 0; // "Two buffer" means that a third buffer was never used, whereas // "double-buffered" means that on average the segment only used two // buffers (though it may have used a third for some part of the // segment) - nsecs_t twoBufferTime; - nsecs_t doubleBufferedTime; - nsecs_t tripleBufferedTime; + nsecs_t twoBufferTime = 0; + nsecs_t doubleBufferedTime = 0; + nsecs_t tripleBufferedTime = 0; }; mutable Mutex mBufferingStatsMutex; std::unordered_map<std::string, BufferingStats> mBufferingStats; @@ -200,16 +164,7 @@ public: // The composer sequence id is a monotonically increasing integer that we // use to differentiate callbacks from different hardware composer // instances. Each hardware composer instance gets a different sequence id. - int32_t mComposerSequenceId; -}; - -class SetInputWindowsListener : public BnSetInputWindowsListener { -public: - SetInputWindowsListener(const sp<SurfaceFlinger>& flinger) : mFlinger(flinger) {} - void onSetInputWindowsFinished() override; - -private: - const sp<SurfaceFlinger> mFlinger; + int32_t mComposerSequenceId = 0; }; class SurfaceFlinger : public BnSurfaceComposer, @@ -358,16 +313,12 @@ public: return mTransactionCompletedThread; } - void setInputWindowsFinished(); - private: - friend class Client; - friend class DisplayEventConnection; - friend class impl::EventThread; - friend class Layer; friend class BufferLayer; friend class BufferQueueLayer; friend class BufferStateLayer; + friend class Client; + friend class Layer; friend class MonitoredProducer; friend class RefreshRateOverlay; friend class RegionSamplingThread; @@ -532,6 +483,8 @@ private: void signalLayerUpdate(); void signalRefresh(); + using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; + struct ActiveConfigInfo { RefreshRateType type; int configId; @@ -587,6 +540,7 @@ private: void updateInputWindowInfo(); void commitInputWindowCommands() REQUIRES(mStateLock); void executeInputWindowCommands(); + void setInputWindowsFinished(); void updateCursorAsync(); /* handlePageFlip - latch a new buffer if available and compute the dirty @@ -606,7 +560,10 @@ private: const std::vector<ListenerCallbacks>& listenerCallbacks, const int64_t postTime, bool privileged, bool isMainThread = false) REQUIRES(mStateLock); + // Returns true if at least one transaction was flushed bool flushTransactionQueues(); + // Returns true if there is at least one transaction that needs to be flushed + bool transactionFlushNeeded(); uint32_t getTransactionFlags(uint32_t flags); uint32_t peekTransactionFlags(); // Can only be called from the main thread or with mStateLock held @@ -673,6 +630,8 @@ private: void startBootAnim(); + using TraverseLayersFunction = std::function<void(const LayerVector::Visitor&)>; + void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, ANativeWindowBuffer* buffer, bool useIdentityTransform, int* outSyncFd); @@ -958,12 +917,12 @@ private: // access must be protected by mStateLock mutable Mutex mStateLock; State mCurrentState{LayerVector::StateSet::Current}; - std::atomic<int32_t> mTransactionFlags{0}; + std::atomic<int32_t> mTransactionFlags = 0; Condition mTransactionCV; - bool mTransactionPending; - bool mAnimTransactionPending; - SortedVector< sp<Layer> > mLayersPendingRemoval; - bool mTraversalNeededMainThread; + bool mTransactionPending = false; + bool mAnimTransactionPending = false; + SortedVector<sp<Layer>> mLayersPendingRemoval; + bool mTraversalNeededMainThread = false; // guards access to the mDrawing state if tracing is enabled. mutable std::mutex mDrawingStateLock; @@ -978,31 +937,30 @@ private: size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS; // protected by mStateLock (but we could use another lock) - bool mLayersRemoved; - bool mLayersAdded; + bool mLayersRemoved = false; + bool mLayersAdded = false; - std::atomic<bool> mRepaintEverything{false}; + std::atomic<bool> mRepaintEverything = false; // constant members (no synchronization needed for access) - nsecs_t mBootTime; - bool mGpuToCpuSupported; + const nsecs_t mBootTime = systemTime(); + bool mGpuToCpuSupported = false; std::unique_ptr<EventThread> mInjectorEventThread; std::unique_ptr<InjectVSyncSource> mVSyncInjector; - std::unique_ptr<EventControlThread> mEventControlThread; // Calculates correct offsets. VSyncModulator mVsyncModulator; // Keeps track of all available phase offsets for different refresh types. - std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets; + const std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets; // Can only accessed from the main thread, these members // don't need synchronization State mDrawingState{LayerVector::StateSet::Drawing}; - bool mVisibleRegionsDirty; + bool mVisibleRegionsDirty = false; // Set during transaction commit stage to track if the input info for a layer has changed. - bool mInputInfoChanged{false}; - bool mGeometryInvalid; - bool mAnimCompositionPending; + bool mInputInfoChanged = false; + bool mGeometryInvalid = false; + bool mAnimCompositionPending = false; std::vector<sp<Layer>> mLayersWithQueuedFrames; // Tracks layers that need to update a display's dirty region. std::vector<sp<Layer>> mLayersPendingRefresh; @@ -1019,7 +977,7 @@ private: BOOTANIMATION, FINISHED, }; - BootStage mBootStage; + BootStage mBootStage = BootStage::BOOTLOADER; struct HotplugEvent { hwc2_display_t hwcDisplayId; @@ -1034,26 +992,22 @@ private: std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens; // don't use a lock for these, we don't care - int mDebugRegion; - int mDebugDisableHWC; - int mDebugDisableTransformHint; - bool mDebugEnableProtectedContent; - volatile nsecs_t mDebugInSwapBuffers; - volatile nsecs_t mDebugInTransaction; - nsecs_t mLastTransactionTime; - nsecs_t mPostFramebufferTime; - bool mForceFullDamage; + int mDebugRegion = 0; + bool mDebugDisableHWC = false; + bool mDebugDisableTransformHint = false; + volatile nsecs_t mDebugInTransaction = 0; + bool mForceFullDamage = false; bool mPropagateBackpressure = true; - std::unique_ptr<SurfaceInterceptor> mInterceptor{mFactory.createSurfaceInterceptor(this)}; - SurfaceTracing mTracing; + std::unique_ptr<SurfaceInterceptor> mInterceptor; + SurfaceTracing mTracing{*this}; bool mTracingEnabled = false; bool mTracingEnabledChanged GUARDED_BY(mStateLock) = false; LayerStats mLayerStats; - std::shared_ptr<TimeStats> mTimeStats; + const std::shared_ptr<TimeStats> mTimeStats; bool mUseHwcVirtualDisplays = false; - std::atomic<uint32_t> mFrameMissedCount{0}; - std::atomic<uint32_t> mHwcFrameMissedCount{0}; - std::atomic<uint32_t> mGpuFrameMissedCount{0}; + std::atomic<uint32_t> mFrameMissedCount = 0; + std::atomic<uint32_t> mHwcFrameMissedCount = 0; + std::atomic<uint32_t> mGpuFrameMissedCount = 0; TransactionCompletedThread mTransactionCompletedThread; @@ -1061,16 +1015,16 @@ private: bool mLayerTripleBufferingDisabled = false; // these are thread safe - mutable std::unique_ptr<MessageQueue> mEventQueue{mFactory.createMessageQueue()}; + std::unique_ptr<MessageQueue> mEventQueue; FrameTracker mAnimFrameTracker; // protected by mDestroyedLayerLock; mutable Mutex mDestroyedLayerLock; Vector<Layer const *> mDestroyedLayers; - nsecs_t mRefreshStartTime; + nsecs_t mRefreshStartTime = 0; - std::atomic<bool> mRefreshPending{false}; + std::atomic<bool> mRefreshPending = false; // We maintain a pool of pre-generated texture names to hand out to avoid // layer creation needing to run on the main thread (which it would @@ -1114,21 +1068,21 @@ private: * Feature prototyping */ - bool mInjectVSyncs; + bool mInjectVSyncs = false; // Static screen stats - bool mHasPoweredOff; + bool mHasPoweredOff = false; - size_t mNumLayers; + size_t mNumLayers = 0; // Verify that transaction is being called by an approved process: // either AID_GRAPHICS or AID_SYSTEM. status_t CheckTransactCodeCredentials(uint32_t code); std::unique_ptr<dvr::VrFlinger> mVrFlinger; - std::atomic<bool> mVrFlingerRequestsDisplay; + std::atomic<bool> mVrFlingerRequestsDisplay = false; static bool useVrFlinger; - std::thread::id mMainThreadId; + std::thread::id mMainThreadId = std::this_thread::get_id(); DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::ENHANCED; @@ -1175,23 +1129,30 @@ private: bool mDesiredActiveConfigChanged GUARDED_BY(mActiveConfigLock) = false; bool mCheckPendingFence = false; - /* ------------------------------------------------------------------------ */ bool mLumaSampling = true; sp<RegionSamplingThread> mRegionSamplingThread; + ui::DisplayPrimaries mInternalDisplayPrimaries; sp<IInputFlinger> mInputFlinger; - InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock); // Should only be accessed by the main thread. InputWindowCommands mInputWindowCommands; - ui::DisplayPrimaries mInternalDisplayPrimaries; - sp<SetInputWindowsListener> mSetInputWindowsListener; + struct SetInputWindowsListener : BnSetInputWindowsListener { + explicit SetInputWindowsListener(sp<SurfaceFlinger> flinger) + : mFlinger(std::move(flinger)) {} + + void onSetInputWindowsFinished() override; + + const sp<SurfaceFlinger> mFlinger; + }; + + const sp<SetInputWindowsListener> mSetInputWindowsListener = new SetInputWindowsListener(this); + bool mPendingSyncInputWindows GUARDED_BY(mStateLock); Hwc2::impl::PowerAdvisor mPowerAdvisor; std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay; }; -}; // namespace android -#endif // ANDROID_SURFACE_FLINGER_H +} // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 09b793a035..3522429a82 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -1,3 +1,18 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> @@ -223,6 +238,14 @@ bool use_smart_90_for_video(bool defaultValue) { return defaultValue; } +bool enable_protected_contents(bool defaultValue) { + auto temp = SurfaceFlingerProperties::enable_protected_contents(); + if (temp.has_value()) { + return *temp; + } + return defaultValue; +} + #define DISPLAY_PRIMARY_SIZE 3 constexpr float kSrgbRedX = 0.4123f; diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index b2fafddfe7..18642901d1 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -1,3 +1,18 @@ +/* + * 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. + */ #ifndef SURFACEFLINGERPROPERTIES_H_ #define SURFACEFLINGERPROPERTIES_H_ @@ -59,6 +74,8 @@ int32_t set_idle_timer_ms(int32_t defaultValue); bool use_smart_90_for_video(bool defaultValue); +bool enable_protected_contents(bool defaultValue); + android::ui::DisplayPrimaries getDisplayNativePrimaries(); } // namespace sysprop } // namespace android diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index 4be2ee9f59..4773307a65 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -41,7 +41,7 @@ constexpr auto operator""_MB(unsigned long long const num) { */ class SurfaceTracing { public: - SurfaceTracing(SurfaceFlinger& flinger); + explicit SurfaceTracing(SurfaceFlinger& flinger); void enable(); bool disable(); status_t writeToFile(); diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp index 1d2217d322..6b2b58346f 100644 --- a/services/surfaceflinger/TransactionCompletedThread.cpp +++ b/services/surfaceflinger/TransactionCompletedThread.cpp @@ -34,7 +34,8 @@ namespace android { // >0 if the first id that doesn't match is greater in c2 or all ids match but c2 is longer // // See CallbackIdsHash for a explaniation of why this works -static int compareCallbackIds(const std::vector<CallbackId>& c1, const std::vector<CallbackId> c2) { +static int compareCallbackIds(const std::vector<CallbackId>& c1, + const std::vector<CallbackId>& c2) { if (c1.empty()) { return !c2.empty(); } diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h index 09feb75d1a..21e2678701 100644 --- a/services/surfaceflinger/TransactionCompletedThread.h +++ b/services/surfaceflinger/TransactionCompletedThread.h @@ -37,7 +37,7 @@ struct CallbackIdsHash { // 2) CallbackId vectors for the same listener either are identical or contain none of the // same members. It is sufficient to just check the first CallbackId in the vectors. If // they match, they are the same. If they do not match, they are not the same. - std::size_t operator()(const std::vector<CallbackId> callbackIds) const { + std::size_t operator()(const std::vector<CallbackId>& callbackIds) const { return std::hash<CallbackId>{}((callbackIds.empty()) ? 0 : callbackIds.front()); } }; diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index fe6dc931f7..830c03eee7 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -307,3 +307,11 @@ prop { access: Readonly prop_name: "ro.surface_flinger.use_smart_90_for_video" } + +prop { + api_name: "enable_protected_contents" + type: Boolean + scope: Internal + access: Readonly + prop_name: "ro.surface_flinger.protected_contents" +} diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 12b41fd32c..d4eac88ba1 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -49,6 +49,7 @@ cc_test { "SchedulerUtilsTest.cpp", "RefreshRateConfigsTest.cpp", "RefreshRateStatsTest.cpp", + "RegionSamplingTest.cpp", "TimeStatsTest.cpp", "mock/DisplayHardware/MockComposer.cpp", "mock/DisplayHardware/MockDisplay.cpp", diff --git a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp new file mode 100644 index 0000000000..51d6d7e1df --- /dev/null +++ b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp @@ -0,0 +1,77 @@ +/* + * 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. + */ + +#undef LOG_TAG +#define LOG_TAG "RegionSamplingTest" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <array> +#include <limits> + +#include "RegionSamplingThread.h" + +namespace android { + +struct RegionSamplingTest : testing::Test { +public: + static uint32_t constexpr kBlack = 0; + static uint32_t constexpr kWhite = std::numeric_limits<uint32_t>::max(); + static int constexpr kWidth = 98; + static int constexpr kStride = 100; + static int constexpr kHeight = 29; + std::array<uint32_t, kHeight * kStride> buffer; + Rect const whole_area{0, 0, kWidth, kHeight}; +}; + +TEST_F(RegionSamplingTest, calculate_mean_white) { + std::fill(buffer.begin(), buffer.end(), kWhite); + EXPECT_THAT(sampleArea(buffer.data(), kStride, whole_area), testing::FloatEq(1.0f)); +} + +TEST_F(RegionSamplingTest, calculate_mean_black) { + std::fill(buffer.begin(), buffer.end(), kBlack); + EXPECT_THAT(sampleArea(buffer.data(), kStride, whole_area), testing::FloatEq(0.0f)); +} + +TEST_F(RegionSamplingTest, calculate_mean_partial_region) { + auto const halfway_down = kHeight >> 1; + auto const half = halfway_down * kStride; + Rect const partial_region = {whole_area.left, whole_area.top, whole_area.right, + whole_area.top + halfway_down}; + std::fill(buffer.begin(), buffer.begin() + half, 0); + std::fill(buffer.begin() + half, buffer.end(), kWhite); + EXPECT_THAT(sampleArea(buffer.data(), kStride, partial_region), testing::FloatEq(0.0f)); +} + +TEST_F(RegionSamplingTest, calculate_mean_mixed_values) { + std::generate(buffer.begin(), buffer.end(), [n = 0]() mutable { + uint32_t const pixel = (n % std::numeric_limits<uint8_t>::max()) << ((n % 3) * CHAR_BIT); + n++; + return pixel; + }); + EXPECT_THAT(sampleArea(buffer.data(), kStride, whole_area), testing::FloatNear(0.083f, 0.01f)); +} + +TEST_F(RegionSamplingTest, bimodal_tiebreaker) { + std::generate(buffer.begin(), buffer.end(), + [n = 0]() mutable { return (n++ % 2) ? kBlack : kWhite; }); + // presently there's no tiebreaking strategy in place, accept either of the means + EXPECT_THAT(sampleArea(buffer.data(), kStride, whole_area), + testing::AnyOf(testing::FloatEq(1.0), testing::FloatEq(0.0f))); +} + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 46fd964047..81235ba260 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -31,6 +31,7 @@ #include "FakePhaseOffsets.h" #include "Layer.h" #include "NativeWindowSurface.h" +#include "Scheduler/MessageQueue.h" #include "StartPropertySetThread.h" #include "SurfaceFlinger.h" #include "SurfaceFlingerFactory.h" @@ -276,8 +277,9 @@ public: auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what); } auto captureScreenImplLocked(const RenderArea& renderArea, - TraverseLayersFunction traverseLayers, ANativeWindowBuffer* buffer, - bool useIdentityTransform, bool forSystem, int* outSyncFd) { + SurfaceFlinger::TraverseLayersFunction traverseLayers, + ANativeWindowBuffer* buffer, bool useIdentityTransform, + bool forSystem, int* outSyncFd) { return mFlinger->captureScreenImplLocked(renderArea, traverseLayers, buffer, useIdentityTransform, forSystem, outSyncFd); } |