Merge "Updatable Driver: Decouple gfx_driver from sphal"
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
index c541511..38f036e 100644
--- a/include/android/system_fonts.h
+++ b/include/android/system_fonts.h
@@ -24,7 +24,7 @@
* The ASystemFontIterator_open method will give you an iterator which can iterate all system
* installed font files as shown in the following example.
*
- * <code>
+ * \code{.cpp}
* ASystemFontIterator* iterator = ASystemFontIterator_open();
* ASystemFont* font = NULL;
*
@@ -50,7 +50,7 @@
*
* // Use this font for your text rendering engine.
*
- * </code>
+ * \endcode
*
* Available since API level 29.
*/
@@ -142,7 +142,7 @@
/**
* Close an opened system font iterator, freeing any related resources.
*
- * \param a pointer of an iterator for the system fonts. Do nothing if NULL is passed.
+ * \param iterator a pointer of an iterator for the system fonts. Do nothing if NULL is passed.
*/
void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTRODUCED_IN(29);
@@ -174,7 +174,7 @@
* drawing Tofu character.
*
* Examples:
- * <code>
+ * \code{.cpp}
* // Simple font query for the ASCII character.
* std::vector<uint16_t> text = { 'A' };
* ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
@@ -202,15 +202,15 @@
* 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.
- * </code>
+ * \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.
- * \param textLength a length of the given text buffer.
+ * \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.
@@ -239,7 +239,7 @@
* 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 iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \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);
@@ -251,14 +251,11 @@
* Here are pairs of the common names and their values.
* <p>
* <table>
- * <thead>
* <tr>
* <th align="center">Value</th>
* <th align="center">Name</th>
* <th align="center">NDK Definition</th>
* </tr>
- * </thead>
- * <tbody>
* <tr>
* <td align="center">100</td>
* <td align="center">Thin</td>
@@ -304,13 +301,13 @@
* <td align="center">Black (Heavy)</td>
* <td align="center">{@link ASYSTEM_FONT_WEIGHT_BLACK}</td>
* </tr>
- * </tbody>
+ * </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 iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \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);
@@ -318,7 +315,7 @@
/**
* Return true if the current font is italic, otherwise returns false.
*
- * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \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);
@@ -330,7 +327,7 @@
*
* Note that the returned pointer is valid until ASystemFont_close() is called.
*
- * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \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);
@@ -342,7 +339,7 @@
* 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 iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \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);
@@ -356,7 +353,7 @@
* 'wght' 700, 'slnt' -12
* In this case, ASystemFont_getAxisCount returns 2 and ASystemFont_getAxisTag
* and ASystemFont_getAxisValue will return following values.
- * <code>
+ * \code{.cpp}
* ASystemFont* font = ASystemFontIterator_next(ite);
*
* // Returns the number of axes
@@ -369,11 +366,11 @@
* // Returns the tag-value pair for the second axis.
* ASystemFont_getAxisTag(font, 1); // Returns 'slnt'(0x736c6e74)
* ASystemFont_getAxisValue(font, 1); // Returns -12.0
- * </code>
+ * \endcode
*
* For more information about font variation settings, read [Font Variations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/fvar)
*
- * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \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);
@@ -384,8 +381,8 @@
*
* See ASystemFont_getAxisCount for more details.
*
- * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
- * \param an index to the font variation settings. Passing value larger than or
+ * \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.
*/
@@ -397,8 +394,8 @@
*
* See ASystemFont_getAxisCount for more details.
*
- * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
- * \param an index to the font variation settings. Passing value larger than or
+ * \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.
*/
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index 1ef8986..610834d 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -36,6 +36,9 @@
DECLARE_META_INTERFACE(InputFlinger)
virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles) = 0;
+
+ virtual void registerInputChannel(const sp<InputChannel>& channel) = 0;
+ virtual void unregisterInputChannel(const sp<InputChannel>& channel) = 0;
};
@@ -46,6 +49,8 @@
public:
enum {
SET_INPUT_WINDOWS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+ REGISTER_INPUT_CHANNEL_TRANSACTION,
+ UNREGISTER_INPUT_CHANNEL_TRANSACTION
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/input/Input.h b/include/input/Input.h
index cc45aef..ee22bc6 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -244,7 +244,12 @@
float getAxisValue(int32_t axis) const;
status_t setAxisValue(int32_t axis, float value);
- void scale(float scale);
+ void scale(float globalScale);
+
+ // Scale the pointer coordinates according to a global scale and a
+ // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR
+ // axes, however the window scaling will not.
+ void scale(float globalScale, float windowXScale, float windowYScale);
void applyOffset(float xOffset, float yOffset);
inline float getX() const {
@@ -595,7 +600,7 @@
void offsetLocation(float xOffset, float yOffset);
- void scale(float scaleFactor);
+ void scale(float globalScaleFactor);
// Apply 3x3 perspective matrix transformation.
// Matrix is in row-major form and compatible with SkMatrix.
diff --git a/include/input/InputApplication.h b/include/input/InputApplication.h
index 9b365b9..71a8f20 100644
--- a/include/input/InputApplication.h
+++ b/include/input/InputApplication.h
@@ -19,6 +19,9 @@
#include <string>
+#include <binder/IBinder.h>
+#include <binder/Parcel.h>
+
#include <input/Input.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
@@ -29,8 +32,12 @@
* Describes the properties of an application that can receive input.
*/
struct InputApplicationInfo {
+ sp<IBinder> token;
std::string name;
nsecs_t dispatchingTimeout;
+
+ status_t write(Parcel& output) const;
+ static InputApplicationInfo read(const Parcel& from);
};
@@ -54,6 +61,10 @@
return mInfo ? mInfo->dispatchingTimeout : defaultValue;
}
+ inline sp<IBinder> getApplicationToken() const {
+ return mInfo ? mInfo->token : nullptr;
+ }
+
/**
* Requests that the state of this object be updated to reflect
* the most current available information about the application.
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 9e3d334..8dd95cf 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -116,17 +116,42 @@
INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002,
INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004,
};
-
- sp<InputChannel> inputChannel;
+
+ /* These values are filled in by the WM and passed through SurfaceFlinger
+ * unless specified otherwise.
+ */
+ sp<IBinder> token;
std::string name;
int32_t layoutParamsFlags;
int32_t layoutParamsType;
nsecs_t dispatchingTimeout;
+
+ /* These values are filled in by SurfaceFlinger. */
int32_t frameLeft;
int32_t frameTop;
int32_t frameRight;
int32_t frameBottom;
- float scaleFactor;
+
+ /*
+ * SurfaceFlinger consumes this value to shrink the computed frame. This is
+ * different from shrinking the touchable region in that it DOES shift the coordinate
+ * space where-as the touchable region does not and is more like "cropping". This
+ * is used for window shadows.
+ */
+ int32_t surfaceInset = 0;
+
+ // A global scaling factor for all windows. Unlike windowScaleX/Y this results
+ // in scaling of the TOUCH_MAJOR/TOUCH_MINOR axis.
+ float globalScaleFactor;
+
+ // Scaling factors applied to individual windows.
+ float windowXScale = 1.0f;
+ float windowYScale = 1.0f;
+
+ /*
+ * This is filled in by the WM relative to the frame and then translated
+ * to absolute coordinates by SurfaceFlinger once the frame is computed.
+ */
Region touchableRegion;
bool visible;
bool canReceiveKeys;
@@ -138,6 +163,7 @@
int32_t ownerUid;
int32_t inputFeatures;
int32_t displayId;
+ InputApplicationInfo applicationInfo;
void addTouchableRegion(const Rect& region);
@@ -168,20 +194,23 @@
*/
class InputWindowHandle : public RefBase {
public:
- const sp<InputApplicationHandle> inputApplicationHandle;
inline const InputWindowInfo* getInfo() const {
return &mInfo;
}
- sp<InputChannel> getInputChannel() const;
+ sp<IBinder> getToken() const;
+
+ sp<IBinder> getApplicationToken() {
+ return mInfo.applicationInfo.token;
+ }
inline std::string getName() const {
- return mInfo.inputChannel ? mInfo.name : "<invalid>";
+ return mInfo.token ? mInfo.name : "<invalid>";
}
inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
- return mInfo.inputChannel? mInfo.dispatchingTimeout : defaultValue;
+ return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
}
/**
@@ -202,7 +231,7 @@
void releaseChannel();
protected:
- explicit InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
+ explicit InputWindowHandle();
virtual ~InputWindowHandle();
InputWindowInfo mInfo;
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index f0c21f5..8df83f1 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -109,9 +109,7 @@
"BC_DEAD_BINDER_DONE"
};
-// The work source represents the UID of the process we should attribute the transaction to.
-// We use -1 to specify that the work source was not set using #setWorkSource.
-static const int kUnsetWorkSource = -1;
+static const int64_t kWorkSourcePropagatedBitIndex = 32;
static const char* getReturnString(uint32_t cmd)
{
@@ -389,12 +387,29 @@
int64_t IPCThreadState::setCallingWorkSourceUid(uid_t uid)
{
- // Note: we currently only use half of the int64. We return an int64 for extensibility.
- int64_t token = mWorkSource;
+ int64_t token = setCallingWorkSourceUidWithoutPropagation(uid);
+ mPropagateWorkSource = true;
+ return token;
+}
+
+int64_t IPCThreadState::setCallingWorkSourceUidWithoutPropagation(uid_t uid)
+{
+ const int64_t propagatedBit = ((int64_t)mPropagateWorkSource) << kWorkSourcePropagatedBitIndex;
+ int64_t token = propagatedBit | mWorkSource;
mWorkSource = uid;
return token;
}
+void IPCThreadState::clearPropagateWorkSource()
+{
+ mPropagateWorkSource = false;
+}
+
+bool IPCThreadState::shouldPropagateWorkSource() const
+{
+ return mPropagateWorkSource;
+}
+
uid_t IPCThreadState::getCallingWorkSourceUid() const
{
return mWorkSource;
@@ -408,7 +423,8 @@
void IPCThreadState::restoreCallingWorkSource(int64_t token)
{
uid_t uid = (int)token;
- setCallingWorkSourceUid(uid);
+ setCallingWorkSourceUidWithoutPropagation(uid);
+ mPropagateWorkSource = ((token >> kWorkSourcePropagatedBitIndex) & 1) == 1;
}
void IPCThreadState::setLastTransactionBinderFlags(int32_t flags)
@@ -765,6 +781,7 @@
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mWorkSource(kUnsetWorkSource),
+ mPropagateWorkSource(false),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0)
{
@@ -1127,6 +1144,13 @@
const uid_t origUid = mCallingUid;
const int32_t origStrictModePolicy = mStrictModePolicy;
const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
+ const int32_t origWorkSource = mWorkSource;
+ const bool origPropagateWorkSet = mPropagateWorkSource;
+ // Calling work source will be set by Parcel#enforceInterface. Parcel#enforceInterface
+ // is only guaranteed to be called for AIDL-generated stubs so we reset the work source
+ // here to never propagate it.
+ clearCallingWorkSource();
+ clearPropagateWorkSource();
mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid;
@@ -1179,6 +1203,8 @@
mCallingUid = origUid;
mStrictModePolicy = origStrictModePolicy;
mLastTransactionBinderFlags = origTransactionBinderFlags;
+ mWorkSource = origWorkSource;
+ mPropagateWorkSource = origPropagateWorkSet;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 643f428..a0a634a 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -599,9 +599,10 @@
// Write RPC headers. (previously just the interface token)
status_t Parcel::writeInterfaceToken(const String16& interface)
{
- writeInt32(IPCThreadState::self()->getStrictModePolicy() |
- STRICT_MODE_PENALTY_GATHER);
- writeInt32(IPCThreadState::self()->getCallingWorkSourceUid());
+ const IPCThreadState* threadState = IPCThreadState::self();
+ writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
+ writeInt32(threadState->shouldPropagateWorkSource() ?
+ threadState->getCallingWorkSourceUid() : IPCThreadState::kUnsetWorkSource);
// currently the interface identification token is just its name as a string
return writeString16(interface);
}
@@ -631,7 +632,7 @@
}
// WorkSource.
int32_t workSource = readInt32();
- threadState->setCallingWorkSourceUid(workSource);
+ threadState->setCallingWorkSourceUidWithoutPropagation(workSource);
// Interface descriptor.
const String16 str(readString16());
if (str == interface) {
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index de126d5..75b348c 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -49,12 +49,16 @@
// See Binder#setCallingWorkSourceUid in Binder.java.
int64_t setCallingWorkSourceUid(uid_t uid);
+ // Internal only. Use setCallingWorkSourceUid(uid) instead.
+ int64_t setCallingWorkSourceUidWithoutPropagation(uid_t uid);
// See Binder#getCallingWorkSourceUid in Binder.java.
uid_t getCallingWorkSourceUid() const;
// See Binder#clearCallingWorkSource in Binder.java.
int64_t clearCallingWorkSource();
// See Binder#restoreCallingWorkSource in Binder.java.
void restoreCallingWorkSource(int64_t token);
+ void clearPropagateWorkSource();
+ bool shouldPropagateWorkSource() const;
void setLastTransactionBinderFlags(int32_t flags);
int32_t getLastTransactionBinderFlags() const;
@@ -127,6 +131,11 @@
// infer information about thread state.
bool isServingCall() const;
+ // The work source represents the UID of the process we should attribute the transaction
+ // to.
+ // We use -1 to specify that the work source was not set using #setWorkSource.
+ static const int32_t kUnsetWorkSource = -1;
+
private:
IPCThreadState();
~IPCThreadState();
@@ -167,6 +176,8 @@
// The UID of the process who is responsible for this transaction.
// This is used for resource attribution.
int32_t mWorkSource;
+ // Whether the work source should be propagated.
+ bool mPropagateWorkSource;
int32_t mStrictModePolicy;
int32_t mLastTransactionBinderFlags;
IPCThreadStateBase *mIPCThreadStateBase;
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
index e2c0cfa..c6fcaa4 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -163,7 +163,9 @@
ScopedAResource& operator=(ScopedAResource&&) = delete;
// move-constructing is okay
- ScopedAResource(ScopedAResource&&) = default;
+ ScopedAResource(ScopedAResource&& other) : mT(std::move(other.mT)) {
+ other.mT = DEFAULT;
+ }
private:
T mT;
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 3594349..866af70 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -54,6 +54,31 @@
void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29);
/**
+ * Sets the position within the parcel.
+ *
+ * \param parcel The parcel of which to set the position.
+ * \param position Position of the parcel to set. This must be a value returned by
+ * AParcel_getDataPosition. Positions are constant for a given parcel between processes.
+ *
+ * \return STATUS_OK on success. If position is negative, then STATUS_BAD_VALUE will be returned.
+ */
+binder_status_t AParcel_setDataPosition(const AParcel* parcel, int32_t position)
+ __INTRODUCED_IN(29);
+
+/**
+ * Gets the current position within the parcel.
+ *
+ * \param parcel The parcel of which to get the position.
+ *
+ * \return The size of the parcel. This will always be greater than 0. The values returned by this
+ * function before and after calling various reads and writes are not defined. Only the delta
+ * between two positions between a specific sequence of calls is defined. For instance, if position
+ * is X, writeBool is called, and then position is Y, readBool can be called from position X will
+ * return the same value, and then position will be Y.
+ */
+int32_t AParcel_getDataPosition(const AParcel* parcel) __INTRODUCED_IN(29);
+
+/**
* This is called to allocate a buffer for a C-style string (null-terminated). The returned buffer
* should be at least length bytes. This includes space for a null terminator. For a string, length
* will always be strictly less than or equal to the maximum size that can be held in a size_t and
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 41df90b..4328b6e 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -25,6 +25,7 @@
AIBinder_Weak_new;
AIBinder_Weak_promote;
AParcel_delete;
+ AParcel_getDataPosition;
AParcel_readBool;
AParcel_readBoolArray;
AParcel_readByte;
@@ -48,6 +49,7 @@
AParcel_readUint32Array;
AParcel_readUint64;
AParcel_readUint64Array;
+ AParcel_setDataPosition;
AParcel_writeBool;
AParcel_writeBoolArray;
AParcel_writeByte;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 3c32100..2d68559 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -212,6 +212,19 @@
delete parcel;
}
+binder_status_t AParcel_setDataPosition(const AParcel* parcel, int32_t position) {
+ if (position < 0) {
+ return STATUS_BAD_VALUE;
+ }
+
+ parcel->get()->setDataPosition(position);
+ return STATUS_OK;
+}
+
+int32_t AParcel_getDataPosition(const AParcel* parcel) {
+ return parcel->get()->dataPosition();
+}
+
binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) {
sp<IBinder> writeBinder = binder != nullptr ? binder->getBinder() : nullptr;
return parcel->get()->writeStrongBinder(writeBinder);
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 22c1bad..cd37d49 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -180,6 +180,7 @@
public:
virtual void SetUp() {
m_server = static_cast<BinderLibTestEnv *>(binder_env)->getServer();
+ IPCThreadState::self()->restoreCallingWorkSource(0);
}
virtual void TearDown() {
}
@@ -953,11 +954,28 @@
{
status_t ret;
Parcel data, reply;
+ IPCThreadState::self()->clearCallingWorkSource();
int64_t previousWorkSource = IPCThreadState::self()->setCallingWorkSourceUid(100);
data.writeInterfaceToken(binderLibTestServiceName);
ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
EXPECT_EQ(100, reply.readInt32());
EXPECT_EQ(-1, previousWorkSource);
+ EXPECT_EQ(true, IPCThreadState::self()->shouldPropagateWorkSource());
+ EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, WorkSourceSetWithoutPropagation)
+{
+ status_t ret;
+ Parcel data, reply;
+
+ IPCThreadState::self()->setCallingWorkSourceUidWithoutPropagation(100);
+ EXPECT_EQ(false, IPCThreadState::self()->shouldPropagateWorkSource());
+
+ data.writeInterfaceToken(binderLibTestServiceName);
+ ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+ EXPECT_EQ(-1, reply.readInt32());
+ EXPECT_EQ(false, IPCThreadState::self()->shouldPropagateWorkSource());
EXPECT_EQ(NO_ERROR, ret);
}
@@ -967,7 +985,8 @@
Parcel data, reply;
IPCThreadState::self()->setCallingWorkSourceUid(100);
- int64_t previousWorkSource = IPCThreadState::self()->clearCallingWorkSource();
+ int64_t token = IPCThreadState::self()->clearCallingWorkSource();
+ int32_t previousWorkSource = (int32_t)token;
data.writeInterfaceToken(binderLibTestServiceName);
ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
@@ -989,9 +1008,58 @@
ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
EXPECT_EQ(100, reply.readInt32());
+ EXPECT_EQ(true, IPCThreadState::self()->shouldPropagateWorkSource());
EXPECT_EQ(NO_ERROR, ret);
}
+TEST_F(BinderLibTest, PropagateFlagSet)
+{
+ status_t ret;
+ Parcel data, reply;
+
+ IPCThreadState::self()->clearPropagateWorkSource();
+ IPCThreadState::self()->setCallingWorkSourceUid(100);
+ EXPECT_EQ(true, IPCThreadState::self()->shouldPropagateWorkSource());
+}
+
+TEST_F(BinderLibTest, PropagateFlagCleared)
+{
+ status_t ret;
+ Parcel data, reply;
+
+ IPCThreadState::self()->setCallingWorkSourceUid(100);
+ IPCThreadState::self()->clearPropagateWorkSource();
+ EXPECT_EQ(false, IPCThreadState::self()->shouldPropagateWorkSource());
+}
+
+TEST_F(BinderLibTest, PropagateFlagRestored)
+{
+ status_t ret;
+ Parcel data, reply;
+
+ int token = IPCThreadState::self()->setCallingWorkSourceUid(100);
+ IPCThreadState::self()->restoreCallingWorkSource(token);
+
+ EXPECT_EQ(false, IPCThreadState::self()->shouldPropagateWorkSource());
+}
+
+TEST_F(BinderLibTest, WorkSourcePropagatedForAllFollowingBinderCalls)
+{
+ IPCThreadState::self()->setCallingWorkSourceUid(100);
+
+ Parcel data, reply;
+ status_t ret;
+ data.writeInterfaceToken(binderLibTestServiceName);
+ ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+
+ Parcel data2, reply2;
+ status_t ret2;
+ data2.writeInterfaceToken(binderLibTestServiceName);
+ ret2 = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data2, &reply2);
+ EXPECT_EQ(100, reply2.readInt32());
+ EXPECT_EQ(NO_ERROR, ret2);
+}
+
class BinderLibTestService : public BBinder
{
public:
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 0d224d8..04884bb 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -48,6 +48,7 @@
"android.hardware.drm@1.0::IDrmFactory",
"android.hardware.graphics.allocator@2.0::IAllocator",
"android.hardware.graphics.composer@2.1::IComposer",
+ "android.hardware.health@2.0::IHealth",
"android.hardware.media.omx@1.0::IOmx",
"android.hardware.media.omx@1.0::IOmxStore",
"android.hardware.sensors@1.0::ISensors",
diff --git a/libs/gui/HdrMetadata.cpp b/libs/gui/HdrMetadata.cpp
index b715e43..add3ef0 100644
--- a/libs/gui/HdrMetadata.cpp
+++ b/libs/gui/HdrMetadata.cpp
@@ -15,6 +15,7 @@
*/
#include <gui/HdrMetadata.h>
+#include <limits>
namespace android {
@@ -26,6 +27,10 @@
if (validTypes & CTA861_3) {
size += sizeof(cta8613);
}
+ if (validTypes & HDR10PLUS) {
+ size += sizeof(size_t);
+ size += hdr10plus.size();
+ }
return size;
}
@@ -41,6 +46,12 @@
if (validTypes & CTA861_3) {
FlattenableUtils::write(buffer, size, cta8613);
}
+ if (validTypes & HDR10PLUS) {
+ size_t metadataSize = hdr10plus.size();
+ FlattenableUtils::write(buffer, size, metadataSize);
+ memcpy(buffer, hdr10plus.data(), metadataSize);
+ FlattenableUtils::advance(buffer, size, metadataSize);
+ }
return NO_ERROR;
}
@@ -62,6 +73,22 @@
}
FlattenableUtils::read(buffer, size, cta8613);
}
+ if (validTypes & HDR10PLUS) {
+ if (size < sizeof(size_t)) {
+ return NO_MEMORY;
+ }
+
+ size_t metadataSize;
+ FlattenableUtils::read(buffer, size, metadataSize);
+
+ if (size < metadataSize) {
+ return NO_MEMORY;
+ }
+
+ hdr10plus.resize(metadataSize);
+ memcpy(hdr10plus.data(), buffer, metadataSize);
+ FlattenableUtils::advance(buffer, size, metadataSize);
+ }
return NO_ERROR;
}
@@ -91,6 +118,10 @@
}
}
+ if ((validTypes & HDR10PLUS) == HDR10PLUS) {
+ if (hdr10plus != rhs.hdr10plus) return false;
+ }
+
return true;
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index b505c6f..00e23f0 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -965,6 +965,9 @@
case NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA:
res = dispatchSetBuffersCta8613Metadata(args);
break;
+ case NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA:
+ res = dispatchSetBuffersHdr10PlusMetadata(args);
+ break;
case NATIVE_WINDOW_SET_SURFACE_DAMAGE:
res = dispatchSetSurfaceDamage(args);
break;
@@ -1120,6 +1123,12 @@
return setBuffersCta8613Metadata(metadata);
}
+int Surface::dispatchSetBuffersHdr10PlusMetadata(va_list args) {
+ const size_t size = va_arg(args, size_t);
+ const uint8_t* metadata = va_arg(args, const uint8_t*);
+ return setBuffersHdr10PlusMetadata(size, metadata);
+}
+
int Surface::dispatchSetSurfaceDamage(va_list args) {
android_native_rect_t* rects = va_arg(args, android_native_rect_t*);
size_t numRects = va_arg(args, size_t);
@@ -1568,6 +1577,19 @@
return NO_ERROR;
}
+int Surface::setBuffersHdr10PlusMetadata(const size_t size, const uint8_t* metadata) {
+ ALOGV("Surface::setBuffersBlobMetadata");
+ Mutex::Autolock lock(mMutex);
+ if (size > 0) {
+ mHdrMetadata.hdr10plus.assign(metadata, metadata + size);
+ mHdrMetadata.validTypes |= HdrMetadata::HDR10PLUS;
+ } else {
+ mHdrMetadata.validTypes &= ~HdrMetadata::HDR10PLUS;
+ mHdrMetadata.hdr10plus.clear();
+ }
+ return NO_ERROR;
+}
+
Dataspace Surface::getBuffersDataSpace() {
ALOGV("Surface::getBuffersDataSpace");
Mutex::Autolock lock(mMutex);
diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h
index 9800602..1e9c3e7 100644
--- a/libs/gui/include/gui/HdrMetadata.h
+++ b/libs/gui/include/gui/HdrMetadata.h
@@ -17,6 +17,7 @@
#pragma once
#include <stdint.h>
+#include <vector>
#include <system/graphics.h>
#include <utils/Flattenable.h>
@@ -26,12 +27,15 @@
struct HdrMetadata : public LightFlattenable<HdrMetadata> {
enum Type : uint32_t {
SMPTE2086 = 1 << 0,
- CTA861_3 = 1 << 1,
+ CTA861_3 = 1 << 1,
+ HDR10PLUS = 1 << 2,
};
+
uint32_t validTypes{0};
android_smpte2086_metadata smpte2086{};
android_cta861_3_metadata cta8613{};
+ std::vector<uint8_t> hdr10plus{};
// LightFlattenable
bool isFixedSize() const { return false; }
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 32ee595..248e105 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -218,6 +218,7 @@
int dispatchSetBuffersDataSpace(va_list args);
int dispatchSetBuffersSmpte2086Metadata(va_list args);
int dispatchSetBuffersCta8613Metadata(va_list args);
+ int dispatchSetBuffersHdr10PlusMetadata(va_list args);
int dispatchSetSurfaceDamage(va_list args);
int dispatchSetSharedBufferMode(va_list args);
int dispatchSetAutoRefresh(va_list args);
@@ -249,6 +250,7 @@
virtual int setBuffersDataSpace(ui::Dataspace dataSpace);
virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata);
virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata);
+ virtual int setBuffersHdr10PlusMetadata(const size_t size, const uint8_t* metadata);
virtual int setCrop(Rect const* rect);
virtual int setUsage(uint64_t reqUsage);
virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 7ecadf8..a6295e0 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -16,6 +16,7 @@
"BufferItemConsumer_test.cpp",
"BufferQueue_test.cpp",
"CpuConsumer_test.cpp",
+ "EndToEndNativeInputTest.cpp",
"FillBuffer.cpp",
"GLTest.cpp",
"IGraphicBufferProducer_test.cpp",
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
new file mode 100644
index 0000000..86e9c23
--- /dev/null
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -0,0 +1,271 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <poll.h>
+
+#include <memory>
+
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+
+#include <input/InputWindow.h>
+#include <input/IInputFlinger.h>
+#include <input/InputTransport.h>
+#include <input/Input.h>
+
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+
+namespace android {
+namespace test {
+
+sp<IInputFlinger> getInputFlinger() {
+ sp<IBinder> input(defaultServiceManager()->getService(
+ String16("inputflinger")));
+ if (input == nullptr) {
+ ALOGE("Failed to link to input service");
+ } else { ALOGE("Linked to input"); }
+ return interface_cast<IInputFlinger>(input);
+}
+
+// We use the top 10 layers as a way to haphazardly place ourselves above anything else.
+static const int LAYER_BASE = INT32_MAX - 10;
+
+class InputSurface {
+public:
+ InputSurface(const sp<SurfaceComposerClient>& scc, int width, int height) {
+ mSurfaceControl = scc->createSurface(String8("Test Surface"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor);
+
+ InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
+ mServerChannel->setToken(new BBinder());
+
+ mInputFlinger = getInputFlinger();
+ mInputFlinger->registerInputChannel(mServerChannel);
+
+ populateInputInfo(width, height);
+
+ mInputConsumer = new InputConsumer(mClientChannel);
+ }
+
+ InputEvent* consumeEvent() {
+ waitForEventAvailable();
+
+ InputEvent *ev;
+ uint32_t seqId;
+ status_t consumed = mInputConsumer->consume(&mInputEventFactory, true, -1, &seqId, &ev);
+ if (consumed != OK) {
+ return nullptr;
+ }
+ mInputConsumer->sendFinishedSignal(seqId, true);
+ return ev;
+ }
+
+ void expectTap(int x, int y) {
+ InputEvent* ev = consumeEvent();
+ EXPECT_TRUE(ev != nullptr);
+ EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION);
+ MotionEvent* mev = static_cast<MotionEvent*>(ev);
+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction());
+ EXPECT_EQ(x, mev->getX(0));
+ EXPECT_EQ(y, mev->getY(0));
+
+ ev = consumeEvent();
+ EXPECT_TRUE(ev != nullptr);
+ EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION);
+ mev = static_cast<MotionEvent*>(ev);
+ EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
+ }
+
+ ~InputSurface() {
+ mInputFlinger->unregisterInputChannel(mServerChannel);
+ }
+
+ void doTransaction(std::function<void(SurfaceComposerClient::Transaction&,
+ const sp<SurfaceControl>&)> transactionBody) {
+ SurfaceComposerClient::Transaction t;
+ transactionBody(t, mSurfaceControl);
+ t.apply(true);
+ }
+
+ void showAt(int x, int y) {
+ SurfaceComposerClient::Transaction t;
+ t.show(mSurfaceControl);
+ t.setInputWindowInfo(mSurfaceControl, mInputInfo);
+ t.setLayer(mSurfaceControl, LAYER_BASE);
+ t.setPosition(mSurfaceControl, x, y);
+ t.setCrop_legacy(mSurfaceControl, Rect(0, 0, 100, 100));
+ t.setAlpha(mSurfaceControl, 1);
+ t.apply(true);
+ }
+
+private:
+ void waitForEventAvailable() {
+ struct pollfd fd;
+
+ fd.fd = mClientChannel->getFd();
+ fd.events = POLLIN;
+ poll(&fd, 1, 3000);
+ }
+
+ void populateInputInfo(int width, int height) {
+ mInputInfo.token = mServerChannel->getToken();
+ mInputInfo.name = "Test info";
+ mInputInfo.layoutParamsFlags = InputWindowInfo::FLAG_NOT_TOUCH_MODAL;
+ mInputInfo.layoutParamsType = InputWindowInfo::TYPE_BASE_APPLICATION;
+ mInputInfo.dispatchingTimeout = 100000;
+ mInputInfo.globalScaleFactor = 1.0;
+ mInputInfo.canReceiveKeys = true;
+ mInputInfo.hasFocus = true;
+ mInputInfo.hasWallpaper = false;
+ mInputInfo.paused = false;
+
+ mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height));
+
+ // TODO: Fill in from SF?
+ mInputInfo.ownerPid = 11111;
+ mInputInfo.ownerUid = 11111;
+ mInputInfo.inputFeatures = 0;
+ mInputInfo.displayId = 0;
+
+ InputApplicationInfo aInfo;
+ aInfo.token = new BBinder();
+ aInfo.name = "Test app info";
+ aInfo.dispatchingTimeout = 100000;
+
+ mInputInfo.applicationInfo = aInfo;
+ }
+public:
+ sp<SurfaceControl> mSurfaceControl;
+ sp<InputChannel> mServerChannel, mClientChannel;
+ sp<IInputFlinger> mInputFlinger;
+
+ InputWindowInfo mInputInfo;
+
+ PreallocatedInputEventFactory mInputEventFactory;
+ InputConsumer* mInputConsumer;
+};
+
+class InputSurfacesTest : public ::testing::Test {
+public:
+ InputSurfacesTest() {
+ ProcessState::self()->startThreadPool();
+ }
+
+ void SetUp() {
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+ }
+
+ void TearDown() {
+ mComposerClient->dispose();
+ }
+
+ std::unique_ptr<InputSurface> makeSurface(int width, int height) {
+ return std::make_unique<InputSurface>(mComposerClient, width, height);
+ }
+
+ sp<SurfaceComposerClient> mComposerClient;
+};
+
+void injectTap(int x, int y) {
+ char *buf1, *buf2;
+ asprintf(&buf1, "%d", x);
+ asprintf(&buf2, "%d", y);
+ if (fork() == 0) {
+ execlp("input", "input", "tap", buf1, buf2, NULL);
+ }
+}
+
+TEST_F(InputSurfacesTest, can_receive_input) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(100, 100);
+
+ injectTap(101, 101);
+
+ EXPECT_TRUE(surface->consumeEvent() != nullptr);
+}
+
+TEST_F(InputSurfacesTest, input_respects_positioning) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(100, 100);
+
+ std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
+ surface2->showAt(200, 200);
+
+ injectTap(201, 201);
+ surface2->expectTap(1, 1);
+
+ injectTap(101, 101);
+ surface->expectTap(1, 1);
+
+ surface2->doTransaction([](auto &t, auto &sc) {
+ t.setPosition(sc, 100, 100);
+ });
+ surface->doTransaction([](auto &t, auto &sc) {
+ t.setPosition(sc, 200, 200);
+ });
+
+ injectTap(101, 101);
+ surface2->expectTap(1, 1);
+
+ injectTap(201, 201);
+ surface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_layering) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
+
+ surface->showAt(10, 10);
+ surface2->showAt(10, 10);
+
+ surface->doTransaction([](auto &t, auto &sc) {
+ t.setLayer(sc, LAYER_BASE + 1);
+ });
+
+ injectTap(11, 11);
+ surface->expectTap(1, 1);
+
+ surface2->doTransaction([](auto &t, auto &sc) {
+ t.setLayer(sc, LAYER_BASE + 1);
+ });
+
+ injectTap(11, 11);
+ surface2->expectTap(1, 1);
+
+ surface2->doTransaction([](auto &t, auto &sc) {
+ t.hide(sc);
+ });
+
+ injectTap(11, 11);
+ surface->expectTap(1, 1);
+}
+
+}
+}
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index d0600da..4ba7da3 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -366,10 +366,17 @@
78.0,
62.0,
};
+
+ std::vector<uint8_t> hdr10plus;
+ hdr10plus.push_back(0xff);
+
int error = native_window_set_buffers_smpte2086_metadata(window.get(), &smpte2086);
ASSERT_EQ(error, NO_ERROR);
error = native_window_set_buffers_cta861_3_metadata(window.get(), &cta861_3);
ASSERT_EQ(error, NO_ERROR);
+ error = native_window_set_buffers_hdr10_plus_metadata(window.get(), hdr10plus.size(),
+ hdr10plus.data());
+ ASSERT_EQ(error, NO_ERROR);
}
TEST_F(SurfaceTest, DynamicSetBufferCount) {
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index 47a2c0c..477e54e 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -40,6 +40,20 @@
}
remote()->transact(BnInputFlinger::SET_INPUT_WINDOWS_TRANSACTION, data, &reply);
}
+
+ virtual void registerInputChannel(const sp<InputChannel>& channel) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+ channel->write(data);
+ remote()->transact(BnInputFlinger::REGISTER_INPUT_CHANNEL_TRANSACTION, data, &reply);
+ }
+
+ virtual void unregisterInputChannel(const sp<InputChannel>& channel) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+ channel->write(data);
+ remote()->transact(BnInputFlinger::UNREGISTER_INPUT_CHANNEL_TRANSACTION, data, &reply);
+ }
};
IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger");
@@ -61,6 +75,20 @@
setInputWindows(handles);
break;
}
+ case REGISTER_INPUT_CHANNEL_TRANSACTION: {
+ CHECK_INTERFACE(IInputFlinger, data, reply);
+ sp<InputChannel> channel = new InputChannel();
+ channel->read(data);
+ registerInputChannel(channel);
+ break;
+ }
+ case UNREGISTER_INPUT_CHANNEL_TRANSACTION: {
+ CHECK_INTERFACE(IInputFlinger, data, reply);
+ sp<InputChannel> channel = new InputChannel();
+ channel->read(data);
+ unregisterInputChannel(channel);
+ break;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 8a15e2f..a558970 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -131,15 +131,24 @@
}
}
-void PointerCoords::scale(float scaleFactor) {
+void PointerCoords::scale(float globalScaleFactor, float windowXScale, float windowYScale) {
// No need to scale pressure or size since they are normalized.
// No need to scale orientation since it is meaningless to do so.
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
+
+ // If there is a global scale factor, it is included in the windowX/YScale
+ // so we don't need to apply it twice to the X/Y axes.
+ // However we don't want to apply any windowXYScale not included in the global scale
+ // to the TOUCH_MAJOR/MINOR coordinates.
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, windowXScale);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, windowYScale);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, globalScaleFactor);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, globalScaleFactor);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, globalScaleFactor);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, globalScaleFactor);
+}
+
+void PointerCoords::scale(float globalScaleFactor) {
+ scale(globalScaleFactor, globalScaleFactor, globalScaleFactor);
}
void PointerCoords::applyOffset(float xOffset, float yOffset) {
@@ -345,15 +354,15 @@
mYOffset += yOffset;
}
-void MotionEvent::scale(float scaleFactor) {
- mXOffset *= scaleFactor;
- mYOffset *= scaleFactor;
- mXPrecision *= scaleFactor;
- mYPrecision *= scaleFactor;
+void MotionEvent::scale(float globalScaleFactor) {
+ mXOffset *= globalScaleFactor;
+ mYOffset *= globalScaleFactor;
+ mXPrecision *= globalScaleFactor;
+ mYPrecision *= globalScaleFactor;
size_t numSamples = mSamplePointerCoords.size();
for (size_t i = 0; i < numSamples; i++) {
- mSamplePointerCoords.editItemAt(i).scale(scaleFactor);
+ mSamplePointerCoords.editItemAt(i).scale(globalScaleFactor);
}
}
diff --git a/libs/input/InputApplication.cpp b/libs/input/InputApplication.cpp
index a0d1668..7936f50 100644
--- a/libs/input/InputApplication.cpp
+++ b/libs/input/InputApplication.cpp
@@ -39,4 +39,21 @@
}
}
+InputApplicationInfo InputApplicationInfo::read(const Parcel& from) {
+ InputApplicationInfo ret;
+ ret.token = from.readStrongBinder();
+ ret.name = from.readString8().c_str();
+ ret.dispatchingTimeout = from.readInt64();
+
+ return ret;
+}
+
+status_t InputApplicationInfo::write(Parcel& output) const {
+ output.writeStrongBinder(token);
+ output.writeString8(String8(name.c_str()));
+ output.writeInt64(dispatchingTimeout);
+
+ return OK;
+}
+
} // namespace android
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index f82437e..556a005 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -65,12 +65,12 @@
}
status_t InputWindowInfo::write(Parcel& output) const {
- if (inputChannel == nullptr) {
+ if (token == nullptr) {
output.writeInt32(0);
return OK;
}
output.writeInt32(1);
- status_t s = inputChannel->write(output);
+ status_t s = output.writeStrongBinder(token);
if (s != OK) return s;
output.writeString8(String8(name.c_str()));
@@ -81,7 +81,10 @@
output.writeInt32(frameTop);
output.writeInt32(frameRight);
output.writeInt32(frameBottom);
- output.writeFloat(scaleFactor);
+ output.writeInt32(surfaceInset);
+ output.writeFloat(globalScaleFactor);
+ output.writeFloat(windowXScale);
+ output.writeFloat(windowYScale);
output.writeBool(visible);
output.writeBool(canReceiveKeys);
output.writeBool(hasFocus);
@@ -92,6 +95,7 @@
output.writeInt32(ownerUid);
output.writeInt32(inputFeatures);
output.writeInt32(displayId);
+ applicationInfo.write(output);
output.write(touchableRegion);
return OK;
@@ -102,15 +106,14 @@
if (from.readInt32() == 0) {
return ret;
-
}
- sp<InputChannel> inputChannel = new InputChannel();
- status_t s = inputChannel->read(from);
- if (s != OK) {
+
+ sp<IBinder> token = from.readStrongBinder();
+ if (token == nullptr) {
return ret;
}
- ret.inputChannel = inputChannel;
+ ret.token = token;
ret.name = from.readString8().c_str();
ret.layoutParamsFlags = from.readInt32();
ret.layoutParamsType = from.readInt32();
@@ -119,7 +122,10 @@
ret.frameTop = from.readInt32();
ret.frameRight = from.readInt32();
ret.frameBottom = from.readInt32();
- ret.scaleFactor = from.readFloat();
+ ret.surfaceInset = from.readInt32();
+ ret.globalScaleFactor = from.readFloat();
+ ret.windowXScale = from.readFloat();
+ ret.windowYScale = from.readFloat();
ret.visible = from.readBool();
ret.canReceiveKeys = from.readBool();
ret.hasFocus = from.readBool();
@@ -130,6 +136,7 @@
ret.ownerUid = from.readInt32();
ret.inputFeatures = from.readInt32();
ret.displayId = from.readInt32();
+ ret.applicationInfo = InputApplicationInfo::read(from);
from.read(ret.touchableRegion);
return ret;
@@ -141,19 +148,18 @@
// --- InputWindowHandle ---
-InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
- inputApplicationHandle(inputApplicationHandle) {
+InputWindowHandle::InputWindowHandle() {
}
InputWindowHandle::~InputWindowHandle() {
}
void InputWindowHandle::releaseChannel() {
- mInfo.inputChannel.clear();
+ mInfo.token.clear();
}
-sp<InputChannel> InputWindowHandle::getInputChannel() const {
- return mInfo.inputChannel;
+sp<IBinder> InputWindowHandle::getToken() const {
+ return mInfo.token;
}
} // namespace android
diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp
index 39ad26e..5e5893f 100644
--- a/libs/input/tests/InputWindow_test.cpp
+++ b/libs/input/tests/InputWindow_test.cpp
@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
+#include <binder/Binder.h>
#include <binder/Parcel.h>
#include <input/InputWindow.h>
@@ -24,24 +25,20 @@
namespace android {
namespace test {
-TEST(InputWindowInfo, ParcellingWithoutChannel) {
+TEST(InputWindowInfo, ParcellingWithoutToken) {
InputWindowInfo i;
- i.inputChannel = nullptr;
+ i.token = nullptr;
Parcel p;
ASSERT_EQ(OK, i.write(p));
p.setDataPosition(0);
InputWindowInfo i2 = InputWindowInfo::read(p);
- ASSERT_TRUE(i2.inputChannel == nullptr);
+ ASSERT_TRUE(i2.token == nullptr);
}
TEST(InputWindowInfo, Parcelling) {
- sp<InputChannel> channel, junkChannel;
- status_t result = InputChannel::openInputChannelPair("name", channel, junkChannel);
- ASSERT_EQ(OK, result) << "openInputChannelPair should have returned valid channels";
-
InputWindowInfo i;
- i.inputChannel = channel;
+ i.token = new BBinder();
i.name = "Foobar";
i.layoutParamsFlags = 7;
i.layoutParamsType = 39;
@@ -50,7 +47,10 @@
i.frameTop = 34;
i.frameRight = 16;
i.frameBottom = 19;
- i.scaleFactor = 0.3;
+ i.surfaceInset = 17;
+ i.globalScaleFactor = 0.3;
+ i.windowXScale = 0.4;
+ i.windowYScale = 0.5;
i.visible = false;
i.canReceiveKeys = false;
i.hasFocus = false;
@@ -67,7 +67,7 @@
p.setDataPosition(0);
InputWindowInfo i2 = InputWindowInfo::read(p);
- ASSERT_EQ(i.inputChannel->getName(), i2.inputChannel->getName());
+ ASSERT_EQ(i.token, i2.token);
ASSERT_EQ(i.name, i2.name);
ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags);
ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType);
@@ -76,7 +76,10 @@
ASSERT_EQ(i.frameTop, i2.frameTop);
ASSERT_EQ(i.frameRight, i2.frameRight);
ASSERT_EQ(i.frameBottom, i2.frameBottom);
- ASSERT_EQ(i.scaleFactor, i2.scaleFactor);
+ ASSERT_EQ(i.surfaceInset, i2.surfaceInset);
+ ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor);
+ ASSERT_EQ(i.windowXScale, i2.windowXScale);
+ ASSERT_EQ(i.windowYScale, i2.windowYScale);
ASSERT_EQ(i.visible, i2.visible);
ASSERT_EQ(i.canReceiveKeys, i2.canReceiveKeys);
ASSERT_EQ(i.hasFocus, i2.hasFocus);
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 7e26b0b..a19fe17 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -41,33 +41,11 @@
// ----------------------------------------------------------------------------
int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc, AHardwareBuffer** outBuffer) {
- if (!outBuffer || !desc)
- return BAD_VALUE;
-
- if (!AHardwareBuffer_isValidPixelFormat(desc->format)) {
- ALOGE("Invalid AHardwareBuffer pixel format %u (%#x))", desc->format, desc->format);
- return BAD_VALUE;
- }
+ if (!outBuffer || !desc) return BAD_VALUE;
+ if (!AHardwareBuffer_isValidDescription(desc, /*log=*/true)) return BAD_VALUE;
int format = AHardwareBuffer_convertToPixelFormat(desc->format);
- if (desc->rfu0 != 0 || desc->rfu1 != 0) {
- ALOGE("AHardwareBuffer_Desc::rfu fields must be 0");
- return BAD_VALUE;
- }
-
- if (desc->format == AHARDWAREBUFFER_FORMAT_BLOB && desc->height != 1) {
- ALOGE("Height must be 1 when using the AHARDWAREBUFFER_FORMAT_BLOB format");
- return BAD_VALUE;
- }
-
- if ((desc->usage & (AHARDWAREBUFFER_USAGE_CPU_READ_MASK | AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) &&
- (desc->usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT)) {
- ALOGE("AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT requires AHARDWAREBUFFER_USAGE_CPU_READ_NEVER "
- "and AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER");
- return BAD_VALUE;
- }
-
- uint64_t usage = AHardwareBuffer_convertToGrallocUsageBits(desc->usage);
+ uint64_t usage = AHardwareBuffer_convertToGrallocUsageBits(desc->usage);
sp<GraphicBuffer> gbuffer(new GraphicBuffer(
desc->width, desc->height, format, desc->layers, usage,
std::string("AHardwareBuffer pid [") + std::to_string(getpid()) + "]"));
@@ -122,19 +100,26 @@
if (usage & ~(AHARDWAREBUFFER_USAGE_CPU_READ_MASK |
AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) {
ALOGE("Invalid usage flags passed to AHardwareBuffer_lock; only "
- " AHARDWAREBUFFER_USAGE_CPU_* flags are allowed");
+ "AHARDWAREBUFFER_USAGE_CPU_* flags are allowed");
return BAD_VALUE;
}
usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
- GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+ GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+
+ if (gbuffer->getLayerCount() > 1) {
+ ALOGE("Buffer with multiple layers passed to AHardwareBuffer_lock; "
+ "only buffers with one layer are allowed");
+ return INVALID_OPERATION;
+ }
+
Rect bounds;
if (!rect) {
- bounds.set(Rect(gBuffer->getWidth(), gBuffer->getHeight()));
+ bounds.set(Rect(gbuffer->getWidth(), gbuffer->getHeight()));
} else {
bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
}
- return gBuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence);
+ return gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence);
}
int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) {
@@ -274,6 +259,25 @@
return NO_ERROR;
}
+int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) {
+ if (!desc) return 0;
+ if (!AHardwareBuffer_isValidDescription(desc, /*log=*/false)) return 0;
+
+ // Make a trial allocation.
+ // TODO(b/115660272): add implementation that uses a HAL query.
+ AHardwareBuffer_Desc trialDesc = *desc;
+ trialDesc.width = 4;
+ trialDesc.height = desc->format == AHARDWAREBUFFER_FORMAT_BLOB ? 1 : 4;
+ trialDesc.layers = desc->layers == 1 ? 1 : 2;
+ AHardwareBuffer* trialBuffer = nullptr;
+ int result = AHardwareBuffer_allocate(&trialDesc, &trialBuffer);
+ if (result == NO_ERROR) {
+ AHardwareBuffer_release(trialBuffer);
+ return 1;
+ }
+ return 0;
+}
+
// ----------------------------------------------------------------------------
// VNDK functions
@@ -322,14 +326,71 @@
namespace android {
-// A 1:1 mapping of AHardwaqreBuffer bitmasks to gralloc1 bitmasks.
-struct UsageMaskMapping {
- uint64_t hardwareBufferMask;
- uint64_t grallocMask;
-};
+bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool log) {
+ if (desc->width == 0 || desc->height == 0 || desc->layers == 0) {
+ ALOGE_IF(log, "Width, height and layers must all be nonzero");
+ return false;
+ }
-static inline bool containsBits(uint64_t mask, uint64_t bitsToCheck) {
- return (mask & bitsToCheck) == bitsToCheck && bitsToCheck;
+ if (!AHardwareBuffer_isValidPixelFormat(desc->format)) {
+ ALOGE_IF(log, "Invalid AHardwareBuffer pixel format %u (%#x))",
+ desc->format, desc->format);
+ return false;
+ }
+
+ if (desc->rfu0 != 0 || desc->rfu1 != 0) {
+ ALOGE_IF(log, "AHardwareBuffer_Desc::rfu fields must be 0");
+ return false;
+ }
+
+ if (desc->format == AHARDWAREBUFFER_FORMAT_BLOB) {
+ if (desc->height != 1 || desc->layers != 1) {
+ ALOGE_IF(log, "Height and layers must be 1 for AHARDWAREBUFFER_FORMAT_BLOB");
+ return false;
+ }
+ const uint64_t blobInvalidGpuMask =
+ AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+ AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER |
+ AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE |
+ AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP;
+ if (desc->usage & blobInvalidGpuMask) {
+ ALOGE_IF(log, "Invalid GPU usage flag for AHARDWAREBUFFER_FORMAT_BLOB; "
+ "only AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER is allowed");
+ return false;
+ }
+ if (desc->usage & AHARDWAREBUFFER_USAGE_VIDEO_ENCODE) {
+ ALOGE_IF(log, "AHARDWAREBUFFER_FORMAT_BLOB cannot be encoded as video");
+ return false;
+ }
+ } else {
+ if (desc->usage & AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA) {
+ ALOGE_IF(log, "AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA requires AHARDWAREBUFFER_FORMAT_BLOB");
+ return false;
+ }
+ if (desc->usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) {
+ ALOGE_IF(log, "AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER requires AHARDWAREBUFFER_FORMAT_BLOB");
+ return false;
+ }
+ }
+
+ if ((desc->usage & (AHARDWAREBUFFER_USAGE_CPU_READ_MASK | AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) &&
+ (desc->usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT)) {
+ ALOGE_IF(log, "AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT requires AHARDWAREBUFFER_USAGE_CPU_READ_NEVER "
+ "and AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER");
+ return false;
+ }
+
+ if (desc->usage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP) {
+ if (desc->width != desc->height) {
+ ALOGE_IF(log, "Cube maps must be square");
+ return false;
+ }
+ if (desc->layers % 6 != 0) {
+ ALOGE_IF(log, "Cube map layers must be a multiple of 6");
+ return false;
+ }
+ }
+ return true;
}
bool AHardwareBuffer_isValidPixelFormat(uint32_t format) {
@@ -445,7 +506,7 @@
"gralloc and AHardwareBuffer flags don't match");
static_assert(AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE == (uint64_t)BufferUsage::GPU_TEXTURE,
"gralloc and AHardwareBuffer flags don't match");
- static_assert(AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT == (uint64_t)BufferUsage::GPU_RENDER_TARGET,
+ static_assert(AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER == (uint64_t)BufferUsage::GPU_RENDER_TARGET,
"gralloc and AHardwareBuffer flags don't match");
static_assert(AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT == (uint64_t)BufferUsage::PROTECTED,
"gralloc and AHardwareBuffer flags don't match");
diff --git a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
index 71f5634..bf688f8 100644
--- a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
+++ b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
@@ -28,10 +28,15 @@
#include <stdint.h>
struct AHardwareBuffer;
+struct AHardwareBuffer_Desc;
struct ANativeWindowBuffer;
namespace android {
+// Validates whether the passed description does not have conflicting
+// parameters. Note: this does not verify any platform-specific contraints.
+bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool log);
+
// whether this AHardwareBuffer format is valid
bool AHardwareBuffer_isValidPixelFormat(uint32_t ahardwarebuffer_format);
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 23ac60b..03545a6 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -102,8 +102,10 @@
AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM = 0x2b,
/**
- * An opaque binary blob format that must have height 1, with width equal to
- * the buffer size in bytes.
+ * Opaque binary blob format.
+ * Must have height 1 and one layer, with width equal to the buffer
+ * size in bytes. Corresponds to Vulkan buffers and OpenGL buffer
+ * objects. Can be bound to the latter using GL_EXT_external_buffer.
*/
AHARDWAREBUFFER_FORMAT_BLOB = 0x21,
@@ -195,20 +197,25 @@
/// The buffer will be written to by the GPU as a framebuffer attachment.
AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER = 1UL << 9,
/**
- * The buffer will be written to by the GPU as a framebuffer attachment.
- * Note that the name of this flag is somewhat misleading: it does not imply
- * that the buffer contains a color format. A buffer with depth or stencil
- * format that will be used as a framebuffer attachment should also have
- * this flag.
+ * The buffer will be written to by the GPU as a framebuffer
+ * attachment.
+ *
+ * Note that the name of this flag is somewhat misleading: it does
+ * not imply that the buffer contains a color format. A buffer with
+ * depth or stencil format that will be used as a framebuffer
+ * attachment should also have this flag. Use the equivalent flag
+ * AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER to avoid this confusion.
*/
AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,
/**
- * The buffer is protected from direct CPU access or being read by non-secure
- * hardware, such as video encoders. This flag is incompatible with CPU
- * read and write flags. It is mainly used when handling DRM video.
- * Refer to the EGL extension EGL_EXT_protected_content and GL extension
- * EXT_protected_textures for more information on how these buffers are expected
- * to behave.
+ * The buffer is protected from direct CPU access or being read by
+ * non-secure hardware, such as video encoders.
+ *
+ * This flag is incompatible with CPU read and write flags. It is
+ * mainly used when handling DRM video. Refer to the EGL extension
+ * EGL_EXT_protected_content and GL extension
+ * GL_EXT_protected_textures for more information on how these
+ * buffers are expected to behave.
*/
AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14,
/// The buffer will be read by a hardware video encoder.
@@ -225,11 +232,17 @@
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24,
/**
* The buffer will be used as a cube map texture.
- * When this flag is present, the buffer must have a layer count that is
- * a multiple of 6.
+ * When this flag is present, the buffer must have a layer count
+ * that is a multiple of 6. Note that buffers with this flag must be
+ * bound to OpenGL textures using the extension
+ * GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image.
*/
AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 1UL << 25,
- /// The buffer contains a complete mipmap hierarchy.
+ /**
+ * The buffer contains a complete mipmap hierarchy.
+ * Note that buffers with this flag must be bound to OpenGL textures using
+ * the extension GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image.
+ */
AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26,
AHARDWAREBUFFER_USAGE_VENDOR_0 = 1ULL << 28,
@@ -255,13 +268,21 @@
};
/**
- * Buffer description. Used for allocating new buffers and querying parameters
- * of existing ones.
+ * Buffer description. Used for allocating new buffers and querying
+ * parameters of existing ones.
*/
typedef struct AHardwareBuffer_Desc {
uint32_t width; ///< Width in pixels.
uint32_t height; ///< Height in pixels.
- uint32_t layers; ///< Number of images in an image array.
+ /**
+ * Number of images in an image array. AHardwareBuffers with one
+ * layer correspond to regular 2D textures. AHardwareBuffers with
+ * more than layer correspond to texture arrays. If the layer count
+ * is a multiple of 6 and the usage flag
+ * AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP is present, the buffer is
+ * a cube map or a cube map array.
+ */
+ uint32_t layers;
uint32_t format; ///< One of AHardwareBuffer_Format.
uint64_t usage; ///< Combination of AHardwareBuffer_UsageFlags.
uint32_t stride; ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
@@ -290,8 +311,10 @@
int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
AHardwareBuffer** outBuffer) __INTRODUCED_IN(26);
/**
- * Acquire a reference on the given AHardwareBuffer object. This prevents the
- * object from being deleted until the last reference is removed.
+ * Acquire a reference on the given AHardwareBuffer object.
+ *
+ * This prevents the object from being deleted until the last reference
+ * is removed.
*/
void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
@@ -309,50 +332,73 @@
AHardwareBuffer_Desc* outDesc) __INTRODUCED_IN(26);
/**
- * Lock the AHardwareBuffer for reading or writing, depending on the usage flags
- * passed. This call may block if the hardware needs to finish rendering or if
- * CPU caches need to be synchronized, or possibly for other implementation-
- * specific reasons. If fence is not negative, then it specifies a fence file
- * descriptor that will be signaled when the buffer is locked, otherwise the
- * caller will block until the buffer is available.
+ * Lock the AHardwareBuffer for direct CPU access.
*
- * If \a rect is not NULL, the caller promises to modify only data in the area
- * specified by rect. If rect is NULL, the caller may modify the contents of the
- * entire buffer.
+ * This function can lock the buffer for either reading or writing.
+ * It may block if the hardware needs to finish rendering, if CPU caches
+ * need to be synchronized, or possibly for other implementation-
+ * specific reasons.
*
- * The content of the buffer outside of the specified rect is NOT modified
- * by this call.
+ * The passed AHardwareBuffer must have one layer, otherwise the call
+ * will fail.
*
- * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set,
- * then outVirtualAddress is filled with the address of the buffer in virtual
+ * If \a fence is not negative, it specifies a fence file descriptor on
+ * which to wait before locking the buffer. If it's negative, the caller
+ * is responsible for ensuring that writes to the buffer have completed
+ * before calling this function. Using this parameter is more efficient
+ * than waiting on the fence and then calling this function.
+ *
+ * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*.
+ * If set, then outVirtualAddress is filled with the address of the
+ * buffer in virtual memory. The flags must also be compatible with
+ * usage flags specified at buffer creation: if a read flag is passed,
+ * the buffer must have been created with
+ * AHARDWAREBUFFER_USAGE_CPU_READ_RARELY or
+ * AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN. If a write flag is passed, it
+ * must have been created with AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY or
+ * AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN.
+ *
+ * If \a rect is not NULL, the caller promises to modify only data in
+ * the area specified by rect. If rect is NULL, the caller may modify
+ * the contents of the entire buffer. The content of the buffer outside
+ * of the specified rect is NOT modified by this call.
+ *
+ * It is legal for several different threads to lock a buffer for read
+ * access; none of the threads are blocked.
+ *
+ * Locking a buffer simultaneously for write or read/write is undefined,
+ * but will neither terminate the process nor block the caller.
+ * AHardwareBuffer_lock may return an error or leave the buffer's
+ * content in an indeterminate state.
+ *
+ * If the buffer has AHARDWAREBUFFER_FORMAT_BLOB, it is legal lock it
+ * for reading and writing in multiple threads and/or processes
+ * simultaneously, and the contents of the buffer behave like shared
* memory.
*
- * THREADING CONSIDERATIONS:
- *
- * It is legal for several different threads to lock a buffer for read access;
- * none of the threads are blocked.
- *
- * Locking a buffer simultaneously for write or read/write is undefined, but
- * will neither terminate the process nor block the caller; AHardwareBuffer_lock
- * may return an error or leave the buffer's content into an indeterminate
- * state.
- *
- * \return 0 on success, -EINVAL if \a buffer is NULL or if the usage
- * flags are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or an error
- * number of the lock fails for any reason.
+ * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags
+ * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer
+ * has more than one layer. Error number if the lock fails for any other
+ * reason.
*/
int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
int32_t fence, const ARect* rect, void** outVirtualAddress) __INTRODUCED_IN(26);
/**
- * Unlock the AHardwareBuffer; must be called after all changes to the buffer
- * are completed by the caller. If fence is not NULL then it will be set to a
- * file descriptor that is signaled when all pending work on the buffer is
- * completed. The caller is responsible for closing the fence when it is no
- * longer needed.
+ * Unlock the AHardwareBuffer from direct CPU access.
*
- * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
- * number if the unlock fails for any reason.
+ * Must be called after all changes to the buffer are completed by the
+ * caller. If \a fence is NULL, the function will block until all work
+ * is completed. Otherwise, \a fence will be set either to a valid file
+ * descriptor or to -1. The file descriptor will become signaled once
+ * the unlocking is complete and buffer contents are updated.
+ * The caller is responsible for closing the file descriptor once it's
+ * no longer needed. The value -1 indicates that unlocking has already
+ * completed before the function returned and no further operations are
+ * necessary.
+ *
+ * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if
+ * the unlock fails for any reason.
*/
int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED_IN(26);
@@ -365,7 +411,7 @@
int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd) __INTRODUCED_IN(26);
/**
- * Receive the AHardwareBuffer from an AF_UNIX socket.
+ * Receive an AHardwareBuffer from an AF_UNIX socket.
*
* \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error
* number if the operation fails for any reason.
@@ -374,6 +420,29 @@
#endif // __ANDROID_API__ >= 26
+#if __ANDROID_API__ >= 29
+
+/**
+ * Test whether the given format and usage flag combination is
+ * allocatable.
+ *
+ * If this function returns true, it means that a buffer with the given
+ * description can be allocated on this implementation, unless resource
+ * exhaustion occurs. If this function returns false, it means that the
+ * allocation of the given description will never succeed.
+ *
+ * The return value of this function may depend on all fields in the
+ * description, except stride, which is always ignored. For example,
+ * some implementations have implementation-defined limits on texture
+ * size and layer count.
+ *
+ * \return 1 if the format and usage flag combination is allocatable,
+ * 0 otherwise.
+ */
+int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
__END_DECLS
#endif // ANDROID_HARDWARE_BUFFER_H
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 197f73f..61590e0 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -202,7 +202,7 @@
* ANativeWindow.
*/
enum {
-// clang-format off
+ // clang-format off
NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */
NATIVE_WINDOW_CONNECT = 1, /* deprecated */
NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
@@ -237,7 +237,8 @@
NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31,
NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33,
-// clang-format on
+ NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34,
+ // clang-format on
};
/* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -748,6 +749,27 @@
}
/*
+ * native_window_set_buffers_hdr10_plus_metadata(..., metadata)
+ * All buffers queued after this call will be associated with the
+ * HDR10+ dynamic metadata specified.
+ *
+ * metadata specifies additional dynamic information about the
+ * contents of the buffer that may affect how it is displayed. When
+ * it is nullptr, it means no such information is available. No
+ * HDR10+ dynamic emtadata is associated with the buffers by default.
+ *
+ * Parameter "size" refers to the length of the metadata blob pointed to
+ * by parameter "data". The metadata blob will adhere to the HDR10+ SEI
+ * message standard.
+ */
+static inline int native_window_set_buffers_hdr10_plus_metadata(struct ANativeWindow* window,
+ const size_t size,
+ const uint8_t* metadata) {
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA, size,
+ metadata);
+}
+
+/*
* native_window_set_buffers_transform(..., int transform)
* All buffers queued after this call will be displayed transformed according
* to the transform parameter specified.
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 753954d..a796e97 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -5,6 +5,7 @@
AHardwareBuffer_createFromHandle; # vndk
AHardwareBuffer_describe;
AHardwareBuffer_getNativeHandle; # vndk
+ AHardwareBuffer_isSupported; # introduced=29
AHardwareBuffer_lock;
AHardwareBuffer_recvHandleFromUnixSocket;
AHardwareBuffer_release;
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 7efc8bd..beaf9ee 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -50,7 +50,6 @@
"gl/GLExtensions.cpp",
"gl/GLFramebuffer.cpp",
"gl/GLImage.cpp",
- "gl/GLSurface.cpp",
"gl/Program.cpp",
"gl/ProgramCache.cpp",
],
diff --git a/libs/renderengine/gl/GLES20RenderEngine.cpp b/libs/renderengine/gl/GLES20RenderEngine.cpp
index e244a83..b10b52b 100644
--- a/libs/renderengine/gl/GLES20RenderEngine.cpp
+++ b/libs/renderengine/gl/GLES20RenderEngine.cpp
@@ -41,7 +41,6 @@
#include "GLExtensions.h"
#include "GLFramebuffer.h"
#include "GLImage.h"
-#include "GLSurface.h"
#include "Program.h"
#include "ProgramCache.h"
@@ -241,60 +240,29 @@
config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
}
- EGLint renderableType = 0;
- if (config == EGL_NO_CONFIG) {
- renderableType = EGL_OPENGL_ES2_BIT;
- } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
- LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
- }
- EGLint contextClientVersion = 0;
- if (renderableType & EGL_OPENGL_ES2_BIT) {
- contextClientVersion = 2;
- } else if (renderableType & EGL_OPENGL_ES_BIT) {
- contextClientVersion = 1;
- } else {
- LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
- }
-
- std::vector<EGLint> contextAttributes;
- contextAttributes.reserve(6);
- contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
- contextAttributes.push_back(contextClientVersion);
bool useContextPriority = extensions.hasContextPriority() &&
(featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
- if (useContextPriority) {
- contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
- contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
- }
- contextAttributes.push_back(EGL_NONE);
-
- EGLContext ctxt = eglCreateContext(display, config, nullptr, contextAttributes.data());
+ EGLContext ctxt = createEglContext(display, config, EGL_NO_CONTEXT, useContextPriority);
// if can't create a GL context, we can only abort.
LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
- // now figure out what version of GL did we actually get
- // NOTE: a dummy surface is not needed if KHR_create_context is supported
- // TODO(alecmouri): don't create this surface if EGL_KHR_surfaceless_context
- // is supported.
-
- EGLConfig dummyConfig = config;
- if (dummyConfig == EGL_NO_CONFIG) {
- dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+ EGLSurface dummy = EGL_NO_SURFACE;
+ if (!extensions.hasSurfacelessContext()) {
+ dummy = createDummyEglPbufferSurface(display, config, hwcFormat);
+ LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
}
- EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
- EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);
- LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
+
EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
+ // now figure out what version of GL did we actually get
GlesVersion version = parseGlesVersion(extensions.getVersion());
// initialize the renderer while GL is current
-
std::unique_ptr<GLES20RenderEngine> engine;
switch (version) {
case GLES_VERSION_1_0:
@@ -423,10 +391,6 @@
return std::make_unique<GLFramebuffer>(*this);
}
-std::unique_ptr<Surface> GLES20RenderEngine::createSurface() {
- return std::make_unique<GLSurface>(*this);
-}
-
std::unique_ptr<Image> GLES20RenderEngine::createImage() {
return std::make_unique<GLImage>(*this);
}
@@ -439,31 +403,6 @@
return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
}
-bool GLES20RenderEngine::setCurrentSurface(const Surface& surface) {
- // Surface is an abstract interface. GLES20RenderEngine only ever
- // creates GLSurface's, so it is safe to just cast to the actual
- // type.
- bool success = true;
- const GLSurface& glSurface = static_cast<const GLSurface&>(surface);
- EGLSurface eglSurface = glSurface.getEGLSurface();
- if (eglSurface != eglGetCurrentSurface(EGL_DRAW)) {
- success = eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext) == EGL_TRUE;
- if (success && glSurface.getAsync()) {
- eglSwapInterval(mEGLDisplay, 0);
- }
- if (success) {
- mSurfaceHeight = glSurface.getHeight();
- }
- }
-
- return success;
-}
-
-void GLES20RenderEngine::resetCurrentSurface() {
- eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- mSurfaceHeight = 0;
-}
-
base::unique_fd GLES20RenderEngine::flush() {
if (!GLExtensions::getInstance().hasNativeFenceSync()) {
return base::unique_fd();
@@ -577,7 +516,7 @@
void GLES20RenderEngine::setScissor(const Rect& region) {
// Invert y-coordinate to map to GL-space.
- int32_t canvasHeight = mRenderToFbo ? mFboHeight : mSurfaceHeight;
+ int32_t canvasHeight = mFboHeight;
int32_t glBottom = canvasHeight - region.bottom;
glScissor(region.left, glBottom, region.getWidth(), region.getHeight());
@@ -620,7 +559,6 @@
glBindFramebuffer(GL_FRAMEBUFFER, framebufferName);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0);
- mRenderToFbo = true;
mFboHeight = glFramebuffer->getBufferHeight();
uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -632,7 +570,6 @@
}
void GLES20RenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
- mRenderToFbo = false;
mFboHeight = 0;
// back to main framebuffer
@@ -661,9 +598,7 @@
int32_t r = sourceCrop.right;
int32_t b = sourceCrop.bottom;
int32_t t = sourceCrop.top;
- if (mRenderToFbo) {
- std::swap(t, b);
- }
+ std::swap(t, b);
mat4 m = mat4::ortho(l, r, b, t, 0, 1);
// Apply custom rotation to the projection.
@@ -942,6 +877,53 @@
return GLES_VERSION_1_0;
}
+EGLContext GLES20RenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
+ EGLContext shareContext, bool useContextPriority) {
+ EGLint renderableType = 0;
+ if (config == EGL_NO_CONFIG) {
+ renderableType = EGL_OPENGL_ES2_BIT;
+ } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
+ LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
+ }
+ EGLint contextClientVersion = 0;
+ if (renderableType & EGL_OPENGL_ES2_BIT) {
+ contextClientVersion = 2;
+ } else if (renderableType & EGL_OPENGL_ES_BIT) {
+ contextClientVersion = 1;
+ } else {
+ LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
+ }
+
+ std::vector<EGLint> contextAttributes;
+ contextAttributes.reserve(5);
+ contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
+ contextAttributes.push_back(contextClientVersion);
+ if (useContextPriority) {
+ contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
+ contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
+ }
+ contextAttributes.push_back(EGL_NONE);
+
+ return eglCreateContext(display, config, shareContext, contextAttributes.data());
+}
+
+EGLSurface GLES20RenderEngine::createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
+ int hwcFormat) {
+ EGLConfig dummyConfig = config;
+ if (dummyConfig == EGL_NO_CONFIG) {
+ dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+ }
+ std::vector<EGLint> attributes;
+ attributes.reserve(5);
+ attributes.push_back(EGL_WIDTH);
+ attributes.push_back(1);
+ attributes.push_back(EGL_HEIGHT);
+ attributes.push_back(1);
+ attributes.push_back(EGL_NONE);
+
+ return eglCreatePbufferSurface(display, dummyConfig, attributes.data());
+}
+
bool GLES20RenderEngine::isHdrDataSpace(const Dataspace dataSpace) const {
const Dataspace standard = static_cast<Dataspace>(dataSpace & Dataspace::STANDARD_MASK);
const Dataspace transfer = static_cast<Dataspace>(dataSpace & Dataspace::TRANSFER_MASK);
diff --git a/libs/renderengine/gl/GLES20RenderEngine.h b/libs/renderengine/gl/GLES20RenderEngine.h
index aebb319..77dba62 100644
--- a/libs/renderengine/gl/GLES20RenderEngine.h
+++ b/libs/renderengine/gl/GLES20RenderEngine.h
@@ -40,7 +40,6 @@
namespace gl {
class GLImage;
-class GLSurface;
class GLES20RenderEngine : public impl::RenderEngine {
public:
@@ -52,13 +51,10 @@
~GLES20RenderEngine() override;
std::unique_ptr<Framebuffer> createFramebuffer() override;
- std::unique_ptr<Surface> createSurface() override;
std::unique_ptr<Image> createImage() override;
void primeCache() const override;
bool isCurrent() const override;
- bool setCurrentSurface(const Surface& surface) override;
- void resetCurrentSurface() override;
base::unique_fd flush() override;
bool finish() override;
bool waitFence(base::unique_fd fenceFd) override;
@@ -116,6 +112,10 @@
};
static GlesVersion parseGlesVersion(const char* str);
+ static EGLContext createEglContext(EGLDisplay display, EGLConfig config,
+ EGLContext shareContext, bool useContextPriority);
+ static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
+ int hwcFormat);
// A data space is considered HDR data space if it has BT2020 color space
// with PQ or HLG transfer function.
@@ -147,8 +147,6 @@
mat4 mBt2020ToSrgb;
mat4 mBt2020ToDisplayP3;
- bool mRenderToFbo = false;
- int32_t mSurfaceHeight = 0;
int32_t mFboHeight = 0;
// Current dataspace of layer being rendered
diff --git a/libs/renderengine/gl/GLExtensions.cpp b/libs/renderengine/gl/GLExtensions.cpp
index 784693b..ce83dd5 100644
--- a/libs/renderengine/gl/GLExtensions.cpp
+++ b/libs/renderengine/gl/GLExtensions.cpp
@@ -112,6 +112,9 @@
if (extensionSet.hasExtension("EGL_IMG_context_priority")) {
mHasContextPriority = true;
}
+ if (extensionSet.hasExtension("EGL_KHR_surfaceless_context")) {
+ mHasSurfacelessContext = true;
+ }
}
char const* GLExtensions::getEGLVersion() const {
diff --git a/libs/renderengine/gl/GLExtensions.h b/libs/renderengine/gl/GLExtensions.h
index 382c23a..2a654d5 100644
--- a/libs/renderengine/gl/GLExtensions.h
+++ b/libs/renderengine/gl/GLExtensions.h
@@ -32,29 +32,6 @@
namespace gl {
class GLExtensions : public Singleton<GLExtensions> {
- friend class Singleton<GLExtensions>;
-
- bool mHasNoConfigContext = false;
- bool mHasNativeFenceSync = false;
- bool mHasFenceSync = false;
- bool mHasWaitSync = false;
- bool mHasProtectedContent = false;
- bool mHasContextPriority = false;
-
- String8 mVendor;
- String8 mRenderer;
- String8 mVersion;
- String8 mExtensions;
-
- String8 mEGLVersion;
- String8 mEGLExtensions;
-
- GLExtensions(const GLExtensions&);
- GLExtensions& operator=(const GLExtensions&);
-
-protected:
- GLExtensions() = default;
-
public:
bool hasNoConfigContext() const { return mHasNoConfigContext; }
bool hasNativeFenceSync() const { return mHasNativeFenceSync; }
@@ -62,6 +39,7 @@
bool hasWaitSync() const { return mHasWaitSync; }
bool hasProtectedContent() const { return mHasProtectedContent; }
bool hasContextPriority() const { return mHasContextPriority; }
+ bool hasSurfacelessContext() const { return mHasSurfacelessContext; }
void initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version,
GLubyte const* extensions);
@@ -73,6 +51,31 @@
void initWithEGLStrings(char const* eglVersion, char const* eglExtensions);
char const* getEGLVersion() const;
char const* getEGLExtensions() const;
+
+protected:
+ GLExtensions() = default;
+
+private:
+ friend class Singleton<GLExtensions>;
+
+ bool mHasNoConfigContext = false;
+ bool mHasNativeFenceSync = false;
+ bool mHasFenceSync = false;
+ bool mHasWaitSync = false;
+ bool mHasProtectedContent = false;
+ bool mHasContextPriority = false;
+ bool mHasSurfacelessContext = false;
+
+ String8 mVendor;
+ String8 mRenderer;
+ String8 mVersion;
+ String8 mExtensions;
+
+ String8 mEGLVersion;
+ String8 mEGLExtensions;
+
+ GLExtensions(const GLExtensions&);
+ GLExtensions& operator=(const GLExtensions&);
};
} // namespace gl
diff --git a/libs/renderengine/gl/GLSurface.cpp b/libs/renderengine/gl/GLSurface.cpp
deleted file mode 100644
index 2d694e9..0000000
--- a/libs/renderengine/gl/GLSurface.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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 "GLSurface.h"
-
-#include <android/native_window.h>
-#include <log/log.h>
-#include <ui/PixelFormat.h>
-#include "GLES20RenderEngine.h"
-
-namespace android {
-namespace renderengine {
-namespace gl {
-
-GLSurface::GLSurface(const GLES20RenderEngine& engine)
- : mEGLDisplay(engine.getEGLDisplay()), mEGLConfig(engine.getEGLConfig()) {
- // RE does not assume any config when EGL_KHR_no_config_context is supported
- if (mEGLConfig == EGL_NO_CONFIG_KHR) {
- mEGLConfig =
- GLES20RenderEngine::chooseEglConfig(mEGLDisplay, PIXEL_FORMAT_RGBA_8888, false);
- }
-}
-
-GLSurface::~GLSurface() {
- setNativeWindow(nullptr);
-}
-
-void GLSurface::setNativeWindow(ANativeWindow* window) {
- if (mEGLSurface != EGL_NO_SURFACE) {
- eglDestroySurface(mEGLDisplay, mEGLSurface);
- mEGLSurface = EGL_NO_SURFACE;
- mSurfaceWidth = 0;
- mSurfaceHeight = 0;
- }
-
- mWindow = window;
- if (mWindow) {
- mEGLSurface = eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mWindow, nullptr);
- mSurfaceWidth = ANativeWindow_getWidth(window);
- mSurfaceHeight = ANativeWindow_getHeight(window);
- }
-}
-
-void GLSurface::swapBuffers() const {
- if (!eglSwapBuffers(mEGLDisplay, mEGLSurface)) {
- EGLint error = eglGetError();
-
- const char format[] = "eglSwapBuffers(%p, %p) failed with 0x%08x";
- if (mCritical || error == EGL_CONTEXT_LOST) {
- LOG_ALWAYS_FATAL(format, mEGLDisplay, mEGLSurface, error);
- } else {
- ALOGE(format, mEGLDisplay, mEGLSurface, error);
- }
- }
-}
-
-EGLint GLSurface::queryConfig(EGLint attrib) const {
- EGLint value;
- if (!eglGetConfigAttrib(mEGLDisplay, mEGLConfig, attrib, &value)) {
- value = 0;
- }
-
- return value;
-}
-
-int32_t GLSurface::queryRedSize() const {
- return queryConfig(EGL_RED_SIZE);
-}
-
-int32_t GLSurface::queryGreenSize() const {
- return queryConfig(EGL_GREEN_SIZE);
-}
-
-int32_t GLSurface::queryBlueSize() const {
- return queryConfig(EGL_BLUE_SIZE);
-}
-
-int32_t GLSurface::queryAlphaSize() const {
- return queryConfig(EGL_ALPHA_SIZE);
-}
-
-int32_t GLSurface::getWidth() const {
- return mSurfaceWidth;
-}
-
-int32_t GLSurface::getHeight() const {
- return mSurfaceHeight;
-}
-
-} // namespace gl
-} // namespace renderengine
-} // namespace android
diff --git a/libs/renderengine/gl/GLSurface.h b/libs/renderengine/gl/GLSurface.h
deleted file mode 100644
index 092d371..0000000
--- a/libs/renderengine/gl/GLSurface.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include <EGL/egl.h>
-#include <android-base/macros.h>
-#include <renderengine/Surface.h>
-
-struct ANativeWindow;
-
-namespace android {
-namespace renderengine {
-namespace gl {
-
-class GLES20RenderEngine;
-
-class GLSurface final : public renderengine::Surface {
-public:
- GLSurface(const GLES20RenderEngine& engine);
- ~GLSurface() override;
-
- // renderengine::Surface implementation
- void setCritical(bool enable) override { mCritical = enable; }
- void setAsync(bool enable) override { mAsync = enable; }
-
- void setNativeWindow(ANativeWindow* window) override;
- void swapBuffers() const override;
-
- int32_t queryRedSize() const override;
- int32_t queryGreenSize() const override;
- int32_t queryBlueSize() const override;
- int32_t queryAlphaSize() const override;
-
- bool getAsync() const { return mAsync; }
- EGLSurface getEGLSurface() const { return mEGLSurface; }
-
- int32_t getWidth() const override;
- int32_t getHeight() const override;
-
-private:
- EGLint queryConfig(EGLint attrib) const;
-
- EGLDisplay mEGLDisplay;
- EGLConfig mEGLConfig;
-
- bool mCritical = false;
- bool mAsync = false;
-
- int32_t mSurfaceWidth = 0;
- int32_t mSurfaceHeight = 0;
-
- ANativeWindow* mWindow = nullptr;
- EGLSurface mEGLSurface = EGL_NO_SURFACE;
-
- DISALLOW_COPY_AND_ASSIGN(GLSurface);
-};
-
-} // namespace gl
-} // namespace renderengine
-} // namespace android
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index becb3c3..22891c4 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -48,7 +48,6 @@
class BindNativeBufferAsFramebuffer;
class Image;
class Mesh;
-class Surface;
class Texture;
namespace impl {
@@ -72,7 +71,6 @@
// used to support legacy behavior.
virtual std::unique_ptr<Framebuffer> createFramebuffer() = 0;
- virtual std::unique_ptr<Surface> createSurface() = 0;
virtual std::unique_ptr<Image> createImage() = 0;
virtual void primeCache() const = 0;
@@ -84,8 +82,6 @@
virtual bool useWaitSync() const = 0;
virtual bool isCurrent() const = 0;
- virtual bool setCurrentSurface(const Surface& surface) = 0;
- virtual void resetCurrentSurface() = 0;
// helpers
// flush submits RenderEngine command stream for execution and returns a
diff --git a/libs/renderengine/include/renderengine/Surface.h b/libs/renderengine/include/renderengine/Surface.h
deleted file mode 100644
index ba7331d..0000000
--- a/libs/renderengine/include/renderengine/Surface.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <cstdint>
-
-struct ANativeWindow;
-
-namespace android {
-namespace renderengine {
-
-class Surface {
-public:
- virtual ~Surface() = default;
-
- virtual void setCritical(bool enable) = 0;
- virtual void setAsync(bool enable) = 0;
-
- virtual void setNativeWindow(ANativeWindow* window) = 0;
- virtual void swapBuffers() const = 0;
-
- virtual int32_t queryRedSize() const = 0;
- virtual int32_t queryGreenSize() const = 0;
- virtual int32_t queryBlueSize() const = 0;
- virtual int32_t queryAlphaSize() const = 0;
-
- virtual int32_t getWidth() const = 0;
- virtual int32_t getHeight() const = 0;
-};
-
-} // namespace renderengine
-} // namespace android
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index fe4ae6c..8150931 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -325,6 +325,20 @@
return *this;
}
+Region& Region::scaleSelf(int sx, int sy) {
+ size_t count = mStorage.size();
+ Rect* rects = mStorage.editArray();
+ while (count) {
+ rects->left *= sx;
+ rects->right *= sx;
+ rects->top *= sy;
+ rects->bottom *= sy;
+ rects++;
+ count--;
+ }
+ return *this;
+}
+
// ----------------------------------------------------------------------------
const Region Region::merge(const Rect& rhs) const {
diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp
index 8e949ec..25128ef 100644
--- a/libs/ui/Transform.cpp
+++ b/libs/ui/Transform.cpp
@@ -95,6 +95,14 @@
return mMatrix[2][1];
}
+float Transform::sx() const {
+ return mMatrix[0][0];
+}
+
+float Transform::sy() const {
+ return mMatrix[1][1];
+}
+
void Transform::reset() {
mType = IDENTITY;
for(size_t i = 0; i < 3; i++) {
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 68b60fc..c5e31c5 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -89,11 +89,13 @@
// these translate rhs first
Region& translateSelf(int dx, int dy);
+ Region& scaleSelf(int sx, int sy);
Region& orSelf(const Region& rhs, int dx, int dy);
Region& xorSelf(const Region& rhs, int dx, int dy);
Region& andSelf(const Region& rhs, int dx, int dy);
Region& subtractSelf(const Region& rhs, int dx, int dy);
+
// these translate rhs first
const Region translate(int dx, int dy) const WARN_UNUSED;
const Region merge(const Region& rhs, int dx, int dy) const WARN_UNUSED;
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index 42dca75..900a5c4 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -65,6 +65,8 @@
const vec3& operator [] (size_t i) const; // returns column i
float tx() const;
float ty() const;
+ float sx() const;
+ float sy() const;
// modify the transform
void reset();
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index 6af8033..d30636f 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -156,20 +156,25 @@
memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
sp<IBufferClient> client;
+ BufferHubStatus ret;
IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& outClient, const auto& status) {
- ASSERT_EQ(status, BufferHubStatus::NO_ERROR);
- ASSERT_NE(nullptr, outClient.get());
client = outClient;
+ ret = status;
};
ASSERT_TRUE(bufferhub->allocateBuffer(desc, kUserMetadataSize, alloc_cb).isOk());
+ EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
+ ASSERT_NE(nullptr, client.get());
- IBufferClient::duplicate_cb dup_cb = [](const auto& token, const auto& status) {
- ASSERT_EQ(status, BufferHubStatus::NO_ERROR);
- ASSERT_NE(token.getNativeHandle(), nullptr);
- EXPECT_EQ(token->numInts, 1);
- EXPECT_EQ(token->numFds, 0);
+ hidl_handle token;
+ IBufferClient::duplicate_cb dup_cb = [&](const auto& outToken, const auto& status) {
+ token = outToken;
+ ret = status;
};
EXPECT_TRUE(client->duplicate(dup_cb).isOk());
+ EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
+ ASSERT_NE(token.getNativeHandle(), nullptr);
+ EXPECT_EQ(token->numInts, 1);
+ EXPECT_EQ(token->numFds, 0);
}
} // namespace
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
index 28a7501..b747dbc 100644
--- a/services/bufferhub/Android.bp
+++ b/services/bufferhub/Android.bp
@@ -17,6 +17,7 @@
cc_library_shared {
name: "libbufferhubservice",
cflags: [
+ "-DLOG_TAG=\"libbufferhubservice\"",
"-Wall",
"-Werror",
"-Wextra",
@@ -71,6 +72,7 @@
"libutils",
],
cflags: [
+ "-DLOG_TAG=\"bufferhub\"",
"-Wall",
"-Werror",
"-Wextra",
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index fc5ad1d..1a38dd8 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -58,7 +58,7 @@
return Void();
}
-hidl_handle BufferHubService::registerToken(const BufferClient* client) {
+hidl_handle BufferHubService::registerToken(const wp<BufferClient>& client) {
uint32_t token;
std::lock_guard<std::mutex> lock(mTokenMapMutex);
do {
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
index 5441750..e3f657f 100644
--- a/services/bufferhub/include/bufferhub/BufferHubService.h
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -46,18 +46,18 @@
// Non-binder functions
// Internal help function for IBufferClient::duplicate.
- hidl_handle registerToken(const BufferClient* client);
+ hidl_handle registerToken(const wp<BufferClient>& client);
private:
// List of active BufferClient for bookkeeping.
std::mutex mClientListMutex;
- std::vector<sp<BufferClient>> mClientList GUARDED_BY(mClientListMutex);
+ std::vector<wp<BufferClient>> mClientList GUARDED_BY(mClientListMutex);
// TODO(b/118180214): use a more secure implementation
std::mt19937 mTokenEngine;
// The mapping from token to the client creates it.
std::mutex mTokenMapMutex;
- std::map<uint32_t, const BufferClient*> mTokenMap GUARDED_BY(mTokenMapMutex);
+ std::map<uint32_t, const wp<BufferClient>> mTokenMap GUARDED_BY(mTokenMapMutex);
};
} // namespace implementation
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 0c9e04b..bea4f91 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -489,7 +489,7 @@
if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
&& (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
- && mInputTargetWaitApplicationHandle != nullptr) {
+ && mInputTargetWaitApplicationToken != nullptr) {
int32_t displayId = motionEntry->displayId;
int32_t x = int32_t(motionEntry->pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_X));
@@ -497,8 +497,8 @@
getAxisValue(AMOTION_EVENT_AXIS_Y));
sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y);
if (touchedWindowHandle != nullptr
- && touchedWindowHandle->inputApplicationHandle
- != mInputTargetWaitApplicationHandle) {
+ && touchedWindowHandle->getApplicationToken()
+ != mInputTargetWaitApplicationToken) {
// User touched a different application than the one we are waiting on.
// Flag the event, and start pruning the input queue.
mNextUnblockedEvent = motionEntry;
@@ -819,7 +819,8 @@
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
if (focusedWindowHandle != nullptr) {
- commandEntry->inputChannel = focusedWindowHandle->getInputChannel();
+ commandEntry->inputChannel =
+ getInputChannelLocked(focusedWindowHandle->getToken());
}
commandEntry->keyEntry = entry;
entry->refCount += 1;
@@ -1010,7 +1011,7 @@
mInputTargetWaitStartTime = currentTime;
mInputTargetWaitTimeoutTime = LONG_LONG_MAX;
mInputTargetWaitTimeoutExpired = false;
- mInputTargetWaitApplicationHandle.clear();
+ mInputTargetWaitApplicationToken.clear();
}
} else {
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
@@ -1033,13 +1034,13 @@
mInputTargetWaitStartTime = currentTime;
mInputTargetWaitTimeoutTime = currentTime + timeout;
mInputTargetWaitTimeoutExpired = false;
- mInputTargetWaitApplicationHandle.clear();
+ mInputTargetWaitApplicationToken.clear();
if (windowHandle != nullptr) {
- mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;
+ mInputTargetWaitApplicationToken = windowHandle->getApplicationToken();
}
- if (mInputTargetWaitApplicationHandle == nullptr && applicationHandle != nullptr) {
- mInputTargetWaitApplicationHandle = applicationHandle;
+ if (mInputTargetWaitApplicationToken == nullptr && applicationHandle != nullptr) {
+ mInputTargetWaitApplicationToken = applicationHandle->getApplicationToken();
}
}
}
@@ -1117,7 +1118,7 @@
// Reset input target wait timeout.
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
- mInputTargetWaitApplicationHandle.clear();
+ mInputTargetWaitApplicationToken.clear();
}
/**
@@ -1666,11 +1667,13 @@
const InputWindowInfo* windowInfo = windowHandle->getInfo();
InputTarget& target = inputTargets.editTop();
- target.inputChannel = windowInfo->inputChannel;
+ target.inputChannel = getInputChannelLocked(windowHandle->getToken());
target.flags = targetFlags;
target.xOffset = - windowInfo->frameLeft;
target.yOffset = - windowInfo->frameTop;
- target.scaleFactor = windowInfo->scaleFactor;
+ target.globalScaleFactor = windowInfo->globalScaleFactor;
+ target.windowXScale = windowInfo->windowXScale;
+ target.windowYScale = windowInfo->windowYScale;
target.pointerIds = pointerIds;
}
@@ -1691,7 +1694,7 @@
target.xOffset = 0;
target.yOffset = 0;
target.pointerIds.clear();
- target.scaleFactor = 1.0f;
+ target.globalScaleFactor = 1.0f;
}
} else {
// If there is no monitor channel registered or all monitor channel unregistered,
@@ -1773,7 +1776,8 @@
}
// If the window's connection is not registered then keep waiting.
- ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
+ ssize_t connectionIndex = getConnectionIndexLocked(
+ getInputChannelLocked(windowHandle->getToken()));
if (connectionIndex < 0) {
return StringPrintf("Waiting because the %s window's input channel is not "
"registered with the input dispatcher. The window may be in the process "
@@ -1910,11 +1914,13 @@
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
- "xOffset=%f, yOffset=%f, scaleFactor=%f, "
- "pointerIds=0x%x",
+ "xOffset=%f, yOffset=%f, globalScaleFactor=%f, "
+ "windowScaleFactor=(%f, %f), pointerIds=0x%x",
connection->getInputChannelName().c_str(), inputTarget->flags,
inputTarget->xOffset, inputTarget->yOffset,
- inputTarget->scaleFactor, inputTarget->pointerIds.value);
+ inputTarget->globalScaleFactor,
+ inputTarget->windowXScale, inputTarget->windowYScale,
+ inputTarget->pointerIds.value);
#endif
// Skip this event if the connection status is not normal.
@@ -1991,7 +1997,8 @@
// Enqueue a new dispatch entry onto the outbound queue for this connection.
DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
- inputTarget->scaleFactor);
+ inputTarget->globalScaleFactor, inputTarget->windowXScale,
+ inputTarget->windowYScale);
// Apply target flags and update the connection's input state.
switch (eventEntry->type) {
@@ -2107,13 +2114,15 @@
float xOffset, yOffset;
if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
- float scaleFactor = dispatchEntry->scaleFactor;
- xOffset = dispatchEntry->xOffset * scaleFactor;
- yOffset = dispatchEntry->yOffset * scaleFactor;
- if (scaleFactor != 1.0f) {
+ float globalScaleFactor = dispatchEntry->globalScaleFactor;
+ float wxs = dispatchEntry->windowXScale;
+ float wys = dispatchEntry->windowYScale;
+ xOffset = dispatchEntry->xOffset * wxs;
+ yOffset = dispatchEntry->yOffset * wys;
+ if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) {
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
scaledCoords[i] = motionEntry->pointerCoords[i];
- scaledCoords[i].scale(scaleFactor);
+ scaledCoords[i].scale(globalScaleFactor, wxs, wys);
}
usingCoords = scaledCoords;
}
@@ -2371,11 +2380,13 @@
const InputWindowInfo* windowInfo = windowHandle->getInfo();
target.xOffset = -windowInfo->frameLeft;
target.yOffset = -windowInfo->frameTop;
- target.scaleFactor = windowInfo->scaleFactor;
+ target.globalScaleFactor = windowInfo->globalScaleFactor;
+ target.windowXScale = windowInfo->windowXScale;
+ target.windowYScale = windowInfo->windowYScale;
} else {
target.xOffset = 0;
target.yOffset = 0;
- target.scaleFactor = 1.0f;
+ target.globalScaleFactor = 1.0f;
}
target.inputChannel = connection->inputChannel;
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
@@ -3004,7 +3015,7 @@
size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
- if (windowHandle->getInputChannel() == inputChannel) {
+ if (windowHandle->getToken() == inputChannel->getToken()) {
return windowHandle;
}
}
@@ -3018,8 +3029,8 @@
const Vector<sp<InputWindowHandle>> windowHandles = it.second;
size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- if (windowHandles.itemAt(i)->getInputChannel()->getToken()
- == windowHandle->getInputChannel()->getToken()) {
+ if (windowHandles.itemAt(i)->getToken()
+ == windowHandle->getToken()) {
if (windowHandle->getInfo()->displayId != it.first) {
ALOGE("Found window %s in display %" PRId32
", but it should belong to display %" PRId32,
@@ -3033,6 +3044,14 @@
return false;
}
+sp<InputChannel> InputDispatcher::getInputChannelLocked(const sp<IBinder>& token) const {
+ size_t count = mInputChannelsByToken.count(token);
+ if (count == 0) {
+ return nullptr;
+ }
+ return mInputChannelsByToken.at(token);
+}
+
/**
* Called from InputManagerService, update window handle list by displayId that can receive input.
* A window handle contains information about InputChannel, Touch Region, Types, Focused,...
@@ -3061,7 +3080,9 @@
size_t numWindows = inputWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
const sp<InputWindowHandle>& windowHandle = inputWindowHandles.itemAt(i);
- if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) {
+ if (!windowHandle->updateInfo() || getInputChannelLocked(windowHandle->getToken()) == nullptr) {
+ ALOGE("Window handle %s has no registered input channel",
+ windowHandle->getName().c_str());
continue;
}
@@ -3097,7 +3118,8 @@
ALOGD("Focus left window: %s in display %" PRId32,
oldFocusedWindowHandle->getName().c_str(), displayId);
#endif
- sp<InputChannel> focusedInputChannel = oldFocusedWindowHandle->getInputChannel();
+ sp<InputChannel> focusedInputChannel = getInputChannelLocked(
+ oldFocusedWindowHandle->getToken());
if (focusedInputChannel != nullptr) {
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"focus left window");
@@ -3113,6 +3135,11 @@
#endif
mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle;
}
+
+ if (mFocusedDisplayId == displayId) {
+ onFocusChangedLocked(newFocusedWindowHandle);
+ }
+
}
ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
@@ -3126,7 +3153,7 @@
touchedWindow.windowHandle->getName().c_str(), displayId);
#endif
sp<InputChannel> touchedInputChannel =
- touchedWindow.windowHandle->getInputChannel();
+ getInputChannelLocked(touchedWindow.windowHandle->getToken());
if (touchedInputChannel != nullptr) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"touched window was removed");
@@ -3214,7 +3241,8 @@
sp<InputWindowHandle> oldFocusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId);
if (oldFocusedWindowHandle != nullptr) {
- sp<InputChannel> inputChannel = oldFocusedWindowHandle->getInputChannel();
+ sp<InputChannel> inputChannel =
+ getInputChannelLocked(oldFocusedWindowHandle->getToken());
if (inputChannel != nullptr) {
CancelationOptions options(
CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS,
@@ -3227,6 +3255,8 @@
// Sanity check
sp<InputWindowHandle> newFocusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+ onFocusChangedLocked(newFocusedWindowHandle);
+
if (newFocusedWindowHandle == nullptr) {
ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
if (!mFocusedWindowHandlesByDisplay.empty()) {
@@ -3488,7 +3518,7 @@
dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, "
"paused=%s, hasFocus=%s, hasWallpaper=%s, "
"visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
- "frame=[%d,%d][%d,%d], scale=%f, "
+ "frame=[%d,%d][%d,%d], globalScale=%f, windowScale=%f,%f"
"touchableRegion=",
i, windowInfo->name.c_str(), windowInfo->displayId,
toString(windowInfo->paused),
@@ -3500,7 +3530,8 @@
windowInfo->layer,
windowInfo->frameLeft, windowInfo->frameTop,
windowInfo->frameRight, windowInfo->frameBottom,
- windowInfo->scaleFactor);
+ windowInfo->globalScaleFactor,
+ windowInfo->windowXScale, windowInfo->windowYScale);
dumpRegion(dump, windowInfo->touchableRegion);
dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
@@ -3667,6 +3698,7 @@
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);
+ mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
// Store monitor channel by displayId.
if (monitor) {
@@ -3715,6 +3747,8 @@
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
mConnectionsByFd.removeItemsAt(connectionIndex);
+ mInputChannelsByToken.erase(inputChannel->getToken());
+
if (connection->monitor) {
removeMonitorChannelLocked(inputChannel);
}
@@ -3782,6 +3816,13 @@
commandEntry->connection = connection;
}
+void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& newFocus) {
+ sp<IBinder> token = newFocus != nullptr ? newFocus->getToken() : nullptr;
+ CommandEntry* commandEntry = postCommandLocked(
+ & InputDispatcher::doNotifyFocusChangedLockedInterruptible);
+ commandEntry->token = token;
+}
+
void InputDispatcher::onANRLocked(
nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
@@ -3812,7 +3853,8 @@
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doNotifyANRLockedInterruptible);
commandEntry->inputApplicationHandle = applicationHandle;
- commandEntry->inputChannel = windowHandle != nullptr ? windowHandle->getInputChannel() : nullptr;
+ commandEntry->inputChannel = windowHandle != nullptr ?
+ getInputChannelLocked(windowHandle->getToken()) : nullptr;
commandEntry->reason = reason;
}
@@ -3838,6 +3880,14 @@
}
}
+void InputDispatcher::doNotifyFocusChangedLockedInterruptible(
+ CommandEntry* commandEntry) {
+ sp<IBinder> token = commandEntry->token;
+ mLock.unlock();
+ mPolicy->notifyFocusChanged(token);
+ mLock.lock();
+}
+
void InputDispatcher::doNotifyANRLockedInterruptible(
CommandEntry* commandEntry) {
mLock.unlock();
@@ -4343,10 +4393,12 @@
volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic;
InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry,
- int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) :
+ int32_t targetFlags, float xOffset, float yOffset, float globalScaleFactor,
+ float windowXScale, float windowYScale) :
seq(nextSeq()),
eventEntry(eventEntry), targetFlags(targetFlags),
- xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor),
+ xOffset(xOffset), yOffset(yOffset), globalScaleFactor(globalScaleFactor),
+ windowXScale(windowXScale), windowYScale(windowYScale),
deliveryTime(0), resolvedAction(0), resolvedFlags(0) {
eventEntry->refCount += 1;
}
@@ -4847,7 +4899,7 @@
void InputDispatcher::TouchState::removeWindowByToken(const sp<IBinder>& token) {
for (size_t i = 0; i < windows.size(); i++) {
- if (windows.itemAt(i).windowHandle->getInputChannel()->getToken() == token) {
+ if (windows.itemAt(i).windowHandle->getToken() == token) {
windows.removeAt(i);
return;
}
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 5016082..73bcc25 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -29,6 +29,7 @@
#include <utils/Looper.h>
#include <utils/BitSet.h>
#include <cutils/atomic.h>
+#include <unordered_map>
#include <stddef.h>
#include <unistd.h>
@@ -159,7 +160,9 @@
// Scaling factor to apply to MotionEvent as it is delivered.
// (ignored for KeyEvents)
- float scaleFactor;
+ float globalScaleFactor;
+ float windowXScale = 1.0f;
+ float windowYScale = 1.0f;
// The subset of pointer ids to include in motion events dispatched to this input target
// if FLAG_SPLIT is set.
@@ -213,6 +216,7 @@
/* Notifies the system that an input channel is unrecoverably broken. */
virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
+ virtual void notifyFocusChanged(const sp<IBinder>& token) = 0;
/* Gets the input dispatcher configuration. */
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
@@ -561,7 +565,9 @@
int32_t targetFlags;
float xOffset;
float yOffset;
- float scaleFactor;
+ float globalScaleFactor;
+ float windowXScale = 1.0f;
+ float windowYScale = 1.0f;
nsecs_t deliveryTime; // time when the event was actually delivered
// Set to the resolved action and flags when the event is enqueued.
@@ -569,7 +575,8 @@
int32_t resolvedFlags;
DispatchEntry(EventEntry* eventEntry,
- int32_t targetFlags, float xOffset, float yOffset, float scaleFactor);
+ int32_t targetFlags, float xOffset, float yOffset,
+ float globalScaleFactor, float windowXScale, float windowYScale);
~DispatchEntry();
inline bool hasForegroundTarget() const {
@@ -622,6 +629,7 @@
uint32_t seq;
bool handled;
sp<InputChannel> inputChannel;
+ sp<IBinder> token;
};
// Generic queue implementation.
@@ -916,6 +924,13 @@
// All registered connections mapped by channel file descriptor.
KeyedVector<int, sp<Connection> > mConnectionsByFd;
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& b) const {
+ return std::hash<IBinder *>{}(b.get());
+ }
+ };
+ std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken;
+
ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
// Input channels that will receive a copy of all input events sent to the provided display.
@@ -979,6 +994,7 @@
// Get window handles by display, return an empty vector if not found.
Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const;
sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
+ sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const;
bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
// Focus tracking for keys, trackball, etc.
@@ -1051,7 +1067,7 @@
nsecs_t mInputTargetWaitStartTime;
nsecs_t mInputTargetWaitTimeoutTime;
bool mInputTargetWaitTimeoutExpired;
- sp<InputApplicationHandle> mInputTargetWaitApplicationHandle;
+ sp<IBinder> mInputTargetWaitApplicationToken;
// Contains the last window which received a hover event.
sp<InputWindowHandle> mLastHoverWindowHandle;
@@ -1143,6 +1159,7 @@
nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
void onDispatchCycleBrokenLocked(
nsecs_t currentTime, const sp<Connection>& connection);
+ void onFocusChangedLocked(const sp<InputWindowHandle>& newFocus);
void onANRLocked(
nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
@@ -1151,6 +1168,7 @@
// Outbound policy interactions.
void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry);
void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
+ void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry);
void doNotifyANRLockedInterruptible(CommandEntry* commandEntry);
void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry);
void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry);
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 388423c..15d8070 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -21,9 +21,13 @@
#include "InputManager.h"
#include "InputReaderFactory.h"
+#include <binder/IPCThreadState.h>
+
#include <log/log.h>
#include <unordered_map>
+#include <private/android_filesystem_config.h>
+
namespace android {
InputManager::InputManager(
@@ -83,20 +87,9 @@
return mDispatcher;
}
-class BinderApplicationHandle : public InputApplicationHandle {
-public:
- BinderApplicationHandle() = default;
-
- bool updateInfo() override {
- return true;
- }
-};
-
class BinderWindowHandle : public InputWindowHandle {
public:
- BinderWindowHandle(const InputWindowInfo& info) :
- InputWindowHandle(new BinderApplicationHandle()) {
-
+ BinderWindowHandle(const InputWindowInfo& info) {
mInfo = info;
}
@@ -118,4 +111,20 @@
}
}
+// Used by tests only.
+void InputManager::registerInputChannel(const sp<InputChannel>& channel) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int uid = ipc->getCallingUid();
+ if (uid != AID_SHELL && uid != AID_ROOT) {
+ ALOGE("Invalid attempt to register input channel over IPC"
+ "from non shell/root entity (PID: %d)", ipc->getCallingPid());
+ return;
+ }
+ mDispatcher->registerInputChannel(channel, false);
+}
+
+void InputManager::unregisterInputChannel(const sp<InputChannel>& channel) {
+ mDispatcher->unregisterInputChannel(channel);
+}
+
} // namespace android
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 1173fa1..8f7551e 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -35,6 +35,7 @@
#include <utils/RefBase.h>
namespace android {
+class InputChannel;
/*
* The input manager is the core of the system event processing.
@@ -91,6 +92,9 @@
virtual void setInputWindows(const Vector<InputWindowInfo>& handles);
+ virtual void registerInputChannel(const sp<InputChannel>& channel);
+ virtual void unregisterInputChannel(const sp<InputChannel>& channel);
+
private:
sp<InputReaderInterface> mReader;
sp<InputReaderThread> mReaderThread;
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index 0e48f24..cbe0190 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -62,6 +62,4 @@
static_libs: [
"libarect",
],
-
- init_rc: ["inputflinger.rc"],
}
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 15ca7b3..82ff089 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -40,6 +40,8 @@
virtual status_t dump(int fd, const Vector<String16>& args);
void setInputWindows(const Vector<InputWindowInfo>&) {}
+ void registerInputChannel(const sp<InputChannel>&) {}
+ void unregisterInputChannel(const sp<InputChannel>&) {}
private:
virtual ~InputFlinger();
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index e860db5..26f01b7 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -63,6 +63,9 @@
virtual void notifyInputChannelBroken(const sp<IBinder>&) {
}
+ virtual void notifyFocusChanged(const sp<IBinder>&) {
+ }
+
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
*outConfig = mConfig;
}
@@ -338,7 +341,6 @@
const std::string name, int32_t displayId) :
mDispatcher(dispatcher), mName(name), mDisplayId(displayId) {
InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
-
mConsumer = new InputConsumer(mClientChannel);
}
@@ -352,6 +354,7 @@
sp<InputDispatcher> mDispatcher;
sp<InputChannel> mServerChannel, mClientChannel;
+ sp<IBinder> mToken;
InputConsumer *mConsumer;
PreallocatedInputEventFactory mEventFactory;
@@ -366,15 +369,17 @@
FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<InputDispatcher>& dispatcher, const std::string name, int32_t displayId) :
- InputWindowHandle(inputApplicationHandle),
FakeInputReceiver(dispatcher, name, displayId),
mFocused(false) {
mServerChannel->setToken(new BBinder());
mDispatcher->registerInputChannel(mServerChannel, displayId);
+
+ inputApplicationHandle->updateInfo();
+ mInfo.applicationInfo = *inputApplicationHandle->getInfo();
}
virtual bool updateInfo() {
- mInfo.inputChannel = mServerChannel;
+ mInfo.token = mServerChannel->getToken();
mInfo.name = mName;
mInfo.layoutParamsFlags = 0;
mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
@@ -383,7 +388,7 @@
mInfo.frameTop = 0;
mInfo.frameRight = WIDTH;
mInfo.frameBottom = HEIGHT;
- mInfo.scaleFactor = 1.0;
+ mInfo.globalScaleFactor = 1.0;
mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
mInfo.visible = true;
mInfo.canReceiveKeys = true;
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 0fb4ac6..8dc80cc 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -315,32 +315,7 @@
if (mCacheSize != 0) {
// There are some events in the cache which need to be sent first. Copy this buffer to
// the end of cache.
- if (mCacheSize + count <= mMaxCacheSize) {
- memcpy(&mEventCache[mCacheSize], scratch, count * sizeof(sensors_event_t));
- mCacheSize += count;
- } else {
- // Check if any new sensors have registered on this connection which may have increased
- // the max cache size that is desired.
- if (mCacheSize + count < computeMaxCacheSizeLocked()) {
- reAllocateCacheLocked(scratch, count);
- return status_t(NO_ERROR);
- }
- // Some events need to be dropped.
- int remaningCacheSize = mMaxCacheSize - mCacheSize;
- if (remaningCacheSize != 0) {
- memcpy(&mEventCache[mCacheSize], scratch,
- remaningCacheSize * sizeof(sensors_event_t));
- }
- int numEventsDropped = count - remaningCacheSize;
- countFlushCompleteEventsLocked(mEventCache, numEventsDropped);
- // Drop the first "numEventsDropped" in the cache.
- memmove(mEventCache, &mEventCache[numEventsDropped],
- (mCacheSize - numEventsDropped) * sizeof(sensors_event_t));
-
- // Copy the remainingEvents in scratch buffer to the end of cache.
- memcpy(&mEventCache[mCacheSize - numEventsDropped], scratch + remaningCacheSize,
- numEventsDropped * sizeof(sensors_event_t));
- }
+ appendEventsToCacheLocked(scratch, count);
return status_t(NO_ERROR);
}
@@ -376,8 +351,8 @@
mEventCache = new sensors_event_t[mMaxCacheSize];
mCacheSize = 0;
}
- memcpy(&mEventCache[mCacheSize], scratch, count * sizeof(sensors_event_t));
- mCacheSize += count;
+ // Save the events so that they can be written later
+ appendEventsToCacheLocked(scratch, count);
// Add this file descriptor to the looper to get a callback when this fd is available for
// writing.
@@ -417,6 +392,51 @@
mMaxCacheSize = new_cache_size;
}
+void SensorService::SensorEventConnection::appendEventsToCacheLocked(sensors_event_t const* events,
+ int count) {
+ if (count <= 0) {
+ return;
+ } else if (mCacheSize + count <= mMaxCacheSize) {
+ // The events fit within the current cache: add them
+ memcpy(&mEventCache[mCacheSize], events, count * sizeof(sensors_event_t));
+ mCacheSize += count;
+ } else if (mCacheSize + count <= computeMaxCacheSizeLocked()) {
+ // The events fit within a resized cache: resize the cache and add the events
+ reAllocateCacheLocked(events, count);
+ } else {
+ // The events do not fit within the cache: drop the oldest events.
+ ALOGW("Dropping events from cache (%d / %d) to save %d newer events", mCacheSize,
+ mMaxCacheSize, count);
+
+ int freeSpace = mMaxCacheSize - mCacheSize;
+
+ // Drop up to the currently cached number of events to make room for new events
+ int cachedEventsToDrop = std::min(mCacheSize, count - freeSpace);
+
+ // New events need to be dropped if there are more new events than the size of the cache
+ int newEventsToDrop = std::max(0, count - mMaxCacheSize);
+
+ // Determine the number of new events to copy into the cache
+ int eventsToCopy = std::min(mMaxCacheSize, count);
+
+ // Check for any flush complete events in the events that will be dropped
+ countFlushCompleteEventsLocked(mEventCache, cachedEventsToDrop);
+ countFlushCompleteEventsLocked(events, newEventsToDrop);
+
+ // Only shift the events if they will not all be overwritten
+ if (eventsToCopy != mMaxCacheSize) {
+ memmove(mEventCache, &mEventCache[cachedEventsToDrop],
+ (mCacheSize - cachedEventsToDrop) * sizeof(sensors_event_t));
+ }
+ mCacheSize -= cachedEventsToDrop;
+
+ // Copy the events into the cache
+ memcpy(&mEventCache[mCacheSize], &events[newEventsToDrop],
+ eventsToCopy * sizeof(sensors_event_t));
+ mCacheSize += eventsToCopy;
+ }
+}
+
void SensorService::SensorEventConnection::sendPendingFlushEventsLocked() {
ASensorEvent flushCompleteEvent;
memset(&flushCompleteEvent, 0, sizeof(flushCompleteEvent));
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 40c21ff..eefd81a 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -108,6 +108,10 @@
// size, reallocate memory and copy over events from the older cache.
void reAllocateCacheLocked(sensors_event_t const* scratch, int count);
+ // Add the events to the cache. If the cache would be exceeded, drop events at the beginning of
+ // the cache.
+ void appendEventsToCacheLocked(sensors_event_t const* events, int count);
+
// LooperCallback method. If there is data to read on this fd, it is an ack from the app that it
// has read events from a wake up sensor, decrement mWakeLockRefCount. If this fd is available
// for writing send the data from the cache.
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 088c256..1007b3d 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -54,6 +54,7 @@
"libsync",
"libtimestats_proto",
"libui",
+ "libinput",
"libutils",
],
static_libs: [
@@ -183,6 +184,7 @@
"libdisplayservicehidl",
"libhidlbase",
"libhidltransport",
+ "libinput",
"liblayers_proto",
"liblog",
"libsync",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index ade62bf..7caae98 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -501,7 +501,7 @@
// FIXME: postedRegion should be dirty & bounds
// transform the dirty region to window-manager space
- return getTransform().transform(Region(Rect(getActiveWidth(s), getActiveHeight(s))));
+ return getTransform().transform(Region(getBufferSize(s)));
}
// transaction
@@ -624,11 +624,13 @@
ui::Transform t = getTransform();
Rect win = bounds;
+ const int bufferWidth = getBufferSize(s).getWidth();
+ const int bufferHeight = getBufferSize(s).getHeight();
- float left = float(win.left) / float(getActiveWidth(s));
- float top = float(win.top) / float(getActiveHeight(s));
- float right = float(win.right) / float(getActiveWidth(s));
- float bottom = float(win.bottom) / float(getActiveHeight(s));
+ const float left = float(win.left) / float(bufferWidth);
+ const float top = float(win.top) / float(bufferHeight);
+ const float right = float(win.right) / float(bufferWidth);
+ const float bottom = float(win.bottom) / float(bufferHeight);
// TODO: we probably want to generate the texture coords with the mesh
// here we assume that we only have 4 vertices
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 78ab23a..162f391 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -352,9 +352,10 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
- // Report the timestamp to the Scheduler.
+ // Report the requested present time to the Scheduler.
if (mFlinger->mUseScheduler) {
- mFlinger->mScheduler->addNewFrameTimestamp(item.mTimestamp, item.mIsAutoTimestamp);
+ mFlinger->mScheduler->addFramePresentTimeForLayer(item.mTimestamp,
+ item.mIsAutoTimestamp, mName.c_str());
}
Mutex::Autolock lock(mQueueItemLock);
@@ -382,7 +383,7 @@
mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
item.mGraphicBuffer->getHeight(), item.mFrameNumber);
-
+
// If this layer is orphaned, then we run a fake vsync pulse so that
// dequeueBuffer doesn't block indefinitely.
if (isRemovedFromCurrentState()) {
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 425f5c7..5ffd8ad 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -336,6 +336,9 @@
}
PixelFormat BufferStateLayer::getPixelFormat() const {
+ if (!mActiveBuffer) {
+ return PIXEL_FORMAT_NONE;
+ }
return mActiveBuffer->format;
}
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 55ce434..1215bd9 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -225,7 +225,6 @@
mNativeWindow(args.nativeWindow),
mGraphicBuffer(nullptr),
mDisplaySurface(args.displaySurface),
- mSurface{std::move(args.renderSurface)},
mDisplayInstallOrientation(args.displayInstallOrientation),
mPageFlipCount(0),
mIsVirtual(args.isVirtual),
@@ -247,7 +246,6 @@
ALOGE_IF(!mNativeWindow, "No native window was set for display");
ALOGE_IF(!mDisplaySurface, "No display surface was set for display");
- ALOGE_IF(!mSurface, "No render surface was set for display");
std::vector<Hdr> types = args.hdrCapabilities.getSupportedHdrTypes();
for (Hdr hdrType : types) {
@@ -443,12 +441,6 @@
mDisplaySurface->onFrameCommitted();
}
-bool DisplayDevice::makeCurrent() const {
- bool success = mFlinger->getRenderEngine().setCurrentSurface(*mSurface);
- setViewportAndProjection();
- return success;
-}
-
void DisplayDevice::setViewportAndProjection() const {
size_t w = mDisplayWidth;
size_t h = mDisplayHeight;
@@ -611,12 +603,8 @@
void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
dirtyRegion.set(getBounds());
- mSurface->setNativeWindow(nullptr);
-
mDisplaySurface->resizeBuffers(newWidth, newHeight);
- ANativeWindow* const window = mNativeWindow.get();
- mSurface->setNativeWindow(window);
mDisplayWidth = newWidth;
mDisplayHeight = newHeight;
}
@@ -732,12 +720,11 @@
ANativeWindow* const window = mNativeWindow.get();
result.appendFormat("+ %s\n", getDebugName().c_str());
result.appendFormat(" layerStack=%u, (%4dx%4d), ANativeWindow=%p "
- "(%d:%d:%d:%d), orient=%2d (type=%08x), "
- "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n",
+ "format=%d, orient=%2d (type=%08x), flips=%u, isSecure=%d, "
+ "powerMode=%d, activeConfig=%d, numLayers=%zu\n",
mLayerStack, mDisplayWidth, mDisplayHeight, window,
- mSurface->queryRedSize(), mSurface->queryGreenSize(),
- mSurface->queryBlueSize(), mSurface->queryAlphaSize(), mOrientation,
- tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
+ ANativeWindow_getFormat(window), mOrientation, tr.getType(),
+ getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
mVisibleLayersSortedByZ.size());
result.appendFormat(" v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
"transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
@@ -748,9 +735,9 @@
auto const surface = static_cast<Surface*>(window);
ui::Dataspace dataspace = surface->getBuffersDataSpace();
result.appendFormat(" wideColorGamut=%d, hdr10=%d, colorMode=%s, dataspace: %s (%d)\n",
- mHasWideColorGamut, mHasHdr10,
- decodeColorMode(mActiveColorMode).c_str(),
- dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
+ mHasWideColorGamut, mHasHdr10, decodeColorMode(mActiveColorMode).c_str(),
+ dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(),
+ dataspace);
String8 surfaceDump;
mDisplaySurface->dumpAsString(surfaceDump);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 560a958..eb2c5c3 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -24,12 +24,13 @@
#include <string>
#include <unordered_map>
+#include <android/native_window.h>
#include <binder/IBinder.h>
#include <gui/LayerState.h>
#include <hardware/hwcomposer_defs.h>
#include <math/mat4.h>
#include <renderengine/RenderEngine.h>
-#include <renderengine/Surface.h>
+#include <system/window.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
@@ -42,8 +43,6 @@
#include "DisplayHardware/DisplayIdentification.h"
#include "RenderArea.h"
-struct ANativeWindow;
-
namespace android {
class DisplaySurface;
@@ -163,7 +162,6 @@
void setDisplayName(const std::string& displayName);
const std::string& getDisplayName() const { return mDisplayName; }
- bool makeCurrent() const;
// Acquires a new buffer for GPU composition.
void readyNewBuffer();
// Marks the current buffer has finished, so that it can be presented and
@@ -220,7 +218,6 @@
// that drawing to the buffer is now complete.
base::unique_fd mBufferReady;
- std::unique_ptr<renderengine::Surface> mSurface;
int mDisplayWidth;
int mDisplayHeight;
const int mDisplayInstallOrientation;
@@ -340,7 +337,6 @@
bool isSecure{false};
sp<ANativeWindow> nativeWindow;
sp<DisplaySurface> displaySurface;
- std::unique_ptr<renderengine::Surface> renderSurface;
int displayInstallOrientation{DisplayState::eOrientationDefault};
bool hasWideColorGamut{false};
HdrCapabilities hdrCapabilities;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 0f25b52..9bbc37f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -20,31 +20,12 @@
#define LOG_TAG "HWComposer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <inttypes.h>
-#include <math.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
#include <utils/Errors.h>
-#include <utils/misc.h>
-#include <utils/NativeHandle.h>
-#include <utils/String8.h>
-#include <utils/Thread.h>
#include <utils/Trace.h>
-#include <utils/Vector.h>
#include <ui/DebugUtils.h>
#include <ui/GraphicBuffer.h>
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-
-#include <android/configuration.h>
-
-#include <cutils/properties.h>
#include <log/log.h>
#include "HWComposer.h"
@@ -85,11 +66,7 @@
namespace android {
-#define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION
-
-// ---------------------------------------------------------------------------
-
-HWComposer::HWComposer(std::unique_ptr<android::Hwc2::Composer> composer)
+HWComposer::HWComposer(std::unique_ptr<Hwc2::Composer> composer)
: mHwcDevice(std::make_unique<HWC2::Device>(std::move(composer))) {}
HWComposer::~HWComposer() {
@@ -184,30 +161,31 @@
RETURN_IF_INVALID_DISPLAY(*displayId, false);
- const auto& displayData = mDisplayData[*displayId];
+ auto& displayData = mDisplayData[*displayId];
if (displayData.isVirtual) {
LOG_DISPLAY_ERROR(*displayId, "Invalid operation on virtual display");
return false;
}
{
- Mutex::Autolock _l(mLock);
+ std::lock_guard lock(displayData.lastHwVsyncLock);
// There have been reports of HWCs that signal several vsync events
// with the same timestamp when turning the display off and on. This
// is a bug in the HWC implementation, but filter the extra events
// out here so they don't cause havoc downstream.
- if (timestamp == mLastHwVSync[*displayId]) {
+ if (timestamp == displayData.lastHwVsync) {
ALOGW("Ignoring duplicate VSYNC event from HWC for display %s (t=%" PRId64 ")",
to_string(*displayId).c_str(), timestamp);
return false;
}
- mLastHwVSync[*displayId] = timestamp;
+ displayData.lastHwVsync = timestamp;
}
const auto tag = "HW_VSYNC_" + to_string(*displayId);
- ATRACE_INT(tag.c_str(), ++mVSyncCounts[*displayId] & 1);
+ ATRACE_INT(tag.c_str(), displayData.vsyncTraceToggle);
+ displayData.vsyncTraceToggle = !displayData.vsyncTraceToggle;
return true;
}
@@ -270,13 +248,14 @@
nsecs_t HWComposer::getRefreshTimestamp(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, 0);
+ const auto& displayData = mDisplayData.at(displayId);
// this returns the last refresh timestamp.
// if the last one is not available, we estimate it based on
// the refresh period and whatever closest timestamp we have.
- Mutex::Autolock _l(mLock);
+ std::lock_guard lock(displayData.lastHwVsyncLock);
nsecs_t now = systemTime(CLOCK_MONOTONIC);
auto vsyncPeriod = getActiveConfig(displayId)->getVsyncPeriod();
- return now - ((now - mLastHwVSync[displayId]) % vsyncPeriod);
+ return now - ((now - displayData.lastHwVsync) % vsyncPeriod);
}
bool HWComposer::isConnected(DisplayId displayId) const {
@@ -375,17 +354,19 @@
// into the HWC with the lock held, and we want to make sure
// that even if HWC blocks (which it shouldn't), it won't
// affect other threads.
- Mutex::Autolock _l(mVsyncLock);
- if (enabled != displayData.vsyncEnabled) {
- ATRACE_CALL();
- auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
- RETURN_IF_HWC_ERROR(error, displayId);
-
- displayData.vsyncEnabled = enabled;
-
- const auto tag = "HW_VSYNC_ON_" + to_string(displayId);
- ATRACE_INT(tag.c_str(), enabled == HWC2::Vsync::Enable ? 1 : 0);
+ std::lock_guard lock(displayData.vsyncEnabledLock);
+ if (enabled == displayData.vsyncEnabled) {
+ return;
}
+
+ ATRACE_CALL();
+ auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
+ RETURN_IF_HWC_ERROR(error, displayId);
+
+ displayData.vsyncEnabled = enabled;
+
+ const auto tag = "HW_VSYNC_ON_" + to_string(displayId);
+ ATRACE_INT(tag.c_str(), enabled == HWC2::Vsync::Enable ? 1 : 0);
}
status_t HWComposer::setClientTarget(DisplayId displayId, uint32_t slot,
@@ -405,8 +386,6 @@
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
- Mutex::Autolock _l(mDisplayLock);
-
auto& displayData = mDisplayData[displayId];
auto& hwcDisplay = displayData.hwcDisplay;
if (!hwcDisplay->isConnected()) {
@@ -428,7 +407,7 @@
// back to validate when there is any client layer.
displayData.validateWasSkipped = false;
if (!displayData.hasClientComposition) {
- sp<android::Fence> outPresentFence;
+ sp<Fence> outPresentFence;
uint32_t state = UINT32_MAX;
error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
if (error != HWC2::Error::HasChanges) {
@@ -689,7 +668,6 @@
const auto hwcDisplayId = displayData.hwcDisplay->getId();
mPhysicalDisplayIdMap.erase(hwcDisplayId);
mDisplayData.erase(displayId);
- mVSyncCounts.erase(displayId);
// TODO(b/74619554): Select internal/external display from remaining displays.
if (hwcDisplayId == mInternalHwcDisplayId) {
@@ -755,26 +733,6 @@
return matrix;
}
-// Converts a PixelFormat to a human-readable string. Max 11 chars.
-// (Could use a table of prefab String8 objects.)
-/*
-static String8 getFormatStr(PixelFormat format) {
- switch (format) {
- case PIXEL_FORMAT_RGBA_8888: return String8("RGBA_8888");
- case PIXEL_FORMAT_RGBX_8888: return String8("RGBx_8888");
- case PIXEL_FORMAT_RGB_888: return String8("RGB_888");
- case PIXEL_FORMAT_RGB_565: return String8("RGB_565");
- case PIXEL_FORMAT_BGRA_8888: return String8("BGRA_8888");
- case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
- return String8("ImplDef");
- default:
- String8 result;
- result.appendFormat("? %08x", format);
- return result;
- }
-}
-*/
-
bool HWComposer::isUsingVrComposer() const {
return getComposer()->isUsingVrComposer();
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index b78433d..2f57907 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -17,49 +17,26 @@
#ifndef ANDROID_SF_HWCOMPOSER_H
#define ANDROID_SF_HWCOMPOSER_H
-#include "HWC2.h"
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <ui/Fence.h>
-#include <ui/GraphicTypes.h>
-#include <utils/BitSet.h>
-#include <utils/Condition.h>
-#include <utils/Mutex.h>
-#include <utils/StrongPointer.h>
-#include <utils/Thread.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
+#include <cstdint>
#include <memory>
+#include <mutex>
#include <optional>
#include <unordered_map>
#include <unordered_set>
#include <vector>
+#include <android-base/thread_annotations.h>
+#include <ui/Fence.h>
+#include <ui/GraphicTypes.h>
+#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
+
#include "DisplayIdentification.h"
-
-extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
- const struct timespec *request,
- struct timespec *remain);
-
-struct framebuffer_device_t;
-
-namespace HWC2 {
- class Device;
- class Display;
-}
+#include "HWC2.h"
namespace android {
-// ---------------------------------------------------------------------------
-class DisplayDevice;
-class Fence;
-class FloatRect;
class GraphicBuffer;
-class NativeHandle;
-class Region;
class String8;
class TestableSurfaceFlinger;
struct CompositionInfo;
@@ -71,7 +48,7 @@
class HWComposer
{
public:
- explicit HWComposer(std::unique_ptr<android::Hwc2::Composer> composer);
+ explicit HWComposer(std::unique_ptr<Hwc2::Composer> composer);
~HWComposer();
@@ -177,7 +154,7 @@
// for debugging ----------------------------------------------------------
void dump(String8& out) const;
- android::Hwc2::Composer* getComposer() const { return mHwcDevice->getComposer(); }
+ Hwc2::Composer* getComposer() const { return mHwcDevice->getComposer(); }
// TODO(b/74619554): Remove special cases for internal/external display.
std::optional<hwc2_display_t> getInternalHwcDisplayId() const { return mInternalHwcDisplayId; }
@@ -194,8 +171,6 @@
static void validateChange(HWC2::Composition from, HWC2::Composition to);
- struct cb_context;
-
struct DisplayData {
bool isVirtual = false;
bool hasClientComposition = false;
@@ -209,11 +184,16 @@
mutable std::unordered_map<int32_t,
std::shared_ptr<const HWC2::Display::Config>> configMap;
- // protected by mVsyncLock
- HWC2::Vsync vsyncEnabled = HWC2::Vsync::Disable;
-
bool validateWasSkipped;
HWC2::Error presentError;
+
+ bool vsyncTraceToggle = false;
+
+ std::mutex vsyncEnabledLock;
+ HWC2::Vsync vsyncEnabled GUARDED_BY(vsyncEnabledLock) = HWC2::Vsync::Disable;
+
+ mutable std::mutex lastHwVsyncLock;
+ nsecs_t lastHwVsync GUARDED_BY(lastHwVsyncLock) = 0;
};
std::unordered_map<DisplayId, DisplayData> mDisplayData;
@@ -227,25 +207,11 @@
std::optional<hwc2_display_t> mExternalHwcDisplayId;
bool mHasMultiDisplaySupport = false;
- // protect mDisplayData from races between prepare and dump
- mutable Mutex mDisplayLock;
-
- cb_context* mCBContext = nullptr;
- std::unordered_map<DisplayId, size_t> mVSyncCounts;
-
std::unordered_set<DisplayId> mFreeVirtualDisplayIds;
uint32_t mNextVirtualDisplayId = 0;
uint32_t mRemainingHwcVirtualDisplays{mHwcDevice->getMaxVirtualDisplayCount()};
-
- // protected by mLock
- mutable Mutex mLock;
- mutable std::unordered_map<DisplayId, nsecs_t> mLastHwVSync;
-
- // thread-safe
- mutable Mutex mVsyncLock;
};
-// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1e910ce..3b444f7 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -367,27 +367,24 @@
// layerstack space, and convert-back to layer space.
// if there are no window scaling involved, this operation will map to full
// pixels in the buffer.
- // FIXME: the 3 lines below can produce slightly incorrect clipping when we have
- // a viewport clipping and a window transform. we should use floating point to fix this.
- Rect activeCrop(getActiveWidth(s), getActiveHeight(s));
- Rect crop = getCrop(s);
- if (!crop.isEmpty()) {
- activeCrop.intersect(crop, &activeCrop);
- }
-
+ FloatRect activeCropFloat = computeBounds();
ui::Transform t = getTransform();
- activeCrop = t.transform(activeCrop);
- if (!activeCrop.intersect(display->getViewport(), &activeCrop)) {
+ // Transform to screen space.
+ activeCropFloat = t.transform(activeCropFloat);
+ activeCropFloat = activeCropFloat.intersect(display->getViewport().toFloatRect());
+ // Back to layer space to work with the content crop.
+ activeCropFloat = t.inverse().transform(activeCropFloat);
+ // This needs to be here as transform.transform(Rect) computes the
+ // transformed rect and then takes the bounding box of the result before
+ // returning. This means
+ // transform.inverse().transform(transform.transform(Rect)) != Rect
+ // in which case we need to make sure the final rect is clipped to the
+ // display bounds.
+ Rect activeCrop{activeCropFloat};
+ if (!activeCrop.intersect(getBufferSize(s), &activeCrop)) {
activeCrop.clear();
}
-
- const auto& p = mDrawingParent.promote();
- if (p != nullptr) {
- auto parentCrop = p->computeInitialCrop(display);
- activeCrop.intersect(parentCrop, &activeCrop);
- }
-
return activeCrop;
}
@@ -399,24 +396,8 @@
// In addition there is a WM-specified crop we pull from our drawing state.
const State& s(getDrawingState());
- // Screen space to make reduction to parent crop clearer.
Rect activeCrop = computeInitialCrop(display);
- ui::Transform t = getTransform();
- // Back to layer space to work with the content crop.
- activeCrop = t.inverse().transform(activeCrop);
-
- // This needs to be here as transform.transform(Rect) computes the
- // transformed rect and then takes the bounding box of the result before
- // returning. This means
- // transform.inverse().transform(transform.transform(Rect)) != Rect
- // in which case we need to make sure the final rect is clipped to the
- // display bounds.
- if (!activeCrop.intersect(Rect(getActiveWidth(s), getActiveHeight(s)), &activeCrop)) {
- activeCrop.clear();
- }
-
- // subtract the transparent region and snap to the bounds
- activeCrop = reduce(activeCrop, getActiveTransparentRegion(s));
+ Rect bufferSize = getBufferSize(s);
// Transform the window crop to match the buffer coordinate system,
// which means using the inverse of the current transform set on the
@@ -437,8 +418,8 @@
ui::Transform(invTransform)).getOrientation();
}
- int winWidth = getActiveWidth(s);
- int winHeight = getActiveHeight(s);
+ int winWidth = bufferSize.getWidth();
+ int winHeight = bufferSize.getHeight();
if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
// If the activeCrop has been rotate the ends are rotated but not
// the space itself so when transforming ends back we can't rely on
@@ -450,10 +431,10 @@
if (is_h_flipped == is_v_flipped) {
invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H;
}
- winWidth = getActiveHeight(s);
- winHeight = getActiveWidth(s);
+ std::swap(winWidth, winHeight);
}
- const Rect winCrop = activeCrop.transform(invTransform, getActiveWidth(s), getActiveHeight(s));
+ const Rect winCrop =
+ activeCrop.transform(invTransform, bufferSize.getWidth(), bufferSize.getHeight());
// below, crop is intersected with winCrop expressed in crop's coordinate space
float xScale = crop.getWidth() / float(winWidth);
@@ -489,6 +470,8 @@
// this gives us only the "orientation" component of the transform
const State& s(getDrawingState());
+ const int bufferWidth = getBufferSize(s).getWidth();
+ const int bufferHeight = getBufferSize(s).getHeight();
auto blendMode = HWC2::BlendMode::None;
if (!isOpaque(s) || getAlpha() != 1.0f) {
blendMode =
@@ -519,16 +502,15 @@
// transform.inverse().transform(transform.transform(Rect)) != Rect
// in which case we need to make sure the final rect is clipped to the
// display bounds.
- if (!activeCrop.intersect(Rect(getActiveWidth(s), getActiveHeight(s)), &activeCrop)) {
+ if (!activeCrop.intersect(Rect(bufferWidth, bufferHeight), &activeCrop)) {
activeCrop.clear();
}
// mark regions outside the crop as transparent
- activeTransparentRegion.orSelf(Rect(0, 0, getActiveWidth(s), activeCrop.top));
- activeTransparentRegion.orSelf(
- Rect(0, activeCrop.bottom, getActiveWidth(s), getActiveHeight(s)));
+ activeTransparentRegion.orSelf(Rect(0, 0, bufferWidth, activeCrop.top));
+ activeTransparentRegion.orSelf(Rect(0, activeCrop.bottom, bufferWidth, bufferHeight));
activeTransparentRegion.orSelf(Rect(0, activeCrop.top, activeCrop.left, activeCrop.bottom));
activeTransparentRegion.orSelf(
- Rect(activeCrop.right, activeCrop.top, getActiveWidth(s), activeCrop.bottom));
+ Rect(activeCrop.right, activeCrop.top, bufferWidth, activeCrop.bottom));
}
// computeBounds returns a FloatRect to provide more accuracy during the
@@ -664,11 +646,7 @@
// Apply the layer's transform, followed by the display's global transform
// Here we're guaranteed that the layer's transform preserves rects
- Rect win(getActiveWidth(s), getActiveHeight(s));
- Rect crop = getCrop(s);
- if (!crop.isEmpty()) {
- win.intersect(crop, &win);
- }
+ Rect win = getCroppedBufferSize(s);
// Subtract the transparent region and snap to the bounds
Rect bounds = reduce(win, getActiveTransparentRegion(s));
Rect frame(getTransform().transform(bounds));
@@ -1021,6 +999,10 @@
uint32_t Layer::doTransaction(uint32_t flags) {
ATRACE_CALL();
+ if (mLayerDetached) {
+ return 0;
+ }
+
pushPendingState();
State c = getCurrentState();
if (!applyPendingStates(&c)) {
@@ -1053,6 +1035,11 @@
clearSyncPoints();
}
+ if (mCurrentState.inputInfoChanged) {
+ flags |= eInputInfoChanged;
+ mCurrentState.inputInfoChanged = false;
+ }
+
// Commit the transaction
commitTransaction(c);
mCurrentState.callbackHandles = {};
@@ -1553,6 +1540,9 @@
return false;
}
+ if (attachChildren()) {
+ setTransactionFlags(eTransactionNeeded);
+ }
for (const sp<Layer>& child : mCurrentChildren) {
newParent->addChild(child);
@@ -1597,6 +1587,13 @@
client->updateParent(newParent);
}
+ if (mLayerDetached) {
+ mLayerDetached = false;
+ setTransactionFlags(eTransactionNeeded);
+ }
+ if (attachChildren()) {
+ setTransactionFlags(eTransactionNeeded);
+ }
return true;
}
@@ -1605,7 +1602,7 @@
sp<Client> parentClient = mClientRef.promote();
sp<Client> client(child->mClientRef.promote());
if (client != nullptr && parentClient != client) {
- client->detachLayer(child.get());
+ child->mLayerDetached = true;
child->detachChildren();
}
}
@@ -1613,6 +1610,23 @@
return true;
}
+bool Layer::attachChildren() {
+ bool changed = false;
+ for (const sp<Layer>& child : mCurrentChildren) {
+ sp<Client> parentClient = mClientRef.promote();
+ sp<Client> client(child->mClientRef.promote());
+ if (client != nullptr && parentClient != client) {
+ if (child->mLayerDetached) {
+ child->mLayerDetached = false;
+ changed = true;
+ }
+ changed |= child->attachChildren();
+ }
+ }
+
+ return changed;
+}
+
bool Layer::setColorTransform(const mat4& matrix) {
static const mat4 identityMatrix = mat4();
@@ -1897,6 +1911,13 @@
mDrawingParent = mCurrentParent;
}
+void Layer::setInputInfo(const InputWindowInfo& info) {
+ mCurrentState.inputInfo = info;
+ mCurrentState.modified = true;
+ mCurrentState.inputInfoChanged = true;
+ setTransactionFlags(eTransactionNeeded);
+}
+
void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet) {
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
@@ -2024,6 +2045,30 @@
return mRemovedFromCurrentState;
}
+InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) {
+ InputWindowInfo info = mDrawingState.inputInfo;
+ info.frameLeft = screenBounds.left + info.surfaceInset;
+ info.frameTop = screenBounds.top + info.surfaceInset;
+ info.frameRight = screenBounds.right - info.surfaceInset;
+ info.frameBottom = screenBounds.bottom - info.surfaceInset;
+
+ ui::Transform t = getTransform();
+ info.windowXScale *= 1.0f / t.sx();
+ info.windowYScale *= 1.0f / t.sy();
+
+ info.touchableRegion.scaleSelf(t.sx(), t.sy());
+
+ info.touchableRegion = info.touchableRegion.translate(
+ screenBounds.left,
+ screenBounds.top);
+ info.visible = isVisible();
+ return info;
+}
+
+bool Layer::hasInput() const {
+ return mDrawingState.inputInfo.token != nullptr;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 40ebe1e..00a6bbe 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -22,6 +22,7 @@
#include <gui/BufferQueue.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
+#include <input/InputWindow.h>
#include <layerproto/LayerProtoHeader.h>
#include <math/vec4.h>
#include <renderengine/Mesh.h>
@@ -109,6 +110,7 @@
enum { // flags for doTransaction()
eDontUpdateGeometryState = 0x00000001,
eVisibleRegion = 0x00000002,
+ eInputInfoChanged = 0x00000004
};
struct Geometry {
@@ -166,6 +168,9 @@
half4 color;
+ bool inputInfoChanged;
+ InputWindowInfo inputInfo;
+
// The fields below this point are only used by BufferStateLayer
Geometry active;
@@ -263,6 +268,8 @@
virtual void setChildrenDrawingParent(const sp<Layer>& layer);
virtual bool reparent(const sp<IBinder>& newParentHandle);
virtual bool detachChildren();
+ bool attachChildren();
+ bool isLayerDetached() const { return mLayerDetached; }
virtual bool setColorTransform(const mat4& matrix);
virtual const mat4& getColorTransform() const;
virtual bool hasColorTransform() const;
@@ -355,7 +362,6 @@
// to avoid grabbing the lock again to avoid deadlock
virtual bool isCreatedFromMainThread() const { return false; }
-
bool isRemovedFromCurrentState() const;
void writeToProto(LayerProto* layerInfo,
@@ -590,6 +596,12 @@
int32_t getZ() const;
virtual void pushPendingState();
+ /**
+ * Returns active buffer size in the correct orientation. Buffer size is determined by undoing
+ * any buffer transformations. If the layer has no buffer then return INVALID_RECT.
+ */
+ virtual Rect getBufferSize(const Layer::State&) const { return Rect::INVALID_RECT; }
+
protected:
// constant
sp<SurfaceFlinger> mFlinger;
@@ -707,6 +719,10 @@
bool getPremultipledAlpha() const;
bool mPendingHWCDestroy{false};
+ void setInputInfo(const InputWindowInfo& info);
+
+ InputWindowInfo fillInputInfo(const Rect& screenBounds);
+ bool hasInput() const;
protected:
// -----------------------------------------------------------------------
@@ -776,6 +792,9 @@
mutable LayerBE mBE;
+ // Can only be accessed with the SF state lock held.
+ bool mLayerDetached{false};
+
private:
/**
* Returns an unsorted vector of all layers that are part of this tree.
@@ -806,12 +825,6 @@
* bounds are constrained by its parent bounds.
*/
Rect getCroppedBufferSize(const Layer::State& s) const;
-
- /**
- * Returns active buffer size in the correct orientation. Buffer size is determined by undoing
- * any buffer transformations. If the layer has no buffer then return INVALID_RECT.
- */
- virtual Rect getBufferSize(const Layer::State&) const { return Rect::INVALID_RECT; }
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index e944eb9..1f47949 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -39,11 +39,15 @@
void LayerHistory::incrementCounter() {
mCounter++;
mCounter = mCounter % ARRAY_SIZE;
+ // Clear all the previous data from the history. This is a ring buffer, so we are
+ // reusing memory.
mElements[mCounter].clear();
}
const std::unordered_map<std::string, nsecs_t>& LayerHistory::get(size_t index) const {
- return mElements.at(index);
+ // For the purposes of the layer history, the index = 0 always needs to start at the
+ // current counter, and then decrement to access the layers in correct historical order.
+ return mElements.at((ARRAY_SIZE + (mCounter - (index % ARRAY_SIZE))) % ARRAY_SIZE);
}
} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 1a7f9cd..76c1352 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -42,14 +42,17 @@
~LayerHistory();
// Method for inserting layers and their requested present time into the ring buffer.
- // The elements are going to be inserted into an unordered_map at the position of
- // mCounter.
+ // The elements are going to be inserted into an unordered_map at the position 'now'.
void insert(const std::string layerName, nsecs_t presentTime);
// Method for incrementing the current slot in the ring buffer. It also clears the
// unordered_map, if it was created previously.
void incrementCounter();
- // Returns unordered_map at the given at index.
+ // Returns unordered_map at the given at index. The index is decremented from 'now'. For
+ // example, 0 is now, 1 is previous frame.
const std::unordered_map<std::string, nsecs_t>& get(size_t index) const;
+ // Returns the total size of the ring buffer. The value is always the same regardless
+ // of how many slots we filled in.
+ static constexpr size_t getSize() { return ARRAY_SIZE; }
private:
size_t mCounter = 0;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 4286cc9..4d3ae33 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -30,6 +30,7 @@
#include <gui/ISurfaceComposer.h>
#include <ui/DisplayStatInfo.h>
+#include <utils/Timers.h>
#include <utils/Trace.h>
#include "DispSync.h"
@@ -205,15 +206,95 @@
mHWVsyncAvailable = makeAvailable;
}
-void Scheduler::addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp) {
+void Scheduler::addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp,
+ const std::string layerName) {
+ // This is V1 logic. It calculates the average FPS based on the timestamp frequency
+ // regardless of which layer the timestamp came from.
+ // For now, the averages and FPS are recorded in the systrace.
+ determineTimestampAverage(isAutoTimestamp, framePresentTime);
+
+ // This is V2 logic. It calculates the average and median timestamp difference based on the
+ // individual layer history. The results are recorded in the systrace.
+ determineLayerTimestampStats(layerName, framePresentTime);
+}
+
+void Scheduler::incrementFrameCounter() {
+ mLayerHistory.incrementCounter();
+}
+
+nsecs_t Scheduler::calculateAverage() const {
+ nsecs_t sum = std::accumulate(mTimeDifferences.begin(), mTimeDifferences.end(), 0);
+ return (sum / ARRAY_SIZE);
+}
+
+void Scheduler::updateFrameSkipping(const int64_t skipCount) {
+ ATRACE_INT("FrameSkipCount", skipCount);
+ if (mSkipCount != skipCount) {
+ // Only update DispSync if it hasn't been updated yet.
+ mPrimaryDispSync->setRefreshSkipCount(skipCount);
+ mSkipCount = skipCount;
+ }
+}
+
+void Scheduler::determineLayerTimestampStats(const std::string layerName,
+ const nsecs_t framePresentTime) {
+ mLayerHistory.insert(layerName, framePresentTime);
+ std::vector<int64_t> differencesMs;
+
+ // Traverse through the layer history, and determine the differences in present times.
+ nsecs_t newestPresentTime = framePresentTime;
+ for (int i = 1; i < mLayerHistory.getSize(); i++) {
+ std::unordered_map<std::string, nsecs_t> layers = mLayerHistory.get(i);
+ for (auto layer : layers) {
+ if (layer.first != layerName) {
+ continue;
+ }
+ int64_t differenceMs = (newestPresentTime - layer.second) / 1000000;
+ ALOGD("%d Layer %s: %" PRId64, i, layerName.c_str(), differenceMs);
+ // Dismiss noise.
+ if (differenceMs > 10 && differenceMs < 60) {
+ differencesMs.push_back(differenceMs);
+ }
+ newestPresentTime = layer.second;
+ }
+ }
+ // Average is a good indicator for when 24fps videos are playing, because the frames come in
+ // 33, and 49 ms intervals with occasional 41ms.
+ int64_t average =
+ std::accumulate(differencesMs.begin(), differencesMs.end(), 0) / differencesMs.size();
+ const auto tag = "TimestampAvg_" + layerName;
+ ATRACE_INT(tag.c_str(), average);
+
+ // Mode and median are good indicators for 30 and 60 fps videos, because the majority of frames
+ // come in 16, or 33 ms intervals.
+ // TODO(b/113612090): Calculate mode. Median is good for now, since we want a given interval to
+ // repeat at least ARRAY_SIZE/2 + 1 times.
+ if (differencesMs.size() > 0) {
+ const auto tagMedian = "TimestampMedian_" + layerName;
+ ATRACE_INT(tagMedian.c_str(), calculateMedian(&differencesMs));
+ }
+}
+
+int64_t Scheduler::calculateMedian(std::vector<int64_t>* v) {
+ if (!v || v->size() == 0) {
+ return 0;
+ }
+
+ size_t n = v->size() / 2;
+ nth_element(v->begin(), v->begin() + n, v->end());
+ return v->at(n);
+}
+
+void Scheduler::determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime) {
ATRACE_INT("AutoTimestamp", isAutoTimestamp);
+
// Video does not have timestamp automatically set, so we discard timestamps that are
// coming in from other sources for now.
if (isAutoTimestamp) {
return;
}
- int64_t differenceMs = (newFrameTimestamp - mPreviousFrameTimestamp) / 1000000;
- mPreviousFrameTimestamp = newFrameTimestamp;
+ int64_t differenceMs = (framePresentTime - mPreviousFrameTimestamp) / 1000000;
+ mPreviousFrameTimestamp = framePresentTime;
if (differenceMs < 10 || differenceMs > 100) {
// Dismiss noise.
@@ -240,18 +321,4 @@
updateFrameSkipping(0);
}
-nsecs_t Scheduler::calculateAverage() const {
- nsecs_t sum = std::accumulate(mTimeDifferences.begin(), mTimeDifferences.end(), 0);
- return (sum / ARRAY_SIZE);
-}
-
-void Scheduler::updateFrameSkipping(const int64_t skipCount) {
- ATRACE_INT("FrameSkipCount", skipCount);
- if (mSkipCount != skipCount) {
- // Only update DispSync if it hasn't been updated yet.
- mPrimaryDispSync->setRefreshSkipCount(skipCount);
- mSkipCount = skipCount;
- }
-}
-
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index dd1f24b..adfc071 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -26,6 +26,7 @@
#include "EventControlThread.h"
#include "EventThread.h"
#include "InjectVSyncSource.h"
+#include "LayerHistory.h"
namespace android {
@@ -103,9 +104,15 @@
void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
void setIgnorePresentFences(bool ignore);
void makeHWSyncAvailable(bool makeAvailable);
- void addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp);
+ // Adds the present time for given layer to the history of present times.
+ void addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp,
+ const std::string layerName);
+ // Increments counter in the layer history to indicate that SF has started a new frame.
+ void incrementFrameCounter();
protected:
+ friend class SchedulerTest;
+
virtual std::unique_ptr<EventThread> makeEventThread(
const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
@@ -114,6 +121,15 @@
private:
nsecs_t calculateAverage() const;
void updateFrameSkipping(const int64_t skipCount);
+ // Collects the statistical mean (average) and median between timestamp
+ // intervals for each frame for each layer.
+ void determineLayerTimestampStats(const std::string layerName, const nsecs_t framePresentTime);
+ // Calculates the statistical median in the vector. Return 0 if the vector is empty. The
+ // function modifies the vector contents.
+ int64_t calculateMedian(std::vector<int64_t>* v);
+ // Collects the average difference between timestamps for each frame regardless
+ // of which layer the timestamp came from.
+ void determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime);
// TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it
// should make request to Scheduler to compute next refresh.
@@ -150,6 +166,8 @@
static constexpr size_t ARRAY_SIZE = 30;
std::array<int64_t, ARRAY_SIZE> mTimeDifferences;
size_t mCounter = 0;
+
+ LayerHistory mLayerHistory;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7150660..06c5094 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -37,6 +37,8 @@
#include <dvr/vr_flinger.h>
+#include <input/IInputFlinger.h>
+
#include <ui/ColorSpace.h>
#include <ui/DebugUtils.h>
#include <ui/DisplayInfo.h>
@@ -554,6 +556,13 @@
if (window != 0) {
window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
}
+ sp<IBinder> input(defaultServiceManager()->getService(
+ String16("inputflinger")));
+ if (input == nullptr) {
+ ALOGE("Failed to link to input service");
+ } else {
+ mInputFlinger = interface_cast<IInputFlinger>(input);
+ }
if (mVrFlinger) {
mVrFlinger->OnBootFinished();
@@ -1489,6 +1498,10 @@
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
+ if (mUseScheduler) {
+ // This call is made each time SF wakes up and creates a new frame.
+ mScheduler->incrementFrameCounter();
+ }
bool frameMissed = !mHadClientComposition &&
mPreviousPresentFence != Fence::NO_FENCE &&
(mPreviousPresentFence->getSignalTime() ==
@@ -1679,8 +1692,6 @@
mDrawingState.colorMatrixChanged = false;
for (const auto& [token, display] : mDisplays) {
- getBE().mCompositionInfo[token].clear();
-
for (auto& layer : display->getVisibleLayersSortedByZ()) {
const auto displayId = display->getId();
layer->getBE().compositionInfo.compositionType = layer->getCompositionType(displayId);
@@ -1964,6 +1975,17 @@
ATRACE_CALL();
ALOGV("rebuildLayerStacks");
+ // We need to clear these out now as these may be holding on to a
+ // HWC2::Layer reference at the same time as the LayerBE::HWCInfo structure
+ // also holds a reference. When the set of visible layers is recomputed,
+ // some layers may be destroyed if the only thing keeping them alive was
+ // that list of visible layers associated with each display. The layer
+ // destruction code asserts that the HWC2::Layer is properly destroyed, but
+ // that doesn't happen if SurfaceFlingerBE::mCompositionInfo keeps it alive.
+ for (const auto& [token, display] : mDisplays) {
+ getBE().mCompositionInfo[token].clear();
+ }
+
// rebuild the visible layer list per screen
if (CC_UNLIKELY(mVisibleRegionsDirty)) {
ATRACE_NAME("rebuildLayerStacks VR Dirty");
@@ -2337,14 +2359,6 @@
auto nativeWindow = nativeWindowSurface->getNativeWindow();
creationArgs.nativeWindow = nativeWindow;
- /*
- * Create our display's surface
- */
- std::unique_ptr<renderengine::Surface> renderSurface = getRenderEngine().createSurface();
- renderSurface->setCritical(isInternalDisplay);
- renderSurface->setAsync(state.isVirtual());
- creationArgs.renderSurface = std::move(renderSurface);
-
// Make sure that composition can never be stalled by a virtual display
// consumer that isn't processing buffers fast enough. We have to do this
// here, in case the display is composed entirely by HWC.
@@ -2568,6 +2582,7 @@
* (perform the transaction for each of them if needed)
*/
+ bool inputChanged = false;
if (transactionFlags & eTraversalNeeded) {
mCurrentState.traverseInZOrder([&](Layer* layer) {
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
@@ -2576,6 +2591,10 @@
const uint32_t flags = layer->doTransaction(0);
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
+
+ if (flags & Layer::eInputInfoChanged) {
+ inputChanged = true;
+ }
});
}
@@ -2685,9 +2704,26 @@
commitTransaction();
+ if ((inputChanged || mVisibleRegionsDirty) && mInputFlinger) {
+ updateInputWindows();
+ }
+
updateCursorAsync();
}
+void SurfaceFlinger::updateInputWindows() {
+ ATRACE_CALL();
+
+ Vector<InputWindowInfo> inputHandles;
+
+ mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
+ if (layer->hasInput()) {
+ inputHandles.add(layer->fillInputInfo(layer->computeScreenBounds()));
+ }
+ });
+ mInputFlinger->setInputWindows(inputHandles);
+}
+
void SurfaceFlinger::updateCursorAsync()
{
for (const auto& [token, display] : mDisplays) {
@@ -2795,6 +2831,7 @@
if (CC_LIKELY(layer->isVisible())) {
const bool translucent = !layer->isOpaque(s);
Rect bounds(layer->computeScreenBounds());
+
visibleRegion.set(bounds);
ui::Transform tr = layer->getTransform();
if (!visibleRegion.isEmpty()) {
@@ -3198,6 +3235,10 @@
}
status_t SurfaceFlinger::removeLayerLocked(const Mutex& lock, const sp<Layer>& layer) {
+ if (layer->isLayerDetached()) {
+ return NO_ERROR;
+ }
+
const auto& p = layer->getParent();
ssize_t index;
if (p != nullptr) {
@@ -3606,7 +3647,10 @@
if (what & layer_state_t::eSidebandStreamChanged) {
if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
}
-
+ if (what & layer_state_t::eInputInfoChanged) {
+ layer->setInputInfo(s.inputInfo);
+ flags |= eTraversalNeeded;
+ }
std::vector<sp<CallbackHandle>> callbackHandles;
if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
mTransactionCompletedThread.run();
@@ -3663,11 +3707,24 @@
result = createBufferStateLayer(client, uniqueName, w, h, flags, handle, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceColor:
+ // check if buffer size is set for color layer.
+ if (w > 0 || h > 0) {
+ ALOGE("createLayer() failed, w or h cannot be set for color layer (w=%d, h=%d)",
+ int(w), int(h));
+ return BAD_VALUE;
+ }
+
result = createColorLayer(client,
uniqueName, w, h, flags,
handle, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceContainer:
+ // check if buffer size is set for container layer.
+ if (w > 0 || h > 0) {
+ ALOGE("createLayer() failed, w or h cannot be set for container layer (w=%d, h=%d)",
+ int(w), int(h));
+ return BAD_VALUE;
+ }
result = createContainerLayer(client,
uniqueName, w, h, flags,
handle, &layer);
@@ -5117,12 +5174,14 @@
const ui::Transform& getTransform() const override { return mTransform; }
Rect getBounds() const override {
const Layer::State& layerState(mLayer->getDrawingState());
- return Rect(mLayer->getActiveWidth(layerState), mLayer->getActiveHeight(layerState));
+ return mLayer->getBufferSize(layerState);
}
int getHeight() const override {
- return mLayer->getActiveHeight(mLayer->getDrawingState());
+ return mLayer->getBufferSize(mLayer->getDrawingState()).getHeight();
}
- int getWidth() const override { return mLayer->getActiveWidth(mLayer->getDrawingState()); }
+ int getWidth() const override {
+ return mLayer->getBufferSize(mLayer->getDrawingState()).getWidth();
+ }
bool isSecure() const override { return false; }
bool needsFiltering() const override { return mNeedsFiltering; }
Rect getSourceCrop() const override {
@@ -5196,12 +5255,12 @@
Rect crop(sourceCrop);
if (sourceCrop.width() <= 0) {
crop.left = 0;
- crop.right = parent->getActiveWidth(parent->getCurrentState());
+ crop.right = parent->getBufferSize(parent->getCurrentState()).getWidth();
}
if (sourceCrop.height() <= 0) {
crop.top = 0;
- crop.bottom = parent->getActiveHeight(parent->getCurrentState());
+ crop.bottom = parent->getBufferSize(parent->getCurrentState()).getHeight();
}
int32_t reqWidth = crop.width() * frameScale;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f98dddf..4a14de7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -98,6 +98,7 @@
class EventThread;
class IGraphicBufferConsumer;
class IGraphicBufferProducer;
+class IInputFlinger;
class InjectVSyncSource;
class Layer;
class Surface;
@@ -531,6 +532,7 @@
void handleTransaction(uint32_t transactionFlags);
void handleTransactionLocked(uint32_t transactionFlags);
+ void updateInputWindows();
void updateCursorAsync();
/* handlePageFlip - latch a new buffer if available and compute the dirty
@@ -986,6 +988,8 @@
std::unique_ptr<Scheduler> mScheduler;
sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
+
+ sp<IInputFlinger> mInputFlinger;
};
}; // namespace android
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 599ff5c..75ce4be 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -13,8 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include "timestatsproto/TimeStatsHelper.h"
+
#include <android-base/stringprintf.h>
-#include <timestatsproto/TimeStatsHelper.h>
+#include <inttypes.h>
#include <array>
@@ -46,6 +48,14 @@
hist[*iter]++;
}
+int64_t TimeStatsHelper::Histogram::totalTime() const {
+ int64_t ret = 0;
+ for (const auto& ele : hist) {
+ ret += ele.first * ele.second;
+ }
+ return ret;
+}
+
float TimeStatsHelper::Histogram::averageTime() const {
int64_t ret = 0;
int64_t count = 0;
@@ -87,12 +97,13 @@
std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional<uint32_t> maxLayers) const {
std::string result = "SurfaceFlinger TimeStats:\n";
- StringAppendF(&result, "statsStart = %lld\n", static_cast<long long int>(statsStart));
- StringAppendF(&result, "statsEnd = %lld\n", static_cast<long long int>(statsEnd));
+ StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStart);
+ StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEnd);
StringAppendF(&result, "totalFrames = %d\n", totalFrames);
StringAppendF(&result, "missedFrames = %d\n", missedFrames);
StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
- StringAppendF(&result, "displayOnTime = %lld ms\n", static_cast<long long int>(displayOnTime));
+ StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
+ StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
StringAppendF(&result, "presentToPresent histogram is as below:\n");
result.append(presentToPresent.toString());
const auto dumpStats = generateDumpStats(maxLayers);
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 7d0fe79..5f40a1a 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -34,6 +34,7 @@
std::unordered_map<int32_t, int32_t> hist;
void insert(int32_t delta);
+ int64_t totalTime() const;
float averageTime() const;
std::string toString() const;
};
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index 9b9dc57..389118a 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -30,6 +30,8 @@
namespace android {
TransactionCompletedThread::~TransactionCompletedThread() {
+ std::lock_guard lockThread(mThreadMutex);
+
{
std::lock_guard lock(mMutex);
mKeepRunning = false;
@@ -50,11 +52,13 @@
void TransactionCompletedThread::run() {
std::lock_guard lock(mMutex);
- if (mRunning) {
+ if (mRunning || !mKeepRunning) {
return;
}
mDeathRecipient = new ThreadDeathRecipient();
mRunning = true;
+
+ std::lock_guard lockThread(mThreadMutex);
mThread = std::thread(&TransactionCompletedThread::threadMain, this);
}
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index 5af4097..1612f69 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -90,7 +90,10 @@
}
};
- std::thread mThread;
+ // Protects the creation and destruction of mThread
+ std::mutex mThreadMutex;
+
+ std::thread mThread GUARDED_BY(mThreadMutex);
std::mutex mMutex;
std::condition_variable_any mConditionVariable;
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 988454a..7e95d99 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -334,16 +334,10 @@
virtual sp<SurfaceControl> createLayer(const sp<SurfaceComposerClient>& client,
const char* name, uint32_t width, uint32_t height,
uint32_t flags = 0) {
- auto layer =
- client->createSurface(String8(name), width, height, PIXEL_FORMAT_RGBA_8888, flags);
- EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
+ auto layer = createSurface(client, name, width, height, PIXEL_FORMAT_RGBA_8888, flags);
Transaction t;
t.setLayerStack(layer, mDisplayLayerStack).setLayer(layer, mLayerZBase);
- // If we are creating a color layer, set its crop since its size will be ignored.
- if (flags == ISurfaceComposerClient::eFXSurfaceColor) {
- t.setCrop_legacy(layer, Rect(0, 0, width, height));
- }
status_t error = t.apply();
if (error != NO_ERROR) {
@@ -354,6 +348,15 @@
return layer;
}
+ virtual sp<SurfaceControl> createSurface(const sp<SurfaceComposerClient>& client,
+ const char* name, uint32_t width, uint32_t height,
+ PixelFormat format, uint32_t flags,
+ SurfaceControl* parent = nullptr) {
+ auto layer = client->createSurface(String8(name), width, height, format, flags, parent);
+ EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
+ return layer;
+ }
+
virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
uint32_t flags = 0) {
return createLayer(mClient, name, width, height, flags);
@@ -509,9 +512,9 @@
mDisplayLayerStack = 0;
- mBlackBgSurface = mClient->createSurface(String8("BaseSurface"), mDisplayWidth,
- mDisplayHeight, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor);
+ mBlackBgSurface =
+ createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */,
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
// set layer stack (b/68888219)
Transaction t;
@@ -834,8 +837,9 @@
TEST_P(LayerTypeTransactionTest, SetZNegative) {
sp<SurfaceControl> parent =
- LayerTransactionTest::createLayer("Parent", mDisplayWidth, mDisplayHeight,
+ LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
ISurfaceComposerClient::eFXSurfaceContainer);
+ Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
@@ -892,8 +896,9 @@
TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) {
sp<SurfaceControl> parent =
- LayerTransactionTest::createLayer("Parent", mDisplayWidth, mDisplayHeight,
+ LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
ISurfaceComposerClient::eFXSurfaceContainer);
+ Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
sp<SurfaceControl> layerB;
@@ -1225,10 +1230,15 @@
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(
- colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor));
- Transaction().setLayer(colorLayer, mLayerZBase + 1).apply();
+ Transaction()
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setLayer(colorLayer, mLayerZBase + 1)
+ .apply();
+
{
SCOPED_TRACE("default color");
screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
@@ -1248,10 +1258,14 @@
TEST_F(LayerTransactionTest, SetColorClamped) {
sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(
- colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor));
+ Transaction()
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f))
+ .apply();
- Transaction().setColor(colorLayer, half3(2.0f, -1.0f, 0.0f)).apply();
screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
@@ -1260,8 +1274,10 @@
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(
- colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor));
+ Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
const float alpha = 0.25f;
@@ -1285,9 +1301,10 @@
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parentWithAlpha", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer(
- "childWithColor", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
-
+ ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */,
+ 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor));
+ Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
const float alpha = 0.25f;
const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
@@ -2129,10 +2146,13 @@
TEST_F(LayerTransactionTest, SetColorTransformBasic) {
sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(
- colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
-
- Transaction().setLayer(colorLayer, mLayerZBase + 1).apply();
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor));
+ Transaction()
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setLayer(colorLayer, mLayerZBase + 1)
+ .apply();
{
SCOPED_TRACE("default color");
screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
@@ -3024,11 +3044,10 @@
std::unique_ptr<ScreenCapture> sc;
sp<SurfaceControl> childNoBuffer =
- mClient->createSurface(String8("Bufferless child"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- sp<SurfaceControl> childBuffer =
- mClient->createSurface(String8("Buffered child"), 20, 20,
- PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
+ createSurface(mClient, "Bufferless child", 0 /* buffer width */, 0 /* buffer height */,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> childBuffer = createSurface(mClient, "Buffered child", 20, 20,
+ PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
fillSurfaceRGBA8(childBuffer, 200, 200, 200);
SurfaceComposerClient::Transaction{}
.setCrop_legacy(childNoBuffer, Rect(0, 0, 10, 10))
@@ -3078,8 +3097,8 @@
protected:
void SetUp() override {
LayerUpdateTest::SetUp();
- mChild = mClient->createSurface(String8("Child surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0,
+ mFGSurfaceControl.get());
fillSurfaceRGBA8(mChild, 200, 200, 200);
{
@@ -3254,8 +3273,7 @@
TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) {
sp<SurfaceControl> mGrandChild =
- mClient->createSurface(String8("Grand Child"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+ createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
{
@@ -3318,10 +3336,9 @@
TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
sp<SurfaceComposerClient> mNewComposerClient = new SurfaceComposerClient;
sp<SurfaceControl> mChildNewClient =
- mNewComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ createSurface(mNewComposerClient, "New Child Test Surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- ASSERT_TRUE(mChildNewClient != nullptr);
ASSERT_TRUE(mChildNewClient->isValid());
fillSurfaceRGBA8(mChildNewClient, 200, 200, 200);
@@ -3356,6 +3373,61 @@
}
}
+TEST_F(ChildLayerTest, DetachChildrenThenAttach) {
+ sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> childNewClient =
+ newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+ ASSERT_TRUE(childNewClient != nullptr);
+ ASSERT_TRUE(childNewClient->isValid());
+
+ fillSurfaceRGBA8(childNewClient, 200, 200, 200);
+
+ Transaction()
+ .hide(mChild)
+ .show(childNewClient)
+ .setPosition(childNewClient, 10, 10)
+ .setPosition(mFGSurfaceControl, 64, 64)
+ .apply();
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ Transaction().detachChildren(mFGSurfaceControl).apply();
+ Transaction().hide(childNewClient).apply();
+
+ // Nothing should have changed.
+ {
+ mCapture = screenshot();
+ mCapture->expectFGColor(64, 64);
+ mCapture->expectChildColor(74, 74);
+ mCapture->expectFGColor(84, 84);
+ }
+
+ sp<SurfaceControl> newParentSurface = createLayer(String8("New Parent Surface"), 32, 32, 0);
+ fillLayerColor(ISurfaceComposerClient::eFXSurfaceBufferQueue, newParentSurface, Color::RED, 32,
+ 32);
+ Transaction()
+ .setLayer(newParentSurface, INT32_MAX - 1)
+ .show(newParentSurface)
+ .setPosition(newParentSurface, 20, 20)
+ .reparent(childNewClient, newParentSurface->getHandle())
+ .apply();
+ {
+ mCapture = screenshot();
+ // Child is now hidden.
+ mCapture->expectColor(Rect(20, 20, 52, 52), Color::RED);
+ }
+}
+
TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
asTransaction([&](Transaction& t) {
t.show(mChild);
@@ -3427,9 +3499,8 @@
mChild.clear();
// Now recreate it as hidden
- mChild = mClient->createSurface(String8("Child surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eHidden,
- mFGSurfaceControl.get());
+ mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eHidden, mFGSurfaceControl.get());
// Show the child layer in a deferred transaction
asTransaction([&](Transaction& t) {
@@ -3545,9 +3616,8 @@
}
TEST_F(ChildLayerTest, NestedChildren) {
- sp<SurfaceControl> grandchild =
- mClient->createSurface(String8("Grandchild surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+ sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
fillSurfaceRGBA8(grandchild, 50, 50, 50);
{
@@ -3585,9 +3655,8 @@
// Verify setting a size on a buffer layer has no effect.
TEST_F(BoundlessLayerTest, BufferLayerIgnoresSize) {
sp<SurfaceControl> bufferLayer =
- mClient->createSurface(String8("BufferLayer"), 45, 45, PIXEL_FORMAT_RGBA_8888, 0,
- mFGSurfaceControl.get());
- ASSERT_TRUE(bufferLayer != nullptr);
+ createSurface(mClient, "BufferLayer", 45, 45, PIXEL_FORMAT_RGBA_8888, 0,
+ mFGSurfaceControl.get());
ASSERT_TRUE(bufferLayer->isValid());
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::BLACK, 30, 30));
asTransaction([&](Transaction& t) { t.show(bufferLayer); });
@@ -3606,10 +3675,8 @@
// which will crop the color layer.
TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) {
sp<SurfaceControl> colorLayer =
- mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor,
- mFGSurfaceControl.get());
- ASSERT_TRUE(colorLayer != nullptr);
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setColor(colorLayer, half3{0, 0, 0});
@@ -3629,15 +3696,12 @@
// Verify a boundless color layer will fill its parent bounds. The parent has no buffer but has
// a crop which will be used to crop the color layer.
TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) {
- sp<SurfaceControl> cropLayer =
- mClient->createSurface(String8("CropLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- 0 /* flags */, mFGSurfaceControl.get());
- ASSERT_TRUE(cropLayer != nullptr);
+ sp<SurfaceControl> cropLayer = createSurface(mClient, "CropLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, mFGSurfaceControl.get());
ASSERT_TRUE(cropLayer->isValid());
sp<SurfaceControl> colorLayer =
- mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get());
- ASSERT_TRUE(colorLayer != nullptr);
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10));
@@ -3661,10 +3725,8 @@
// Verify for boundless layer with no children, their transforms have no effect.
TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) {
sp<SurfaceControl> colorLayer =
- mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor,
- mFGSurfaceControl.get());
- ASSERT_TRUE(colorLayer != nullptr);
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setPosition(colorLayer, 320, 320);
@@ -3686,20 +3748,16 @@
// Verify for boundless layer with children, their transforms have an effect.
TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) {
sp<SurfaceControl> boundlessLayerRightShift =
- mClient->createSurface(String8("BoundlessLayerRightShift"), 0, 0,
- PIXEL_FORMAT_RGBA_8888, 0 /* flags */, mFGSurfaceControl.get());
- ASSERT_TRUE(boundlessLayerRightShift != nullptr);
+ createSurface(mClient, "BoundlessLayerRightShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, mFGSurfaceControl.get());
ASSERT_TRUE(boundlessLayerRightShift->isValid());
sp<SurfaceControl> boundlessLayerDownShift =
- mClient->createSurface(String8("BoundlessLayerLeftShift"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- 0 /* flags */, boundlessLayerRightShift.get());
- ASSERT_TRUE(boundlessLayerDownShift != nullptr);
+ createSurface(mClient, "BoundlessLayerLeftShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, boundlessLayerRightShift.get());
ASSERT_TRUE(boundlessLayerDownShift->isValid());
sp<SurfaceControl> colorLayer =
- mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor,
- boundlessLayerDownShift.get());
- ASSERT_TRUE(colorLayer != nullptr);
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, boundlessLayerDownShift.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setPosition(boundlessLayerRightShift, 32, 0);
@@ -3760,16 +3818,13 @@
// Verify for boundless root layers with children, their transforms have an effect.
TEST_F(BoundlessLayerTest, RootBoundlessLayerCanSetTransform) {
- sp<SurfaceControl> rootBoundlessLayer =
- mClient->createSurface(String8("RootBoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- 0 /* flags */);
- ASSERT_TRUE(rootBoundlessLayer != nullptr);
+ sp<SurfaceControl> rootBoundlessLayer = createSurface(mClient, "RootBoundlessLayer", 0, 0,
+ PIXEL_FORMAT_RGBA_8888, 0 /* flags */);
ASSERT_TRUE(rootBoundlessLayer->isValid());
sp<SurfaceControl> colorLayer =
- mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor,
- rootBoundlessLayer.get());
- ASSERT_TRUE(colorLayer != nullptr);
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, rootBoundlessLayer.get());
+
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setLayer(rootBoundlessLayer, INT32_MAX - 1);
@@ -3809,9 +3864,8 @@
TEST_F(ScreenCaptureTest, CaptureLayerWithChild) {
auto fgHandle = mFGSurfaceControl->getHandle();
- sp<SurfaceControl> child =
- mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
- 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
fillSurfaceRGBA8(child, 200, 200, 200);
SurfaceComposerClient::Transaction().show(child).apply(true);
@@ -3825,9 +3879,8 @@
TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) {
auto fgHandle = mFGSurfaceControl->getHandle();
- sp<SurfaceControl> child =
- mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
- 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
fillSurfaceRGBA8(child, 200, 200, 200);
SurfaceComposerClient::Transaction().show(child).apply(true);
@@ -3839,9 +3892,8 @@
}
TEST_F(ScreenCaptureTest, CaptureTransparent) {
- sp<SurfaceControl> child =
- mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
- 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
fillSurfaceRGBA8(child, 200, 200, 200);
@@ -3859,9 +3911,9 @@
TEST_F(ScreenCaptureTest, DontCaptureRelativeOutsideTree) {
auto fgHandle = mFGSurfaceControl->getHandle();
- sp<SurfaceControl> child =
- mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
- 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ ASSERT_NE(nullptr, child.get()) << "failed to create surface";
sp<SurfaceControl> relative = createLayer(String8("Relative surface"), 10, 10, 0);
fillSurfaceRGBA8(child, 200, 200, 200);
fillSurfaceRGBA8(relative, 100, 100, 100);
@@ -3882,12 +3934,10 @@
TEST_F(ScreenCaptureTest, CaptureRelativeInTree) {
auto fgHandle = mFGSurfaceControl->getHandle();
- sp<SurfaceControl> child =
- mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
- 0, mFGSurfaceControl.get());
- sp<SurfaceControl> relative =
- mClient->createSurface(String8("Relative surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> relative = createSurface(mClient, "Relative surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
fillSurfaceRGBA8(child, 200, 200, 200);
fillSurfaceRGBA8(relative, 100, 100, 100);
@@ -3916,9 +3966,8 @@
void SetUp() override {
LayerUpdateTest::SetUp();
- mChild =
- mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
- 0, mFGSurfaceControl.get());
+ mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0,
+ mFGSurfaceControl.get());
fillSurfaceRGBA8(mChild, 200, 200, 200);
SurfaceComposerClient::Transaction().show(mChild).apply(true);
@@ -3974,14 +4023,12 @@
TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) {
auto fgHandle = mFGSurfaceControl->getHandle();
- sp<SurfaceControl> child =
- mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
- 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
fillSurfaceRGBA8(child, 200, 200, 200);
- sp<SurfaceControl> grandchild =
- mClient->createSurface(String8("Grandchild surface"), 5, 5,
- PIXEL_FORMAT_RGBA_8888, 0, child.get());
+ sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
+ PIXEL_FORMAT_RGBA_8888, 0, child.get());
fillSurfaceRGBA8(grandchild, 50, 50, 50);
SurfaceComposerClient::Transaction()
@@ -3998,9 +4045,8 @@
}
TEST_F(ScreenCaptureTest, CaptureChildOnly) {
- sp<SurfaceControl> child =
- mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
- 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
fillSurfaceRGBA8(child, 200, 200, 200);
auto childHandle = child->getHandle();
@@ -4013,15 +4059,13 @@
}
TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) {
- sp<SurfaceControl> child =
- mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
- 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
fillSurfaceRGBA8(child, 200, 200, 200);
auto childHandle = child->getHandle();
- sp<SurfaceControl> grandchild =
- mClient->createSurface(String8("Grandchild surface"), 5, 5,
- PIXEL_FORMAT_RGBA_8888, 0, child.get());
+ sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
+ PIXEL_FORMAT_RGBA_8888, 0, child.get());
fillSurfaceRGBA8(grandchild, 50, 50, 50);
SurfaceComposerClient::Transaction()
@@ -4040,9 +4084,8 @@
TEST_F(ScreenCaptureTest, CaptureCrop) {
sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
- sp<SurfaceControl> blueLayer =
- mClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888,
- 0, redLayer.get());
+ sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
+ PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
@@ -4073,9 +4116,8 @@
TEST_F(ScreenCaptureTest, CaptureSize) {
sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
- sp<SurfaceControl> blueLayer =
- mClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888,
- 0, redLayer.get());
+ sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
+ PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 6d3e715..cfaf495 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -94,6 +94,10 @@
EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
EXPECT_CALL(*mPrimaryDispSync, getPeriod())
.WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
setupComposer(0);
@@ -140,7 +144,6 @@
sp<DisplayDevice> mDisplay;
sp<DisplayDevice> mExternalDisplay;
sp<mock::DisplaySurface> mDisplaySurface = new mock::DisplaySurface();
- renderengine::mock::Surface* mRenderSurface = new renderengine::mock::Surface();
mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
sp<GraphicBuffer> mBuffer = new GraphicBuffer();
@@ -246,8 +249,6 @@
test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
false /* isVirtual */, true /* isPrimary */)
.setDisplaySurface(test->mDisplaySurface)
- .setRenderSurface(std::unique_ptr<renderengine::Surface>(
- test->mRenderSurface))
.setNativeWindow(test->mNativeWindow)
.setSecure(Derived::IS_SECURE)
.setPowerMode(Derived::INIT_POWER_MODE)
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index e8c8894..5aaf848 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -135,7 +135,6 @@
sp<mock::GraphicBufferConsumer> mConsumer;
sp<mock::GraphicBufferProducer> mProducer;
surfaceflinger::mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
- renderengine::mock::Surface* mRenderSurface = nullptr;
};
DisplayTransactionTest::DisplayTransactionTest() {
@@ -342,22 +341,10 @@
EXPECT_CALL(*test->mNativeWindowSurface, getNativeWindow())
.WillOnce(Return(test->mNativeWindow));
- // For simplicity, we only expect to create a single render surface for
- // each test.
- ASSERT_TRUE(test->mRenderSurface == nullptr);
- test->mRenderSurface = new renderengine::mock::Surface();
- EXPECT_CALL(*test->mRenderEngine, createSurface())
- .WillOnce(Return(ByMove(
- std::unique_ptr<renderengine::Surface>(test->mRenderSurface))));
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
-
- // Creating a DisplayDevice requires getting default dimensions from the
- // native window.
- EXPECT_CALL(*test->mRenderSurface, setAsync(static_cast<bool>(ASYNC))).Times(1);
- EXPECT_CALL(*test->mRenderSurface, setCritical(static_cast<bool>(CRITICAL))).Times(1);
}
static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) {
@@ -1285,7 +1272,7 @@
// Insert display data so that the HWC thinks it created the virtual display.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(displayId);
- mFlinger.mutableHwcDisplayData()[*displayId] = {};
+ mFlinger.mutableHwcDisplayData().try_emplace(*displayId);
setupNewDisplayDeviceInternalTest<Case>();
}
@@ -1798,7 +1785,7 @@
// A virtual display is set up but is removed from the current state.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(displayId);
- mFlinger.mutableHwcDisplayData()[*displayId] = {};
+ mFlinger.mutableHwcDisplayData().try_emplace(*displayId);
Case::Display::injectHwcDisplay(this);
auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
existing.inject();
@@ -1946,12 +1933,10 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
auto displaySurface = new mock::DisplaySurface();
- auto renderSurface = new renderengine::mock::Surface();
sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
- display.setRenderSurface(std::unique_ptr<renderengine::Surface>(renderSurface));
// Setup injection expections
EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
@@ -1992,12 +1977,10 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
auto displaySurface = new mock::DisplaySurface();
- auto renderSurface = new renderengine::mock::Surface();
sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
- display.setRenderSurface(std::unique_ptr<renderengine::Surface>(renderSurface));
// Setup injection expections
EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
@@ -2931,7 +2914,7 @@
// Insert display data so that the HWC thinks it created the virtual display.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(displayId);
- mFlinger.mutableHwcDisplayData()[*displayId] = {};
+ mFlinger.mutableHwcDisplayData().try_emplace(*displayId);
// A virtual display device is set up
Case::Display::injectHwcDisplay(this);
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index b518f10..3fb1a6e 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -85,11 +85,13 @@
// Because the counter was incremented, the elements were inserted into different
// containers.
+ // We expect the get method to access the slot at the current counter of the index
+ // is 0.
const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0);
EXPECT_EQ(1, testMap1.size());
- auto element = testMap1.find("TestLayer0");
- EXPECT_EQ("TestLayer0", element->first);
- EXPECT_EQ(0, element->second);
+ auto element = testMap1.find("TestLayer3");
+ EXPECT_EQ("TestLayer3", element->first);
+ EXPECT_EQ(3, element->second);
const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(1);
EXPECT_EQ(2, testMap2.size());
@@ -102,9 +104,9 @@
const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(2);
EXPECT_EQ(1, testMap3.size());
- element = testMap3.find("TestLayer3");
- EXPECT_EQ("TestLayer3", element->first);
- EXPECT_EQ(3, element->second);
+ element = testMap3.find("TestLayer0");
+ EXPECT_EQ("TestLayer0", element->first);
+ EXPECT_EQ(0, element->second);
// Testing accessing object at an empty container will return an empty map.
const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(3);
@@ -113,7 +115,6 @@
TEST_F(LayerHistoryTest, clearTheMap) {
mLayerHistory->insert("TestLayer0", 0);
- mLayerHistory->incrementCounter();
const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0);
EXPECT_EQ(1, testMap1.size());
@@ -121,6 +122,7 @@
EXPECT_EQ("TestLayer0", element->first);
EXPECT_EQ(0, element->second);
+ mLayerHistory->incrementCounter();
// The array currently contains 30 elements.
for (int i = 1; i < 30; ++i) {
mLayerHistory->insert("TestLayer0", i);
@@ -140,5 +142,33 @@
EXPECT_EQ(testMap3.end(), element);
}
+TEST_F(LayerHistoryTest, testingGet) {
+ // The array currently contains 30 elements.
+ for (int i = 0; i < 30; ++i) {
+ const auto name = "TestLayer" + std::to_string(i);
+ mLayerHistory->insert(name, i);
+ mLayerHistory->incrementCounter();
+ }
+
+ // The counter should be set to 0, and the map at 0 should be cleared.
+ const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0);
+ EXPECT_EQ(0, testMap1.size());
+
+ // This should return (ARRAY_SIZE + (counter - 3)) % ARRAY_SIZE
+ const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(3);
+ EXPECT_EQ(1, testMap2.size());
+ auto element = testMap2.find("TestLayer27");
+ EXPECT_EQ("TestLayer27", element->first);
+ EXPECT_EQ(27, element->second);
+
+ // If the user gives an out of bound index, we should mod it with ARRAY_SIZE first,
+ // so requesting element 40 would be the same as requesting element 10.
+ const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(40);
+ EXPECT_EQ(1, testMap3.size());
+ element = testMap3.find("TestLayer20");
+ EXPECT_EQ("TestLayer20", element->first);
+ EXPECT_EQ(20, element->second);
+}
+
} // namespace
} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index be91a9c..e967742 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -59,6 +59,8 @@
SchedulerTest();
~SchedulerTest() override;
+ int64_t calculateMedian(std::vector<int64_t>* v);
+
sp<Scheduler::ConnectionHandle> mConnectionHandle;
mock::DispSync* mPrimaryDispSync = new mock::DispSync();
mock::EventThread* mEventThread;
@@ -95,6 +97,10 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
+int64_t SchedulerTest::calculateMedian(std::vector<int64_t>* v) {
+ return mScheduler->calculateMedian(v);
+}
+
namespace {
/* ------------------------------------------------------------------------
* Test cases
@@ -185,5 +191,37 @@
ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10));
}
+TEST_F(SchedulerTest, calculateMedian) {
+ std::vector<int64_t> testVector;
+ // Calling the function on empty vector returns 0.
+ EXPECT_EQ(0, calculateMedian(&testVector));
+
+ testVector.push_back(33);
+ EXPECT_EQ(33, calculateMedian(&testVector));
+ testVector.push_back(33);
+ testVector.push_back(33);
+ EXPECT_EQ(33, calculateMedian(&testVector));
+ testVector.push_back(42);
+ EXPECT_EQ(33, calculateMedian(&testVector));
+ testVector.push_back(33);
+ EXPECT_EQ(33, calculateMedian(&testVector));
+ testVector.push_back(42);
+ EXPECT_EQ(33, calculateMedian(&testVector));
+ testVector.push_back(42);
+ EXPECT_EQ(33, calculateMedian(&testVector));
+ testVector.push_back(42);
+ EXPECT_EQ(42, calculateMedian(&testVector));
+ testVector.push_back(60);
+ EXPECT_EQ(42, calculateMedian(&testVector));
+ testVector.push_back(60);
+ EXPECT_EQ(42, calculateMedian(&testVector));
+ testVector.push_back(33);
+ EXPECT_EQ(42, calculateMedian(&testVector));
+ testVector.push_back(33);
+ EXPECT_EQ(42, calculateMedian(&testVector));
+ testVector.push_back(33);
+ EXPECT_EQ(33, calculateMedian(&testVector));
+}
+
} // namespace
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index a519f1f..85c835e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -474,11 +474,6 @@
return *this;
}
- auto& setRenderSurface(std::unique_ptr<renderengine::Surface> renderSurface) {
- mCreationArgs.renderSurface = std::move(renderSurface);
- return *this;
- }
-
auto& setSecure(bool secure) {
mCreationArgs.isSecure = secure;
return *this;
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
index af54df6..fbfbc3f 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
@@ -26,9 +26,6 @@
RenderEngine::RenderEngine() = default;
RenderEngine::~RenderEngine() = default;
-Surface::Surface() = default;
-Surface::~Surface() = default;
-
Image::Image() = default;
Image::~Image() = default;
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index afca63a..90c3c20 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -23,7 +23,6 @@
#include <renderengine/LayerSettings.h>
#include <renderengine/Mesh.h>
#include <renderengine/RenderEngine.h>
-#include <renderengine/Surface.h>
#include <renderengine/Texture.h>
#include <ui/GraphicBuffer.h>
@@ -37,15 +36,12 @@
~RenderEngine() override;
MOCK_METHOD0(createFramebuffer, std::unique_ptr<Framebuffer>());
- MOCK_METHOD0(createSurface, std::unique_ptr<renderengine::Surface>());
MOCK_METHOD0(createImage, std::unique_ptr<renderengine::Image>());
MOCK_CONST_METHOD0(primeCache, void());
MOCK_METHOD1(dump, void(String8&));
MOCK_CONST_METHOD0(useNativeFenceSync, bool());
MOCK_CONST_METHOD0(useWaitSync, bool());
MOCK_CONST_METHOD0(isCurrent, bool());
- MOCK_METHOD1(setCurrentSurface, bool(const renderengine::Surface&));
- MOCK_METHOD0(resetCurrentSurface, void());
MOCK_METHOD0(flush, base::unique_fd());
MOCK_METHOD0(finish, bool());
MOCK_METHOD1(waitFence, bool(base::unique_fd*));
@@ -82,23 +78,6 @@
ANativeWindowBuffer* const, base::unique_fd*));
};
-class Surface : public renderengine::Surface {
-public:
- Surface();
- ~Surface() override;
-
- MOCK_METHOD1(setCritical, void(bool));
- MOCK_METHOD1(setAsync, void(bool));
- MOCK_METHOD1(setNativeWindow, void(ANativeWindow*));
- MOCK_CONST_METHOD0(swapBuffers, void());
- MOCK_CONST_METHOD0(queryRedSize, int32_t());
- MOCK_CONST_METHOD0(queryGreenSize, int32_t());
- MOCK_CONST_METHOD0(queryBlueSize, int32_t());
- MOCK_CONST_METHOD0(queryAlphaSize, int32_t());
- MOCK_CONST_METHOD0(getWidth, int32_t());
- MOCK_CONST_METHOD0(getHeight, int32_t());
-};
-
class Image : public renderengine::Image {
public:
Image();