Merge "Deletes temporary files from thread pool when report is cancel"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 2519ffa..3184843 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -99,7 +99,9 @@
/* Tracing categories */
static const TracingCategory k_categories[] = {
- { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { } },
+ { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, {
+ { OPT, "events/gpu_mem/gpu_mem_total/enable" },
+ } },
{ "input", "Input", ATRACE_TAG_INPUT, { } },
{ "view", "View System", ATRACE_TAG_VIEW, { } },
{ "webview", "WebView", ATRACE_TAG_WEBVIEW, { } },
@@ -241,6 +243,7 @@
{ OPT, "events/kmem/ion_heap_grow/enable" },
{ OPT, "events/kmem/ion_heap_shrink/enable" },
{ OPT, "events/ion/ion_stat/enable" },
+ { OPT, "events/gpu_mem/gpu_mem_total/enable" },
} },
{ "thermal", "Thermal event", 0, {
{ REQ, "events/thermal/thermal_temperature/enable" },
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index 50f117d..cf78102 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -44,6 +44,7 @@
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
<feature name="android.software.secure_lock_screen" />
+ <feature name="android.software.input_methods" />
<!-- devices with GPS must include android.hardware.location.gps.xml -->
<!-- devices with an autofocus camera and/or flash must include either
diff --git a/include/input/Input.h b/include/input/Input.h
index 7b66d3c..258adae 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -578,10 +578,18 @@
float getAxisValue(int32_t axis, size_t pointerIndex) const;
+ /**
+ * Get the X coordinate of the latest sample in this MotionEvent for pointer 'pointerIndex'.
+ * Identical to calling getHistoricalX(pointerIndex, getHistorySize()).
+ */
inline float getX(size_t pointerIndex) const {
return getAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
}
+ /**
+ * Get the Y coordinate of the latest sample in this MotionEvent for pointer 'pointerIndex'.
+ * Identical to calling getHistoricalX(pointerIndex, getHistorySize()).
+ */
inline float getY(size_t pointerIndex) const {
return getAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex);
}
@@ -722,7 +730,7 @@
inline const PointerProperties* getPointerProperties() const {
return mPointerProperties.array();
}
- inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); }
+ inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.data(); }
inline const PointerCoords* getSamplePointerCoords() const {
return mSamplePointerCoords.array();
}
@@ -747,7 +755,7 @@
float mRawYCursorPosition;
nsecs_t mDownTime;
Vector<PointerProperties> mPointerProperties;
- Vector<nsecs_t> mSampleEventTimes;
+ std::vector<nsecs_t> mSampleEventTimes;
Vector<PointerCoords> mSamplePointerCoords;
};
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 8e00969..ad0a14e 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -246,6 +246,8 @@
/* Return a new object that has a duplicate of this channel's fd. */
std::unique_ptr<InputChannel> dup() const;
+ void copyTo(InputChannel& outChannel) const;
+
status_t readFromParcel(const android::Parcel* parcel) override;
status_t writeToParcel(android::Parcel* parcel) const override;
@@ -277,6 +279,8 @@
}
private:
+ base::unique_fd dupFd() const;
+
std::string mName;
android::base::unique_fd mFd;
diff --git a/include/input/PropertyMap.h b/include/input/PropertyMap.h
index 3d04331..451918b 100644
--- a/include/input/PropertyMap.h
+++ b/include/input/PropertyMap.h
@@ -17,6 +17,7 @@
#ifndef _UTILS_PROPERTY_MAP_H
#define _UTILS_PROPERTY_MAP_H
+#include <android-base/result.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
@@ -78,7 +79,7 @@
inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; }
/* Loads a property map from a file. */
- static status_t load(const String8& filename, PropertyMap** outMap);
+ static android::base::Result<std::unique_ptr<PropertyMap>> load(const char* filename);
private:
class Parser {
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index ee010a3..886f1f7 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -96,7 +96,7 @@
// are included in the movement.
// The positions array contains position information for each pointer in order by
// increasing id. Its size should be equal to the number of one bits in idBits.
- void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions);
+ void addMovement(nsecs_t eventTime, BitSet32 idBits, const std::vector<Position>& positions);
// Adds movement information for all pointers in a MotionEvent, including historical samples.
void addMovement(const MotionEvent* event);
@@ -149,7 +149,7 @@
virtual void clear() = 0;
virtual void clearPointers(BitSet32 idBits) = 0;
virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) = 0;
+ const std::vector<VelocityTracker::Position>& positions) = 0;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0;
};
@@ -180,8 +180,8 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
- virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions);
+ void addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -223,8 +223,8 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
- virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions);
+ void addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -257,8 +257,8 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
- virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions);
+ void addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -292,8 +292,8 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
- virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions);
+ void addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 9675a53..d363ee9 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -99,6 +99,7 @@
"MemoryDealer.cpp",
"MemoryHeapBase.cpp",
"Parcel.cpp",
+ "ParcelableHolder.cpp",
"ParcelFileDescriptor.cpp",
"PersistableBundle.cpp",
"ProcessState.cpp",
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 0c71ed8..05fcc2b 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -448,6 +448,14 @@
return mLastTransactionBinderFlags;
}
+void IPCThreadState::setCallRestriction(ProcessState::CallRestriction restriction) {
+ mCallRestriction = restriction;
+}
+
+ProcessState::CallRestriction IPCThreadState::getCallRestriction() const {
+ return mCallRestriction;
+}
+
void IPCThreadState::restoreCallingIdentity(int64_t token)
{
mCallingUid = (int)(token>>32);
@@ -1320,6 +1328,22 @@
}
}
+status_t IPCThreadState::getProcessFreezeInfo(pid_t pid, bool *sync_received, bool *async_received)
+{
+ int ret = 0;
+ binder_frozen_status_info info;
+ info.pid = pid;
+
+#if defined(__ANDROID__)
+ if (ioctl(self()->mProcess->mDriverFD, BINDER_GET_FROZEN_INFO, &info) < 0)
+ ret = -errno;
+#endif
+ *sync_received = info.sync_recv;
+ *async_received = info.async_recv;
+
+ return ret;
+}
+
status_t IPCThreadState::freeze(pid_t pid, bool enable, uint32_t timeout_ms) {
struct binder_freeze_info info;
int ret = 0;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 14ab60f..06f6249 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -77,9 +77,8 @@
// many things compile this into prebuilts on the stack
static_assert(sizeof(Parcel) == 60 || sizeof(Parcel) == 120);
-static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER;
-static size_t gParcelGlobalAllocSize = 0;
-static size_t gParcelGlobalAllocCount = 0;
+static std::atomic<size_t> gParcelGlobalAllocCount;
+static std::atomic<size_t> gParcelGlobalAllocSize;
static size_t gMaxFds = 0;
@@ -275,17 +274,11 @@
}
size_t Parcel::getGlobalAllocSize() {
- pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
- size_t size = gParcelGlobalAllocSize;
- pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
- return size;
+ return gParcelGlobalAllocSize.load();
}
size_t Parcel::getGlobalAllocCount() {
- pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
- size_t count = gParcelGlobalAllocCount;
- pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
- return count;
+ return gParcelGlobalAllocCount.load();
}
const uint8_t* Parcel::data() const
@@ -2625,16 +2618,8 @@
releaseObjects();
if (mData) {
LOG_ALLOC("Parcel %p: freeing with %zu capacity", this, mDataCapacity);
- pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
- if (mDataCapacity <= gParcelGlobalAllocSize) {
- gParcelGlobalAllocSize = gParcelGlobalAllocSize - mDataCapacity;
- } else {
- gParcelGlobalAllocSize = 0;
- }
- if (gParcelGlobalAllocCount > 0) {
- gParcelGlobalAllocCount--;
- }
- pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
+ gParcelGlobalAllocSize -= mDataCapacity;
+ gParcelGlobalAllocCount--;
free(mData);
}
if (mObjects) free(mObjects);
@@ -2680,13 +2665,15 @@
if (data || desired == 0) {
LOG_ALLOC("Parcel %p: restart from %zu to %zu capacity", this, mDataCapacity, desired);
- pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
- gParcelGlobalAllocSize += desired;
- gParcelGlobalAllocSize -= mDataCapacity;
+ if (mDataCapacity > desired) {
+ gParcelGlobalAllocSize -= (mDataCapacity - desired);
+ } else {
+ gParcelGlobalAllocSize += (desired - mDataCapacity);
+ }
+
if (!mData) {
gParcelGlobalAllocCount++;
}
- pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
mData = data;
mDataCapacity = desired;
}
@@ -2774,10 +2761,8 @@
mOwner = nullptr;
LOG_ALLOC("Parcel %p: taking ownership of %zu capacity", this, desired);
- pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
gParcelGlobalAllocSize += desired;
gParcelGlobalAllocCount++;
- pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
mData = data;
mObjects = objects;
@@ -2825,10 +2810,8 @@
if (data) {
LOG_ALLOC("Parcel %p: continue from %zu to %zu capacity", this, mDataCapacity,
desired);
- pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
gParcelGlobalAllocSize += desired;
gParcelGlobalAllocSize -= mDataCapacity;
- pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
mData = data;
mDataCapacity = desired;
} else {
@@ -2860,10 +2843,8 @@
}
LOG_ALLOC("Parcel %p: allocating with %zu capacity", this, desired);
- pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
gParcelGlobalAllocSize += desired;
gParcelGlobalAllocCount++;
- pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
mData = data;
mDataSize = mDataPos = 0;
diff --git a/libs/binder/ParcelableHolder.cpp b/libs/binder/ParcelableHolder.cpp
new file mode 100644
index 0000000..e9df279
--- /dev/null
+++ b/libs/binder/ParcelableHolder.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 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 <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/ParcelableHolder.h>
+
+#define RETURN_ON_FAILURE(expr) \
+ do { \
+ android::status_t _status = (expr); \
+ if (_status != android::OK) return _status; \
+ } while (false)
+
+namespace android {
+namespace os {
+status_t ParcelableHolder::writeToParcel(Parcel* p) const {
+ std::lock_guard<std::mutex> l(mMutex);
+ RETURN_ON_FAILURE(p->writeInt32(static_cast<int32_t>(this->getStability())));
+ if (this->mParcelPtr) {
+ RETURN_ON_FAILURE(p->writeInt32(this->mParcelPtr->dataSize()));
+ RETURN_ON_FAILURE(p->appendFrom(this->mParcelPtr.get(), 0, this->mParcelPtr->dataSize()));
+ return OK;
+ }
+ if (this->mParcelable) {
+ size_t sizePos = p->dataPosition();
+ RETURN_ON_FAILURE(p->writeInt32(0));
+ size_t dataStartPos = p->dataPosition();
+ RETURN_ON_FAILURE(p->writeUtf8AsUtf16(this->mParcelableName));
+ this->mParcelable->writeToParcel(p);
+ size_t dataSize = p->dataPosition() - dataStartPos;
+
+ p->setDataPosition(sizePos);
+ RETURN_ON_FAILURE(p->writeInt32(dataSize));
+ p->setDataPosition(p->dataPosition() + dataSize);
+ return OK;
+ }
+
+ RETURN_ON_FAILURE(p->writeInt32(0));
+ return OK;
+}
+
+status_t ParcelableHolder::readFromParcel(const Parcel* p) {
+ std::lock_guard<std::mutex> l(mMutex);
+ this->mStability = static_cast<Stability>(p->readInt32());
+ this->mParcelable = nullptr;
+ this->mParcelableName = std::nullopt;
+ int32_t rawDataSize;
+
+ status_t status = p->readInt32(&rawDataSize);
+ if (status != android::OK || rawDataSize < 0) {
+ this->mParcelPtr = nullptr;
+ return status != android::OK ? status : BAD_VALUE;
+ }
+ if (rawDataSize == 0) {
+ if (this->mParcelPtr) {
+ this->mParcelPtr = nullptr;
+ }
+ return OK;
+ }
+
+ size_t dataSize = rawDataSize;
+
+ size_t dataStartPos = p->dataPosition();
+
+ if (dataStartPos > SIZE_MAX - dataSize) {
+ this->mParcelPtr = nullptr;
+ return BAD_VALUE;
+ }
+
+ if (!this->mParcelPtr) {
+ this->mParcelPtr = std::make_unique<Parcel>();
+ }
+ this->mParcelPtr->freeData();
+
+ status = this->mParcelPtr->appendFrom(p, dataStartPos, dataSize);
+ if (status != android::OK) {
+ this->mParcelPtr = nullptr;
+ return status;
+ }
+ p->setDataPosition(dataStartPos + dataSize);
+ return OK;
+}
+} // namespace os
+} // namespace android
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index a530565..83ca687 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -282,9 +282,17 @@
// a driver API to get a handle to the context manager with
// proper reference counting.
+ IPCThreadState* ipc = IPCThreadState::self();
+
+ CallRestriction originalCallRestriction = ipc->getCallRestriction();
+ ipc->setCallRestriction(CallRestriction::NONE);
+
Parcel data;
- status_t status = IPCThreadState::self()->transact(
+ status_t status = ipc->transact(
0, IBinder::PING_TRANSACTION, data, nullptr, 0);
+
+ ipc->setCallRestriction(originalCallRestriction);
+
if (status == DEAD_OBJECT)
return nullptr;
}
diff --git a/libs/binder/fuzzer/binder.cpp b/libs/binder/fuzzer/binder.cpp
index 8c0495c..e5c6333 100644
--- a/libs/binder/fuzzer/binder.cpp
+++ b/libs/binder/fuzzer/binder.cpp
@@ -19,6 +19,8 @@
#include "util.h"
#include <android/os/IServiceManager.h>
+#include <binder/ParcelableHolder.h>
+#include <binder/PersistableBundle.h>
using ::android::status_t;
@@ -271,5 +273,20 @@
PARCEL_READ_NO_STATUS(uid_t, readCallingWorkSourceUid),
PARCEL_READ_NO_STATUS(size_t, getBlobAshmemSize),
PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),
+
+ // additional parcelable objects defined in libbinder
+ [] (const ::android::Parcel& p, uint8_t data) {
+ using ::android::os::ParcelableHolder;
+ using ::android::Parcelable;
+ FUZZ_LOG() << "about to read ParcelableHolder using readParcelable with status";
+ Parcelable::Stability stability = Parcelable::Stability::STABILITY_LOCAL;
+ if ( (data & 1) == 1 ) {
+ stability = Parcelable::Stability::STABILITY_VINTF;
+ }
+ ParcelableHolder t = ParcelableHolder(stability);
+ status_t status = p.readParcelable(&t);
+ FUZZ_LOG() << "ParcelableHolder status: " << status;
+ },
+ PARCEL_READ_WITH_STATUS(android::os::PersistableBundle, readParcelable),
};
// clang-format on
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index cdeccea..49ef253 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -32,6 +32,8 @@
class IPCThreadState
{
public:
+ using CallRestriction = ProcessState::CallRestriction;
+
static IPCThreadState* self();
static IPCThreadState* selfOrNull(); // self(), but won't instantiate
@@ -49,6 +51,9 @@
// returns: 0 in case of success, a value < 0 in case of error
static status_t freeze(pid_t pid, bool enabled, uint32_t timeout_ms);
+ // Provide information about the state of a frozen process
+ static status_t getProcessFreezeInfo(pid_t pid, bool *sync_received,
+ bool *async_received);
sp<ProcessState> process();
status_t clearLastError();
@@ -96,6 +101,9 @@
void setLastTransactionBinderFlags(int32_t flags);
int32_t getLastTransactionBinderFlags() const;
+ void setCallRestriction(CallRestriction restriction);
+ CallRestriction getCallRestriction() const;
+
int64_t clearCallingIdentity();
// Restores PID/UID (not SID)
void restoreCallingIdentity(int64_t token);
@@ -154,7 +162,6 @@
// This constant needs to be kept in sync with Binder.UNSET_WORKSOURCE from the Java
// side.
static const int32_t kUnsetWorkSource = -1;
-
private:
IPCThreadState();
~IPCThreadState();
@@ -201,8 +208,7 @@
bool mPropagateWorkSource;
int32_t mStrictModePolicy;
int32_t mLastTransactionBinderFlags;
-
- ProcessState::CallRestriction mCallRestriction;
+ CallRestriction mCallRestriction;
};
} // namespace android
diff --git a/libs/binder/include/binder/Parcelable.h b/libs/binder/include/binder/Parcelable.h
index 83c2f19..a6e610c 100644
--- a/libs/binder/include/binder/Parcelable.h
+++ b/libs/binder/include/binder/Parcelable.h
@@ -56,7 +56,7 @@
// WARNING: for use by auto-generated code only (AIDL). Should not be used
// manually, or there is a risk of breaking CTS, GTS, VTS, or CTS-on-GSI
// tests.
- enum class Stability {
+ enum class Stability : int32_t {
STABILITY_LOCAL,
STABILITY_VINTF, // corresponds to @VintfStability
};
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
new file mode 100644
index 0000000..b6814aa
--- /dev/null
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2020 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 <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <mutex>
+#include <optional>
+#include <tuple>
+
+namespace android {
+namespace os {
+/*
+ * C++ implementation of the Java class android.os.ParcelableHolder
+ */
+class ParcelableHolder : public android::Parcelable {
+public:
+ ParcelableHolder() = delete;
+ explicit ParcelableHolder(Stability stability) : mStability(stability){};
+ virtual ~ParcelableHolder() = default;
+ ParcelableHolder(const ParcelableHolder& other) {
+ mParcelable = other.mParcelable;
+ mParcelableName = other.mParcelableName;
+ if (other.mParcelPtr) {
+ mParcelPtr = std::make_unique<Parcel>();
+ mParcelPtr->appendFrom(other.mParcelPtr.get(), 0, other.mParcelPtr->dataSize());
+ }
+ mStability = other.mStability;
+ };
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+ void reset() {
+ this->mParcelable = nullptr;
+ this->mParcelableName = std::nullopt;
+ this->mParcelPtr = nullptr;
+ }
+
+ template <typename T>
+ bool setParcelable(T&& p) {
+ using Tt = typename std::decay<T>::type;
+ return setParcelable<Tt>(std::make_shared<Tt>(std::forward<T>(p)));
+ }
+
+ template <typename T>
+ bool setParcelable(std::shared_ptr<T> p) {
+ std::lock_guard<std::mutex> l(mMutex);
+ static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
+ if (p && this->getStability() > p->getStability()) {
+ return false;
+ }
+ this->mParcelable = p;
+ this->mParcelableName = T::getParcelableDescriptor();
+ this->mParcelPtr = nullptr;
+ return true;
+ }
+
+ template <typename T>
+ std::shared_ptr<T> getParcelable() const {
+ static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
+ std::lock_guard<std::mutex> l(mMutex);
+ const std::string& parcelableDesc = T::getParcelableDescriptor();
+ if (!this->mParcelPtr) {
+ if (!this->mParcelable || !this->mParcelableName) {
+ ALOGD("empty ParcelableHolder");
+ return nullptr;
+ } else if (parcelableDesc != *mParcelableName) {
+ ALOGD("extension class name mismatch expected:%s actual:%s",
+ mParcelableName->c_str(), parcelableDesc.c_str());
+ return nullptr;
+ }
+ return std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+ }
+ this->mParcelPtr->setDataPosition(0);
+ status_t status = this->mParcelPtr->readUtf8FromUtf16(&this->mParcelableName);
+ if (status != android::OK || parcelableDesc != this->mParcelableName) {
+ this->mParcelableName = std::nullopt;
+ return nullptr;
+ }
+ this->mParcelable = std::make_shared<T>();
+ status = mParcelable.get()->readFromParcel(this->mParcelPtr.get());
+ if (status != android::OK) {
+ this->mParcelableName = std::nullopt;
+ this->mParcelable = nullptr;
+ return nullptr;
+ }
+ this->mParcelPtr = nullptr;
+ return std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+ }
+
+ Stability getStability() const override { return mStability; };
+
+ inline bool operator!=(const ParcelableHolder& rhs) const {
+ return std::tie(mParcelable, mParcelPtr, mStability) !=
+ std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+ }
+ inline bool operator<(const ParcelableHolder& rhs) const {
+ return std::tie(mParcelable, mParcelPtr, mStability) <
+ std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+ }
+ inline bool operator<=(const ParcelableHolder& rhs) const {
+ return std::tie(mParcelable, mParcelPtr, mStability) <=
+ std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+ }
+ inline bool operator==(const ParcelableHolder& rhs) const {
+ return std::tie(mParcelable, mParcelPtr, mStability) ==
+ std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+ }
+ inline bool operator>(const ParcelableHolder& rhs) const {
+ return std::tie(mParcelable, mParcelPtr, mStability) >
+ std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+ }
+ inline bool operator>=(const ParcelableHolder& rhs) const {
+ return std::tie(mParcelable, mParcelPtr, mStability) >=
+ std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+ }
+
+private:
+ mutable std::shared_ptr<Parcelable> mParcelable;
+ mutable std::optional<std::string> mParcelableName;
+ mutable std::unique_ptr<Parcel> mParcelPtr;
+ Stability mStability;
+ mutable std::mutex mMutex;
+};
+} // namespace os
+} // namespace android
diff --git a/libs/binder/include/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h
index 7898928..7be8f7b 100644
--- a/libs/binder/include/private/binder/binder_module.h
+++ b/libs/binder/include/private/binder/binder_module.h
@@ -66,6 +66,29 @@
};
#endif //BINDER_FREEZE
+#ifndef BINDER_GET_FROZEN_INFO
+
+#define BINDER_GET_FROZEN_INFO _IOWR('b', 15, struct binder_frozen_status_info)
+
+struct binder_frozen_status_info {
+ //
+ // Group-leader PID of process to be queried
+ //
+ __u32 pid;
+ //
+ // Indicates whether the process has received any sync calls since last
+ // freeze (cleared at freeze/unfreeze)
+ //
+ __u32 sync_recv;
+ //
+ // Indicates whether the process has received any async calls since last
+ // freeze (cleared at freeze/unfreeze)
+ //
+ __u32 async_recv;
+};
+#endif //BINDER_GET_FROZEN_INFO
+
+
#ifdef __cplusplus
} // namespace android
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 7d9fd51..51fd84c 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android/binder_context.h>
#include <android/binder_ibinder.h>
#include <android/binder_ibinder_platform.h>
#include "ibinder_internal.h"
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index f44ce0c..a4f4441 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -93,7 +93,7 @@
//
// Use 'SharedRefBase::make<T>(...)' to make. SharedRefBase has implicit
// ownership. Making this operator private to avoid double-ownership.
-#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 30
+#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 30 || defined(__ANDROID_APEX__)
private:
#else
[[deprecated("Prefer SharedRefBase::make<T>(...) if possible.")]]
diff --git a/libs/binder/ndk/include_platform/android/binder_context.h b/libs/binder/ndk/include_platform/android/binder_context.h
new file mode 100644
index 0000000..a99d555
--- /dev/null
+++ b/libs/binder/ndk/include_platform/android/binder_context.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 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 <android/binder_ibinder.h>
+
+__BEGIN_DECLS
+
+/**
+ * Makes calls to AIBinder_getCallingSid work if the kernel supports it. This
+ * must be called on a local binder server before it is sent out to any othe
+ * process. If this is a remote binder, it will abort. If the kernel doesn't
+ * support this feature, you'll always get null from AIBinder_getCallingSid.
+ *
+ * \param binder local server binder to request security contexts on
+ */
+__attribute__((weak)) void AIBinder_setRequestingSid(AIBinder* binder, bool requestingSid)
+ __INTRODUCED_IN(31);
+
+/**
+ * Returns the selinux context of the callee.
+ *
+ * In order for this to work, the following conditions must be met:
+ * - The kernel must be new enough to support this feature.
+ * - The server must have called AIBinder_setRequestingSid.
+ * - The callee must be a remote process.
+ *
+ * \return security context or null if unavailable. The lifetime of this context
+ * is the lifetime of the transaction.
+ */
+__attribute__((weak, warn_unused_result)) const char* AIBinder_getCallingSid() __INTRODUCED_IN(31);
+
+__END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
index 5811760..2af65cf 100644
--- a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
+++ b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
@@ -16,41 +16,14 @@
#pragma once
+// binder_context.h used to be part of this header and is included for backwards
+// compatibility.
+#include <android/binder_context.h>
+
+#if !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)
+
#include <android/binder_ibinder.h>
-
-#if !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)
#include <binder/IBinder.h>
-#endif
-
-__BEGIN_DECLS
-
-/**
- * Makes calls to AIBinder_getCallingSid work if the kernel supports it. This
- * must be called on a local binder server before it is sent out to any othe
- * process. If this is a remote binder, it will abort. If the kernel doesn't
- * support this feature, you'll always get null from AIBinder_getCallingSid.
- *
- * \param binder local server binder to request security contexts on
- */
-__attribute__((weak)) void AIBinder_setRequestingSid(AIBinder* binder, bool requestingSid)
- __INTRODUCED_IN(31);
-
-/**
- * Returns the selinux context of the callee.
- *
- * In order for this to work, the following conditions must be met:
- * - The kernel must be new enough to support this feature.
- * - The server must have called AIBinder_setRequestingSid.
- * - The callee must be a remote process.
- *
- * \return security context or null if unavailable. The lifetime of this context
- * is the lifetime of the transaction.
- */
-__attribute__((weak, warn_unused_result)) const char* AIBinder_getCallingSid() __INTRODUCED_IN(31);
-
-__END_DECLS
-
-#if !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)
/**
* Get libbinder version of binder from AIBinder.
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index c33c44f..722ae23 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -272,7 +272,7 @@
}
binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status) {
- return PruneStatusT(status->get()->writeToParcel(parcel->get()));
+ return PruneStatusT(status->get().writeToParcel(parcel->get()));
}
binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status) {
::android::binder::Status bstatus;
diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp
index d889593..4fd59a2 100644
--- a/libs/binder/ndk/status.cpp
+++ b/libs/binder/ndk/status.cpp
@@ -47,27 +47,27 @@
}
bool AStatus_isOk(const AStatus* status) {
- return status->get()->isOk();
+ return status->get().isOk();
}
binder_exception_t AStatus_getExceptionCode(const AStatus* status) {
- return PruneException(status->get()->exceptionCode());
+ return PruneException(status->get().exceptionCode());
}
int32_t AStatus_getServiceSpecificError(const AStatus* status) {
- return status->get()->serviceSpecificErrorCode();
+ return status->get().serviceSpecificErrorCode();
}
binder_status_t AStatus_getStatus(const AStatus* status) {
- return PruneStatusT(status->get()->transactionError());
+ return PruneStatusT(status->get().transactionError());
}
const char* AStatus_getMessage(const AStatus* status) {
- return status->get()->exceptionMessage().c_str();
+ return status->get().exceptionMessage().c_str();
}
const char* AStatus_getDescription(const AStatus* status) {
- android::String8 description = status->get()->toString8();
+ android::String8 description = status->get().toString8();
char* cStr = new char[description.size() + 1];
memcpy(cStr, description.c_str(), description.size() + 1);
return cStr;
diff --git a/libs/binder/ndk/status_internal.h b/libs/binder/ndk/status_internal.h
index f6227f7..cb96e48 100644
--- a/libs/binder/ndk/status_internal.h
+++ b/libs/binder/ndk/status_internal.h
@@ -25,8 +25,7 @@
AStatus() {} // ok
explicit AStatus(::android::binder::Status&& status) : mStatus(std::move(status)) {}
- ::android::binder::Status* get() { return &mStatus; }
- const ::android::binder::Status* get() const { return &mStatus; }
+ const ::android::binder::Status& get() const { return mStatus; }
private:
::android::binder::Status mStatus;
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 2bd5248..160b9f2 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -18,6 +18,7 @@
#include <aidl/BnBinderNdkUnitTest.h>
#include <aidl/BnEmpty.h>
#include <android-base/logging.h>
+#include <android/binder_context.h>
#include <android/binder_ibinder_jni.h>
#include <android/binder_ibinder_platform.h>
#include <android/binder_manager.h>
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 6bf9cd5..81a5f02 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -98,6 +98,9 @@
/// Send a ping transaction to this object
fn ping_binder(&mut self) -> Result<()>;
+ /// Indicate that the service intends to receive caller security contexts.
+ fn set_requesting_sid(&mut self, enable: bool);
+
/// Dump this object to the given file handle
fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()>;
@@ -587,6 +590,15 @@
f.pad(stringify!($interface))
}
}
+
+ // Convert a &dyn $interface to Box<dyn $interface>
+ impl std::borrow::ToOwned for dyn $interface {
+ type Owned = Box<dyn $interface>;
+ fn to_owned(&self) -> Self::Owned {
+ self.as_binder().into_interface()
+ .expect(concat!("Error cloning interface ", stringify!($interface)))
+ }
+ }
};
}
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index a248f5c..2c1e5a4 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -345,7 +345,6 @@
fn test_read_write() {
use crate::binder::Interface;
use crate::native::Binder;
- use std::ffi::CString;
let mut service = Binder::new(()).as_binder();
let mut parcel = Parcel::new_for_test(&mut service).unwrap();
@@ -360,7 +359,7 @@
assert_eq!(parcel.read::<u64>(), Err(StatusCode::NOT_ENOUGH_DATA));
assert_eq!(parcel.read::<f32>(), Err(StatusCode::NOT_ENOUGH_DATA));
assert_eq!(parcel.read::<f64>(), Err(StatusCode::NOT_ENOUGH_DATA));
- assert_eq!(parcel.read::<Option<CString>>(), Ok(None));
+ assert_eq!(parcel.read::<Option<String>>(), Ok(None));
assert_eq!(parcel.read::<String>(), Err(StatusCode::UNEXPECTED_NULL));
assert_eq!(parcel.read_binder().err(), Some(StatusCode::BAD_TYPE));
@@ -470,11 +469,24 @@
}
assert_eq!(
parcel.read::<Option<String>>().unwrap().unwrap(),
- "Hello, Binder!"
+ "Hello, Binder!",
);
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
+
+ assert!(parcel.write("Embedded null \0 inside a string").is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert_eq!(
+ parcel.read::<Option<String>>().unwrap().unwrap(),
+ "Embedded null \0 inside a string",
+ );
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
assert!(parcel.write(&["str1", "str2", "str3"][..]).is_ok());
assert!(parcel
.write(
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 78b3d2c..138b360 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -21,7 +21,8 @@
use crate::sys;
use std::convert::TryInto;
-use std::ffi::{c_void, CStr, CString};
+use std::ffi::c_void;
+use std::os::raw::c_char;
use std::ptr;
/// A struct whose instances can be written to a [`Parcel`].
@@ -340,7 +341,7 @@
}
}
-impl SerializeOption for CStr {
+impl SerializeOption for str {
fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
match this {
None => unsafe {
@@ -356,14 +357,17 @@
},
Some(s) => unsafe {
// Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. `AParcel_writeString` assumes that we pass a
- // null-terminated C string pointer with no nulls in the middle
- // of the string. Rust guarantees exactly that for a valid CStr
- // instance.
+ // `AParcel`. `AParcel_writeString` assumes that we pass a utf-8
+ // string pointer of `length` bytes, which is what str in Rust
+ // is. The docstring for `AParcel_writeString` says that the
+ // string input should be null-terminated, but it doesn't
+ // actually rely on that fact in the code. If this ever becomes
+ // necessary, we will need to null-terminate the str buffer
+ // before sending it.
status_result(sys::AParcel_writeString(
parcel.as_native_mut(),
- s.as_ptr(),
- s.to_bytes()
+ s.as_ptr() as *const c_char,
+ s.as_bytes()
.len()
.try_into()
.or(Err(StatusCode::BAD_VALUE))?,
@@ -373,29 +377,15 @@
}
}
-impl SerializeArray for Option<&CStr> {}
+impl SerializeArray for Option<&str> {}
-impl Serialize for CStr {
+impl Serialize for str {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
Some(self).serialize(parcel)
}
}
-impl Serialize for CString {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
- Some(self.as_c_str()).serialize(parcel)
- }
-}
-
-impl SerializeArray for CString {}
-
-impl SerializeOption for CString {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
- SerializeOption::serialize_option(this.map(CString::as_c_str), parcel)
- }
-}
-
-impl SerializeArray for Option<CString> {}
+impl SerializeArray for &str {}
impl Serialize for String {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
@@ -413,7 +403,7 @@
impl SerializeArray for Option<String> {}
-impl Deserialize for Option<CString> {
+impl Deserialize for Option<String> {
fn deserialize(parcel: &Parcel) -> Result<Self> {
let mut vec: Option<Vec<u8>> = None;
let status = unsafe {
@@ -430,26 +420,15 @@
status_result(status)?;
vec.map(|mut s| {
- // The vector includes a null-terminator and CString::new requires
- // no nulls, including terminating.
+ // The vector includes a null-terminator and we don't want the
+ // string to be null-terminated for Rust.
s.pop();
- CString::new(s).or(Err(StatusCode::BAD_VALUE))
+ String::from_utf8(s).or(Err(StatusCode::BAD_VALUE))
})
.transpose()
}
}
-impl DeserializeArray for Option<CString> {}
-
-impl DeserializeOption for String {
- fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
- let c_str = <Option<CString>>::deserialize(parcel)?;
- c_str
- .map(|s| s.into_string().or(Err(StatusCode::BAD_VALUE)))
- .transpose()
- }
-}
-
impl DeserializeArray for Option<String> {}
impl Deserialize for String {
@@ -462,28 +441,6 @@
impl DeserializeArray for String {}
-impl SerializeOption for str {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
- match this {
- None => parcel.write(&-1i32),
- Some(s) => {
- let c_str = CString::new(s).or(Err(StatusCode::BAD_VALUE))?;
- parcel.write(&c_str)
- }
- }
- }
-}
-
-impl Serialize for str {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
- Some(self).serialize(parcel)
- }
-}
-
-impl SerializeArray for &str {}
-
-impl SerializeArray for Option<&str> {}
-
impl<T: SerializeArray> Serialize for [T] {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
SerializeArray::serialize_array(self, parcel)
@@ -905,8 +862,9 @@
let s1 = "Hello, Binder!";
let s2 = "This is a utf8 string.";
let s3 = "Some more text here.";
+ let s4 = "Embedded nulls \0 \0";
- let strs = [s1, s2, s3];
+ let strs = [s1, s2, s3, s4];
unsafe {
assert!(parcel.set_data_position(start).is_ok());
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 5602c96..82212d8 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -249,6 +249,12 @@
status_result(status)
}
+ fn set_requesting_sid(&mut self, enable: bool) {
+ unsafe {
+ sys::AIBinder_setRequestingSid(self.as_native_mut(), enable)
+ };
+ }
+
fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()> {
let args: Vec<_> = args.iter().map(|a| CString::new(*a).unwrap()).collect();
let mut arg_ptrs: Vec<_> = args.iter().map(|a| a.as_ptr()).collect();
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index 992f074..0e05f10 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -98,4 +98,36 @@
sys::AIBinder_getCallingPid()
}
}
+
+ /// This function makes the client's security context available to the
+ /// service calling this function. This can be used for access control.
+ /// It does not suffer from the TOCTOU issues of get_calling_pid.
+ ///
+ /// Implementations of `check_permission` should use the given CStr
+ /// argument as context for selinux permission checks. If `None` is
+ /// given, the implementation should fall back to using the PID
+ /// instead.
+ ///
+ /// Note: `None` may be passed to the callback if the caller did not
+ /// `set_requesting_sid` on the serviced binder, or if the underlying
+ /// kernel is too old to support this feature.
+ pub fn with_calling_sid<T, F>(check_permission: F) -> T
+ where
+ for<'a> F: FnOnce(Option<&'a std::ffi::CStr>) -> T {
+ // Safety: AIBinder_getCallingSid returns a c-string pointer
+ // that is valid for a transaction. Also, the string returned
+ // is thread local. By restricting the lifetime of the CStr
+ // reference to the scope of the callback, we prevent it being
+ // used beyond the guaranteed lifetime.
+ check_permission(unsafe {
+ let sid = sys::AIBinder_getCallingSid();
+ // AIBinder_getCallingSid() returns a '\0' terminated string
+ // or NULL.
+ if sid.is_null() {
+ None
+ } else {
+ Some(std::ffi::CStr::from_ptr(sid))
+ }
+ })
+ }
}
diff --git a/libs/binder/rust/sys/BinderBindings.h b/libs/binder/rust/sys/BinderBindings.h
index c7a06d9..303f4a5 100644
--- a/libs/binder/rust/sys/BinderBindings.h
+++ b/libs/binder/rust/sys/BinderBindings.h
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android/binder_context.h>
#include <android/binder_ibinder.h>
#include <android/binder_manager.h>
#include <android/binder_parcel.h>
diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp
index 622604f..3db40ba 100644
--- a/libs/binder/rust/tests/Android.bp
+++ b/libs/binder/rust/tests/Android.bp
@@ -3,6 +3,10 @@
srcs: ["integration.rs"],
rustlibs: [
"libbinder_rs",
+ "libselinux_bindgen",
+ ],
+ shared_libs: [
+ "libselinux",
],
// For the binaries to be pushed properly as specified in AndroidTest.xml,
// this cannot be the same as the module name.
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index fe59416..953d328 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -18,7 +18,8 @@
use binder::declare_binder_interface;
use binder::parcel::Parcel;
-use binder::{Binder, IBinder, Interface, SpIBinder, TransactionCode};
+use binder::{Binder, IBinder, Interface, SpIBinder, StatusCode, ThreadState, TransactionCode};
+use std::convert::{TryFrom, TryInto};
/// Name of service runner.
///
@@ -49,6 +50,7 @@
let mut service = Binder::new(BnTest(Box::new(TestService {
s: service_name.clone(),
})));
+ service.set_requesting_sid(true);
if let Some(extension_name) = extension_name {
let extension = BnTest::new_binder(TestService { s: extension_name });
service
@@ -79,18 +81,47 @@
s: String,
}
+#[repr(u32)]
+enum TestTransactionCode {
+ Test = SpIBinder::FIRST_CALL_TRANSACTION,
+ GetSelinuxContext,
+}
+
+impl TryFrom<u32> for TestTransactionCode {
+ type Error = StatusCode;
+
+ fn try_from(c: u32) -> Result<Self, Self::Error> {
+ match c {
+ _ if c == TestTransactionCode::Test as u32 => Ok(TestTransactionCode::Test),
+ _ if c == TestTransactionCode::GetSelinuxContext as u32 => {
+ Ok(TestTransactionCode::GetSelinuxContext)
+ }
+ _ => Err(StatusCode::UNKNOWN_TRANSACTION),
+ }
+ }
+}
+
impl Interface for TestService {}
impl ITest for TestService {
fn test(&self) -> binder::Result<String> {
Ok(self.s.clone())
}
+
+ fn get_selinux_context(&self) -> binder::Result<String> {
+ let sid =
+ ThreadState::with_calling_sid(|sid| sid.map(|s| s.to_string_lossy().into_owned()));
+ sid.ok_or(StatusCode::UNEXPECTED_NULL)
+ }
}
/// Trivial testing binder interface
pub trait ITest: Interface {
/// Returns a test string
fn test(&self) -> binder::Result<String>;
+
+ /// Returns the caller's SELinux context
+ fn get_selinux_context(&self) -> binder::Result<String>;
}
declare_binder_interface! {
@@ -104,19 +135,30 @@
fn on_transact(
service: &dyn ITest,
- _code: TransactionCode,
+ code: TransactionCode,
_data: &Parcel,
reply: &mut Parcel,
) -> binder::Result<()> {
- reply.write(&service.test()?)?;
- Ok(())
+ match code.try_into()? {
+ TestTransactionCode::Test => reply.write(&service.test()?),
+ TestTransactionCode::GetSelinuxContext => reply.write(&service.get_selinux_context()?),
+ }
}
impl ITest for BpTest {
fn test(&self) -> binder::Result<String> {
- let reply = self
- .binder
- .transact(SpIBinder::FIRST_CALL_TRANSACTION, 0, |_| Ok(()))?;
+ let reply =
+ self.binder
+ .transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
+ reply.read()
+ }
+
+ fn get_selinux_context(&self) -> binder::Result<String> {
+ let reply = self.binder.transact(
+ TestTransactionCode::GetSelinuxContext as TransactionCode,
+ 0,
+ |_| Ok(()),
+ )?;
reply.read()
}
}
@@ -125,12 +167,19 @@
fn test(&self) -> binder::Result<String> {
self.0.test()
}
+
+ fn get_selinux_context(&self) -> binder::Result<String> {
+ self.0.get_selinux_context()
+ }
}
#[cfg(test)]
mod tests {
+ use selinux_bindgen as selinux_sys;
+ use std::ffi::CStr;
use std::fs::File;
use std::process::{Child, Command};
+ use std::ptr;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
@@ -203,6 +252,24 @@
assert_eq!(test_client.test().unwrap(), "trivial_client_test");
}
+ #[test]
+ fn get_selinux_context() {
+ let service_name = "get_selinux_context";
+ let _process = ScopedServiceProcess::new(service_name);
+ let test_client: Box<dyn ITest> =
+ binder::get_interface(service_name).expect("Did not get manager binder service");
+ let expected_context = unsafe {
+ let mut out_ptr = ptr::null_mut();
+ assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
+ assert!(!out_ptr.is_null());
+ CStr::from_ptr(out_ptr)
+ };
+ assert_eq!(
+ test_client.get_selinux_context().unwrap(),
+ expected_context.to_str().expect("context was invalid UTF-8"),
+ );
+ }
+
fn register_death_notification(binder: &mut SpIBinder) -> (Arc<AtomicBool>, DeathRecipient) {
let binder_died = Arc::new(AtomicBool::new(false));
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 145c099..98f0868 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -432,6 +432,15 @@
EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, 1, 0));
EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, 1, 1000));
EXPECT_EQ(FAILED_TRANSACTION, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply));
+
+ bool sync_received, async_received;
+
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->getProcessFreezeInfo(pid, &sync_received,
+ &async_received));
+
+ EXPECT_EQ(sync_received, 1);
+ EXPECT_EQ(async_received, 0);
+
EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, 0, 0));
EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply));
}
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index 62311d4..a6b6b84 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -30,42 +30,21 @@
public:
ServiceManager();
- /**
- * Equivalent of checkService.
- */
sp<IBinder> getService( const String16& name) const override;
- /**
- * Retrieve an existing service, non-blocking.
- */
sp<IBinder> checkService( const String16& name) const override;
- /**
- * Register a service.
- */
status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated = false,
int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) override;
- /**
- * Return list of all existing services.
- */
Vector<String16> listServices(int dumpsysFlags = 0) override;
IBinder* onAsBinder() override;
- /**
- * Effectively no-oped in this implementation - equivalent to checkService.
- */
sp<IBinder> waitForService(const String16& name) override;
- /**
- * Check if a service is declared (e.g. VINTF manifest).
- *
- * If this returns true, waitForService should always be able to return the
- * service.
- */
- bool isDeclared(const String16& name) override;
+ bool isDeclared(const String16& name) override;
private:
std::map<String16, sp<IBinder>> mNameToService;
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index 53c68b7..e2f072a 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -706,35 +706,35 @@
return err;
}
- err = encodeInteger<int64_t>(static_cast<int32_t>(input.offsetInBytes), output);
+ err = encodeInteger<int64_t>(static_cast<int64_t>(input.offsetInBytes), output);
if (err) {
return err;
}
- err = encodeInteger<int64_t>(static_cast<int32_t>(input.sampleIncrementInBits), output);
+ err = encodeInteger<int64_t>(static_cast<int64_t>(input.sampleIncrementInBits), output);
if (err) {
return err;
}
- err = encodeInteger<int64_t>(static_cast<int32_t>(input.strideInBytes), output);
+ err = encodeInteger<int64_t>(static_cast<int64_t>(input.strideInBytes), output);
if (err) {
return err;
}
- err = encodeInteger<int64_t>(static_cast<int32_t>(input.widthInSamples), output);
+ err = encodeInteger<int64_t>(static_cast<int64_t>(input.widthInSamples), output);
if (err) {
return err;
}
- err = encodeInteger<int64_t>(static_cast<int32_t>(input.heightInSamples), output);
+ err = encodeInteger<int64_t>(static_cast<int64_t>(input.heightInSamples), output);
if (err) {
return err;
}
- err = encodeInteger<int64_t>(static_cast<int32_t>(input.totalSizeInBytes), output);
+ err = encodeInteger<int64_t>(static_cast<int64_t>(input.totalSizeInBytes), output);
if (err) {
return err;
}
- err = encodeInteger<int64_t>(static_cast<int32_t>(input.horizontalSubsampling), output);
+ err = encodeInteger<int64_t>(static_cast<int64_t>(input.horizontalSubsampling), output);
if (err) {
return err;
}
- return encodeInteger<int64_t>(static_cast<int32_t>(input.verticalSubsampling), output);
+ return encodeInteger<int64_t>(static_cast<int64_t>(input.verticalSubsampling), output);
}
status_t decodePlaneLayout(InputHidlVec* input, PlaneLayout* output) {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index ae265ca..a0e9cbf 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -30,6 +30,12 @@
min_sdk_version: "29",
}
+filegroup {
+ name: "libgui_aidl",
+ srcs: ["aidl/**/*.aidl"],
+ path: "aidl/",
+}
+
cc_library_shared {
name: "libgui",
vendor_available: false,
@@ -42,6 +48,7 @@
srcs: [
":framework_native_aidl",
+ ":libgui_aidl",
":libgui_bufferqueue_sources",
"BitTube.cpp",
@@ -74,6 +81,7 @@
"SurfaceControl.cpp",
"SurfaceComposerClient.cpp",
"SyncFeatures.cpp",
+ "TransactionTracing.cpp",
"view/Surface.cpp",
"bufferqueue/1.0/B2HProducerListener.cpp",
"bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
@@ -145,6 +153,7 @@
defaults: ["libgui_bufferqueue-defaults"],
srcs: [
+ ":libgui_aidl",
":libgui_bufferqueue_sources",
],
}
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 2cc7c34..7e894b4 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -73,7 +73,8 @@
nsecs_t vsyncTimestamp;
PhysicalDisplayId vsyncDisplayId;
uint32_t vsyncCount;
- if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
+ int64_t vsyncId;
+ if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncId)) {
ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
}
@@ -116,11 +117,13 @@
nsecs_t vsyncTimestamp;
PhysicalDisplayId vsyncDisplayId;
uint32_t vsyncCount;
- if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
- ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", displayId=%s, count=%d", this,
- ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount);
+ int64_t vsyncId;
+ if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncId)) {
+ ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
+ ", displayId=%s, count=%d, vsyncId=%" PRId64,
+ this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount, vsyncId);
mWaitingForVsync = false;
- dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
+ dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncId);
}
return 1; // keep the callback
@@ -128,10 +131,11 @@
bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
PhysicalDisplayId* outDisplayId,
- uint32_t* outCount) {
+ uint32_t* outCount, int64_t* outVsyncId) {
bool gotVsync = false;
DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
ssize_t n;
+ *outVsyncId = 0;
while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
ALOGV("dispatcher %p ~ Read %d events.", this, int(n));
for (ssize_t i = 0; i < n; i++) {
@@ -144,6 +148,7 @@
*outTimestamp = ev.header.timestamp;
*outDisplayId = ev.header.displayId;
*outCount = ev.vsync.count;
+ *outVsyncId = ev.vsync.vsyncId;
break;
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 0ac493d..7a2f656 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -20,6 +20,8 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/gui/ITransactionTraceListener.h>
+
#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -244,10 +246,25 @@
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeString8(displayName);
- data.writeInt32(secure ? 1 : 0);
- remote()->transact(BnSurfaceComposer::CREATE_DISPLAY, data, &reply);
- return reply.readStrongBinder();
+ status_t status = data.writeString8(displayName);
+ if (status) {
+ return nullptr;
+ }
+ status = data.writeBool(secure);
+ if (status) {
+ return nullptr;
+ }
+
+ status = remote()->transact(BnSurfaceComposer::CREATE_DISPLAY, data, &reply);
+ if (status) {
+ return nullptr;
+ }
+ sp<IBinder> display;
+ status = reply.readNullableStrongBinder(&display);
+ if (status) {
+ return nullptr;
+ }
+ return display;
}
virtual void destroyDisplay(const sp<IBinder>& display)
@@ -1150,6 +1167,47 @@
return NO_ERROR;
}
+
+ virtual status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface,
+ int64_t frameTimelineVsyncId) {
+ Parcel data, reply;
+ status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (err != NO_ERROR) {
+ ALOGE("setFrameTimelineVsync: failed writing interface token: %s (%d)", strerror(-err),
+ -err);
+ return err;
+ }
+
+ err = data.writeStrongBinder(IInterface::asBinder(surface));
+ if (err != NO_ERROR) {
+ ALOGE("setFrameTimelineVsync: failed writing strong binder: %s (%d)", strerror(-err),
+ -err);
+ return err;
+ }
+
+ err = data.writeInt64(frameTimelineVsyncId);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameTimelineVsync: failed writing int64_t: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_VSYNC, data, &reply);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameTimelineVsync: failed to transact: %s (%d)", strerror(-err), err);
+ return err;
+ }
+
+ return reply.readInt32();
+ }
+
+ virtual status_t addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& listener) {
+ Parcel data, reply;
+ SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+ SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
+
+ return remote()->transact(BnSurfaceComposer::ADD_TRANSACTION_TRACE_LISTENER, data, &reply);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -1295,10 +1353,12 @@
}
case CREATE_DISPLAY: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- String8 displayName = data.readString8();
- bool secure = bool(data.readInt32());
- sp<IBinder> display(createDisplay(displayName, secure));
- reply->writeStrongBinder(display);
+ String8 displayName;
+ SAFE_PARCEL(data.readString8, &displayName);
+ bool secure = false;
+ SAFE_PARCEL(data.readBool, &secure);
+ sp<IBinder> display = createDisplay(displayName, secure);
+ SAFE_PARCEL(reply->writeStrongBinder, display);
return NO_ERROR;
}
case DESTROY_DISPLAY: {
@@ -1950,6 +2010,40 @@
}
return NO_ERROR;
}
+ case SET_FRAME_TIMELINE_VSYNC: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> binder;
+ status_t err = data.readStrongBinder(&binder);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameTimelineVsync: failed to read strong binder: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+ sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(binder);
+ if (!surface) {
+ ALOGE("setFrameTimelineVsync: failed to cast to IGraphicBufferProducer: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+ int64_t frameTimelineVsyncId;
+ err = data.readInt64(&frameTimelineVsyncId);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameTimelineVsync: failed to read int64_t: %s (%d)", strerror(-err),
+ -err);
+ return err;
+ }
+
+ status_t result = setFrameTimelineVsync(surface, frameTimelineVsyncId);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
+ case ADD_TRANSACTION_TRACE_LISTENER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<gui::ITransactionTraceListener> listener;
+ SAFE_PARCEL(data.readStrongBinder, &listener);
+
+ return addTransactionTraceListener(listener);
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index e45b3d1..9ce8442 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1207,6 +1207,9 @@
case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER:
res = dispatchGetLastQueuedBuffer(args);
break;
+ case NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC:
+ res = dispatchSetFrameTimelineVsync(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -1513,6 +1516,14 @@
return result;
}
+int Surface::dispatchSetFrameTimelineVsync(va_list args) {
+ ATRACE_CALL();
+ auto frameTimelineVsyncId = static_cast<int64_t>(va_arg(args, int64_t));
+
+ ALOGV("Surface::dispatchSetFrameTimelineVsync");
+ return composerService()->setFrameTimelineVsync(mGraphicBufferProducer, frameTimelineVsyncId);
+}
+
bool Surface::transformToDisplayInverse() {
return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index ce2e5ed..8d2a7d9 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -861,9 +861,8 @@
mStatus = BAD_INDEX;
return *this;
}
- if ((mask & layer_state_t::eLayerOpaque) ||
- (mask & layer_state_t::eLayerHidden) ||
- (mask & layer_state_t::eLayerSecure)) {
+ if ((mask & layer_state_t::eLayerOpaque) || (mask & layer_state_t::eLayerHidden) ||
+ (mask & layer_state_t::eLayerSecure) || (mask & layer_state_t::eLayerSkipScreenshot)) {
s->what |= layer_state_t::eFlagsChanged;
}
s->flags &= ~mask;
@@ -1923,57 +1922,29 @@
}
// ----------------------------------------------------------------------------
-status_t SyncScreenCaptureListener::onScreenCaptureComplete(
- const ScreenCaptureResults& captureResults) {
- resultsPromise.set_value(captureResults);
- return NO_ERROR;
-}
-
-ScreenCaptureResults SyncScreenCaptureListener::waitForResults() {
- std::future<ScreenCaptureResults> resultsFuture = resultsPromise.get_future();
- return resultsFuture.get();
-}
status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs,
- ScreenCaptureResults& captureResults) {
+ const sp<IScreenCaptureListener>& captureListener) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
- status_t status = s->captureDisplay(captureArgs, captureListener);
- if (status != NO_ERROR) {
- return status;
- }
- captureResults = captureListener->waitForResults();
- return captureResults.result;
+ return s->captureDisplay(captureArgs, captureListener);
}
status_t ScreenshotClient::captureDisplay(uint64_t displayOrLayerStack,
- ScreenCaptureResults& captureResults) {
+ const sp<IScreenCaptureListener>& captureListener) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
- status_t status = s->captureDisplay(displayOrLayerStack, captureListener);
- if (status != NO_ERROR) {
- return status;
- }
- captureResults = captureListener->waitForResults();
- return captureResults.result;
+ return s->captureDisplay(displayOrLayerStack, captureListener);
}
status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs,
- ScreenCaptureResults& captureResults) {
+ const sp<IScreenCaptureListener>& captureListener) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
- status_t status = s->captureLayers(captureArgs, captureListener);
- if (status != NO_ERROR) {
- return status;
- }
- captureResults = captureListener->waitForResults();
- return captureResults.result;
+ return s->captureLayers(captureArgs, captureListener);
}
} // namespace android
diff --git a/libs/gui/TransactionTracing.cpp b/libs/gui/TransactionTracing.cpp
new file mode 100644
index 0000000..eedc3df
--- /dev/null
+++ b/libs/gui/TransactionTracing.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gui/TransactionTracing.h"
+#include "gui/ISurfaceComposer.h"
+
+#include <private/gui/ComposerService.h>
+
+namespace android {
+
+sp<TransactionTraceListener> TransactionTraceListener::sInstance = nullptr;
+std::mutex TransactionTraceListener::sMutex;
+
+TransactionTraceListener::TransactionTraceListener() {}
+
+sp<TransactionTraceListener> TransactionTraceListener::getInstance() {
+ const std::lock_guard<std::mutex> lock(sMutex);
+
+ if (sInstance == nullptr) {
+ sInstance = new TransactionTraceListener;
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sf->addTransactionTraceListener(sInstance);
+ }
+
+ return sInstance;
+}
+
+binder::Status TransactionTraceListener::onToggled(bool enabled) {
+ ALOGD("TransactionTraceListener: onToggled listener called");
+ mTracingEnabled = enabled;
+
+ return binder::Status::ok();
+}
+
+bool TransactionTraceListener::isTracingEnabled() {
+ return mTracingEnabled;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/aidl/android/gui/ITransactionTraceListener.aidl b/libs/gui/aidl/android/gui/ITransactionTraceListener.aidl
new file mode 100644
index 0000000..5cd12fd
--- /dev/null
+++ b/libs/gui/aidl/android/gui/ITransactionTraceListener.aidl
@@ -0,0 +1,6 @@
+package android.gui;
+
+/** @hide */
+interface ITransactionTraceListener {
+ void onToggled(boolean enabled);
+}
\ No newline at end of file
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index eb5b004..cf598ea 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -43,7 +43,8 @@
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
- virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0;
+ virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
+ int64_t vsyncId) = 0;
virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
bool connected) = 0;
virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
@@ -53,6 +54,6 @@
virtual void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) = 0;
bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
- uint32_t* outCount);
+ uint32_t* outCount, int64_t* outVsyncId);
};
} // namespace android
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 0d0d102..df3118f 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -73,6 +73,7 @@
uint32_t count;
nsecs_t expectedVSyncTimestamp __attribute__((aligned(8)));
nsecs_t deadlineTimestamp __attribute__((aligned(8)));
+ int64_t vsyncId;
};
struct Hotplug {
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e057b68..3627deb 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -22,6 +22,7 @@
#include <binder/IBinder.h>
#include <binder/IInterface.h>
+#include <android/gui/ITransactionTraceListener.h>
#include <gui/IScreenCaptureListener.h>
#include <gui/ITransactionCompletedListener.h>
@@ -479,6 +480,19 @@
* for tests. Release the token by releasing the returned IBinder reference.
*/
virtual status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) = 0;
+
+ /*
+ * Sets the frame timeline vsync id received from choreographer that corresponds to next
+ * buffer submitted on that surface.
+ */
+ virtual status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface,
+ int64_t frameTimelineVsyncId) = 0;
+
+ /*
+ * Adds a TransactionTraceListener to listen for transaction tracing state updates.
+ */
+ virtual status_t addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& listener) = 0;
};
// ----------------------------------------------------------------------------
@@ -538,6 +552,8 @@
SET_GAME_CONTENT_TYPE,
SET_FRAME_RATE,
ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
+ SET_FRAME_TIMELINE_VSYNC,
+ ADD_TRANSACTION_TRACE_LISTENER,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 3afbabf..ec0a8d1 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -36,6 +36,7 @@
enum { // (keep in sync with SurfaceControl.java)
eHidden = 0x00000004,
eDestroyBackbuffer = 0x00000020,
+ eSkipScreenshot = 0x00000040,
eSecure = 0x00000080,
eNonPremultiplied = 0x00000100,
eOpaque = 0x00000400,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index a763d1d..7a9bb12 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -76,9 +76,10 @@
*/
struct layer_state_t {
enum {
- eLayerHidden = 0x01, // SURFACE_HIDDEN in SurfaceControl.java
- eLayerOpaque = 0x02, // SURFACE_OPAQUE
- eLayerSecure = 0x80, // SECURE
+ eLayerHidden = 0x01, // SURFACE_HIDDEN in SurfaceControl.java
+ eLayerOpaque = 0x02, // SURFACE_OPAQUE
+ eLayerSkipScreenshot = 0x40, // SKIP_SCREENSHOT
+ eLayerSecure = 0x80, // SECURE
};
enum {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 55b4101..a68f2e7 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -265,6 +265,7 @@
int dispatchAddQueueInterceptor(va_list args);
int dispatchAddQueryInterceptor(va_list args);
int dispatchGetLastQueuedBuffer(va_list args);
+ int dispatchSetFrameTimelineVsync(va_list args);
bool transformToDisplayInverse();
protected:
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index af37468..6cac287 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -18,7 +18,6 @@
#include <stdint.h>
#include <sys/types.h>
-#include <future>
#include <set>
#include <unordered_map>
#include <unordered_set>
@@ -594,23 +593,14 @@
// ---------------------------------------------------------------------------
-class SyncScreenCaptureListener : public BnScreenCaptureListener {
-public:
- status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override;
- ScreenCaptureResults waitForResults();
-
-private:
- std::promise<ScreenCaptureResults> resultsPromise;
-};
-
class ScreenshotClient {
public:
static status_t captureDisplay(const DisplayCaptureArgs& captureArgs,
- ScreenCaptureResults& captureResults);
+ const sp<IScreenCaptureListener>& captureListener);
static status_t captureDisplay(uint64_t displayOrLayerStack,
- ScreenCaptureResults& captureResults);
+ const sp<IScreenCaptureListener>& captureListener);
static status_t captureLayers(const LayerCaptureArgs& captureArgs,
- ScreenCaptureResults& captureResults);
+ const sp<IScreenCaptureListener>& captureListener);
};
// ---------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/SyncScreenCaptureListener.h b/libs/gui/include/gui/SyncScreenCaptureListener.h
new file mode 100644
index 0000000..2857996
--- /dev/null
+++ b/libs/gui/include/gui/SyncScreenCaptureListener.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020 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 <gui/SurfaceComposerClient.h>
+#include <future>
+
+namespace android {
+
+class SyncScreenCaptureListener : public BnScreenCaptureListener {
+public:
+ status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override {
+ resultsPromise.set_value(captureResults);
+ return NO_ERROR;
+ }
+
+ ScreenCaptureResults waitForResults() {
+ std::future<ScreenCaptureResults> resultsFuture = resultsPromise.get_future();
+ return resultsFuture.get();
+ }
+
+private:
+ std::promise<ScreenCaptureResults> resultsPromise;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/include/gui/TransactionTracing.h b/libs/gui/include/gui/TransactionTracing.h
new file mode 100644
index 0000000..9efba47
--- /dev/null
+++ b/libs/gui/include/gui/TransactionTracing.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 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 <android/gui/BnTransactionTraceListener.h>
+#include <utils/Mutex.h>
+
+namespace android {
+
+class TransactionTraceListener : public gui::BnTransactionTraceListener {
+ static std::mutex sMutex;
+ static sp<TransactionTraceListener> sInstance;
+
+ TransactionTraceListener();
+
+public:
+ static sp<TransactionTraceListener> getInstance();
+
+ binder::Status onToggled(bool enabled) override;
+
+ bool isTracingEnabled();
+
+private:
+ bool mTracingEnabled = false;
+};
+
+} // namespace android
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 4a186b1..da0d5f8 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -25,6 +25,7 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
#include <gui/SurfaceComposerClient.h>
+#include <gui/SyncScreenCaptureListener.h>
#include <private/gui/ComposerService.h>
#include <ui/DisplayConfig.h>
#include <ui/GraphicBuffer.h>
diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp
index 4bcb795..7210910 100644
--- a/libs/gui/tests/DisplayEventStructLayout_test.cpp
+++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp
@@ -33,6 +33,8 @@
CHECK_OFFSET(DisplayEventReceiver::Event::VSync, count, 0);
CHECK_OFFSET(DisplayEventReceiver::Event::VSync, expectedVSyncTimestamp, 8);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, deadlineTimestamp, 16);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncId, 24);
CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connected, 0);
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 4d306e7..ef4d870 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -68,12 +68,10 @@
public:
InputSurface(const sp<SurfaceControl> &sc, int width, int height) {
mSurfaceControl = sc;
- std::unique_ptr<InputChannel> clientChannel;
- InputChannel::openInputChannelPair("testchannels", mServerChannel, clientChannel);
- mClientChannel = std::move(clientChannel);
mInputFlinger = getInputFlinger();
- mInputFlinger->registerInputChannel(*mServerChannel);
+ mClientChannel = std::make_shared<InputChannel>();
+ mInputFlinger->createInputChannel("testchannels", mClientChannel.get());
populateInputInfo(width, height);
@@ -155,7 +153,7 @@
EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
}
- ~InputSurface() { mInputFlinger->unregisterInputChannel(mServerChannel->getConnectionToken()); }
+ ~InputSurface() { mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken()); }
void doTransaction(std::function<void(SurfaceComposerClient::Transaction&,
const sp<SurfaceControl>&)> transactionBody) {
@@ -192,7 +190,7 @@
}
void populateInputInfo(int width, int height) {
- mInputInfo.token = mServerChannel->getConnectionToken();
+ mInputInfo.token = mClientChannel->getConnectionToken();
mInputInfo.name = "Test info";
mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL;
mInputInfo.type = InputWindowInfo::Type::BASE_APPLICATION;
@@ -219,7 +217,6 @@
}
public:
sp<SurfaceControl> mSurfaceControl;
- std::unique_ptr<InputChannel> mServerChannel;
std::shared_ptr<InputChannel> mClientChannel;
sp<IInputFlinger> mInputFlinger;
@@ -536,4 +533,73 @@
surface->assertFocusChange(true);
}
+
+TEST_F(InputSurfacesTest, rotate_surface) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(10, 10);
+ surface->doTransaction([](auto &t, auto &sc) {
+ t.setMatrix(sc, 0, 1, -1, 0); // 90 degrees
+ });
+ injectTap(8, 11);
+ surface->expectTap(1, 2);
+
+ surface->doTransaction([](auto &t, auto &sc) {
+ t.setMatrix(sc, -1, 0, 0, -1); // 180 degrees
+ });
+ injectTap(9, 8);
+ surface->expectTap(1, 2);
+
+ surface->doTransaction([](auto &t, auto &sc) {
+ t.setMatrix(sc, 0, -1, 1, 0); // 270 degrees
+ });
+ injectTap(12, 9);
+ surface->expectTap(1, 2);
+}
+
+TEST_F(InputSurfacesTest, rotate_surface_with_scale) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(10, 10);
+ surface->doTransaction([](auto &t, auto &sc) {
+ t.setMatrix(sc, 0, 2, -4, 0); // 90 degrees
+ });
+ injectTap(2, 12);
+ surface->expectTap(1, 2);
+
+ surface->doTransaction([](auto &t, auto &sc) {
+ t.setMatrix(sc, -2, 0, 0, -4); // 180 degrees
+ });
+ injectTap(8, 2);
+ surface->expectTap(1, 2);
+
+ surface->doTransaction([](auto &t, auto &sc) {
+ t.setMatrix(sc, 0, -2, 4, 0); // 270 degrees
+ });
+ injectTap(18, 8);
+ surface->expectTap(1, 2);
+}
+
+TEST_F(InputSurfacesTest, rotate_surface_with_scale_and_insets) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->mInputInfo.surfaceInset = 5;
+ surface->showAt(100, 100);
+
+ surface->doTransaction([](auto &t, auto &sc) {
+ t.setMatrix(sc, 0, 2, -4, 0); // 90 degrees
+ });
+ injectTap(40, 120);
+ surface->expectTap(5, 10);
+
+ surface->doTransaction([](auto &t, auto &sc) {
+ t.setMatrix(sc, -2, 0, 0, -4); // 180 degrees
+ });
+ injectTap(80, 40);
+ surface->expectTap(5, 10);
+
+ surface->doTransaction([](auto &t, auto &sc) {
+ t.setMatrix(sc, 0, -2, 4, 0); // 270 degrees
+ });
+ injectTap(160, 80);
+ surface->expectTap(5, 10);
+}
+
} // namespace android::test
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index aedba2a..b8b8e4f 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -28,6 +28,7 @@
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
+#include <gui/SyncScreenCaptureListener.h>
#include <inttypes.h>
#include <private/gui/ComposerService.h>
#include <ui/BufferQueueDefs.h>
@@ -676,8 +677,7 @@
NewFrameEventsEntry mNewFrameEntryOverride = { 0, 0, 0, nullptr };
};
-
-class FakeSurfaceComposer : public ISurfaceComposer{
+class FakeSurfaceComposer : public ISurfaceComposer {
public:
~FakeSurfaceComposer() override {}
@@ -868,7 +868,19 @@
return NO_ERROR;
}
- status_t acquireFrameRateFlexibilityToken(sp<IBinder>* /*outToken*/) { return NO_ERROR; }
+ status_t acquireFrameRateFlexibilityToken(sp<IBinder>* /*outToken*/) override {
+ return NO_ERROR;
+ }
+
+ status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& /*surface*/,
+ int64_t /*frameTimelineVsyncId*/) override {
+ return NO_ERROR;
+ }
+
+ status_t addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& /*listener*/) override {
+ return NO_ERROR;
+ }
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 692c65d..fb2f186 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -376,7 +376,7 @@
mSamplePointerCoords = other->mSamplePointerCoords;
} else {
mSampleEventTimes.clear();
- mSampleEventTimes.push(other->getEventTime());
+ mSampleEventTimes.push_back(other->getEventTime());
mSamplePointerCoords.clear();
size_t pointerCount = other->getPointerCount();
size_t historySize = other->getHistorySize();
@@ -388,7 +388,7 @@
void MotionEvent::addSample(
int64_t eventTime,
const PointerCoords* pointerCoords) {
- mSampleEventTimes.push(eventTime);
+ mSampleEventTimes.push_back(eventTime);
mSamplePointerCoords.appendArray(pointerCoords, getPointerCount());
}
@@ -599,7 +599,7 @@
mPointerProperties.clear();
mPointerProperties.setCapacity(pointerCount);
mSampleEventTimes.clear();
- mSampleEventTimes.setCapacity(sampleCount);
+ mSampleEventTimes.reserve(sampleCount);
mSamplePointerCoords.clear();
mSamplePointerCoords.setCapacity(sampleCount * pointerCount);
@@ -612,7 +612,7 @@
while (sampleCount > 0) {
sampleCount--;
- mSampleEventTimes.push(parcel->readInt64());
+ mSampleEventTimes.push_back(parcel->readInt64());
for (size_t i = 0; i < pointerCount; i++) {
mSamplePointerCoords.push();
status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel);
@@ -663,7 +663,7 @@
const PointerCoords* pc = mSamplePointerCoords.array();
for (size_t h = 0; h < sampleCount; h++) {
- parcel->writeInt64(mSampleEventTimes.itemAt(h));
+ parcel->writeInt64(mSampleEventTimes[h]);
for (size_t i = 0; i < pointerCount; i++) {
status_t status = (pc++)->writeToParcel(parcel);
if (status) {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 79e15c1..85df405 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -377,22 +377,16 @@
}
std::unique_ptr<InputChannel> InputChannel::dup() const {
- android::base::unique_fd newFd(::dup(getFd()));
- if (!newFd.ok()) {
- ALOGE("Could not duplicate fd %i for channel %s: %s", getFd().get(), getName().c_str(),
- strerror(errno));
- const bool hitFdLimit = errno == EMFILE || errno == ENFILE;
- // If this process is out of file descriptors, then throwing that might end up exploding
- // on the other side of a binder call, which isn't really helpful.
- // Better to just crash here and hope that the FD leak is slow.
- // Other failures could be client errors, so we still propagate those back to the caller.
- LOG_ALWAYS_FATAL_IF(hitFdLimit, "Too many open files, could not duplicate input channel %s",
- getName().c_str());
- return nullptr;
- }
+ base::unique_fd newFd(dupFd());
return InputChannel::create(getName(), std::move(newFd), getConnectionToken());
}
+void InputChannel::copyTo(InputChannel& outChannel) const {
+ outChannel.mName = getName();
+ outChannel.mFd = dupFd();
+ outChannel.mToken = getConnectionToken();
+}
+
status_t InputChannel::writeToParcel(android::Parcel* parcel) const {
if (parcel == nullptr) {
ALOGE("%s: Null parcel", __func__);
@@ -415,6 +409,23 @@
return mToken;
}
+base::unique_fd InputChannel::dupFd() const {
+ android::base::unique_fd newFd(::dup(getFd()));
+ if (!newFd.ok()) {
+ ALOGE("Could not duplicate fd %i for channel %s: %s", getFd().get(), getName().c_str(),
+ strerror(errno));
+ const bool hitFdLimit = errno == EMFILE || errno == ENFILE;
+ // If this process is out of file descriptors, then throwing that might end up exploding
+ // on the other side of a binder call, which isn't really helpful.
+ // Better to just crash here and hope that the FD leak is slow.
+ // Other failures could be client errors, so we still propagate those back to the caller.
+ LOG_ALWAYS_FATAL_IF(hitFdLimit, "Too many open files, could not duplicate input channel %s",
+ getName().c_str());
+ return {};
+ }
+ return newFd;
+}
+
// --- InputPublisher ---
InputPublisher::InputPublisher(const std::shared_ptr<InputChannel>& channel) : mChannel(channel) {}
diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp
index 4833eb9..a842166 100644
--- a/libs/input/PropertyMap.cpp
+++ b/libs/input/PropertyMap.cpp
@@ -107,23 +107,22 @@
}
}
-status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) {
- *outMap = nullptr;
+android::base::Result<std::unique_ptr<PropertyMap>> PropertyMap::load(const char* filename) {
+ std::unique_ptr<PropertyMap> outMap = std::make_unique<PropertyMap>();
+ if (outMap == nullptr) {
+ return android::base::Error(NO_MEMORY) << "Error allocating property map.";
+ }
- Tokenizer* tokenizer;
- status_t status = Tokenizer::open(filename, &tokenizer);
+ Tokenizer* rawTokenizer;
+ status_t status = Tokenizer::open(String8(filename), &rawTokenizer);
+ std::unique_ptr<Tokenizer> tokenizer(rawTokenizer);
if (status) {
- ALOGE("Error %d opening property file %s.", status, filename.string());
+ ALOGE("Error %d opening property file %s.", status, filename);
} else {
- PropertyMap* map = new PropertyMap();
- if (!map) {
- ALOGE("Error allocating property map.");
- status = NO_MEMORY;
- } else {
#if DEBUG_PARSER_PERFORMANCE
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
#endif
- Parser parser(map, tokenizer);
+ Parser parser(outMap.get(), tokenizer.get());
status = parser.parse();
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
@@ -132,14 +131,10 @@
elapsedTime / 1000000.0);
#endif
if (status) {
- delete map;
- } else {
- *outMap = map;
+ return android::base::Error(BAD_VALUE) << "Could not parse " << filename;
}
- }
- delete tokenizer;
}
- return status;
+ return std::move(outMap);
}
// --- PropertyMap::Parser ---
diff --git a/libs/input/PropertyMap_fuzz.cpp b/libs/input/PropertyMap_fuzz.cpp
index 23ead0e..afb97a1 100755
--- a/libs/input/PropertyMap_fuzz.cpp
+++ b/libs/input/PropertyMap_fuzz.cpp
@@ -42,7 +42,7 @@
android::String8 out;
propertyMap.tryGetProperty(key, out);
},
- [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
+ [](FuzzedDataProvider* dataProvider, android::PropertyMap /*unused*/) -> void {
TemporaryFile tf;
// Generate file contents
std::string contents = dataProvider->ConsumeRandomLengthString(MAX_FILE_SIZE);
@@ -52,8 +52,7 @@
const char* bytes = contents.c_str();
android::base::WriteStringToFd(bytes, tf.fd);
}
- android::PropertyMap* mapPtr = &propertyMap;
- android::PropertyMap::load(android::String8(tf.path), &mapPtr);
+ android::PropertyMap::load(tf.path);
},
[](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
@@ -65,12 +64,12 @@
};
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
FuzzedDataProvider dataProvider(data, size);
- android::PropertyMap proprtyMap = android::PropertyMap();
+ android::PropertyMap propertyMap = android::PropertyMap();
int opsRun = 0;
while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
- operations[op](&dataProvider, proprtyMap);
+ operations[op](&dataProvider, propertyMap);
}
return 0;
}
diff --git a/libs/input/VelocityControl.cpp b/libs/input/VelocityControl.cpp
index bcf55b0..2c04d42 100644
--- a/libs/input/VelocityControl.cpp
+++ b/libs/input/VelocityControl.cpp
@@ -66,7 +66,7 @@
if (deltaY) {
mRawPosition.y += *deltaY;
}
- mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition);
+ mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), {mRawPosition});
float vx, vy;
float scale = mParameters.scale;
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 7c28ac5..a44f0b7 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -193,7 +193,11 @@
mStrategy->clearPointers(idBits);
}
-void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) {
+void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) {
+ LOG_ALWAYS_FATAL_IF(idBits.count() != positions.size(),
+ "Mismatching number of pointers, idBits=%" PRIu32 ", positions=%zu",
+ idBits.count(), positions.size());
while (idBits.count() > MAX_POINTERS) {
idBits.clearLastMarkedBit();
}
@@ -285,12 +289,12 @@
pointerIndex[i] = idBits.getIndexOfBit(event->getPointerId(i));
}
- nsecs_t eventTime;
- Position positions[pointerCount];
+ std::vector<Position> positions;
+ positions.resize(pointerCount);
size_t historySize = event->getHistorySize();
- for (size_t h = 0; h < historySize; h++) {
- eventTime = event->getHistoricalEventTime(h);
+ for (size_t h = 0; h <= historySize; h++) {
+ nsecs_t eventTime = event->getHistoricalEventTime(h);
for (size_t i = 0; i < pointerCount; i++) {
uint32_t index = pointerIndex[i];
positions[index].x = event->getHistoricalX(i, h);
@@ -298,14 +302,6 @@
}
addMovement(eventTime, idBits, positions);
}
-
- eventTime = event->getEventTime();
- for (size_t i = 0; i < pointerCount; i++) {
- uint32_t index = pointerIndex[i];
- positions[index].x = event->getX(i);
- positions[index].y = event->getY(i);
- }
- addMovement(eventTime, idBits, positions);
}
bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
@@ -346,8 +342,9 @@
mMovements[mIndex].idBits = remainingIdBits;
}
-void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) {
+void LeastSquaresVelocityTrackerStrategy::addMovement(
+ nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) {
if (mMovements[mIndex].eventTime != eventTime) {
// When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates
// of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include
@@ -419,13 +416,15 @@
* http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares
* http://en.wikipedia.org/wiki/Gram-Schmidt
*/
-static bool solveLeastSquares(const float* x, const float* y,
- const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) {
+static bool solveLeastSquares(const std::vector<float>& x, const std::vector<float>& y,
+ const std::vector<float>& w, uint32_t n, float* outB, float* outDet) {
+ const size_t m = x.size();
#if DEBUG_STRATEGY
ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
vectorToString(x, m).c_str(), vectorToString(y, m).c_str(),
vectorToString(w, m).c_str());
#endif
+ LOG_ALWAYS_FATAL_IF(m != y.size() || m != w.size(), "Mismatched vector sizes");
// Expand the X vector to a matrix A, pre-multiplied by the weights.
float a[n][m]; // column-major order
@@ -542,7 +541,9 @@
* the default implementation
*/
static std::optional<std::array<float, 3>> solveUnweightedLeastSquaresDeg2(
- const float* x, const float* y, size_t count) {
+ const std::vector<float>& x, const std::vector<float>& y) {
+ const size_t count = x.size();
+ LOG_ALWAYS_FATAL_IF(count != y.size(), "Mismatching array sizes");
// Solving y = a*x^2 + b*x + c
float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0;
@@ -594,11 +595,11 @@
outEstimator->clear();
// Iterate over movement samples in reverse time order and collect samples.
- float x[HISTORY_SIZE];
- float y[HISTORY_SIZE];
- float w[HISTORY_SIZE];
- float time[HISTORY_SIZE];
- uint32_t m = 0;
+ std::vector<float> x;
+ std::vector<float> y;
+ std::vector<float> w;
+ std::vector<float> time;
+
uint32_t index = mIndex;
const Movement& newestMovement = mMovements[mIndex];
do {
@@ -613,13 +614,14 @@
}
const VelocityTracker::Position& position = movement.getPosition(id);
- x[m] = position.x;
- y[m] = position.y;
- w[m] = chooseWeight(index);
- time[m] = -age * 0.000000001f;
+ x.push_back(position.x);
+ y.push_back(position.y);
+ w.push_back(chooseWeight(index));
+ time.push_back(-age * 0.000000001f);
index = (index == 0 ? HISTORY_SIZE : index) - 1;
- } while (++m < HISTORY_SIZE);
+ } while (x.size() < HISTORY_SIZE);
+ const size_t m = x.size();
if (m == 0) {
return false; // no data
}
@@ -632,8 +634,8 @@
if (degree == 2 && mWeighting == WEIGHTING_NONE) {
// Optimize unweighted, quadratic polynomial fit
- std::optional<std::array<float, 3>> xCoeff = solveUnweightedLeastSquaresDeg2(time, x, m);
- std::optional<std::array<float, 3>> yCoeff = solveUnweightedLeastSquaresDeg2(time, y, m);
+ std::optional<std::array<float, 3>> xCoeff = solveUnweightedLeastSquaresDeg2(time, x);
+ std::optional<std::array<float, 3>> yCoeff = solveUnweightedLeastSquaresDeg2(time, y);
if (xCoeff && yCoeff) {
outEstimator->time = newestMovement.eventTime;
outEstimator->degree = 2;
@@ -648,8 +650,8 @@
// General case for an Nth degree polynomial fit
float xdet, ydet;
uint32_t n = degree + 1;
- if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet)
- && solveLeastSquares(time, y, w, m, n, outEstimator->yCoeff, &ydet)) {
+ if (solveLeastSquares(time, x, w, n, outEstimator->xCoeff, &xdet) &&
+ solveLeastSquares(time, y, w, n, outEstimator->yCoeff, &ydet)) {
outEstimator->time = newestMovement.eventTime;
outEstimator->degree = degree;
outEstimator->confidence = xdet * ydet;
@@ -758,8 +760,9 @@
mPointerIdBits.value &= ~idBits.value;
}
-void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) {
+void IntegratingVelocityTrackerStrategy::addMovement(
+ nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) {
uint32_t index = 0;
for (BitSet32 iterIdBits(idBits); !iterIdBits.isEmpty();) {
uint32_t id = iterIdBits.clearFirstMarkedBit();
@@ -876,8 +879,9 @@
mMovements[mIndex].idBits = remainingIdBits;
}
-void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) {
+void LegacyVelocityTrackerStrategy::addMovement(
+ nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) {
if (++mIndex == HISTORY_SIZE) {
mIndex = 0;
}
@@ -990,8 +994,9 @@
mMovements[mIndex].idBits = remainingIdBits;
}
-void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) {
+void ImpulseVelocityTrackerStrategy::addMovement(
+ nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) {
if (mMovements[mIndex].eventTime != eventTime) {
// When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates
// of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include
diff --git a/libs/input/android/os/IInputFlinger.aidl b/libs/input/android/os/IInputFlinger.aidl
index 0cdf0bb..1771d19 100644
--- a/libs/input/android/os/IInputFlinger.aidl
+++ b/libs/input/android/os/IInputFlinger.aidl
@@ -30,8 +30,8 @@
// shouldn't be a concern.
oneway void setInputWindows(in InputWindowInfo[] inputHandles,
in @nullable ISetInputWindowsListener setInputWindowsListener);
- void registerInputChannel(in InputChannel channel);
- void unregisterInputChannel(in IBinder connectionToken);
+ InputChannel createInputChannel(in @utf8InCpp String name);
+ void removeInputChannel(in IBinder connectionToken);
/**
* Sets focus to the window identified by the token. This must be called
* after updating any input window handles.
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 9782c1a..7ff5ab6 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -19,13 +19,16 @@
"-Wextra",
"-Werror",
],
- shared_libs: [
+ static_libs: [
"libinput",
- "libcutils",
- "libutils",
- "libbinder",
- "libui",
+ ],
+ shared_libs: [
"libbase",
+ "libbinder",
+ "libcutils",
+ "liblog",
+ "libui",
+ "libutils",
]
}
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index ff1b5e6..470f28f 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -128,11 +128,14 @@
static Choreographer* getForThread();
virtual ~Choreographer() override EXCLUDES(gChoreographers.lock);
+ int64_t getVsyncId() const;
+
private:
Choreographer(const Choreographer&) = delete;
- void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
+ void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
+ int64_t vsyncId) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId,
nsecs_t vsyncPeriod) override;
@@ -146,6 +149,7 @@
std::vector<RefreshRateCallback> mRefreshRateCallbacks;
nsecs_t mLatestVsyncPeriod = -1;
+ int64_t mLastVsyncId = -1;
const sp<Looper> mLooper;
const std::thread::id mThreadId;
@@ -350,7 +354,7 @@
// TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
// internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
// the internal display implicitly.
-void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) {
+void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t, int64_t vsyncId) {
std::vector<FrameCallback> callbacks{};
{
std::lock_guard<std::mutex> _l{mLock};
@@ -360,6 +364,7 @@
mFrameCallbacks.pop();
}
}
+ mLastVsyncId = vsyncId;
for (const auto& cb : callbacks) {
if (cb.callback64 != nullptr) {
cb.callback64(timestamp, cb.data);
@@ -404,6 +409,10 @@
}
}
+int64_t Choreographer::getVsyncId() const {
+ return mLastVsyncId;
+}
+
} // namespace android
using namespace android;
@@ -411,6 +420,11 @@
return reinterpret_cast<Choreographer*>(choreographer);
}
+static inline const Choreographer* AChoreographer_to_Choreographer(
+ const AChoreographer* choreographer) {
+ return reinterpret_cast<const Choreographer*>(choreographer);
+}
+
// Glue for private C api
namespace android {
void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock) {
@@ -441,12 +455,18 @@
}
void AChoreographer_routePostFrameCallback(AChoreographer* choreographer,
AChoreographer_frameCallback callback, void* data) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return AChoreographer_postFrameCallback(choreographer, callback, data);
+#pragma clang diagnostic pop
}
void AChoreographer_routePostFrameCallbackDelayed(AChoreographer* choreographer,
AChoreographer_frameCallback callback, void* data,
long delayMillis) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return AChoreographer_postFrameCallbackDelayed(choreographer, callback, data, delayMillis);
+#pragma clang diagnostic pop
}
void AChoreographer_routePostFrameCallback64(AChoreographer* choreographer,
AChoreographer_frameCallback64 callback, void* data) {
@@ -468,15 +488,14 @@
return AChoreographer_unregisterRefreshRateCallback(choreographer, callback, data);
}
+int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer) {
+ return AChoreographer_to_Choreographer(choreographer)->getVsyncId();
+}
+
} // namespace android
/* Glue for the NDK interface */
-static inline const Choreographer* AChoreographer_to_Choreographer(
- const AChoreographer* choreographer) {
- return reinterpret_cast<const Choreographer*>(choreographer);
-}
-
static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) {
return reinterpret_cast<AChoreographer*>(choreographer);
}
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
index 2164930..1d57c15 100644
--- a/libs/nativedisplay/include-private/private/android/choreographer.h
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -29,6 +29,12 @@
// for consumption by callbacks.
void AChoreographer_signalRefreshRateCallbacks(int64_t vsyncPeriod);
+// Returns the vsync id of the last frame callback. Client are expected to call
+// this function from their frame callback function to get the vsyncId and pass
+// it together with a buffer or transaction to the Surface Composer. Calling
+// this function from anywhere else will return an undefined value.
+int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer);
+
// Trampoline functions allowing libandroid.so to define the NDK symbols without including
// the entirety of libnativedisplay as a whole static lib. As libnativedisplay
// maintains global state, libnativedisplay can never be directly statically
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index fc59431..5ed2e49 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -29,6 +29,7 @@
android::AChoreographer_routeRegisterRefreshRateCallback*;
android::AChoreographer_routeUnregisterRefreshRateCallback*;
android::AChoreographer_signalRefreshRateCallbacks*;
+ android::AChoreographer_getVsyncId*;
android::ADisplay_acquirePhysicalDisplays*;
android::ADisplay_release*;
android::ADisplay_getMaxSupportedFps*;
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index b78fc5d..138e08f 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -255,6 +255,7 @@
NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */
NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */
NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */
+ NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC = 48, /* private */
// clang-format on
};
@@ -1022,6 +1023,12 @@
(int)compatibility);
}
+static inline int native_window_set_frame_timeline_vsync(struct ANativeWindow* window,
+ int64_t frameTimelineVsyncId) {
+ return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC,
+ frameTimelineVsyncId);
+}
+
// ------------------------------------------------------------------------------------------------
// Candidates for APEX visibility
// These functions are planned to be made stable for APEX modules, but have not
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 9264bb6..1ccbff1 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -31,6 +31,7 @@
"libui",
"libutils",
],
+ whole_static_libs: ["libskia"],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
}
@@ -71,6 +72,14 @@
],
}
+filegroup {
+ name: "librenderengine_skia_sources",
+ srcs: [
+ "skia/SkiaRenderEngine.cpp",
+ "skia/SkiaGLRenderEngine.cpp",
+ ],
+}
+
cc_library_static {
name: "librenderengine",
defaults: ["librenderengine_defaults"],
@@ -84,6 +93,7 @@
":librenderengine_sources",
":librenderengine_gl_sources",
":librenderengine_threaded_sources",
+ ":librenderengine_skia_sources",
],
lto: {
thin: true,
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index eb0074b..3e65d9a 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -18,10 +18,11 @@
#include <cutils/properties.h>
#include <log/log.h>
-#include <private/gui/SyncFeatures.h>
#include "gl/GLESRenderEngine.h"
#include "threaded/RenderEngineThreaded.h"
+#include "skia/SkiaGLRenderEngine.h"
+
namespace android {
namespace renderengine {
@@ -37,12 +38,17 @@
if (strcmp(prop, "threaded") == 0) {
renderEngineType = RenderEngineType::THREADED;
}
+ if (strcmp(prop, "skiagl") == 0) {
+ renderEngineType = RenderEngineType::SKIA_GL;
+ }
switch (renderEngineType) {
case RenderEngineType::THREADED:
ALOGD("Threaded RenderEngine with GLES Backend");
return renderengine::threaded::RenderEngineThreaded::create(
[args]() { return android::renderengine::gl::GLESRenderEngine::create(args); });
+ case RenderEngineType::SKIA_GL:
+ return renderengine::skia::SkiaGLRenderEngine::create(args);
case RenderEngineType::GLES:
default:
ALOGD("RenderEngine with GLES Backend");
@@ -52,16 +58,5 @@
RenderEngine::~RenderEngine() = default;
-namespace impl {
-
-RenderEngine::RenderEngine(const RenderEngineCreationArgs& args) : mArgs(args) {}
-
-RenderEngine::~RenderEngine() = default;
-
-bool RenderEngine::useNativeFenceSync() const {
- return SyncFeatures::getInstance().useNativeFenceSync();
-}
-
-} // namespace impl
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 42e74df..6adcbea 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -356,8 +356,7 @@
GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
EGLConfig config, EGLContext ctxt, EGLSurface stub,
EGLContext protectedContext, EGLSurface protectedStub)
- : renderengine::impl::RenderEngine(args),
- mEGLDisplay(display),
+ : mEGLDisplay(display),
mEGLConfig(config),
mEGLContext(ctxt),
mStubSurface(stub),
@@ -366,7 +365,8 @@
mVpWidth(0),
mVpHeight(0),
mFramebufferImageCacheSize(args.imageCacheSize),
- mUseColorManagement(args.useColorManagement) {
+ mUseColorManagement(args.useColorManagement),
+ mPrecacheToneMapperShaderOnly(args.precacheToneMapperShaderOnly) {
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
@@ -475,8 +475,7 @@
void GLESRenderEngine::primeCache() const {
ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext,
- mArgs.useColorManagement,
- mArgs.precacheToneMapperShaderOnly);
+ mUseColorManagement, mPrecacheToneMapperShaderOnly);
}
base::unique_fd GLESRenderEngine::flush() {
@@ -639,13 +638,8 @@
}
}
-status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName,
- const sp<GraphicBuffer>& buffer,
- const sp<Fence>& bufferFence) {
- if (buffer == nullptr) {
- return BAD_VALUE;
- }
-
+void GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
+ const sp<Fence>& bufferFence) {
ATRACE_CALL();
bool found = false;
@@ -661,7 +655,8 @@
if (!found) {
status_t cacheResult = mImageManager->cache(buffer);
if (cacheResult != NO_ERROR) {
- return cacheResult;
+ ALOGE("Error with caching buffer: %d", cacheResult);
+ return;
}
}
@@ -678,7 +673,7 @@
// We failed creating the image if we got here, so bail out.
ALOGE("Failed to create an EGLImage when rendering");
bindExternalTextureImage(texName, *createImage());
- return NO_INIT;
+ return;
}
bindExternalTextureImage(texName, *cachedImage->second);
@@ -691,22 +686,22 @@
base::unique_fd fenceFd(bufferFence->dup());
if (fenceFd == -1) {
ALOGE("error dup'ing fence fd: %d", errno);
- return -errno;
+ return;
}
if (!waitFence(std::move(fenceFd))) {
ALOGE("failed to wait on fence fd");
- return UNKNOWN_ERROR;
+ return;
}
} else {
status_t err = bufferFence->waitForever("RenderEngine::bindExternalTextureBuffer");
if (err != NO_ERROR) {
ALOGE("error waiting for fence: %d", err);
- return err;
+ return;
}
}
}
- return NO_ERROR;
+ return;
}
void GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 8f0df2c..1779994 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -48,7 +48,7 @@
class GLImage;
class BlurFilter;
-class GLESRenderEngine : public impl::RenderEngine {
+class GLESRenderEngine : public RenderEngine {
public:
static std::unique_ptr<GLESRenderEngine> create(const RenderEngineCreationArgs& args);
@@ -60,8 +60,6 @@
void primeCache() const override;
void genTextures(size_t count, uint32_t* names) override;
void deleteTextures(size_t count, uint32_t const* names) override;
- status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
- const sp<Fence>& fence) EXCLUDES(mRenderingMutex);
void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex);
@@ -135,6 +133,8 @@
status_t bindFrameBuffer(Framebuffer* framebuffer);
void unbindFrameBuffer(Framebuffer* framebuffer);
void bindExternalTextureImage(uint32_t texName, const Image& image);
+ void bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
+ const sp<Fence>& fence) EXCLUDES(mRenderingMutex);
void cleanFramebufferCache() EXCLUDES(mFramebufferImageCacheMutex) override;
// A data space is considered HDR data space if it has BT2020 color space
@@ -231,6 +231,10 @@
// supports sRGB, DisplayP3 color spaces.
const bool mUseColorManagement = false;
+ // Whether only shaders performing tone mapping from HDR to SDR will be generated on
+ // primeCache().
+ const bool mPrecacheToneMapperShaderOnly = false;
+
// Cache of GL images that we'll store per GraphicBuffer ID
std::unordered_map<uint64_t, std::unique_ptr<Image>> mImageCache GUARDED_BY(mRenderingMutex);
std::unordered_map<uint32_t, std::optional<uint64_t>> mTextureView;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index a0e7ab7..11b8e44 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -73,6 +73,7 @@
enum class RenderEngineType {
GLES = 1,
THREADED = 2,
+ SKIA_GL = 3,
};
static std::unique_ptr<RenderEngine> create(const RenderEngineCreationArgs& args);
@@ -88,14 +89,8 @@
// dump the extension strings. always call the base class.
virtual void dump(std::string& result) = 0;
- virtual bool useNativeFenceSync() const = 0;
virtual void genTextures(size_t count, uint32_t* names) = 0;
virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
- // Legacy public method used by devices that don't support native fence
- // synchronization in their GPU driver, as this method provides implicit
- // synchronization for latching buffers.
- virtual status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
- const sp<Fence>& fence) = 0;
// Caches Image resources for this buffer, but does not bind the buffer to
// a particular texture.
// Note that work is deferred to an additional thread, i.e. this call
@@ -267,21 +262,6 @@
RenderEngine::RenderEngineType renderEngineType = RenderEngine::RenderEngineType::GLES;
};
-namespace impl {
-
-// impl::RenderEngine contains common implementation that is graphics back-end agnostic.
-class RenderEngine : public renderengine::RenderEngine {
-public:
- virtual ~RenderEngine() = 0;
-
- bool useNativeFenceSync() const override;
-
-protected:
- RenderEngine(const RenderEngineCreationArgs& args);
- const RenderEngineCreationArgs mArgs;
-};
-
-} // namespace impl
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 0b80d88..95ee925 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -35,20 +35,12 @@
RenderEngine();
~RenderEngine() override;
- MOCK_METHOD0(getFramebufferForDrawing, Framebuffer*());
MOCK_CONST_METHOD0(primeCache, void());
MOCK_METHOD1(dump, void(std::string&));
- MOCK_CONST_METHOD0(useNativeFenceSync, bool());
- MOCK_CONST_METHOD0(useWaitSync, bool());
- MOCK_CONST_METHOD0(isCurrent, bool());
MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
MOCK_METHOD1(cacheExternalTextureBuffer, void(const sp<GraphicBuffer>&));
- MOCK_METHOD3(bindExternalTextureBuffer,
- status_t(uint32_t, const sp<GraphicBuffer>&, const sp<Fence>&));
MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t));
- MOCK_METHOD1(bindFrameBuffer, status_t(renderengine::Framebuffer*));
- MOCK_METHOD1(unbindFrameBuffer, void(renderengine::Framebuffer*));
MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&));
MOCK_CONST_METHOD0(getMaxTextureSize, size_t());
MOCK_CONST_METHOD0(getMaxViewportDims, size_t());
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
new file mode 100644
index 0000000..cb752b0
--- /dev/null
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -0,0 +1,622 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <cmath>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <sync/sync.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Trace.h>
+#include "../gl/GLExtensions.h"
+#include "SkiaGLRenderEngine.h"
+
+#include <GrContextOptions.h>
+#include <gl/GrGLInterface.h>
+
+#include <SkCanvas.h>
+#include <SkImage.h>
+#include <SkShadowUtils.h>
+#include <SkSurface.h>
+
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+
+bool checkGlError(const char* op, int lineNumber);
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
+ EGLint wanted, EGLConfig* outConfig) {
+ EGLint numConfigs = -1, n = 0;
+ eglGetConfigs(dpy, nullptr, 0, &numConfigs);
+ std::vector<EGLConfig> configs(numConfigs, EGL_NO_CONFIG_KHR);
+ eglChooseConfig(dpy, attrs, configs.data(), configs.size(), &n);
+ configs.resize(n);
+
+ if (!configs.empty()) {
+ if (attribute != EGL_NONE) {
+ for (EGLConfig config : configs) {
+ EGLint value = 0;
+ eglGetConfigAttrib(dpy, config, attribute, &value);
+ if (wanted == value) {
+ *outConfig = config;
+ return NO_ERROR;
+ }
+ }
+ } else {
+ // just pick the first one
+ *outConfig = configs[0];
+ return NO_ERROR;
+ }
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType,
+ EGLConfig* config) {
+ // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
+ // it is to be used with WIFI displays
+ status_t err;
+ EGLint wantedAttribute;
+ EGLint wantedAttributeValue;
+
+ std::vector<EGLint> attribs;
+ if (renderableType) {
+ const ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(format);
+ const bool is1010102 = pixelFormat == ui::PixelFormat::RGBA_1010102;
+
+ // Default to 8 bits per channel.
+ const EGLint tmpAttribs[] = {
+ EGL_RENDERABLE_TYPE,
+ renderableType,
+ EGL_RECORDABLE_ANDROID,
+ EGL_TRUE,
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+ EGL_FRAMEBUFFER_TARGET_ANDROID,
+ EGL_TRUE,
+ EGL_RED_SIZE,
+ is1010102 ? 10 : 8,
+ EGL_GREEN_SIZE,
+ is1010102 ? 10 : 8,
+ EGL_BLUE_SIZE,
+ is1010102 ? 10 : 8,
+ EGL_ALPHA_SIZE,
+ is1010102 ? 2 : 8,
+ EGL_NONE,
+ };
+ std::copy(tmpAttribs, tmpAttribs + (sizeof(tmpAttribs) / sizeof(EGLint)),
+ std::back_inserter(attribs));
+ wantedAttribute = EGL_NONE;
+ wantedAttributeValue = EGL_NONE;
+ } else {
+ // if no renderable type specified, fallback to a simplified query
+ wantedAttribute = EGL_NATIVE_VISUAL_ID;
+ wantedAttributeValue = format;
+ }
+
+ err = selectConfigForAttribute(display, attribs.data(), wantedAttribute, wantedAttributeValue,
+ config);
+ if (err == NO_ERROR) {
+ EGLint caveat;
+ if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
+ ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!");
+ }
+
+ return err;
+}
+
+std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create(
+ const RenderEngineCreationArgs& args) {
+ // initialize EGL for the default display
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (!eglInitialize(display, nullptr, nullptr)) {
+ LOG_ALWAYS_FATAL("failed to initialize EGL");
+ }
+
+ const auto eglVersion = eglQueryStringImplementationANDROID(display, EGL_VERSION);
+ if (!eglVersion) {
+ checkGlError(__FUNCTION__, __LINE__);
+ LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_VERSION) failed");
+ }
+
+ const auto eglExtensions = eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS);
+ if (!eglExtensions) {
+ checkGlError(__FUNCTION__, __LINE__);
+ LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_EXTENSIONS) failed");
+ }
+
+ auto& extensions = gl::GLExtensions::getInstance();
+ extensions.initWithEGLStrings(eglVersion, eglExtensions);
+
+ // The code assumes that ES2 or later is available if this extension is
+ // supported.
+ EGLConfig config = EGL_NO_CONFIG_KHR;
+ if (!extensions.hasNoConfigContext()) {
+ config = chooseEglConfig(display, args.pixelFormat, /*logConfig*/ true);
+ }
+
+ bool useContextPriority =
+ extensions.hasContextPriority() && args.contextPriority == ContextPriority::HIGH;
+ EGLContext protectedContext = EGL_NO_CONTEXT;
+ if (args.enableProtectedContext && extensions.hasProtectedContent()) {
+ protectedContext = createEglContext(display, config, nullptr, useContextPriority,
+ Protection::PROTECTED);
+ ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context");
+ }
+
+ EGLContext ctxt = createEglContext(display, config, protectedContext, useContextPriority,
+ Protection::UNPROTECTED);
+
+ // if can't create a GL context, we can only abort.
+ LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
+
+ EGLSurface placeholder = EGL_NO_SURFACE;
+ if (!extensions.hasSurfacelessContext()) {
+ placeholder = createPlaceholderEglPbufferSurface(display, config, args.pixelFormat,
+ Protection::UNPROTECTED);
+ LOG_ALWAYS_FATAL_IF(placeholder == EGL_NO_SURFACE, "can't create placeholder pbuffer");
+ }
+ EGLBoolean success = eglMakeCurrent(display, placeholder, placeholder, ctxt);
+ LOG_ALWAYS_FATAL_IF(!success, "can't make placeholder pbuffer current");
+ extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
+ glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
+
+ EGLSurface protectedPlaceholder = EGL_NO_SURFACE;
+ if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) {
+ protectedPlaceholder = createPlaceholderEglPbufferSurface(display, config, args.pixelFormat,
+ Protection::PROTECTED);
+ ALOGE_IF(protectedPlaceholder == EGL_NO_SURFACE,
+ "can't create protected placeholder pbuffer");
+ }
+
+ // initialize the renderer while GL is current
+ std::unique_ptr<SkiaGLRenderEngine> engine =
+ std::make_unique<SkiaGLRenderEngine>(display, config, ctxt, placeholder,
+ protectedContext, protectedPlaceholder);
+
+ ALOGI("OpenGL ES informations:");
+ ALOGI("vendor : %s", extensions.getVendor());
+ ALOGI("renderer : %s", extensions.getRenderer());
+ ALOGI("version : %s", extensions.getVersion());
+ ALOGI("extensions: %s", extensions.getExtensions());
+ ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
+ ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
+
+ return engine;
+}
+
+EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
+ status_t err;
+ EGLConfig config;
+
+ // First try to get an ES3 config
+ err = selectEGLConfig(display, format, EGL_OPENGL_ES3_BIT, &config);
+ if (err != NO_ERROR) {
+ // If ES3 fails, try to get an ES2 config
+ err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config);
+ if (err != NO_ERROR) {
+ // If ES2 still doesn't work, probably because we're on the emulator.
+ // try a simplified query
+ ALOGW("no suitable EGLConfig found, trying a simpler query");
+ err = selectEGLConfig(display, format, 0, &config);
+ if (err != NO_ERROR) {
+ // this EGL is too lame for android
+ LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up");
+ }
+ }
+ }
+
+ if (logConfig) {
+ // print some debugging info
+ EGLint r, g, b, a;
+ eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
+ ALOGI("EGL information:");
+ ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR));
+ ALOGI("version : %s", eglQueryString(display, EGL_VERSION));
+ ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
+ ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported");
+ ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
+ }
+
+ return config;
+}
+
+SkiaGLRenderEngine::SkiaGLRenderEngine(EGLDisplay display, EGLConfig config, EGLContext ctxt,
+ EGLSurface placeholder, EGLContext protectedContext,
+ EGLSurface protectedPlaceholder)
+ : mEGLDisplay(display),
+ mEGLConfig(config),
+ mEGLContext(ctxt),
+ mPlaceholderSurface(placeholder),
+ mProtectedEGLContext(protectedContext),
+ mProtectedPlaceholderSurface(protectedPlaceholder) {
+ // Suppress unused field warnings for things we definitely will need/use
+ // These EGL fields will all be needed for toggling between protected & unprotected contexts
+ // Or we need different RE instances for that
+ (void)mEGLDisplay;
+ (void)mEGLConfig;
+ (void)mEGLContext;
+ (void)mPlaceholderSurface;
+ (void)mProtectedEGLContext;
+ (void)mProtectedPlaceholderSurface;
+
+ sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
+ LOG_ALWAYS_FATAL_IF(!glInterface.get());
+
+ GrContextOptions options;
+ options.fPreferExternalImagesOverES3 = true;
+ options.fDisableDistanceFieldPaths = true;
+ mGrContext = GrDirectContext::MakeGL(std::move(glInterface), options);
+}
+
+base::unique_fd SkiaGLRenderEngine::flush() {
+ ATRACE_CALL();
+ if (!gl::GLExtensions::getInstance().hasNativeFenceSync()) {
+ return base::unique_fd();
+ }
+
+ EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
+ return base::unique_fd();
+ }
+
+ // native fence fd will not be populated until flush() is done.
+ glFlush();
+
+ // get the fence fd
+ base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
+ }
+
+ return fenceFd;
+}
+
+bool SkiaGLRenderEngine::waitFence(base::unique_fd fenceFd) {
+ if (!gl::GLExtensions::getInstance().hasNativeFenceSync() ||
+ !gl::GLExtensions::getInstance().hasWaitSync()) {
+ return false;
+ }
+
+ // release the fd and transfer the ownership to EGLSync
+ EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd.release(), EGL_NONE};
+ EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
+ return false;
+ }
+
+ // XXX: The spec draft is inconsistent as to whether this should return an
+ // EGLint or void. Ignore the return value for now, as it's not strictly
+ // needed.
+ eglWaitSyncKHR(mEGLDisplay, sync, 0);
+ EGLint error = eglGetError();
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ if (error != EGL_SUCCESS) {
+ ALOGE("failed to wait for EGL native fence sync: %#x", error);
+ return false;
+ }
+
+ return true;
+}
+
+static bool hasUsage(const AHardwareBuffer_Desc& desc, uint64_t usage) {
+ return !!(desc.usage & usage);
+}
+
+void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ mImageCache.erase(bufferId);
+}
+
+status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
+ const sp<GraphicBuffer>& buffer,
+ const bool useFramebufferCache,
+ base::unique_fd&& bufferFence, base::unique_fd* drawFence) {
+ ATRACE_NAME("SkiaGL::drawLayers");
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ if (layers.empty()) {
+ ALOGV("Drawing empty layer stack");
+ return NO_ERROR;
+ }
+
+ if (bufferFence.get() >= 0) {
+ // Duplicate the fence for passing to waitFence.
+ base::unique_fd bufferFenceDup(dup(bufferFence.get()));
+ if (bufferFenceDup < 0 || !waitFence(std::move(bufferFenceDup))) {
+ ATRACE_NAME("Waiting before draw");
+ sync_wait(bufferFence.get(), -1);
+ }
+ }
+ if (buffer == nullptr) {
+ ALOGE("No output buffer provided. Aborting GPU composition.");
+ return BAD_VALUE;
+ }
+
+ AHardwareBuffer_Desc bufferDesc;
+ AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc);
+
+ LOG_ALWAYS_FATAL_IF(!hasUsage(bufferDesc, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE),
+ "missing usage");
+
+ sk_sp<SkSurface> surface;
+ if (useFramebufferCache) {
+ auto iter = mSurfaceCache.find(buffer->getId());
+ if (iter != mSurfaceCache.end()) {
+ ALOGV("Cache hit!");
+ surface = iter->second;
+ }
+ }
+ if (!surface) {
+ surface = SkSurface::MakeFromAHardwareBuffer(mGrContext.get(), buffer->toAHardwareBuffer(),
+ GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
+ SkColorSpace::MakeSRGB(), nullptr);
+ if (useFramebufferCache && surface) {
+ ALOGD("Adding to cache");
+ mSurfaceCache.insert({buffer->getId(), surface});
+ }
+ }
+ if (!surface) {
+ ALOGE("Failed to make surface");
+ return BAD_VALUE;
+ }
+ auto canvas = surface->getCanvas();
+ canvas->save();
+
+ // Before doing any drawing, let's make sure that we'll start at the origin of the display.
+ // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
+ // displays might have different scaling when compared to the physical screen.
+ canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
+ const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
+ static_cast<SkScalar>(display.clip.width());
+ const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
+ static_cast<SkScalar>(display.clip.height());
+ canvas->scale(scaleX, scaleY);
+ canvas->clipRect(getSkRect(display.clip));
+ canvas->drawColor(0, SkBlendMode::kSrc);
+ for (const auto& layer : layers) {
+ SkPaint paint;
+ const auto& bounds = layer->geometry.boundaries;
+ const auto dest = getSkRect(bounds);
+
+ if (layer->source.buffer.buffer) {
+ ATRACE_NAME("DrawImage");
+ const auto& item = layer->source.buffer;
+ sk_sp<SkImage> image;
+ auto iter = mImageCache.find(item.buffer->getId());
+ if (iter != mImageCache.end()) {
+ image = iter->second;
+ } else {
+ image = SkImage::MakeFromAHardwareBuffer(item.buffer->toAHardwareBuffer(),
+ item.usePremultipliedAlpha
+ ? kPremul_SkAlphaType
+ : kUnpremul_SkAlphaType);
+ mImageCache.insert({item.buffer->getId(), image});
+ }
+
+ SkMatrix matrix;
+ if (layer->geometry.roundedCornersRadius > 0) {
+ const auto roundedRect = getRoundedRect(layer);
+ matrix.setTranslate(roundedRect.getBounds().left() - dest.left(),
+ roundedRect.getBounds().top() - dest.top());
+ } else {
+ matrix.setIdentity();
+ }
+ paint.setShader(image->makeShader(matrix));
+ } else {
+ ATRACE_NAME("DrawColor");
+ const auto color = layer->source.solidColor;
+ paint.setColor(SkColor4f{.fR = color.r, .fG = color.g, .fB = color.b, layer->alpha});
+ }
+
+ // Layers have a local transform matrix that should be applied to them.
+ canvas->save();
+ canvas->concat(getSkM44(layer->geometry.positionTransform));
+
+ if (layer->shadow.length > 0) {
+ const auto rect = layer->geometry.roundedCornersRadius > 0
+ ? getSkRect(layer->geometry.roundedCornersCrop)
+ : dest;
+ drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
+ }
+
+ if (layer->geometry.roundedCornersRadius > 0) {
+ canvas->drawRRect(getRoundedRect(layer), paint);
+ } else {
+ canvas->drawRect(dest, paint);
+ }
+ canvas->restore();
+ }
+ {
+ ATRACE_NAME("flush surface");
+ surface->flush();
+ }
+ canvas->restore();
+
+ if (drawFence != nullptr) {
+ *drawFence = flush();
+ }
+
+ // If flush failed or we don't support native fences, we need to force the
+ // gl command stream to be executed.
+ bool requireSync = drawFence == nullptr || drawFence->get() < 0;
+ if (requireSync) {
+ ATRACE_BEGIN("Submit(sync=true)");
+ } else {
+ ATRACE_BEGIN("Submit(sync=false)");
+ }
+ bool success = mGrContext->submit(requireSync);
+ ATRACE_END();
+ if (!success) {
+ ALOGE("Failed to flush RenderEngine commands");
+ // Chances are, something illegal happened (either the caller passed
+ // us bad parameters, or we messed up our shader generation).
+ return INVALID_OPERATION;
+ }
+
+ // checkErrors();
+ return NO_ERROR;
+}
+
+inline SkRect SkiaGLRenderEngine::getSkRect(const FloatRect& rect) {
+ return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
+}
+
+inline SkRect SkiaGLRenderEngine::getSkRect(const Rect& rect) {
+ return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
+}
+
+inline SkRRect SkiaGLRenderEngine::getRoundedRect(const LayerSettings* layer) {
+ const auto rect = getSkRect(layer->geometry.roundedCornersCrop);
+ const auto cornerRadius = layer->geometry.roundedCornersRadius;
+ return SkRRect::MakeRectXY(rect, cornerRadius, cornerRadius);
+}
+
+inline SkColor SkiaGLRenderEngine::getSkColor(const vec4& color) {
+ return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255);
+}
+
+inline SkM44 SkiaGLRenderEngine::getSkM44(const mat4& matrix) {
+ return SkM44(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],
+ matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],
+ matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2],
+ matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);
+}
+
+inline SkPoint3 SkiaGLRenderEngine::getSkPoint3(const vec3& vector) {
+ return SkPoint3::Make(vector.x, vector.y, vector.z);
+}
+
+size_t SkiaGLRenderEngine::getMaxTextureSize() const {
+ return mGrContext->maxTextureSize();
+}
+
+size_t SkiaGLRenderEngine::getMaxViewportDims() const {
+ return mGrContext->maxRenderTargetSize();
+}
+
+void SkiaGLRenderEngine::drawShadow(SkCanvas* canvas, const SkRect& casterRect, float cornerRadius,
+ const ShadowSettings& settings) {
+ ATRACE_CALL();
+ const float casterZ = settings.length / 2.0f;
+ const auto shadowShape = cornerRadius > 0
+ ? SkPath::RRect(SkRRect::MakeRectXY(casterRect, cornerRadius, cornerRadius))
+ : SkPath::Rect(casterRect);
+ const auto flags =
+ settings.casterIsTranslucent ? kTransparentOccluder_ShadowFlag : kNone_ShadowFlag;
+
+ SkShadowUtils::DrawShadow(canvas, shadowShape, SkPoint3::Make(0, 0, casterZ),
+ getSkPoint3(settings.lightPos), settings.lightRadius,
+ getSkColor(settings.ambientColor), getSkColor(settings.spotColor),
+ flags);
+}
+
+EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
+ EGLContext shareContext, bool useContextPriority,
+ Protection protection) {
+ EGLint renderableType = 0;
+ if (config == EGL_NO_CONFIG_KHR) {
+ renderableType = EGL_OPENGL_ES3_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_ES3_BIT) {
+ contextClientVersion = 3;
+ } else 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(7);
+ 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);
+ }
+ if (protection == Protection::PROTECTED) {
+ contextAttributes.push_back(EGL_PROTECTED_CONTENT_EXT);
+ contextAttributes.push_back(EGL_TRUE);
+ }
+ contextAttributes.push_back(EGL_NONE);
+
+ EGLContext context = eglCreateContext(display, config, shareContext, contextAttributes.data());
+
+ if (contextClientVersion == 3 && context == EGL_NO_CONTEXT) {
+ // eglGetConfigAttrib indicated we can create GLES 3 context, but we failed, thus
+ // EGL_NO_CONTEXT so that we can abort.
+ if (config != EGL_NO_CONFIG_KHR) {
+ return context;
+ }
+ // If |config| is EGL_NO_CONFIG_KHR, we speculatively try to create GLES 3 context, so we
+ // should try to fall back to GLES 2.
+ contextAttributes[1] = 2;
+ context = eglCreateContext(display, config, shareContext, contextAttributes.data());
+ }
+
+ return context;
+}
+
+EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay display,
+ EGLConfig config, int hwcFormat,
+ Protection protection) {
+ EGLConfig placeholderConfig = config;
+ if (placeholderConfig == EGL_NO_CONFIG_KHR) {
+ placeholderConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+ }
+ std::vector<EGLint> attributes;
+ attributes.reserve(7);
+ attributes.push_back(EGL_WIDTH);
+ attributes.push_back(1);
+ attributes.push_back(EGL_HEIGHT);
+ attributes.push_back(1);
+ if (protection == Protection::PROTECTED) {
+ attributes.push_back(EGL_PROTECTED_CONTENT_EXT);
+ attributes.push_back(EGL_TRUE);
+ }
+ attributes.push_back(EGL_NONE);
+
+ return eglCreatePbufferSurface(display, placeholderConfig, attributes.data());
+}
+
+void SkiaGLRenderEngine::cleanFramebufferCache() {
+ mSurfaceCache.clear();
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
new file mode 100644
index 0000000..3da7f25
--- /dev/null
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SF_SKIAGLRENDERENGINE_H_
+#define SF_SKIAGLRENDERENGINE_H_
+
+#include <sys/types.h>
+#include <mutex>
+#include <unordered_map>
+
+#include <android-base/thread_annotations.h>
+#include <renderengine/RenderEngine.h>
+
+#include <GrDirectContext.h>
+#include <SkSurface.h>
+
+#include "SkiaRenderEngine.h"
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+class SkiaGLRenderEngine : public skia::SkiaRenderEngine {
+public:
+ static std::unique_ptr<SkiaGLRenderEngine> create(const RenderEngineCreationArgs& args);
+ SkiaGLRenderEngine(EGLDisplay display, EGLConfig config, EGLContext ctxt,
+ EGLSurface placeholder, EGLContext protectedContext,
+ EGLSurface protectedPlaceholder);
+ ~SkiaGLRenderEngine() override{};
+
+ void unbindExternalTextureBuffer(uint64_t bufferId) override;
+ status_t drawLayers(const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
+ const sp<GraphicBuffer>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
+ void cleanFramebufferCache() override;
+
+protected:
+ void dump(std::string& /*result*/) override{};
+ size_t getMaxTextureSize() const override;
+ size_t getMaxViewportDims() const override;
+
+private:
+ static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
+ static EGLContext createEglContext(EGLDisplay display, EGLConfig config,
+ EGLContext shareContext, bool useContextPriority,
+ Protection protection);
+ static EGLSurface createPlaceholderEglPbufferSurface(EGLDisplay display, EGLConfig config,
+ int hwcFormat, Protection protection);
+ inline SkRect getSkRect(const FloatRect& layer);
+ inline SkRect getSkRect(const Rect& layer);
+ inline SkRRect getRoundedRect(const LayerSettings* layer);
+ inline SkColor getSkColor(const vec4& color);
+ inline SkM44 getSkM44(const mat4& matrix);
+ inline SkPoint3 getSkPoint3(const vec3& vector);
+
+ base::unique_fd flush();
+ bool waitFence(base::unique_fd fenceFd);
+ void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
+ const ShadowSettings& shadowSettings);
+
+ EGLDisplay mEGLDisplay;
+ EGLConfig mEGLConfig;
+ EGLContext mEGLContext;
+ EGLSurface mPlaceholderSurface;
+ EGLContext mProtectedEGLContext;
+ EGLSurface mProtectedPlaceholderSurface;
+
+ // Cache of GL images that we'll store per GraphicBuffer ID
+ std::unordered_map<uint64_t, sk_sp<SkImage>> mImageCache GUARDED_BY(mRenderingMutex);
+ // Mutex guarding rendering operations, so that:
+ // 1. GL operations aren't interleaved, and
+ // 2. Internal state related to rendering that is potentially modified by
+ // multiple threads is guaranteed thread-safe.
+ std::mutex mRenderingMutex;
+
+ sp<Fence> mLastDrawFence;
+
+ sk_sp<GrDirectContext> mGrContext;
+
+ std::unordered_map<uint64_t, sk_sp<SkSurface>> mSurfaceCache;
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
+
+#endif /* SF_GLESRENDERENGINE_H_ */
\ No newline at end of file
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
new file mode 100644
index 0000000..81f0b6f
--- /dev/null
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+namespace android {
+namespace renderengine {
+namespace skia {} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
new file mode 100644
index 0000000..2352c7e
--- /dev/null
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SF_SKIARENDERENGINE_H_
+#define SF_SKIARENDERENGINE_H_
+
+#include <renderengine/RenderEngine.h>
+#include <sys/types.h>
+
+namespace android {
+
+namespace renderengine {
+
+class Mesh;
+class Texture;
+
+namespace skia {
+
+class BlurFilter;
+
+// TODO: Put common skia stuff here that can be shared between the GL & Vulkan backends
+// Currently mostly just handles all the no-op / missing APIs
+class SkiaRenderEngine : public RenderEngine {
+public:
+ static std::unique_ptr<SkiaRenderEngine> create(const RenderEngineCreationArgs& args);
+ ~SkiaRenderEngine() override {}
+
+ virtual void primeCache() const override{};
+ virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override{};
+ virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{};
+ virtual void cacheExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/){};
+ virtual void unbindExternalTextureBuffer(uint64_t /*bufferId*/){};
+
+ virtual bool isProtected() const override { return false; } // mInProtectedContext; }
+ virtual bool supportsProtectedContent() const override { return false; };
+ virtual bool useProtectedContext(bool /*useProtectedContext*/) override { return false; };
+ virtual status_t drawLayers(const DisplaySettings& /*display*/,
+ const std::vector<const LayerSettings*>& /*layers*/,
+ const sp<GraphicBuffer>& /*buffer*/,
+ const bool /*useFramebufferCache*/,
+ base::unique_fd&& /*bufferFence*/,
+ base::unique_fd* /*drawFence*/) override {
+ return 0;
+ };
+ virtual bool cleanupPostRender(CleanupMode) override { return true; };
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
+
+#endif /* SF_GLESRENDERENGINE_H_ */
\ No newline at end of file
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index c92e817..d795616 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -1242,31 +1242,6 @@
EXPECT_EQ(NO_ERROR, barrier->result);
}
-TEST_F(RenderEngineTest, bindExternalBuffer_withNullBuffer) {
- status_t result = sRE->bindExternalTextureBuffer(0, nullptr, nullptr);
- ASSERT_EQ(BAD_VALUE, result);
-}
-
-TEST_F(RenderEngineTest, bindExternalBuffer_cachesImages) {
- sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
- uint32_t texName;
- sRE->genTextures(1, &texName);
- mTexNames.push_back(texName);
-
- sRE->bindExternalTextureBuffer(texName, buf, nullptr);
- uint64_t bufferId = buf->getId();
- EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
- std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
- sRE->unbindExternalTextureBufferForTesting(bufferId);
- std::lock_guard<std::mutex> lock(barrier->mutex);
- ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
- [&]() REQUIRES(barrier->mutex) {
- return barrier->isOpen;
- }));
- EXPECT_EQ(NO_ERROR, barrier->result);
- EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
-}
-
TEST_F(RenderEngineTest, cacheExternalBuffer_withNullBuffer) {
std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
sRE->cacheExternalTextureBufferForTesting(nullptr);
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 78fec29..ba5175d 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -62,21 +62,6 @@
mThreadedRE->deleteTextures(1, &texName);
}
-TEST_F(RenderEngineThreadedTest, bindExternalBuffer_nullptrBuffer) {
- EXPECT_CALL(*mRenderEngine, bindExternalTextureBuffer(0, Eq(nullptr), Eq(nullptr)))
- .WillOnce(Return(BAD_VALUE));
- status_t result = mThreadedRE->bindExternalTextureBuffer(0, nullptr, nullptr);
- ASSERT_EQ(BAD_VALUE, result);
-}
-
-TEST_F(RenderEngineThreadedTest, bindExternalBuffer_withBuffer) {
- sp<GraphicBuffer> buf = new GraphicBuffer();
- EXPECT_CALL(*mRenderEngine, bindExternalTextureBuffer(0, buf, Eq(nullptr)))
- .WillOnce(Return(NO_ERROR));
- status_t result = mThreadedRE->bindExternalTextureBuffer(0, buf, nullptr);
- ASSERT_EQ(NO_ERROR, result);
-}
-
TEST_F(RenderEngineThreadedTest, cacheExternalTextureBuffer_nullptr) {
EXPECT_CALL(*mRenderEngine, cacheExternalTextureBuffer(Eq(nullptr)));
mThreadedRE->cacheExternalTextureBuffer(nullptr);
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 9b79943..5453302 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -116,21 +116,6 @@
result.assign(resultFuture.get());
}
-bool RenderEngineThreaded::useNativeFenceSync() const {
- std::promise<bool> resultPromise;
- std::future<bool> resultFuture = resultPromise.get_future();
- {
- std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& /*instance*/) {
- ATRACE_NAME("REThreaded::useNativeFenceSync");
- bool returnValue = SyncFeatures::getInstance().useNativeFenceSync();
- resultPromise.set_value(returnValue);
- });
- }
- mCondition.notify_one();
- return resultFuture.get();
-}
-
void RenderEngineThreaded::genTextures(size_t count, uint32_t* names) {
std::promise<void> resultPromise;
std::future<void> resultFuture = resultPromise.get_future();
@@ -161,24 +146,6 @@
resultFuture.wait();
}
-status_t RenderEngineThreaded::bindExternalTextureBuffer(uint32_t texName,
- const sp<GraphicBuffer>& buffer,
- const sp<Fence>& fence) {
- std::promise<status_t> resultPromise;
- std::future<status_t> resultFuture = resultPromise.get_future();
- {
- std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push(
- [&resultPromise, texName, &buffer, &fence](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::bindExternalTextureBuffer");
- status_t status = instance.bindExternalTextureBuffer(texName, buffer, fence);
- resultPromise.set_value(status);
- });
- }
- mCondition.notify_one();
- return resultFuture.get();
-}
-
void RenderEngineThreaded::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
std::promise<void> resultPromise;
std::future<void> resultFuture = resultPromise.get_future();
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index b02cdd9..cdfbd04 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -45,11 +45,8 @@
void dump(std::string& result) override;
- bool useNativeFenceSync() const override;
void genTextures(size_t count, uint32_t* names) override;
void deleteTextures(size_t count, uint32_t const* names) override;
- status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
- const sp<Fence>& fence) override;
void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override;
void unbindExternalTextureBuffer(uint64_t bufferId) override;
size_t getMaxTextureSize() const override;
diff --git a/libs/ui/PublicFormat.cpp b/libs/ui/PublicFormat.cpp
index 70e3ce7..a6595cf 100644
--- a/libs/ui/PublicFormat.cpp
+++ b/libs/ui/PublicFormat.cpp
@@ -35,6 +35,8 @@
case PublicFormat::RAW_SENSOR:
case PublicFormat::RAW_DEPTH:
return HAL_PIXEL_FORMAT_RAW16;
+ case PublicFormat::RAW_DEPTH10:
+ return HAL_PIXEL_FORMAT_RAW10;
default:
// Most formats map 1:1
return static_cast<int>(f);
@@ -50,6 +52,7 @@
case PublicFormat::DEPTH_POINT_CLOUD:
case PublicFormat::DEPTH16:
case PublicFormat::RAW_DEPTH:
+ case PublicFormat::RAW_DEPTH10:
dataspace = Dataspace::DEPTH;
break;
case PublicFormat::RAW_SENSOR:
@@ -80,6 +83,13 @@
PublicFormat mapHalFormatDataspaceToPublicFormat(int format, android_dataspace dataSpace) {
Dataspace ds = static_cast<Dataspace>(dataSpace);
switch (format) {
+ case HAL_PIXEL_FORMAT_RAW10:
+ switch (ds) {
+ case Dataspace::DEPTH:
+ return PublicFormat::RAW_DEPTH10;
+ default:
+ return PublicFormat::RAW10;
+ }
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
case HAL_PIXEL_FORMAT_RGBA_FP16:
@@ -87,7 +97,6 @@
case HAL_PIXEL_FORMAT_RGB_888:
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_Y8:
- case HAL_PIXEL_FORMAT_RAW10:
case HAL_PIXEL_FORMAT_RAW12:
case HAL_PIXEL_FORMAT_YCbCr_420_888:
case HAL_PIXEL_FORMAT_YV12:
diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp
index ec8a78a..cd68c1c 100644
--- a/libs/ui/Transform.cpp
+++ b/libs/ui/Transform.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#undef LOG_TAG
+#define LOG_TAG "Transform"
+
#include <math.h>
#include <android-base/stringprintf.h>
@@ -132,7 +135,7 @@
}
float Transform::getScaleX() const {
- return sqrt(dsdx() * dsdx()) + (dtdx() * dtdx());
+ return sqrt((dsdx() * dsdx()) + (dtdx() * dtdx()));
}
float Transform::getScaleY() const {
diff --git a/libs/ui/include/ui/PublicFormat.h b/libs/ui/include/ui/PublicFormat.h
index 1152cc5..22274a2 100644
--- a/libs/ui/include/ui/PublicFormat.h
+++ b/libs/ui/include/ui/PublicFormat.h
@@ -50,6 +50,7 @@
JPEG = 0x100,
DEPTH_POINT_CLOUD = 0x101,
RAW_DEPTH = 0x1002, // @hide
+ RAW_DEPTH10 = 0x1003, // @hide
YV12 = 0x32315659,
Y8 = 0x20203859,
Y16 = 0x20363159, // @hide
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index 9a434e5..a197b3b 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -111,7 +111,7 @@
void dump(std::string& result, const char* name, const char* prefix = "") const;
void dump(const char* name, const char* prefix = "") const;
- static RotationFlags toRotationFlags(Rotation);
+ static constexpr RotationFlags toRotationFlags(Rotation);
private:
struct mat33 {
@@ -136,7 +136,7 @@
*os << out;
}
-inline Transform::RotationFlags Transform::toRotationFlags(Rotation rotation) {
+inline constexpr Transform::RotationFlags Transform::toRotationFlags(Rotation rotation) {
switch (rotation) {
case ROTATION_0:
return ROT_0;
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index 1bcaab4..9a9bca1 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -44,11 +44,11 @@
defaults: ["libgpuservice_defaults"],
cflags: [
"-fvisibility=hidden",
- "-fwhole-program-vtables", // requires ThinLTO
],
lto: {
thin: true,
},
+ whole_program_vtables: true, // Requires ThinLTO
}
filegroup {
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 8af9bcb..3d99589 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -31,6 +31,25 @@
namespace android {
+static int32_t exceptionCodeFromStatusT(status_t status) {
+ switch (status) {
+ case OK:
+ return binder::Status::EX_NONE;
+ case INVALID_OPERATION:
+ return binder::Status::EX_UNSUPPORTED_OPERATION;
+ case BAD_VALUE:
+ case BAD_TYPE:
+ case NAME_NOT_FOUND:
+ return binder::Status::EX_ILLEGAL_ARGUMENT;
+ case NO_INIT:
+ return binder::Status::EX_ILLEGAL_STATE;
+ case PERMISSION_DENIED:
+ return binder::Status::EX_SECURITY;
+ default:
+ return binder::Status::EX_TRANSACTION_FAILED;
+ }
+}
+
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
@@ -119,7 +138,7 @@
}
// Used by tests only.
-binder::Status InputManager::registerInputChannel(const InputChannel& channel) {
+binder::Status InputManager::createInputChannel(const std::string& name, InputChannel* outChannel) {
IPCThreadState* ipc = IPCThreadState::self();
const int uid = ipc->getCallingUid();
if (uid != AID_SHELL && uid != AID_ROOT) {
@@ -128,12 +147,17 @@
return binder::Status::ok();
}
- mDispatcher->registerInputChannel(channel.dup());
+ base::Result<std::unique_ptr<InputChannel>> channel = mDispatcher->createInputChannel(name);
+ if (!channel) {
+ return binder::Status::fromExceptionCode(exceptionCodeFromStatusT(channel.error().code()),
+ channel.error().message().c_str());
+ }
+ (*channel)->copyTo(*outChannel);
return binder::Status::ok();
}
-binder::Status InputManager::unregisterInputChannel(const sp<IBinder>& connectionToken) {
- mDispatcher->unregisterInputChannel(connectionToken);
+binder::Status InputManager::removeInputChannel(const sp<IBinder>& connectionToken) {
+ mDispatcher->removeInputChannel(connectionToken);
return binder::Status::ok();
}
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 35d2d58..49bea13 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -108,8 +108,8 @@
const std::vector<InputWindowInfo>& handles,
const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
- binder::Status registerInputChannel(const InputChannel& channel) override;
- binder::Status unregisterInputChannel(const sp<IBinder>& connectionToken) override;
+ binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
+ binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override;
binder::Status setFocusedWindow(const FocusRequest&) override;
private:
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index b645d69..46bc055 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -129,17 +129,14 @@
protected:
explicit FakeInputReceiver(const sp<InputDispatcher>& dispatcher, const std::string name)
: mDispatcher(dispatcher) {
- std::unique_ptr<InputChannel> serverChannel, clientChannel;
- InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
- mServerChannel = std::move(serverChannel);
- mClientChannel = std::move(clientChannel);
+ mClientChannel = *mDispatcher->createInputChannel(name);
mConsumer = std::make_unique<InputConsumer>(mClientChannel);
}
virtual ~FakeInputReceiver() {}
sp<InputDispatcher> mDispatcher;
- std::shared_ptr<InputChannel> mServerChannel, mClientChannel;
+ std::shared_ptr<InputChannel> mClientChannel;
std::unique_ptr<InputConsumer> mConsumer;
PreallocatedInputEventFactory mEventFactory;
};
@@ -152,14 +149,12 @@
FakeWindowHandle(const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
const sp<InputDispatcher>& dispatcher, const std::string name)
: FakeInputReceiver(dispatcher, name), mFrame(Rect(0, 0, WIDTH, HEIGHT)) {
- mDispatcher->registerInputChannel(mServerChannel);
-
inputApplicationHandle->updateInfo();
mInfo.applicationInfo = *inputApplicationHandle->getInfo();
}
virtual bool updateInfo() override {
- mInfo.token = mServerChannel->getConnectionToken();
+ mInfo.token = mClientChannel->getConnectionToken();
mInfo.name = "FakeWindowHandle";
mInfo.type = InputWindowInfo::Type::APPLICATION;
mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6460fe9..3ccb0c9 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -28,8 +28,8 @@
// Log debug messages about the dispatch cycle.
#define DEBUG_DISPATCH_CYCLE 0
-// Log debug messages about registrations.
-#define DEBUG_REGISTRATION 0
+// Log debug messages about channel creation
+#define DEBUG_CHANNEL_CREATION 0
// Log debug messages about input event injection.
#define DEBUG_INJECTION 0
@@ -351,6 +351,16 @@
}
}
+static status_t openInputChannelPair(const std::string& name,
+ std::shared_ptr<InputChannel>& serverChannel,
+ std::unique_ptr<InputChannel>& clientChannel) {
+ std::unique_ptr<InputChannel> uniqueServerChannel;
+ status_t result = InputChannel::openInputChannelPair(name, uniqueServerChannel, clientChannel);
+
+ serverChannel = std::move(uniqueServerChannel);
+ return result;
+}
+
const char* InputDispatcher::typeToString(InputDispatcher::FocusResult result) {
switch (result) {
case InputDispatcher::FocusResult::OK:
@@ -364,6 +374,17 @@
}
}
+template <typename T>
+static bool sharedPointersEqual(const std::shared_ptr<T>& lhs, const std::shared_ptr<T>& rhs) {
+ if (lhs == nullptr && rhs == nullptr) {
+ return true;
+ }
+ if (lhs == nullptr || rhs == nullptr) {
+ return false;
+ }
+ return *lhs == *rhs;
+}
+
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -401,7 +422,7 @@
while (!mConnectionsByFd.empty()) {
sp<Connection> connection = mConnectionsByFd.begin()->second;
- unregisterInputChannel(connection->inputChannel->getConnectionToken());
+ removeInputChannel(connection->inputChannel->getConnectionToken());
}
}
@@ -496,7 +517,7 @@
connection->responsive = false;
// Stop waking up for this unresponsive connection
mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken());
- onAnrLocked(connection);
+ onAnrLocked(*connection);
return LONG_LONG_MIN;
}
@@ -1097,11 +1118,17 @@
(entry->policyFlags & POLICY_FLAG_TRUSTED) &&
(!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) {
if (mKeyRepeatState.lastKeyEntry &&
- mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
+ mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode &&
// We have seen two identical key downs in a row which indicates that the device
// driver is automatically generating key repeats itself. We take note of the
// repeat here, but we disable our own next key repeat timer since it is clear that
// we will not need to synthesize key repeats ourselves.
+ mKeyRepeatState.lastKeyEntry->deviceId == entry->deviceId) {
+ // Make sure we don't get key down from a different device. If a different
+ // device Id has same key pressed down, the new device Id will replace the
+ // current one to hold the key repeat with repeat count reset.
+ // In the future when got a KEY_UP on the device id, drop it and do not
+ // stop the key repeat on current device.
entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1;
resetKeyRepeatLocked();
mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves
@@ -1112,6 +1139,12 @@
}
mKeyRepeatState.lastKeyEntry = entry;
entry->refCount += 1;
+ } else if (entry->action == AKEY_EVENT_ACTION_UP && mKeyRepeatState.lastKeyEntry &&
+ mKeyRepeatState.lastKeyEntry->deviceId != entry->deviceId) {
+ // The stale device releases the key, reset staleDeviceId.
+#if DEBUG_INBOUND_EVENT_DETAILS
+ ALOGD("deviceId=%d got KEY_UP as stale", entry->deviceId);
+#endif
} else if (!entry->syntheticRepeat) {
resetKeyRepeatLocked();
}
@@ -2814,8 +2847,8 @@
}
}
- // Unregister the channel.
- d->unregisterInputChannelLocked(connection->inputChannel->getConnectionToken(), notify);
+ // Remove the channel.
+ d->removeInputChannelLocked(connection->inputChannel->getConnectionToken(), notify);
return 0; // remove the callback
} // release lock
}
@@ -3885,31 +3918,26 @@
ALOGD("setFocusedApplication displayId=%" PRId32 " %s", displayId,
inputApplicationHandle ? inputApplicationHandle->getName().c_str() : "<nullptr>");
}
- if (inputApplicationHandle != nullptr &&
- inputApplicationHandle->getApplicationToken() != nullptr) {
- // acquire lock
+ { // acquire lock
std::scoped_lock _l(mLock);
std::shared_ptr<InputApplicationHandle> oldFocusedApplicationHandle =
getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
- // If oldFocusedApplicationHandle already exists
- if (oldFocusedApplicationHandle != nullptr) {
- // If a new focused application handle is different from the old one and
- // old focus application info is awaited focused application info.
- if (*oldFocusedApplicationHandle != *inputApplicationHandle &&
- mAwaitedFocusedApplication != nullptr &&
- *oldFocusedApplicationHandle == *mAwaitedFocusedApplication) {
- resetNoFocusedWindowTimeoutLocked();
- }
- // Erase the old application from container first
- mFocusedApplicationHandlesByDisplay.erase(displayId);
- // Should already get freed after removed from container but just double check.
- oldFocusedApplicationHandle.reset();
+ if (sharedPointersEqual(oldFocusedApplicationHandle, inputApplicationHandle)) {
+ return; // This application is already focused. No need to wake up or change anything.
}
// Set the new application handle.
- mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
+ if (inputApplicationHandle != nullptr) {
+ mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
+ } else {
+ mFocusedApplicationHandlesByDisplay.erase(displayId);
+ }
+
+ // No matter what the old focused application was, stop waiting on it because it is
+ // no longer focused.
+ resetNoFocusedWindowTimeoutLocked();
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
@@ -4234,6 +4262,7 @@
"hasWallpaper=%s, visible=%s, "
"flags=%s, type=0x%08x, "
"frame=[%d,%d][%d,%d], globalScale=%f, "
+ "applicationInfo=%s, "
"touchableRegion=",
i, windowInfo->name.c_str(), windowInfo->displayId,
windowInfo->portalToDisplayId,
@@ -4245,7 +4274,8 @@
static_cast<int32_t>(windowInfo->type),
windowInfo->frameLeft, windowInfo->frameTop,
windowInfo->frameRight, windowInfo->frameBottom,
- windowInfo->globalScaleFactor);
+ windowInfo->globalScaleFactor,
+ windowInfo->applicationInfo.name.c_str());
dumpRegion(dump, windowInfo->touchableRegion);
dump += StringPrintf(", inputFeatures=%s",
windowInfo->inputFeatures.string().c_str());
@@ -4395,71 +4425,76 @@
}
}
-status_t InputDispatcher::registerInputChannel(const std::shared_ptr<InputChannel>& inputChannel) {
-#if DEBUG_REGISTRATION
- ALOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().c_str());
+base::Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(
+ const std::string& name) {
+#if DEBUG_CHANNEL_CREATION
+ ALOGD("channel '%s' ~ createInputChannel", name.c_str());
#endif
+ std::shared_ptr<InputChannel> serverChannel;
+ std::unique_ptr<InputChannel> clientChannel;
+ status_t result = openInputChannelPair(name, serverChannel, clientChannel);
+
+ if (result) {
+ return base::Error(result) << "Failed to open input channel pair with name " << name;
+ }
+
{ // acquire lock
std::scoped_lock _l(mLock);
- sp<Connection> existingConnection = getConnectionLocked(inputChannel->getConnectionToken());
- if (existingConnection != nullptr) {
- ALOGW("Attempted to register already registered input channel '%s'",
- inputChannel->getName().c_str());
- return BAD_VALUE;
- }
+ sp<Connection> connection = new Connection(serverChannel, false /*monitor*/, mIdGenerator);
- sp<Connection> connection = new Connection(inputChannel, false /*monitor*/, mIdGenerator);
-
- int fd = inputChannel->getFd();
+ int fd = serverChannel->getFd();
mConnectionsByFd[fd] = connection;
- mInputChannelsByToken[inputChannel->getConnectionToken()] = inputChannel;
+ mInputChannelsByToken[serverChannel->getConnectionToken()] = serverChannel;
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
- return OK;
+ return clientChannel;
}
-status_t InputDispatcher::registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
- int32_t displayId, bool isGestureMonitor) {
+base::Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor(
+ int32_t displayId, bool isGestureMonitor, const std::string& name) {
+ std::shared_ptr<InputChannel> serverChannel;
+ std::unique_ptr<InputChannel> clientChannel;
+ status_t result = openInputChannelPair(name, serverChannel, clientChannel);
+ if (result) {
+ return base::Error(result) << "Failed to open input channel pair with name " << name;
+ }
+
{ // acquire lock
std::scoped_lock _l(mLock);
if (displayId < 0) {
- ALOGW("Attempted to register input monitor without a specified display.");
- return BAD_VALUE;
+ return base::Error(BAD_VALUE) << "Attempted to create input monitor with name " << name
+ << " without a specified display.";
}
- if (inputChannel->getConnectionToken() == nullptr) {
- ALOGW("Attempted to register input monitor without an identifying token.");
- return BAD_VALUE;
- }
+ sp<Connection> connection = new Connection(serverChannel, true /*monitor*/, mIdGenerator);
- sp<Connection> connection = new Connection(inputChannel, true /*monitor*/, mIdGenerator);
-
- const int fd = inputChannel->getFd();
+ const int fd = serverChannel->getFd();
mConnectionsByFd[fd] = connection;
- mInputChannelsByToken[inputChannel->getConnectionToken()] = inputChannel;
+ mInputChannelsByToken[serverChannel->getConnectionToken()] = serverChannel;
auto& monitorsByDisplay =
isGestureMonitor ? mGestureMonitorsByDisplay : mGlobalMonitorsByDisplay;
- monitorsByDisplay[displayId].emplace_back(inputChannel);
+ monitorsByDisplay[displayId].emplace_back(serverChannel);
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
}
+
// Wake the looper because some connections have changed.
mLooper->wake();
- return OK;
+ return clientChannel;
}
-status_t InputDispatcher::unregisterInputChannel(const sp<IBinder>& connectionToken) {
+status_t InputDispatcher::removeInputChannel(const sp<IBinder>& connectionToken) {
{ // acquire lock
std::scoped_lock _l(mLock);
- status_t status = unregisterInputChannelLocked(connectionToken, false /*notify*/);
+ status_t status = removeInputChannelLocked(connectionToken, false /*notify*/);
if (status) {
return status;
}
@@ -4471,8 +4506,8 @@
return OK;
}
-status_t InputDispatcher::unregisterInputChannelLocked(const sp<IBinder>& connectionToken,
- bool notify) {
+status_t InputDispatcher::removeInputChannelLocked(const sp<IBinder>& connectionToken,
+ bool notify) {
sp<Connection> connection = getConnectionLocked(connectionToken);
if (connection == nullptr) {
ALOGW("Attempted to unregister already unregistered input channel");
@@ -4635,12 +4670,12 @@
postCommandLocked(std::move(commandEntry));
}
-void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
+void InputDispatcher::onAnrLocked(const Connection& connection) {
// Since we are allowing the policy to extend the timeout, maybe the waitQueue
// is already healthy again. Don't raise ANR in this situation
- if (connection->waitQueue.empty()) {
+ if (connection.waitQueue.empty()) {
ALOGI("Not raising ANR because the connection %s has recovered",
- connection->inputChannel->getName().c_str());
+ connection.inputChannel->getName().c_str());
return;
}
/**
@@ -4651,21 +4686,21 @@
* processes the events linearly. So providing information about the oldest entry seems to be
* most useful.
*/
- DispatchEntry* oldestEntry = *connection->waitQueue.begin();
+ DispatchEntry* oldestEntry = *connection.waitQueue.begin();
const nsecs_t currentWait = now() - oldestEntry->deliveryTime;
std::string reason =
android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",
- connection->inputChannel->getName().c_str(),
+ connection.inputChannel->getName().c_str(),
ns2ms(currentWait),
oldestEntry->eventEntry->getDescription().c_str());
- updateLastAnrStateLocked(getWindowHandleLocked(connection->inputChannel->getConnectionToken()),
+ updateLastAnrStateLocked(getWindowHandleLocked(connection.inputChannel->getConnectionToken()),
reason);
std::unique_ptr<CommandEntry> commandEntry =
std::make_unique<CommandEntry>(&InputDispatcher::doNotifyAnrLockedInterruptible);
commandEntry->inputApplicationHandle = nullptr;
- commandEntry->inputChannel = connection->inputChannel;
+ commandEntry->inputChannel = connection.inputChannel;
commandEntry->reason = std::move(reason);
postCommandLocked(std::move(commandEntry));
}
@@ -4765,15 +4800,15 @@
void InputDispatcher::extendAnrTimeoutsLocked(
const std::shared_ptr<InputApplicationHandle>& application,
const sp<IBinder>& connectionToken, std::chrono::nanoseconds timeoutExtension) {
+ if (connectionToken == nullptr && application != nullptr) {
+ // The ANR happened because there's no focused window
+ mNoFocusedWindowTimeoutTime = now() + timeoutExtension.count();
+ mAwaitedFocusedApplication = application;
+ }
+
sp<Connection> connection = getConnectionLocked(connectionToken);
if (connection == nullptr) {
- if (mNoFocusedWindowTimeoutTime.has_value() && application != nullptr) {
- // Maybe ANR happened because there's no focused window?
- mNoFocusedWindowTimeoutTime = now() + timeoutExtension.count();
- mAwaitedFocusedApplication = application;
- } else {
- // It's also possible that the connection already disappeared. No action necessary.
- }
+ // It's possible that the connection already disappeared. No action necessary.
return;
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index f3b3dda..4fcdcc2 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -116,12 +116,12 @@
virtual bool transferTouchFocus(const sp<IBinder>& fromToken,
const sp<IBinder>& toToken) override;
- virtual status_t registerInputChannel(
- const std::shared_ptr<InputChannel>& inputChannel) override;
+ virtual base::Result<std::unique_ptr<InputChannel>> createInputChannel(
+ const std::string& name) override;
virtual void setFocusedWindow(const FocusRequest&) override;
- virtual status_t registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
- int32_t displayId, bool isGestureMonitor) override;
- virtual status_t unregisterInputChannel(const sp<IBinder>& connectionToken) override;
+ virtual base::Result<std::unique_ptr<InputChannel>> createInputMonitor(
+ int32_t displayId, bool isGestureMonitor, const std::string& name) override;
+ virtual status_t removeInputChannel(const sp<IBinder>& connectionToken) override;
virtual status_t pilferPointers(const sp<IBinder>& token) override;
std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;
@@ -513,7 +513,7 @@
void removeMonitorChannelLocked(
const sp<IBinder>& connectionToken,
std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock);
- status_t unregisterInputChannelLocked(const sp<IBinder>& connectionToken, bool notify)
+ status_t removeInputChannelLocked(const sp<IBinder>& connectionToken, bool notify)
REQUIRES(mLock);
// Interesting events that we might like to log or tell the framework about.
@@ -525,7 +525,7 @@
int32_t displayId, std::string_view reason) REQUIRES(mLock);
void notifyFocusChangedLocked(const sp<IBinder>& oldFocus, const sp<IBinder>& newFocus)
REQUIRES(mLock);
- void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
+ void onAnrLocked(const Connection& connection) REQUIRES(mLock);
void onAnrLocked(const std::shared_ptr<InputApplicationHandle>& application) REQUIRES(mLock);
void updateLastAnrStateLocked(const sp<InputWindowHandle>& window, const std::string& reason)
REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index c3d50ea..67d9a06 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -18,6 +18,7 @@
#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H
#include <InputListener.h>
+#include <android-base/result.h>
#include <android/FocusRequest.h>
#include <android/os/ISetInputWindowsListener.h>
#include <input/InputApplication.h>
@@ -155,13 +156,16 @@
*/
virtual void setFocusedWindow(const FocusRequest&) = 0;
- /* Registers input channels that may be used as targets for input events.
+ /**
+ * Creates an input channel that may be used as targets for input events.
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual status_t registerInputChannel(const std::shared_ptr<InputChannel>& inputChannel) = 0;
+ virtual base::Result<std::unique_ptr<InputChannel>> createInputChannel(
+ const std::string& name) = 0;
- /* Registers input channels to be used to monitor input events.
+ /**
+ * Creates an input channel to be used to monitor input events.
*
* Each monitor must target a specific display and will only receive input events sent to that
* display. If the monitor is a gesture monitor, it will only receive pointer events on the
@@ -169,14 +173,14 @@
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual status_t registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
- int32_t displayId, bool gestureMonitor) = 0;
+ virtual base::Result<std::unique_ptr<InputChannel>> createInputMonitor(
+ int32_t displayId, bool gestureMonitor, const std::string& name) = 0;
- /* Unregister input channels that will no longer receive input events.
+ /* Removes input channels that will no longer receive input events.
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual status_t unregisterInputChannel(const sp<IBinder>& connectionToken) = 0;
+ virtual status_t removeInputChannel(const sp<IBinder>& connectionToken) = 0;
/* Allows an input monitor steal the current pointer stream away from normal input windows.
*
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
index cabc782..2ebdbcf 100644
--- a/services/inputflinger/host/InputDriver.cpp
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -36,7 +36,7 @@
#define INDENT2 " "
struct input_property_map {
- android::PropertyMap* propertyMap;
+ std::unique_ptr<android::PropertyMap> propertyMap;
};
struct input_property {
@@ -225,16 +225,17 @@
ALOGD("No input device configuration file found for device '%s'.",
idi.name.c_str());
} else {
- auto propMap = new input_property_map_t();
- status_t status = PropertyMap::load(String8(configFile.c_str()), &propMap->propertyMap);
- if (status) {
+ std::unique_ptr<input_property_map_t> propMap = std::make_unique<input_property_map_t>();
+ android::base::Result<std::unique_ptr<PropertyMap>> result =
+ PropertyMap::load(configFile.c_str());
+ if (!result.ok()) {
ALOGE("Error loading input device configuration file for device '%s'. "
"Using default configuration.",
idi.name.c_str());
- delete propMap;
return nullptr;
}
- return propMap;
+ propMap->propertyMap = std::move(*result);
+ return propMap.release();
}
return nullptr;
}
@@ -278,7 +279,6 @@
void InputDriver::inputFreeDevicePropertyMap(input_property_map_t* map) {
if (map != nullptr) {
- delete map->propertyMap;
delete map;
}
}
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 577309a..47773d9 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -48,8 +48,10 @@
const sp<ISetInputWindowsListener>&) {
return binder::Status::ok();
}
- binder::Status registerInputChannel(const InputChannel&) { return binder::Status::ok(); }
- binder::Status unregisterInputChannel(const sp<IBinder>&) { return binder::Status::ok(); }
+ binder::Status createInputChannel(const std::string&, InputChannel*) {
+ return binder::Status::ok();
+ }
+ binder::Status removeInputChannel(const sp<IBinder>&) { return binder::Status::ok(); }
binder::Status setFocusedWindow(const FocusRequest&) { return binder::Status::ok(); }
private:
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 67d3cc2..c5210b5 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -280,14 +280,14 @@
if (configurationFile.empty()) {
ALOGD("No input device configuration file found for device '%s'.", identifier.name.c_str());
} else {
- PropertyMap* propertyMap;
- status_t status = PropertyMap::load(String8(configurationFile.c_str()), &propertyMap);
- if (status) {
+ android::base::Result<std::unique_ptr<PropertyMap>> propertyMap =
+ PropertyMap::load(configurationFile.c_str());
+ if (!propertyMap.ok()) {
ALOGE("Error loading input device configuration file for device '%s'. "
"Using default configuration.",
identifier.name.c_str());
} else {
- configuration = std::unique_ptr<PropertyMap>(propertyMap);
+ configuration = std::move(*propertyMap);
}
}
}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index e867c6f..e957826 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -192,6 +192,20 @@
info->addMotionRange(mOrientedRanges.y);
info->addMotionRange(mOrientedRanges.pressure);
+ if (mDeviceMode == DeviceMode::UNSCALED && mSource == AINPUT_SOURCE_TOUCHPAD) {
+ // Populate RELATIVE_X and RELATIVE_Y motion ranges for touchpad capture mode.
+ //
+ // RELATIVE_X and RELATIVE_Y motion ranges should be the largest possible relative
+ // motion, i.e. the hardware dimensions, as the finger could move completely across the
+ // touchpad in one sample cycle.
+ const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
+ const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
+ info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -x.max, x.max, x.flat,
+ x.fuzz, x.resolution);
+ info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -y.max, y.max, y.flat,
+ y.fuzz, y.resolution);
+ }
+
if (mOrientedRanges.haveSize) {
info->addMotionRange(mOrientedRanges.size);
}
@@ -2610,14 +2624,14 @@
// Update the velocity tracker.
{
- VelocityTracker::Position positions[MAX_POINTERS];
- uint32_t count = 0;
- for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) {
+ std::vector<VelocityTracker::Position> positions;
+ for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty();) {
uint32_t id = idBits.clearFirstMarkedBit();
const RawPointerData::Pointer& pointer =
mCurrentRawState.rawPointerData.pointerForId(id);
- positions[count].x = pointer.x * mPointerXMovementScale;
- positions[count].y = pointer.y * mPointerYMovementScale;
+ float x = pointer.x * mPointerXMovementScale;
+ float y = pointer.y * mPointerYMovementScale;
+ positions.push_back({x, y});
}
mPointerGesture.velocityTracker.addMovement(when, mCurrentCookedState.fingerIdBits,
positions);
diff --git a/services/inputflinger/tests/IInputFlingerQuery.aidl b/services/inputflinger/tests/IInputFlingerQuery.aidl
index b5c5c9e..5c8a8da 100644
--- a/services/inputflinger/tests/IInputFlingerQuery.aidl
+++ b/services/inputflinger/tests/IInputFlingerQuery.aidl
@@ -26,4 +26,5 @@
void getInputWindows(out InputWindowInfo[] inputHandles);
void getInputChannels(out InputChannel[] channels);
void getLastFocusRequest(out FocusRequest request);
+ void resetInputManager();
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 6e08e1b..70f872a 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -152,6 +152,7 @@
const std::chrono::duration waited = std::chrono::steady_clock::now() - start;
if (mAnrApplications.empty() || mAnrWindowTokens.empty()) {
ADD_FAILURE() << "Did not receive ANR callback";
+ return {};
}
// Ensure that the ANR didn't get raised too early. We can't be too strict here because
// the dispatcher started counting before this function was called
@@ -548,10 +549,9 @@
class FakeInputReceiver {
public:
- explicit FakeInputReceiver(const std::shared_ptr<InputChannel>& clientChannel,
- const std::string name)
+ explicit FakeInputReceiver(std::unique_ptr<InputChannel> clientChannel, const std::string name)
: mName(name) {
- mConsumer = std::make_unique<InputConsumer>(clientChannel);
+ mConsumer = std::make_unique<InputConsumer>(std::move(clientChannel));
}
InputEvent* consume() {
@@ -701,11 +701,10 @@
int32_t displayId, std::optional<sp<IBinder>> token = std::nullopt)
: mName(name) {
if (token == std::nullopt) {
- std::unique_ptr<InputChannel> serverChannel, clientChannel;
- InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
- mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(clientChannel), name);
- token = serverChannel->getConnectionToken();
- dispatcher->registerInputChannel(std::move(serverChannel));
+ base::Result<std::unique_ptr<InputChannel>> channel =
+ dispatcher->createInputChannel(name);
+ token = (*channel)->getConnectionToken();
+ mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(*channel), name);
}
inputApplicationHandle->updateInfo();
@@ -1653,10 +1652,9 @@
public:
FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
int32_t displayId, bool isGestureMonitor = false) {
- std::unique_ptr<InputChannel> serverChannel, clientChannel;
- InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
- mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(clientChannel), name);
- dispatcher->registerInputMonitor(std::move(serverChannel), displayId, isGestureMonitor);
+ base::Result<std::unique_ptr<InputChannel>> channel =
+ dispatcher->createInputMonitor(displayId, isGestureMonitor, name);
+ mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(*channel), name);
}
sp<IBinder> getToken() { return mInputReceiver->getToken(); }
@@ -2144,8 +2142,9 @@
mWindow->consumeFocusEvent(true);
}
- void sendAndConsumeKeyDown() {
+ void sendAndConsumeKeyDown(int32_t deviceId) {
NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ keyArgs.deviceId = deviceId;
keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event
mDispatcher->notifyKey(&keyArgs);
@@ -2167,8 +2166,9 @@
EXPECT_EQ(repeatCount, repeatKeyEvent->getRepeatCount());
}
- void sendAndConsumeKeyUp() {
+ void sendAndConsumeKeyUp(int32_t deviceId) {
NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+ keyArgs.deviceId = deviceId;
keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event
mDispatcher->notifyKey(&keyArgs);
@@ -2179,21 +2179,59 @@
};
TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
- sendAndConsumeKeyDown();
+ sendAndConsumeKeyDown(1 /* deviceId */);
+ for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
+ expectKeyRepeatOnce(repeatCount);
+ }
+}
+
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeatFromTwoDevices) {
+ sendAndConsumeKeyDown(1 /* deviceId */);
+ for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
+ expectKeyRepeatOnce(repeatCount);
+ }
+ sendAndConsumeKeyDown(2 /* deviceId */);
+ /* repeatCount will start from 1 for deviceId 2 */
for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
expectKeyRepeatOnce(repeatCount);
}
}
TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) {
- sendAndConsumeKeyDown();
+ sendAndConsumeKeyDown(1 /* deviceId */);
expectKeyRepeatOnce(1 /*repeatCount*/);
- sendAndConsumeKeyUp();
+ sendAndConsumeKeyUp(1 /* deviceId */);
+ mWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
+ sendAndConsumeKeyDown(1 /* deviceId */);
+ expectKeyRepeatOnce(1 /*repeatCount*/);
+ sendAndConsumeKeyDown(2 /* deviceId */);
+ expectKeyRepeatOnce(1 /*repeatCount*/);
+ // Stale key up from device 1.
+ sendAndConsumeKeyUp(1 /* deviceId */);
+ // Device 2 is still down, keep repeating
+ expectKeyRepeatOnce(2 /*repeatCount*/);
+ expectKeyRepeatOnce(3 /*repeatCount*/);
+ // Device 2 key up
+ sendAndConsumeKeyUp(2 /* deviceId */);
+ mWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp) {
+ sendAndConsumeKeyDown(1 /* deviceId */);
+ expectKeyRepeatOnce(1 /*repeatCount*/);
+ sendAndConsumeKeyDown(2 /* deviceId */);
+ expectKeyRepeatOnce(1 /*repeatCount*/);
+ // Device 2 which holds the key repeating goes up, expect the repeating to stop.
+ sendAndConsumeKeyUp(2 /* deviceId */);
+ // Device 1 still holds key down, but the repeating was already stopped
mWindow->assertNoEvents();
}
TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
- sendAndConsumeKeyDown();
+ sendAndConsumeKeyDown(1 /* deviceId */);
for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
InputEvent* repeatEvent = mWindow->consume();
ASSERT_NE(nullptr, repeatEvent) << "Didn't receive event with repeat count " << repeatCount;
@@ -2203,7 +2241,7 @@
}
TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) {
- sendAndConsumeKeyDown();
+ sendAndConsumeKeyDown(1 /* deviceId */);
std::unordered_set<int32_t> idSet;
for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
@@ -2810,6 +2848,26 @@
mFakePolicy->assertNotifyAnrWasNotCalled();
}
+TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) {
+ mWindow->setFocusable(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
+ mWindow->consumeFocusEvent(false);
+
+ int32_t result =
+ injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /*repeatCount*/, ADISPLAY_ID_DEFAULT,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 10ms /*injectionTimeout*/);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, result);
+ // Key will not go to window because we have no focused window.
+ // The 'no focused window' ANR timer should start instead.
+
+ // Now, the focused application goes away.
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, nullptr);
+ // The key should get dropped and there should be no ANR.
+
+ ASSERT_TRUE(mDispatcher->waitForIdle());
+ mFakePolicy->assertNotifyAnrWasNotCalled();
+}
+
// Send an event to the app and have the app not respond right away.
// When ANR is raised, policy will tell the dispatcher to cancel the events for that window.
// So InputDispatcher will enqueue ACTION_CANCEL event as well.
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
index 3aef1e4..c368e79 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -135,7 +135,6 @@
public:
TestInputManager(){};
- void checkFdFlags(const android::base::unique_fd& fd);
binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles);
binder::Status getInputChannels(std::vector<::android::InputChannel>* channels);
@@ -147,10 +146,12 @@
const std::vector<InputWindowInfo>& handles,
const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
- binder::Status registerInputChannel(const InputChannel& channel) override;
- binder::Status unregisterInputChannel(const sp<IBinder>& connectionToken) override;
+ binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
+ binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override;
binder::Status setFocusedWindow(const FocusRequest&) override;
+ void reset();
+
private:
mutable Mutex mLock;
std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mHandlesPerDisplay;
@@ -164,6 +165,7 @@
binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles) override;
binder::Status getInputChannels(std::vector<::android::InputChannel>* channels) override;
binder::Status getLastFocusRequest(FocusRequest*) override;
+ binder::Status resetInputManager() override;
private:
sp<android::TestInputManager> mManager;
@@ -182,6 +184,11 @@
return mManager->getLastFocusRequest(request);
}
+binder::Status TestInputQuery::resetInputManager() {
+ mManager->reset();
+ return binder::Status::ok();
+}
+
binder::Status SetInputWindowsListener::onSetInputWindowsFinished() {
if (mCbFunc != nullptr) {
mCbFunc();
@@ -204,23 +211,21 @@
return binder::Status::ok();
}
-void TestInputManager::checkFdFlags(const android::base::unique_fd& fd) {
- const int result = fcntl(fd, F_GETFL);
- EXPECT_NE(result, -1);
- EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
-}
-
-binder::Status TestInputManager::registerInputChannel(const InputChannel& channel) {
+binder::Status TestInputManager::createInputChannel(const std::string& name,
+ InputChannel* outChannel) {
AutoMutex _l(mLock);
- // check Fd flags
- checkFdFlags(channel.getFd());
+ std::unique_ptr<InputChannel> serverChannel;
+ std::unique_ptr<InputChannel> clientChannel;
+ InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
- mInputChannels.push_back(channel.dup());
+ clientChannel->copyTo(*outChannel);
+
+ mInputChannels.emplace_back(std::move(serverChannel));
return binder::Status::ok();
}
-binder::Status TestInputManager::unregisterInputChannel(const sp<IBinder>& connectionToken) {
+binder::Status TestInputManager::removeInputChannel(const sp<IBinder>& connectionToken) {
AutoMutex _l(mLock);
auto it = std::find_if(mInputChannels.begin(), mInputChannels.end(),
@@ -271,6 +276,12 @@
return binder::Status::ok();
}
+void TestInputManager::reset() {
+ mHandlesPerDisplay.clear();
+ mInputChannels.clear();
+ mFocusRequest = FocusRequest();
+}
+
void InputFlingerServiceTest::SetUp() {
mSetInputWindowsListener = new SetInputWindowsListener([&]() {
std::unique_lock<std::mutex> lock(mLock);
@@ -316,7 +327,9 @@
InitializeInputFlinger();
}
-void InputFlingerServiceTest::TearDown() {}
+void InputFlingerServiceTest::TearDown() {
+ mQuery->resetInputManager();
+}
void InputFlingerServiceTest::verifyInputWindowInfo(const InputWindowInfo& info) const {
EXPECT_EQ(mInfo, info);
@@ -367,45 +380,33 @@
}
/**
- * Test InputFlinger service interface registerInputChannel
+ * Test InputFlinger service interface createInputChannel
*/
-TEST_F(InputFlingerServiceTest, InputWindow_RegisterInputChannel) {
- std::unique_ptr<InputChannel> serverChannel, clientChannel;
+TEST_F(InputFlingerServiceTest, CreateInputChannelReturnsUnblockedFd) {
+ // Test that the unblocked file descriptor flag is kept across processes over binder
+ // transactions.
- InputChannel::openInputChannelPair("testchannels", serverChannel, clientChannel);
- mService->registerInputChannel(*serverChannel);
+ InputChannel channel;
+ ASSERT_TRUE(mService->createInputChannel("testchannels", &channel).isOk());
+
+ const base::unique_fd& fd = channel.getFd();
+ ASSERT_TRUE(fd.ok());
+
+ const int result = fcntl(fd, F_GETFL);
+ EXPECT_NE(result, -1);
+ EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
+}
+
+TEST_F(InputFlingerServiceTest, InputWindow_CreateInputChannel) {
+ InputChannel channel;
+ ASSERT_TRUE(mService->createInputChannel("testchannels", &channel).isOk());
std::vector<::android::InputChannel> channels;
mQuery->getInputChannels(&channels);
ASSERT_EQ(channels.size(), 1UL);
- EXPECT_EQ(channels[0], *serverChannel);
+ EXPECT_EQ(channels[0].getConnectionToken(), channel.getConnectionToken());
- mService->unregisterInputChannel(serverChannel->getConnectionToken());
- mQuery->getInputChannels(&channels);
- EXPECT_EQ(channels.size(), 0UL);
-}
-
-/**
- * Test InputFlinger service interface registerInputChannel with invalid cases
- */
-TEST_F(InputFlingerServiceTest, InputWindow_RegisterInputChannelInvalid) {
- std::unique_ptr<InputChannel> serverChannel, clientChannel;
- InputChannel::openInputChannelPair("testchannels", serverChannel, clientChannel);
-
- std::vector<::android::InputChannel> channels;
- mQuery->getInputChannels(&channels);
- EXPECT_EQ(channels.size(), 0UL);
-
- mService->registerInputChannel(InputChannel());
- mService->unregisterInputChannel(clientChannel->getConnectionToken());
-
- mService->registerInputChannel(*serverChannel);
- mService->registerInputChannel(*clientChannel);
- mQuery->getInputChannels(&channels);
- EXPECT_EQ(channels.size(), 2UL);
-
- mService->unregisterInputChannel(clientChannel->getConnectionToken());
- mService->unregisterInputChannel(serverChannel->getConnectionToken());
+ mService->removeInputChannel(channel.getConnectionToken());
mQuery->getInputChannels(&channels);
EXPECT_EQ(channels.size(), 0UL);
}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index f56735a..4b0a945 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -7652,6 +7652,20 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
+ InputDeviceInfo deviceInfo;
+ mDevice->getDeviceInfo(&deviceInfo);
+
+ const InputDeviceInfo::MotionRange* relRangeX =
+ deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD);
+ ASSERT_NE(relRangeX, nullptr);
+ ASSERT_EQ(relRangeX->min, -(RAW_X_MAX - RAW_X_MIN));
+ ASSERT_EQ(relRangeX->max, RAW_X_MAX - RAW_X_MIN);
+ const InputDeviceInfo::MotionRange* relRangeY =
+ deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD);
+ ASSERT_NE(relRangeY, nullptr);
+ ASSERT_EQ(relRangeY->min, -(RAW_Y_MAX - RAW_Y_MIN));
+ ASSERT_EQ(relRangeY->max, RAW_Y_MAX - RAW_Y_MIN);
+
// run captured pointer tests - note that this is unscaled, so input listener events should be
// identical to what the hardware sends (accounting for any
// calibration).
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index cf46e03..ed0d75b 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -13,14 +13,16 @@
cc_defaults {
name: "libsurfaceflinger_defaults",
- defaults: ["surfaceflinger_defaults"],
+ defaults: [
+ "surfaceflinger_defaults",
+ "skia_deps",
+ ],
cflags: [
"-DLOG_TAG=\"SurfaceFlinger\"",
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
],
shared_libs: [
- "android.frameworks.vr.composer@2.0",
"android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
"android.hardware.configstore@1.1",
@@ -36,7 +38,6 @@
"android.hardware.power-cpp",
"libbase",
"libbinder",
- "libbufferhubqueue",
"libcutils",
"libEGL",
"libfmq",
@@ -47,7 +48,6 @@
"liblayers_proto",
"liblog",
"libnativewindow",
- "libpdx_default_transport",
"libprocessgroup",
"libprotobuf-cpp-lite",
"libstatslog",
@@ -58,14 +58,6 @@
"libutils",
"libSurfaceFlingerProp",
],
- // VrComposer is not used when building surfaceflinger for vendors
- target: {
- vendor: {
- exclude_shared_libs: [
- "android.frameworks.vr.composer@2.0",
- ],
- },
- },
static_libs: [
"libcompositionengine",
"libframetimeline",
@@ -73,7 +65,6 @@
"librenderengine",
"libserviceutils",
"libtrace_proto",
- "libvrflinger",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
@@ -109,11 +100,11 @@
defaults: ["libsurfaceflinger_defaults"],
cflags: [
"-fvisibility=hidden",
- "-fwhole-program-vtables", // requires ThinLTO
],
lto: {
thin: true,
},
+ whole_program_vtables: true, // Requires ThinLTO
// TODO(b/131771163): Fix broken fuzzer support with LTO.
sanitize: {
fuzzer: false,
@@ -195,17 +186,7 @@
],
cflags: [
"-DLOG_TAG=\"SurfaceFlinger\"",
- "-DUSE_VR_COMPOSER=1",
],
- // VrComposer is not used when building surfaceflinger for vendors
- // TODO: Is this ever built for vendors?
- target: {
- vendor: {
- cflags: [
- "-DUSE_VR_COMPOSER=0",
- ],
- },
- },
shared_libs: [
"android.frameworks.displayservice@1.0",
"android.hardware.configstore-utils",
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 54c060b..4cbfdff 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -37,6 +37,7 @@
#include "BufferLayerConsumer.h"
#include "Client.h"
#include "DisplayHardware/HWComposer.h"
+#include "FrameTimeline.h"
#include "FrameTracker.h"
#include "Layer.h"
#include "LayerVector.h"
@@ -187,7 +188,6 @@
virtual bool hasFrameUpdate() const = 0;
- virtual status_t bindTextureImage() = 0;
virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
nsecs_t expectedPresentTime) = 0;
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 94cbfa1..7c73df2 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -153,25 +153,9 @@
if (err != NO_ERROR) {
return err;
}
-
- if (!mRE.useNativeFenceSync()) {
- // Bind the new buffer to the GL texture.
- //
- // Older devices require the "implicit" synchronization provided
- // by glEGLImageTargetTexture2DOES, which this method calls. Newer
- // devices will either call this in Layer::onDraw, or (if it's not
- // a GL-composited layer) not at all.
- err = bindTextureImageLocked();
- }
-
return err;
}
-status_t BufferLayerConsumer::bindTextureImage() {
- Mutex::Autolock lock(mMutex);
- return bindTextureImageLocked();
-}
-
void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) {
if (!fence->isValid()) {
return;
@@ -292,17 +276,6 @@
return err;
}
-status_t BufferLayerConsumer::bindTextureImageLocked() {
- ATRACE_CALL();
-
- if (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->graphicBuffer() != nullptr) {
- return mRE.bindExternalTextureBuffer(mTexName, mCurrentTextureBuffer->graphicBuffer(),
- mCurrentFence);
- }
-
- return NO_INIT;
-}
-
void BufferLayerConsumer::getTransformMatrix(float mtx[16]) {
Mutex::Autolock lock(mMutex);
memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index a28902d..dd39214 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -94,9 +94,6 @@
status_t updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber);
- // See BufferLayerConsumer::bindTextureImageLocked().
- status_t bindTextureImage();
-
// setReleaseFence stores a fence that will signal when the current buffer
// is no longer being read. This fence will be returned to the producer
// when the current buffer is released by updateTexImage(). Multiple
@@ -214,10 +211,6 @@
PendingRelease* pendingRelease = nullptr)
EXCLUDES(mImagesMutex);
- // Binds mTexName and the current buffer to TEXTURE_EXTERNAL target.
- // If the bind succeeds, this calls doFenceWait.
- status_t bindTextureImageLocked();
-
private:
// Utility class for managing GraphicBuffer references into renderengine
class Image {
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 89284f2..33126ab 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -35,6 +35,7 @@
#include "TimeStats/TimeStats.h"
namespace android {
+using PresentState = frametimeline::SurfaceFrame::PresentState;
BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {}
@@ -109,7 +110,7 @@
Mutex::Autolock lock(mQueueItemLock);
- const int64_t addedTime = mQueueItems[0].mTimestamp;
+ const int64_t addedTime = mQueueItems[0].item.mTimestamp;
// Ignore timestamps more than a second in the future
const bool isPlausible = addedTime < (expectedPresentTime + s2ns(1));
@@ -136,7 +137,7 @@
}
Mutex::Autolock lock(mQueueItemLock);
- if (mQueueItems[0].mIsDroppable) {
+ if (mQueueItems[0].item.mIsDroppable) {
// Even though this buffer's fence may not have signaled yet, it could
// be replaced by another buffer before it has a chance to, which means
// that it's possible to get into a situation where a buffer is never
@@ -144,7 +145,7 @@
return true;
}
const bool fenceSignaled =
- mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+ mQueueItems[0].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
if (!fenceSignaled) {
mFlinger->mTimeStats->incrementLatchSkipped(getSequence(),
TimeStats::LatchSkipReason::LateAcquire);
@@ -159,12 +160,12 @@
}
Mutex::Autolock lock(mQueueItemLock);
- return mQueueItems[0].mTimestamp <= expectedPresentTime;
+ return mQueueItems[0].item.mTimestamp <= expectedPresentTime;
}
uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const {
Mutex::Autolock lock(mQueueItemLock);
- uint64_t frameNumber = mQueueItems[0].mFrameNumber;
+ uint64_t frameNumber = mQueueItems[0].item.mFrameNumber;
// The head of the queue will be dropped if there are signaled and timely frames behind it
if (isRemovedFromCurrentState()) {
@@ -173,23 +174,23 @@
for (int i = 1; i < mQueueItems.size(); i++) {
const bool fenceSignaled =
- mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+ mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
if (!fenceSignaled) {
break;
}
// We don't drop frames without explicit timestamps
- if (mQueueItems[i].mIsAutoTimestamp) {
+ if (mQueueItems[i].item.mIsAutoTimestamp) {
break;
}
- const nsecs_t desiredPresent = mQueueItems[i].mTimestamp;
+ const nsecs_t desiredPresent = mQueueItems[i].item.mTimestamp;
if (desiredPresent < expectedPresentTime - BufferQueueConsumer::MAX_REASONABLE_NSEC ||
desiredPresent > expectedPresentTime) {
break;
}
- frameNumber = mQueueItems[i].mFrameNumber;
+ frameNumber = mQueueItems[i].item.mFrameNumber;
}
return frameNumber;
@@ -229,10 +230,6 @@
return mQueuedFrames > 0;
}
-status_t BufferQueueLayer::bindTextureImage() {
- return mConsumer->bindTextureImage();
-}
-
status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
nsecs_t expectedPresentTime) {
// This boolean is used to make sure that SurfaceFlinger's shadow copy
@@ -258,11 +255,11 @@
Mutex::Autolock lock(mQueueItemLock);
for (int i = 0; i < mQueueItems.size(); i++) {
bool fenceSignaled =
- mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+ mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
if (!fenceSignaled) {
break;
}
- lastSignaledFrameNumber = mQueueItems[i].mFrameNumber;
+ lastSignaledFrameNumber = mQueueItems[i].item.mFrameNumber;
}
}
const uint64_t maxFrameNumberToAcquire =
@@ -280,9 +277,13 @@
// and return early
if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
- mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
- mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].mFrameNumber);
- mQueueItems.removeAt(0);
+ mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
+ mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
+ if (mQueueItems[0].surfaceFrame) {
+ mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame),
+ PresentState::Dropped);
+ }
+ mQueueItems.erase(mQueueItems.begin());
mQueuedFrames--;
}
return BAD_VALUE;
@@ -293,6 +294,12 @@
// early.
if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
+ for (auto& [item, surfaceFrame] : mQueueItems) {
+ if (surfaceFrame) {
+ mFlinger->mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+ PresentState::Dropped);
+ }
+ }
mQueueItems.clear();
mQueuedFrames = 0;
mFlinger->mTimeStats->onDestroy(layerId);
@@ -316,19 +323,29 @@
// Remove any stale buffers that have been dropped during
// updateTexImage
- while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
- mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
- mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].mFrameNumber);
- mQueueItems.removeAt(0);
+ while (mQueueItems[0].item.mFrameNumber != currentFrameNumber) {
+ mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
+ mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
+ if (mQueueItems[0].surfaceFrame) {
+ mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame),
+ PresentState::Dropped);
+ }
+ mQueueItems.erase(mQueueItems.begin());
mQueuedFrames--;
}
- uint64_t bufferID = mQueueItems[0].mGraphicBuffer->getId();
+ uint64_t bufferID = mQueueItems[0].item.mGraphicBuffer->getId();
mFlinger->mTimeStats->setLatchTime(layerId, currentFrameNumber, latchTime);
mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, currentFrameNumber, latchTime,
FrameTracer::FrameEvent::LATCH);
- mQueueItems.removeAt(0);
+ if (mQueueItems[0].surfaceFrame) {
+ mQueueItems[0].surfaceFrame->setActualEndTime(
+ mQueueItems[0].item.mFenceTime->getSignalTime());
+ mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame),
+ PresentState::Presented);
+ }
+ mQueueItems.erase(mQueueItems.begin());
}
// Decrement the queued-frames count. Signal another event if we
@@ -420,7 +437,11 @@
}
}
- mQueueItems.push_back(item);
+ auto surfaceFrame =
+ mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId);
+ surfaceFrame->setActualQueueTime(systemTime());
+
+ mQueueItems.push_back({item, std::move(surfaceFrame)});
mQueuedFrames++;
// Wake up any pending callbacks
@@ -453,7 +474,12 @@
ALOGE("Can't replace a frame on an empty queue");
return;
}
- mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
+
+ auto surfaceFrame =
+ mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId);
+ surfaceFrame->setActualQueueTime(systemTime());
+ mQueueItems[mQueueItems.size() - 1].item = item;
+ mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame);
// Wake up any pending callbacks
mLastFrameNumberReceived = item.mFrameNumber;
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 1ac0453..fc992f7 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -22,6 +22,10 @@
namespace android {
+namespace frametimeline {
+class SurfaceFrame;
+}
+
/*
* A new BufferQueue and a new BufferLayerConsumer are created when the
* BufferLayer is first referenced.
@@ -94,7 +98,6 @@
bool hasFrameUpdate() const override;
- status_t bindTextureImage() override;
status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
nsecs_t expectedPresentTime) override;
@@ -126,7 +129,14 @@
// Local copy of the queued contents of the incoming BufferQueue
mutable Mutex mQueueItemLock;
Condition mQueueItemCondition;
- Vector<BufferItem> mQueueItems;
+
+ struct BufferData {
+ BufferData(BufferItem item, std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame)
+ : item(item), surfaceFrame(std::move(surfaceFrame)) {}
+ BufferItem item;
+ std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame;
+ };
+ std::vector<BufferData> mQueueItems;
std::atomic<uint64_t> mLastFrameNumberReceived{0};
bool mAutoRefresh{false};
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 884cc0c..ea1f78c 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -508,13 +508,6 @@
return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr);
}
-status_t BufferStateLayer::bindTextureImage() {
- const State& s(getDrawingState());
- auto& engine(mFlinger->getRenderEngine());
-
- return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence);
-}
-
status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
nsecs_t /*expectedPresentTime*/) {
const State& s(getDrawingState());
@@ -559,20 +552,6 @@
handle->frameNumber = mDrawingState.frameNumber;
}
- if (!SyncFeatures::getInstance().useNativeFenceSync()) {
- // Bind the new buffer to the GL texture.
- //
- // Older devices require the "implicit" synchronization provided
- // by glEGLImageTargetTexture2DOES, which this method calls. Newer
- // devices will either call this in Layer::onDraw, or (if it's not
- // a GL-composited layer) not at all.
- status_t err = bindTextureImage();
- if (err != NO_ERROR) {
- mFlinger->mTimeStats->onDestroy(layerId);
- return BAD_VALUE;
- }
- }
-
mFlinger->mTimeStats->setAcquireFence(layerId, mDrawingState.frameNumber,
std::make_shared<FenceTime>(mDrawingState.acquireFence));
mFlinger->mTimeStats->setLatchTime(layerId, mDrawingState.frameNumber, latchTime);
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 89d9a00..81959ae 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -129,7 +129,6 @@
bool hasFrameUpdate() const override;
- status_t bindTextureImage() override;
status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
nsecs_t expectedPresentTime) override;
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index b37ca33..57dc60b 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -6,7 +6,6 @@
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
],
shared_libs: [
- "android.frameworks.vr.composer@2.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
@@ -96,8 +95,9 @@
"tests/MockHWC2.cpp",
"tests/MockHWComposer.cpp",
"tests/MockPowerAdvisor.cpp",
- "tests/OutputTest.cpp",
"tests/OutputLayerTest.cpp",
+ "tests/OutputTest.cpp",
+ "tests/ProjectionSpaceTest.cpp",
"tests/RenderSurfaceTest.cpp",
],
static_libs: [
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index b4ed92f..77400eb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -130,16 +130,6 @@
Rect geomContentCrop;
Rect geomCrop;
- /*
- * Extra metadata
- */
-
- // The type for this layer
- int type{0};
-
- // The appId for this layer
- int appId{0};
-
GenericLayerMetadataMap metadata;
/*
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 6552c54..fc1adcc 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -163,9 +163,8 @@
virtual void setCompositionEnabled(bool) = 0;
// Sets the projection state to use
- virtual void setProjection(const ui::Transform&, uint32_t orientation,
- const Rect& orientedDisplaySpaceRect,
- const Rect& layerStackSpaceRect, const Rect& displaySpaceRect) = 0;
+ virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
+ const Rect& orientedDisplaySpaceRect) = 0;
// Sets the bounds to use
virtual void setDisplaySpaceSize(const ui::Size&) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
index 9d15665..7ca91d8 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
@@ -38,14 +38,73 @@
// Rect onto which content is projected.
Rect content;
+
+ // The orientation of this space. This value is meaningful only in relation to the rotation
+ // of another projection space and it's used to determine the rotating transformation when
+ // mapping between the two.
+ // As a convention when using this struct orientation = 0 for the "oriented*" projection
+ // spaces. For example when the display is rotated 90 degress counterclockwise, the orientation
+ // of the display space will become 90, while the orientation of the layer stack space will
+ // remain the same.
+ ui::Rotation orientation = ui::ROTATION_0;
+
+ // Returns a transform which maps this.content into destination.content
+ // and also rotates according to this.orientation and destination.orientation
+ ui::Transform getTransform(const ProjectionSpace& destination) const {
+ ui::Rotation rotation = destination.orientation - orientation;
+
+ // Compute a transformation which rotates the destination in a way it has the same
+ // orientation as us.
+ const uint32_t inverseRotationFlags = ui::Transform::toRotationFlags(-rotation);
+ ui::Transform inverseRotatingTransform;
+ inverseRotatingTransform.set(inverseRotationFlags, destination.bounds.width(),
+ destination.bounds.height());
+ // The destination content rotated so it has the same orientation as us.
+ Rect orientedDestContent = inverseRotatingTransform.transform(destination.content);
+
+ // Compute translation from the source content to (0, 0).
+ const float sourceX = content.left;
+ const float sourceY = content.top;
+ ui::Transform sourceTranslation;
+ sourceTranslation.set(-sourceX, -sourceY);
+
+ // Compute scaling transform which maps source content to destination content, assuming
+ // they are both at (0, 0).
+ ui::Transform scale;
+ const float scaleX = static_cast<float>(orientedDestContent.width()) / content.width();
+ const float scaleY = static_cast<float>(orientedDestContent.height()) / content.height();
+ scale.set(scaleX, 0, 0, scaleY);
+
+ // Compute translation from (0, 0) to the orientated destination content.
+ const float destX = orientedDestContent.left;
+ const float destY = orientedDestContent.top;
+ ui::Transform destTranslation;
+ destTranslation.set(destX, destY);
+
+ // Compute rotation transform.
+ const uint32_t orientationFlags = ui::Transform::toRotationFlags(rotation);
+ auto orientedDestWidth = destination.bounds.width();
+ auto orientedDestHeight = destination.bounds.height();
+ if (rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270) {
+ std::swap(orientedDestWidth, orientedDestHeight);
+ }
+ ui::Transform rotationTransform;
+ rotationTransform.set(orientationFlags, orientedDestWidth, orientedDestHeight);
+
+ // The layerStackSpaceRect and orientedDisplaySpaceRect are both in the logical orientation.
+ // Apply the logical translation, scale to physical size, apply the
+ // physical translation and finally rotate to the physical orientation.
+ return rotationTransform * destTranslation * scale * sourceTranslation;
+ }
};
} // namespace compositionengine
inline std::string to_string(const android::compositionengine::ProjectionSpace& space) {
- return android::base::StringPrintf("ProjectionSpace(bounds = %s, content = %s)",
- to_string(space.bounds).c_str(),
- to_string(space.content).c_str());
+ return android::base::
+ StringPrintf("ProjectionSpace(bounds = %s, content = %s, orientation = %s)",
+ to_string(space.bounds).c_str(), to_string(space.content).c_str(),
+ toCString(space.orientation));
}
// Defining PrintTo helps with Google Tests.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index e009894..6fe93bf 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -38,9 +38,8 @@
bool isValid() const override;
std::optional<DisplayId> getDisplayId() const override;
void setCompositionEnabled(bool) override;
- void setProjection(const ui::Transform&, uint32_t orientation,
- const Rect& orientedDisplaySpaceRect, const Rect& layerStackSpaceRect,
- const Rect& displaySpaceRect) override;
+ void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
+ const Rect& orientedDisplaySpaceRect) override;
void setDisplaySpaceSize(const ui::Size&) override;
void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 462d952..f4d2b56 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -64,13 +64,11 @@
uint32_t layerStackId{~0u};
// The common space for all layers in the layer stack. layerStackSpace.content is the Rect
- // which gets projected on the display. The content in this space is always in a single
- // orientation.
+ // which gets projected on the display. The orientation of this space is always ROTATION_0.
ProjectionSpace layerStackSpace;
// Oriented physical display space. It will have the same size as displaySpace oriented to
- // match the orientation of layerStackSpace. The content in this space is always in a single
- // orientation.
+ // match the orientation of layerStackSpace. The orientation of this space is always ROTATION_0.
ProjectionSpace orientedDisplaySpace;
// The space of the physical display. It is as big as the currently active display mode. The
@@ -80,9 +78,6 @@
// Transformation from layerStackSpace to displaySpace
ui::Transform transform;
- // The physical orientation of the display, expressed as ui::Transform orientation flags.
- uint32_t orientation{0};
-
// If true, RenderEngine filtering should be enabled
bool needsFiltering{false};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 5350611..19025c1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -36,8 +36,7 @@
MOCK_CONST_METHOD0(getDisplayId, std::optional<DisplayId>());
MOCK_METHOD1(setCompositionEnabled, void(bool));
- MOCK_METHOD5(setProjection,
- void(const ui::Transform&, uint32_t, const Rect&, const Rect&, const Rect&));
+ MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
MOCK_METHOD1(setDisplaySpaceSize, void(const ui::Size&));
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index 02e3a45..1338538 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -75,10 +75,6 @@
dumpVal(out, "alpha", alpha);
dumpVal(out, "backgroundBlurRadius", backgroundBlurRadius);
- out.append("\n ");
- dumpVal(out, "type", type);
- dumpVal(out, "appId", appId);
-
if (!metadata.empty()) {
out.append("\n metadata {");
for (const auto& [key, entry] : metadata) {
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 816a09b..abb8769 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -105,25 +105,34 @@
dirtyEntireOutput();
}
-void Output::setProjection(const ui::Transform& transform, uint32_t orientation,
- const Rect& orientedDisplaySpaceRect, const Rect& layerStackSpaceRect,
- const Rect& displaySpaceRect) {
+void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
+ const Rect& orientedDisplaySpaceRect) {
auto& outputState = editState();
- outputState.transform = transform;
- outputState.orientation = orientation;
- outputState.displaySpace.content = displaySpaceRect;
- // outputState.displaySpace.bounds should be already set from setDisplaySpaceSize().
- outputState.orientedDisplaySpace.content = orientedDisplaySpaceRect;
+ outputState.displaySpace.orientation = orientation;
+ // outputState.displaySpace.bounds should be already set from setDisplaySpaceSize().
+
+ // Compute the orientedDisplaySpace bounds
ui::Size orientedSize = outputState.displaySpace.bounds.getSize();
- if (orientation == ui::Transform::ROT_90 || orientation == ui::Transform::ROT_270) {
+ if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
std::swap(orientedSize.width, orientedSize.height);
}
outputState.orientedDisplaySpace.bounds = Rect(orientedSize);
+ outputState.orientedDisplaySpace.content = orientedDisplaySpaceRect;
+
+ // Compute displaySpace.content
+ const uint32_t transformOrientationFlags = ui::Transform::toRotationFlags(orientation);
+ ui::Transform rotation;
+ if (transformOrientationFlags != ui::Transform::ROT_INVALID) {
+ const auto displaySize = outputState.displaySpace.bounds;
+ rotation.set(transformOrientationFlags, displaySize.width(), displaySize.height());
+ }
+ outputState.displaySpace.content = rotation.transform(orientedDisplaySpaceRect);
outputState.layerStackSpace.content = layerStackSpaceRect;
outputState.layerStackSpace.bounds = layerStackSpaceRect;
- outputState.needsFiltering = transform.needsBilinearFiltering();
+ outputState.transform = outputState.layerStackSpace.getTransform(outputState.displaySpace);
+ outputState.needsFiltering = outputState.transform.needsBilinearFiltering();
dirtyEntireOutput();
}
@@ -870,7 +879,8 @@
renderengine::DisplaySettings clientCompositionDisplay;
clientCompositionDisplay.physicalDisplay = outputState.displaySpace.content;
clientCompositionDisplay.clip = outputState.layerStackSpace.content;
- clientCompositionDisplay.orientation = outputState.orientation;
+ clientCompositionDisplay.orientation =
+ ui::Transform::toRotationFlags(outputState.displaySpace.orientation);
clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut()
? outputState.dataspace
: ui::Dataspace::UNKNOWN;
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 376b4b3..0faab6f 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -133,7 +133,8 @@
* the code below applies the primary display's inverse transform to the
* buffer
*/
- uint32_t invTransformOrient = outputState.orientation;
+ uint32_t invTransformOrient =
+ ui::Transform::toRotationFlags(outputState.displaySpace.orientation);
// calculate the inverse transform
if (invTransformOrient & HAL_TRANSFORM_ROT_90) {
invTransformOrient ^= HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H;
@@ -402,13 +403,6 @@
outputIndependentState.alpha, to_string(error).c_str(), static_cast<int32_t>(error));
}
- if (auto error = hwcLayer->setInfo(static_cast<uint32_t>(outputIndependentState.type),
- static_cast<uint32_t>(outputIndependentState.appId));
- error != hal::Error::NONE) {
- ALOGE("[%s] Failed to set info %s (%d)", getLayerFE().getDebugName(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
for (const auto& [name, entry] : outputIndependentState.metadata) {
if (auto error = hwcLayer->setLayerGenericMetadata(name, entry.mandatory, entry.value);
error != hal::Error::NONE) {
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 2773fd3..b47f7fd 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -48,6 +48,8 @@
namespace impl {
+constexpr auto DEFAULT_USAGE = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+
std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
const compositionengine::CompositionEngine& compositionEngine,
compositionengine::Display& display,
@@ -81,7 +83,7 @@
ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status);
- status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER);
+ status = native_window_set_usage(window, DEFAULT_USAGE);
ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status);
}
@@ -109,7 +111,7 @@
}
void RenderSurface::setProtected(bool useProtected) {
- uint64_t usageFlags = GRALLOC_USAGE_HW_RENDER;
+ uint64_t usageFlags = DEFAULT_USAGE;
if (useProtected) {
usageFlags |= GRALLOC_USAGE_PROTECTED;
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index d889d74..d5bf569 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -30,6 +30,7 @@
namespace {
using ::testing::_;
+using ::testing::DoAll;
using ::testing::InSequence;
using ::testing::Ref;
using ::testing::Return;
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index d21b97e..87911cc 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -66,7 +66,6 @@
MOCK_METHOD1(setTransform, Error(hal::Transform));
MOCK_METHOD1(setVisibleRegion, Error(const android::Region&));
MOCK_METHOD1(setZOrder, Error(uint32_t));
- MOCK_METHOD2(setInfo, Error(uint32_t, uint32_t));
MOCK_METHOD1(setColorTransform, Error(const android::mat4&));
MOCK_METHOD3(setLayerGenericMetadata,
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index df3da85..dcfc162 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -21,6 +21,7 @@
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/Output.h>
#include <gtest/gtest.h>
+#include <log/log.h>
#include "MockHWC2.h"
#include "MockHWComposer.h"
@@ -55,6 +56,22 @@
return expected.r == arg.r && expected.g == arg.g && expected.b == arg.b && expected.a == arg.a;
}
+ui::Rotation toRotation(uint32_t rotationFlag) {
+ switch (rotationFlag) {
+ case ui::Transform::RotationFlags::ROT_0:
+ return ui::ROTATION_0;
+ case ui::Transform::RotationFlags::ROT_90:
+ return ui::ROTATION_90;
+ case ui::Transform::RotationFlags::ROT_180:
+ return ui::ROTATION_180;
+ case ui::Transform::RotationFlags::ROT_270:
+ return ui::ROTATION_270;
+ default:
+ LOG_FATAL("Unexpected rotation flag %d", rotationFlag);
+ return ui::Rotation(-1);
+ }
+}
+
struct OutputLayerTest : public testing::Test {
struct OutputLayer final : public impl::OutputLayer {
OutputLayer(const compositionengine::Output& output, sp<compositionengine::LayerFE> layerFE)
@@ -209,7 +226,7 @@
mLayerFEState.geomBufferUsesDisplayInverseTransform = entry.bufferInvDisplay;
mLayerFEState.geomBufferTransform = entry.buffer;
- mOutputState.orientation = entry.display;
+ mOutputState.displaySpace.orientation = toRotation(entry.display);
EXPECT_THAT(calculateOutputSourceCrop(), entry.expected) << "entry " << i;
}
@@ -358,7 +375,7 @@
mLayerFEState.geomLayerTransform.set(entry.layer, 1920, 1080);
mLayerFEState.geomBufferTransform = entry.buffer;
- mOutputState.orientation = entry.display;
+ mOutputState.displaySpace.orientation = toRotation(entry.display);
mOutputState.transform = ui::Transform{entry.display};
const auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(entry.display);
@@ -470,7 +487,7 @@
mLayerFEState.geomLayerTransform.set(entry.layer, 1920, 1080);
mLayerFEState.geomBufferTransform = entry.buffer;
- mOutputState.orientation = entry.display;
+ mOutputState.displaySpace.orientation = toRotation(entry.display);
mOutputState.transform = ui::Transform{entry.display};
const auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(entry.internal);
@@ -676,8 +693,6 @@
static constexpr Hwc2::IComposerClient::BlendMode kBlendMode =
static_cast<Hwc2::IComposerClient::BlendMode>(41);
static constexpr float kAlpha = 51.f;
- static constexpr uint32_t kType = 61u;
- static constexpr uint32_t kAppId = 62u;
static constexpr ui::Dataspace kDataspace = static_cast<ui::Dataspace>(71);
static constexpr int kSupportedPerFrameMetadata = 101;
static constexpr int kExpectedHwcSlot = 0;
@@ -711,8 +726,6 @@
mLayerFEState.blendMode = kBlendMode;
mLayerFEState.alpha = kAlpha;
- mLayerFEState.type = kType;
- mLayerFEState.appId = kAppId;
mLayerFEState.colorTransform = kColorTransform;
mLayerFEState.color = kColor;
mLayerFEState.surfaceDamage = kSurfaceDamage;
@@ -746,7 +759,6 @@
EXPECT_CALL(*mHwcLayer, setBlendMode(kBlendMode)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setPlaneAlpha(kAlpha)).WillOnce(Return(kError));
- EXPECT_CALL(*mHwcLayer, setInfo(kType, kAppId)).WillOnce(Return(kError));
}
void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None) {
@@ -858,7 +870,7 @@
// This test simulates a scenario where displayInstallOrientation is set to
// ROT_90. This only has an effect on the transform; orientation stays 0 (see
// DisplayDevice::setProjection).
- mOutputState.orientation = TR_IDENT;
+ mOutputState.displaySpace.orientation = ui::ROTATION_0;
mOutputState.transform = ui::Transform{TR_ROT_90};
// Buffers are pre-rotated based on the transform hint (ROT_90); their
// geomBufferTransform is set to the inverse transform.
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 23efd2d..c01f3e0 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -236,19 +236,15 @@
*/
TEST_F(OutputTest, setProjectionTriviallyWorks) {
- const ui::Transform transform{ui::Transform::ROT_180};
- const int32_t orientation = 123;
+ const ui::Rotation orientation = ui::ROTATION_90;
const Rect frame{1, 2, 3, 4};
const Rect viewport{5, 6, 7, 8};
- const Rect destinationClip{13, 14, 15, 16};
- mOutput->setProjection(transform, orientation, frame, viewport, destinationClip);
+ mOutput->setProjection(orientation, viewport, frame);
- EXPECT_THAT(mOutput->getState().transform, transform);
- EXPECT_EQ(orientation, mOutput->getState().orientation);
+ EXPECT_EQ(orientation, mOutput->getState().displaySpace.orientation);
EXPECT_EQ(frame, mOutput->getState().orientedDisplaySpace.content);
EXPECT_EQ(viewport, mOutput->getState().layerStackSpace.content);
- EXPECT_EQ(destinationClip, mOutput->getState().displaySpace.content);
}
/*
@@ -2783,8 +2779,8 @@
mOutput.mState.orientedDisplaySpace.content = kDefaultOutputFrame;
mOutput.mState.layerStackSpace.content = kDefaultOutputViewport;
mOutput.mState.displaySpace.content = kDefaultOutputDestinationClip;
- mOutput.mState.transform = ui::Transform{kDefaultOutputOrientation};
- mOutput.mState.orientation = kDefaultOutputOrientation;
+ mOutput.mState.transform = ui::Transform{kDefaultOutputOrientationFlags};
+ mOutput.mState.displaySpace.orientation = kDefaultOutputOrientation;
mOutput.mState.dataspace = kDefaultOutputDataspace;
mOutput.mState.colorTransformMatrix = kDefaultColorTransformMat;
mOutput.mState.isSecure = false;
@@ -2819,7 +2815,9 @@
// Call this member function to start using the mini-DSL defined above.
[[nodiscard]] auto verify() { return ExecuteState::make(this); }
- static constexpr uint32_t kDefaultOutputOrientation = TR_IDENT;
+ static constexpr ui::Rotation kDefaultOutputOrientation = ui::ROTATION_0;
+ static constexpr uint32_t kDefaultOutputOrientationFlags =
+ ui::Transform::toRotationFlags(kDefaultOutputOrientation);
static constexpr ui::Dataspace kDefaultOutputDataspace = ui::Dataspace::UNKNOWN;
static constexpr ui::Dataspace kExpensiveOutputDataspace = ui::Dataspace::DISPLAY_P3;
static constexpr float kDefaultMaxLuminance = 0.9f;
@@ -3116,7 +3114,7 @@
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- Region::INVALID_REGION, kDefaultOutputOrientation})
+ Region::INVALID_REGION, kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
}
@@ -3127,7 +3125,7 @@
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- Region::INVALID_REGION, kDefaultOutputOrientation})
+ Region::INVALID_REGION, kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
}
@@ -3139,7 +3137,7 @@
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace,
kDefaultColorTransformMat, Region::INVALID_REGION,
- kDefaultOutputOrientation})
+ kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
}
@@ -3151,7 +3149,7 @@
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace,
kDefaultColorTransformMat, Region::INVALID_REGION,
- kDefaultOutputOrientation})
+ kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
}
@@ -3163,7 +3161,7 @@
.andIfSkipColorTransform(true)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- Region::INVALID_REGION, kDefaultOutputOrientation})
+ Region::INVALID_REGION, kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
}
@@ -3409,8 +3407,9 @@
mOutput.mState.orientedDisplaySpace.content = kDisplayFrame;
mOutput.mState.layerStackSpace.content = kDisplayViewport;
mOutput.mState.displaySpace.content = kDisplayDestinationClip;
- mOutput.mState.transform = ui::Transform{kDisplayOrientation};
- mOutput.mState.orientation = kDisplayOrientation;
+ mOutput.mState.transform =
+ ui::Transform{ui::Transform::toRotationFlags(kDisplayOrientation)};
+ mOutput.mState.displaySpace.orientation = kDisplayOrientation;
mOutput.mState.needsFiltering = false;
mOutput.mState.isSecure = false;
@@ -3434,7 +3433,7 @@
EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(mLayers.size()));
}
- static constexpr uint32_t kDisplayOrientation = TR_IDENT;
+ static constexpr ui::Rotation kDisplayOrientation = ui::ROTATION_0;
static constexpr ui::Dataspace kDisplayDataspace = ui::Dataspace::UNKNOWN;
static const Rect kDisplayFrame;
@@ -3918,14 +3917,14 @@
const Rect kPortraitFrame(0, 0, 1000, 2000);
const Rect kPortraitViewport(0, 0, 2000, 1000);
const Rect kPortraitDestinationClip(0, 0, 1000, 2000);
- const uint32_t kPortraitOrientation = TR_ROT_90;
+ const ui::Rotation kPortraitOrientation = ui::ROTATION_90;
constexpr ui::Dataspace kOutputDataspace = ui::Dataspace::DISPLAY_P3;
mOutput.mState.orientedDisplaySpace.content = kPortraitFrame;
mOutput.mState.layerStackSpace.content = kPortraitViewport;
mOutput.mState.displaySpace.content = kPortraitDestinationClip;
- mOutput.mState.transform = ui::Transform{kPortraitOrientation};
- mOutput.mState.orientation = kPortraitOrientation;
+ mOutput.mState.transform = ui::Transform{ui::Transform::toRotationFlags(kPortraitOrientation)};
+ mOutput.mState.displaySpace.orientation = kPortraitOrientation;
mOutput.mState.needsFiltering = false;
mOutput.mState.isSecure = true;
diff --git a/services/surfaceflinger/CompositionEngine/tests/ProjectionSpaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/ProjectionSpaceTest.cpp
new file mode 100644
index 0000000..704f5a8
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/ProjectionSpaceTest.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2020 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 <compositionengine/ProjectionSpace.h>
+#include <gtest/gtest.h>
+
+namespace android::compositionengine {
+namespace {
+
+// Returns a rectangular strip along the side of the given rect pointed by
+// rotation. E.g. if rotation is ROTATION_0, the srip will be along the top
+// side, if it is ROTATION_90 the stip will be along the right wall.
+// One of the dimensions of the strip will be 0 and the other one will match
+// the length of the corresponding side.
+// The strip will be contained inside the given rect.
+Rect getSideStrip(const Rect& rect, ui::Rotation rotation) {
+ int width, height;
+ if (rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270) {
+ width = 0;
+ height = rect.height();
+ } else {
+ width = rect.width();
+ height = 0;
+ }
+
+ if (rotation == ui::ROTATION_0 || rotation == ui::ROTATION_270) {
+ return Rect(rect.left, rect.top, rect.left + width, rect.top + height);
+ }
+
+ if (rotation == ui::ROTATION_90) {
+ return Rect(rect.right, rect.top, rect.right + width, rect.top + height);
+ }
+
+ if (rotation == ui::ROTATION_180) {
+ return Rect(rect.left, rect.bottom, rect.left + width, rect.bottom + height);
+ }
+
+ return Rect::INVALID_RECT;
+}
+} // namespace
+
+TEST(ProjectionSpaceTest, getTransformToSelfIsIdentity) {
+ ProjectionSpace space;
+ space.content = Rect(100, 200);
+ space.bounds = Rect(100, 200);
+
+ const ui::Transform identity;
+ for (int rotation = 0; rotation <= 3; rotation++) {
+ space.orientation = ui::Rotation(rotation);
+ EXPECT_EQ(space.getTransform(space), identity);
+ }
+}
+
+TEST(ProjectionSpaceTest, getTransformWhenTranslationIsNeeded) {
+ ProjectionSpace source;
+ source.content = Rect(10, 10, 20, 20);
+ source.bounds = Rect(100, 200);
+
+ ProjectionSpace dest;
+ dest.content = Rect(10, 20, 30, 20);
+ dest.bounds = source.bounds;
+
+ const auto transform = source.getTransform(dest);
+ EXPECT_EQ(transform.transform(source.content), dest.content);
+}
+
+TEST(ProjectionSpaceTest, getTransformWhenScaleIsNeeded) {
+ ProjectionSpace source;
+ source.content = Rect(0, 0, 20, 20);
+ source.bounds = Rect(100, 200);
+
+ ProjectionSpace dest;
+ dest.content = Rect(0, 0, 40, 30);
+ dest.bounds = source.bounds;
+
+ const auto transform = source.getTransform(dest);
+ EXPECT_EQ(transform.transform(source.content), dest.content);
+}
+
+TEST(ProjectionSpaceTest, getSideStripTest) {
+ const Rect rect(10, 20, 40, 100);
+ EXPECT_EQ(getSideStrip(rect, ui::ROTATION_0), Rect(10, 20, 40, 20));
+ EXPECT_EQ(getSideStrip(rect, ui::ROTATION_90), Rect(40, 20, 40, 100));
+ EXPECT_EQ(getSideStrip(rect, ui::ROTATION_180), Rect(10, 100, 40, 100));
+ EXPECT_EQ(getSideStrip(rect, ui::ROTATION_270), Rect(10, 20, 10, 100));
+}
+
+void testTransform(const ProjectionSpace& source, const ProjectionSpace& dest) {
+ const auto transform = source.getTransform(dest);
+ EXPECT_EQ(transform.transform(source.content), dest.content)
+ << "Source content doesn't map to dest content when projecting " << to_string(source)
+ << " onto " << to_string(dest);
+
+ // We take a strip at the top (according to the orientation) of each
+ // content rect and verify that transform maps between them. This way we
+ // verify that the transform is rotating properly.
+ // In the following example the strip is marked with asterisks:
+ //
+ // ******* +-------*
+ // | | | *
+ // | | | *
+ // +-----+ +-------*
+ // source(ROTATION_0) dest (ROTATION_90)
+ const auto sourceStrip = getSideStrip(source.content, source.orientation);
+ const auto destStrip = getSideStrip(dest.content, dest.orientation);
+ ASSERT_NE(sourceStrip, Rect::INVALID_RECT);
+ ASSERT_NE(destStrip, Rect::INVALID_RECT);
+ const auto mappedStrip = transform.transform(sourceStrip);
+ EXPECT_EQ(mappedStrip, destStrip)
+ << to_string(sourceStrip) << " maps to " << to_string(mappedStrip) << " instead of "
+ << to_string(destStrip) << " when projecting " << to_string(source) << " onto "
+ << to_string(dest);
+}
+
+TEST(ProjectionSpaceTest, getTransformWithOrienations) {
+ ProjectionSpace source;
+ source.bounds = Rect(12, 13, 678, 789);
+ source.content = Rect(40, 50, 234, 343);
+ ProjectionSpace dest;
+ dest.bounds = Rect(17, 18, 879, 564);
+ dest.content = Rect(43, 52, 432, 213);
+
+ for (int sourceRot = 0; sourceRot <= 3; sourceRot++) {
+ source.orientation = ui::Rotation(sourceRot);
+ for (int destRot = 0; destRot <= 3; destRot++) {
+ dest.orientation = ui::Rotation(destRot);
+ testTransform(source, dest);
+ }
+ }
+}
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 519cc57..8d1eb36 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -82,7 +82,8 @@
EXPECT_CALL(*mNativeWindow, connect(NATIVE_WINDOW_API_EGL)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mNativeWindow, setBuffersFormat(HAL_PIXEL_FORMAT_RGBA_8888))
.WillOnce(Return(NO_ERROR));
- EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE))
+ .WillOnce(Return(NO_ERROR));
mSurface.initialize();
}
@@ -136,7 +137,9 @@
TEST_F(RenderSurfaceTest, setProtectedTrueEnablesProtection) {
EXPECT_FALSE(mSurface.isProtected());
- EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PROTECTED))
+ EXPECT_CALL(*mNativeWindow,
+ setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE |
+ GRALLOC_USAGE_PROTECTED))
.WillOnce(Return(NO_ERROR));
mSurface.setProtected(true);
@@ -145,7 +148,8 @@
TEST_F(RenderSurfaceTest, setProtectedFalseDisablesProtection) {
EXPECT_FALSE(mSurface.isProtected());
- EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE))
+ .WillOnce(Return(NO_ERROR));
mSurface.setProtected(false);
EXPECT_FALSE(mSurface.isProtected());
@@ -153,9 +157,12 @@
TEST_F(RenderSurfaceTest, setProtectedEnableAndDisable) {
EXPECT_FALSE(mSurface.isProtected());
- EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PROTECTED))
+ EXPECT_CALL(*mNativeWindow,
+ setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE |
+ GRALLOC_USAGE_PROTECTED))
.WillOnce(Return(NO_ERROR));
- EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE))
+ .WillOnce(Return(NO_ERROR));
mSurface.setProtected(true);
EXPECT_TRUE(mSurface.isProtected());
@@ -165,7 +172,9 @@
TEST_F(RenderSurfaceTest, setProtectedEnableWithError) {
EXPECT_FALSE(mSurface.isProtected());
- EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PROTECTED))
+ EXPECT_CALL(*mNativeWindow,
+ setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE |
+ GRALLOC_USAGE_PROTECTED))
.WillOnce(Return(INVALID_OPERATION));
mSurface.setProtected(true);
EXPECT_FALSE(mSurface.isProtected());
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b53f88d..7df9b76 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -163,6 +163,10 @@
Rect orientedDisplaySpaceRect) {
mOrientation = orientation;
+ if (isPrimary()) {
+ sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation);
+ }
+
const Rect& displayBounds = getCompositionDisplay()->getState().displaySpace.bounds;
const int displayWidth = displayBounds.width();
const int displayHeight = displayBounds.height();
@@ -184,52 +188,11 @@
}
}
- ui::Transform logicalTranslation, physicalTranslation, scale;
- const float sourceWidth = layerStackSpaceRect.width();
- const float sourceHeight = layerStackSpaceRect.height();
- const float destWidth = orientedDisplaySpaceRect.width();
- const float destHeight = orientedDisplaySpaceRect.height();
- if (sourceWidth != destWidth || sourceHeight != destHeight) {
- const float scaleX = destWidth / sourceWidth;
- const float scaleY = destHeight / sourceHeight;
- scale.set(scaleX, 0, 0, scaleY);
- }
-
- const float sourceX = layerStackSpaceRect.left;
- const float sourceY = layerStackSpaceRect.top;
- const float destX = orientedDisplaySpaceRect.left;
- const float destY = orientedDisplaySpaceRect.top;
- logicalTranslation.set(-sourceX, -sourceY);
- physicalTranslation.set(destX, destY);
-
// We need to take care of display rotation for globalTransform for case if the panel is not
// installed aligned with device orientation.
const auto transformOrientation = orientation + mPhysicalOrientation;
- const uint32_t transformOrientationFlags = ui::Transform::toRotationFlags(transformOrientation);
- ui::Transform rotation;
- if (transformOrientationFlags != ui::Transform::ROT_INVALID) {
- rotation.set(transformOrientationFlags, displayWidth, displayHeight);
- }
-
- // The layerStackSpaceRect and orientedDisplaySpaceRect are both in the logical orientation.
- // Apply the logical translation, scale to physical size, apply the
- // physical translation and finally rotate to the physical orientation.
- ui::Transform globalTransform = rotation * physicalTranslation * scale * logicalTranslation;
-
- Rect displaySpaceRect = globalTransform.transform(layerStackSpaceRect);
- if (displaySpaceRect.isEmpty()) {
- displaySpaceRect = displayBounds;
- }
- // Make sure the displaySpaceRect is contained in the display bounds
- displaySpaceRect.intersect(displayBounds, &displaySpaceRect);
-
- if (isPrimary()) {
- sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation);
- }
-
- getCompositionDisplay()->setProjection(globalTransform, transformOrientationFlags,
- orientedDisplaySpaceRect, layerStackSpaceRect,
- displaySpaceRect);
+ getCompositionDisplay()->setProjection(transformOrientation, layerStackSpaceRect,
+ orientedDisplaySpaceRect);
}
ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() {
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index a3f1b52..1bf43da 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -117,63 +117,7 @@
namespace impl {
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-Composer::CommandWriter::CommandWriter(uint32_t initialMaxSize)
- : CommandWriterBase(initialMaxSize) {}
-
-Composer::CommandWriter::~CommandWriter()
-{
-}
-
-void Composer::CommandWriter::setLayerInfo(uint32_t type, uint32_t appId)
-{
- constexpr uint16_t kSetLayerInfoLength = 2;
- beginCommand(static_cast<V2_1::IComposerClient::Command>(
- IVrComposerClient::VrCommand::SET_LAYER_INFO),
- kSetLayerInfoLength);
- write(type);
- write(appId);
- endCommand();
-}
-
-void Composer::CommandWriter::setClientTargetMetadata(
- const IVrComposerClient::BufferMetadata& metadata)
-{
- constexpr uint16_t kSetClientTargetMetadataLength = 7;
- beginCommand(static_cast<V2_1::IComposerClient::Command>(
- IVrComposerClient::VrCommand::SET_CLIENT_TARGET_METADATA),
- kSetClientTargetMetadataLength);
- writeBufferMetadata(metadata);
- endCommand();
-}
-
-void Composer::CommandWriter::setLayerBufferMetadata(
- const IVrComposerClient::BufferMetadata& metadata)
-{
- constexpr uint16_t kSetLayerBufferMetadataLength = 7;
- beginCommand(static_cast<V2_1::IComposerClient::Command>(
- IVrComposerClient::VrCommand::SET_LAYER_BUFFER_METADATA),
- kSetLayerBufferMetadataLength);
- writeBufferMetadata(metadata);
- endCommand();
-}
-
-void Composer::CommandWriter::writeBufferMetadata(
- const IVrComposerClient::BufferMetadata& metadata)
-{
- write(metadata.width);
- write(metadata.height);
- write(metadata.stride);
- write(metadata.layerCount);
- writeSigned(static_cast<int32_t>(metadata.format));
- write64(metadata.usage);
-}
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-
-Composer::Composer(const std::string& serviceName)
- : mWriter(kWriterInitialSize),
- mIsUsingVrComposer(serviceName == std::string("vr"))
-{
+Composer::Composer(const std::string& serviceName) : mWriter(kWriterInitialSize) {
mComposer = V2_1::IComposer::getService(serviceName);
if (mComposer == nullptr) {
@@ -215,15 +159,6 @@
if (mClient == nullptr) {
LOG_ALWAYS_FATAL("failed to create composer client");
}
-
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
- if (mIsUsingVrComposer) {
- sp<IVrComposerClient> vrClient = IVrComposerClient::castFrom(mClient);
- if (vrClient == nullptr) {
- LOG_ALWAYS_FATAL("failed to create vr composer client");
- }
- }
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
}
Composer::~Composer() = default;
@@ -262,10 +197,6 @@
}
}
-bool Composer::isRemote() {
- return mClient->isRemote();
-}
-
void Composer::resetCommands() {
mWriter.reset();
}
@@ -587,20 +518,6 @@
{
mWriter.selectDisplay(display);
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
- if (mIsUsingVrComposer && target.get()) {
- IVrComposerClient::BufferMetadata metadata = {
- .width = target->getWidth(),
- .height = target->getHeight(),
- .stride = target->getStride(),
- .layerCount = target->getLayerCount(),
- .format = static_cast<types::V1_2::PixelFormat>(target->getPixelFormat()),
- .usage = target->getUsage(),
- };
- mWriter.setClientTargetMetadata(metadata);
- }
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-
const native_handle_t* handle = nullptr;
if (target.get()) {
handle = target->getNativeBuffer()->handle;
@@ -720,20 +637,6 @@
mWriter.selectDisplay(display);
mWriter.selectLayer(layer);
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
- if (mIsUsingVrComposer && buffer.get()) {
- IVrComposerClient::BufferMetadata metadata = {
- .width = buffer->getWidth(),
- .height = buffer->getHeight(),
- .stride = buffer->getStride(),
- .layerCount = buffer->getLayerCount(),
- .format = static_cast<types::V1_2::PixelFormat>(buffer->getPixelFormat()),
- .usage = buffer->getUsage(),
- };
- mWriter.setLayerBufferMetadata(metadata);
- }
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-
const native_handle_t* handle = nullptr;
if (buffer.get()) {
handle = buffer->getNativeBuffer()->handle;
@@ -850,27 +753,6 @@
return Error::NONE;
}
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-Error Composer::setLayerInfo(Display display, Layer layer, uint32_t type,
- uint32_t appId)
-{
- if (mIsUsingVrComposer) {
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerInfo(type, appId);
- }
- return Error::NONE;
-}
-#else
-Error Composer::setLayerInfo(Display display, Layer layer, uint32_t, uint32_t) {
- if (mIsUsingVrComposer) {
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- }
- return Error::NONE;
-}
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-
Error Composer::execute()
{
// prepare input command queue
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 00ef782..5b66809 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -27,9 +27,6 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
#include <android/hardware/graphics/common/1.1/types.h>
#include <android/hardware/graphics/composer/2.4/IComposer.h>
#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
@@ -47,10 +44,6 @@
namespace Hwc2 {
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-using frameworks::vr::composer::V2_0::IVrComposerClient;
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-
namespace types = hardware::graphics::common;
namespace V2_1 = hardware::graphics::composer::V2_1;
@@ -91,11 +84,6 @@
virtual void registerCallback(const sp<IComposerCallback>& callback) = 0;
- // Returns true if the connected composer service is running in a remote
- // process, false otherwise. This will return false if the service is
- // configured in passthrough mode, for example.
- virtual bool isRemote() = 0;
-
// Reset all pending commands in the command buffer. Useful if you want to
// skip a frame but have already queued some commands.
virtual void resetCommands() = 0;
@@ -104,7 +92,6 @@
virtual Error executeCommands() = 0;
virtual uint32_t getMaxVirtualDisplayCount() = 0;
- virtual bool isUsingVrComposer() const = 0;
virtual Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
Display* outDisplay) = 0;
virtual Error destroyVirtualDisplay(Display display) = 0;
@@ -188,7 +175,6 @@
virtual Error setLayerVisibleRegion(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& visible) = 0;
virtual Error setLayerZOrder(Display display, Layer layer, uint32_t z) = 0;
- virtual Error setLayerInfo(Display display, Layer layer, uint32_t type, uint32_t appId) = 0;
// Composer HAL 2.2
virtual Error setLayerPerFrameMetadata(
@@ -344,11 +330,6 @@
void registerCallback(const sp<IComposerCallback>& callback) override;
- // Returns true if the connected composer service is running in a remote
- // process, false otherwise. This will return false if the service is
- // configured in passthrough mode, for example.
- bool isRemote() override;
-
// Reset all pending commands in the command buffer. Useful if you want to
// skip a frame but have already queued some commands.
void resetCommands() override;
@@ -357,7 +338,6 @@
Error executeCommands() override;
uint32_t getMaxVirtualDisplayCount() override;
- bool isUsingVrComposer() const override { return mIsUsingVrComposer; }
Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
Display* outDisplay) override;
Error destroyVirtualDisplay(Display display) override;
@@ -436,7 +416,6 @@
Error setLayerVisibleRegion(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& visible) override;
Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
- Error setLayerInfo(Display display, Layer layer, uint32_t type, uint32_t appId) override;
// Composer HAL 2.2
Error setLayerPerFrameMetadata(
@@ -490,29 +469,11 @@
IComposerClient::ClientTargetProperty* outClientTargetProperty) override;
private:
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
- class CommandWriter : public CommandWriterBase {
- public:
- explicit CommandWriter(uint32_t initialMaxSize);
- ~CommandWriter() override;
-
- void setLayerInfo(uint32_t type, uint32_t appId);
- void setClientTargetMetadata(
- const IVrComposerClient::BufferMetadata& metadata);
- void setLayerBufferMetadata(
- const IVrComposerClient::BufferMetadata& metadata);
-
- private:
- void writeBufferMetadata(
- const IVrComposerClient::BufferMetadata& metadata);
- };
-#else
class CommandWriter : public CommandWriterBase {
public:
explicit CommandWriter(uint32_t initialMaxSize) : CommandWriterBase(initialMaxSize) {}
~CommandWriter() override {}
};
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
// Many public functions above simply write a command into the command
// queue to batch the calls. validateDisplay and presentDisplay will call
@@ -531,10 +492,6 @@
64 * 1024 / sizeof(uint32_t) - 16;
CommandWriter mWriter;
CommandReader mReader;
-
- // When true, the we attach to the vr_hwcomposer service instead of the
- // hwcomposer. This allows us to redirect surfaces to 3d surfaces in vr.
- const bool mIsUsingVrComposer;
};
} // namespace impl
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 08559bd..e6bff04 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -977,12 +977,6 @@
return static_cast<Error>(intError);
}
-Error Layer::setInfo(uint32_t type, uint32_t appId)
-{
- auto intError = mComposer.setLayerInfo(mDisplayId, mId, type, appId);
- return static_cast<Error>(intError);
-}
-
// Composer HAL 2.3
Error Layer::setColorTransform(const android::mat4& matrix) {
if (matrix == mColorMatrix) {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 12f26f6..1f03787 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -378,7 +378,6 @@
[[clang::warn_unused_result]] virtual hal::Error setVisibleRegion(
const android::Region& region) = 0;
[[clang::warn_unused_result]] virtual hal::Error setZOrder(uint32_t z) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setInfo(uint32_t type, uint32_t appId) = 0;
// Composer HAL 2.3
[[clang::warn_unused_result]] virtual hal::Error setColorTransform(
@@ -420,7 +419,6 @@
hal::Error setTransform(hal::Transform transform) override;
hal::Error setVisibleRegion(const android::Region& region) override;
hal::Error setZOrder(uint32_t z) override;
- hal::Error setInfo(uint32_t type, uint32_t appId) override;
// Composer HAL 2.3
hal::Error setColorTransform(const android::mat4& matrix) override;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 05ef599..195182a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -816,10 +816,6 @@
});
}
-bool HWComposer::isUsingVrComposer() const {
- return getComposer()->isUsingVrComposer();
-}
-
status_t HWComposer::setAutoLowLatencyMode(DisplayId displayId, bool on) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
const auto error = mDisplayData[displayId].hwcDisplay->setAutoLowLatencyMode(on);
@@ -886,11 +882,6 @@
bool HWComposer::shouldIgnoreHotplugConnect(hal::HWDisplayId hwcDisplayId,
bool hasDisplayIdentificationData) const {
- if (isUsingVrComposer() && mInternalHwcDisplayId) {
- ALOGE("Ignoring connection of external display %" PRIu64 " in VR mode", hwcDisplayId);
- return true;
- }
-
if (mHasMultiDisplaySupport && !hasDisplayIdentificationData) {
ALOGE("Ignoring connection of display %" PRIu64 " without identification data",
hwcDisplayId);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 698e3af..488cdc5 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -190,8 +190,6 @@
virtual status_t setActiveColorMode(DisplayId, ui::ColorMode mode, ui::RenderIntent) = 0;
- virtual bool isUsingVrComposer() const = 0;
-
// Composer 2.4
virtual DisplayConnectionType getDisplayConnectionType(DisplayId) const = 0;
virtual bool isVsyncPeriodSwitchSupported(DisplayId) const = 0;
@@ -324,8 +322,6 @@
status_t setActiveColorMode(DisplayId, ui::ColorMode, ui::RenderIntent) override;
- bool isUsingVrComposer() const override;
-
// Composer 2.4
DisplayConnectionType getDisplayConnectionType(DisplayId) const override;
bool isVsyncPeriodSwitchSupported(DisplayId) const override;
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index c95440a..a12f4c7 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -20,6 +20,7 @@
#include "FrameTimeline.h"
#include <android-base/stringprintf.h>
+#include <utils/Trace.h>
#include <cinttypes>
namespace android::frametimeline::impl {
@@ -27,6 +28,7 @@
using base::StringAppendF;
int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
+ ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
const int64_t assignedToken = mCurrentToken++;
mPredictions[assignedToken] = predictions;
@@ -88,18 +90,34 @@
return mActuals;
}
-void SurfaceFrame::setActuals(frametimeline::TimelineItem&& actuals) {
+nsecs_t SurfaceFrame::getActualQueueTime() {
std::lock_guard<std::mutex> lock(mMutex);
- mActuals = actuals;
+ return mActualQueueTime;
}
-void SurfaceFrame::setPresentTime(nsecs_t presentTime) {
+void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mActuals.startTime = actualStartTime;
+}
+
+void SurfaceFrame::setActualQueueTime(nsecs_t actualQueueTime) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mActualQueueTime = actualQueueTime;
+}
+void SurfaceFrame::setActualEndTime(nsecs_t actualEndTime) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mActuals.endTime = actualEndTime;
+}
+
+void SurfaceFrame::setActualPresentTime(nsecs_t presentTime) {
std::lock_guard<std::mutex> lock(mMutex);
mActuals.presentTime = presentTime;
}
void SurfaceFrame::dump(std::string& result) {
std::lock_guard<std::mutex> lock(mMutex);
+ StringAppendF(&result, "Present State : %d\n", static_cast<int>(mPresentState));
+ StringAppendF(&result, "Prediction State : %d\n", static_cast<int>(mPredictionState));
StringAppendF(&result, "Predicted Start Time : %" PRId64 "\n", mPredictions.startTime);
StringAppendF(&result, "Actual Start Time : %" PRId64 "\n", mActuals.startTime);
StringAppendF(&result, "Actual Queue Time : %" PRId64 "\n", mActualQueueTime);
@@ -120,6 +138,7 @@
std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
const std::string& layerName, std::optional<int64_t> token) {
+ ATRACE_CALL();
if (!token) {
return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::None,
TimelineItem());
@@ -136,6 +155,7 @@
void FrameTimeline::addSurfaceFrame(
std::unique_ptr<android::frametimeline::SurfaceFrame> surfaceFrame,
SurfaceFrame::PresentState state) {
+ ATRACE_CALL();
surfaceFrame->setPresentState(state);
std::unique_ptr<impl::SurfaceFrame> implSurfaceFrame(
static_cast<impl::SurfaceFrame*>(surfaceFrame.release()));
@@ -144,18 +164,21 @@
}
void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) {
+ ATRACE_CALL();
const std::optional<TimelineItem> prediction = mTokenManager.getPredictionsForToken(token);
std::lock_guard<std::mutex> lock(mMutex);
if (!prediction) {
mCurrentDisplayFrame->predictionState = PredictionState::Expired;
} else {
mCurrentDisplayFrame->surfaceFlingerPredictions = *prediction;
+ mCurrentDisplayFrame->predictionState = PredictionState::Valid;
}
mCurrentDisplayFrame->surfaceFlingerActuals.startTime = wakeUpTime;
}
void FrameTimeline::setSfPresent(nsecs_t sfPresentTime,
const std::shared_ptr<FenceTime>& presentFence) {
+ ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
mCurrentDisplayFrame->surfaceFlingerActuals.endTime = sfPresentTime;
mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame));
@@ -179,7 +202,7 @@
for (auto& surfaceFrame : displayFrame->surfaceFrames) {
if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) {
// Only presented SurfaceFrames need to be updated
- surfaceFrame->setPresentTime(signalTime);
+ surfaceFrame->setActualPresentTime(signalTime);
}
}
}
@@ -204,6 +227,8 @@
StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size());
for (const auto& displayFrame : mDisplayFrames) {
StringAppendF(&result, "---Display Frame---\n");
+ StringAppendF(&result, "Prediction State : %d\n",
+ static_cast<int>(displayFrame->predictionState));
StringAppendF(&result, "Predicted SF wake time : %" PRId64 "\n",
displayFrame->surfaceFlingerPredictions.startTime);
StringAppendF(&result, "Actual SF wake time : %" PRId64 "\n",
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 291e30e..a42c32c 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -51,7 +51,7 @@
// Generates a token for the given set of predictions. Stores the predictions for 120ms and
// destroys it later.
- virtual int64_t generateTokenForPredictions(TimelineItem&& prediction);
+ virtual int64_t generateTokenForPredictions(TimelineItem&& prediction) = 0;
};
enum class PredictionState {
@@ -76,15 +76,18 @@
virtual TimelineItem getPredictions() = 0;
virtual TimelineItem getActuals() = 0;
+ virtual nsecs_t getActualQueueTime() = 0;
virtual PresentState getPresentState() = 0;
virtual PredictionState getPredictionState() = 0;
virtual void setPresentState(PresentState state) = 0;
- virtual void setActuals(TimelineItem&& actuals) = 0;
- // There is no prediction for Queue time and it is not a part of TimelineItem. Set it
- // separately.
+ // Actual timestamps of the app are set individually at different functions.
+ // Start time (if the app provides) and Queue time are accessible after queueing the frame,
+ // whereas End time is available only during latch.
+ virtual void setActualStartTime(nsecs_t actualStartTime) = 0;
virtual void setActualQueueTime(nsecs_t actualQueueTime) = 0;
+ virtual void setActualEndTime(nsecs_t actualEndTime) = 0;
};
/*
@@ -94,7 +97,7 @@
class FrameTimeline {
public:
virtual ~FrameTimeline() = default;
- virtual TokenManager& getTokenManager() = 0;
+ virtual TokenManager* getTokenManager() = 0;
// Create a new surface frame, set the predictions based on a token and return it to the caller.
// Sets the PredictionState of SurfaceFrame.
@@ -115,6 +118,8 @@
// that vsync.
virtual void setSfPresent(nsecs_t sfPresentTime,
const std::shared_ptr<FenceTime>& presentFence) = 0;
+
+ virtual void dump(std::string& result) = 0;
};
namespace impl {
@@ -151,14 +156,15 @@
TimelineItem getPredictions() override { return mPredictions; };
TimelineItem getActuals() override;
+ nsecs_t getActualQueueTime() override;
PresentState getPresentState() override;
PredictionState getPredictionState() override;
- void setActuals(TimelineItem&& actuals) override;
- void setActualQueueTime(nsecs_t actualQueueTime) override {
- mActualQueueTime = actualQueueTime;
- };
+
+ void setActualStartTime(nsecs_t actualStartTime) override;
+ void setActualQueueTime(nsecs_t actualQueueTime) override;
+ void setActualEndTime(nsecs_t actualEndTime) override;
void setPresentState(PresentState state) override;
- void setPresentTime(nsecs_t presentTime);
+ void setActualPresentTime(nsecs_t presentTime);
void dump(std::string& result);
private:
@@ -176,7 +182,7 @@
FrameTimeline();
~FrameTimeline() = default;
- frametimeline::TokenManager& getTokenManager() override { return mTokenManager; }
+ frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
std::unique_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken(
const std::string& layerName, std::optional<int64_t> token) override;
void addSurfaceFrame(std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame,
@@ -184,7 +190,7 @@
void setSfWakeUp(int64_t token, nsecs_t wakeupTime) override;
void setSfPresent(nsecs_t sfPresentTime,
const std::shared_ptr<FenceTime>& presentFence) override;
- void dump(std::string& result);
+ void dump(std::string& result) override;
private:
// Friend class for testing
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index eced6bd..85046a4 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -89,6 +89,8 @@
if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
if (args.flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure;
+ if (args.flags & ISurfaceComposerClient::eSkipScreenshot)
+ layerFlags |= layer_state_t::eLayerSkipScreenshot;
mCurrentState.active_legacy.w = args.w;
mCurrentState.active_legacy.h = args.h;
@@ -504,9 +506,6 @@
compositionState->geomUsesSourceCrop = usesSourceCrop();
compositionState->isSecure = isSecure();
- compositionState->type = type;
- compositionState->appId = appId;
-
compositionState->metadata.clear();
const auto& supportedMetadata = mFlinger->getHwComposer().getSupportedLayerGenericMetadata();
for (const auto& [key, mandatory] : supportedMetadata) {
@@ -1435,6 +1434,10 @@
return true;
}
+void Layer::setFrameTimelineVsync(int64_t frameTimelineVsyncId) {
+ mFrameTimelineVsyncId = frameTimelineVsyncId;
+}
+
Layer::FrameRate Layer::getFrameRateForLayerTree() const {
const auto frameRate = getDrawingState().frameRate;
if (frameRate.rate > 0 || frameRate.type == FrameRateCompatibility::NoVote) {
@@ -2415,32 +2418,64 @@
const float xScale = t.getScaleX();
const float yScale = t.getScaleY();
if (xScale != 1.0f || yScale != 1.0f) {
- info.touchableRegion.scaleSelf(xScale, yScale);
xSurfaceInset = std::round(xSurfaceInset * xScale);
ySurfaceInset = std::round(ySurfaceInset * yScale);
}
- layerBounds = t.transform(layerBounds);
+ Rect transformedLayerBounds = t.transform(layerBounds);
// clamp inset to layer bounds
- xSurfaceInset = (xSurfaceInset >= 0) ? std::min(xSurfaceInset, layerBounds.getWidth() / 2) : 0;
- ySurfaceInset = (ySurfaceInset >= 0) ? std::min(ySurfaceInset, layerBounds.getHeight() / 2) : 0;
+ xSurfaceInset = (xSurfaceInset >= 0)
+ ? std::min(xSurfaceInset, transformedLayerBounds.getWidth() / 2)
+ : 0;
+ ySurfaceInset = (ySurfaceInset >= 0)
+ ? std::min(ySurfaceInset, transformedLayerBounds.getHeight() / 2)
+ : 0;
- layerBounds.inset(xSurfaceInset, ySurfaceInset, xSurfaceInset, ySurfaceInset);
+ // inset while protecting from overflow TODO(b/161235021): What is going wrong
+ // in the overflow scenario?
+ {
+ int32_t tmp;
+ if (!__builtin_add_overflow(transformedLayerBounds.left, xSurfaceInset, &tmp))
+ transformedLayerBounds.left = tmp;
+ if (!__builtin_sub_overflow(transformedLayerBounds.right, xSurfaceInset, &tmp))
+ transformedLayerBounds.right = tmp;
+ if (!__builtin_add_overflow(transformedLayerBounds.top, ySurfaceInset, &tmp))
+ transformedLayerBounds.top = tmp;
+ if (!__builtin_sub_overflow(transformedLayerBounds.bottom, ySurfaceInset, &tmp))
+ transformedLayerBounds.bottom = tmp;
+ }
// Input coordinate should match the layer bounds.
- info.frameLeft = layerBounds.left;
- info.frameTop = layerBounds.top;
- info.frameRight = layerBounds.right;
- info.frameBottom = layerBounds.bottom;
+ info.frameLeft = transformedLayerBounds.left;
+ info.frameTop = transformedLayerBounds.top;
+ info.frameRight = transformedLayerBounds.right;
+ info.frameBottom = transformedLayerBounds.bottom;
+ // Compute the correct transform to send to input. This will allow it to transform the
+ // input coordinates from display space into window space. Therefore, it needs to use the
+ // final layer frame to create the inverse transform. Since surface insets are added later,
+ // along with the overflow, the best way to ensure we get the correct transform is to use
+ // the final frame calculated.
+ // 1. Take the original transform set on the window and get the inverse transform. This is
+ // used to get the final bounds in display space (ignorning the transform). Apply the
+ // inverse transform on the layerBounds to get the untransformed frame (in display space)
+ // 2. Take the top and left of the untransformed frame to get the real position on screen.
+ // Apply the layer transform on top/left so it includes any scale or rotation. These will
+ // be the new translation values for the transform.
+ // 3. Update the translation of the original transform to the new translation values.
+ // 4. Send the inverse transform to input so the coordinates can be transformed back into
+ // window space.
+ ui::Transform inverseTransform = t.inverse();
+ Rect nonTransformedBounds = inverseTransform.transform(transformedLayerBounds);
+ vec2 translation = t.transform(nonTransformedBounds.left, nonTransformedBounds.top);
ui::Transform inputTransform(t);
- inputTransform.set(layerBounds.left, layerBounds.top);
+ inputTransform.set(translation.x, translation.y);
info.transform = inputTransform.inverse();
// Position the touchable region relative to frame screen location and restrict it to frame
// bounds.
- info.touchableRegion = info.touchableRegion.translate(info.frameLeft, info.frameTop);
+ info.touchableRegion = inputTransform.transform(info.touchableRegion);
// For compatibility reasons we let layers which can receive input
// receive input before they have actually submitted a buffer. Because
// of this we use canReceiveInput instead of isVisible to check the
@@ -2649,6 +2684,16 @@
}
}
+bool Layer::getPrimaryDisplayOnly() const {
+ const State& s(mDrawingState);
+ if (s.flags & layer_state_t::eLayerSkipScreenshot) {
+ return true;
+ }
+
+ sp<Layer> parent = mDrawingParent.promote();
+ return parent == nullptr ? false : parent->getPrimaryDisplayOnly();
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 913f13a..88ece50 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -695,8 +695,7 @@
InputWindowInfo::Type getWindowType() const { return mWindowType; }
- void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; }
- bool getPrimaryDisplayOnly() const { return mPrimaryDisplayOnly; }
+ bool getPrimaryDisplayOnly() const;
void updateMirrorInfo();
@@ -822,6 +821,8 @@
bool setFrameRate(FrameRate);
+ void setFrameTimelineVsync(int64_t frameTimelineVsyncId);
+
// Creates a new handle each time, so we only expect
// this to be called once.
sp<IBinder> getHandle();
@@ -961,8 +962,6 @@
const std::string mName;
const std::string mTransactionName{"TX - " + mName};
- bool mPrimaryDisplayOnly = false;
-
// These are only accessed by the main thread or the tracing thread.
State mDrawingState;
// Store a copy of the pending state so that the drawing thread can access the
@@ -1022,6 +1021,9 @@
// Can only be accessed with the SF state lock held.
bool mChildrenChanged{false};
+ // Can only be accessed with the SF state lock held.
+ std::optional<int64_t> mFrameTimelineVsyncId;
+
// Window types from WindowManager.LayoutParams
const InputWindowInfo::Type mWindowType;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index a2fc692..b7b7e46 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -29,6 +29,7 @@
#include <compositionengine/impl/OutputCompositionState.h>
#include <cutils/properties.h>
#include <gui/IRegionSamplingListener.h>
+#include <gui/SyncScreenCaptureListener.h>
#include <ui/DisplayStatInfo.h>
#include <utils/Trace.h>
@@ -441,27 +442,12 @@
mCachedBuffer->getHeight() == sampledBounds.getHeight()) {
buffer = mCachedBuffer;
} else {
- const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
+ const uint32_t usage =
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(),
PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
}
- class SyncScreenCaptureListener : public BnScreenCaptureListener {
- public:
- status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override {
- resultsPromise.set_value(captureResults);
- return NO_ERROR;
- }
-
- ScreenCaptureResults waitForResults() {
- std::future<ScreenCaptureResults> resultsFuture = resultsPromise.get_future();
- return resultsFuture.get();
- }
-
- private:
- std::promise<ScreenCaptureResults> resultsPromise;
- };
-
const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
true /* regionSampling */, captureListener);
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index f513535..3307388 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -40,6 +40,7 @@
#include <utils/Trace.h>
#include "EventThread.h"
+#include "FrameTimeline.h"
#include "HwcStrongTypes.h"
using namespace std::chrono_literals;
@@ -99,12 +100,13 @@
DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp,
uint32_t count, nsecs_t expectedVSyncTimestamp,
- nsecs_t deadlineTimestamp) {
+ nsecs_t deadlineTimestamp, int64_t vsyncId) {
DisplayEventReceiver::Event event;
event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
event.vsync.count = count;
event.vsync.expectedVSyncTimestamp = expectedVSyncTimestamp;
event.vsync.deadlineTimestamp = deadlineTimestamp;
+ event.vsync.vsyncId = vsyncId;
return event;
}
@@ -165,8 +167,10 @@
namespace impl {
EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
+ android::frametimeline::TokenManager* tokenManager,
InterceptVSyncsCallback interceptVSyncsCallback)
: mVSyncSource(std::move(vsyncSource)),
+ mTokenManager(tokenManager),
mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
mThreadName(mVSyncSource->getName()) {
mVSyncSource->setCallback(this);
@@ -291,8 +295,16 @@
std::lock_guard<std::mutex> lock(mMutex);
LOG_FATAL_IF(!mVSyncState);
+ const int64_t vsyncId = [&] {
+ if (mTokenManager != nullptr) {
+ return mTokenManager->generateTokenForPredictions(
+ {timestamp, deadlineTimestamp, expectedVSyncTimestamp});
+ }
+ return static_cast<int64_t>(0);
+ }();
+
mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
- expectedVSyncTimestamp, deadlineTimestamp));
+ expectedVSyncTimestamp, deadlineTimestamp, vsyncId));
mCondition.notify_all();
}
@@ -416,9 +428,10 @@
const auto now = systemTime(SYSTEM_TIME_MONOTONIC);
const auto deadlineTimestamp = now + timeout.count();
const auto expectedVSyncTime = deadlineTimestamp + timeout.count();
+ // TODO(b/162890590): use TokenManager to populate vsyncId
mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now,
++mVSyncState->count, expectedVSyncTime,
- deadlineTimestamp));
+ deadlineTimestamp, /*vsyncId=*/0));
}
}
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index fa1ca64..80bd606 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -41,6 +41,10 @@
class EventThreadTest;
class SurfaceFlinger;
+namespace frametimeline {
+class TokenManager;
+} // namespace frametimeline
+
// ---------------------------------------------------------------------------
using ResyncCallback = std::function<void()>;
@@ -137,7 +141,8 @@
public:
using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
- EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback);
+ EventThread(std::unique_ptr<VSyncSource>, frametimeline::TokenManager*,
+ InterceptVSyncsCallback);
~EventThread();
sp<EventThreadConnection> createEventConnection(
@@ -185,6 +190,7 @@
nsecs_t deadlineTimestamp) override;
const std::unique_ptr<VSyncSource> mVSyncSource GUARDED_BY(mMutex);
+ frametimeline::TokenManager* const mTokenManager;
const InterceptVSyncsCallback mInterceptVSyncsCallback;
const char* const mThreadName;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 6067e69..641a0a3 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -39,8 +39,9 @@
}
}
-void MessageQueue::Handler::dispatchInvalidate(nsecs_t expectedVSyncTimestamp) {
+void MessageQueue::Handler::dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp) {
if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
+ mVsyncId = vsyncId;
mExpectedVSyncTime = expectedVSyncTimestamp;
mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
}
@@ -50,11 +51,11 @@
switch (message.what) {
case INVALIDATE:
android_atomic_and(~eventMaskInvalidate, &mEventMask);
- mQueue.mFlinger->onMessageReceived(message.what, mExpectedVSyncTime);
+ mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
break;
case REFRESH:
android_atomic_and(~eventMaskRefresh, &mEventMask);
- mQueue.mFlinger->onMessageReceived(message.what, mExpectedVSyncTime);
+ mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
break;
}
}
@@ -123,7 +124,8 @@
while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
for (int i = 0; i < n; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
- mHandler->dispatchInvalidate(buffer[i].vsync.expectedVSyncTimestamp);
+ mHandler->dispatchInvalidate(buffer[i].vsync.vsyncId,
+ buffer[i].vsync.expectedVSyncTimestamp);
break;
}
}
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 132b416..e263b2f 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -79,13 +79,14 @@
enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 };
MessageQueue& mQueue;
int32_t mEventMask;
+ std::atomic<int64_t> mVsyncId;
std::atomic<nsecs_t> mExpectedVSyncTime;
public:
explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {}
virtual void handleMessage(const Message& message);
void dispatchRefresh();
- void dispatchInvalidate(nsecs_t expectedVSyncTimestamp);
+ void dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp);
};
friend class Handler;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 5271ccc..9c145cc 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -31,6 +31,7 @@
#include <utils/Timers.h>
#include <utils/Trace.h>
+#include <FrameTimeline/FrameTimeline.h>
#include <algorithm>
#include <cinttypes>
#include <cstdint>
@@ -212,11 +213,11 @@
}
Scheduler::ConnectionHandle Scheduler::createConnection(
- const char* connectionName, std::chrono::nanoseconds workDuration,
- std::chrono::nanoseconds readyDuration,
+ const char* connectionName, frametimeline::TokenManager* tokenManager,
+ std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration);
- auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource),
+ auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource), tokenManager,
std::move(interceptCallback));
return createConnection(std::move(eventThread));
}
@@ -332,6 +333,7 @@
auto eventThread =
std::make_unique<impl::EventThread>(std::move(vsyncSource),
+ /*tokenManager=*/nullptr,
impl::EventThread::InterceptVSyncsCallback());
mInjectorConnectionHandle = createConnection(std::move(eventThread));
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 0b5c9d2..da25f5c 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -50,6 +50,10 @@
class VSyncTracker;
} // namespace scheduler
+namespace frametimeline {
+class TokenManager;
+} // namespace frametimeline
+
struct ISchedulerCallback {
virtual void setVsyncEnabled(bool) = 0;
virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
@@ -70,7 +74,7 @@
~Scheduler();
using ConnectionHandle = scheduler::ConnectionHandle;
- ConnectionHandle createConnection(const char* connectionName,
+ ConnectionHandle createConnection(const char* connectionName, frametimeline::TokenManager*,
std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration,
impl::EventThread::InterceptVSyncsCallback);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9d35a3f..6a0f24a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -48,7 +48,6 @@
#include <cutils/compiler.h>
#include <cutils/properties.h>
#include <dlfcn.h>
-#include <dvr/vr_flinger.h>
#include <errno.h>
#include <gui/BufferQueue.h>
#include <gui/DebugEGLImageTracker.h>
@@ -284,7 +283,6 @@
bool SurfaceFlinger::useHwcForRgbToYuv;
uint64_t SurfaceFlinger::maxVirtualDisplaySize;
bool SurfaceFlinger::hasSyncFramework;
-bool SurfaceFlinger::useVrFlinger;
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
uint32_t SurfaceFlinger::maxGraphicsWidth;
uint32_t SurfaceFlinger::maxGraphicsHeight;
@@ -333,7 +331,7 @@
mInterceptor(mFactory.createSurfaceInterceptor(this)),
mTimeStats(std::make_shared<impl::TimeStats>()),
mFrameTracer(std::make_unique<FrameTracer>()),
- mFrameTimeline(std::make_shared<frametimeline::impl::FrameTimeline>()),
+ mFrameTimeline(std::make_unique<frametimeline::impl::FrameTimeline>()),
mEventQueue(mFactory.createMessageQueue()),
mCompositionEngine(mFactory.createCompositionEngine()),
mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
@@ -352,9 +350,6 @@
maxVirtualDisplaySize = max_virtual_display_dimension(0);
- // Vr flinger is only enabled on Daydream ready devices.
- useVrFlinger = use_vr_flinger(false);
-
maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2);
maxGraphicsWidth = std::max(max_graphics_width(0), 0);
@@ -509,6 +504,15 @@
}
sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, bool secure) {
+ // onTransact already checks for some permissions, but adding an additional check here.
+ // This is to ensure that only system and graphics can request to create a secure
+ // display. Secure displays can show secure content so we add an additional restriction on it.
+ const int uid = IPCThreadState::self()->getCallingUid();
+ if (secure && uid != AID_GRAPHICS && uid != AID_SYSTEM) {
+ ALOGE("Only privileged processes can create a secure display");
+ return nullptr;
+ }
+
class DisplayToken : public BBinder {
sp<SurfaceFlinger> flinger;
virtual ~DisplayToken() {
@@ -624,10 +628,6 @@
mWindowManager->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
}
- if (mVrFlinger) {
- mVrFlinger->OnBootFinished();
- }
-
// stop boot animation
// formerly we would just kill the process, but we now ask it to exit so it
// can choose where to stop the animation.
@@ -711,9 +711,6 @@
: renderengine::RenderEngine::ContextPriority::MEDIUM)
.build()));
mCompositionEngine->setTimeStats(mTimeStats);
-
- LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
- "Starting with vr flinger active is not currently supported.");
mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName));
mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId);
// Process any initial hotplug and resulting display changes.
@@ -723,31 +720,6 @@
LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(*display->getId()),
"Internal display is disconnected.");
- if (useVrFlinger) {
- auto vrFlingerRequestDisplayCallback = [this](bool requestDisplay) {
- // This callback is called from the vr flinger dispatch thread. We
- // need to call signalTransaction(), which requires holding
- // mStateLock when we're not on the main thread. Acquiring
- // mStateLock from the vr flinger dispatch thread might trigger a
- // deadlock in surface flinger (see b/66916578), so post a message
- // to be handled on the main thread instead.
- static_cast<void>(schedule([=] {
- ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
- mVrFlingerRequestsDisplay = requestDisplay;
- signalTransaction();
- }));
- };
- auto hwcDisplayId =
- getHwComposer()
- .fromPhysicalDisplayId(static_cast<PhysicalDisplayId>(*display->getId()))
- .value_or(0);
- mVrFlinger = dvr::VrFlinger::Create(getHwComposer().getComposer(), hwcDisplayId,
- vrFlingerRequestDisplayCallback);
- if (!mVrFlinger) {
- ALOGE("Failed to start vrflinger");
- }
- }
-
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -1698,98 +1670,6 @@
}));
}
-void SurfaceFlinger::resetDisplayState() {
- mScheduler->disableHardwareVsync(true);
- // Clear the drawing state so that the logic inside of
- // handleTransactionLocked will fire. It will determine the delta between
- // mCurrentState and mDrawingState and re-apply all changes when we make the
- // transition.
- mDrawingState.displays.clear();
- mDisplays.clear();
-}
-
-void SurfaceFlinger::updateVrFlinger() {
- ATRACE_CALL();
- if (!mVrFlinger)
- return;
- bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
- if (vrFlingerRequestsDisplay == getHwComposer().isUsingVrComposer()) {
- return;
- }
-
- if (vrFlingerRequestsDisplay && !getHwComposer().getComposer()->isRemote()) {
- ALOGE("Vr flinger is only supported for remote hardware composer"
- " service connections. Ignoring request to transition to vr"
- " flinger.");
- mVrFlingerRequestsDisplay = false;
- return;
- }
-
- Mutex::Autolock _l(mStateLock);
-
- sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
- LOG_ALWAYS_FATAL_IF(!display);
-
- const hal::PowerMode currentDisplayPowerMode = display->getPowerMode();
-
- // Clear out all the output layers from the composition engine for all
- // displays before destroying the hardware composer interface. This ensures
- // any HWC layers are destroyed through that interface before it becomes
- // invalid.
- for (const auto& [token, displayDevice] : mDisplays) {
- displayDevice->getCompositionDisplay()->clearOutputLayers();
- }
-
- // This DisplayDevice will no longer be relevant once resetDisplayState() is
- // called below. Clear the reference now so we don't accidentally use it
- // later.
- display.clear();
-
- if (!vrFlingerRequestsDisplay) {
- mVrFlinger->SeizeDisplayOwnership();
- }
-
- resetDisplayState();
- // Delete the current instance before creating the new one
- mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
- mCompositionEngine->setHwComposer(getFactory().createHWComposer(
- vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName));
- mCompositionEngine->getHwComposer().setConfiguration(this, ++getBE().mComposerSequenceId);
-
- LOG_ALWAYS_FATAL_IF(!getHwComposer().getComposer()->isRemote(),
- "Switched to non-remote hardware composer");
-
- if (vrFlingerRequestsDisplay) {
- mVrFlinger->GrantDisplayOwnership();
- }
-
- mVisibleRegionsDirty = true;
- invalidateHwcGeometry();
-
- // Re-enable default display.
- display = getDefaultDisplayDeviceLocked();
- LOG_ALWAYS_FATAL_IF(!display);
- setPowerModeInternal(display, currentDisplayPowerMode);
-
- // Reset the timing values to account for the period of the swapped in HWC
- const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
- mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
-
- // The present fences returned from vr_hwc are not an accurate
- // representation of vsync times.
- mScheduler->setIgnorePresentFences(getHwComposer().isUsingVrComposer() || !hasSyncFramework);
-
- // Use phase of 0 since phase is not known.
- // Use latency of 0, which will snap to the ideal latency.
- DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
- setCompositorTimingSnapped(stats, 0);
-
- mScheduler->resyncToHardwareVsync(false, vsyncPeriod);
-
- mRepaintEverything = true;
- setTransactionFlags(eDisplayTransactionNeeded);
-}
-
sp<Fence> SurfaceFlinger::previousFrameFence() {
// We are storing the last 2 present fences. If sf's phase offset is to be
// woken up before the actual vsync but targeting the next vsync, we need to check
@@ -1830,11 +1710,11 @@
: stats.vsyncTime + stats.vsyncPeriod;
}
-void SurfaceFlinger::onMessageReceived(int32_t what, nsecs_t expectedVSyncTime) {
+void SurfaceFlinger::onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime) {
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
- onMessageInvalidate(expectedVSyncTime);
+ onMessageInvalidate(vsyncId, expectedVSyncTime);
break;
}
case MessageQueue::REFRESH: {
@@ -1844,7 +1724,7 @@
}
}
-void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) {
+void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime) {
ATRACE_CALL();
const nsecs_t frameStart = systemTime();
@@ -1955,11 +1835,6 @@
}
}
- // Now that we're going to make it to the handleMessageTransaction()
- // call below it's safe to call updateVrFlinger(), which will
- // potentially trigger a display handoff.
- updateVrFlinger();
-
if (mTracingEnabledChanged) {
mTracingEnabled = mTracing.isEnabled();
mTracingEnabledChanged = false;
@@ -1975,6 +1850,8 @@
{
ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled);
+ mFrameTimeline->setSfWakeUp(vsyncId, frameStart);
+
refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
if (mTracingEnabled) {
@@ -2102,6 +1979,9 @@
postFrame();
postComposition();
+ mFrameTimeline->setSfPresent(systemTime(),
+ std::make_shared<FenceTime>(mPreviousPresentFences[0]));
+
const bool prevFrameHadDeviceComposition = mHadDeviceComposition;
mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
@@ -2617,7 +2497,7 @@
builder.setIsSecure(state.isSecure);
builder.setLayerStackId(state.layerStack);
builder.setPowerAdvisor(&mPowerAdvisor);
- builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer());
+ builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays);
builder.setName(state.displayName);
const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
@@ -2989,12 +2869,12 @@
mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
const auto configs = mVsyncConfiguration->getCurrentConfigs();
mAppConnectionHandle =
- mScheduler->createConnection("app",
+ mScheduler->createConnection("app", mFrameTimeline->getTokenManager(),
/*workDuration=*/configs.late.appWorkDuration,
/*readyDuration=*/configs.late.sfWorkDuration,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
- mScheduler->createConnection("sf",
+ mScheduler->createConnection("sf", mFrameTimeline->getTokenManager(),
/*workDuration=*/configs.late.sfWorkDuration,
/*readyDuration=*/0ns, [this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
@@ -4007,23 +3887,6 @@
std::string uniqueName = getUniqueLayerName(name.string());
- bool primaryDisplayOnly = false;
-
- // window type is WINDOW_TYPE_DONT_SCREENSHOT from SurfaceControl.java
- // TODO b/64227542
- if (metadata.has(METADATA_WINDOW_TYPE)) {
- int32_t windowType = metadata.getInt32(METADATA_WINDOW_TYPE, 0);
- if (windowType == 441731) {
- using U = std::underlying_type_t<InputWindowInfo::Type>;
- // TODO(b/129481165): This static assert can be safely removed once conversion warnings
- // are re-enabled.
- static_assert(std::is_same_v<U, int32_t>);
- metadata.setInt32(METADATA_WINDOW_TYPE,
- static_cast<U>(InputWindowInfo::Type::NAVIGATION_BAR_PANEL));
- primaryDisplayOnly = true;
- }
- }
-
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceBufferQueue:
result = createBufferQueueLayer(client, std::move(uniqueName), w, h, flags,
@@ -4064,10 +3927,6 @@
return result;
}
- if (primaryDisplayOnly) {
- layer->setPrimaryDisplayOnly();
- }
-
bool addToCurrentState = callingThreadHasUnscopedSurfaceFlingerAccess();
result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer,
addToCurrentState, outTransformHint);
@@ -4365,6 +4224,7 @@
{"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)},
{"--vsync"s, dumper(&SurfaceFlinger::dumpVSync)},
{"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)},
+ {"--frametimeline"s, dumper([this](std::string& s) { mFrameTimeline->dump(s); })},
};
const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
@@ -4883,15 +4743,6 @@
const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
alloc.dump(result);
- /*
- * Dump VrFlinger state if in use.
- */
- if (mVrFlingerRequestsDisplay && mVrFlinger) {
- result.append("VrFlinger state:\n");
- result.append(mVrFlinger->Dump());
- result.append("\n");
- }
-
result.append(mTimeStats->miniDump());
result.append("\n");
}
@@ -5001,7 +4852,8 @@
// captureLayers and captureDisplay will handle the permission check in the function
case CAPTURE_LAYERS:
case CAPTURE_DISPLAY:
- case SET_DISPLAY_BRIGHTNESS: {
+ case SET_DISPLAY_BRIGHTNESS:
+ case SET_FRAME_TIMELINE_VSYNC: {
return OK;
}
@@ -5018,6 +4870,7 @@
}
return OK;
}
+ case ADD_TRANSACTION_TRACE_LISTENER:
case CAPTURE_DISPLAY_BY_ID: {
IPCThreadState* ipc = IPCThreadState::self();
const int uid = ipc->getCallingUid();
@@ -5276,11 +5129,8 @@
}
return NO_ERROR;
}
- // Is VrFlinger active?
- case 1028: {
- Mutex::Autolock _l(mStateLock);
- reply->writeBool(getHwComposer().isUsingVrComposer());
- return NO_ERROR;
+ case 1028: { // Unused.
+ return NAME_NOT_FOUND;
}
// Set buffer size for SF tracing (value in KB)
case 1029: {
@@ -6231,9 +6081,6 @@
// on the work to remove the table in that bug rather than adding more to
// it.
static const std::unordered_map<std::string, uint32_t> genericLayerMetadataKeyMap{
- // Note: METADATA_OWNER_UID and METADATA_WINDOW_TYPE are officially
- // supported, and exposed via the
- // IVrComposerClient::VrCommand::SET_LAYER_INFO command.
{"org.chromium.arc.V1_0.TaskId", METADATA_TASK_ID},
{"org.chromium.arc.V1_0.CursorInfo", METADATA_MOUSE_CURSOR},
};
@@ -6333,6 +6180,19 @@
}));
}
+status_t SurfaceFlinger::setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface,
+ int64_t frameTimelineVsyncId) {
+ Mutex::Autolock lock(mStateLock);
+ if (!authenticateSurfaceTextureLocked(surface)) {
+ ALOGE("Attempt to set frame timeline vsync on an unrecognized IGraphicBufferProducer");
+ return BAD_VALUE;
+ }
+
+ sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
+ layer->setFrameTimelineVsync(frameTimelineVsyncId);
+ return NO_ERROR;
+}
+
void SurfaceFlinger::enableRefreshRateOverlay(bool enable) {
static_cast<void>(schedule([=] {
std::unique_ptr<RefreshRateOverlay> overlay;
@@ -6356,6 +6216,17 @@
}));
}
+status_t SurfaceFlinger::addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& listener) {
+ if (!listener) {
+ return BAD_VALUE;
+ }
+
+ mInterceptor->addTransactionTraceListener(listener);
+
+ return NO_ERROR;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 28762c9..3b4d5d4 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -117,10 +117,6 @@
class RenderEngine;
} // namespace renderengine
-namespace dvr {
-class VrFlinger;
-} // namespace dvr
-
enum {
eTransactionNeeded = 0x01,
eTraversalNeeded = 0x02,
@@ -307,7 +303,7 @@
// called on the main thread by MessageQueue when an internal message
// is received
// TODO: this should be made accessible only to MessageQueue
- void onMessageReceived(int32_t what, nsecs_t expectedVSyncTime);
+ void onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime);
renderengine::RenderEngine& getRenderEngine() const;
@@ -597,6 +593,12 @@
int8_t compatibility) override;
status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) override;
+ status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface,
+ int64_t frameTimelineVsyncId) override;
+
+ status_t addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& listener) override;
+
// Implements IBinder::DeathRecipient.
void binderDied(const wp<IBinder>& who) override;
@@ -672,7 +674,7 @@
// Handle the INVALIDATE message queue event, latching new buffers and applying
// incoming transactions
- void onMessageInvalidate(nsecs_t expectedVSyncTime);
+ void onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime);
// Returns whether the transaction actually modified any state
bool handleMessageTransaction();
@@ -850,8 +852,7 @@
// The following thread safety rules apply when accessing mHwc, either
// directly or via getHwComposer():
//
- // 1. When recreating mHwc, acquire mStateLock. We currently recreate mHwc
- // only when switching into and out of vr. Recreating mHwc must only be
+ // 1. When recreating mHwc, acquire mStateLock. Recreating mHwc must only be
// done on the main thread.
//
// 2. When accessing mHwc on the main thread, it's not necessary to acquire
@@ -1008,14 +1009,6 @@
void onFrameRateFlexibilityTokenReleased();
- /*
- * VrFlinger
- */
- void resetDisplayState() REQUIRES(mStateLock);
-
- // Check to see if we should handoff to vr flinger.
- void updateVrFlinger();
-
void updateColorMatrixLocked();
// Verify that transaction is being called by an approved process:
@@ -1122,7 +1115,7 @@
volatile nsecs_t mDebugInTransaction = 0;
bool mForceFullDamage = false;
bool mPropagateBackpressureClientComposition = false;
- std::unique_ptr<SurfaceInterceptor> mInterceptor;
+ sp<SurfaceInterceptor> mInterceptor;
SurfaceTracing mTracing{*this};
std::mutex mTracingLock;
@@ -1132,7 +1125,7 @@
const std::shared_ptr<TimeStats> mTimeStats;
const std::unique_ptr<FrameTracer> mFrameTracer;
- const std::shared_ptr<frametimeline::FrameTimeline> mFrameTimeline;
+ const std::unique_ptr<frametimeline::FrameTimeline> mFrameTimeline;
bool mUseHwcVirtualDisplays = false;
// If blurs should be enabled on this device.
bool mSupportsBlur = false;
@@ -1186,9 +1179,6 @@
// to mWindowManager or mInputFlinger
std::atomic<bool> mBootFinished = false;
- std::unique_ptr<dvr::VrFlinger> mVrFlinger;
- std::atomic<bool> mVrFlingerRequestsDisplay = false;
- static bool useVrFlinger;
std::thread::id mMainThreadId = std::this_thread::get_id();
DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::kEnhanced;
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index fb08e69..93d36a6 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -68,9 +68,8 @@
return std::make_unique<Scheduler>(configs, callback);
}
-std::unique_ptr<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor(
- SurfaceFlinger* flinger) {
- return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
+sp<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor(SurfaceFlinger* flinger) {
+ return new android::impl::SurfaceInterceptor(flinger);
}
sp<StartPropertySetThread> DefaultFactory::createStartPropertySetThread(
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 86e5a7a..e06c2f4 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -32,7 +32,7 @@
const scheduler::RefreshRateConfigs&) override;
std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
ISchedulerCallback&) override;
- std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) override;
+ sp<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) override;
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override;
sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&) override;
sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 753476e..41ccc10 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -73,7 +73,7 @@
const scheduler::RefreshRateConfigs&) = 0;
virtual std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
ISchedulerCallback&) = 0;
- virtual std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
+ virtual sp<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
virtual sp<StartPropertySetThread> createStartPropertySetThread(
bool timestampPropertyValue) = 0;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index c15d0df..9d705e5 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -45,6 +45,24 @@
{
}
+void SurfaceInterceptor::addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& listener) {
+ sp<IBinder> asBinder = IInterface::asBinder(listener);
+
+ std::scoped_lock lock(mListenersMutex);
+
+ asBinder->linkToDeath(this);
+
+ listener->onToggled(mEnabled); // notifies of current state
+
+ mTraceToggledListeners.emplace(asBinder, listener);
+}
+
+void SurfaceInterceptor::binderDied(const wp<IBinder>& who) {
+ std::scoped_lock lock(mListenersMutex);
+ mTraceToggledListeners.erase(who);
+}
+
void SurfaceInterceptor::enable(const SortedVector<sp<Layer>>& layers,
const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays)
{
@@ -52,8 +70,14 @@
return;
}
ATRACE_CALL();
+ {
+ std::scoped_lock lock(mListenersMutex);
+ for (const auto& [_, listener] : mTraceToggledListeners) {
+ listener->onToggled(true);
+ }
+ }
mEnabled = true;
- std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+ std::scoped_lock<std::mutex> protoGuard(mTraceMutex);
saveExistingDisplaysLocked(displays);
saveExistingSurfacesLocked(layers);
}
@@ -63,8 +87,14 @@
return;
}
ATRACE_CALL();
- std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+ {
+ std::scoped_lock lock(mListenersMutex);
+ for (const auto& [_, listener] : mTraceToggledListeners) {
+ listener->onToggled(false);
+ }
+ }
mEnabled = false;
+ std::scoped_lock<std::mutex> protoGuard(mTraceMutex);
status_t err(writeProtoFileLocked());
ALOGE_IF(err == PERMISSION_DENIED, "Could not save the proto file! Permission denied");
ALOGE_IF(err == NOT_ENOUGH_DATA, "Could not save the proto file! There are missing fields");
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 1798b5a..4908bae 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -21,6 +21,8 @@
#include <mutex>
+#include <binder/IBinder.h>
+
#include <gui/LayerState.h>
#include <utils/KeyedVector.h>
@@ -48,7 +50,7 @@
constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
-class SurfaceInterceptor {
+class SurfaceInterceptor : public IBinder::DeathRecipient {
public:
virtual ~SurfaceInterceptor();
@@ -58,6 +60,10 @@
virtual void disable() = 0;
virtual bool isEnabled() = 0;
+ virtual void addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& listener) = 0;
+ virtual void binderDied(const wp<IBinder>& who) = 0;
+
// Intercept display and surface transactions
virtual void saveTransaction(
const Vector<ComposerState>& stateUpdates,
@@ -95,6 +101,9 @@
void disable() override;
bool isEnabled() override;
+ void addTransactionTraceListener(const sp<gui::ITransactionTraceListener>& listener) override;
+ void binderDied(const wp<IBinder>& who) override;
+
// Intercept display and surface transactions
void saveTransaction(const Vector<ComposerState>& stateUpdates,
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
@@ -193,6 +202,9 @@
std::mutex mTraceMutex {};
Trace mTrace {};
SurfaceFlinger* const mFlinger;
+ std::mutex mListenersMutex;
+ std::map<wp<IBinder>, sp<gui::ITransactionTraceListener>> mTraceToggledListeners
+ GUARDED_BY(mListenersMutex);
};
} // namespace impl
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 894ee6d..d77387a 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -112,7 +112,7 @@
StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
StringAppendF(&result, "displayConfigStats is as below:\n");
for (const auto& [fps, duration] : refreshRateStats) {
- StringAppendF(&result, "%dfps=%ldms ", fps, ns2ms(duration));
+ StringAppendF(&result, "%dfps = %ldms\n", fps, ns2ms(duration));
}
result.back() = '\n';
StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 7b1f0fb..7666f7f 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -72,7 +72,7 @@
prop {
api_name: "max_graphics_width"
type: Integer
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.max_graphics_width"
}
@@ -82,7 +82,7 @@
prop {
api_name: "max_graphics_height"
type: Integer
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.max_graphics_height"
}
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt
index b66e56e..ba60a7d 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt
@@ -36,6 +36,11 @@
prop_name: "ro.surface_flinger.display_primary_white"
}
prop {
+ api_name: "display_update_imminent_timeout_ms"
+ type: Integer
+ prop_name: "ro.surface_flinger.display_update_imminent_timeout_ms"
+ }
+ prop {
api_name: "enable_protected_contents"
prop_name: "ro.surface_flinger.protected_contents"
}
@@ -57,6 +62,16 @@
prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
}
prop {
+ api_name: "max_graphics_height"
+ type: Integer
+ prop_name: "ro.surface_flinger.max_graphics_height"
+ }
+ prop {
+ api_name: "max_graphics_width"
+ type: Integer
+ prop_name: "ro.surface_flinger.max_graphics_width"
+ }
+ prop {
api_name: "max_virtual_display_dimension"
type: Long
prop_name: "ro.surface_flinger.max_virtual_display_dimension"
@@ -73,6 +88,11 @@
enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270"
}
prop {
+ api_name: "refresh_rate_switching"
+ prop_name: "ro.surface_flinger.refresh_rate_switching"
+ deprecated: true
+ }
+ prop {
api_name: "running_without_sync_framework"
prop_name: "ro.surface_flinger.running_without_sync_framework"
}
@@ -100,16 +120,29 @@
prop_name: "ro.surface_flinger.support_kernel_idle_timer"
}
prop {
+ api_name: "supports_background_blur"
+ prop_name: "ro.surface_flinger.supports_background_blur"
+ }
+ prop {
api_name: "use_color_management"
prop_name: "ro.surface_flinger.use_color_management"
}
prop {
+ api_name: "use_content_detection_for_refresh_rate"
+ prop_name: "ro.surface_flinger.use_content_detection_for_refresh_rate"
+ }
+ prop {
api_name: "use_context_priority"
prop_name: "ro.surface_flinger.use_context_priority"
}
prop {
+ api_name: "use_frame_rate_api"
+ prop_name: "ro.surface_flinger.use_frame_rate_api"
+ }
+ prop {
api_name: "use_smart_90_for_video"
prop_name: "ro.surface_flinger.use_smart_90_for_video"
+ deprecated: true
}
prop {
api_name: "use_vr_flinger"
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index e2c038d..7f541e2 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -98,26 +98,6 @@
t.setLayer(mBGSurfaceControl, INT_MAX - 3).show(mBGSurfaceControl).apply());
}
- void setupVirtualDisplay() {
- mVirtualDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
- const ssize_t displayWidth = 100;
- const ssize_t displayHeight = 100;
-
- // Background surface
- mVirtualSurfaceControl =
- mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight,
- PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(mVirtualSurfaceControl != nullptr);
- ASSERT_TRUE(mVirtualSurfaceControl->isValid());
-
- Transaction t;
- t.setDisplayLayerStack(mVirtualDisplay, 0);
- ASSERT_EQ(NO_ERROR,
- t.setLayer(mVirtualSurfaceControl, INT_MAX - 3)
- .show(mVirtualSurfaceControl)
- .apply());
- }
-
/**
* Sets UID to imitate Graphic's process.
*/
@@ -165,6 +145,10 @@
// Check as a non-supported user.
setBinUID();
ASSERT_EQ(unprivilegedValue, condition());
+
+ // Check as shell since shell has some additional permissions
+ seteuid(AID_SHELL);
+ ASSERT_EQ(unprivilegedValue, condition());
}
};
@@ -262,11 +246,31 @@
}
TEST_F(CredentialsTest, CreateDisplayTest) {
+ // Only graphics and system processes can create a secure display.
std::function<bool()> condition = [=]() {
sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
return testDisplay.get() != nullptr;
};
- ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
+
+ // Check with root.
+ seteuid(AID_ROOT);
+ ASSERT_FALSE(condition());
+
+ // Check as a Graphics user.
+ setGraphicsUID();
+ ASSERT_TRUE(condition());
+
+ // Check as a system user.
+ setSystemUID();
+ ASSERT_TRUE(condition());
+
+ // Check as a non-supported user.
+ setBinUID();
+ ASSERT_FALSE(condition());
+
+ // Check as shell since shell has some additional permissions
+ seteuid(AID_SHELL);
+ ASSERT_FALSE(condition());
condition = [=]() {
sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 962a0cf..3ab2ad1 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -572,6 +572,97 @@
mCapture->expectBorder(Rect(128, 128, 160, 160), Color::BLACK);
}
+TEST_F(ScreenCaptureTest, CaptureDisplayPrimaryDisplayOnly) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test layer", 0, 0, ISurfaceComposerClient::eFXSurfaceEffect));
+
+ const Color layerColor = Color::RED;
+ const Rect bounds = Rect(10, 10, 40, 40);
+
+ Transaction()
+ .show(layer)
+ .hide(mFGSurfaceControl)
+ .setLayerStack(layer, 0)
+ .setLayer(layer, INT32_MAX)
+ .setColor(layer, {layerColor.r / 255, layerColor.g / 255, layerColor.b / 255})
+ .setCrop_legacy(layer, bounds)
+ .apply();
+
+ DisplayCaptureArgs captureArgs;
+ captureArgs.displayToken = mDisplay;
+
+ {
+ ScreenCapture::captureDisplay(&mCapture, captureArgs);
+ mCapture->expectColor(bounds, layerColor);
+ mCapture->expectBorder(bounds, {63, 63, 195, 255});
+ }
+
+ Transaction()
+ .setFlags(layer, layer_state_t::eLayerSkipScreenshot,
+ layer_state_t::eLayerSkipScreenshot)
+ .apply();
+
+ {
+ // Can't screenshot test layer since it now has flag
+ // eLayerSkipScreenshot
+ ScreenCapture::captureDisplay(&mCapture, captureArgs);
+ mCapture->expectColor(bounds, {63, 63, 195, 255});
+ mCapture->expectBorder(bounds, {63, 63, 195, 255});
+ }
+}
+
+TEST_F(ScreenCaptureTest, CaptureDisplayChildPrimaryDisplayOnly) {
+ sp<SurfaceControl> layer;
+ sp<SurfaceControl> childLayer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test layer", 0, 0, ISurfaceComposerClient::eFXSurfaceEffect));
+ ASSERT_NO_FATAL_FAILURE(childLayer = createLayer("test layer", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceEffect,
+ layer.get()));
+
+ const Color layerColor = Color::RED;
+ const Color childColor = Color::BLUE;
+ const Rect bounds = Rect(10, 10, 40, 40);
+ const Rect childBounds = Rect(20, 20, 30, 30);
+
+ Transaction()
+ .show(layer)
+ .show(childLayer)
+ .hide(mFGSurfaceControl)
+ .setLayerStack(layer, 0)
+ .setLayer(layer, INT32_MAX)
+ .setColor(layer, {layerColor.r / 255, layerColor.g / 255, layerColor.b / 255})
+ .setColor(childLayer, {childColor.r / 255, childColor.g / 255, childColor.b / 255})
+ .setCrop_legacy(layer, bounds)
+ .setCrop_legacy(childLayer, childBounds)
+ .apply();
+
+ DisplayCaptureArgs captureArgs;
+ captureArgs.displayToken = mDisplay;
+
+ {
+ ScreenCapture::captureDisplay(&mCapture, captureArgs);
+ mCapture->expectColor(childBounds, childColor);
+ mCapture->expectBorder(childBounds, layerColor);
+ mCapture->expectBorder(bounds, {63, 63, 195, 255});
+ }
+
+ Transaction()
+ .setFlags(layer, layer_state_t::eLayerSkipScreenshot,
+ layer_state_t::eLayerSkipScreenshot)
+ .apply();
+
+ {
+ // Can't screenshot child layer since the parent has the flag
+ // eLayerSkipScreenshot
+ ScreenCapture::captureDisplay(&mCapture, captureArgs);
+ mCapture->expectColor(childBounds, {63, 63, 195, 255});
+ mCapture->expectBorder(childBounds, {63, 63, 195, 255});
+ mCapture->expectBorder(bounds, {63, 63, 195, 255});
+ }
+}
+
TEST_F(ScreenCaptureTest, CaptureLayerWithUid) {
uid_t fakeUid = 12345;
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 8d97f27..8570032 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -422,7 +422,7 @@
}
void SurfaceInterceptorTest::displayCreation(Transaction&) {
- sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
+ sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
SurfaceComposerClient::destroyDisplay(testDisplay);
}
@@ -819,7 +819,7 @@
bool SurfaceInterceptorTest::displayCreationFound(const Increment& increment, bool foundDisplay) {
bool isMatch(increment.display_creation().name() == DISPLAY_NAME.string() &&
- increment.display_creation().is_secure());
+ !increment.display_creation().is_secure());
if (isMatch && !foundDisplay) {
foundDisplay = true;
} else if (isMatch && foundDisplay) {
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 159a215..8a0b551 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -339,8 +339,6 @@
EXPECT_CALL(*test->mComposer, presentDisplay(HWC_DISPLAY, _)).Times(1);
EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
-
EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1);
@@ -449,8 +447,6 @@
template <typename Case>
static void setupCommonCompositionCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
-
// TODO: This seems like an unnecessary call if display is powered off.
EXPECT_CALL(*test->mComposer,
setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
@@ -465,8 +461,6 @@
static void setupHwcForcedClientCompositionCallExpectations(CompositionTest*) {}
static void setupRECompositionCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
-
// TODO: This seems like an unnecessary call if display is powered off.
EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
.WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
@@ -549,7 +543,6 @@
enqueueBuffer(test, layer);
Mock::VerifyAndClearExpectations(test->mMessageQueue);
- EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
bool ignoredRecomputeVisibleRegions;
layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, 0);
Mock::VerifyAndClear(test->mRenderEngine);
@@ -582,8 +575,6 @@
.Times(1);
// TODO: Coverage of other values
EXPECT_CALL(*test->mComposer, setLayerZOrder(HWC_DISPLAY, HWC_LAYER, 0u)).Times(1);
- // TODO: Coverage of other values
- EXPECT_CALL(*test->mComposer, setLayerInfo(HWC_DISPLAY, HWC_LAYER, 0u, 0u)).Times(1);
// These expectations retire on saturation as the code path these
// expectations are for appears to make an extra call to them.
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index b939b9a..b750d6b 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -24,6 +24,7 @@
#include <type_traits>
#include <android/hardware/power/Boost.h>
+#include <binder/IPCThreadState.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/impl/Display.h>
@@ -37,6 +38,7 @@
#include <gui/mock/GraphicBufferConsumer.h>
#include <gui/mock/GraphicBufferProducer.h>
#include <log/log.h>
+#include <private/android_filesystem_config.h>
#include <renderengine/mock/RenderEngine.h>
#include <ui/DebugUtils.h>
@@ -153,7 +155,7 @@
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
Hwc2::mock::Composer* mComposer = nullptr;
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
- mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
+ sp<mock::SurfaceInterceptor> mSurfaceInterceptor = new mock::SurfaceInterceptor;
mock::VsyncController* mVsyncController = new mock::VsyncController;
mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker;
@@ -192,7 +194,7 @@
injectMockScheduler();
mFlinger.mutableEventQueue().reset(mMessageQueue);
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
- mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
+ mFlinger.mutableInterceptor() = mSurfaceInterceptor;
injectMockComposer(0);
}
@@ -1230,8 +1232,12 @@
// --------------------------------------------------------------------
// Invocation
-
+ int64_t oldId = IPCThreadState::self()->clearCallingIdentity();
+ // Set the calling identity to graphics so captureDisplay with secure is allowed.
+ IPCThreadState::self()->restoreCallingIdentity(static_cast<int64_t>(AID_GRAPHICS) << 32 |
+ AID_GRAPHICS);
sp<IBinder> displayToken = mFlinger.createDisplay(name, true);
+ IPCThreadState::self()->restoreCallingIdentity(oldId);
// --------------------------------------------------------------------
// Postconditions
@@ -1304,53 +1310,6 @@
}
/* ------------------------------------------------------------------------
- * SurfaceFlinger::resetDisplayState
- */
-
-TEST_F(DisplayTransactionTest, resetDisplayStateClearsState) {
- using Case = NonHwcVirtualDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // vsync is enabled and available
- mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = true;
- mFlinger.scheduler()->mutableHWVsyncAvailable() = true;
-
- // A display exists
- auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
- existing.inject();
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- // The call disable vsyncs
- EXPECT_CALL(mSchedulerCallback, setVsyncEnabled(false)).Times(1);
-
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.resetDisplayState();
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // vsyncs should be off and not available.
- EXPECT_FALSE(mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled());
- EXPECT_FALSE(mFlinger.scheduler()->mutableHWVsyncAvailable());
-
- // The display should have been removed from the display map.
- EXPECT_FALSE(hasDisplayDevice(existing.token()));
-
- // The display should still exist in the current state
- EXPECT_TRUE(hasCurrentDisplayState(existing.token()));
-
- // The display should have been removed from the drawing state
- EXPECT_FALSE(hasDrawingDisplayState(existing.token()));
-}
-
-/* ------------------------------------------------------------------------
* SurfaceFlinger::notifyPowerBoost
*/
@@ -1522,7 +1481,7 @@
EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_0, mHardwareDisplaySize.width,
mHardwareDisplaySize.height),
compositionState.transform);
- EXPECT_EQ(TRANSFORM_FLAGS_ROT_0, compositionState.orientation);
+ EXPECT_EQ(ui::ROTATION_0, compositionState.displaySpace.orientation);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
@@ -1534,7 +1493,7 @@
EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_90, mHardwareDisplaySize.width,
mHardwareDisplaySize.height),
compositionState.transform);
- EXPECT_EQ(TRANSFORM_FLAGS_ROT_90, compositionState.orientation);
+ EXPECT_EQ(ui::ROTATION_90, compositionState.displaySpace.orientation);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
// For 90, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
// size width and height swapped
@@ -1549,7 +1508,7 @@
EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_180, mHardwareDisplaySize.width,
mHardwareDisplaySize.height),
compositionState.transform);
- EXPECT_EQ(TRANSFORM_FLAGS_ROT_180, compositionState.orientation);
+ EXPECT_EQ(ui::ROTATION_180, compositionState.displaySpace.orientation);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
EXPECT_EQ(false, compositionState.needsFiltering);
@@ -1560,7 +1519,7 @@
EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_270, mHardwareDisplaySize.width,
mHardwareDisplaySize.height),
compositionState.transform);
- EXPECT_EQ(TRANSFORM_FLAGS_ROT_270, compositionState.orientation);
+ EXPECT_EQ(ui::ROTATION_270, compositionState.displaySpace.orientation);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
// For 270, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
// size width and height swapped
@@ -2050,8 +2009,6 @@
// --------------------------------------------------------------------
// Call Expectations
- EXPECT_CALL(*mComposer, isUsingVrComposer()).WillOnce(Return(false));
-
setupCommonCallExpectationsForConnectProcessing<Case>();
// --------------------------------------------------------------------
@@ -2113,7 +2070,6 @@
// --------------------------------------------------------------------
// Call Expectations
- EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
EXPECT_CALL(*mComposer, getDisplayIdentificationData(Case::Display::HWC_DISPLAY_ID, _, _))
.Times(0);
@@ -2170,20 +2126,9 @@
SetArgPointee<2>(TertiaryDisplay::GET_IDENTIFICATION_DATA()),
Return(Error::NONE)));
- EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
-
ignoresHotplugConnectCommon<SimpleTertiaryDisplayCase>();
}
-TEST_F(HandleTransactionLockedTest, ignoresHotplugConnectIfExternalForVrComposer) {
- // Inject a primary display.
- PrimaryDisplayVariant::injectHwcDisplay(this);
-
- EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(true));
-
- ignoresHotplugConnectCommon<SimpleExternalDisplayCase>();
-}
-
TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectPrimaryDisplay) {
processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>();
}
@@ -2208,8 +2153,6 @@
// --------------------------------------------------------------------
// Call Expectations
- EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
-
setupCommonCallExpectationsForConnectProcessing<Case>();
setupCommonCallExpectationsForDisconnectProcessing<Case>();
@@ -2256,8 +2199,6 @@
// --------------------------------------------------------------------
// Call Expectations
- EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
-
setupCommonCallExpectationsForConnectProcessing<Case>();
setupCommonCallExpectationsForDisconnectProcessing<Case>();
@@ -2416,11 +2357,6 @@
mFlinger.mutableCurrentState().displays.removeItem(existing.token());
// --------------------------------------------------------------------
- // Call Expectations
-
- EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
-
- // --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index ae94f16..f680bdb 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -141,6 +141,7 @@
void EventThreadTest::createThread(std::unique_ptr<VSyncSource> source) {
mThread = std::make_unique<impl::EventThread>(std::move(source),
+ /*tokenManager=*/nullptr,
mInterceptVSyncCallRecorder.getInvocable());
// EventThread should register itself as VSyncSource callback.
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index b024568..98b20e8 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -83,8 +83,8 @@
return nullptr;
}
- std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger* flinger) override {
- return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
+ sp<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger* flinger) override {
+ return new android::impl::SurfaceInterceptor(flinger);
}
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
@@ -285,8 +285,6 @@
return mFlinger->destroyDisplay(displayToken);
}
- auto resetDisplayState() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->resetDisplayState(); }
-
auto setupNewDisplayDeviceInternal(
const wp<IBinder>& displayToken,
std::shared_ptr<compositionengine::Display> compositionDisplay,
@@ -325,7 +323,9 @@
return mFlinger->setPowerModeInternal(display, mode);
}
- auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what, systemTime()); }
+ auto onMessageReceived(int32_t what) {
+ return mFlinger->onMessageReceived(what, /*vsyncId=*/0, systemTime());
+ }
auto renderScreenImplLocked(const RenderArea& renderArea,
SurfaceFlinger::TraverseLayersFunction traverseLayers,
@@ -362,6 +362,10 @@
auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); };
+ auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+ return mFlinger->onTransact(code, data, reply, flags);
+ }
+
/* ------------------------------------------------------------------------
* Read-only access to private data to assert post-conditions.
*/
@@ -420,7 +424,7 @@
mutableCurrentState().displays.clear();
mutableDrawingState().displays.clear();
mutableEventQueue().reset();
- mutableInterceptor().reset();
+ mutableInterceptor().clear();
mFlinger->mScheduler.reset();
mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
mFlinger->mCompositionEngine->setRenderEngine(
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index c2c5072..cd9b87a 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -52,11 +52,9 @@
MOCK_METHOD0(getCapabilities, std::vector<IComposer::Capability>());
MOCK_METHOD0(dumpDebugInfo, std::string());
MOCK_METHOD1(registerCallback, void(const sp<IComposerCallback>&));
- MOCK_METHOD0(isRemote, bool());
MOCK_METHOD0(resetCommands, void());
MOCK_METHOD0(executeCommands, Error());
MOCK_METHOD0(getMaxVirtualDisplayCount, uint32_t());
- MOCK_CONST_METHOD0(isUsingVrComposer, bool());
MOCK_METHOD4(createVirtualDisplay, Error(uint32_t, uint32_t, PixelFormat*, Display*));
MOCK_METHOD1(destroyVirtualDisplay, Error(Display));
MOCK_METHOD1(acceptDisplayChanges, Error(Display));
@@ -110,7 +108,6 @@
MOCK_METHOD3(setLayerVisibleRegion,
Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
MOCK_METHOD3(setLayerZOrder, Error(Display, Layer, uint32_t));
- MOCK_METHOD4(setLayerInfo, Error(Display, Layer, uint32_t, uint32_t));
MOCK_METHOD3(getRenderIntents, Error(Display, ColorMode, std::vector<RenderIntent>*));
MOCK_METHOD3(setLayerColorTransform, Error(Display, Layer, const float*));
MOCK_METHOD4(getDisplayedContentSamplingAttributes,
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
index ccb7bb9..e2c8a65 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
@@ -33,6 +33,8 @@
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&));
MOCK_METHOD0(disable, void());
MOCK_METHOD0(isEnabled, bool());
+ MOCK_METHOD1(addTransactionTraceListener, void(const sp<gui::ITransactionTraceListener>&));
+ MOCK_METHOD1(binderDied, void(const wp<IBinder>&));
MOCK_METHOD6(saveTransaction,
void(const Vector<ComposerState>&,
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&,
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index 1d94f21..ca3551e 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -15,32 +15,16 @@
*/
#pragma once
+#include <gui/SyncScreenCaptureListener.h>
#include <ui/Rect.h>
#include <utils/String8.h>
#include <functional>
-#include <future>
#include "TransactionUtils.h"
namespace android {
namespace {
-class SyncScreenCaptureListener : public BnScreenCaptureListener {
-public:
- status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override {
- resultsPromise.set_value(captureResults);
- return NO_ERROR;
- }
-
- ScreenCaptureResults waitForResults() {
- std::future<ScreenCaptureResults> resultsFuture = resultsPromise.get_future();
- return resultsFuture.get();
- }
-
-private:
- std::promise<ScreenCaptureResults> resultsPromise;
-};
-
// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
// individual pixel values for testing purposes.
class ScreenCapture : public RefBase {
diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp
index c45a1a1..fa742c5 100644
--- a/services/vibratorservice/Android.bp
+++ b/services/vibratorservice/Android.bp
@@ -19,6 +19,7 @@
"VibratorCallbackScheduler.cpp",
"VibratorHalController.cpp",
"VibratorHalWrapper.cpp",
+ "VibratorManagerHalWrapper.cpp",
],
aidl: {
diff --git a/services/vibratorservice/VibratorHalController.cpp b/services/vibratorservice/VibratorHalController.cpp
index 46175ad..e8606ca 100644
--- a/services/vibratorservice/VibratorHalController.cpp
+++ b/services/vibratorservice/VibratorHalController.cpp
@@ -46,8 +46,6 @@
// -------------------------------------------------------------------------------------------------
-static constexpr int MAX_RETRIES = 1;
-
std::shared_ptr<HalWrapper> HalConnector::connect(std::shared_ptr<CallbackScheduler> scheduler) {
static bool gHalExists = true;
if (!gHalExists) {
@@ -89,6 +87,8 @@
// -------------------------------------------------------------------------------------------------
+static constexpr int MAX_RETRIES = 1;
+
template <typename T>
HalResult<T> HalController::processHalResult(HalResult<T> result, const char* functionName) {
if (result.isFailed()) {
@@ -126,11 +126,12 @@
// -------------------------------------------------------------------------------------------------
-void HalController::init() {
+bool HalController::init() {
std::lock_guard<std::mutex> lock(mConnectedHalMutex);
if (mConnectedHal == nullptr) {
mConnectedHal = mHalConnector->connect(mCallbackScheduler);
}
+ return mConnectedHal != nullptr;
}
HalResult<void> HalController::ping() {
diff --git a/services/vibratorservice/VibratorManagerHalWrapper.cpp b/services/vibratorservice/VibratorManagerHalWrapper.cpp
new file mode 100644
index 0000000..71955af
--- /dev/null
+++ b/services/vibratorservice/VibratorManagerHalWrapper.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VibratorManagerHalWrapper"
+
+#include <utils/Log.h>
+
+#include <vibratorservice/VibratorManagerHalWrapper.h>
+
+namespace android {
+
+namespace vibrator {
+
+constexpr int32_t SINGLE_VIBRATOR_ID = 0;
+
+HalResult<void> LegacyManagerHalWrapper::ping() {
+ return mController->ping();
+}
+
+void LegacyManagerHalWrapper::tryReconnect() {
+ mController->tryReconnect();
+}
+
+HalResult<std::vector<int32_t>> LegacyManagerHalWrapper::getVibratorIds() {
+ if (mController->init()) {
+ return HalResult<std::vector<int32_t>>::ok(std::vector<int32_t>(1, SINGLE_VIBRATOR_ID));
+ }
+ // Controller.init did not connect to any vibrator HAL service, so the device has no vibrator.
+ return HalResult<std::vector<int32_t>>::ok(std::vector<int32_t>());
+}
+
+HalResult<std::shared_ptr<HalController>> LegacyManagerHalWrapper::getVibrator(int32_t id) {
+ if (id == SINGLE_VIBRATOR_ID && mController->init()) {
+ return HalResult<std::shared_ptr<HalController>>::ok(mController);
+ }
+ // Controller.init did not connect to any vibrator HAL service, so the device has no vibrator.
+ return HalResult<std::shared_ptr<HalController>>::failed("No vibrator with id = " +
+ std::to_string(id));
+}
+
+HalResult<void> LegacyManagerHalWrapper::prepareSynced(const std::vector<int32_t>&) {
+ return HalResult<void>::unsupported();
+}
+
+HalResult<void> LegacyManagerHalWrapper::triggerSynced(const std::function<void()>&) {
+ return HalResult<void>::unsupported();
+}
+
+HalResult<void> LegacyManagerHalWrapper::cancelSynced() {
+ return HalResult<void>::unsupported();
+}
+
+}; // namespace vibrator
+
+}; // namespace android
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
index 3b61f42..d1028a4 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
@@ -51,11 +51,19 @@
mConnectedHal(nullptr) {}
virtual ~HalController() = default;
- void init();
+ /* Connects to the newest HAL version available, possibly waiting for the registered service to
+ * become available. This will automatically be called at the first API usage if it was not
+ * manually called beforehand. Calling this manually during the setup phase can avoid slowing
+ * the first API call later on. Returns true if any HAL version is available, false otherwise.
+ */
+ virtual bool init();
- HalResult<void> ping() final override;
- void tryReconnect() final override;
+ /* reloads HAL service instance without waiting. This relies on the HAL version found by init()
+ * to rapidly reconnect to the specific HAL service, or defers to init() if it was never called.
+ */
+ virtual void tryReconnect() override;
+ virtual HalResult<void> ping() override;
HalResult<void> on(std::chrono::milliseconds timeout,
const std::function<void()>& completionCallback) final override;
HalResult<void> off() final override;
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 7b99bbb..bcb735d 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -140,9 +140,12 @@
: mCallbackScheduler(std::move(scheduler)) {}
virtual ~HalWrapper() = default;
- virtual HalResult<void> ping() = 0;
+ /* reloads wrapped HAL service instance without waiting. This can be used to reconnect when the
+ * service restarts, to rapidly retry after a failure.
+ */
virtual void tryReconnect() = 0;
+ virtual HalResult<void> ping() = 0;
virtual HalResult<void> on(std::chrono::milliseconds timeout,
const std::function<void()>& completionCallback) = 0;
virtual HalResult<void> off() = 0;
diff --git a/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h
new file mode 100644
index 0000000..99947a5
--- /dev/null
+++ b/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_OS_VIBRATOR_MANAGER_HAL_WRAPPER_H
+#define ANDROID_OS_VIBRATOR_MANAGER_HAL_WRAPPER_H
+
+#include <vibratorservice/VibratorHalController.h>
+
+namespace android {
+
+namespace vibrator {
+
+// Wrapper for VibratorManager HAL handlers.
+class ManagerHalWrapper {
+public:
+ ManagerHalWrapper() = default;
+ virtual ~ManagerHalWrapper() = default;
+
+ virtual HalResult<void> ping() = 0;
+
+ /* reloads wrapped HAL service instance without waiting. This can be used to reconnect when the
+ * service restarts, to rapidly retry after a failure.
+ */
+ virtual void tryReconnect() = 0;
+
+ virtual HalResult<std::vector<int32_t>> getVibratorIds() = 0;
+ virtual HalResult<std::shared_ptr<HalController>> getVibrator(int32_t id) = 0;
+
+ virtual HalResult<void> prepareSynced(const std::vector<int32_t>& ids) = 0;
+ virtual HalResult<void> triggerSynced(const std::function<void()>& completionCallback) = 0;
+ virtual HalResult<void> cancelSynced() = 0;
+};
+
+// Wrapper for the VibratorManager over single Vibrator HAL.
+class LegacyManagerHalWrapper : public ManagerHalWrapper {
+public:
+ LegacyManagerHalWrapper() : LegacyManagerHalWrapper(std::make_shared<HalController>()) {}
+ explicit LegacyManagerHalWrapper(std::shared_ptr<HalController> controller)
+ : mController(std::move(controller)) {}
+ virtual ~LegacyManagerHalWrapper() = default;
+
+ HalResult<void> ping() override final;
+ void tryReconnect() override final;
+
+ HalResult<std::vector<int32_t>> getVibratorIds() override final;
+ HalResult<std::shared_ptr<HalController>> getVibrator(int32_t id) override final;
+
+ HalResult<void> prepareSynced(const std::vector<int32_t>& ids) override final;
+ HalResult<void> triggerSynced(const std::function<void()>& completionCallback) override final;
+ HalResult<void> cancelSynced() override final;
+
+private:
+ const std::shared_ptr<HalController> mController;
+};
+
+}; // namespace vibrator
+
+}; // namespace android
+
+#endif // ANDROID_OS_VIBRATOR_MANAGER_HAL_WRAPPER_H
diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp
index 9033124..5fc6d45 100644
--- a/services/vibratorservice/test/Android.bp
+++ b/services/vibratorservice/test/Android.bp
@@ -23,6 +23,7 @@
"VibratorHalWrapperHidlV1_1Test.cpp",
"VibratorHalWrapperHidlV1_2Test.cpp",
"VibratorHalWrapperHidlV1_3Test.cpp",
+ "VibratorManagerHalWrapperLegacyTest.cpp",
],
cflags: [
"-Wall",
diff --git a/services/vibratorservice/test/VibratorHalControllerTest.cpp b/services/vibratorservice/test/VibratorHalControllerTest.cpp
index f04e016..cda5e9a 100644
--- a/services/vibratorservice/test/VibratorHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorHalControllerTest.cpp
@@ -184,11 +184,11 @@
// -------------------------------------------------------------------------------------------------
TEST_F(VibratorHalControllerTest, TestInit) {
- mController->init();
+ ASSERT_TRUE(mController->init());
ASSERT_EQ(1, mConnectCounter);
// Noop when wrapper was already initialized.
- mController->init();
+ ASSERT_TRUE(mController->init());
ASSERT_EQ(1, mConnectCounter);
}
@@ -339,6 +339,7 @@
std::make_unique<vibrator::HalController>(std::move(failingHalConnector), nullptr);
ASSERT_EQ(0, mConnectCounter);
+ ASSERT_FALSE(mController->init());
ASSERT_TRUE(mController->ping().isUnsupported());
ASSERT_TRUE(mController->on(10ms, []() {}).isUnsupported());
ASSERT_TRUE(mController->off().isUnsupported());
@@ -356,7 +357,7 @@
.isUnsupported());
// One connection attempt per api call.
- ASSERT_EQ(12, mConnectCounter);
+ ASSERT_EQ(13, mConnectCounter);
}
TEST_F(VibratorHalControllerTest, TestScheduledCallbackSurvivesReconnection) {
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp
new file mode 100644
index 0000000..d5520a1
--- /dev/null
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VibratorManagerHalWrapperLegacyTest"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+
+#include <vibratorservice/VibratorManagerHalWrapper.h>
+
+using android::hardware::vibrator::CompositeEffect;
+using android::hardware::vibrator::CompositePrimitive;
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+
+using std::chrono::milliseconds;
+
+using namespace android;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockHalController : public vibrator::HalController {
+public:
+ MockHalController() = default;
+ virtual ~MockHalController() = default;
+
+ MOCK_METHOD(bool, init, (), (override));
+ MOCK_METHOD(vibrator::HalResult<void>, ping, (), (override));
+ MOCK_METHOD(void, tryReconnect, (), (override));
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class VibratorManagerHalWrapperLegacyTest : public Test {
+public:
+ void SetUp() override {
+ mMockController = std::make_shared<StrictMock<MockHalController>>();
+ mWrapper = std::make_unique<vibrator::LegacyManagerHalWrapper>(mMockController);
+ ASSERT_NE(mWrapper, nullptr);
+ }
+
+protected:
+ std::shared_ptr<StrictMock<MockHalController>> mMockController = nullptr;
+ std::unique_ptr<vibrator::ManagerHalWrapper> mWrapper = nullptr;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestPing) {
+ EXPECT_CALL(*mMockController.get(), ping())
+ .Times(Exactly(2))
+ .WillOnce(Return(vibrator::HalResult<void>::failed("message")))
+ .WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
+
+ ASSERT_TRUE(mWrapper->ping().isFailed());
+ ASSERT_TRUE(mWrapper->ping().isOk());
+}
+
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestTryReconnect) {
+ EXPECT_CALL(*mMockController.get(), tryReconnect()).Times(Exactly(1));
+
+ mWrapper->tryReconnect();
+}
+
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestGetVibratorIds) {
+ std::vector<int32_t> expectedIds;
+ expectedIds.push_back(0);
+
+ EXPECT_CALL(*mMockController.get(), init())
+ .Times(Exactly(2))
+ .WillOnce(Return(false))
+ .WillRepeatedly(Return(true));
+
+ auto result = mWrapper->getVibratorIds();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(std::vector<int32_t>(), result.value());
+
+ result = mWrapper->getVibratorIds();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(expectedIds, result.value());
+}
+
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestGetVibratorWithValidIdReturnsController) {
+ EXPECT_CALL(*mMockController.get(), init())
+ .Times(Exactly(2))
+ .WillOnce(Return(false))
+ .WillRepeatedly(Return(true));
+
+ ASSERT_TRUE(mWrapper->getVibrator(0).isFailed());
+
+ auto result = mWrapper->getVibrator(0);
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(mMockController.get(), result.value().get());
+}
+
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestGetVibratorWithInvalidIdFails) {
+ ASSERT_TRUE(mWrapper->getVibrator(-1).isFailed());
+}
+
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestSyncedOperationsUnsupported) {
+ std::vector<int32_t> vibratorIds;
+ vibratorIds.push_back(0);
+
+ ASSERT_TRUE(mWrapper->prepareSynced(vibratorIds).isUnsupported());
+ ASSERT_TRUE(mWrapper->triggerSynced([]() {}).isUnsupported());
+ ASSERT_TRUE(mWrapper->cancelSynced().isUnsupported());
+}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 0f791c9..48090af 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -258,7 +258,11 @@
bool shared;
struct Image {
- Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
+ Image()
+ : image(VK_NULL_HANDLE),
+ dequeue_fence(-1),
+ release_fence(-1),
+ dequeued(false) {}
VkImage image;
android::sp<ANativeWindowBuffer> buffer;
// The fence is only valid when the buffer is dequeued, and should be
@@ -266,6 +270,10 @@
// closed: either by closing it explicitly when queueing the buffer,
// or by passing ownership e.g. to ANativeWindow::cancelBuffer().
int dequeue_fence;
+ // This fence is a dup of the sync fd returned from the driver via
+ // vkQueueSignalReleaseImageANDROID upon vkQueuePresentKHR. We must
+ // ensure it is closed upon re-presenting or releasing the image.
+ int release_fence;
bool dequeued;
} images[android::BufferQueueDefs::NUM_BUFFER_SLOTS];
@@ -280,10 +288,19 @@
return reinterpret_cast<Swapchain*>(handle);
}
+static bool IsFencePending(int fd) {
+ if (fd < 0)
+ return false;
+
+ errno = 0;
+ return sync_wait(fd, 0 /* timeout */) == -1 && errno == ETIME;
+}
+
void ReleaseSwapchainImage(VkDevice device,
ANativeWindow* window,
int release_fence,
- Swapchain::Image& image) {
+ Swapchain::Image& image,
+ bool defer_if_pending) {
ATRACE_CALL();
ALOG_ASSERT(release_fence == -1 || image.dequeued,
@@ -319,10 +336,18 @@
close(release_fence);
}
}
-
+ release_fence = -1;
image.dequeued = false;
}
+ if (defer_if_pending && IsFencePending(image.release_fence))
+ return;
+
+ if (image.release_fence >= 0) {
+ close(image.release_fence);
+ image.release_fence = -1;
+ }
+
if (image.image) {
ATRACE_BEGIN("DestroyImage");
GetData(device).driver.DestroyImage(device, image.image, nullptr);
@@ -338,7 +363,8 @@
return;
for (uint32_t i = 0; i < swapchain->num_images; i++) {
if (!swapchain->images[i].dequeued)
- ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i]);
+ ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i],
+ true);
}
swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
swapchain->timing.clear();
@@ -996,7 +1022,7 @@
}
for (uint32_t i = 0; i < swapchain->num_images; i++) {
- ReleaseSwapchainImage(device, window, -1, swapchain->images[i]);
+ ReleaseSwapchainImage(device, window, -1, swapchain->images[i], false);
}
if (active) {
@@ -1628,6 +1654,9 @@
ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
swapchain_result = result;
}
+ if (img.release_fence >= 0)
+ close(img.release_fence);
+ img.release_fence = fence < 0 ? -1 : dup(fence);
if (swapchain.surface.swapchain_handle ==
present_info->pSwapchains[sc]) {
@@ -1761,7 +1790,7 @@
WorstPresentResult(swapchain_result, VK_SUBOPTIMAL_KHR);
}
} else {
- ReleaseSwapchainImage(device, nullptr, fence, img);
+ ReleaseSwapchainImage(device, nullptr, fence, img, true);
swapchain_result = VK_ERROR_OUT_OF_DATE_KHR;
}