Merge changes Iea02806d,I45af7b49,Id50e0d23
* changes:
Revert "Bind to FBO when using GPU composition"
Revert "Remove gl surfaces from DisplayDevice."
Revert "Delete renderengine::Surface"
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 50a2412..aad9939 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -701,12 +701,13 @@
unique_fd&& reference_profile_fd,
unique_fd&& apk_fd,
const std::string& dex_location) {
- std::vector<unique_fd> profiles_fd;
- profiles_fd.push_back(std::move(profile_fd));
- std::vector<unique_fd> apk_fds;
- profiles_fd.push_back(std::move(apk_fd));
+ // The fds need to stay open longer than the scope of the function, so put them into a local
+ // variable vector.
+ profiles_fd_.push_back(std::move(profile_fd));
+ apk_fds_.push_back(std::move(apk_fd));
+ reference_profile_fd_ = std::move(reference_profile_fd);
std::vector<std::string> dex_locations = {dex_location};
- SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
+ SetupArgs(profiles_fd_, reference_profile_fd_, apk_fds_, dex_locations,
/*copy_and_update=*/true);
}
@@ -724,6 +725,11 @@
void Exec() {
ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
}
+
+ private:
+ unique_fd reference_profile_fd_;
+ std::vector<unique_fd> profiles_fd_;
+ std::vector<unique_fd> apk_fds_;
};
diff --git a/headers/media_plugin/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h
index c44a1f6..aa8bd3d 100644
--- a/headers/media_plugin/media/drm/DrmAPI.h
+++ b/headers/media_plugin/media/drm/DrmAPI.h
@@ -167,6 +167,25 @@
kSecurityLevelHwSecureAll
};
+ // An offline license may be usable or inactive. The keys in a
+ // usable offline license are available for decryption. When
+ // the offline license state is inactive, the keys have been
+ // marked for release using getKeyRequest with
+ // kKeyType_Release but the key response has not been
+ // received. The keys in an inactive offline license are not
+ // usable for decryption.
+
+ enum OfflineLicenseState {
+ // The offline license state is unknown due to an error
+ kOfflineLicenseStateUnknown,
+ // Offline license state is usable, the keys may be used for decryption.
+ kOfflineLicenseStateUsable,
+ // Offline license state is inactive, the keys have been marked for
+ // release using getKeyRequest() with kKeyType_Release but the
+ // key response has not been received.
+ kOfflineLicenseStateInactive
+ };
+
DrmPlugin() {}
virtual ~DrmPlugin() {}
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 7c284dd..918b9e1 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -168,17 +168,17 @@
const sp<InputApplicationHandle> inputApplicationHandle;
inline const InputWindowInfo* getInfo() const {
- return mInfo;
+ return &mInfo;
}
sp<InputChannel> getInputChannel() const;
inline std::string getName() const {
- return mInfo ? mInfo->name : "<invalid>";
+ return mInfo.inputChannel ? mInfo.name : "<invalid>";
}
inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
- return mInfo ? mInfo->dispatchingTimeout : defaultValue;
+ return mInfo.inputChannel? mInfo.dispatchingTimeout : defaultValue;
}
/**
@@ -193,16 +193,16 @@
virtual bool updateInfo() = 0;
/**
- * Releases the storage used by the associated information when it is
+ * Releases the channel used by the associated information when it is
* no longer needed.
*/
- void releaseInfo();
+ void releaseChannel();
protected:
explicit InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
virtual ~InputWindowHandle();
- InputWindowInfo* mInfo;
+ InputWindowInfo mInfo;
};
} // namespace android
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 14edcbe..1674516 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -47,7 +47,7 @@
* (method calls, property get and set) is down through a low-level
* protocol implemented on top of the transact() API.
*/
-class IBinder : public virtual RefBase
+class [[clang::lto_visibility_public]] IBinder : public virtual RefBase
{
public:
enum {
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index a5842f7..4ee1b67 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -109,11 +109,11 @@
*
* \param arrayData some external representation of an array.
* \param index the index at which a string should be allocated.
- * \param outLength an out parameter for the length of the string (not including the
- * null-terminator)
+ * \param outLength an out parameter for the length of the string at the specified index. This
+ * should not include the length for a null-terminator if there is one.
*
- * \param a null-terminated buffer of size 'outLength + 1' representing the string at the provided
- * index including the null-terminator.
+ * \param a buffer of size outLength or more representing the string at the provided index. This is
+ * not required to be null-terminated.
*/
typedef const char* (*AParcel_stringArrayElementGetter)(const void* arrayData, size_t index,
size_t* outLength);
@@ -382,8 +382,7 @@
* Writes utf-8 string value to the next location in a non-null parcel.
*
* \param parcel the parcel to write to.
- * \param string the null-terminated string to write to the parcel. The buffer including the null
- * terminator should be of size 'length' + 1.
+ * \param string the null-terminated string to write to the parcel, at least of size 'length'.
* \param length the length of the string to be written.
*
* \return STATUS_OK on successful write.
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 98264ac..7677c3a 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -107,6 +107,7 @@
"IProducerListener.cpp",
"ISurfaceComposer.cpp",
"ISurfaceComposerClient.cpp",
+ "ITransactionCompletedListener.cpp",
"LayerDebugInfo.cpp",
"LayerState.cpp",
"OccupancyTracker.cpp",
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index accf72c..69e5379 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -634,10 +634,10 @@
if (count > data.dataSize()) {
return BAD_VALUE;
}
- ComposerState s;
Vector<ComposerState> state;
state.setCapacity(count);
for (size_t i = 0; i < count; i++) {
+ ComposerState s;
if (s.read(data) == BAD_VALUE) {
return BAD_VALUE;
}
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
new file mode 100644
index 0000000..95b1038
--- /dev/null
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ITransactionCompletedListener"
+//#define LOG_NDEBUG 0
+
+#include <gui/ITransactionCompletedListener.h>
+
+namespace android {
+
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+ ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION,
+ LAST = ON_TRANSACTION_COMPLETED,
+};
+
+} // Anonymous namespace
+
+status_t SurfaceStats::writeToParcel(Parcel* output) const {
+ status_t err = output->writeStrongBinder(surfaceControl);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->writeInt64(acquireTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return output->writeBool(releasePreviousBuffer);
+}
+
+status_t SurfaceStats::readFromParcel(const Parcel* input) {
+ status_t err = input->readStrongBinder(&surfaceControl);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = input->readInt64(&acquireTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return input->readBool(&releasePreviousBuffer);
+}
+
+status_t TransactionStats::writeToParcel(Parcel* output) const {
+ status_t err = output->writeInt64(latchTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->writeInt64(presentTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return output->writeParcelableVector(surfaceStats);
+}
+
+status_t TransactionStats::readFromParcel(const Parcel* input) {
+ status_t err = input->readInt64(&latchTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = input->readInt64(&presentTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return input->readParcelableVector(&surfaceStats);
+}
+
+status_t ListenerStats::writeToParcel(Parcel* output) const {
+ status_t err = output->writeInt32(static_cast<int32_t>(transactionStats.size()));
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ for (const auto& [callbackIds, stats] : transactionStats) {
+ err = output->writeParcelable(stats);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->writeInt64Vector(callbackIds);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t ListenerStats::readFromParcel(const Parcel* input) {
+ int32_t transactionStats_size = input->readInt32();
+
+ for (int i = 0; i < transactionStats_size; i++) {
+ TransactionStats stats;
+ std::vector<CallbackId> callbackIds;
+
+ status_t err = input->readParcelable(&stats);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = input->readInt64Vector(&callbackIds);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ transactionStats.emplace(callbackIds, stats);
+ }
+ return NO_ERROR;
+}
+
+ListenerStats ListenerStats::createEmpty(const sp<ITransactionCompletedListener>& listener,
+ const std::unordered_set<CallbackId>& callbackIds) {
+ ListenerStats listenerStats;
+ listenerStats.listener = listener;
+ TransactionStats transactionStats;
+ listenerStats.transactionStats.emplace(std::piecewise_construct,
+ std::forward_as_tuple(callbackIds.begin(),
+ callbackIds.end()),
+ std::forward_as_tuple(transactionStats));
+ return listenerStats;
+}
+
+class BpTransactionCompletedListener : public SafeBpInterface<ITransactionCompletedListener> {
+public:
+ explicit BpTransactionCompletedListener(const sp<IBinder>& impl)
+ : SafeBpInterface<ITransactionCompletedListener>(impl, "BpTransactionCompletedListener") {
+ }
+
+ ~BpTransactionCompletedListener() override;
+
+ void onTransactionCompleted(ListenerStats stats) override {
+ callRemoteAsync<decltype(&ITransactionCompletedListener::
+ onTransactionCompleted)>(Tag::ON_TRANSACTION_COMPLETED,
+ stats);
+ }
+};
+
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpTransactionCompletedListener::~BpTransactionCompletedListener() = default;
+
+IMPLEMENT_META_INTERFACE(TransactionCompletedListener, "android.gui.ITransactionComposerListener");
+
+status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags) {
+ if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ auto tag = static_cast<Tag>(code);
+ switch (tag) {
+ case Tag::ON_TRANSACTION_COMPLETED:
+ return callLocalAsync(data, reply,
+ &ITransactionCompletedListener::onTransactionCompleted);
+ }
+}
+
+}; // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 2b0a461..7b71b39 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -80,6 +80,13 @@
memcpy(output.writeInplace(16 * sizeof(float)),
colorTransform.asArray(), 16 * sizeof(float));
+ if (output.writeVectorSize(listenerCallbacks) == NO_ERROR) {
+ for (const auto& [listener, callbackIds] : listenerCallbacks) {
+ output.writeStrongBinder(IInterface::asBinder(listener));
+ output.writeInt64Vector(callbackIds);
+ }
+ }
+
return NO_ERROR;
}
@@ -135,6 +142,14 @@
colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
+ int32_t listenersSize = input.readInt32();
+ for (int32_t i = 0; i < listenersSize; i++) {
+ auto listener = interface_cast<ITransactionCompletedListener>(input.readStrongBinder());
+ std::vector<CallbackId> callbackIds;
+ input.readInt64Vector(&callbackIds);
+ listenerCallbacks.emplace_back(listener, callbackIds);
+ }
+
return NO_ERROR;
}
@@ -323,6 +338,10 @@
what |= eColorTransformChanged;
colorTransform = other.colorTransform;
}
+ if (other.what & eListenerCallbacksChanged) {
+ what |= eListenerCallbacksChanged;
+ listenerCallbacks = other.listenerCallbacks;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index e5a2454..e10bda4 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -25,7 +25,9 @@
#include <utils/String8.h>
#include <utils/threads.h>
+#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
#include <system/graphics.h>
@@ -98,6 +100,61 @@
// ---------------------------------------------------------------------------
+// TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs
+// to be able to return a sp<> to its instance to pass to SurfaceFlinger.
+// ANDROID_SINGLETON_STATIC_INSTANCE only allows a reference to an instance.
+
+// 0 is an invalid callback id
+TransactionCompletedListener::TransactionCompletedListener() : mCallbackIdCounter(1) {}
+
+CallbackId TransactionCompletedListener::getNextIdLocked() {
+ return mCallbackIdCounter++;
+}
+
+sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() {
+ static sp<TransactionCompletedListener> sInstance = new TransactionCompletedListener;
+ return sInstance;
+}
+
+sp<ITransactionCompletedListener> TransactionCompletedListener::getIInstance() {
+ return static_cast<sp<ITransactionCompletedListener>>(getInstance());
+}
+
+void TransactionCompletedListener::startListeningLocked() {
+ if (mListening) {
+ return;
+ }
+ ProcessState::self()->startThreadPool();
+ mListening = true;
+}
+
+CallbackId TransactionCompletedListener::addCallback(const TransactionCompletedCallback& callback) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ startListeningLocked();
+
+ CallbackId callbackId = getNextIdLocked();
+ mCallbacks.emplace(callbackId, callback);
+ return callbackId;
+}
+
+void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
+ std::lock_guard lock(mMutex);
+
+ for (const auto& [callbackIds, transactionStats] : listenerStats.transactionStats) {
+ for (auto callbackId : callbackIds) {
+ const auto& callback = mCallbacks[callbackId];
+ if (!callback) {
+ ALOGE("cannot call null callback function, skipping");
+ continue;
+ }
+ callback(transactionStats);
+ mCallbacks.erase(callbackId);
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
SurfaceComposerClient::Transaction::Transaction(const Transaction& other) :
mForceSynchronous(other.mForceSynchronous),
mTransactionNestCount(other.mTransactionNestCount),
@@ -127,6 +184,17 @@
}
other.mDisplayStates.clear();
+ for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) {
+ auto& [callbackIds, surfaceControls] = callbackInfo;
+ mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator(
+ callbackIds.begin()),
+ std::make_move_iterator(callbackIds.end()));
+ mListenerCallbacks[listener]
+ .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()),
+ std::make_move_iterator(surfaceControls.end()));
+ }
+ other.mListenerCallbacks.clear();
+
return *this;
}
@@ -137,6 +205,32 @@
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ // For every listener with registered callbacks
+ for (const auto& [listener, callbackInfo] : mListenerCallbacks) {
+ auto& [callbackIds, surfaceControls] = callbackInfo;
+ if (callbackIds.empty()) {
+ continue;
+ }
+
+ // If the listener does not have any SurfaceControls set on this Transaction, send the
+ // callback now
+ if (surfaceControls.empty()) {
+ listener->onTransactionCompleted(ListenerStats::createEmpty(listener, callbackIds));
+ }
+
+ // If the listener has any SurfaceControls set on this Transaction update the surface state
+ for (const auto& surfaceControl : surfaceControls) {
+ layer_state_t* s = getLayerState(surfaceControl);
+ if (!s) {
+ ALOGE("failed to get layer state");
+ continue;
+ }
+ s->what |= layer_state_t::eListenerCallbacksChanged;
+ s->listenerCallbacks.emplace_back(listener, std::move(callbackIds));
+ }
+ }
+ mListenerCallbacks.clear();
+
Vector<ComposerState> composerStates;
Vector<DisplayState> displayStates;
uint32_t flags = 0;
@@ -206,6 +300,11 @@
return &(mComposerStates[sc].state);
}
+void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback(
+ const sp<SurfaceControl>& sc) {
+ mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls.insert(sc);
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition(
const sp<SurfaceControl>& sc, float x, float y) {
layer_state_t* s = getLayerState(sc);
@@ -216,6 +315,8 @@
s->what |= layer_state_t::ePositionChanged;
s->x = x;
s->y = y;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -240,6 +341,7 @@
s->w = w;
s->h = h;
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -252,6 +354,8 @@
}
s->what |= layer_state_t::eLayerChanged;
s->z = z;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -264,6 +368,8 @@
s->what |= layer_state_t::eRelativeLayerChanged;
s->relativeLayerHandle = relativeTo;
s->z = z;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -283,6 +389,8 @@
s->flags &= ~mask;
s->flags |= (flags & mask);
s->mask |= mask;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -296,6 +404,8 @@
}
s->what |= layer_state_t::eTransparentRegionChanged;
s->transparentRegion = transparentRegion;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -308,6 +418,8 @@
}
s->what |= layer_state_t::eAlphaChanged;
s->alpha = alpha;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -320,6 +432,8 @@
}
s->what |= layer_state_t::eLayerStackChanged;
s->layerStack = layerStack;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -338,6 +452,8 @@
matrix.dsdy = dsdy;
matrix.dtdy = dtdy;
s->matrix = matrix;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -350,6 +466,8 @@
}
s->what |= layer_state_t::eCropChanged_legacy;
s->crop_legacy = crop;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -365,6 +483,8 @@
s->what |= layer_state_t::eDeferTransaction_legacy;
s->barrierHandle_legacy = handle;
s->frameNumber_legacy = frameNumber;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -380,6 +500,8 @@
s->what |= layer_state_t::eDeferTransaction_legacy;
s->barrierGbp_legacy = barrierSurface->getIGraphicBufferProducer();
s->frameNumber_legacy = frameNumber;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -393,6 +515,8 @@
}
s->what |= layer_state_t::eReparentChildren;
s->reparentHandle = newParentHandle;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -406,6 +530,8 @@
}
s->what |= layer_state_t::eReparent;
s->parentHandleForChild = newParentHandle;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -419,6 +545,8 @@
}
s->what |= layer_state_t::eColorChanged;
s->color = color;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -431,6 +559,8 @@
}
s->what |= layer_state_t::eTransformChanged;
s->transform = transform;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -444,6 +574,8 @@
}
s->what |= layer_state_t::eTransformToDisplayInverseChanged;
s->transformToDisplayInverse = transformToDisplayInverse;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -456,6 +588,8 @@
}
s->what |= layer_state_t::eCropChanged;
s->crop = crop;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -468,6 +602,8 @@
}
s->what |= layer_state_t::eBufferChanged;
s->buffer = buffer;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -480,6 +616,8 @@
}
s->what |= layer_state_t::eAcquireFenceChanged;
s->acquireFence = fence;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -492,6 +630,8 @@
}
s->what |= layer_state_t::eDataspaceChanged;
s->dataspace = dataspace;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -504,6 +644,8 @@
}
s->what |= layer_state_t::eHdrMetadataChanged;
s->hdrMetadata = hdrMetadata;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -516,6 +658,8 @@
}
s->what |= layer_state_t::eSurfaceDamageRegionChanged;
s->surfaceDamageRegion = surfaceDamageRegion;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -528,6 +672,8 @@
}
s->what |= layer_state_t::eApiChanged;
s->api = api;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -540,6 +686,22 @@
}
s->what |= layer_state_t::eSidebandStreamChanged;
s->sidebandStream = sidebandStream;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
+ TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
+ auto listener = TransactionCompletedListener::getInstance();
+
+ auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1);
+
+ CallbackId callbackId = listener->addCallback(callbackWithContext);
+
+ mListenerCallbacks[TransactionCompletedListener::getIInstance()].callbackIds.emplace(
+ callbackId);
return *this;
}
@@ -550,6 +712,8 @@
mStatus = BAD_INDEX;
}
s->what |= layer_state_t::eDetachChildren;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -577,6 +741,8 @@
s->what |= layer_state_t::eOverrideScalingModeChanged;
s->overrideScalingMode = overrideScalingMode;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -588,6 +754,8 @@
return *this;
}
s->what |= layer_state_t::eGeometryAppliesWithResize;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -611,6 +779,8 @@
}
s->what |= layer_state_t::eColorTransformChanged;
s->colorTransform = mat4(matrix, translation);
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
new file mode 100644
index 0000000..5c41c21
--- /dev/null
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/SafeInterface.h>
+
+#include <utils/Timers.h>
+
+#include <cstdint>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace android {
+
+class ITransactionCompletedListener;
+
+using CallbackId = int64_t;
+
+struct CallbackIdsHash {
+ // CallbackId vectors have several properties that let us get away with this simple hash.
+ // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is
+ // empty we can still hash 0.
+ // 2) CallbackId vectors for the same listener either are identical or contain none of the
+ // same members. It is sufficient to just check the first CallbackId in the vectors. If
+ // they match, they are the same. If they do not match, they are not the same.
+ std::size_t operator()(const std::vector<CallbackId> callbackIds) const {
+ return std::hash<CallbackId>{}((callbackIds.size() == 0) ? 0 : callbackIds.front());
+ }
+};
+
+class SurfaceStats : public Parcelable {
+public:
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ SurfaceStats() = default;
+ SurfaceStats(const sp<IBinder>& sc, nsecs_t time, bool releasePrevBuffer)
+ : surfaceControl(sc), acquireTime(time), releasePreviousBuffer(releasePrevBuffer) {}
+
+ sp<IBinder> surfaceControl;
+ nsecs_t acquireTime = -1;
+ bool releasePreviousBuffer = false;
+};
+
+class TransactionStats : public Parcelable {
+public:
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ nsecs_t latchTime = -1;
+ nsecs_t presentTime = -1;
+ std::vector<SurfaceStats> surfaceStats;
+};
+
+class ListenerStats : public Parcelable {
+public:
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ static ListenerStats createEmpty(const sp<ITransactionCompletedListener>& listener,
+ const std::unordered_set<CallbackId>& callbackIds);
+
+ sp<ITransactionCompletedListener> listener;
+ std::unordered_map<std::vector<CallbackId>, TransactionStats, CallbackIdsHash> transactionStats;
+};
+
+class ITransactionCompletedListener : public IInterface {
+public:
+ DECLARE_META_INTERFACE(TransactionCompletedListener)
+
+ virtual void onTransactionCompleted(ListenerStats stats) = 0;
+};
+
+class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> {
+public:
+ BnTransactionCompletedListener()
+ : SafeBnInterface<ITransactionCompletedListener>("BnTransactionCompletedListener") {}
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0) override;
+};
+
+class ListenerCallbacks {
+public:
+ ListenerCallbacks(const sp<ITransactionCompletedListener>& listener,
+ const std::unordered_set<CallbackId>& callbacks)
+ : transactionCompletedListener(listener),
+ callbackIds(callbacks.begin(), callbacks.end()) {}
+
+ ListenerCallbacks(const sp<ITransactionCompletedListener>& listener,
+ const std::vector<CallbackId>& ids)
+ : transactionCompletedListener(listener), callbackIds(ids) {}
+
+ sp<ITransactionCompletedListener> transactionCompletedListener;
+ std::vector<CallbackId> callbackIds;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index e06e2b1..ddbac7b 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -23,6 +23,7 @@
#include <utils/Errors.h>
#include <gui/IGraphicBufferProducer.h>
+#include <gui/ITransactionCompletedListener.h>
#include <math/mat4.h>
#include <math/vec3.h>
#include <ui/GraphicTypes.h>
@@ -74,6 +75,7 @@
eApiChanged = 0x04000000,
eSidebandStreamChanged = 0x08000000,
eColorTransformChanged = 0x10000000,
+ eListenerCallbacksChanged = 0x20000000,
};
layer_state_t()
@@ -154,6 +156,8 @@
int32_t api;
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
+
+ std::vector<ListenerCallbacks> listenerCallbacks;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 8ccee05..1cafb77 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -19,7 +19,9 @@
#include <stdint.h>
#include <sys/types.h>
+#include <set>
#include <unordered_map>
+#include <unordered_set>
#include <binder/IBinder.h>
@@ -33,9 +35,10 @@
#include <ui/PixelFormat.h>
#include <gui/CpuConsumer.h>
+#include <gui/ITransactionCompletedListener.h>
+#include <gui/LayerState.h>
#include <gui/SurfaceControl.h>
#include <math/vec3.h>
-#include <gui/LayerState.h>
namespace android {
@@ -49,6 +52,37 @@
// ---------------------------------------------------------------------------
+using TransactionCompletedCallbackTakesContext =
+ std::function<void(void* /*context*/, const TransactionStats&)>;
+using TransactionCompletedCallback = std::function<void(const TransactionStats&)>;
+
+class TransactionCompletedListener : public BnTransactionCompletedListener {
+ TransactionCompletedListener();
+
+ CallbackId getNextIdLocked() REQUIRES(mMutex);
+
+ std::mutex mMutex;
+
+ bool mListening GUARDED_BY(mMutex) = false;
+
+ CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1;
+
+ std::map<CallbackId, TransactionCompletedCallback> mCallbacks GUARDED_BY(mMutex);
+
+public:
+ static sp<TransactionCompletedListener> getInstance();
+ static sp<ITransactionCompletedListener> getIInstance();
+
+ void startListeningLocked() REQUIRES(mMutex);
+
+ CallbackId addCallback(const TransactionCompletedCallback& callback);
+
+ // Overrides BnTransactionCompletedListener's onTransactionCompleted
+ void onTransactionCompleted(ListenerStats stats) override;
+};
+
+// ---------------------------------------------------------------------------
+
class SurfaceComposerClient : public RefBase
{
friend class Composer;
@@ -158,9 +192,27 @@
}
};
+ struct TCLHash {
+ std::size_t operator()(const sp<ITransactionCompletedListener>& tcl) const {
+ return std::hash<IBinder*>{}((tcl) ? IInterface::asBinder(tcl).get() : nullptr);
+ }
+ };
+
+ struct CallbackInfo {
+ // All the callbacks that have been requested for a TransactionCompletedListener in the
+ // Transaction
+ std::unordered_set<CallbackId> callbackIds;
+ // All the SurfaceControls that have been modified in this TransactionCompletedListener's
+ // process that require a callback if there is one or more callbackIds set.
+ std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls;
+ };
+
class Transaction {
std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
SortedVector<DisplayState > mDisplayStates;
+ std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
+ mListenerCallbacks;
+
uint32_t mForceSynchronous = 0;
uint32_t mTransactionNestCount = 0;
bool mAnimation = false;
@@ -171,6 +223,8 @@
layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
DisplayState& getDisplayState(const sp<IBinder>& token);
+ void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
+
public:
Transaction() = default;
virtual ~Transaction() = default;
@@ -250,6 +304,9 @@
Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
const sp<NativeHandle>& sidebandStream);
+ Transaction& addTransactionCompletedCallback(
+ TransactionCompletedCallbackTakesContext callback, void* callbackContext);
+
// Detaches all child surfaces (and their children recursively)
// from their SurfaceControl.
// The child SurfaceControls will not throw exceptions or return errors,
@@ -349,6 +406,7 @@
};
// ---------------------------------------------------------------------------
+
}; // namespace android
#endif // ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index f94faba..6968661 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -138,22 +138,18 @@
// --- InputWindowHandle ---
InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
- inputApplicationHandle(inputApplicationHandle), mInfo(nullptr) {
+ inputApplicationHandle(inputApplicationHandle) {
}
InputWindowHandle::~InputWindowHandle() {
- delete mInfo;
}
-void InputWindowHandle::releaseInfo() {
- if (mInfo) {
- delete mInfo;
- mInfo = nullptr;
- }
+void InputWindowHandle::releaseChannel() {
+ mInfo.inputChannel.clear();
}
sp<InputChannel> InputWindowHandle::getInputChannel() const {
- return mInfo ? mInfo->inputChannel : nullptr;
+ return mInfo.inputChannel;
}
} // namespace android
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 1bbd82b..42d774e 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -327,8 +327,8 @@
eventTime = event->getHistoricalEventTime(h);
for (size_t i = 0; i < pointerCount; i++) {
uint32_t index = pointerIndex[i];
- positions[index].x = event->getHistoricalRawX(i, h);
- positions[index].y = event->getHistoricalRawY(i, h);
+ positions[index].x = event->getHistoricalX(i, h);
+ positions[index].y = event->getHistoricalY(i, h);
}
addMovement(eventTime, idBits, positions);
}
@@ -336,8 +336,8 @@
eventTime = event->getEventTime();
for (size_t i = 0; i < pointerCount; i++) {
uint32_t index = pointerIndex[i];
- positions[index].x = event->getRawX(i);
- positions[index].y = event->getRawY(i);
+ positions[index].x = event->getX(i);
+ positions[index].y = event->getY(i);
}
addMovement(eventTime, idBits, positions);
}
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 647fe86..fba319d 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -47,6 +47,7 @@
cflags: [
"-Wall",
"-Werror",
+ "-Wno-enum-compare",
"-Wno-unused-function",
],
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 9ca4941..23ac60b 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -15,12 +15,31 @@
*/
/**
- * @addtogroup NativeActivity Native Activity
- * @{
- */
-
-/**
* @file hardware_buffer.h
+ * @brief API for native hardware buffers.
+ */
+/**
+ * @defgroup AHardwareBuffer Native Hardware Buffer
+ *
+ * AHardwareBuffer objects represent chunks of memory that can be
+ * accessed by various hardware components in the system. It can be
+ * easily converted to the Java counterpart
+ * android.hardware.HardwareBuffer and passed between processes using
+ * Binder. All operations involving AHardwareBuffer and HardwareBuffer
+ * are zero-copy, i.e., passing AHardwareBuffer to another process
+ * creates a shared view of the same region of memory.
+ *
+ * AHardwareBuffers can be bound to EGL/OpenGL and Vulkan primitives.
+ * For EGL, use the extension function eglGetNativeClientBufferANDROID
+ * to obtain an EGLClientBuffer and pass it directly to
+ * eglCreateImageKHR. Refer to the EGL extensions
+ * EGL_ANDROID_get_native_client_buffer and
+ * EGL_ANDROID_image_native_buffer for more information. In Vulkan,
+ * the contents of the AHardwareBuffer can be accessed as external
+ * memory. See the VK_ANDROID_external_memory_android_hardware_buffer
+ * extension for details.
+ *
+ * @{
*/
#ifndef ANDROID_HARDWARE_BUFFER_H
@@ -37,7 +56,7 @@
/**
* Buffer pixel formats.
*/
-enum {
+enum AHardwareBuffer_Format {
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_R8G8B8A8_UNORM
@@ -134,27 +153,47 @@
/**
* Buffer usage flags, specifying how the buffer will be accessed.
*/
-enum {
- /// The buffer will never be read by the CPU.
+enum AHardwareBuffer_UsageFlags {
+ /// The buffer will never be locked for direct CPU reads using the
+ /// AHardwareBuffer_lock() function. Note that reading the buffer
+ /// using OpenGL or Vulkan functions or memory mappings is still
+ /// allowed.
AHARDWAREBUFFER_USAGE_CPU_READ_NEVER = 0UL,
- /// The buffer will sometimes be read by the CPU.
+ /// The buffer will sometimes be locked for direct CPU reads using
+ /// the AHardwareBuffer_lock() function. Note that reading the
+ /// buffer using OpenGL or Vulkan functions or memory mappings
+ /// does not require the presence of this flag.
AHARDWAREBUFFER_USAGE_CPU_READ_RARELY = 2UL,
- /// The buffer will often be read by the CPU.
+ /// The buffer will often be locked for direct CPU reads using
+ /// the AHardwareBuffer_lock() function. Note that reading the
+ /// buffer using OpenGL or Vulkan functions or memory mappings
+ /// does not require the presence of this flag.
AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN = 3UL,
/// CPU read value mask.
AHARDWAREBUFFER_USAGE_CPU_READ_MASK = 0xFUL,
- /// The buffer will never be written by the CPU.
+ /// The buffer will never be locked for direct CPU writes using the
+ /// AHardwareBuffer_lock() function. Note that writing the buffer
+ /// using OpenGL or Vulkan functions or memory mappings is still
+ /// allowed.
AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER = 0UL << 4,
- /// The buffer will sometimes be written to by the CPU.
+ /// The buffer will sometimes be locked for direct CPU writes using
+ /// the AHardwareBuffer_lock() function. Note that writing the
+ /// buffer using OpenGL or Vulkan functions or memory mappings
+ /// does not require the presence of this flag.
AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY = 2UL << 4,
- /// The buffer will often be written to by the CPU.
+ /// The buffer will often be locked for direct CPU writes using
+ /// the AHardwareBuffer_lock() function. Note that writing the
+ /// buffer using OpenGL or Vulkan functions or memory mappings
+ /// does not require the presence of this flag.
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN = 3UL << 4,
/// CPU write value mask.
AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK = 0xFUL << 4,
/// The buffer will be read from by the GPU as a texture.
AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE = 1UL << 8,
+ /// The buffer will be written to by the GPU as a framebuffer attachment.
+ AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER = 1UL << 9,
/**
* The buffer will be written to by the GPU as a framebuffer attachment.
* Note that the name of this flag is somewhat misleading: it does not imply
@@ -162,16 +201,33 @@
* format that will be used as a framebuffer attachment should also have
* this flag.
*/
- AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = 1UL << 9,
- /// The buffer must not be used outside of a protected hardware path.
+ AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,
+ /**
+ * The buffer is protected from direct CPU access or being read by non-secure
+ * hardware, such as video encoders. This flag is incompatible with CPU
+ * read and write flags. It is mainly used when handling DRM video.
+ * Refer to the EGL extension EGL_EXT_protected_content and GL extension
+ * EXT_protected_textures for more information on how these buffers are expected
+ * to behave.
+ */
AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14,
/// The buffer will be read by a hardware video encoder.
AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16,
- /// The buffer will be used for direct writes from sensors.
+ /**
+ * The buffer will be used for direct writes from sensors.
+ * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
+ */
AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA = 1UL << 23,
- /// The buffer will be used as a shader storage or uniform buffer object.
+ /**
+ * The buffer will be used as a shader storage or uniform buffer object.
+ * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
+ */
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24,
- /// The buffer will be used as a cube map texture.
+ /**
+ * The buffer will be used as a cube map texture.
+ * When this flag is present, the buffer must have a layer count that is
+ * a multiple of 6.
+ */
AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 1UL << 25,
/// The buffer contains a complete mipmap hierarchy.
AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26,
@@ -206,20 +262,27 @@
uint32_t width; ///< Width in pixels.
uint32_t height; ///< Height in pixels.
uint32_t layers; ///< Number of images in an image array.
- uint32_t format; ///< One of AHARDWAREBUFFER_FORMAT_*
- uint64_t usage; ///< Combination of AHARDWAREBUFFER_USAGE_*
+ uint32_t format; ///< One of AHardwareBuffer_Format.
+ uint64_t usage; ///< Combination of AHardwareBuffer_UsageFlags.
uint32_t stride; ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
uint32_t rfu0; ///< Initialize to zero, reserved for future use.
uint64_t rfu1; ///< Initialize to zero, reserved for future use.
} AHardwareBuffer_Desc;
+/**
+ * Opaque handle for a native hardware buffer.
+ */
typedef struct AHardwareBuffer AHardwareBuffer;
#if __ANDROID_API__ >= 26
/**
- * Allocates a buffer that backs an AHardwareBuffer using the passed
- * AHardwareBuffer_Desc.
+ * Allocates a buffer that matches the passed AHardwareBuffer_Desc.
+ *
+ * If allocation succeeds, the buffer can be used according to the
+ * usage flags specified in its description. If a buffer is used in ways
+ * not compatible with its usage flags, the results are undefined and
+ * may include program termination.
*
* \return 0 on success, or an error number of the allocation fails for
* any reason. The returned buffer has a reference count of 1.
@@ -234,7 +297,7 @@
/**
* Remove a reference that was previously acquired with
- * AHardwareBuffer_acquire().
+ * AHardwareBuffer_acquire() or AHardwareBuffer_allocate().
*/
void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 6831f91..6730596 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -15,7 +15,13 @@
*/
/**
- * @addtogroup NativeActivity Native Activity
+ * @defgroup ANativeWindow Native Window
+ *
+ * ANativeWindow represents the producer end of an image queue.
+ * It is the C counterpart of the android.view.Surface object in Java,
+ * and can be converted both ways. Depending on the consumer, images
+ * submitted to ANativeWindow can be shown on the display or sent to
+ * other consumers, such as video encoders.
* @{
*/
@@ -41,7 +47,7 @@
* Legacy window pixel format names, kept for backwards compatibility.
* New code and APIs should use AHARDWAREBUFFER_FORMAT_*.
*/
-enum {
+enum ANativeWindow_LegacyFormat {
// NOTE: these values must match the values from graphics/common/x.x/types.hal
/** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Alpha: 8 bits. **/
@@ -95,7 +101,7 @@
/// memory. This may be >= width.
int32_t stride;
- /// The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
+ /// The format of the buffer. One of AHardwareBuffer_Format.
int32_t format;
/// The actual bits.
@@ -151,7 +157,7 @@
*
* \param width width of the buffers in pixels.
* \param height height of the buffers in pixels.
- * \param format one of AHARDWAREBUFFER_FORMAT_* constants.
+ * \param format one of the AHardwareBuffer_Format constants.
* \return 0 for success, or a negative value on error.
*/
int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 5a1ddee..29deb01 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -64,12 +64,11 @@
{
}
-GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
- PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage, std::string requestorName)
- : GraphicBuffer()
-{
- mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount,
- usage, std::move(requestorName));
+GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint64_t inUsage, std::string requestorName)
+ : GraphicBuffer() {
+ mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage,
+ std::move(requestorName));
}
// deprecated
@@ -82,15 +81,12 @@
{
}
-GraphicBuffer::GraphicBuffer(const native_handle_t* handle,
- HandleWrapMethod method, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount,
- uint64_t usage,
- uint32_t stride)
- : GraphicBuffer()
-{
- mInitCheck = initWithHandle(handle, method, width, height, format,
- layerCount, usage, stride);
+GraphicBuffer::GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method,
+ uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride)
+ : GraphicBuffer() {
+ mInitCheck = initWithHandle(inHandle, method, inWidth, inHeight, inFormat, inLayerCount,
+ inUsage, inStride);
}
GraphicBuffer::~GraphicBuffer()
@@ -182,26 +178,24 @@
return err;
}
-status_t GraphicBuffer::initWithHandle(const native_handle_t* handle,
- HandleWrapMethod method, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount, uint64_t usage,
- uint32_t stride)
-{
- ANativeWindowBuffer::width = static_cast<int>(width);
- ANativeWindowBuffer::height = static_cast<int>(height);
- ANativeWindowBuffer::stride = static_cast<int>(stride);
- ANativeWindowBuffer::format = format;
- ANativeWindowBuffer::usage = usage;
- ANativeWindowBuffer::usage_deprecated = int(usage);
+status_t GraphicBuffer::initWithHandle(const native_handle_t* inHandle, HandleWrapMethod method,
+ uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride) {
+ ANativeWindowBuffer::width = static_cast<int>(inWidth);
+ ANativeWindowBuffer::height = static_cast<int>(inHeight);
+ ANativeWindowBuffer::stride = static_cast<int>(inStride);
+ ANativeWindowBuffer::format = inFormat;
+ ANativeWindowBuffer::usage = inUsage;
+ ANativeWindowBuffer::usage_deprecated = int(inUsage);
- ANativeWindowBuffer::layerCount = layerCount;
+ ANativeWindowBuffer::layerCount = inLayerCount;
mOwner = (method == WRAP_HANDLE) ? ownNone : ownHandle;
if (method == TAKE_UNREGISTERED_HANDLE || method == CLONE_HANDLE) {
buffer_handle_t importedHandle;
- status_t err = mBufferMapper.importBuffer(handle, width, height,
- layerCount, format, usage, stride, &importedHandle);
+ status_t err = mBufferMapper.importBuffer(inHandle, inWidth, inHeight, inLayerCount,
+ inFormat, inUsage, inStride, &importedHandle);
if (err != NO_ERROR) {
initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0);
@@ -209,15 +203,15 @@
}
if (method == TAKE_UNREGISTERED_HANDLE) {
- native_handle_close(handle);
- native_handle_delete(const_cast<native_handle_t*>(handle));
+ native_handle_close(inHandle);
+ native_handle_delete(const_cast<native_handle_t*>(inHandle));
}
- handle = importedHandle;
- mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
+ inHandle = importedHandle;
+ mBufferMapper.getTransportSize(inHandle, &mTransportNumFds, &mTransportNumInts);
}
- ANativeWindowBuffer::handle = handle;
+ ANativeWindowBuffer::handle = inHandle;
return NO_ERROR;
}
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index e794462..fe6229a 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -117,18 +117,16 @@
// cannot be used directly, such as one from hidl_handle.
CLONE_HANDLE,
};
- GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method,
- uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount,
- uint64_t usage, uint32_t stride);
+ GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method, uint32_t inWidth,
+ uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage,
+ uint32_t inStride);
// These functions are deprecated because they only take 32 bits of usage
- GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method,
- uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount,
- uint32_t usage, uint32_t stride)
- : GraphicBuffer(handle, method, width, height, format, layerCount,
- static_cast<uint64_t>(usage), stride) {}
+ GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method, uint32_t inWidth,
+ uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage,
+ uint32_t inStride)
+ : GraphicBuffer(inHandle, method, inWidth, inHeight, inFormat, inLayerCount,
+ static_cast<uint64_t>(inUsage), inStride) {}
GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
uint32_t inLayerCount, uint32_t inUsage, uint32_t inStride,
native_handle_t* inHandle, bool keepOwnership);
@@ -220,10 +218,9 @@
PixelFormat inFormat, uint32_t inLayerCount,
uint64_t inUsage, std::string requestorName);
- status_t initWithHandle(const native_handle_t* handle,
- HandleWrapMethod method, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount,
- uint64_t usage, uint32_t stride);
+ status_t initWithHandle(const native_handle_t* inHandle, HandleWrapMethod method,
+ uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride);
void free_handle();
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 1521e1d..4c9c176 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -32,7 +32,8 @@
name: "BufferHubBuffer_test",
header_libs: [
"libbufferhub_headers",
- "libdvr_headers"
+ "libdvr_headers",
+ "libnativewindow_headers",
],
shared_libs: [
"android.frameworks.bufferhub@1.0",
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index a247e60..6af8033 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,7 +16,9 @@
#define LOG_TAG "BufferHubBufferTest"
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
+#include <android/hardware_buffer.h>
#include <gtest/gtest.h>
#include <hidl/ServiceManagement.h>
#include <hwbinder/IPCThreadState.h>
@@ -33,13 +35,14 @@
const int kUsage = 0;
const size_t kUserMetadataSize = 0;
-} // namespace
-
using dvr::BufferHubDefs::IsBufferGained;
using dvr::BufferHubDefs::kFirstClientBitMask;
using dvr::BufferHubDefs::kMetadataHeaderSize;
+using frameworks::bufferhub::V1_0::BufferHubStatus;
+using frameworks::bufferhub::V1_0::IBufferClient;
using frameworks::bufferhub::V1_0::IBufferHub;
using hardware::hidl_handle;
+using hardware::graphics::common::V1_2::HardwareBufferDescription;
using hidl::base::V1_0::IBase;
using pdx::LocalChannelHandle;
@@ -123,14 +126,51 @@
return;
}
-TEST_F(BufferHubBufferTest, ConnectHidlServer) {
+TEST_F(BufferHubBufferTest, AllocateBuffer) {
+ // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
+ sp<IBufferHub> bufferHub = IBufferHub::getService();
+ ASSERT_NE(nullptr, bufferHub.get());
+
+ // Stride is an output, rfu0 and rfu1 are reserved data slot for future use.
+ AHardwareBuffer_Desc aDesc = {kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+ HardwareBufferDescription desc;
+ memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
+
+ IBufferHub::allocateBuffer_cb callback = [](const auto& client, const auto& status) {
+ EXPECT_EQ(status, BufferHubStatus::NO_ERROR);
+ EXPECT_NE(nullptr, client.get());
+ };
+ EXPECT_TRUE(bufferHub->allocateBuffer(desc, kUserMetadataSize, callback).isOk());
+}
+
+TEST_F(BufferHubBufferTest, DuplicateBuffer) {
+ // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
sp<IBufferHub> bufferhub = IBufferHub::getService();
ASSERT_NE(nullptr, bufferhub.get());
- // TODO(b/116681016): Fill in real test once the interface gets implemented..
- hidl_handle handle;
- sp<IBase> interface = bufferhub->importBuffer(handle);
- EXPECT_EQ(nullptr, interface.get());
+ // Stride is an output, rfu0 and rfu1 are reserved data slot for future use.
+ AHardwareBuffer_Desc aDesc = {kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+ HardwareBufferDescription desc;
+ memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
+
+ sp<IBufferClient> client;
+ IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& outClient, const auto& status) {
+ ASSERT_EQ(status, BufferHubStatus::NO_ERROR);
+ ASSERT_NE(nullptr, outClient.get());
+ client = outClient;
+ };
+ ASSERT_TRUE(bufferhub->allocateBuffer(desc, kUserMetadataSize, alloc_cb).isOk());
+
+ IBufferClient::duplicate_cb dup_cb = [](const auto& token, const auto& status) {
+ ASSERT_EQ(status, BufferHubStatus::NO_ERROR);
+ ASSERT_NE(token.getNativeHandle(), nullptr);
+ EXPECT_EQ(token->numInts, 1);
+ EXPECT_EQ(token->numFds, 0);
+ };
+ EXPECT_TRUE(client->duplicate(dup_cb).isOk());
}
+} // namespace
} // namespace android
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index b8e2f9d..f7942d0 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -337,8 +337,6 @@
Status<void> BufferHubQueue::Enqueue(Entry entry) {
if (!is_full()) {
- available_buffers_.push(std::move(entry));
-
// Find and remove the enqueued buffer from unavailable_buffers_slot if
// exist.
auto enqueued_buffer_iter = std::find_if(
@@ -348,6 +346,8 @@
unavailable_buffers_slot_.erase(enqueued_buffer_iter);
}
+ available_buffers_.push(std::move(entry));
+
// Trigger OnBufferAvailable callback if registered.
if (on_buffer_available_)
on_buffer_available_();
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index 68b8dd7..3769162 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -318,13 +318,7 @@
PDX_TRACE_NAME("Message::ReplyFileHandle");
auto svc = service_.lock();
if (!replied_ && svc) {
- Status<void> ret;
-
- if (handle)
- ret = svc->endpoint()->MessageReply(this, handle.Get());
- else
- ret = svc->endpoint()->MessageReply(this, handle.Get());
-
+ Status<void> ret = svc->endpoint()->MessageReply(this, handle.Get());
replied_ = ret.ok();
return ret;
} else {
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 0c43b83..e27f233 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -584,7 +584,13 @@
// The "Developer Options" value wasn't set to force the use of ANGLE. Need to temporarily
// load ANGLE and call the updatable opt-in/out logic:
- cnx->featureSo = load_angle_from_namespace("feature_support", ns);
+ // Check if ANGLE is enabled. Workaround for several bugs:
+ // b/119305693 b/119322355 b/119305887
+ // Something is not working correctly in the feature library
+ property_get("debug.angle.enable", prop, "0");
+ if (atoi(prop)) {
+ cnx->featureSo = load_angle_from_namespace("feature_support", ns);
+ }
if (cnx->featureSo) {
ALOGV("loaded ANGLE's opt-in/out logic from namespace");
use_angle = check_angle_rules(cnx->featureSo, app_name);
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
index d03d833..8b43333 100644
--- a/services/bufferhub/Android.bp
+++ b/services/bufferhub/Android.bp
@@ -22,6 +22,7 @@
"-Wextra",
],
srcs: [
+ "BufferClient.cpp",
"BufferHubService.cpp",
"BufferNode.cpp",
],
@@ -33,6 +34,7 @@
],
shared_libs: [
"android.frameworks.bufferhub@1.0",
+ "libcutils",
"libhidlbase",
"libhidltransport",
"libhwbinder",
@@ -51,9 +53,16 @@
srcs: [
"main_bufferhub.cpp"
],
+ header_libs: [
+ "libbufferhub_headers",
+ "libdvr_headers",
+ "libnativewindow_headers",
+ "libpdx_headers",
+ ],
shared_libs: [
"android.frameworks.bufferhub@1.0",
"libbufferhubservice",
+ "libcutils",
"libhidltransport",
"libhwbinder",
"liblog",
diff --git a/services/bufferhub/BufferClient.cpp b/services/bufferhub/BufferClient.cpp
new file mode 100644
index 0000000..37fd75f
--- /dev/null
+++ b/services/bufferhub/BufferClient.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bufferhub/BufferClient.h>
+#include <bufferhub/BufferHubService.h>
+#include <hidl/HidlSupport.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using hardware::hidl_handle;
+using hardware::Void;
+
+BufferClient* BufferClient::create(BufferHubService* service,
+ const std::shared_ptr<BufferNode>& node) {
+ if (!service) {
+ ALOGE("%s: service cannot be nullptr.", __FUNCTION__);
+ return nullptr;
+ } else if (!node) {
+ ALOGE("%s: node cannot be nullptr.", __FUNCTION__);
+ return nullptr;
+ }
+ return new BufferClient(service, node);
+}
+
+Return<void> BufferClient::duplicate(duplicate_cb _hidl_cb) {
+ if (!mBufferNode) {
+ // Should never happen
+ ALOGE("%s: node is missing.", __FUNCTION__);
+ _hidl_cb(/*token=*/hidl_handle(), /*status=*/BufferHubStatus::BUFFER_FREED);
+ return Void();
+ }
+
+ sp<BufferHubService> service = mService.promote();
+ if (service == nullptr) {
+ // Should never happen. Kill the process.
+ LOG_FATAL("%s: service died.", __FUNCTION__);
+ }
+
+ const hidl_handle token = service->registerToken(this);
+ _hidl_cb(/*token=*/token, /*status=*/BufferHubStatus::NO_ERROR);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
\ No newline at end of file
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index 8be85a5..3bfd9cb 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -14,7 +14,10 @@
* limitations under the License.
*/
+#include <android/hardware_buffer.h>
#include <bufferhub/BufferHubService.h>
+#include <cutils/native_handle.h>
+#include <log/log.h>
namespace android {
namespace frameworks {
@@ -22,16 +25,56 @@
namespace V1_0 {
namespace implementation {
-using ::android::status_t;
-using ::android::hardware::Void;
+using hardware::Void;
-Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& /*description*/,
- allocateBuffer_cb /*hidl_cb*/) {
+Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& description,
+ const uint32_t userMetadataSize,
+ allocateBuffer_cb _hidl_cb) {
+ AHardwareBuffer_Desc desc;
+ memcpy(&desc, &description, sizeof(AHardwareBuffer_Desc));
+
+ std::shared_ptr<BufferNode> node =
+ std::make_shared<BufferNode>(desc.width, desc.height, desc.layers, desc.format,
+ desc.usage, userMetadataSize);
+ if (node == nullptr || !node->IsValid()) {
+ ALOGE("%s: creating BufferNode failed.", __FUNCTION__);
+ _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::ALLOCATION_FAILED);
+ return Void();
+ }
+
+ sp<BufferClient> client = BufferClient::create(this, node);
+ // Add it to list for bookkeeping and dumpsys.
+ std::lock_guard<std::mutex> lock(mClientListMutex);
+ mClientList.push_back(client);
+
+ _hidl_cb(/*bufferClient=*/client, /*status=*/BufferHubStatus::NO_ERROR);
return Void();
}
-Return<sp<IBase>> BufferHubService::importBuffer(const hidl_handle& /*nativeHandle*/) {
- return nullptr;
+Return<void> BufferHubService::importBuffer(const hidl_handle& /*nativeHandle*/,
+ importBuffer_cb _hidl_cb) {
+ // TODO(b/118614157): implement buffer import
+ _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::NO_ERROR);
+ return Void();
+}
+
+hidl_handle BufferHubService::registerToken(const BufferClient* client) {
+ uint32_t token;
+ std::lock_guard<std::mutex> lock(mTokenMapMutex);
+ do {
+ token = mTokenEngine();
+ } while (mTokenMap.find(token) != mTokenMap.end());
+
+ // native_handle_t use int[], so here need one slots to fit in uint32_t
+ native_handle_t* handle = native_handle_create(/*numFds=*/0, /*numInts=*/1);
+ handle->data[0] = token;
+
+ // returnToken owns the native_handle_t* thus doing lifecycle management
+ hidl_handle returnToken;
+ returnToken.setTo(handle, /*shoudOwn=*/true);
+
+ mTokenMap.emplace(token, client);
+ return returnToken;
}
} // namespace implementation
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
index 62583a6..53dd702 100644
--- a/services/bufferhub/BufferNode.cpp
+++ b/services/bufferhub/BufferNode.cpp
@@ -35,7 +35,7 @@
/*requestor=*/"bufferhub");
if (ret != OK || buffer_handle_ == nullptr) {
- ALOGE("BufferNode::BufferNode: Failed to allocate buffer: %s", strerror(-ret));
+ ALOGE("%s: Failed to allocate buffer: %s", __FUNCTION__, strerror(-ret));
return;
}
@@ -48,7 +48,7 @@
metadata_ = BufferHubMetadata::Create(user_metadata_size);
if (!metadata_.IsValid()) {
- ALOGE("BufferNode::BufferNode: Failed to allocate metadata.");
+ ALOGE("%s: Failed to allocate metadata.", __FUNCTION__);
return;
}
InitializeMetadata();
@@ -59,7 +59,7 @@
if (buffer_handle_ != nullptr) {
status_t ret = GraphicBufferAllocator::get().free(buffer_handle_);
if (ret != OK) {
- ALOGE("BufferNode::~BufferNode: Failed to free handle; Got error: %d", ret);
+ ALOGE("%s: Failed to free handle; Got error: %d", __FUNCTION__, ret);
}
}
}
@@ -76,8 +76,7 @@
client_state_mask = dvr::BufferHubDefs::FindNextAvailableClientStateMask(
current_active_clients_bit_mask);
if (client_state_mask == 0ULL) {
- ALOGE("BufferNode::AddNewActiveClientsBitToMask: reached the maximum "
- "mumber of channels per buffer node: 32.");
+ ALOGE("%s: reached the maximum number of channels per buffer node: 32.", __FUNCTION__);
errno = E2BIG;
return 0ULL;
}
diff --git a/services/bufferhub/include/bufferhub/BufferClient.h b/services/bufferhub/include/bufferhub/BufferClient.h
new file mode 100644
index 0000000..5456ec3
--- /dev/null
+++ b/services/bufferhub/include/bufferhub/BufferClient.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H
+#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H
+
+#include <mutex>
+
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
+#include <bufferhub/BufferNode.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using hardware::hidl_handle;
+using hardware::Return;
+
+// Forward declaration to avoid circular dependency
+class BufferHubService;
+
+class BufferClient : public IBufferClient {
+public:
+ // Creates a server-side buffer client from an existing BufferNode. Note that
+ // this funciton takes ownership of the shared_ptr.
+ // Returns a raw pointer to the BufferClient on success, nullptr on failure.
+ static BufferClient* create(BufferHubService* service, const std::shared_ptr<BufferNode>& node);
+
+ Return<void> duplicate(duplicate_cb _hidl_cb) override;
+
+private:
+ BufferClient(wp<BufferHubService> service, const std::shared_ptr<BufferNode>& node)
+ : mService(service), mBufferNode(node){};
+
+ wp<BufferHubService> mService;
+ std::shared_ptr<BufferNode> mBufferNode;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
+
+#endif
\ No newline at end of file
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
index b273e5b..dbbee8f 100644
--- a/services/bufferhub/include/bufferhub/BufferHubService.h
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -17,8 +17,12 @@
#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
+#include <mutex>
+#include <random>
+
#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
-#include <android/hardware/graphics/common/1.2/types.h>
+#include <bufferhub/BufferClient.h>
+#include <utils/Mutex.h>
namespace android {
namespace frameworks {
@@ -26,17 +30,31 @@
namespace V1_0 {
namespace implementation {
-using ::android::sp;
-using ::android::hardware::hidl_handle;
-using ::android::hardware::Return;
-using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
-using ::android::hidl::base::V1_0::IBase;
+using hardware::hidl_handle;
+using hardware::Return;
+using hardware::graphics::common::V1_2::HardwareBufferDescription;
class BufferHubService : public IBufferHub {
public:
- Return<void> allocateBuffer(const HardwareBufferDescription& /*description*/,
- allocateBuffer_cb /*hidl_cb*/) override;
- Return<sp<IBase>> importBuffer(const hidl_handle& /*nativeHandle*/) override;
+ Return<void> allocateBuffer(const HardwareBufferDescription& description,
+ const uint32_t userMetadataSize,
+ allocateBuffer_cb _hidl_cb) override;
+ Return<void> importBuffer(const hidl_handle& nativeHandle, importBuffer_cb _hidl_cb) override;
+
+ // Non-binder functions
+ // Internal help function for IBufferClient::duplicate.
+ hidl_handle registerToken(const BufferClient* client);
+
+private:
+ // List of active BufferClient for bookkeeping.
+ std::mutex mClientListMutex;
+ std::vector<sp<BufferClient>> mClientList GUARDED_BY(mClientListMutex);
+
+ // TODO(b/118180214): use a more secure implementation
+ std::mt19937 mTokenEngine;
+ // The mapping from token to the client creates it.
+ std::mutex mTokenMapMutex;
+ std::map<uint32_t, const BufferClient*> mTokenMap GUARDED_BY(mTokenMapMutex);
};
} // namespace implementation
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index a964d29..31057f6 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -147,8 +147,7 @@
fd(fd), id(id), path(path), identifier(identifier),
classes(0), configuration(nullptr), virtualKeyMap(nullptr),
ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0),
- timestampOverrideSec(0), timestampOverrideUsec(0), enabled(true),
- isVirtual(fd < 0) {
+ enabled(true), isVirtual(fd < 0) {
memset(keyBitmask, 0, sizeof(keyBitmask));
memset(absBitmask, 0, sizeof(absBitmask));
memset(relBitmask, 0, sizeof(relBitmask));
@@ -193,8 +192,6 @@
// --- EventHub ---
-const uint32_t EventHub::EPOLL_ID_INOTIFY;
-const uint32_t EventHub::EPOLL_ID_WAKE;
const int EventHub::EPOLL_SIZE_HINT;
const int EventHub::EPOLL_MAX_EVENTS;
@@ -217,7 +214,7 @@
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
- eventItem.data.u32 = EPOLL_ID_INOTIFY;
+ eventItem.data.fd = mINotifyFd;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
@@ -236,7 +233,7 @@
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
- eventItem.data.u32 = EPOLL_ID_WAKE;
+ eventItem.data.fd = mWakeReadPipeFd;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
@@ -735,6 +732,16 @@
return nullptr;
}
+EventHub::Device* EventHub::getDeviceByFdLocked(int fd) const {
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ Device* device = mDevices.valueAt(i);
+ if (device->fd == fd) {
+ return device;
+ }
+ }
+ return nullptr;
+}
+
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
ALOG_ASSERT(bufferSize >= 1);
@@ -811,7 +818,7 @@
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
- if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
+ if (eventItem.data.fd == mINotifyFd) {
if (eventItem.events & EPOLLIN) {
mPendingINotify = true;
} else {
@@ -820,7 +827,7 @@
continue;
}
- if (eventItem.data.u32 == EPOLL_ID_WAKE) {
+ if (eventItem.data.fd == mWakeReadPipeFd) {
if (eventItem.events & EPOLLIN) {
ALOGV("awoken after wake()");
awoken = true;
@@ -836,14 +843,13 @@
continue;
}
- ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
- if (deviceIndex < 0) {
- ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",
- eventItem.events, eventItem.data.u32);
+ Device* device = getDeviceByFdLocked(eventItem.data.fd);
+ if (device == nullptr) {
+ ALOGW("Received unexpected epoll event 0x%08x for unknown device fd %d.",
+ eventItem.events, eventItem.data.fd);
continue;
}
- Device* device = mDevices.valueAt(deviceIndex);
if (eventItem.events & EPOLLIN) {
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
@@ -871,31 +877,6 @@
(int) iev.time.tv_sec, (int) iev.time.tv_usec,
iev.type, iev.code, iev.value);
- // Some input devices may have a better concept of the time
- // when an input event was actually generated than the kernel
- // which simply timestamps all events on entry to evdev.
- // This is a custom Android extension of the input protocol
- // mainly intended for use with uinput based device drivers.
- if (iev.type == EV_MSC) {
- if (iev.code == MSC_ANDROID_TIME_SEC) {
- device->timestampOverrideSec = iev.value;
- continue;
- } else if (iev.code == MSC_ANDROID_TIME_USEC) {
- device->timestampOverrideUsec = iev.value;
- continue;
- }
- }
- if (device->timestampOverrideSec || device->timestampOverrideUsec) {
- iev.time.tv_sec = device->timestampOverrideSec;
- iev.time.tv_usec = device->timestampOverrideUsec;
- if (iev.type == EV_SYN && iev.code == SYN_REPORT) {
- device->timestampOverrideSec = 0;
- device->timestampOverrideUsec = 0;
- }
- ALOGV("applied override time %d.%06d",
- int(iev.time.tv_sec), int(iev.time.tv_usec));
- }
-
// Use the time specified in the event instead of the current time
// so that downstream code can get more accurate estimates of
// event dispatch latency from the time the event is enqueued onto
@@ -1089,7 +1070,7 @@
if (mUsingEpollWakeup) {
eventItem.events |= EPOLLWAKEUP;
}
- eventItem.data.u32 = device->id;
+ eventItem.data.fd = device->fd;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, device->fd, &eventItem)) {
ALOGE("Could not add device fd to epoll instance. errno=%d", errno);
return -errno;
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index ea663b7..e2c7e82 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -42,20 +42,6 @@
#define BTN_FIRST 0x100 // first button code
#define BTN_LAST 0x15f // last button code
-/*
- * These constants are used privately in Android to pass raw timestamps
- * through evdev from uinput device drivers because there is currently no
- * other way to transfer this information. The evdev driver automatically
- * timestamps all input events with the time they were posted and clobbers
- * whatever information was passed in.
- *
- * For the purposes of this hack, the timestamp is specified in the
- * CLOCK_MONOTONIC timebase and is split into two EV_MSC events specifying
- * seconds and microseconds.
- */
-#define MSC_ANDROID_TIME_SEC 0x6
-#define MSC_ANDROID_TIME_USEC 0x7
-
namespace android {
enum {
@@ -371,9 +357,6 @@
int32_t controllerNumber;
- int32_t timestampOverrideSec;
- int32_t timestampOverrideUsec;
-
Device(int fd, int32_t id, const std::string& path,
const InputDeviceIdentifier& identifier);
~Device();
@@ -418,6 +401,7 @@
Device* getDeviceByDescriptorLocked(const std::string& descriptor) const;
Device* getDeviceLocked(int32_t deviceId) const;
Device* getDeviceByPathLocked(const char* devicePath) const;
+ Device* getDeviceByFdLocked(int fd) const;
bool hasKeycodeLocked(Device* device, int keycode) const;
@@ -466,10 +450,6 @@
int mWakeReadPipeFd;
int mWakeWritePipeFd;
- // Ids used for epoll notifications not associated with devices.
- static const uint32_t EPOLL_ID_INOTIFY = 0x80000001;
- static const uint32_t EPOLL_ID_WAKE = 0x80000002;
-
// Epoll FD list size hint.
static const int EPOLL_SIZE_HINT = 8;
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 2e984d9..3f39afd 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -864,11 +864,11 @@
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", "
"policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, "
- "metaState=0x%x, repeatCount=%d, downTime=%" PRId64,
+ "metaState=0x%x, repeatCount=%d, downTime=%" PRId64 ", displayId=%" PRId32,
prefix,
entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags,
entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState,
- entry->repeatCount, entry->downTime);
+ entry->repeatCount, entry->downTime, entry->displayId);
#endif
}
@@ -940,13 +940,13 @@
", policyFlags=0x%x, "
"action=0x%x, actionButton=0x%x, flags=0x%x, "
"metaState=0x%x, buttonState=0x%x,"
- "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
+ "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64", displayId=%" PRId32,
prefix,
entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags,
entry->action, entry->actionButton, entry->flags,
entry->metaState, entry->buttonState,
entry->edgeFlags, entry->xPrecision, entry->yPrecision,
- entry->downTime);
+ entry->downTime, entry->displayId);
for (uint32_t i = 0; i < entry->pointerCount; i++) {
ALOGD(" Pointer %d: id=%d, toolType=%d, "
@@ -1168,7 +1168,8 @@
goto Unresponsive;
}
- ALOGI("Dropping event because there is no focused window or focused application.");
+ ALOGI("Dropping event because there is no focused window or focused application in display "
+ "%" PRId32 ".", displayId);
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
}
@@ -1254,7 +1255,8 @@
bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
if (switchedDevice && mTempTouchState.down && !down && !isHoverAction) {
#if DEBUG_FOCUS
- ALOGD("Dropping event because a pointer for a different device is already down.");
+ ALOGD("Dropping event because a pointer for a different device is already down "
+ "in display %" PRId32, displayId);
#endif
// TODO: test multiple simultaneous input streams.
injectionResult = INPUT_EVENT_INJECTION_FAILED;
@@ -1270,7 +1272,8 @@
isSplit = false;
} else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) {
#if DEBUG_FOCUS
- ALOGI("Dropping move event because a pointer for a different device is already active.");
+ ALOGI("Dropping move event because a pointer for a different device is already active "
+ "in display %" PRId32, displayId);
#endif
// TODO: test multiple simultaneous input streams.
injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
@@ -1335,7 +1338,8 @@
// Try to assign the pointer to the first foreground window we find, if there is one.
newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();
if (newTouchedWindowHandle == nullptr) {
- ALOGI("Dropping event because there is no touchable window at (%d, %d).", x, y);
+ ALOGI("Dropping event because there is no touchable window at (%d, %d) in display "
+ "%" PRId32 ".", x, y, displayId);
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
}
@@ -1373,7 +1377,7 @@
if (! mTempTouchState.down) {
#if DEBUG_FOCUS
ALOGD("Dropping event because the pointer is not down or we previously "
- "dropped the pointer down event.");
+ "dropped the pointer down event in display %" PRId32, displayId);
#endif
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
@@ -1393,9 +1397,10 @@
if (oldTouchedWindowHandle != newTouchedWindowHandle
&& newTouchedWindowHandle != nullptr) {
#if DEBUG_FOCUS
- ALOGD("Touch is slipping out of window %s into window %s.",
+ ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32,
oldTouchedWindowHandle->getName().c_str(),
- newTouchedWindowHandle->getName().c_str());
+ newTouchedWindowHandle->getName().c_str(),
+ displayId);
#endif
// Make a slippery exit from the old window.
mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
@@ -1464,7 +1469,8 @@
}
if (! haveForegroundWindow) {
#if DEBUG_FOCUS
- ALOGD("Dropping event because there is no touched foreground window to receive it.");
+ ALOGD("Dropping event because there is no touched foreground window in display %" PRId32
+ " to receive it.", displayId);
#endif
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
@@ -1689,7 +1695,7 @@
} else {
// If there is no monitor channel registered or all monitor channel unregistered,
// the display can't detect the extra system gesture by a copy of input events.
- ALOGW("There is no monitor channel found in display=%" PRId32, displayId);
+ ALOGW("There is no monitor channel found in display %" PRId32, displayId);
}
}
@@ -2533,10 +2539,11 @@
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("notifyKey - eventTime=%" PRId64
", deviceId=%d, source=0x%x, displayId=%" PRId32 "policyFlags=0x%x, action=0x%x, "
- "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
+ "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64
+ ", displayId=%" PRId32,
args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
args->action, args->flags, args->keyCode, args->scanCode,
- args->metaState, args->downTime);
+ args->metaState, args->downTime, args->displayId);
#endif
if (!validateKeyEvent(args->action)) {
return;
@@ -2611,10 +2618,10 @@
ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
", policyFlags=0x%x, "
"action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x,"
- "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
- args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
+ "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", displayId=%" PRId32
+ , args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
- args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
+ args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, args->displayId);
for (uint32_t i = 0; i < args->pointerCount; i++) {
ALOGD(" Pointer %d: id=%d, toolType=%d, "
"x=%f, y=%f, pressure=%f, size=%f, "
@@ -3013,9 +3020,10 @@
for (size_t i = 0; i < numWindows; i++) {
if (windowHandles.itemAt(i) == windowHandle) {
if (windowHandle->getInfo()->displayId != it.first) {
- ALOGE("Found window %s in display %d, but it should belong to display %d",
- windowHandle->getName().c_str(), it.first,
- windowHandle->getInfo()->displayId);
+ ALOGE("Found window %s in display %" PRId32
+ ", but it should belong to display %" PRId32,
+ windowHandle->getName().c_str(), it.first,
+ windowHandle->getInfo()->displayId);
}
return true;
}
@@ -3034,7 +3042,7 @@
void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& inputWindowHandles,
int32_t displayId) {
#if DEBUG_FOCUS
- ALOGD("setInputWindows");
+ ALOGD("setInputWindows displayId=%" PRId32, displayId);
#endif
{ // acquire lock
AutoMutex _l(mLock);
@@ -3085,8 +3093,8 @@
if (oldFocusedWindowHandle != newFocusedWindowHandle) {
if (oldFocusedWindowHandle != nullptr) {
#if DEBUG_FOCUS
- ALOGD("Focus left window: %s",
- oldFocusedWindowHandle->getName().c_str());
+ ALOGD("Focus left window: %s in display %" PRId32,
+ oldFocusedWindowHandle->getName().c_str(), displayId);
#endif
sp<InputChannel> focusedInputChannel = oldFocusedWindowHandle->getInputChannel();
if (focusedInputChannel != nullptr) {
@@ -3099,8 +3107,8 @@
}
if (newFocusedWindowHandle != nullptr) {
#if DEBUG_FOCUS
- ALOGD("Focus entered window: %s",
- newFocusedWindowHandle->getName().c_str());
+ ALOGD("Focus entered window: %s in display %" PRId32,
+ newFocusedWindowHandle->getName().c_str(), displayId);
#endif
mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle;
}
@@ -3113,8 +3121,8 @@
TouchedWindow& touchedWindow = state.windows.editItemAt(i);
if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
#if DEBUG_FOCUS
- ALOGD("Touched window was removed: %s",
- touchedWindow.windowHandle->getName().c_str());
+ ALOGD("Touched window was removed: %s in display %" PRId32,
+ touchedWindow.windowHandle->getName().c_str(), displayId);
#endif
sp<InputChannel> touchedInputChannel =
touchedWindow.windowHandle->getInputChannel();
@@ -3142,7 +3150,7 @@
#if DEBUG_FOCUS
ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
#endif
- oldWindowHandle->releaseInfo();
+ oldWindowHandle->releaseChannel();
}
}
} // release lock
@@ -3154,7 +3162,7 @@
void InputDispatcher::setFocusedApplication(
int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) {
#if DEBUG_FOCUS
- ALOGD("setFocusedApplication");
+ ALOGD("setFocusedApplication displayId=%" PRId32, displayId);
#endif
{ // acquire lock
AutoMutex _l(mLock);
@@ -3469,7 +3477,7 @@
if (!mWindowHandlesByDisplay.empty()) {
for (auto& it : mWindowHandlesByDisplay) {
const Vector<sp<InputWindowHandle>> windowHandles = it.second;
- dump += StringPrintf(INDENT "Display: %d\n", it.first);
+ dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first);
if (!windowHandles.isEmpty()) {
dump += INDENT2 "Windows:\n";
for (size_t i = 0; i < windowHandles.size(); i++) {
@@ -3509,7 +3517,7 @@
if (!mMonitoringChannelsByDisplay.empty()) {
for (auto& it : mMonitoringChannelsByDisplay) {
const Vector<sp<InputChannel>>& monitoringChannels = it.second;
- dump += INDENT "MonitoringChannels in Display %d:\n";
+ dump += StringPrintf(INDENT "MonitoringChannels in display %" PRId32 ":\n", it.first);
const size_t numChannels = monitoringChannels.size();
for (size_t i = 0; i < numChannels; i++) {
const sp<InputChannel>& channel = monitoringChannels[i];
@@ -3737,6 +3745,10 @@
}
ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
+ if (!inputChannel) {
+ return -1;
+ }
+
ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd());
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
@@ -3744,7 +3756,6 @@
return connectionIndex;
}
}
-
return -1;
}
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 869bd71..e85e6ef 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -3480,8 +3480,8 @@
}
// Raw width and height in the natural orientation.
- int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
- int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
+ int32_t rawWidth = mRawPointerAxes.getRawWidth();
+ int32_t rawHeight = mRawPointerAxes.getRawHeight();
// Get associated display dimensions.
DisplayViewport newViewport;
@@ -3913,8 +3913,8 @@
int32_t touchScreenLeft = mRawPointerAxes.x.minValue;
int32_t touchScreenTop = mRawPointerAxes.y.minValue;
- int32_t touchScreenWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
- int32_t touchScreenHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
+ int32_t touchScreenWidth = mRawPointerAxes.getRawWidth();
+ int32_t touchScreenHeight = mRawPointerAxes.getRawHeight();
for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
const VirtualKeyDefinition& virtualKeyDefinition =
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 3410bc9..9b0007a 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -772,6 +772,8 @@
RawAbsoluteAxisInfo slot;
RawPointerAxes();
+ inline int32_t getRawWidth() const { return x.maxValue - x.minValue + 1; }
+ inline int32_t getRawHeight() const { return y.maxValue - y.minValue + 1; }
void clear();
};
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c6eaf9f..066c143 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -370,30 +370,27 @@
}
virtual bool updateInfo() {
- if (!mInfo) {
- mInfo = new InputWindowInfo();
- }
- mInfo->inputChannel = mServerChannel;
- mInfo->name = mName;
- mInfo->layoutParamsFlags = 0;
- mInfo->layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
- mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
- mInfo->frameLeft = 0;
- mInfo->frameTop = 0;
- mInfo->frameRight = WIDTH;
- mInfo->frameBottom = HEIGHT;
- mInfo->scaleFactor = 1.0;
- mInfo->addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
- mInfo->visible = true;
- mInfo->canReceiveKeys = true;
- mInfo->hasFocus = mFocused;
- mInfo->hasWallpaper = false;
- mInfo->paused = false;
- mInfo->layer = 0;
- mInfo->ownerPid = INJECTOR_PID;
- mInfo->ownerUid = INJECTOR_UID;
- mInfo->inputFeatures = 0;
- mInfo->displayId = mDisplayId;
+ mInfo.inputChannel = mServerChannel;
+ mInfo.name = mName;
+ mInfo.layoutParamsFlags = 0;
+ mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
+ mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
+ mInfo.frameLeft = 0;
+ mInfo.frameTop = 0;
+ mInfo.frameRight = WIDTH;
+ mInfo.frameBottom = HEIGHT;
+ mInfo.scaleFactor = 1.0;
+ mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
+ mInfo.visible = true;
+ mInfo.canReceiveKeys = true;
+ mInfo.hasFocus = mFocused;
+ mInfo.hasWallpaper = false;
+ mInfo.paused = false;
+ mInfo.layer = 0;
+ mInfo.ownerPid = INJECTOR_PID;
+ mInfo.ownerUid = INJECTOR_UID;
+ mInfo.inputFeatures = 0;
+ mInfo.displayId = mDisplayId;
return true;
}
@@ -529,6 +526,34 @@
windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
}
+TEST_F(InputDispatcherTest, SetInputWindow_InputWindowInfo) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+
+ sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
+ ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
+ ADISPLAY_ID_DEFAULT);
+
+ windowTop->setFocus();
+
+ Vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.add(windowTop);
+ inputWindowHandles.add(windowSecond);
+
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+
+ // Release channel for window is no longer valid.
+ windowTop->releaseChannel();
+
+ // Test inject a motion down, should timeout because of no target channel.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
+
+ // Top window is invalid, so it should not receive any input event.
+ windowTop->assertNoEvents();
+ windowSecond->assertNoEvents();
+}
+
/* Test InputDispatcher for MultiDisplay */
class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
public:
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index e8092a9..f168db9 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -146,6 +146,7 @@
"SurfaceInterceptor.cpp",
"SurfaceTracing.cpp",
"TimeStats/TimeStats.cpp",
+ "TransactionCompletedThread.cpp",
],
}
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 641bd8d..ade62bf 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -231,15 +231,12 @@
void BufferLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
const Rect& viewport, int32_t supportedPerFrameMetadata) {
+ RETURN_IF_NO_HWC_LAYER(displayId);
+
// Apply this display's projection's viewport to the visible region
// before giving it to the HWC HAL.
Region visible = transform.transform(visibleRegion.intersect(viewport));
- if (!hasHwcLayer(displayId)) {
- ALOGE("[%s] failed to setPerFrameData: no HWC layer found for display %" PRIu64,
- mName.string(), displayId);
- return;
- }
auto& hwcInfo = getBE().mHwcLayers[displayId];
auto& hwcLayer = hwcInfo.layer;
auto error = hwcLayer->setVisibleRegion(visible);
@@ -520,7 +517,7 @@
}
bool BufferLayer::hasReadyFrame() const {
- return hasDrawingBuffer() || getSidebandStreamChanged() || getAutoRefresh();
+ return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh();
}
uint32_t BufferLayer::getEffectiveScalingMode() const {
@@ -658,13 +655,43 @@
}
uint64_t BufferLayer::getHeadFrameNumber() const {
- if (hasDrawingBuffer()) {
+ if (hasFrameUpdate()) {
return getFrameNumber();
} else {
return mCurrentFrameNumber;
}
}
+Rect BufferLayer::getBufferSize(const State& s) const {
+ // If we have a sideband stream, or we are scaling the buffer then return the layer size since
+ // we cannot determine the buffer size.
+ if ((s.sidebandStream != nullptr) ||
+ (getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE)) {
+ return Rect(getActiveWidth(s), getActiveHeight(s));
+ }
+
+ if (mActiveBuffer == nullptr) {
+ return Rect::INVALID_RECT;
+ }
+
+ uint32_t bufWidth = mActiveBuffer->getWidth();
+ uint32_t bufHeight = mActiveBuffer->getHeight();
+
+ // Undo any transformations on the buffer and return the result.
+ if (mCurrentTransform & ui::Transform::ROT_90) {
+ std::swap(bufWidth, bufHeight);
+ }
+
+ if (getTransformToDisplayInverse()) {
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+ if (invTransform & ui::Transform::ROT_90) {
+ std::swap(bufWidth, bufHeight);
+ }
+ }
+
+ return Rect(bufWidth, bufHeight);
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index b3ea7e6..690a4e5 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -136,7 +136,7 @@
virtual std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) = 0;
- virtual bool hasDrawingBuffer() const = 0;
+ virtual bool hasFrameUpdate() const = 0;
virtual void setFilteringEnabled(bool enabled) = 0;
@@ -188,6 +188,8 @@
mutable renderengine::Texture mTexture;
bool mRefreshPending{false};
+
+ Rect getBufferSize(const State& s) const override;
};
} // namespace android
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e10548f..78ab23a 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -82,7 +82,7 @@
return true;
}
- if (!hasDrawingBuffer()) {
+ if (!hasFrameUpdate()) {
return false;
}
@@ -110,7 +110,7 @@
return true;
}
- if (!hasDrawingBuffer()) {
+ if (!hasFrameUpdate()) {
return true;
}
@@ -206,7 +206,7 @@
return {};
}
-bool BufferQueueLayer::hasDrawingBuffer() const {
+bool BufferQueueLayer::hasFrameUpdate() const {
return mQueuedFrames > 0;
}
@@ -352,6 +352,11 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
+ // Report the timestamp to the Scheduler.
+ if (mFlinger->mUseScheduler) {
+ mFlinger->mScheduler->addNewFrameTimestamp(item.mTimestamp, item.mIsAutoTimestamp);
+ }
+
Mutex::Autolock lock(mQueueItemLock);
// Reset the frame number tracker when we receive the first buffer after
// a frame number reset
@@ -402,7 +407,7 @@
}
}
- if (!hasDrawingBuffer()) {
+ if (!hasFrameUpdate()) {
ALOGE("Can't replace a frame on an empty queue");
return;
}
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 74dd21e..ae0b705 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -83,7 +83,7 @@
std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
- bool hasDrawingBuffer() const override;
+ bool hasFrameUpdate() const override;
void setFilteringEnabled(bool enabled) override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 8d59841..425f5c7 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -35,15 +35,19 @@
};
// clang-format on
-BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) : BufferLayer(args) {}
+BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) : BufferLayer(args) {
+ mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
+}
BufferStateLayer::~BufferStateLayer() = default;
// -----------------------------------------------------------------------
// Interface implementation for Layer
// -----------------------------------------------------------------------
-void BufferStateLayer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {
- // TODO(marissaw): send the release fence back to buffer owner
- return;
+void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+ // The transaction completed callback can only be sent if the release fence from the PREVIOUS
+ // frame has fired. In practice, we should never actually wait on the previous release fence
+ // but we should store it just in case.
+ mPreviousReleaseFence = releaseFence;
}
void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
@@ -52,7 +56,6 @@
}
void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
- // TODO(marissaw): use this to signal the buffer owner
return;
}
@@ -61,7 +64,13 @@
return true;
}
- return hasDrawingBuffer();
+ return hasFrameUpdate();
+}
+
+bool BufferStateLayer::willPresentCurrentTransaction() const {
+ // Returns true if the most recent Transaction applied to CurrentState will be presented.
+ return getSidebandStreamChanged() || getAutoRefresh() ||
+ (mCurrentState.modified && mCurrentState.buffer != nullptr);
}
bool BufferStateLayer::getTransformToDisplayInverse() const {
@@ -81,6 +90,7 @@
while (!mPendingStates.empty()) {
popPendingState(stateToCommit);
}
+ mCurrentStateModified = stateUpdateAvailable && mCurrentState.modified;
mCurrentState.modified = false;
return stateUpdateAvailable;
}
@@ -118,7 +128,11 @@
return true;
}
-bool BufferStateLayer::setBuffer(sp<GraphicBuffer> buffer) {
+bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer) {
+ if (mCurrentState.buffer) {
+ mReleasePreviousBuffer = true;
+ }
+
mCurrentState.sequence++;
mCurrentState.buffer = buffer;
mCurrentState.modified = true;
@@ -127,6 +141,9 @@
}
bool BufferStateLayer::setAcquireFence(const sp<Fence>& fence) {
+ // The acquire fences of BufferStateLayers have already signaled before they are set
+ mCallbackHandleAcquireTime = fence->getSignalTime();
+
mCurrentState.acquireFence = fence;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -182,6 +199,44 @@
return true;
}
+bool BufferStateLayer::setTransactionCompletedListeners(
+ const std::vector<sp<CallbackHandle>>& handles) {
+ // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return
+ if (handles.empty()) {
+ mReleasePreviousBuffer = false;
+ return false;
+ }
+
+ const bool willPresent = willPresentCurrentTransaction();
+
+ for (const auto& handle : handles) {
+ // If this transaction set a buffer on this layer, release its previous buffer
+ handle->releasePreviousBuffer = mReleasePreviousBuffer;
+
+ // If this layer will be presented in this frame
+ if (willPresent) {
+ // If this transaction set an acquire fence on this layer, set its acquire time
+ handle->acquireTime = mCallbackHandleAcquireTime;
+
+ // Notify the transaction completed thread that there is a pending latched callback
+ // handle
+ mFlinger->getTransactionCompletedThread().registerPendingLatchedCallbackHandle(handle);
+
+ // Store so latched time and release fence can be set
+ mCurrentState.callbackHandles.push_back(handle);
+
+ } else { // If this layer will NOT need to be relatched and presented this frame
+ // Notify the transaction completed thread this handle is done
+ mFlinger->getTransactionCompletedThread().addUnlatchedCallbackHandle(handle);
+ }
+ }
+
+ mReleasePreviousBuffer = false;
+ mCallbackHandleAcquireTime = -1;
+
+ return willPresent;
+}
+
bool BufferStateLayer::setSize(uint32_t w, uint32_t h) {
if (mCurrentState.active.w == w && mCurrentState.active.h == h) return false;
mCurrentState.active.w = w;
@@ -265,7 +320,7 @@
}
uint32_t BufferStateLayer::getDrawingScalingMode() const {
- return NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
}
Region BufferStateLayer::getDrawingSurfaceDamage() const {
@@ -314,8 +369,8 @@
return {};
}
-bool BufferStateLayer::hasDrawingBuffer() const {
- return getDrawingState().buffer != nullptr;
+bool BufferStateLayer::hasFrameUpdate() const {
+ return mCurrentStateModified && getCurrentState().buffer != nullptr;
}
void BufferStateLayer::setFilteringEnabled(bool enabled) {
@@ -394,7 +449,7 @@
}
}
- if (mOverrideScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE &&
+ if (getEffectiveScalingMode() == NATIVE_WINDOW_SCALING_MODE_FREEZE &&
(s.active.w != bufferWidth || s.active.h != bufferHeight)) {
ALOGE("[%s] rejecting buffer: "
"bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
@@ -403,6 +458,10 @@
return BAD_VALUE;
}
+ mFlinger->getTransactionCompletedThread()
+ .addLatchedCallbackHandles(getDrawingState().callbackHandles, latchTime,
+ mPreviousReleaseFence);
+
// Handle sync fences
if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
// TODO(alecmouri): Fail somewhere upstream if the fence is invalid.
@@ -512,6 +571,7 @@
s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
}
+ mCurrentStateModified = false;
mFrameNumber++;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 381cd28..315d5af 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -62,13 +62,14 @@
bool setTransform(uint32_t transform) override;
bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
bool setCrop(const Rect& crop) override;
- bool setBuffer(sp<GraphicBuffer> buffer) override;
+ bool setBuffer(const sp<GraphicBuffer>& buffer) override;
bool setAcquireFence(const sp<Fence>& fence) override;
bool setDataspace(ui::Dataspace dataspace) override;
bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
bool setSurfaceDamageRegion(const Region& surfaceDamage) override;
bool setApi(int32_t api) override;
bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
+ bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
bool setSize(uint32_t w, uint32_t h) override;
bool setPosition(float x, float y, bool immediate) override;
@@ -110,7 +111,7 @@
std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
- bool hasDrawingBuffer() const override;
+ bool hasFrameUpdate() const override;
void setFilteringEnabled(bool enabled) override;
@@ -125,6 +126,7 @@
private:
void onFirstRef() override;
+ bool willPresentCurrentTransaction() const;
static const std::array<float, 16> IDENTITY_MATRIX;
@@ -136,6 +138,12 @@
uint32_t mFrameNumber{0};
+ sp<Fence> mPreviousReleaseFence;
+
+ bool mCurrentStateModified = false;
+ bool mReleasePreviousBuffer = false;
+ nsecs_t mCallbackHandleAcquireTime = -1;
+
// TODO(marissaw): support sticky transform for LEGACY camera mode
};
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index ad716ef..9c34308 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -59,13 +59,10 @@
void ColorLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
const Rect& viewport, int32_t /* supportedPerFrameMetadata */) {
+ RETURN_IF_NO_HWC_LAYER(displayId);
+
Region visible = transform.transform(visibleRegion.intersect(viewport));
- if (!hasHwcLayer(displayId)) {
- ALOGE("[%s] failed to setPerFrameData: no HWC layer found for display %" PRIu64,
- mName.string(), displayId);
- return;
- }
auto& hwcInfo = getBE().mHwcLayers[displayId];
auto& hwcLayer = hwcInfo.layer;
auto error = hwcLayer->setVisibleRegion(visible);
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index be19b9f..5342bcf 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -642,7 +642,7 @@
}
std::string DisplayDevice::getDebugName() const {
- const auto id = mId ? base::StringPrintf("%" PRIu64 ", ", *mId) : std::string();
+ const auto id = mId ? to_string(*mId) + ", " : std::string();
return base::StringPrintf("DisplayDevice{%s%s%s\"%s\"}", id.c_str(),
isPrimary() ? "primary, " : "", isVirtual() ? "virtual, " : "",
mDisplayName.c_str());
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index ec240f3..ba7818d 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -64,12 +64,16 @@
return letter < 'A' || letter > 'Z' ? '\0' : letter;
}
-DisplayId getEdidDisplayId(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash) {
- return (static_cast<DisplayId>(manufacturerId) << 40) |
- (static_cast<DisplayId>(displayNameHash) << 8) | port;
+} // namespace
+
+uint16_t DisplayId::manufacturerId() const {
+ return static_cast<uint16_t>(value >> 40);
}
-} // namespace
+DisplayId DisplayId::fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash) {
+ return {(static_cast<Type>(manufacturerId) << 40) | (static_cast<Type>(displayNameHash) << 8) |
+ port};
+}
bool isEdid(const DisplayIdentificationData& data) {
const uint8_t kMagic[] = {0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0};
@@ -168,6 +172,10 @@
return a && b && c ? std::make_optional(PnpId{a, b, c}) : std::nullopt;
}
+std::optional<PnpId> getPnpId(DisplayId displayId) {
+ return getPnpId(displayId.manufacturerId());
+}
+
std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData(
uint8_t port, const DisplayIdentificationData& data) {
if (!isEdid(data)) {
@@ -183,16 +191,16 @@
// Hash display name instead of using product code or serial number, since the latter have been
// observed to change on some displays with multiple inputs.
const auto hash = static_cast<uint32_t>(std::hash<std::string_view>()(edid->displayName));
- return DisplayIdentificationInfo{getEdidDisplayId(port, edid->manufacturerId, hash),
+ return DisplayIdentificationInfo{DisplayId::fromEdid(port, edid->manufacturerId, hash),
std::string(edid->displayName)};
}
DisplayId getFallbackDisplayId(uint8_t port) {
- return getEdidDisplayId(port, kFallbackEdidManufacturerId, 0);
+ return DisplayId::fromEdid(port, kFallbackEdidManufacturerId, 0);
}
DisplayId getVirtualDisplayId(uint32_t id) {
- return getEdidDisplayId(0, kVirtualEdidManufacturerId, id);
+ return DisplayId::fromEdid(0, kVirtualEdidManufacturerId, id);
}
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
index 1f2e789..1599995 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -25,7 +25,27 @@
namespace android {
-using DisplayId = uint64_t;
+struct DisplayId {
+ using Type = uint64_t;
+ Type value;
+
+ uint16_t manufacturerId() const;
+
+ static DisplayId fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash);
+};
+
+inline bool operator==(DisplayId lhs, DisplayId rhs) {
+ return lhs.value == rhs.value;
+}
+
+inline bool operator!=(DisplayId lhs, DisplayId rhs) {
+ return !(lhs == rhs);
+}
+
+inline std::string to_string(DisplayId displayId) {
+ return std::to_string(displayId.value);
+}
+
using DisplayIdentificationData = std::vector<uint8_t>;
struct DisplayIdentificationInfo {
@@ -45,6 +65,7 @@
bool isEdid(const DisplayIdentificationData&);
std::optional<Edid> parseEdid(const DisplayIdentificationData&);
std::optional<PnpId> getPnpId(uint16_t manufacturerId);
+std::optional<PnpId> getPnpId(DisplayId);
std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData(
uint8_t port, const DisplayIdentificationData&);
@@ -53,3 +74,14 @@
DisplayId getVirtualDisplayId(uint32_t id);
} // namespace android
+
+namespace std {
+
+template <>
+struct hash<android::DisplayId> {
+ size_t operator()(android::DisplayId displayId) const {
+ return hash<android::DisplayId::Type>()(displayId.value);
+ }
+};
+
+} // namespace std
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index f3f8d9d..27812f7 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -63,7 +63,7 @@
mHasPendingRelease(false),
mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
mPreviousBuffer() {
- ALOGV("Creating for display %" PRIu64, displayId);
+ ALOGV("Creating for display %s", to_string(displayId).c_str());
mName = "FramebufferSurface";
mConsumer->setConsumerName(mName);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 4c472b8..0f25b52 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -58,11 +58,11 @@
ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg)
#define LOG_DISPLAY_ERROR(displayId, msg) \
- ALOGE("%s failed for display %" PRIu64 ": %s", __FUNCTION__, displayId, msg)
+ ALOGE("%s failed for display %s: %s", __FUNCTION__, to_string(displayId).c_str(), msg)
-#define LOG_HWC_ERROR(what, error, displayId) \
- ALOGE("%s: %s failed for display %" PRIu64 ": %s (%d)", __FUNCTION__, what, displayId, \
- to_string(error).c_str(), static_cast<int32_t>(error))
+#define LOG_HWC_ERROR(what, error, displayId) \
+ ALOGE("%s: %s failed for display %s: %s (%d)", __FUNCTION__, what, \
+ to_string(displayId).c_str(), to_string(error).c_str(), static_cast<int32_t>(error))
#define RETURN_IF_INVALID_DISPLAY(displayId, ...) \
do { \
@@ -159,9 +159,9 @@
if (!info) return {};
}
- ALOGV("%s: %s %s display %" PRIu64 " with HWC ID %" PRIu64, __FUNCTION__,
- to_string(connection).c_str(),
- hwcDisplayId == mInternalHwcDisplayId ? "internal" : "external", info->id, hwcDisplayId);
+ ALOGV("%s: %s %s display %s with HWC ID %" PRIu64, __FUNCTION__, to_string(connection).c_str(),
+ hwcDisplayId == mInternalHwcDisplayId ? "internal" : "external",
+ to_string(info->id).c_str(), hwcDisplayId);
mHwcDevice->onHotplug(hwcDisplayId, connection);
@@ -198,15 +198,15 @@
// is a bug in the HWC implementation, but filter the extra events
// out here so they don't cause havoc downstream.
if (timestamp == mLastHwVSync[*displayId]) {
- ALOGW("Ignoring duplicate VSYNC event from HWC for display %" PRIu64 " (t=%" PRId64 ")",
- *displayId, timestamp);
+ ALOGW("Ignoring duplicate VSYNC event from HWC for display %s (t=%" PRId64 ")",
+ to_string(*displayId).c_str(), timestamp);
return false;
}
mLastHwVSync[*displayId] = timestamp;
}
- const auto tag = "HW_VSYNC_" + std::to_string(*displayId);
+ const auto tag = "HW_VSYNC_" + to_string(*displayId);
ATRACE_INT(tag.c_str(), ++mVSyncCounts[*displayId] & 1);
return true;
@@ -383,7 +383,7 @@
displayData.vsyncEnabled = enabled;
- const auto tag = "HW_VSYNC_ON_" + std::to_string(displayId);
+ const auto tag = "HW_VSYNC_ON_" + to_string(displayId);
ATRACE_INT(tag.c_str(), enabled == HWC2::Vsync::Enable ? 1 : 0);
}
}
@@ -393,7 +393,7 @@
ui::Dataspace dataspace) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
- ALOGV("setClientTarget for display %" PRIu64, displayId);
+ ALOGV("%s for display %s", __FUNCTION__, to_string(displayId).c_str());
auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
auto error = hwcDisplay->setClientTarget(slot, target, acquireFence, dataspace);
RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 5074c2c..b78433d 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -233,7 +233,7 @@
cb_context* mCBContext = nullptr;
std::unordered_map<DisplayId, size_t> mVSyncCounts;
- std::unordered_set<uint32_t> mFreeVirtualDisplayIds;
+ std::unordered_set<DisplayId> mFreeVirtualDisplayIds;
uint32_t mNextVirtualDisplayId = 0;
uint32_t mRemainingHwcVirtualDisplays{mHwcDevice->getMaxVirtualDisplayCount()};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f41a753..038bc58 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -197,8 +197,8 @@
// ---------------------------------------------------------------------------
bool Layer::createHwcLayer(HWComposer* hwc, DisplayId displayId) {
- LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(displayId) != 0,
- "Already have a layer for display %" PRIu64, displayId);
+ LOG_ALWAYS_FATAL_IF(hasHwcLayer(displayId), "Already have a layer for display %s",
+ to_string(displayId).c_str());
auto layer = std::shared_ptr<HWC2::Layer>(
hwc->createLayer(displayId),
[hwc, displayId](HWC2::Layer* layer) {
@@ -215,7 +215,7 @@
}
bool Layer::destroyHwcLayer(DisplayId displayId) {
- if (getBE().mHwcLayers.count(displayId) == 0) {
+ if (!hasHwcLayer(displayId)) {
return false;
}
auto& hwcInfo = getBE().mHwcLayers[displayId];
@@ -275,39 +275,12 @@
return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
}
-Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
- const State& s(getDrawingState());
- Rect win(getActiveWidth(s), getActiveHeight(s));
-
- Rect crop = getCrop(s);
- if (!crop.isEmpty()) {
- win.intersect(crop, &win);
- }
-
+Rect Layer::computeScreenBounds() const {
+ FloatRect bounds = computeBounds();
ui::Transform t = getTransform();
- win = t.transform(win);
-
- const sp<Layer>& p = mDrawingParent.promote();
- // Now we need to calculate the parent bounds, so we can clip ourselves to those.
- // When calculating the parent bounds for purposes of clipping,
- // we don't need to constrain the parent to its transparent region.
- // The transparent region is an optimization based on the
- // buffer contents of the layer, but does not affect the space allocated to
- // it by policy, and thus children should be allowed to extend into the
- // parent's transparent region. In fact one of the main uses, is to reduce
- // buffer allocation size in cases where a child window sits behind a main window
- // (by marking the hole in the parent window as a transparent region)
- if (p != nullptr) {
- Rect bounds = p->computeScreenBounds(false);
- bounds.intersect(win, &win);
- }
-
- if (reduceTransparentRegion) {
- auto const screenTransparentRegion = t.transform(getActiveTransparentRegion(s));
- win = reduce(win, screenTransparentRegion);
- }
-
- return win;
+ // Transform to screen space.
+ bounds = t.transform(bounds);
+ return Rect{bounds};
}
FloatRect Layer::computeBounds() const {
@@ -317,32 +290,72 @@
FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const {
const State& s(getDrawingState());
- Rect win(getActiveWidth(s), getActiveHeight(s));
+ Rect bounds = getCroppedBufferSize(s);
+ FloatRect floatBounds = bounds.toFloatRect();
+ if (bounds.isValid()) {
+ // Layer has bounds. Pass in our bounds as a special case. Then pass on to our parents so
+ // that they can clip it.
+ floatBounds = cropChildBounds(floatBounds);
+ } else {
+ // Layer does not have bounds, so we fill to our parent bounds. This is done by getting our
+ // parent bounds and inverting the transform to get the maximum bounds we can have that
+ // will fit within our parent bounds.
+ const auto& p = mDrawingParent.promote();
+ if (p != nullptr) {
+ ui::Transform t = s.active_legacy.transform;
+ // When calculating the parent bounds for purposes of clipping, we don't need to
+ // constrain the parent to its transparent region. The transparent region is an
+ // optimization based on the buffer contents of the layer, but does not affect the
+ // space allocated to it by policy, and thus children should be allowed to extend into
+ // the parent's transparent region.
+ // One of the main uses is a parent window with a child sitting behind the parent
+ // window, marked by a transparent region. When computing the parent bounds from the
+ // parent's perspective we pass in the transparent region to reduce buffer allocation
+ // size. When computing the parent bounds from the child's perspective, we pass in an
+ // empty transparent region in order to extend into the the parent bounds.
+ floatBounds = p->computeBounds(Region());
+ // Transform back to layer space.
+ floatBounds = t.inverse().transform(floatBounds);
+ }
+ }
- Rect crop = getCrop(s);
- if (!crop.isEmpty()) {
- win.intersect(crop, &win);
+ // Subtract the transparent region and snap to the bounds.
+ return reduce(floatBounds, activeTransparentRegion);
+}
+
+FloatRect Layer::cropChildBounds(const FloatRect& childBounds) const {
+ const State& s(getDrawingState());
+ Rect bounds = getCroppedBufferSize(s);
+ FloatRect croppedBounds = childBounds;
+
+ // If the layer has bounds, then crop the passed in child bounds and pass
+ // it to our parents so they can crop it as well. If the layer has no bounds,
+ // then pass on the child bounds.
+ if (bounds.isValid()) {
+ croppedBounds = croppedBounds.intersect(bounds.toFloatRect());
}
const auto& p = mDrawingParent.promote();
- FloatRect floatWin = win.toFloatRect();
- FloatRect parentBounds = floatWin;
if (p != nullptr) {
- // We pass an empty Region here for reasons mirroring that of the case described in
- // the computeScreenBounds reduceTransparentRegion=false case.
- parentBounds = p->computeBounds(Region());
+ // Transform to parent space and allow parent layer to crop the
+ // child bounds as well.
+ ui::Transform t = s.active_legacy.transform;
+ croppedBounds = t.transform(croppedBounds);
+ croppedBounds = p->cropChildBounds(croppedBounds);
+ croppedBounds = t.inverse().transform(croppedBounds);
}
+ return croppedBounds;
+}
- ui::Transform t = s.active_legacy.transform;
-
- if (p != nullptr) {
- floatWin = t.transform(floatWin);
- floatWin = floatWin.intersect(parentBounds);
- floatWin = t.inverse().transform(floatWin);
+Rect Layer::getCroppedBufferSize(const State& s) const {
+ Rect size = getBufferSize(s);
+ Rect crop = getCrop(s);
+ if (!crop.isEmpty() && size.isValid()) {
+ size.intersect(crop, &size);
+ } else if (!crop.isEmpty()) {
+ size = crop;
}
-
- // subtract the transparent region and snap to the bounds
- return reduce(floatWin, activeTransparentRegion);
+ return size;
}
Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& display) const {
@@ -462,11 +475,7 @@
void Layer::setGeometry(const sp<const DisplayDevice>& display, uint32_t z) {
const auto displayId = display->getId();
LOG_ALWAYS_FATAL_IF(!displayId);
- if (!hasHwcLayer(*displayId)) {
- ALOGE("[%s] failed to setGeometry: no HWC layer found for display %" PRIu64, mName.string(),
- *displayId);
- return;
- }
+ RETURN_IF_NO_HWC_LAYER(*displayId);
auto& hwcInfo = getBE().mHwcLayers[*displayId];
// enable this layer
@@ -634,27 +643,19 @@
}
void Layer::forceClientComposition(DisplayId displayId) {
- if (getBE().mHwcLayers.count(displayId) == 0) {
- ALOGE("forceClientComposition: no HWC layer found (display %" PRIu64 ")", displayId);
- return;
- }
-
+ RETURN_IF_NO_HWC_LAYER(displayId);
getBE().mHwcLayers[displayId].forceClientComposition = true;
}
bool Layer::getForceClientComposition(DisplayId displayId) {
- if (getBE().mHwcLayers.count(displayId) == 0) {
- ALOGE("getForceClientComposition: no HWC layer found (display %" PRIu64 ")", displayId);
- return false;
- }
-
+ RETURN_IF_NO_HWC_LAYER(displayId, false);
return getBE().mHwcLayers[displayId].forceClientComposition;
}
void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
const auto displayId = display->getId();
- if (getBE().mHwcLayers.count(*displayId) == 0 ||
- getCompositionType(displayId) != HWC2::Composition::Cursor) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ if (!hasHwcLayer(*displayId) || getCompositionType(displayId) != HWC2::Composition::Cursor) {
return;
}
@@ -1054,6 +1055,7 @@
// Commit the transaction
commitTransaction(c);
+ mCurrentState.callbackHandles = {};
return flags;
}
@@ -1422,7 +1424,7 @@
}
void Layer::miniDump(String8& result, DisplayId displayId) const {
- if (getBE().mHwcLayers.count(displayId) == 0) {
+ if (!hasHwcLayer(displayId)) {
return;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ced6532..40ebe1e 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -48,6 +48,7 @@
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
#include "TimeStats/TimeStats.h"
+#include "TransactionCompletedThread.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/HWComposerBufferCache.h"
@@ -184,6 +185,10 @@
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
bool hasColorTransform;
+
+ // The deque of callback handles for this frame. The back of the deque contains the most
+ // recent callback handle.
+ std::deque<sp<CallbackHandle>> callbackHandles;
};
explicit Layer(const LayerCreationArgs& args);
@@ -266,13 +271,17 @@
virtual bool setTransform(uint32_t /*transform*/) { return false; };
virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
virtual bool setCrop(const Rect& /*crop*/) { return false; };
- virtual bool setBuffer(sp<GraphicBuffer> /*buffer*/) { return false; };
+ virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/) { return false; };
virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; };
virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; };
virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; };
virtual bool setApi(int32_t /*api*/) { return false; };
virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
+ virtual bool setTransactionCompletedListeners(
+ const std::vector<sp<CallbackHandle>>& /*handles*/) {
+ return false;
+ };
ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
@@ -499,7 +508,7 @@
bool destroyHwcLayer(DisplayId displayId);
void destroyAllHwcLayers();
- bool hasHwcLayer(DisplayId displayId) { return getBE().mHwcLayers.count(displayId) > 0; }
+ bool hasHwcLayer(DisplayId displayId) const { return getBE().mHwcLayers.count(displayId) > 0; }
HWC2::Layer* getHwcLayer(DisplayId displayId) {
if (!hasHwcLayer(displayId)) {
@@ -570,7 +579,7 @@
ssize_t removeChild(const sp<Layer>& layer);
sp<Layer> getParent() const { return mCurrentParent.promote(); }
bool hasParent() const { return getParent() != nullptr; }
- Rect computeScreenBounds(bool reduceTransparentRegion = true) const;
+ Rect computeScreenBounds() const;
bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
bool setChildRelativeLayer(const sp<Layer>& childLayer,
const sp<IBinder>& relativeToHandle, int32_t relativeZ);
@@ -782,10 +791,38 @@
const LayerVector::Visitor& visitor);
LayerVector makeChildrenTraversalList(LayerVector::StateSet stateSet,
const std::vector<Layer*>& layersInTree);
+
+ /**
+ * Retuns the child bounds in layer space cropped to its bounds as well all its parent bounds.
+ * The cropped bounds must be transformed back from parent layer space to child layer space by
+ * applying the inverse of the child's transformation.
+ */
+ FloatRect cropChildBounds(const FloatRect& childBounds) const;
+
+ /**
+ * Returns the cropped buffer size or the layer crop if the layer has no buffer. Return
+ * INVALID_RECT if the layer has no buffer and no crop.
+ * A layer with an invalid buffer size and no crop is considered to be boundless. The layer
+ * bounds are constrained by its parent bounds.
+ */
+ Rect getCroppedBufferSize(const Layer::State& s) const;
+
+ /**
+ * Returns active buffer size in the correct orientation. Buffer size is determined by undoing
+ * any buffer transformations. If the layer has no buffer then return INVALID_RECT.
+ */
+ virtual Rect getBufferSize(const Layer::State&) const { return Rect::INVALID_RECT; }
};
-// ---------------------------------------------------------------------------
+} // namespace android
-}; // namespace android
+#define RETURN_IF_NO_HWC_LAYER(displayId, ...) \
+ do { \
+ if (!hasHwcLayer(displayId)) { \
+ ALOGE("[%s] %s failed: no HWC layer found for display %s", mName.string(), \
+ __FUNCTION__, to_string(displayId).c_str()); \
+ return __VA_ARGS__; \
+ } \
+ } while (false)
#endif // ANDROID_LAYER_H
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 18a8bb1..4286cc9 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -14,11 +14,14 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "Scheduler.h"
#include <cinttypes>
#include <cstdint>
#include <memory>
+#include <numeric>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
@@ -27,6 +30,7 @@
#include <gui/ISurfaceComposer.h>
#include <ui/DisplayStatInfo.h>
+#include <utils/Trace.h>
#include "DispSync.h"
#include "DispSyncSource.h"
@@ -196,4 +200,58 @@
mPrimaryDispSync->setIgnorePresentFences(ignore);
}
+void Scheduler::makeHWSyncAvailable(bool makeAvailable) {
+ std::lock_guard<std::mutex> lock(mHWVsyncLock);
+ mHWVsyncAvailable = makeAvailable;
+}
+
+void Scheduler::addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp) {
+ ATRACE_INT("AutoTimestamp", isAutoTimestamp);
+ // Video does not have timestamp automatically set, so we discard timestamps that are
+ // coming in from other sources for now.
+ if (isAutoTimestamp) {
+ return;
+ }
+ int64_t differenceMs = (newFrameTimestamp - mPreviousFrameTimestamp) / 1000000;
+ mPreviousFrameTimestamp = newFrameTimestamp;
+
+ if (differenceMs < 10 || differenceMs > 100) {
+ // Dismiss noise.
+ return;
+ }
+ ATRACE_INT("TimestampDiff", differenceMs);
+
+ mTimeDifferences[mCounter % ARRAY_SIZE] = differenceMs;
+ mCounter++;
+ nsecs_t average = calculateAverage();
+ ATRACE_INT("TimestampAverage", average);
+
+ // TODO(b/113612090): This are current numbers from trial and error while running videos
+ // from YouTube at 24, 30, and 60 fps.
+ if (average > 14 && average < 18) {
+ ATRACE_INT("FPS", 60);
+ } else if (average > 31 && average < 34) {
+ ATRACE_INT("FPS", 30);
+ updateFrameSkipping(1);
+ return;
+ } else if (average > 39 && average < 42) {
+ ATRACE_INT("FPS", 24);
+ }
+ updateFrameSkipping(0);
+}
+
+nsecs_t Scheduler::calculateAverage() const {
+ nsecs_t sum = std::accumulate(mTimeDifferences.begin(), mTimeDifferences.end(), 0);
+ return (sum / ARRAY_SIZE);
+}
+
+void Scheduler::updateFrameSkipping(const int64_t skipCount) {
+ ATRACE_INT("FrameSkipCount", skipCount);
+ if (mSkipCount != skipCount) {
+ // Only update DispSync if it hasn't been updated yet.
+ mPrimaryDispSync->setRefreshSkipCount(skipCount);
+ mSkipCount = skipCount;
+ }
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index fdafe58..dd1f24b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -102,6 +102,8 @@
void addResyncSample(const nsecs_t timestamp);
void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
void setIgnorePresentFences(bool ignore);
+ void makeHWSyncAvailable(bool makeAvailable);
+ void addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp);
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
@@ -110,6 +112,9 @@
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
+ nsecs_t calculateAverage() const;
+ void updateFrameSkipping(const int64_t skipCount);
+
// TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it
// should make request to Scheduler to compute next refresh.
friend class BufferQueueLayer;
@@ -133,6 +138,18 @@
std::unique_ptr<DispSync> mPrimaryDispSync;
std::unique_ptr<EventControlThread> mEventControlThread;
+
+ // TODO(b/113612090): The following set of variables needs to be revised. For now, this is
+ // a proof of concept. We turn on frame skipping if the difference between the timestamps
+ // is between 32 and 34ms. We expect this currently for 30fps videos, so we render them at 30Hz.
+ nsecs_t mPreviousFrameTimestamp = 0;
+ // Keeping track of whether we are skipping the refresh count. If we want to
+ // simulate 30Hz rendering, we skip every other frame, and this variable is set
+ // to 1.
+ int64_t mSkipCount = 0;
+ static constexpr size_t ARRAY_SIZE = 30;
+ std::array<int64_t, ARRAY_SIZE> mTimeDifferences;
+ size_t mCounter = 0;
};
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9d16958..25c60fe 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1043,9 +1043,9 @@
LOG_ALWAYS_FATAL_IF(!displayId);
getHwComposer().setActiveColorMode(*displayId, mode, renderIntent);
- ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), display=%" PRIu64,
+ ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), display=%s",
decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
- renderIntent, *displayId);
+ renderIntent, to_string(*displayId).c_str());
}
status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
@@ -1255,6 +1255,10 @@
if (makeAvailable) {
mHWVsyncAvailable = true;
+ // TODO(b/113612090): This is silly, but necessary evil until we turn on the flag for good.
+ if (mUseScheduler) {
+ mScheduler->makeHWSyncAvailable(true);
+ }
} else if (!mHWVsyncAvailable) {
// Hardware vsync is not currently available, so abort the resync
// attempt for now
@@ -1636,8 +1640,8 @@
display->setColorTransform(mDrawingState.colorMatrix);
status_t result =
getHwComposer().setColorTransform(*displayId, mDrawingState.colorMatrix);
- ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display %" PRIu64 ": %d",
- *displayId, result);
+ ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display %s: %d",
+ to_string(*displayId).c_str(), result);
}
for (auto& layer : display->getVisibleLayersSortedByZ()) {
if (layer->isHdrY410()) {
@@ -1955,6 +1959,9 @@
ATRACE_INT("TexturePoolSize", mTexturePool.size());
}
}
+
+ mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
+ mTransactionCompletedThread.sendCallbacks();
}
void SurfaceFlinger::rebuildLayerStacks() {
@@ -2271,7 +2278,7 @@
if (event.connection == HWC2::Connection::Connected) {
if (!mPhysicalDisplayTokens.count(info->id)) {
- ALOGV("Creating display %" PRIu64, info->id);
+ ALOGV("Creating display %s", to_string(info->id).c_str());
mPhysicalDisplayTokens[info->id] = new BBinder();
DisplayDeviceState state;
state.displayId = info->id;
@@ -2281,7 +2288,7 @@
mInterceptor->saveDisplayCreation(state);
}
} else {
- ALOGV("Removing display %" PRIu64, info->id);
+ ALOGV("Removing display %s", to_string(info->id).c_str());
ssize_t index = mCurrentState.displays.indexOfKey(mPhysicalDisplayTokens[info->id]);
if (index >= 0) {
@@ -2724,7 +2731,11 @@
// abandon the buffer queue.
if (l->isRemovedFromCurrentState()) {
l->destroyAllHwcLayers();
- l->releasePendingBuffer(systemTime());
+ // destroyAllHwcLayers traverses to children, but releasePendingBuffer
+ // doesn't in other scenarios. So we have to traverse explicitly here.
+ l->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* child) {
+ child->releasePendingBuffer(systemTime());
+ });
}
}
mLayersPendingRemoval.clear();
@@ -2968,8 +2979,7 @@
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
// 2) There is work to be done (the dirty region isn't empty)
- bool isHwcDisplay = display->getId() >= 0;
- if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
+ if (!display->getId() && inDirtyRegion.isEmpty()) {
ALOGV("Skipping display composition");
return;
}
@@ -3284,9 +3294,15 @@
transactionFlags |= setDisplayStateLocked(display);
}
+ uint32_t clientStateFlags = 0;
for (const ComposerState& state : states) {
- transactionFlags |= setClientStateLocked(state);
+ clientStateFlags |= setClientStateLocked(state);
}
+ // If the state doesn't require a traversal and there are callbacks, send them now
+ if (!(clientStateFlags & eTraversalNeeded)) {
+ mTransactionCompletedThread.sendCallbacks();
+ }
+ transactionFlags |= clientStateFlags;
// Iterate through all layers again to determine if any need to be destroyed. Marking layers
// as destroyed should only occur after setting all other states. This is to allow for a
@@ -3595,6 +3611,17 @@
if (what & layer_state_t::eSidebandStreamChanged) {
if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
}
+
+ std::vector<sp<CallbackHandle>> callbackHandles;
+ if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
+ mTransactionCompletedThread.run();
+ for (const auto& [listener, callbackIds] : s.listenerCallbacks) {
+ callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
+ }
+ }
+ if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
+ // Do not put anything that updates layer state or modifies flags after
+ // setTransactionCompletedListener
return flags;
}
@@ -3844,7 +3871,7 @@
const auto displayId = display->getId();
LOG_ALWAYS_FATAL_IF(!displayId);
- ALOGD("Setting power mode %d on display %" PRIu64, mode, *displayId);
+ ALOGD("Setting power mode %d on display %s", mode, to_string(*displayId).c_str());
int currentMode = display->getPowerMode();
if (mode == currentMode) {
@@ -3943,7 +3970,7 @@
mTimeStats.setPowerMode(mode);
}
- ALOGD("Finished setting power mode %d on display %" PRIu64, mode, *displayId);
+ ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str());
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
@@ -4274,7 +4301,7 @@
continue;
}
- result.appendFormat("Display %" PRIu64 " (HWC display %" PRIu64 "): ", *displayId,
+ result.appendFormat("Display %s (HWC display %" PRIu64 "): ", to_string(*displayId).c_str(),
*hwcDisplayId);
uint8_t port;
DisplayIdentificationData data;
@@ -4322,7 +4349,7 @@
continue;
}
- result.appendFormat("Display %" PRIu64 " color modes:\n", *displayId);
+ result.appendFormat("Display %s color modes:\n", to_string(*displayId).c_str());
std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
for (auto&& mode : modes) {
result.appendFormat(" %s (%d)\n", decodeColorMode(mode).c_str(), mode);
@@ -4441,15 +4468,15 @@
if (const auto displayId = getInternalDisplayId();
displayId && getHwComposer().isConnected(*displayId)) {
const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
- result.appendFormat("Display %" PRIu64 ": app phase %" PRId64 " ns, "
+ result.appendFormat("Display %s: app phase %" PRId64 " ns, "
"sf phase %" PRId64 " ns, "
"early app phase %" PRId64 " ns, "
"early sf phase %" PRId64 " ns, "
"early app gl phase %" PRId64 " ns, "
"early sf gl phase %" PRId64 " ns, "
"present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
- *displayId, vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, appEarlyOffset,
- sfEarlyOffset, appEarlyGlOffset, sfEarlyGlOffset,
+ to_string(*displayId).c_str(), vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
+ appEarlyOffset, sfEarlyOffset, appEarlyGlOffset, sfEarlyGlOffset,
dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
}
result.append("\n");
@@ -4553,7 +4580,7 @@
continue;
}
- result.appendFormat("Display %" PRIu64 " HWC layers:\n", *displayId);
+ result.appendFormat("Display %s HWC layers:\n", to_string(*displayId).c_str());
Layer::miniDumpHeader(result);
mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, *displayId); });
result.append("\n");
@@ -4594,7 +4621,7 @@
}
}
- ALOGE("%s: Invalid display %" PRIu64, __FUNCTION__, displayId);
+ ALOGE("%s: Invalid display %s", __FUNCTION__, to_string(displayId).c_str());
static const Vector<sp<Layer>> empty;
return empty;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e449e20..6ffe025 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -62,6 +62,7 @@
#include "SurfaceFlingerFactory.h"
#include "SurfaceInterceptor.h"
#include "SurfaceTracing.h"
+#include "TransactionCompletedThread.h"
#include "DisplayHardware/HWC2.h"
#include "DisplayHardware/HWComposer.h"
@@ -368,6 +369,10 @@
inline void onLayerCreated() { mNumLayers++; }
inline void onLayerDestroyed() { mNumLayers--; }
+ TransactionCompletedThread& getTransactionCompletedThread() {
+ return mTransactionCompletedThread;
+ }
+
private:
friend class Client;
friend class DisplayEventConnection;
@@ -919,6 +924,8 @@
bool mUseHwcVirtualDisplays = false;
std::atomic<uint32_t> mFrameMissedCount{0};
+ TransactionCompletedThread mTransactionCompletedThread;
+
// Restrict layers to use two buffers in their bufferqueues.
bool mLayerTripleBufferingDisabled = false;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 7faaff6..55cfa4b 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -497,7 +497,7 @@
creation->set_name(info.displayName);
creation->set_is_secure(info.isSecure);
if (info.displayId) {
- creation->set_display_id(*info.displayId);
+ creation->set_display_id(info.displayId->value);
}
}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index ace7c1b..9730e8c 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -173,8 +173,8 @@
ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID,
timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
+ const std::string& layerName = layerRecord.layerName;
if (prevTimeRecord.ready) {
- const std::string& layerName = layerRecord.layerName;
if (!mTimeStats.stats.count(layerName)) {
mTimeStats.stats[layerName].layerName = layerName;
mTimeStats.stats[layerName].packageName = getPackageName(layerName);
@@ -220,6 +220,18 @@
timeRecords[0].frameTime.frameNumber, presentToPresentMs);
timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
}
+
+ // Output additional trace points to track frame time.
+ ATRACE_INT64(("TimeStats-Post - " + layerName).c_str(), timeRecords[0].frameTime.postTime);
+ ATRACE_INT64(("TimeStats-Acquire - " + layerName).c_str(),
+ timeRecords[0].frameTime.acquireTime);
+ ATRACE_INT64(("TimeStats-Latch - " + layerName).c_str(),
+ timeRecords[0].frameTime.latchTime);
+ ATRACE_INT64(("TimeStats-Desired - " + layerName).c_str(),
+ timeRecords[0].frameTime.desiredTime);
+ ATRACE_INT64(("TimeStats-Present - " + layerName).c_str(),
+ timeRecords[0].frameTime.presentTime);
+
prevTimeRecord = timeRecords[0];
timeRecords.pop_front();
layerRecord.waitData--;
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
new file mode 100644
index 0000000..9b9dc57
--- /dev/null
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "TransactionCompletedThread"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "TransactionCompletedThread.h"
+
+#include <cinttypes>
+
+#include <binder/IInterface.h>
+#include <gui/ITransactionCompletedListener.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+TransactionCompletedThread::~TransactionCompletedThread() {
+ {
+ std::lock_guard lock(mMutex);
+ mKeepRunning = false;
+ mConditionVariable.notify_all();
+ }
+
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+
+ {
+ std::lock_guard lock(mMutex);
+ for (const auto& [listener, listenerStats] : mListenerStats) {
+ listener->unlinkToDeath(mDeathRecipient);
+ }
+ }
+}
+
+void TransactionCompletedThread::run() {
+ std::lock_guard lock(mMutex);
+ if (mRunning) {
+ return;
+ }
+ mDeathRecipient = new ThreadDeathRecipient();
+ mRunning = true;
+ mThread = std::thread(&TransactionCompletedThread::threadMain, this);
+}
+
+void TransactionCompletedThread::registerPendingLatchedCallbackHandle(
+ const sp<CallbackHandle>& handle) {
+ std::lock_guard lock(mMutex);
+
+ sp<IBinder> listener = IInterface::asBinder(handle->listener);
+ const auto& callbackIds = handle->callbackIds;
+
+ mPendingTransactions[listener][callbackIds]++;
+}
+
+void TransactionCompletedThread::addLatchedCallbackHandles(
+ const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
+ const sp<Fence>& previousReleaseFence) {
+ std::lock_guard lock(mMutex);
+
+ // If the previous release fences have not signaled, something as probably gone wrong.
+ // Store the fences and check them again before sending a callback.
+ if (previousReleaseFence &&
+ previousReleaseFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
+ ALOGD("release fence from the previous frame has not signaled");
+ mPreviousReleaseFences.push_back(previousReleaseFence);
+ }
+
+ for (const auto& handle : handles) {
+ auto listener = mPendingTransactions.find(IInterface::asBinder(handle->listener));
+ auto& pendingCallbacks = listener->second;
+ auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
+
+ if (pendingCallback != pendingCallbacks.end()) {
+ auto& pendingCount = pendingCallback->second;
+
+ // Decrease the pending count for this listener
+ if (--pendingCount == 0) {
+ pendingCallbacks.erase(pendingCallback);
+ }
+ } else {
+ ALOGE("there are more latched callbacks than there were registered callbacks");
+ }
+
+ addCallbackHandle(handle, latchTime);
+ }
+}
+
+void TransactionCompletedThread::addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle) {
+ std::lock_guard lock(mMutex);
+ addCallbackHandle(handle);
+}
+
+void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle,
+ nsecs_t latchTime) {
+ const sp<IBinder> listener = IInterface::asBinder(handle->listener);
+
+ // If we don't already have a reference to this listener, linkToDeath so we get a notification
+ // if it dies.
+ if (mListenerStats.count(listener) == 0) {
+ status_t error = listener->linkToDeath(mDeathRecipient);
+ if (error != NO_ERROR) {
+ ALOGE("cannot add callback handle because linkToDeath failed, err: %d", error);
+ return;
+ }
+ }
+
+ auto& listenerStats = mListenerStats[listener];
+ listenerStats.listener = handle->listener;
+
+ auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
+ transactionStats.latchTime = latchTime;
+ transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
+ handle->releasePreviousBuffer);
+}
+
+void TransactionCompletedThread::addPresentFence(const sp<Fence>& presentFence) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mPresentFence = presentFence;
+}
+
+void TransactionCompletedThread::sendCallbacks() {
+ std::lock_guard lock(mMutex);
+ if (mRunning) {
+ mConditionVariable.notify_all();
+ }
+}
+
+void TransactionCompletedThread::threadMain() {
+ std::lock_guard lock(mMutex);
+
+ while (mKeepRunning) {
+ mConditionVariable.wait(mMutex);
+
+ // Present fence should fire almost immediately. If the fence has not signaled in 100ms,
+ // there is a major problem and it will probably never fire.
+ nsecs_t presentTime = -1;
+ if (mPresentFence) {
+ status_t status = mPresentFence->wait(100);
+ if (status == NO_ERROR) {
+ presentTime = mPresentFence->getSignalTime();
+ } else {
+ ALOGE("present fence has not signaled, err %d", status);
+ }
+ }
+
+ // We should never hit this case. The release fences from the previous frame should have
+ // signaled long before the current frame is presented.
+ for (const auto& fence : mPreviousReleaseFences) {
+ status_t status = fence->wait(100);
+ if (status != NO_ERROR) {
+ ALOGE("previous release fence has not signaled, err %d", status);
+ }
+ }
+
+ // For each listener
+ auto it = mListenerStats.begin();
+ while (it != mListenerStats.end()) {
+ auto& [listener, listenerStats] = *it;
+
+ // For each transaction
+ bool sendCallback = true;
+ for (auto& [callbackIds, transactionStats] : listenerStats.transactionStats) {
+ // If we are still waiting on the callback handles for this transaction, skip it
+ if (mPendingTransactions[listener].count(callbackIds) != 0) {
+ sendCallback = false;
+ break;
+ }
+
+ // If the transaction has been latched
+ if (transactionStats.latchTime >= 0) {
+ // If the present time is < 0, this transaction has been latched but not
+ // presented. Skip it for now. This can happen when a new transaction comes
+ // in between the latch and present steps. sendCallbacks is called by
+ // SurfaceFlinger when the transaction is received to ensure that if the
+ // transaction that didn't update state it still got a callback.
+ if (presentTime < 0) {
+ sendCallback = false;
+ break;
+ }
+
+ transactionStats.presentTime = presentTime;
+ }
+ }
+ // If the listener has no pending transactions and all latched transactions have been
+ // presented
+ if (sendCallback) {
+ // If the listener is still alive
+ if (listener->isBinderAlive()) {
+ // Send callback
+ listenerStats.listener->onTransactionCompleted(listenerStats);
+ listener->unlinkToDeath(mDeathRecipient);
+ }
+ it = mListenerStats.erase(it);
+ } else {
+ it++;
+ }
+ }
+
+ if (mPresentFence) {
+ mPresentFence.clear();
+ mPreviousReleaseFences.clear();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+CallbackHandle::CallbackHandle(const sp<ITransactionCompletedListener>& transactionListener,
+ const std::vector<CallbackId>& ids, const sp<IBinder>& sc)
+ : listener(transactionListener), callbackIds(ids), surfaceControl(sc) {}
+
+} // namespace android
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
new file mode 100644
index 0000000..5af4097
--- /dev/null
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <deque>
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+
+#include <android-base/thread_annotations.h>
+
+#include <binder/IBinder.h>
+#include <gui/ITransactionCompletedListener.h>
+#include <ui/Fence.h>
+
+namespace android {
+
+class CallbackHandle : public RefBase {
+public:
+ CallbackHandle(const sp<ITransactionCompletedListener>& transactionListener,
+ const std::vector<CallbackId>& ids, const sp<IBinder>& sc);
+
+ sp<ITransactionCompletedListener> listener;
+ std::vector<CallbackId> callbackIds;
+ sp<IBinder> surfaceControl;
+
+ bool releasePreviousBuffer = false;
+ nsecs_t acquireTime = -1;
+};
+
+class TransactionCompletedThread {
+public:
+ ~TransactionCompletedThread();
+
+ void run();
+
+ // Informs the TransactionCompletedThread that there is a Transaction with a CallbackHandle
+ // that needs to be latched and presented this frame. This function should be called once the
+ // layer has received the CallbackHandle so the TransactionCompletedThread knows not to send
+ // a callback for that Listener/Transaction pair until that CallbackHandle has been latched and
+ // presented.
+ void registerPendingLatchedCallbackHandle(const sp<CallbackHandle>& handle);
+ // Notifies the TransactionCompletedThread that a pending CallbackHandle has been latched.
+ void addLatchedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
+ const sp<Fence>& previousReleaseFence);
+
+ // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
+ // presented this frame.
+ void addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle);
+
+ void addPresentFence(const sp<Fence>& presentFence);
+
+ void sendCallbacks();
+
+private:
+ void threadMain();
+
+ void addCallbackHandle(const sp<CallbackHandle>& handle, nsecs_t latchTime = -1)
+ REQUIRES(mMutex);
+
+ class ThreadDeathRecipient : public IBinder::DeathRecipient {
+ public:
+ // This function is a no-op. isBinderAlive needs a linked DeathRecipient to work.
+ // Death recipients needs a binderDied function.
+ //
+ // (isBinderAlive checks if BpBinder's mAlive is 0. mAlive is only set to 0 in sendObituary.
+ // sendObituary is only called if linkToDeath was called with a DeathRecipient.)
+ void binderDied(const wp<IBinder>& /*who*/) override {}
+ };
+ sp<ThreadDeathRecipient> mDeathRecipient;
+
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& strongPointer) const {
+ return std::hash<IBinder*>{}(strongPointer.get());
+ }
+ };
+
+ std::thread mThread;
+
+ std::mutex mMutex;
+ std::condition_variable_any mConditionVariable;
+
+ std::unordered_map<
+ sp<IBinder /*listener*/>,
+ std::unordered_map<std::vector<CallbackId>, uint32_t /*count*/, CallbackIdsHash>,
+ IBinderHash>
+ mPendingTransactions GUARDED_BY(mMutex);
+ std::unordered_map<sp<IBinder /*listener*/>, ListenerStats, IBinderHash> mListenerStats
+ GUARDED_BY(mMutex);
+
+ bool mRunning GUARDED_BY(mMutex) = false;
+ bool mKeepRunning GUARDED_BY(mMutex) = true;
+
+ sp<Fence> mPresentFence GUARDED_BY(mMutex);
+ std::vector<sp<Fence>> mPreviousReleaseFences GUARDED_BY(mMutex);
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 8bd5fcb..91999ae 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*"
+ "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*"
}
}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 94b33ac..988454a 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -15,9 +15,12 @@
*/
#include <algorithm>
+#include <chrono>
+#include <cinttypes>
#include <functional>
#include <limits>
#include <ostream>
+#include <thread>
#include <gtest/gtest.h>
@@ -64,6 +67,7 @@
const Color Color::TRANSPARENT{0, 0, 0, 0};
using android::hardware::graphics::common::V1_1::BufferUsage;
+using namespace std::chrono_literals;
std::ostream& operator<<(std::ostream& os, const Color& color) {
os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
@@ -327,16 +331,21 @@
mClient = 0;
}
- virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+ virtual sp<SurfaceControl> createLayer(const sp<SurfaceComposerClient>& client,
+ const char* name, uint32_t width, uint32_t height,
uint32_t flags = 0) {
auto layer =
- mClient->createSurface(String8(name), width, height, PIXEL_FORMAT_RGBA_8888, flags);
+ client->createSurface(String8(name), width, height, PIXEL_FORMAT_RGBA_8888, flags);
EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
- status_t error = Transaction()
- .setLayerStack(layer, mDisplayLayerStack)
- .setLayer(layer, mLayerZBase)
- .apply();
+ Transaction t;
+ t.setLayerStack(layer, mDisplayLayerStack).setLayer(layer, mLayerZBase);
+ // If we are creating a color layer, set its crop since its size will be ignored.
+ if (flags == ISurfaceComposerClient::eFXSurfaceColor) {
+ t.setCrop_legacy(layer, Rect(0, 0, width, height));
+ }
+
+ status_t error = t.apply();
if (error != NO_ERROR) {
ADD_FAILURE() << "failed to initialize SurfaceControl";
layer.clear();
@@ -345,6 +354,11 @@
return layer;
}
+ virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+ uint32_t flags = 0) {
+ return createLayer(mClient, name, width, height, flags);
+ }
+
ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
// wait for previous transactions (such as setSize) to complete
Transaction().apply(true);
@@ -502,6 +516,7 @@
// set layer stack (b/68888219)
Transaction t;
t.setDisplayLayerStack(mDisplay, mDisplayLayerStack);
+ t.setCrop_legacy(mBlackBgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight));
t.setLayerStack(mBlackBgSurface, mDisplayLayerStack);
t.setColor(mBlackBgSurface, half3{0, 0, 0});
t.setLayer(mBlackBgSurface, mLayerZBase);
@@ -1953,7 +1968,7 @@
"test");
fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
- sp<Fence> fence = new Fence(-1);
+ sp<Fence> fence = Fence::NO_FENCE;
Transaction()
.setBuffer(layer, buffer)
@@ -2156,6 +2171,627 @@
}
}
+class ExpectedResult {
+public:
+ enum Transaction {
+ NOT_PRESENTED = 0,
+ PRESENTED,
+ };
+
+ enum Buffer {
+ NOT_ACQUIRED = 0,
+ ACQUIRED,
+ };
+
+ enum PreviousBuffer {
+ NOT_RELEASED = 0,
+ RELEASED,
+ };
+
+ void reset() {
+ mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+ mExpectedSurfaceResults.clear();
+ }
+
+ void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer,
+ ExpectedResult::Buffer bufferResult = NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+ mTransactionResult = transactionResult;
+ mExpectedSurfaceResults.emplace(std::piecewise_construct,
+ std::forward_as_tuple(layer->getHandle()),
+ std::forward_as_tuple(bufferResult, previousBufferResult));
+ }
+
+ void addSurfaces(ExpectedResult::Transaction transactionResult,
+ const std::vector<sp<SurfaceControl>>& layers,
+ ExpectedResult::Buffer bufferResult = NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+ for (const auto& layer : layers) {
+ addSurface(transactionResult, layer, bufferResult, previousBufferResult);
+ }
+ }
+
+ void verifyTransactionStats(const TransactionStats& transactionStats) const {
+ const auto& [latchTime, presentTime, surfaceStats] = transactionStats;
+ if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
+ ASSERT_GE(latchTime, 0) << "bad latch time";
+ ASSERT_GE(presentTime, 0) << "bad present time";
+ } else {
+ ASSERT_EQ(presentTime, -1) << "transaction shouldn't have been presented";
+ ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
+ }
+
+ ASSERT_EQ(surfaceStats.size(), mExpectedSurfaceResults.size())
+ << "wrong number of surfaces";
+
+ for (const auto& stats : surfaceStats) {
+ const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl);
+ ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end())
+ << "unexpected surface control";
+ expectedSurfaceResult->second.verifySurfaceStats(stats, latchTime);
+ }
+ }
+
+private:
+ class ExpectedSurfaceResult {
+ public:
+ ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult,
+ ExpectedResult::PreviousBuffer previousBufferResult)
+ : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
+
+ void verifySurfaceStats(const SurfaceStats& surfaceStats, nsecs_t latchTime) const {
+ const auto& [surfaceControl, acquireTime, releasePreviousBuffer] = surfaceStats;
+
+ ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
+ << "bad acquire time";
+ ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
+ ASSERT_EQ(releasePreviousBuffer,
+ mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED)
+ << "bad previous buffer released";
+ }
+
+ private:
+ ExpectedResult::Buffer mBufferResult;
+ ExpectedResult::PreviousBuffer mPreviousBufferResult;
+ };
+
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& strongPointer) const {
+ return std::hash<IBinder*>{}(strongPointer.get());
+ }
+ };
+ ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+ std::unordered_map<sp<IBinder>, ExpectedSurfaceResult, IBinderHash> mExpectedSurfaceResults;
+};
+
+class CallbackHelper {
+public:
+ static void function(void* callbackContext, const TransactionStats& transactionStats) {
+ if (!callbackContext) {
+ ALOGE("failed to get callback context");
+ }
+ CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext);
+ std::lock_guard lock(helper->mMutex);
+ helper->mTransactionStatsQueue.push(transactionStats);
+ helper->mConditionVariable.notify_all();
+ }
+
+ void getTransactionStats(TransactionStats* outStats) {
+ std::unique_lock lock(mMutex);
+
+ if (mTransactionStatsQueue.empty()) {
+ ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)),
+ std::cv_status::timeout)
+ << "did not receive callback";
+ }
+
+ *outStats = std::move(mTransactionStatsQueue.front());
+ mTransactionStatsQueue.pop();
+ }
+
+ void verifyFinalState() {
+ // Wait to see if there are extra callbacks
+ std::this_thread::sleep_for(500ms);
+
+ std::lock_guard lock(mMutex);
+ EXPECT_EQ(mTransactionStatsQueue.size(), 0) << "extra callbacks received";
+ mTransactionStatsQueue = {};
+ }
+
+ void* getContext() { return static_cast<void*>(this); }
+
+ std::mutex mMutex;
+ std::condition_variable mConditionVariable;
+ std::queue<TransactionStats> mTransactionStatsQueue;
+};
+
+class LayerCallbackTest : public LayerTransactionTest {
+protected:
+ virtual sp<SurfaceControl> createBufferStateLayer() {
+ return createLayer(mClient, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
+ }
+
+ virtual void fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
+ const sp<SurfaceControl>& layer = nullptr) {
+ if (layer) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(mWidth, mHeight, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY |
+ BufferUsage::GPU_TEXTURE,
+ "test");
+ fillGraphicBufferColor(buffer, Rect(0, 0, mWidth, mHeight), Color::RED);
+
+ sp<Fence> fence = new Fence(-1);
+
+ transaction.setBuffer(layer, buffer)
+ .setAcquireFence(layer, fence)
+ .setSize(layer, mWidth, mHeight);
+ }
+
+ transaction.addTransactionCompletedCallback(callbackHelper->function,
+ callbackHelper->getContext());
+ }
+
+ void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+ bool finalState = false) {
+ TransactionStats transactionStats;
+ ASSERT_NO_FATAL_FAILURE(helper.getTransactionStats(&transactionStats));
+ EXPECT_NO_FATAL_FAILURE(expectedResult.verifyTransactionStats(transactionStats));
+
+ if (finalState) {
+ ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+ }
+ }
+
+ void waitForCallbacks(CallbackHelper& helper,
+ const std::vector<ExpectedResult>& expectedResults,
+ bool finalState = false) {
+ for (const auto& expectedResult : expectedResults) {
+ waitForCallback(helper, expectedResult);
+ }
+ if (finalState) {
+ ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+ }
+ }
+
+ uint32_t mWidth = 32;
+ uint32_t mHeight = 32;
+};
+
+TEST_F(LayerCallbackTest, Basic) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoBuffer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback);
+
+ transaction.setPosition(layer, mWidth, mHeight).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoStateChange) {
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback);
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, OffScreen) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.setPosition(layer, -100, -100).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SameCallback) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback;
+ fillTransaction(transaction1, &callback, layer1);
+ fillTransaction(transaction2, &callback, layer2);
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SameLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ fillTransaction(transaction1, &callback1, layer);
+ fillTransaction(transaction2, &callback2, layer);
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SingleBuffer) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_DifferentClients) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ ExpectedResult expected;
+
+ if (i == 0) {
+ fillTransaction(transaction, &callback, layer);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ } else {
+ fillTransaction(transaction, &callback);
+ }
+
+ transaction.apply();
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ if (i == 0) {
+ fillTransaction(transaction, &callback, layer);
+ } else {
+ fillTransaction(transaction, &callback);
+ }
+
+ transaction.setPosition(layer, mWidth, mHeight).apply();
+
+ ExpectedResult expected;
+ expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED
+ : ExpectedResult::Transaction::NOT_PRESENTED,
+ layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, i == 0));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ for (size_t i = 0; i < 10; i++) {
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+ ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ for (size_t i = 0; i < 10; i++) {
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+ ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateChange) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+
+ // Normal call to set up test
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+ expected.reset();
+
+ // Test
+ fillTransaction(transaction1, &callback1);
+ fillTransaction(transaction2, &callback2);
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateChange) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+
+ // Normal call to set up test
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+ expected.reset();
+
+ // Test
+ fillTransaction(transaction1, &callback1);
+ fillTransaction(transaction2, &callback2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ std::vector<ExpectedResult> expectedResults(50);
+ ExpectedResult::PreviousBuffer previousBufferResult =
+ ExpectedResult::PreviousBuffer::NOT_RELEASED;
+ for (auto& expected : expectedResults) {
+ expected.reset();
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED, previousBufferResult);
+ previousBufferResult = ExpectedResult::PreviousBuffer::RELEASED;
+
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.apply();
+ std::this_thread::sleep_for(200ms);
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ std::vector<ExpectedResult> expectedResults(50);
+ bool first = true;
+ for (auto& expected : expectedResults) {
+ expected.reset();
+
+ if (first) {
+ fillTransaction(transaction, &callback, layer);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ first = false;
+ } else {
+ fillTransaction(transaction, &callback);
+ }
+
+ transaction.apply();
+ std::this_thread::sleep_for(200ms);
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ // Normal call to set up test
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.setPosition(layer, mWidth, mHeight).apply();
+
+ ExpectedResult expectedResult;
+ expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expectedResult, true));
+
+ // Test
+ std::vector<ExpectedResult> expectedResults(50);
+ for (auto& expected : expectedResults) {
+ expected.reset();
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer);
+
+ fillTransaction(transaction, &callback);
+
+ transaction.setPosition(layer, mWidth, mHeight).apply();
+
+ std::this_thread::sleep_for(200ms);
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
class LayerUpdateTest : public LayerTransactionTest {
protected:
virtual void SetUp() {
@@ -2394,17 +3030,19 @@
mClient->createSurface(String8("Buffered child"), 20, 20,
PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
fillSurfaceRGBA8(childBuffer, 200, 200, 200);
-
- SurfaceComposerClient::Transaction{}.show(childNoBuffer).show(childBuffer).apply(true);
-
+ SurfaceComposerClient::Transaction{}
+ .setCrop_legacy(childNoBuffer, Rect(0, 0, 10, 10))
+ .show(childNoBuffer)
+ .show(childBuffer)
+ .apply(true);
{
ScreenCapture::captureScreen(&sc);
sc->expectChildColor(73, 73);
sc->expectFGColor(74, 74);
}
-
- SurfaceComposerClient::Transaction{}.setSize(childNoBuffer, 20, 20).apply(true);
-
+ SurfaceComposerClient::Transaction{}
+ .setCrop_legacy(childNoBuffer, Rect(0, 0, 20, 20))
+ .apply(true);
{
ScreenCapture::captureScreen(&sc);
sc->expectChildColor(73, 73);
@@ -2939,6 +3577,221 @@
mCapture->checkPixel(10, 10, 255, 255, 255);
}
}
+class BoundlessLayerTest : public LayerUpdateTest {
+protected:
+ std::unique_ptr<ScreenCapture> mCapture;
+};
+
+// Verify setting a size on a buffer layer has no effect.
+TEST_F(BoundlessLayerTest, BufferLayerIgnoresSize) {
+ sp<SurfaceControl> bufferLayer =
+ mClient->createSurface(String8("BufferLayer"), 45, 45, PIXEL_FORMAT_RGBA_8888, 0,
+ mFGSurfaceControl.get());
+ ASSERT_TRUE(bufferLayer != nullptr);
+ ASSERT_TRUE(bufferLayer->isValid());
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::BLACK, 30, 30));
+ asTransaction([&](Transaction& t) { t.show(bufferLayer); });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 94, 94), Color::BLACK);
+ // Buffer layer should not extend past buffer bounds
+ mCapture->expectFGColor(95, 95);
+ }
+}
+
+// Verify a boundless color layer will fill its parent bounds. The parent has a buffer size
+// which will crop the color layer.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) {
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor,
+ mFGSurfaceControl.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify a boundless color layer will fill its parent bounds. The parent has no buffer but has
+// a crop which will be used to crop the color layer.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) {
+ sp<SurfaceControl> cropLayer =
+ mClient->createSurface(String8("CropLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, mFGSurfaceControl.get());
+ ASSERT_TRUE(cropLayer != nullptr);
+ ASSERT_TRUE(cropLayer->isValid());
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10));
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(cropLayer);
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // 5 pixels from the foreground we should see the child surface
+ mCapture->expectColor(Rect(69, 69, 74, 74), Color::BLACK);
+ // 10 pixels from the foreground we should be back to the foreground surface
+ mCapture->expectFGColor(74, 74);
+ }
+}
+
+// Verify for boundless layer with no children, their transforms have no effect.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) {
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor,
+ mFGSurfaceControl.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setPosition(colorLayer, 320, 320);
+ t.setMatrix(colorLayer, 2, 0, 0, 2);
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify for boundless layer with children, their transforms have an effect.
+TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) {
+ sp<SurfaceControl> boundlessLayerRightShift =
+ mClient->createSurface(String8("BoundlessLayerRightShift"), 0, 0,
+ PIXEL_FORMAT_RGBA_8888, 0 /* flags */, mFGSurfaceControl.get());
+ ASSERT_TRUE(boundlessLayerRightShift != nullptr);
+ ASSERT_TRUE(boundlessLayerRightShift->isValid());
+ sp<SurfaceControl> boundlessLayerDownShift =
+ mClient->createSurface(String8("BoundlessLayerLeftShift"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, boundlessLayerRightShift.get());
+ ASSERT_TRUE(boundlessLayerDownShift != nullptr);
+ ASSERT_TRUE(boundlessLayerDownShift->isValid());
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor,
+ boundlessLayerDownShift.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setPosition(boundlessLayerRightShift, 32, 0);
+ t.show(boundlessLayerRightShift);
+ t.setPosition(boundlessLayerDownShift, 0, 32);
+ t.show(boundlessLayerDownShift);
+ t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(96, 96, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify child layers do not get clipped if they temporarily move into the negative
+// coordinate space as the result of an intermediate transformation.
+TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) {
+ sp<SurfaceControl> boundlessLayer =
+ mClient->createSurface(String8("BoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, mFGSurfaceControl.get());
+ ASSERT_TRUE(boundlessLayer != nullptr);
+ ASSERT_TRUE(boundlessLayer->isValid());
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, boundlessLayer.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ // shift child layer off bounds. If this layer was not boundless, we will
+ // expect the child layer to be cropped.
+ t.setPosition(boundlessLayer, 32, 32);
+ t.show(boundlessLayer);
+ t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ // undo shift by parent
+ t.setPosition(colorLayer, -32, -32);
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify for boundless root layers with children, their transforms have an effect.
+TEST_F(BoundlessLayerTest, RootBoundlessLayerCanSetTransform) {
+ sp<SurfaceControl> rootBoundlessLayer =
+ mClient->createSurface(String8("RootBoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */);
+ ASSERT_TRUE(rootBoundlessLayer != nullptr);
+ ASSERT_TRUE(rootBoundlessLayer->isValid());
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor,
+ rootBoundlessLayer.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setLayer(rootBoundlessLayer, INT32_MAX - 1);
+ t.setPosition(rootBoundlessLayer, 32, 32);
+ t.show(rootBoundlessLayer);
+ t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ t.hide(mFGSurfaceControl);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Top left of foreground must now be visible
+ mCapture->expectBGColor(31, 31);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(32, 32, 96, 96), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(97, 97);
+ }
+}
class ScreenCaptureTest : public LayerUpdateTest {
protected:
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index ebb58dc..ab1b252 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -66,7 +66,7 @@
constexpr hwc2_layer_t HWC_LAYER = 5000;
constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
-constexpr DisplayId DEFAULT_DISPLAY_ID = 42;
+constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
@@ -790,6 +790,9 @@
LayerProperties::HEIGHT,
LayerProperties::LAYER_FLAGS));
});
+
+ auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
+ layerDrawingState.crop_legacy = Rect(0, 0, LayerProperties::HEIGHT, LayerProperties::WIDTH);
return layer;
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index a8cd867..32fce67 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -248,8 +248,8 @@
template <typename PhysicalDisplay>
struct PhysicalDisplayId {};
-template <DisplayId displayId>
-using VirtualDisplayId = std::integral_constant<DisplayId, displayId>;
+template <DisplayId::Type displayId>
+using VirtualDisplayId = std::integral_constant<DisplayId::Type, displayId>;
struct NoDisplayId {};
@@ -278,9 +278,9 @@
}
};
-template <DisplayId displayId>
+template <DisplayId::Type displayId>
struct DisplayIdGetter<VirtualDisplayId<displayId>> {
- static std::optional<DisplayId> get() { return displayId; }
+ static std::optional<DisplayId> get() { return DisplayId{displayId}; }
};
template <>
@@ -1103,7 +1103,7 @@
*/
class GetBestColorModeTest : public DisplayTransactionTest {
public:
- static constexpr DisplayId DEFAULT_DISPLAY_ID = 777;
+ static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777};
GetBestColorModeTest()
: DisplayTransactionTest(),
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index c5b60f1..a519f1f 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -175,6 +175,7 @@
auto& mutableLayerDrawingState(sp<Layer> layer) { return layer->mDrawingState; }
void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
+ layer->mDrawingState.sidebandStream = sidebandStream;
layer->getBE().compositionInfo.hwc.sidebandStream = sidebandStream;
}
diff --git a/services/vr/bufferhubd/consumer_queue_channel.cpp b/services/vr/bufferhubd/consumer_queue_channel.cpp
index 74b549d..5d7d4e9 100644
--- a/services/vr/bufferhubd/consumer_queue_channel.cpp
+++ b/services/vr/bufferhubd/consumer_queue_channel.cpp
@@ -80,27 +80,35 @@
}
void ConsumerQueueChannel::RegisterNewBuffer(
- const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot) {
- ALOGD_IF(TRACE,
- "ConsumerQueueChannel::RegisterNewBuffer: queue_id=%d buffer_id=%d "
- "slot=%zu silent=%d",
- buffer_id(), producer_channel->buffer_id(), slot, silent_);
+ const std::shared_ptr<ProducerChannel>& producer_channel,
+ size_t producer_slot) {
+ ALOGD_IF(TRACE, "%s: queue_id=%d buffer_id=%d slot=%zu silent=%d",
+ __FUNCTION__, buffer_id(), producer_channel->buffer_id(),
+ producer_slot, silent_);
// Only register buffers if the queue is not silent.
- if (!silent_) {
- pending_buffer_slots_.emplace(producer_channel, slot);
-
- // Signal the client that there is new buffer available.
- SignalAvailable();
+ if (silent_) {
+ return;
}
+
+ auto status = producer_channel->CreateConsumerStateMask();
+ if (!status.ok()) {
+ ALOGE("%s: Failed to create consumer state mask: %s", __FUNCTION__,
+ status.GetErrorMessage().c_str());
+ return;
+ }
+ uint64_t consumer_state_mask = status.get();
+
+ pending_buffer_slots_.emplace(producer_channel, producer_slot,
+ consumer_state_mask);
+ // Signal the client that there is new buffer available.
+ SignalAvailable();
}
Status<std::vector<std::pair<RemoteChannelHandle, size_t>>>
ConsumerQueueChannel::OnConsumerQueueImportBuffers(Message& message) {
std::vector<std::pair<RemoteChannelHandle, size_t>> buffer_handles;
- ATRACE_NAME("ConsumerQueueChannel::OnConsumerQueueImportBuffers");
- ALOGD_IF(TRACE,
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers: "
- "pending_buffer_slots=%zu",
+ ATRACE_NAME(__FUNCTION__);
+ ALOGD_IF(TRACE, "%s: pending_buffer_slots=%zu", __FUNCTION__,
pending_buffer_slots_.size());
// Indicate this is a silent queue that will not import buffers.
@@ -108,30 +116,30 @@
return ErrorStatus(EBADR);
while (!pending_buffer_slots_.empty()) {
- auto producer_channel = pending_buffer_slots_.front().first.lock();
- size_t producer_slot = pending_buffer_slots_.front().second;
+ auto producer_channel =
+ pending_buffer_slots_.front().producer_channel.lock();
+ size_t producer_slot = pending_buffer_slots_.front().producer_slot;
+ uint64_t consumer_state_mask =
+ pending_buffer_slots_.front().consumer_state_mask;
pending_buffer_slots_.pop();
// It's possible that the producer channel has expired. When this occurs,
// ignore the producer channel.
if (producer_channel == nullptr) {
- ALOGW(
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers: producer "
- "channel has already been expired.");
+ ALOGW("%s: producer channel has already been expired.", __FUNCTION__);
continue;
}
- auto status = producer_channel->CreateConsumer(message);
+ auto status =
+ producer_channel->CreateConsumer(message, consumer_state_mask);
// If no buffers are imported successfully, clear available and return an
// error. Otherwise, return all consumer handles already imported
// successfully, but keep available bits on, so that the client can retry
// importing remaining consumer buffers.
if (!status) {
- ALOGE(
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers: Failed create "
- "consumer: %s",
- status.GetErrorMessage().c_str());
+ ALOGE("%s: Failed create consumer: %s", __FUNCTION__,
+ status.GetErrorMessage().c_str());
if (buffer_handles.empty()) {
ClearAvailable();
return status.error_status();
diff --git a/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h b/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
index 8f35437..3a81b03 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
@@ -3,8 +3,8 @@
#include <queue>
-#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/buffer_hub.h>
+#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/consumer_channel.h>
#include <private/dvr/producer_queue_channel.h>
@@ -28,7 +28,8 @@
// Called by ProdcuerQueueChannel to notify consumer queue that a new
// buffer has been allocated.
void RegisterNewBuffer(
- const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot);
+ const std::shared_ptr<ProducerChannel>& producer_channel,
+ size_t producer_slot);
// Called after clients been signaled by service that new buffer has been
// allocated. Clients uses kOpConsumerQueueImportBuffers to import new
@@ -40,14 +41,29 @@
void OnProducerClosed();
private:
+ // Data structure to store relavant info of a newly allocated producer buffer
+ // so that consumer channel and buffer can be created later.
+ struct PendingBuffer {
+ PendingBuffer(std::shared_ptr<ProducerChannel> channel, size_t slot,
+ uint64_t mask) {
+ producer_channel = channel;
+ producer_slot = slot;
+ consumer_state_mask = mask;
+ }
+ PendingBuffer() = delete;
+
+ std::weak_ptr<ProducerChannel> producer_channel;
+ size_t producer_slot;
+ uint64_t consumer_state_mask;
+ };
+
std::shared_ptr<ProducerQueueChannel> GetProducer() const;
// Pointer to the producer channel.
std::weak_ptr<Channel> producer_;
// Tracks newly allocated buffer producers along with it's slot number.
- std::queue<std::pair<std::weak_ptr<ProducerChannel>, size_t>>
- pending_buffer_slots_;
+ std::queue<PendingBuffer> pending_buffer_slots_;
// Tracks how many buffers have this queue imported.
size_t capacity_;
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index 5868b09..3ad9c70 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -53,7 +53,9 @@
BufferDescription<BorrowedHandle> GetBuffer(uint64_t client_state_mask);
- pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message);
+ pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message,
+ uint64_t consumer_state_mask);
+ pdx::Status<uint64_t> CreateConsumerStateMask();
pdx::Status<RemoteChannelHandle> OnNewConsumer(Message& message);
pdx::Status<LocalFence> OnConsumerAcquire(Message& message);
@@ -93,7 +95,7 @@
LocalFence post_fence_;
LocalFence returned_fence_;
size_t user_metadata_size_; // size of user requested buffer buffer size.
- size_t metadata_buf_size_; // size of the ion buffer that holds metadata.
+ size_t metadata_buf_size_; // size of the ion buffer that holds metadata.
pdx::LocalHandle acquire_fence_fd_;
pdx::LocalHandle release_fence_fd_;
@@ -111,6 +113,10 @@
pdx::Status<void> OnProducerPost(Message& message, LocalFence acquire_fence);
pdx::Status<LocalFence> OnProducerGain(Message& message);
+ // Remove consumer from atomics in shared memory based on consumer_state_mask.
+ // This function is used for clean up for failures in CreateConsumer method.
+ void RemoveConsumerClientMask(uint64_t consumer_state_mask);
+
ProducerChannel(const ProducerChannel&) = delete;
void operator=(const ProducerChannel&) = delete;
};
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 397c0ae..c6e8ea9 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -248,21 +248,7 @@
return {GetBuffer(BufferHubDefs::kFirstClientBitMask)};
}
-Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
- ATRACE_NAME("ProducerChannel::CreateConsumer");
- ALOGD_IF(TRACE,
- "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
- buffer_id(), producer_owns_);
-
- int channel_id;
- auto status = message.PushChannel(0, nullptr, &channel_id);
- if (!status) {
- ALOGE(
- "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
- status.GetErrorMessage().c_str());
- return ErrorStatus(ENOMEM);
- }
-
+Status<uint64_t> ProducerChannel::CreateConsumerStateMask() {
// Try find the next consumer state bit which has not been claimed by any
// consumer yet.
// memory_order_acquire is chosen here because all writes in other threads
@@ -277,7 +263,6 @@
"consumers per producer: 63.");
return ErrorStatus(E2BIG);
}
-
uint64_t updated_active_clients_bit_mask =
current_active_clients_bit_mask | client_state_mask;
// Set the updated value only if the current value stays the same as what was
@@ -286,28 +271,71 @@
// thread, and the modification will be visible in other threads that acquire
// active_clients_bit_mask_. If the comparison fails, load the result of
// all writes from all threads to updated_active_clients_bit_mask.
- if (!active_clients_bit_mask_->compare_exchange_weak(
- current_active_clients_bit_mask, updated_active_clients_bit_mask,
- std::memory_order_acq_rel, std::memory_order_acquire)) {
+ // Keep on finding the next available slient state mask until succeed or out
+ // of memory.
+ while (!active_clients_bit_mask_->compare_exchange_weak(
+ current_active_clients_bit_mask, updated_active_clients_bit_mask,
+ std::memory_order_acq_rel, std::memory_order_acquire)) {
ALOGE("Current active clients bit mask is changed to %" PRIx64
- ", which was expected to be %" PRIx64 ".",
+ ", which was expected to be %" PRIx64
+ ". Trying to generate a new client state mask to resolve race "
+ "condition.",
updated_active_clients_bit_mask, current_active_clients_bit_mask);
- return ErrorStatus(EBUSY);
+ client_state_mask = BufferHubDefs::FindNextAvailableClientStateMask(
+ current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
+ if (client_state_mask == 0ULL) {
+ ALOGE(
+ "ProducerChannel::CreateConsumer: reached the maximum mumber of "
+ "consumers per producer: 63.");
+ return ErrorStatus(E2BIG);
+ }
+ updated_active_clients_bit_mask =
+ current_active_clients_bit_mask | client_state_mask;
}
- auto consumer =
- std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
- client_state_mask, shared_from_this());
+ return {client_state_mask};
+}
+
+void ProducerChannel::RemoveConsumerClientMask(uint64_t consumer_state_mask) {
+ // Clear up the buffer state and fence state in case there is already
+ // something there due to possible race condition between producer post and
+ // consumer failed to create channel.
+ buffer_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
+ fence_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
+
+ // Restore the consumer state bit and make it visible in other threads that
+ // acquire the active_clients_bit_mask_.
+ active_clients_bit_mask_->fetch_and(~consumer_state_mask,
+ std::memory_order_release);
+}
+
+Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(
+ Message& message, uint64_t consumer_state_mask) {
+ ATRACE_NAME("ProducerChannel::CreateConsumer");
+ ALOGD_IF(TRACE,
+ "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
+ buffer_id(), producer_owns_);
+
+ int channel_id;
+ auto status = message.PushChannel(0, nullptr, &channel_id);
+ if (!status) {
+ ALOGE(
+ "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
+ status.GetErrorMessage().c_str());
+ RemoveConsumerClientMask(consumer_state_mask);
+ return ErrorStatus(ENOMEM);
+ }
+
+ auto consumer = std::make_shared<ConsumerChannel>(
+ service(), buffer_id(), channel_id, consumer_state_mask,
+ shared_from_this());
const auto channel_status = service()->SetChannel(channel_id, consumer);
if (!channel_status) {
ALOGE(
"ProducerChannel::CreateConsumer: failed to set new consumer channel: "
"%s",
channel_status.GetErrorMessage().c_str());
- // Restore the consumer state bit and make it visible in other threads that
- // acquire the active_clients_bit_mask_.
- active_clients_bit_mask_->fetch_and(~client_state_mask,
- std::memory_order_release);
+ RemoveConsumerClientMask(consumer_state_mask);
return ErrorStatus(ENOMEM);
}
@@ -327,7 +355,11 @@
Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
ATRACE_NAME("ProducerChannel::OnNewConsumer");
ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
- return CreateConsumer(message);
+ auto status = CreateConsumerStateMask();
+ if (!status.ok()) {
+ return status.error_status();
+ }
+ return CreateConsumer(message, /*consumer_state_mask=*/status.get());
}
Status<void> ProducerChannel::OnProducerPost(Message&,
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 003775b..258b45b 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -55,7 +55,6 @@
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
"-Wall",
"-Werror",
- // mVrClient unused in vr_composer_client.cpp
"-Wno-error=unused-private-field",
// Warnings in vr_hwc.cpp to be fixed after sync of goog/master.
"-Wno-sign-compare",
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index d775711..786d5fa 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -45,7 +45,7 @@
}
VrComposerClient::VrCommandEngine::VrCommandEngine(VrComposerClient& client)
- : ComposerCommandEngine(client.mHal, client.mResources.get()), mVrClient(client),
+ : ComposerCommandEngine(client.mHal, client.mResources.get()),
mVrHal(client.mVrHal) {}
VrComposerClient::VrCommandEngine::~VrCommandEngine() {}
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index 76b1c4f..de22640 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -54,7 +54,6 @@
IVrComposerClient::BufferMetadata readBufferMetadata();
- VrComposerClient& mVrClient;
android::dvr::VrHwc& mVrHal;
VrCommandEngine(const VrCommandEngine&) = delete;
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index 4065785..a24c889 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -12,16 +12,16 @@
#include <thread>
#include <utility>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <dvr/performance_client_api.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
#include "stdio_filebuf.h"
-#include "string_trim.h"
#include "unique_file.h"
-using android::dvr::Trim;
+using android::base::Trim;
using android::dvr::UniqueFile;
using android::dvr::stdio_filebuf;
diff --git a/services/vr/performanced/string_trim.h b/services/vr/performanced/string_trim.h
deleted file mode 100644
index 7094e9f..0000000
--- a/services/vr/performanced/string_trim.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
-#define ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
-
-#include <functional>
-#include <locale>
-#include <string>
-
-namespace android {
-namespace dvr {
-
-// Trims whitespace from the left side of |subject| and returns the result as a
-// new string.
-inline std::string LeftTrim(std::string subject) {
- subject.erase(subject.begin(),
- std::find_if(subject.begin(), subject.end(),
- std::not1(std::ptr_fun<int, int>(std::isspace))));
- return subject;
-}
-
-// Trims whitespace from the right side of |subject| and returns the result as a
-// new string.
-inline std::string RightTrim(std::string subject) {
- subject.erase(std::find_if(subject.rbegin(), subject.rend(),
- std::not1(std::ptr_fun<int, int>(std::isspace)))
- .base(),
- subject.end());
- return subject;
-}
-
-// Trims whitespace from the both sides of |subject| and returns the result as a
-// new string.
-inline std::string Trim(std::string subject) {
- subject.erase(subject.begin(),
- std::find_if(subject.begin(), subject.end(),
- std::not1(std::ptr_fun<int, int>(std::isspace))));
- subject.erase(std::find_if(subject.rbegin(), subject.rend(),
- std::not1(std::ptr_fun<int, int>(std::isspace)))
- .base(),
- subject.end());
- return subject;
-}
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
diff --git a/services/vr/performanced/task.cpp b/services/vr/performanced/task.cpp
index bda1682..2fc96bf 100644
--- a/services/vr/performanced/task.cpp
+++ b/services/vr/performanced/task.cpp
@@ -10,10 +10,10 @@
#include <memory>
#include <sstream>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include "stdio_filebuf.h"
-#include "string_trim.h"
namespace {
@@ -102,7 +102,7 @@
// The status file has lines with the format <field>:<value>. Extract the
// value after the colon.
- return Trim(line.substr(offset + field.size() + 1));
+ return android::base::Trim(line.substr(offset + field.size() + 1));
}
}
@@ -123,7 +123,7 @@
}
std::string key = line.substr(0, offset);
- std::string value = Trim(line.substr(offset + 1));
+ std::string value = android::base::Trim(line.substr(offset + 1));
ALOGD_IF(TRACE, "Task::ReadStatusFields: key=\"%s\" value=\"%s\"",
key.c_str(), value.c_str());
@@ -156,7 +156,7 @@
std::string line = "";
std::getline(file_stream, line);
- return Trim(line);
+ return android::base::Trim(line);
} else {
return "";
}