Merge "SF: Add test for FrameStats refresh rate"
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
index 87d75ac..3a17e03 100644
--- a/cmds/lshal/PipeRelay.cpp
+++ b/cmds/lshal/PipeRelay.cpp
@@ -77,13 +77,12 @@
PipeRelay::~PipeRelay() {
CloseFd(&mFds[1]);
+ CloseFd(&mFds[0]);
if (mThread != nullptr) {
mThread->join();
mThread.clear();
}
-
- CloseFd(&mFds[0]);
}
status_t PipeRelay::initCheck() const {
diff --git a/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h b/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
deleted file mode 100644
index 67abc68..0000000
--- a/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IARC_VIDEO_BRIDGE_H
-#define ANDROID_IARC_VIDEO_BRIDGE_H
-
-#include <arc/MojoBootstrapResult.h>
-#include <binder/IInterface.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-class IArcVideoBridge : public IInterface {
-public:
- DECLARE_META_INTERFACE(ArcVideoBridge);
-
- // Returns MojoBootstrapResult for creating mojo ipc channel of
- // VideoAcceleratorFactory.
- virtual ::arc::MojoBootstrapResult bootstrapVideoAcceleratorFactory() = 0;
-
- // Get the version of the remote VideoHost on Chromium side.
- virtual int32_t hostVersion() = 0;
-};
-
-class BnArcVideoBridge : public BnInterface<IArcVideoBridge> {
-public:
- virtual status_t onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif // ANDROID_IARC_VIDEO_BRIDGE_H
diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h
index b772f70..8c3ff74 100644
--- a/include/android/sharedmem.h
+++ b/include/android/sharedmem.h
@@ -21,6 +21,7 @@
/**
* @file sharedmem.h
+ * @brief Shared memory buffers that can be shared across process.
*/
#ifndef ANDROID_SHARED_MEMORY_H
@@ -45,10 +46,6 @@
* - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
*/
-/**
- * Structures and functions for a shared memory buffer that can be shared across process.
- */
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -64,6 +61,8 @@
*
* Use close() to release the shared memory region.
*
+ * Available since API level 26.
+ *
* \param name an optional name.
* \param size size of the shared memory region
* \return file descriptor that denotes the shared memory; error code on failure.
@@ -73,6 +72,8 @@
/**
* Get the size of the shared memory region.
*
+ * Available since API level 26.
+ *
* \param fd file descriptor of the shared memory region
* \return size in bytes; 0 if fd is not a valid shared memory file descriptor.
*/
@@ -102,6 +103,8 @@
*
* // share fd with another process here and the other process can only map with PROT_READ.
*
+ * Available since API level 26.
+ *
* \param fd file descriptor of the shared memory region.
* \param prot any bitwise-or'ed combination of PROT_READ, PROT_WRITE, PROT_EXEC denoting
* updated access. Note access can only be removed, but not added back.
diff --git a/include/android/sharedmem_jni.h b/include/android/sharedmem_jni.h
index e42f9a1..13e56e6 100644
--- a/include/android/sharedmem_jni.h
+++ b/include/android/sharedmem_jni.h
@@ -21,6 +21,7 @@
/**
* @file sharedmem_jni.h
+ * @brief Shared memory buffers that can be shared across process.
*/
#ifndef ANDROID_SHARED_MEMORY_JNI_H
@@ -47,10 +48,6 @@
* - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
*/
-/**
- * Structures and functions for a shared memory buffer that can be shared across process.
- */
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -65,6 +62,8 @@
*
* Use close() to release the shared memory region.
*
+ * Available since API level 27.
+ *
* \param env The JNIEnv* pointer
* \param sharedMemory The Java android.os.SharedMemory object
* \return file descriptor that denotes the shared memory; -1 if the shared memory object is
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index d0ed31e..c44a17e 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -161,12 +161,8 @@
int n = 0;
while (uptimeMillis() < timeout) {
n++;
- if (isVendorService) {
- ALOGI("Waiting for vendor service %s...", String8(name).string());
- CallStack stack(LOG_TAG);
- } else if (n%10 == 0) {
- ALOGI("Waiting for service %s...", String8(name).string());
- }
+ ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
+ ProcessState::self()->getDriverName().c_str());
usleep(1000*sleepTime);
sp<IBinder> svc = checkService(name);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index e22bc70..7f9668f 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -116,20 +116,20 @@
data.writeInt32(maxLayerZ);
data.writeInt32(static_cast<int32_t>(useIdentityTransform));
data.writeInt32(static_cast<int32_t>(rotation));
- status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
-
- if (err != NO_ERROR) {
- return err;
+ status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("captureScreen failed to transact: %d", result);
+ return result;
}
-
- err = reply.readInt32();
- if (err != NO_ERROR) {
- return err;
+ result = reply.readInt32();
+ if (result != NO_ERROR) {
+ ALOGE("captureScreen failed to readInt32: %d", result);
+ return result;
}
*outBuffer = new GraphicBuffer();
reply.read(**outBuffer);
- return err;
+ return result;
}
virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
@@ -141,21 +141,20 @@
data.write(sourceCrop);
data.writeFloat(frameScale);
data.writeBool(childrenOnly);
- status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
-
- if (err != NO_ERROR) {
- return err;
+ status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("captureLayers failed to transact: %d", result);
+ return result;
}
-
- err = reply.readInt32();
- if (err != NO_ERROR) {
- return err;
+ result = reply.readInt32();
+ if (result != NO_ERROR) {
+ ALOGE("captureLayers failed to readInt32: %d", result);
+ return result;
}
-
*outBuffer = new GraphicBuffer();
reply.read(**outBuffer);
- return err;
+ return result;
}
virtual bool authenticateSurfaceTexture(
@@ -344,10 +343,26 @@
virtual status_t setActiveConfig(const sp<IBinder>& display, int id)
{
Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- data.writeInt32(id);
- remote()->transact(BnSurfaceComposer::SET_ACTIVE_CONFIG, data, &reply);
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("setActiveConfig failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeStrongBinder(display);
+ if (result != NO_ERROR) {
+ ALOGE("setActiveConfig failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = data.writeInt32(id);
+ if (result != NO_ERROR) {
+ ALOGE("setActiveConfig failed to writeInt32: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::SET_ACTIVE_CONFIG, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("setActiveConfig failed to transact: %d", result);
+ return result;
+ }
return reply.readInt32();
}
@@ -429,8 +444,16 @@
virtual status_t clearAnimationFrameStats() {
Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply);
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("clearAnimationFrameStats failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("clearAnimationFrameStats failed to transact: %d", result);
+ return result;
+ }
return reply.readInt32();
}
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 19ad31b..3a6dfda 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -102,14 +102,14 @@
status_t SurfaceControl::clearLayerFrameStats() const {
status_t err = validate();
- if (err < 0) return err;
+ if (err != NO_ERROR) return err;
const sp<SurfaceComposerClient>& client(mClient);
return client->clearLayerFrameStats(mHandle);
}
status_t SurfaceControl::getLayerFrameStats(FrameStats* outStats) const {
status_t err = validate();
- if (err < 0) return err;
+ if (err != NO_ERROR) return err;
const sp<SurfaceComposerClient>& client(mClient);
return client->getLayerFrameStats(mHandle, outStats);
}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e401572..98ec338 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -220,12 +220,12 @@
class BnSurfaceComposer: public BnInterface<ISurfaceComposer> {
public:
- enum {
+ enum ISurfaceComposerTag {
// Note: BOOT_FINISHED must remain this value, it is called from
// Java by ActivityManagerService.
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
CREATE_CONNECTION,
- UNUSED, // formerly CREATE_GRAPHIC_BUFFER_ALLOC
+ CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED, // unused, fails permissions check
CREATE_DISPLAY_EVENT_CONNECTION,
CREATE_DISPLAY,
DESTROY_DISPLAY,
@@ -236,7 +236,7 @@
GET_DISPLAY_CONFIGS,
GET_ACTIVE_CONFIG,
SET_ACTIVE_CONFIG,
- CONNECT_DISPLAY,
+ CONNECT_DISPLAY_UNUSED, // unused, fails permissions check
CAPTURE_SCREEN,
CAPTURE_LAYERS,
CLEAR_ANIMATION_FRAME_STATS,
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index e247398..2a962b5 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -945,3 +945,35 @@
EXPECT_EQ(b1_id, p2_id);
EXPECT_TRUE(IsBufferGained(p2->buffer_state()));
}
+
+TEST_F(LibBufferHubTest, TestDuplicateDetachedBuffer) {
+ auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, kUserMetadataSize);
+ int b1_id = b1->id();
+ EXPECT_TRUE(b1->IsValid());
+
+ auto status_or_handle = b1->Duplicate();
+ EXPECT_TRUE(status_or_handle);
+
+ // The detached buffer should still be valid.
+ EXPECT_TRUE(b1->IsConnected());
+ EXPECT_TRUE(b1->IsValid());
+
+ // Gets the channel handle for the duplicated buffer.
+ LocalChannelHandle h2 = status_or_handle.take();
+ EXPECT_TRUE(h2.valid());
+
+ std::unique_ptr<DetachedBuffer> b2 = DetachedBuffer::Import(std::move(h2));
+ EXPECT_FALSE(h2.valid());
+ ASSERT_TRUE(b2 != nullptr);
+ int b2_id = b2->id();
+
+ // The duplicated buffer should inherit the same buffer id.
+ EXPECT_EQ(b1_id, b2_id);
+
+ // Promote the detached buffer should fail as b1 is no longer the exclusive
+ // owner of the buffer..
+ status_or_handle = b1->Promote();
+ EXPECT_FALSE(status_or_handle.ok());
+ EXPECT_EQ(status_or_handle.error(), EINVAL);
+}
diff --git a/libs/vr/libbufferhub/detached_buffer.cpp b/libs/vr/libbufferhub/detached_buffer.cpp
index 6fae16d..60f11e2 100644
--- a/libs/vr/libbufferhub/detached_buffer.cpp
+++ b/libs/vr/libbufferhub/detached_buffer.cpp
@@ -104,6 +104,20 @@
return status_or_handle;
}
+Status<LocalChannelHandle> DetachedBuffer::Duplicate() {
+ ATRACE_NAME("DetachedBuffer::Duplicate");
+ ALOGD_IF(TRACE, "DetachedBuffer::Duplicate: id=%d.", id_);
+
+ auto status_or_handle =
+ client_.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
+
+ if (!status_or_handle.ok()) {
+ ALOGE("DetachedBuffer::Duplicate: Failed to duplicate buffer (id=%d): %s.",
+ id_, status_or_handle.GetErrorMessage().c_str());
+ }
+ return status_or_handle;
+}
+
sp<GraphicBuffer> DetachedBuffer::TakeGraphicBuffer() {
if (!client_.IsValid() || !buffer_.buffer()) {
ALOGE("DetachedBuffer::TakeGraphicBuffer: Invalid buffer.");
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
new file mode 100644
index 0000000..8b2bf91
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -0,0 +1,89 @@
+#ifndef ANDROID_DVR_BUFFER_HUB_DEFS_H_
+#define ANDROID_DVR_BUFFER_HUB_DEFS_H_
+
+#include <dvr/dvr_api.h>
+#include <hardware/gralloc.h>
+
+#include <atomic>
+
+namespace android {
+namespace dvr {
+
+namespace BufferHubDefs {
+
+static constexpr uint32_t kMetadataFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr uint32_t kMetadataUsage =
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+
+// Single producuer multiple (up to 63) consumers ownership signal.
+// 64-bit atomic unsigned int.
+//
+// MSB LSB
+// | |
+// v v
+// [P|C62|...|C1|C0]
+// Gain'ed state: [0|..|0|0] -> Exclusively Writable.
+// Post'ed state: [1|..|0|0]
+// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
+// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
+static constexpr uint64_t kProducerStateBit = 1ULL << 63;
+static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
+
+static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
+ uint64_t clear_mask, uint64_t set_mask) {
+ uint64_t old_state;
+ uint64_t new_state;
+ do {
+ old_state = buffer_state->load();
+ new_state = (old_state & ~clear_mask) | set_mask;
+ } while (!buffer_state->compare_exchange_weak(old_state, new_state));
+}
+
+static inline bool IsBufferGained(uint64_t state) { return state == 0; }
+
+static inline bool IsBufferPosted(uint64_t state,
+ uint64_t consumer_bit = kConsumerStateMask) {
+ return (state & kProducerStateBit) && !(state & consumer_bit);
+}
+
+static inline bool IsBufferAcquired(uint64_t state) {
+ return (state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+static inline bool IsBufferReleased(uint64_t state) {
+ return !(state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+static inline uint64_t FindNextClearedBit(uint64_t bits) {
+ return ~bits - (~bits & (~bits - 1));
+}
+
+static inline uint64_t FindFirstClearedBit() {
+ return FindNextClearedBit(kProducerStateBit);
+}
+
+struct __attribute__((packed, aligned(8))) MetadataHeader {
+ // Internal data format, which can be updated as long as the size, padding and
+ // field alignment of the struct is consistent within the same ABI. As this
+ // part is subject for future updates, it's not stable cross Android version,
+ // so don't have it visible from outside of the Android platform (include Apps
+ // and vendor HAL).
+ std::atomic<uint64_t> buffer_state;
+ std::atomic<uint64_t> fence_state;
+ uint64_t queue_index;
+
+ // Public data format, which should be updated with caution. See more details
+ // in dvr_api.h
+ DvrNativeBufferMetadata metadata;
+};
+
+static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
+static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
+
+} // namespace BufferHubDefs
+
+} // namespace dvr
+} // namespace android
+
+
+#endif // ANDROID_DVR_BUFFER_HUB_DEFS_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index 088a235..e163216 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -1,11 +1,11 @@
#ifndef ANDROID_DVR_BUFFERHUB_RPC_H_
#define ANDROID_DVR_BUFFERHUB_RPC_H_
+#include "buffer_hub_defs.h"
+
#include <cutils/native_handle.h>
-#include <sys/types.h>
#include <ui/BufferQueueDefs.h>
-#include <dvr/dvr_api.h>
#include <pdx/channel_handle.h>
#include <pdx/file_handle.h>
#include <pdx/rpc/remote_method.h>
@@ -15,71 +15,6 @@
namespace android {
namespace dvr {
-namespace BufferHubDefs {
-
-static constexpr uint32_t kMetadataFormat = HAL_PIXEL_FORMAT_BLOB;
-static constexpr uint32_t kMetadataUsage =
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
-
-// Single producuer multiple (up to 63) consumers ownership signal.
-// 64-bit atomic unsigned int.
-//
-// MSB LSB
-// | |
-// v v
-// [P|C62|...|C1|C0]
-// Gain'ed state: [0|..|0|0] -> Exclusively Writable.
-// Post'ed state: [1|..|0|0]
-// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
-// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
-static constexpr uint64_t kProducerStateBit = 1ULL << 63;
-static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
-
-static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
- uint64_t clear_mask, uint64_t set_mask) {
- uint64_t old_state;
- uint64_t new_state;
- do {
- old_state = buffer_state->load();
- new_state = (old_state & ~clear_mask) | set_mask;
- } while (!buffer_state->compare_exchange_weak(old_state, new_state));
-}
-
-static inline bool IsBufferGained(uint64_t state) { return state == 0; }
-
-static inline bool IsBufferPosted(uint64_t state,
- uint64_t consumer_bit = kConsumerStateMask) {
- return (state & kProducerStateBit) && !(state & consumer_bit);
-}
-
-static inline bool IsBufferAcquired(uint64_t state) {
- return (state & kProducerStateBit) && (state & kConsumerStateMask);
-}
-
-static inline bool IsBufferReleased(uint64_t state) {
- return !(state & kProducerStateBit) && (state & kConsumerStateMask);
-}
-
-struct __attribute__((packed, aligned(8))) MetadataHeader {
- // Internal data format, which can be updated as long as the size, padding and
- // field alignment of the struct is consistent within the same ABI. As this
- // part is subject for future updates, it's not stable cross Android version,
- // so don't have it visible from outside of the Android platform (include Apps
- // and vendor HAL).
- std::atomic<uint64_t> buffer_state;
- std::atomic<uint64_t> fence_state;
- uint64_t queue_index;
-
- // Public data format, which should be updated with caution. See more details
- // in dvr_api.h
- DvrNativeBufferMetadata metadata;
-};
-
-static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
-static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
-
-} // namespace BufferHubDefs
-
template <typename FileHandleType>
class NativeBufferHandle {
public:
@@ -450,6 +385,7 @@
kOpCreate = kOpDetachedBufferBase,
kOpImport,
kOpPromote,
+ kOpDuplicate,
};
public:
@@ -459,8 +395,9 @@
size_t user_metadata_size));
PDX_REMOTE_METHOD(Import, kOpImport, BufferDescription<LocalHandle>(Void));
PDX_REMOTE_METHOD(Promote, kOpPromote, LocalChannelHandle(Void));
+ PDX_REMOTE_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));
- PDX_REMOTE_API(API, Create, Promote);
+ PDX_REMOTE_API(API, Create, Import, Promote, Duplicate);
};
} // namespace dvr
diff --git a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
index 6d0b502..376b53e 100644
--- a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
@@ -57,6 +57,9 @@
// return. Further IPCs towards this channel will return error.
pdx::Status<pdx::LocalChannelHandle> Promote();
+ // Creates a DetachedBuffer from an existing one.
+ pdx::Status<pdx::LocalChannelHandle> Duplicate();
+
// Takes the underlying graphic buffer out of this DetachedBuffer. This call
// immediately invalidates this DetachedBuffer object and transfers the
// underlying pdx::LocalChannelHandle into the GraphicBuffer.
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index c805805..863e426 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -515,9 +515,10 @@
sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
int32_t x, int32_t y) {
// Traverse windows from front to back to find touched window.
- size_t numWindows = mWindowHandles.size();
+ const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+ size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+ sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
const InputWindowInfo* windowInfo = windowHandle->getInfo();
if (windowInfo->displayId == displayId) {
int32_t flags = windowInfo->layoutParamsFlags;
@@ -1247,9 +1248,10 @@
bool isTouchModal = false;
// Traverse windows from front to back to find touched window and outside targets.
- size_t numWindows = mWindowHandles.size();
+ const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+ size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+ sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
const InputWindowInfo* windowInfo = windowHandle->getInfo();
if (windowInfo->displayId != displayId) {
continue; // wrong display
@@ -1472,8 +1474,10 @@
sp<InputWindowHandle> foregroundWindowHandle =
mTempTouchState.getFirstForegroundWindowHandle();
if (foregroundWindowHandle->getInfo()->hasWallpaper) {
- for (size_t i = 0; i < mWindowHandles.size(); i++) {
- sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+ const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+ size_t numWindows = windowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
const InputWindowInfo* info = windowHandle->getInfo();
if (info->displayId == displayId
&& windowHandle->getInfo()->layoutParamsType
@@ -1658,9 +1662,10 @@
bool InputDispatcher::isWindowObscuredAtPointLocked(
const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
int32_t displayId = windowHandle->getInfo()->displayId;
- size_t numWindows = mWindowHandles.size();
+ const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+ size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
+ sp<InputWindowHandle> otherHandle = windowHandles.itemAt(i);
if (otherHandle == windowHandle) {
break;
}
@@ -1678,10 +1683,11 @@
bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const {
int32_t displayId = windowHandle->getInfo()->displayId;
+ const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
const InputWindowInfo* windowInfo = windowHandle->getInfo();
- size_t numWindows = mWindowHandles.size();
+ size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
+ sp<InputWindowHandle> otherHandle = windowHandles.itemAt(i);
if (otherHandle == windowHandle) {
break;
}
@@ -2909,52 +2915,77 @@
}
}
+Vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(int32_t displayId) const {
+ std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>>::const_iterator it
+ = mWindowHandlesByDisplay.find(displayId);
+ if(it != mWindowHandlesByDisplay.end()) {
+ return it->second;
+ }
+
+ // Return an empty one if nothing found.
+ return Vector<sp<InputWindowHandle>>();
+}
+
sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
const sp<InputChannel>& inputChannel) const {
- size_t numWindows = mWindowHandles.size();
- for (size_t i = 0; i < numWindows; i++) {
- const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
- if (windowHandle->getInputChannel() == inputChannel) {
- return windowHandle;
+ for (auto& it : mWindowHandlesByDisplay) {
+ const Vector<sp<InputWindowHandle>> windowHandles = it.second;
+ size_t numWindows = windowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+ if (windowHandle->getInputChannel() == inputChannel) {
+ return windowHandle;
+ }
}
}
return nullptr;
}
bool InputDispatcher::hasWindowHandleLocked(
- const sp<InputWindowHandle>& windowHandle) const {
- size_t numWindows = mWindowHandles.size();
+ const sp<InputWindowHandle>& windowHandle, int32_t displayId) const {
+
+ const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+ size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- if (mWindowHandles.itemAt(i) == windowHandle) {
+ if (windowHandles.itemAt(i) == windowHandle) {
return true;
}
}
return false;
}
-void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
+void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& inputWindowHandles,
+ int displayId) {
#if DEBUG_FOCUS
ALOGD("setInputWindows");
#endif
{ // acquire lock
AutoMutex _l(mLock);
- Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;
- mWindowHandles = inputWindowHandles;
+ const Vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
+ Vector<sp<InputWindowHandle>> windowHandles = inputWindowHandles;
+ // Insert or replace
+ mWindowHandlesByDisplay[displayId] = windowHandles;
- sp<InputWindowHandle> newFocusedWindowHandle;
+ // TODO(b/111361570): multi-display focus, one focus in all display in current.
+ sp<InputWindowHandle> newFocusedWindowHandle = mFocusedWindowHandle;
bool foundHoveredWindow = false;
- for (size_t i = 0; i < mWindowHandles.size(); i++) {
- const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
- if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) {
- mWindowHandles.removeAt(i--);
- continue;
- }
- if (windowHandle->getInfo()->hasFocus) {
- newFocusedWindowHandle = windowHandle;
- }
- if (windowHandle == mLastHoverWindowHandle) {
- foundHoveredWindow = true;
+
+ if (windowHandles.isEmpty()) {
+ // Remove all handles on a display if there are no windows left.
+ mWindowHandlesByDisplay.erase(displayId);
+ } else {
+ for (size_t i = 0; i < windowHandles.size(); i++) {
+ const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+ if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) {
+ continue;
+ }
+ if (windowHandle->getInfo()->hasFocus) {
+ newFocusedWindowHandle = windowHandle;
+ }
+ if (windowHandle == mLastHoverWindowHandle) {
+ foundHoveredWindow = true;
+ }
}
}
@@ -2962,6 +2993,7 @@
mLastHoverWindowHandle = nullptr;
}
+ // TODO(b/111361570): multi-display focus, one focus in all display in current.
if (mFocusedWindowHandle != newFocusedWindowHandle) {
if (mFocusedWindowHandle != nullptr) {
#if DEBUG_FOCUS
@@ -2985,11 +3017,12 @@
mFocusedWindowHandle = newFocusedWindowHandle;
}
- for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) {
- TouchState& state = mTouchStatesByDisplay.editValueAt(d);
+ ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
+ if (stateIndex >= 0) {
+ TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex);
for (size_t i = 0; i < state.windows.size(); ) {
TouchedWindow& touchedWindow = state.windows.editItemAt(i);
- if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
+ if (!hasWindowHandleLocked(touchedWindow.windowHandle, displayId)) {
#if DEBUG_FOCUS
ALOGD("Touched window was removed: %s",
touchedWindow.windowHandle->getName().c_str());
@@ -3015,7 +3048,7 @@
// which might not happen until the next GC.
for (size_t i = 0; i < oldWindowHandles.size(); i++) {
const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i);
- if (!hasWindowHandleLocked(oldWindowHandle)) {
+ if (!hasWindowHandleLocked(oldWindowHandle, displayId)) {
#if DEBUG_FOCUS
ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
#endif
@@ -3266,36 +3299,44 @@
dump += INDENT "TouchStates: <no displays touched>\n";
}
- if (!mWindowHandles.isEmpty()) {
- dump += INDENT "Windows:\n";
- for (size_t i = 0; i < mWindowHandles.size(); i++) {
- const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ if (!mWindowHandlesByDisplay.empty()) {
+ for (auto& it : mWindowHandlesByDisplay) {
+ const Vector<sp<InputWindowHandle>> windowHandles = it.second;
+ dump += StringPrintf(INDENT "Display: %d\n", it.first);
+ if (!windowHandles.isEmpty()) {
+ dump += INDENT "Windows:\n";
+ for (size_t i = 0; i < windowHandles.size(); i++) {
+ const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
- dump += StringPrintf(INDENT2 "%zu: name='%s', displayId=%d, "
- "paused=%s, hasFocus=%s, hasWallpaper=%s, "
- "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
- "frame=[%d,%d][%d,%d], scale=%f, "
- "touchableRegion=",
- i, windowInfo->name.c_str(), windowInfo->displayId,
- toString(windowInfo->paused),
- toString(windowInfo->hasFocus),
- toString(windowInfo->hasWallpaper),
- toString(windowInfo->visible),
- toString(windowInfo->canReceiveKeys),
- windowInfo->layoutParamsFlags, windowInfo->layoutParamsType,
- windowInfo->layer,
- windowInfo->frameLeft, windowInfo->frameTop,
- windowInfo->frameRight, windowInfo->frameBottom,
- windowInfo->scaleFactor);
- dumpRegion(dump, windowInfo->touchableRegion);
- dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
- dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
- windowInfo->ownerPid, windowInfo->ownerUid,
- windowInfo->dispatchingTimeout / 1000000.0);
+ dump += StringPrintf(INDENT2 "%zu: name='%s', displayId=%d, "
+ "paused=%s, hasFocus=%s, hasWallpaper=%s, "
+ "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
+ "frame=[%d,%d][%d,%d], scale=%f, "
+ "touchableRegion=",
+ i, windowInfo->name.c_str(), windowInfo->displayId,
+ toString(windowInfo->paused),
+ toString(windowInfo->hasFocus),
+ toString(windowInfo->hasWallpaper),
+ toString(windowInfo->visible),
+ toString(windowInfo->canReceiveKeys),
+ windowInfo->layoutParamsFlags, windowInfo->layoutParamsType,
+ windowInfo->layer,
+ windowInfo->frameLeft, windowInfo->frameTop,
+ windowInfo->frameRight, windowInfo->frameBottom,
+ windowInfo->scaleFactor);
+ dumpRegion(dump, windowInfo->touchableRegion);
+ dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
+ dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
+ windowInfo->ownerPid, windowInfo->ownerUid,
+ windowInfo->dispatchingTimeout / 1000000.0);
+ }
+ } else {
+ dump += INDENT "Windows: <none>\n";
+ }
}
} else {
- dump += INDENT "Windows: <none>\n";
+ dump += INDENT "Displays: <none>\n";
}
if (!mMonitoringChannels.isEmpty()) {
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 31ab339..5cb7fe1 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -31,6 +31,7 @@
#include <stddef.h>
#include <unistd.h>
#include <limits.h>
+#include <unordered_map>
#include "InputWindow.h"
#include "InputApplication.h"
@@ -307,7 +308,8 @@
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) = 0;
+ virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
+ int displayId) = 0;
/* Sets the focused application.
*
@@ -387,7 +389,8 @@
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
uint32_t policyFlags);
- virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles);
+ virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
+ int displayId);
virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
virtual void setInputDispatchMode(bool enabled, bool frozen);
virtual void setInputFilterEnabled(bool enabled);
@@ -956,10 +959,11 @@
bool mDispatchFrozen;
bool mInputFilterEnabled;
- Vector<sp<InputWindowHandle> > mWindowHandles;
-
+ std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay;
+ // Get window handles by display, return an empty vector if not found.
+ Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const;
sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
- bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
+ bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle, int32_t displayId) const;
// Focus tracking for keys, trackball, etc.
sp<InputWindowHandle> mFocusedWindowHandle;
diff --git a/services/media/arcvideobridge/Android.bp b/services/media/arcvideobridge/Android.bp
deleted file mode 100644
index ca5b896..0000000
--- a/services/media/arcvideobridge/Android.bp
+++ /dev/null
@@ -1,28 +0,0 @@
-cc_library_shared {
- name: "libarcvideobridge",
- product_variables: {
- arc: {
- srcs: [
- "IArcVideoBridge.cpp",
- ],
- shared_libs: [
- "libarcbridge",
- "libarcbridgeservice",
- "libbinder",
- "libchrome",
- "liblog",
- "libmojo",
- "libutils",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- "-Wunused",
- "-Wunreachable-code",
- ],
- include_dirs: [
- "frameworks/native/include/media/arcvideobridge",
- ]
- }
- }
-}
diff --git a/services/media/arcvideobridge/IArcVideoBridge.cpp b/services/media/arcvideobridge/IArcVideoBridge.cpp
deleted file mode 100644
index 468b76b..0000000
--- a/services/media/arcvideobridge/IArcVideoBridge.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "IArcVideoBridge"
-//#define LOG_NDEBUG 0
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "IArcVideoBridge.h"
-#include <binder/Parcel.h>
-#include <utils/Log.h>
-
-namespace android {
-
-enum {
- BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY = IBinder::FIRST_CALL_TRANSACTION,
- HOST_VERSION,
-};
-
-class BpArcVideoBridge : public BpInterface<IArcVideoBridge> {
-public:
- BpArcVideoBridge(const sp<IBinder>& impl) : BpInterface<IArcVideoBridge>(impl) { }
-
- virtual ::arc::MojoBootstrapResult bootstrapVideoAcceleratorFactory() {
- Parcel data, reply;
- ALOGV("bootstrapVideoAcceleratorFactory");
- data.writeInterfaceToken(IArcVideoBridge::getInterfaceDescriptor());
- status_t status = remote()->transact(
- BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY, data, &reply, 0);
- if (status != 0) {
- ALOGE("transact failed: %d", status);
- return arc::MojoBootstrapResult();
- }
- return arc::MojoBootstrapResult::createFromParcel(reply);
- }
-
- virtual int32_t hostVersion() {
- Parcel data, reply;
- ALOGV("hostVersion");
- data.writeInterfaceToken(IArcVideoBridge::getInterfaceDescriptor());
- status_t status = remote()->transact(HOST_VERSION, data, &reply, 0);
- if (status != 0) {
- ALOGE("transact failed: %d", status);
- return false;
- }
- return reply.readInt32();
- }
-};
-
-IMPLEMENT_META_INTERFACE(ArcVideoBridge, "android.os.IArcVideoBridge");
-
-status_t BnArcVideoBridge::onTransact(
- uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
- switch(code) {
- case BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY: {
- ALOGV("BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY");
- CHECK_INTERFACE(IArcVideoBridge, data, reply);
- arc::MojoBootstrapResult result = bootstrapVideoAcceleratorFactory();
- return result.writeToParcel(reply);
- }
- case HOST_VERSION: {
- ALOGV("HOST_VERSION");
- CHECK_INTERFACE(IArcVideoBridge, data, reply);
- reply->writeInt32(hostVersion());
- return OK;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index d231790..8788d47 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -40,7 +40,6 @@
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
-#include <private/gui/SyncFeatures.h>
#include <utils/Log.h>
#include <utils/String8.h>
@@ -206,7 +205,7 @@
return err;
}
- if (!SyncFeatures::getInstance().useNativeFenceSync()) {
+ if (mRE.useNativeFenceSync()) {
// Bind the new buffer to the GL texture.
//
// Older devices require the "implicit" synchronization provided
@@ -374,7 +373,7 @@
BLC_LOGV("syncForReleaseLocked");
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
- if (SyncFeatures::getInstance().useNativeFenceSync()) {
+ if (mRE.useNativeFenceSync()) {
base::unique_fd fenceFd = mRE.flush();
if (fenceFd == -1) {
BLC_LOGE("syncForReleaseLocked: failed to flush RenderEngine");
@@ -512,7 +511,7 @@
}
if (mCurrentFence->isValid()) {
- if (SyncFeatures::getInstance().useWaitSync()) {
+ if (mRE.useWaitSync()) {
base::unique_fd fenceFd(mCurrentFence->dup());
if (fenceFd == -1) {
BLC_LOGE("doFenceWait: error dup'ing fence fd: %d", errno);
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 0913de4..6c339b7 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -245,8 +245,9 @@
LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
getTransformToDisplayInverse(), mFreezeGeometryUpdates);
- status_t updateResult = mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync, &mAutoRefresh,
- &queuedBuffer, mLastFrameNumberReceived);
+ status_t updateResult =
+ mConsumer->updateTexImage(&r, *mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
+ mLastFrameNumberReceived);
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
// layer update so we check again at the next opportunity.
@@ -424,6 +425,8 @@
// -----------------------------------------------------------------------
void BufferQueueLayer::onFirstRef() {
+ BufferLayer::onFirstRef();
+
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 2e411f1..44fa760 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -537,6 +537,8 @@
}
void BufferStateLayer::onFirstRef() {
+ BufferLayer::onFirstRef();
+
if (const auto display = mFlinger->getDefaultDisplayDevice()) {
updateTransformHint(display);
}
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 829b53d..b789d04 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -40,6 +40,10 @@
namespace android {
+DispSync::~DispSync() = default;
+
+namespace impl {
+
// Setting this to true enables verbose tracing that can be used to debug
// vsync event model or phase issues.
static const bool kTraceDetailedInfo = false;
@@ -511,12 +515,26 @@
void DispSync::setPeriod(nsecs_t period) {
Mutex::Autolock lock(mMutex);
- mPeriod = period;
+ mPeriodBase = mPeriod = period;
mPhase = 0;
mReferenceTime = 0;
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
}
+void DispSync::scalePeriod(uint32_t multiplier, uint32_t divisor) {
+ Mutex::Autolock lock(mMutex);
+
+ // if only 1 of the properties is updated, we will get to this
+ // point "attempting" to set the scale to 1 when it is already
+ // 1. Check that special case so that we don't do a useless
+ // update of the model.
+ if ((multiplier == 1) && (divisor == 1) && (mPeriod == mPeriodBase))
+ return;
+
+ mPeriod = mPeriodBase * multiplier / divisor;
+ mThread->updateModel(mPeriod, mPhase, mReferenceTime);
+}
+
nsecs_t DispSync::getPeriod() {
// lock mutex as mPeriod changes multiple times in updateModelLocked
Mutex::Autolock lock(mMutex);
@@ -541,7 +559,7 @@
// Exclude the min and max from the average
durationSum -= minDuration + maxDuration;
- mPeriod = durationSum / (mNumResyncSamples - 3);
+ mPeriodBase = mPeriod = durationSum / (mNumResyncSamples - 3);
ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod));
@@ -707,4 +725,6 @@
result.appendFormat("current monotonic time: %" PRId64 "\n", now);
}
+} // namespace impl
+
} // namespace android
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index c00c161..183966f 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -31,6 +31,37 @@
class String8;
class FenceTime;
+
+class DispSync {
+public:
+ class Callback {
+ public:
+ virtual ~Callback() = default;
+ virtual void onDispSyncEvent(nsecs_t when) = 0;
+ };
+
+ virtual ~DispSync();
+
+ virtual void reset() = 0;
+ virtual bool addPresentFence(const std::shared_ptr<FenceTime>&) = 0;
+ virtual void beginResync() = 0;
+ virtual bool addResyncSample(nsecs_t timestamp) = 0;
+ virtual void endResync() = 0;
+ virtual void setPeriod(nsecs_t period) = 0;
+ virtual void scalePeriod(const uint32_t multiplier, uint32_t divisor) = 0;
+ virtual nsecs_t getPeriod() = 0;
+ virtual void setRefreshSkipCount(int count) = 0;
+ virtual status_t addEventListener(const char* name, nsecs_t phase, Callback* callback) = 0;
+ virtual status_t removeEventListener(Callback* callback) = 0;
+ virtual status_t changePhaseOffset(Callback* callback, nsecs_t phase) = 0;
+ virtual nsecs_t computeNextRefresh(int periodOffset) const = 0;
+ virtual void setIgnorePresentFences(bool ignore) = 0;
+
+ virtual void dump(String8& result) const = 0;
+};
+
+namespace impl {
+
class DispSyncThread;
// DispSync maintains a model of the periodic hardware-based vsync events of a
@@ -46,21 +77,15 @@
// current model accurately represents the hardware event times it will return
// false to indicate that a resynchronization (via addResyncSample) is not
// needed.
-class DispSync {
+class DispSync : public android::DispSync {
public:
- class Callback {
- public:
- virtual ~Callback(){};
- virtual void onDispSyncEvent(nsecs_t when) = 0;
- };
-
explicit DispSync(const char* name);
- ~DispSync();
+ ~DispSync() override;
void init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset);
// reset clears the resync samples and error value.
- void reset();
+ void reset() override;
// addPresentFence adds a fence for use in validating the current vsync
// event model. The fence need not be signaled at the time
@@ -71,7 +96,7 @@
//
// This method should be called with the retire fence from each HWComposer
// set call that affects the display.
- bool addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
+ bool addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) override;
// The beginResync, addResyncSample, and endResync methods are used to re-
// synchronize the DispSync's model to the hardware vsync events. The re-
@@ -84,45 +109,51 @@
// is turned on (i.e. once immediately after it's turned on) and whenever
// addPresentFence returns true indicating that the model has drifted away
// from the hardware vsync events.
- void beginResync();
- bool addResyncSample(nsecs_t timestamp);
- void endResync();
+ void beginResync() override;
+ bool addResyncSample(nsecs_t timestamp) override;
+ void endResync() override;
// The setPeriod method sets the vsync event model's period to a specific
// value. This should be used to prime the model when a display is first
// turned on. It should NOT be used after that.
- void setPeriod(nsecs_t period);
+ void setPeriod(nsecs_t period) override;
+
+ // The scalePeriod method applies the multiplier and divisor to
+ // scale the vsync event model's period. The function is added
+ // for an experimental test mode and should not be used outside
+ // of that purpose.
+ void scalePeriod(const uint32_t multiplier, uint32_t divisor);
// The getPeriod method returns the current vsync period.
- nsecs_t getPeriod();
+ nsecs_t getPeriod() override;
// setRefreshSkipCount specifies an additional number of refresh
// cycles to skip. For example, on a 60Hz display, a skip count of 1
// will result in events happening at 30Hz. Default is zero. The idea
// is to sacrifice smoothness for battery life.
- void setRefreshSkipCount(int count);
+ void setRefreshSkipCount(int count) override;
// addEventListener registers a callback to be called repeatedly at the
// given phase offset from the hardware vsync events. The callback is
// called from a separate thread and it should return reasonably quickly
// (i.e. within a few hundred microseconds).
- status_t addEventListener(const char* name, nsecs_t phase, Callback* callback);
+ status_t addEventListener(const char* name, nsecs_t phase, Callback* callback) override;
// removeEventListener removes an already-registered event callback. Once
// this method returns that callback will no longer be called by the
// DispSync object.
- status_t removeEventListener(Callback* callback);
+ status_t removeEventListener(Callback* callback) override;
// changePhaseOffset changes the phase offset of an already-registered event callback. The
// method will make sure that there is no skipping or double-firing on the listener per frame,
// even when changing the offsets multiple times.
- status_t changePhaseOffset(Callback* callback, nsecs_t phase);
+ status_t changePhaseOffset(Callback* callback, nsecs_t phase) override;
// computeNextRefresh computes when the next refresh is expected to begin.
// The periodOffset value can be used to move forward or backward; an
// offset of zero is the next refresh, -1 is the previous refresh, 1 is
// the refresh after next. etc.
- nsecs_t computeNextRefresh(int periodOffset) const;
+ nsecs_t computeNextRefresh(int periodOffset) const override;
// In certain situations the present fences aren't a good indicator of vsync
// time, e.g. when vr flinger is active, or simply aren't available,
@@ -130,10 +161,10 @@
// whether or not DispSync ignores present fences. If present fences are
// ignored, DispSync will always ask for hardware vsync events by returning
// true from addPresentFence() and addResyncSample().
- void setIgnorePresentFences(bool ignore);
+ void setIgnorePresentFences(bool ignore) override;
// dump appends human-readable debug info to the result string.
- void dump(String8& result) const;
+ void dump(String8& result) const override;
private:
void updateModelLocked();
@@ -152,6 +183,7 @@
// mPeriod is the computed period of the modeled vsync events in
// nanoseconds.
nsecs_t mPeriod;
+ nsecs_t mPeriodBase;
// mPhase is the phase offset of the modeled vsync events. It is the
// number of nanoseconds from time 0 to the first vsync event.
@@ -206,6 +238,8 @@
std::unique_ptr<Callback> mZeroPhaseTracer;
};
+} // namespace impl
+
} // namespace android
#endif // ANDROID_DISPSYNC_H
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 900b3d7..e0d6ecc 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -23,6 +23,7 @@
#undef HWC2_INCLUDE_STRINGIFICATION
#undef HWC2_USE_CPP11
+#include <cutils/properties.h>
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
#include <ui/GraphicTypes.h>
@@ -160,6 +161,8 @@
}
Builder& setVsyncPeriod(int32_t vsyncPeriod) {
mConfig->mVsyncPeriod = vsyncPeriod;
+ mConfig->mPeriodMultiplier = 1;
+ mConfig->mPeriodDivisor = 1;
return *this;
}
Builder& setDpiX(int32_t dpiX) {
@@ -189,7 +192,12 @@
int32_t getWidth() const { return mWidth; }
int32_t getHeight() const { return mHeight; }
- nsecs_t getVsyncPeriod() const { return mVsyncPeriod; }
+ nsecs_t getVsyncPeriod() const {
+ return mVsyncPeriod * mPeriodMultiplier / mPeriodDivisor; }
+ void scalePanelFrequency(int32_t multiplier, int32_t divisor) const {
+ mPeriodMultiplier = multiplier;
+ mPeriodDivisor = divisor;
+ }
float getDpiX() const { return mDpiX; }
float getDpiY() const { return mDpiY; }
@@ -202,6 +210,8 @@
int32_t mWidth;
int32_t mHeight;
nsecs_t mVsyncPeriod;
+ mutable int32_t mPeriodMultiplier;
+ mutable int32_t mPeriodDivisor;
float mDpiX;
float mDpiY;
};
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 744a70c..4860f3c 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -30,7 +30,6 @@
#include <utils/Trace.h>
#include <cutils/compiler.h>
-#include <gui/ISurfaceComposer.h>
#include <math.h>
#include "Description.h"
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 0b8b838..39f7e30 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -29,6 +29,7 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
+#include <private/gui/SyncFeatures.h>
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
@@ -175,6 +176,14 @@
return mEGLConfig;
}
+bool RenderEngine::useNativeFenceSync() const {
+ return SyncFeatures::getInstance().useNativeFenceSync();
+}
+
+bool RenderEngine::useWaitSync() const {
+ return SyncFeatures::getInstance().useWaitSync();
+}
+
bool RenderEngine::isCurrent() const {
return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
}
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 95b9ec8..d2b218e 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -26,7 +26,6 @@
#include <EGL/eglext.h>
#include <Transform.h>
#include <android-base/unique_fd.h>
-#include <gui/SurfaceControl.h>
#include <math/mat4.h>
#define EGL_NO_CONFIG ((EGLConfig)0)
@@ -69,6 +68,9 @@
// dump the extension strings. always call the base class.
virtual void dump(String8& result) = 0;
+ virtual bool useNativeFenceSync() const = 0;
+ virtual bool useWaitSync() const = 0;
+
virtual bool isCurrent() const = 0;
virtual bool setCurrentSurface(const RE::Surface& surface) = 0;
virtual void resetCurrentSurface() = 0;
@@ -190,6 +192,9 @@
// dump the extension strings. always call the base class.
void dump(String8& result) override;
+ bool useNativeFenceSync() const override;
+ bool useWaitSync() const override;
+
bool isCurrent() const;
bool setCurrentSurface(const RE::Surface& surface) override;
void resetCurrentSurface() override;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 399fbd8..4b95036 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -264,7 +264,6 @@
mDebugInTransaction(0),
mLastTransactionTime(0),
mForceFullDamage(false),
- mPrimaryDispSync("PrimaryDispSync"),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
mHasPoweredOff(false),
@@ -325,7 +324,13 @@
}
ALOGV("Primary Display Orientation is set to %2d.", mPrimaryDisplayOrientation);
- mPrimaryDispSync.init(SurfaceFlinger::hasSyncFramework, SurfaceFlinger::dispSyncPresentTimeOffset);
+ // Note: We create a local temporary with the real DispSync implementation
+ // type temporarily so we can initialize it with the configured values,
+ // before storing it for more generic use using the interface type.
+ auto primaryDispSync = std::make_unique<impl::DispSync>("PrimaryDispSync");
+ primaryDispSync->init(SurfaceFlinger::hasSyncFramework,
+ SurfaceFlinger::dispSyncPresentTimeOffset);
+ mPrimaryDispSync = std::move(primaryDispSync);
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
@@ -703,14 +708,14 @@
// start the EventThread
mEventThreadSource =
- std::make_unique<DispSyncSource>(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs,
- true, "app");
+ std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
+ SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
mEventThread = std::make_unique<impl::EventThread>(mEventThreadSource.get(),
[this] { resyncWithRateLimit(); },
impl::EventThread::InterceptVSyncsCallback(),
"appEventThread");
mSfEventThreadSource =
- std::make_unique<DispSyncSource>(&mPrimaryDispSync,
+ std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
mSFEventThread =
@@ -996,8 +1001,8 @@
// FIXME for now we always return stats for the primary display
memset(stats, 0, sizeof(*stats));
- stats->vsyncTime = mPrimaryDispSync.computeNextRefresh(0);
- stats->vsyncPeriod = mPrimaryDispSync.getPeriod();
+ stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
+ stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
return NO_ERROR;
}
@@ -1216,15 +1221,6 @@
status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
NO_THREAD_SAFETY_ANALYSIS {
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
- if ((uid != AID_SHELL) &&
- !PermissionCache::checkPermission(sDump, pid, uid)) {
- ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
-
// Try to acquire a lock for 1s, fail gracefully
const status_t err = mStateLock.timedLock(s2ns(1));
const bool locked = (err == NO_ERROR);
@@ -1295,7 +1291,7 @@
void SurfaceFlinger::enableHardwareVsync() {
Mutex::Autolock _l(mHWVsyncLock);
if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
- mPrimaryDispSync.beginResync();
+ mPrimaryDispSync->beginResync();
mEventControlThread->setVsyncEnabled(true);
mPrimaryHWVsyncEnabled = true;
}
@@ -1320,11 +1316,11 @@
const auto activeConfig = getHwComposer().getActiveConfig(displayId);
const nsecs_t period = activeConfig->getVsyncPeriod();
- mPrimaryDispSync.reset();
- mPrimaryDispSync.setPeriod(period);
+ mPrimaryDispSync->reset();
+ mPrimaryDispSync->setPeriod(period);
if (!mPrimaryHWVsyncEnabled) {
- mPrimaryDispSync.beginResync();
+ mPrimaryDispSync->beginResync();
mEventControlThread->setVsyncEnabled(true);
mPrimaryHWVsyncEnabled = true;
}
@@ -1334,7 +1330,7 @@
Mutex::Autolock _l(mHWVsyncLock);
if (mPrimaryHWVsyncEnabled) {
mEventControlThread->setVsyncEnabled(false);
- mPrimaryDispSync.endResync();
+ mPrimaryDispSync->endResync();
mPrimaryHWVsyncEnabled = false;
}
if (makeUnavailable) {
@@ -1379,7 +1375,7 @@
{ // Scope for the lock
Mutex::Autolock _l(mHWVsyncLock);
if (mPrimaryHWVsyncEnabled) {
- needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
+ needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
}
}
@@ -1506,8 +1502,8 @@
// The present fences returned from vr_hwc are not an accurate
// representation of vsync times.
- mPrimaryDispSync.setIgnorePresentFences(
- getBE().mHwc->isUsingVrComposer() || !hasSyncFramework);
+ mPrimaryDispSync->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() ||
+ !hasSyncFramework);
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
@@ -1770,8 +1766,8 @@
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
getBE().mDisplayTimeline.push(presentFenceTime);
- nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
- nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
+ nsecs_t vsyncPhase = mPrimaryDispSync->computeNextRefresh(0);
+ nsecs_t vsyncInterval = mPrimaryDispSync->getPeriod();
// We use the refreshStartTime which might be sampled a little later than
// when we started doing work for this frame, but that should be okay
@@ -1794,7 +1790,7 @@
});
if (presentFenceTime->isValid()) {
- if (mPrimaryDispSync.addPresentFence(presentFenceTime)) {
+ if (mPrimaryDispSync->addPresentFence(presentFenceTime)) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
@@ -2873,7 +2869,7 @@
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (layer->hasReadyFrame()) {
frameQueued = true;
- if (layer->shouldPresentNow(mPrimaryDispSync)) {
+ if (layer->shouldPresentNow(*mPrimaryDispSync)) {
mLayersWithQueuedFrames.push_back(layer);
} else {
layer->useEmptyDamage();
@@ -3371,9 +3367,8 @@
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
-
if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
- !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
+ !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
return false;
}
return true;
@@ -3966,7 +3961,7 @@
if ((index < numArgs) &&
(args[index] == String16("--dispsync"))) {
index++;
- mPrimaryDispSync.dump(result);
+ mPrimaryDispSync->dump(result);
dumpAll = false;
}
@@ -4559,51 +4554,64 @@
}
status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
- switch (code) {
- case CREATE_CONNECTION:
- case CREATE_DISPLAY:
+#pragma clang diagnostic push
+#pragma clang diagnostic error "-Wswitch-enum"
+ switch (static_cast<ISurfaceComposerTag>(code)) {
+ // These methods should at minimum make sure that the client requested
+ // access to SF.
+ case AUTHENTICATE_SURFACE:
case BOOT_FINISHED:
case CLEAR_ANIMATION_FRAME_STATS:
- case GET_ANIMATION_FRAME_STATS:
- case SET_POWER_MODE:
- case GET_HDR_CAPABILITIES:
+ case CREATE_CONNECTION:
+ case CREATE_DISPLAY:
+ case DESTROY_DISPLAY:
case ENABLE_VSYNC_INJECTIONS:
+ case GET_ACTIVE_COLOR_MODE:
+ case GET_ANIMATION_FRAME_STATS:
+ case GET_HDR_CAPABILITIES:
+ case GET_DISPLAY_COLOR_MODES:
+ case SET_ACTIVE_CONFIG:
+ case SET_ACTIVE_COLOR_MODE:
case INJECT_VSYNC:
- {
- // codes that require permission check
+ case SET_POWER_MODE: {
if (!callingThreadHasUnscopedSurfaceFlingerAccess()) {
IPCThreadState* ipc = IPCThreadState::self();
ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d",
ipc->getCallingPid(), ipc->getCallingUid());
return PERMISSION_DENIED;
}
- break;
- }
- /*
- * Calling setTransactionState is safe, because you need to have been
- * granted a reference to Client* and Handle* to do anything with it.
- *
- * Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
- */
- case SET_TRANSACTION_STATE:
- case CREATE_SCOPED_CONNECTION:
- {
return OK;
}
- case CAPTURE_SCREEN:
- {
- // codes that require permission check
+ case GET_LAYER_DEBUG_INFO: {
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
- if ((uid != AID_GRAPHICS) &&
- !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
- ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid);
+ if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) {
+ ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
}
- break;
+ return OK;
}
- case CAPTURE_LAYERS: {
+ // Used by apps to hook Choreographer to SurfaceFlinger.
+ case CREATE_DISPLAY_EVENT_CONNECTION:
+ // The following calls are currently used by clients that do not
+ // request necessary permissions. However, they do not expose any secret
+ // information, so it is OK to pass them.
+ case GET_ACTIVE_CONFIG:
+ case GET_BUILT_IN_DISPLAY:
+ case GET_DISPLAY_CONFIGS:
+ case GET_DISPLAY_STATS:
+ case GET_SUPPORTED_FRAME_TIMESTAMPS:
+ // Calling setTransactionState is safe, because you need to have been
+ // granted a reference to Client* and Handle* to do anything with it.
+ case SET_TRANSACTION_STATE:
+ // Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
+ case CREATE_SCOPED_CONNECTION: {
+ return OK;
+ }
+ case CAPTURE_LAYERS:
+ case CAPTURE_SCREEN: {
+ // codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
@@ -4612,15 +4620,35 @@
ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
}
- break;
+ return OK;
+ }
+ // The following codes are deprecated and should never be allowed to access SF.
+ case CONNECT_DISPLAY_UNUSED:
+ case CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED: {
+ ALOGE("Attempting to access SurfaceFlinger with unused code: %u", code);
+ return PERMISSION_DENIED;
}
}
- return OK;
+
+ // This code is used for IBinder protocol to interrogate the recipient
+ // side of the transaction for its canonical interface descriptor. We
+ // can let it pass by default.
+ if (code == IBinder::INTERFACE_TRANSACTION) {
+ return OK;
+ }
+ // Numbers from 1000 to 1029 are currently use for backdoors. The code
+ // in onTransact verifies that the user is root, and has access to use SF.
+ if (code >= 1000 && code <= 1029) {
+ ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
+ return OK;
+ }
+ ALOGE("Permission Denial: SurfaceFlinger did not recognize request code: %u", code);
+ return PERMISSION_DENIED;
+#pragma clang diagnostic pop
}
-status_t SurfaceFlinger::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
+status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
status_t credentialCheck = CheckTransactCodeCredentials(code);
if (credentialCheck != OK) {
return credentialCheck;
@@ -4749,7 +4777,7 @@
// Needs to be shifted to proper binder interface when we productize
case 1016: {
n = data.readInt32();
- mPrimaryDispSync.setRefreshSkipCount(n);
+ mPrimaryDispSync->setRefreshSkipCount(n);
return NO_ERROR;
}
case 1017: {
@@ -4850,6 +4878,33 @@
reply->writeBool(getBE().mHwc->isUsingVrComposer());
return NO_ERROR;
}
+ case 1029: {
+ // Code 1029 is an experimental feature that allows applications to
+ // simulate a high frequency panel by setting a multiplier and divisor
+ // on the VSYNC-sf clock. If either the multiplier or divisor are
+ // 0, then the code will set both to 1 to return the VSYNC-sf clock
+ // to it's normal frequency.
+ int multiplier = data.readInt32();
+ int divisor = data.readInt32();
+
+ if ((multiplier == 0) || (divisor == 0)) {
+ multiplier = 1;
+ divisor = 1;
+ }
+
+ if ((multiplier == 1) && (divisor == 1)) {
+ enableHardwareVsync();
+ } else {
+ disableHardwareVsync(true);
+ }
+ getBE().mHwc->getActiveConfig(DisplayDevice::DISPLAY_PRIMARY)
+ ->scalePanelFrequency(multiplier, divisor);
+ mPrimaryDispSync->scalePeriod(multiplier, divisor);
+
+ ATRACE_INT("PeriodMultiplier", multiplier);
+ ATRACE_INT("PeriodDivisor", divisor);
+ return NO_ERROR;
+ }
}
}
return err;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index eaaf742..12f4185 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -853,7 +853,7 @@
// these are thread safe
mutable std::unique_ptr<MessageQueue> mEventQueue{std::make_unique<impl::MessageQueue>()};
FrameTracker mAnimFrameTracker;
- DispSync mPrimaryDispSync;
+ std::unique_ptr<DispSync> mPrimaryDispSync;
int mPrimaryDisplayOrientation = DisplayState::eOrientationDefault;
// protected by mDestroyedLayerLock;
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index c511c5e..604aa7d 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -17,6 +17,7 @@
defaults: ["surfaceflinger_defaults"],
test_suites: ["device-tests"],
srcs: [
+ "Credentials_test.cpp",
"Stress_test.cpp",
"SurfaceInterceptor_test.cpp",
"Transaction_test.cpp",
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
new file mode 100644
index 0000000..9ccada5
--- /dev/null
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -0,0 +1,300 @@
+#include <algorithm>
+#include <functional>
+#include <limits>
+#include <ostream>
+
+#include <gtest/gtest.h>
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+
+#include <private/android_filesystem_config.h>
+#include <private/gui/ComposerService.h>
+
+#include <ui/DisplayInfo.h>
+#include <utils/String8.h>
+
+namespace android {
+
+using Transaction = SurfaceComposerClient::Transaction;
+
+namespace {
+const String8 DISPLAY_NAME("Credentials Display Test");
+const String8 SURFACE_NAME("Test Surface Name");
+const int32_t MIN_LAYER_Z = 0;
+const int32_t MAX_LAYER_Z = std::numeric_limits<int32_t>::max();
+const uint32_t ROTATION = 0;
+const float FRAME_SCALE = 1.0f;
+} // namespace
+
+/**
+ * This class tests the CheckCredentials method in SurfaceFlinger.
+ * Methods like EnableVsyncInjections and InjectVsync are not tested since they do not
+ * return anything meaningful.
+ */
+class CredentialsTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ // Start the tests as root.
+ seteuid(AID_ROOT);
+
+ ASSERT_NO_FATAL_FAILURE(initClient());
+ }
+
+ void TearDown() override {
+ mComposerClient->dispose();
+ mBGSurfaceControl.clear();
+ mComposerClient.clear();
+ // Finish the tests as root.
+ seteuid(AID_ROOT);
+ }
+
+ sp<IBinder> mDisplay;
+ sp<IBinder> mVirtualDisplay;
+ sp<SurfaceComposerClient> mComposerClient;
+ sp<SurfaceControl> mBGSurfaceControl;
+ sp<SurfaceControl> mVirtualSurfaceControl;
+
+ void initClient() {
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+ }
+
+ void setupBackgroundSurface() {
+ mDisplay = SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ DisplayInfo info;
+ SurfaceComposerClient::getDisplayInfo(mDisplay, &info);
+ const ssize_t displayWidth = info.w;
+ const ssize_t displayHeight = info.h;
+
+ // Background surface
+ mBGSurfaceControl =
+ mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mBGSurfaceControl != nullptr);
+ ASSERT_TRUE(mBGSurfaceControl->isValid());
+
+ Transaction t;
+ t.setDisplayLayerStack(mDisplay, 0);
+ ASSERT_EQ(NO_ERROR,
+ t.setLayer(mBGSurfaceControl, INT_MAX - 3).show(mBGSurfaceControl).apply());
+ }
+
+ void setupVirtualDisplay() {
+ mVirtualDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
+ const ssize_t displayWidth = 100;
+ const ssize_t displayHeight = 100;
+
+ // Background surface
+ mVirtualSurfaceControl =
+ mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mVirtualSurfaceControl != nullptr);
+ ASSERT_TRUE(mVirtualSurfaceControl->isValid());
+
+ Transaction t;
+ t.setDisplayLayerStack(mVirtualDisplay, 0);
+ ASSERT_EQ(NO_ERROR,
+ t.setLayer(mVirtualSurfaceControl, INT_MAX - 3)
+ .show(mVirtualSurfaceControl)
+ .apply());
+ }
+
+ /**
+ * Sets UID to imitate Graphic's process.
+ */
+ void setGraphicsUID() {
+ seteuid(AID_ROOT);
+ seteuid(AID_GRAPHICS);
+ }
+
+ /**
+ * Sets UID to imitate System's process.
+ */
+ void setSystemUID() {
+ seteuid(AID_ROOT);
+ seteuid(AID_SYSTEM);
+ }
+
+ /**
+ * Sets UID to imitate a process that doesn't have any special privileges in
+ * our code.
+ */
+ void setBinUID() {
+ seteuid(AID_ROOT);
+ seteuid(AID_BIN);
+ }
+
+ /**
+ * Template function the check a condition for different types of users: root
+ * graphics, system, and non-supported user. Root, graphics, and system should
+ * always equal privilegedValue, and non-supported user should equal unprivilegedValue.
+ */
+ template <typename T>
+ void checkWithPrivileges(std::function<T()> condition, T privilegedValue, T unprivilegedValue) {
+ // Check with root.
+ seteuid(AID_ROOT);
+ ASSERT_EQ(privilegedValue, condition());
+
+ // Check as a Graphics user.
+ setGraphicsUID();
+ ASSERT_EQ(privilegedValue, condition());
+
+ // Check as a system user.
+ setSystemUID();
+ ASSERT_EQ(privilegedValue, condition());
+
+ // Check as a non-supported user.
+ setBinUID();
+ ASSERT_EQ(unprivilegedValue, condition());
+ }
+};
+
+TEST_F(CredentialsTest, ClientInitTest) {
+ // Root can init can init the client.
+ ASSERT_NO_FATAL_FAILURE(initClient());
+
+ // Graphics can init the client.
+ setGraphicsUID();
+ ASSERT_NO_FATAL_FAILURE(initClient());
+
+ // System can init the client.
+ setSystemUID();
+ ASSERT_NO_FATAL_FAILURE(initClient());
+
+ // No one else can init the client.
+ setBinUID();
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_INIT, mComposerClient->initCheck());
+}
+
+TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) {
+ std::function<bool()> condition = [=]() {
+ sp<IBinder> display(
+ SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ return (display != nullptr);
+ };
+ // Anyone can access display information.
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true));
+}
+
+TEST_F(CredentialsTest, AllowedGetterMethodsTest) {
+ // The following methods are tested with a UID that is not root, graphics,
+ // or system, to show that anyone can access them.
+ setBinUID();
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ ASSERT_TRUE(display != nullptr);
+
+ DisplayInfo info;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+
+ Vector<DisplayInfo> configs;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
+
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveConfig(display));
+
+ ASSERT_NE(static_cast<ui::ColorMode>(BAD_VALUE),
+ SurfaceComposerClient::getActiveColorMode(display));
+}
+
+TEST_F(CredentialsTest, GetDisplayColorModesTest) {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ std::function<status_t()> condition = [=]() {
+ Vector<ui::ColorMode> outColorModes;
+ return SurfaceComposerClient::getDisplayColorModes(display, &outColorModes);
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
+}
+
+TEST_F(CredentialsTest, SetActiveConfigTest) {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ std::function<status_t()> condition = [=]() {
+ return SurfaceComposerClient::setActiveConfig(display, 0);
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
+}
+
+TEST_F(CredentialsTest, SetActiveColorModeTest) {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ std::function<status_t()> condition = [=]() {
+ return SurfaceComposerClient::setActiveColorMode(display, ui::ColorMode::NATIVE);
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
+}
+
+TEST_F(CredentialsTest, CreateSurfaceTest) {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ DisplayInfo info;
+ SurfaceComposerClient::getDisplayInfo(display, &info);
+ const ssize_t displayWidth = info.w;
+ const ssize_t displayHeight = info.h;
+
+ std::function<bool()> condition = [=]() {
+ mBGSurfaceControl =
+ mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ return mBGSurfaceControl != nullptr && mBGSurfaceControl->isValid();
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
+}
+
+TEST_F(CredentialsTest, CreateDisplayTest) {
+ std::function<bool()> condition = [=]() {
+ sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
+ return testDisplay.get() != nullptr;
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
+
+ condition = [=]() {
+ sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
+ return testDisplay.get() != nullptr;
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
+}
+
+TEST_F(CredentialsTest, DISABLED_DestroyDisplayTest) {
+ setupVirtualDisplay();
+
+ DisplayInfo info;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info));
+ SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
+ // This test currently fails. TODO(b/112002626): Find a way to properly create
+ // a display in the test environment, so that destroy display can remove it.
+ ASSERT_EQ(NAME_NOT_FOUND, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info));
+}
+
+TEST_F(CredentialsTest, CaptureTest) {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ std::function<status_t()> condition = [=]() {
+ sp<GraphicBuffer> outBuffer;
+ return ScreenshotClient::capture(display, Rect(), 0 /*reqWidth*/, 0 /*reqHeight*/,
+ MIN_LAYER_Z, MAX_LAYER_Z, false, ROTATION, &outBuffer);
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
+}
+
+TEST_F(CredentialsTest, CaptureLayersTest) {
+ setupBackgroundSurface();
+ sp<GraphicBuffer> outBuffer;
+ std::function<status_t()> condition = [=]() {
+ sp<GraphicBuffer> outBuffer;
+ return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(), Rect(), FRAME_SCALE,
+ &outBuffer);
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
+}
+
+/**
+ * Test for methods accessible directly through SurfaceFlinger:
+ */
+TEST_F(CredentialsTest, AuthenticateSurfaceTextureTest) {
+ setupBackgroundSurface();
+ sp<IGraphicBufferProducer> producer =
+ mBGSurfaceControl->getSurface()->getIGraphicBufferProducer();
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+ std::function<bool()> condition = [=]() { return sf->authenticateSurfaceTexture(producer); };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 731e628..1319e12 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:SurfaceInterceptorTest.*:-CropLatchingTest.FinalCropLatchingBufferOldSize"
+ "filter": "CredentialsTest.*:LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:SurfaceInterceptorTest.*:-CropLatchingTest.FinalCropLatchingBufferOldSize"
}
}
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 95c54b8..8f1f5e5 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -27,6 +27,7 @@
"mock/DisplayHardware/MockPowerAdvisor.cpp",
"mock/gui/MockGraphicBufferConsumer.cpp",
"mock/gui/MockGraphicBufferProducer.cpp",
+ "mock/MockDispSync.cpp",
"mock/MockEventControlThread.cpp",
"mock/MockEventThread.cpp",
"mock/MockMessageQueue.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 58d3879..508875d 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -25,6 +25,7 @@
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "mock/MockDispSync.h"
#include "mock/MockEventControlThread.h"
#include "mock/MockEventThread.h"
#include "mock/MockMessageQueue.h"
@@ -119,6 +120,7 @@
Hwc2::mock::Composer* mComposer = nullptr;
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
+ mock::DispSync* mPrimaryDispSync = new mock::DispSync();
// These mocks are created only when expected to be created via a factory.
sp<mock::GraphicBufferConsumer> mConsumer;
@@ -154,6 +156,7 @@
mFlinger.mutableEventQueue().reset(mMessageQueue);
mFlinger.setupRenderEngine(std::unique_ptr<RE::RenderEngine>(mRenderEngine));
mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
+ mFlinger.mutablePrimaryDispSync().reset(mPrimaryDispSync);
injectMockComposer(0);
}
@@ -961,6 +964,9 @@
// The call clears the current render engine surface
EXPECT_CALL(*mRenderEngine, resetCurrentSurface());
+ // The call ends any display resyncs
+ EXPECT_CALL(*mPrimaryDispSync, endResync()).Times(1);
+
// --------------------------------------------------------------------
// Invocation
@@ -2400,6 +2406,24 @@
}
};
+struct DispSyncIsSupportedVariant {
+ static void setupBeginResyncCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mPrimaryDispSync, reset()).Times(1);
+ EXPECT_CALL(*test->mPrimaryDispSync, setPeriod(DEFAULT_REFRESH_RATE)).Times(1);
+ EXPECT_CALL(*test->mPrimaryDispSync, beginResync()).Times(1);
+ }
+
+ static void setupEndResyncCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mPrimaryDispSync, endResync()).Times(1);
+ }
+};
+
+struct DispSyncNotSupportedVariant {
+ static void setupBeginResyncCallExpectations(DisplayTransactionTest* /* test */) {}
+
+ static void setupEndResyncCallExpectations(DisplayTransactionTest* /* test */) {}
+};
+
// --------------------------------------------------------------------
// Note:
//
@@ -2421,6 +2445,7 @@
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+ Case::DispSync::setupBeginResyncCallExpectations(test);
Case::setupRepaintEverythingCallExpectations(test);
}
@@ -2450,6 +2475,7 @@
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+ Case::DispSync::setupEndResyncCallExpectations(test);
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
}
@@ -2485,6 +2511,7 @@
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+ Case::DispSync::setupBeginResyncCallExpectations(test);
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
}
};
@@ -2503,6 +2530,7 @@
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+ Case::DispSync::setupBeginResyncCallExpectations(test);
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
}
};
@@ -2512,6 +2540,7 @@
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+ Case::DispSync::setupEndResyncCallExpectations(test);
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
}
};
@@ -2534,11 +2563,12 @@
// --------------------------------------------------------------------
template <typename DisplayVariant, typename DozeVariant, typename EventThreadVariant,
- typename TransitionVariant>
+ typename DispSyncVariant, typename TransitionVariant>
struct DisplayPowerCase {
using Display = DisplayVariant;
using Doze = DozeVariant;
using EventThread = EventThreadVariant;
+ using DispSync = DispSyncVariant;
using Transition = TransitionVariant;
static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, int mode) {
@@ -2586,15 +2616,16 @@
// In addition to having event thread support, we emulate doze support.
template <typename TransitionVariant>
using PrimaryDisplayPowerCase = DisplayPowerCase<PrimaryDisplayVariant, DozeIsSupportedVariant,
- EventThreadIsSupportedVariant, TransitionVariant>;
+ EventThreadIsSupportedVariant,
+ DispSyncIsSupportedVariant, TransitionVariant>;
// A sample configuration for the external display.
// In addition to not having event thread support, we emulate not having doze
// support.
template <typename TransitionVariant>
-using ExternalDisplayPowerCase =
- DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant,
- EventThreadNotSupportedVariant, TransitionVariant>;
+using ExternalDisplayPowerCase = DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant,
+ EventThreadNotSupportedVariant,
+ DispSyncNotSupportedVariant, TransitionVariant>;
class SetPowerModeInternalTest : public DisplayTransactionTest {
public:
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 5031148..9df4264 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -126,6 +126,7 @@
auto& mutableInterceptor() { return mFlinger->mInterceptor; }
auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
+ auto& mutablePrimaryDispSync() { return mFlinger->mPrimaryDispSync; }
auto& mutablePrimaryHWVsyncEnabled() { return mFlinger->mPrimaryHWVsyncEnabled; }
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
@@ -144,6 +145,7 @@
mutableEventQueue().reset();
mutableEventThread().reset();
mutableInterceptor().reset();
+ mutablePrimaryDispSync().reset();
mFlinger->getBE().mHwc.reset();
mFlinger->getBE().mRenderEngine.reset();
}
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
new file mode 100644
index 0000000..2f7e5ea
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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 "mock/MockDispSync.h"
+
+namespace android {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+DispSync::DispSync() = default;
+DispSync::~DispSync() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
new file mode 100644
index 0000000..cd8d943
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include <utils/String8.h>
+#include "DispSync.h"
+
+namespace android {
+namespace mock {
+
+class DispSync : public android::DispSync {
+public:
+ DispSync();
+ ~DispSync() override;
+
+ MOCK_METHOD0(reset, void());
+ MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr<FenceTime>&));
+ MOCK_METHOD0(beginResync, void());
+ MOCK_METHOD1(addResyncSample, bool(nsecs_t));
+ MOCK_METHOD0(endResync, void());
+ MOCK_METHOD1(setPeriod, void(nsecs_t));
+ MOCK_METHOD2(scalePeriod, void(uint32_t, uint32_t));
+ MOCK_METHOD0(getPeriod, nsecs_t());
+ MOCK_METHOD1(setRefreshSkipCount, void(int));
+ MOCK_METHOD3(addEventListener, status_t(const char*, nsecs_t, Callback*));
+ MOCK_METHOD1(removeEventListener, status_t(Callback*));
+ MOCK_METHOD2(changePhaseOffset, status_t(Callback*, nsecs_t));
+ MOCK_CONST_METHOD1(computeNextRefresh, nsecs_t(int));
+ MOCK_METHOD1(setIgnorePresentFences, void(bool));
+
+ MOCK_CONST_METHOD1(dump, void(String8&));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
index a98bece..200f214 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
@@ -16,6 +16,8 @@
#include "mock/RenderEngine/MockRenderEngine.h"
+#include <ui/Region.h>
+
namespace android {
namespace RE {
namespace mock {
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index 7caf864..7814d32 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -37,6 +37,8 @@
MOCK_METHOD0(createImage, std::unique_ptr<RE::Image>());
MOCK_CONST_METHOD0(primeCache, void());
MOCK_METHOD1(dump, void(String8&));
+ MOCK_CONST_METHOD0(useNativeFenceSync, bool());
+ MOCK_CONST_METHOD0(useWaitSync, bool());
MOCK_CONST_METHOD0(isCurrent, bool());
MOCK_METHOD1(setCurrentSurface, bool(const RE::Surface&));
MOCK_METHOD0(resetCurrentSurface, void());
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 6122846..499a8f6 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -13,11 +13,12 @@
// limitations under the License.
sourceFiles = [
+ "buffer_channel.cpp",
"buffer_hub.cpp",
+ "buffer_node.cpp",
"bufferhubd.cpp",
"consumer_channel.cpp",
"producer_channel.cpp",
- "detached_buffer_channel.cpp",
"consumer_queue_channel.cpp",
"producer_queue_channel.cpp",
]
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
new file mode 100644
index 0000000..2150d62
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -0,0 +1,206 @@
+#include "buffer_channel.h"
+#include "producer_channel.h"
+
+using android::pdx::BorrowedHandle;
+using android::pdx::ErrorStatus;
+using android::pdx::Message;
+using android::pdx::RemoteChannelHandle;
+using android::pdx::Status;
+using android::pdx::rpc::DispatchRemoteMethod;
+
+namespace android {
+namespace dvr {
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+ int channel_id, IonBuffer buffer,
+ IonBuffer metadata_buffer,
+ size_t user_metadata_size)
+ : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
+ buffer_node_(std::make_shared<BufferNode>(
+ std::move(buffer), std::move(metadata_buffer), user_metadata_size)),
+ buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
+ buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+ uint32_t width, uint32_t height,
+ uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t user_metadata_size)
+ : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
+ buffer_node_(std::make_shared<BufferNode>(
+ width, height, layer_count, format, usage, user_metadata_size)),
+ buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
+ buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+ int channel_id,
+ std::shared_ptr<BufferNode> buffer_node,
+ uint64_t buffer_state_bit)
+ : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
+ buffer_node_(buffer_node),
+ buffer_state_bit_(buffer_state_bit) {
+ buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::~BufferChannel() {
+ ALOGD_IF(TRACE, "BufferChannel::~BufferChannel: channel_id=%d buffer_id=%d.",
+ channel_id(), buffer_id());
+ Hangup();
+}
+
+BufferHubChannel::BufferInfo BufferChannel::GetBufferInfo() const {
+ return BufferInfo(
+ buffer_id(), /*consumer_count=*/0, buffer_node_->buffer().width(),
+ buffer_node_->buffer().height(), buffer_node_->buffer().layer_count(),
+ buffer_node_->buffer().format(), buffer_node_->buffer().usage(),
+ /*pending_count=*/0, /*state=*/0, /*signaled_mask=*/0,
+ /*index=*/0);
+}
+
+void BufferChannel::HandleImpulse(Message& /*message*/) {
+ ATRACE_NAME("BufferChannel::HandleImpulse");
+}
+
+bool BufferChannel::HandleMessage(Message& message) {
+ ATRACE_NAME("BufferChannel::HandleMessage");
+ switch (message.GetOp()) {
+ case DetachedBufferRPC::Import::Opcode:
+ DispatchRemoteMethod<DetachedBufferRPC::Import>(
+ *this, &BufferChannel::OnImport, message);
+ return true;
+
+ case DetachedBufferRPC::Duplicate::Opcode:
+ DispatchRemoteMethod<DetachedBufferRPC::Duplicate>(
+ *this, &BufferChannel::OnDuplicate, message);
+ return true;
+
+ case DetachedBufferRPC::Promote::Opcode:
+ DispatchRemoteMethod<DetachedBufferRPC::Promote>(
+ *this, &BufferChannel::OnPromote, message);
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+Status<BufferDescription<BorrowedHandle>> BufferChannel::OnImport(
+ Message& /*message*/) {
+ ATRACE_NAME("BufferChannel::OnImport");
+ ALOGD_IF(TRACE, "BufferChannel::OnImport: buffer=%d.",
+ buffer_id());
+
+ return BufferDescription<BorrowedHandle>{buffer_node_->buffer(),
+ buffer_node_->metadata_buffer(),
+ buffer_id(),
+ channel_id(),
+ buffer_state_bit_,
+ BorrowedHandle{},
+ BorrowedHandle{}};
+}
+
+Status<RemoteChannelHandle> BufferChannel::OnDuplicate(
+ Message& message) {
+ ATRACE_NAME("BufferChannel::OnDuplicate");
+ ALOGD_IF(TRACE, "BufferChannel::OnDuplicate: buffer=%d.",
+ buffer_id());
+
+ int channel_id;
+ auto status = message.PushChannel(0, nullptr, &channel_id);
+ if (!status) {
+ ALOGE(
+ "BufferChannel::OnDuplicate: Failed to push buffer channel: %s",
+ status.GetErrorMessage().c_str());
+ return ErrorStatus(ENOMEM);
+ }
+
+ // Try find the next buffer state bit which has not been claimed by any
+ // other buffers yet.
+ uint64_t buffer_state_bit =
+ BufferHubDefs::FindNextClearedBit(buffer_node_->active_buffer_bit_mask() |
+ BufferHubDefs::kProducerStateBit);
+ if (buffer_state_bit == 0ULL) {
+ ALOGE(
+ "BufferChannel::OnDuplicate: reached the maximum mumber of channels "
+ "per buffer node: 63.");
+ return ErrorStatus(E2BIG);
+ }
+
+ auto channel =
+ std::shared_ptr<BufferChannel>(new BufferChannel(
+ service(), buffer_id(), channel_id, buffer_node_, buffer_state_bit));
+ if (!channel) {
+ ALOGE("BufferChannel::OnDuplicate: Invalid buffer.");
+ return ErrorStatus(EINVAL);
+ }
+
+ const auto channel_status =
+ service()->SetChannel(channel_id, std::move(channel));
+ if (!channel_status) {
+ // Technically, this should never fail, as we just pushed the channel. Note
+ // that LOG_FATAL will be stripped out in non-debug build.
+ LOG_FATAL(
+ "BufferChannel::OnDuplicate: Failed to set new buffer channel: %s.",
+ channel_status.GetErrorMessage().c_str());
+ }
+
+ return status;
+}
+
+Status<RemoteChannelHandle> BufferChannel::OnPromote(
+ Message& message) {
+ ATRACE_NAME("BufferChannel::OnPromote");
+ ALOGD_IF(TRACE, "BufferChannel::OnPromote: buffer_id=%d", buffer_id());
+
+ // Check whether this is the channel exclusive owner of the buffer_node_.
+ if (buffer_state_bit_ != buffer_node_->active_buffer_bit_mask()) {
+ ALOGE(
+ "BufferChannel::OnPromote: Cannot promote this BufferChannel as its "
+ "BufferNode is shared between multiple channels. This channel's state "
+ "bit=0x%" PRIx64 ", acitve_buffer_bit_mask=0x%" PRIx64 ".",
+ buffer_state_bit_, buffer_node_->active_buffer_bit_mask());
+ return ErrorStatus(EINVAL);
+ }
+
+ // Note that the new ProducerChannel will have different channel_id, but
+ // inherits the buffer_id from the DetachedBuffer.
+ int channel_id;
+ auto status = message.PushChannel(0, nullptr, &channel_id);
+ if (!status) {
+ ALOGE(
+ "BufferChannel::OnPromote: Failed to push ProducerChannel: %s.",
+ status.GetErrorMessage().c_str());
+ return ErrorStatus(ENOMEM);
+ }
+
+ IonBuffer buffer = std::move(buffer_node_->buffer());
+ IonBuffer metadata_buffer = std::move(buffer_node_->metadata_buffer());
+ size_t user_metadata_size = buffer_node_->user_metadata_size();
+
+ std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
+ service(), buffer_id(), channel_id, std::move(buffer),
+ std::move(metadata_buffer), user_metadata_size);
+ if (!channel) {
+ ALOGE(
+ "BufferChannel::OnPromote: Failed to create ProducerChannel from a "
+ "BufferChannel, buffer_id=%d.",
+ buffer_id());
+ }
+
+ const auto channel_status =
+ service()->SetChannel(channel_id, std::move(channel));
+ if (!channel_status) {
+ // Technically, this should never fail, as we just pushed the channel. Note
+ // that LOG_FATAL will be stripped out in non-debug build.
+ LOG_FATAL(
+ "BufferChannel::OnPromote: Failed to set new producer buffer channel: "
+ "%s.",
+ channel_status.GetErrorMessage().c_str());
+ }
+
+ return status;
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/services/vr/bufferhubd/buffer_channel.h b/services/vr/bufferhubd/buffer_channel.h
new file mode 100644
index 0000000..ac99a73
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_channel.h
@@ -0,0 +1,66 @@
+#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
+#define ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
+
+#include "buffer_hub.h"
+#include "buffer_node.h"
+
+#include <pdx/channel_handle.h>
+#include <pdx/file_handle.h>
+
+namespace android {
+namespace dvr {
+
+class BufferChannel : public BufferHubChannel {
+ public:
+ ~BufferChannel() override;
+
+ template <typename... Args>
+ static std::unique_ptr<BufferChannel> Create(Args&&... args) {
+ auto buffer = std::unique_ptr<BufferChannel>(
+ new BufferChannel(std::forward<Args>(args)...));
+ return buffer->IsValid() ? std::move(buffer) : nullptr;
+ }
+
+ // Returns whether the object holds a valid graphic buffer.
+ bool IsValid() const {
+ return buffer_node_ != nullptr && buffer_node_->IsValid();
+ }
+
+ // Captures buffer info for use by BufferHubService::DumpState().
+ BufferInfo GetBufferInfo() const override;
+
+ bool HandleMessage(pdx::Message& message) override;
+ void HandleImpulse(pdx::Message& message) override;
+
+ private:
+ // Creates a detached buffer from existing IonBuffers.
+ BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
+ IonBuffer buffer, IonBuffer metadata_buffer,
+ size_t user_metadata_size);
+
+ // Allocates a new detached buffer.
+ BufferChannel(BufferHubService* service, int buffer_id, uint32_t width,
+ uint32_t height, uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t user_metadata_size);
+
+ // Creates a detached buffer from an existing BufferNode.
+ BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
+ std::shared_ptr<BufferNode> buffer_node,
+ uint64_t buffer_state_bit);
+
+ pdx::Status<BufferDescription<pdx::BorrowedHandle>> OnImport(
+ pdx::Message& message);
+ pdx::Status<pdx::RemoteChannelHandle> OnDuplicate(pdx::Message& message);
+ pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
+
+ // The concrete implementation of the Buffer object.
+ std::shared_ptr<BufferNode> buffer_node_;
+
+ // The state bit of this buffer. Must be one the lower 63 bits.
+ uint64_t buffer_state_bit_;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index e57c8ed..c0ee31b 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -13,8 +13,8 @@
#include <pdx/default_transport/service_endpoint.h>
#include <private/dvr/bufferhub_rpc.h>
+#include "buffer_channel.h"
#include "consumer_channel.h"
-#include "detached_buffer_channel.h"
#include "producer_channel.h"
#include "producer_queue_channel.h"
@@ -267,7 +267,7 @@
return {};
case DetachedBufferRPC::Promote::Opcode:
- // In addition to the message handler in the DetachedBufferChannel's
+ // In addition to the message handler in the BufferChannel's
// HandleMessage method, we also need to invalid the channel. Note that
// this has to be done after HandleMessage returns to make sure the IPC
// request has went back to the client first.
@@ -332,9 +332,9 @@
return ErrorStatus(EALREADY);
}
- std::unique_ptr<DetachedBufferChannel> channel =
- DetachedBufferChannel::Create(this, buffer_id, width, height, layer_count,
- format, usage, user_metadata_size);
+ std::unique_ptr<BufferChannel> channel =
+ BufferChannel::Create(this, buffer_id, width, height, layer_count, format,
+ usage, user_metadata_size);
if (!channel) {
ALOGE(
"BufferHubService::OnCreateDetachedBuffer: Failed to allocate buffer, "
diff --git a/services/vr/bufferhubd/buffer_node.cpp b/services/vr/bufferhubd/buffer_node.cpp
new file mode 100644
index 0000000..de22bba
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_node.cpp
@@ -0,0 +1,53 @@
+#include "buffer_node.h"
+
+#include <private/dvr/buffer_hub_defs.h>
+
+namespace android {
+namespace dvr {
+
+BufferNode::BufferNode(IonBuffer buffer, IonBuffer metadata_buffer,
+ size_t user_metadata_size)
+ : buffer_(std::move(buffer)),
+ metadata_buffer_(std::move(metadata_buffer)),
+ user_metadata_size_(user_metadata_size) {}
+
+// Allocates a new BufferNode.
+BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
+ uint32_t format, uint64_t usage,
+ size_t user_metadata_size)
+ : user_metadata_size_(user_metadata_size) {
+ // The size the of metadata buffer is used as the "width" parameter during
+ // allocation. Thus it cannot overflow uint32_t.
+ if (user_metadata_size_ >= (std::numeric_limits<uint32_t>::max() -
+ BufferHubDefs::kMetadataHeaderSize)) {
+ ALOGE(
+ "DetachedBufferChannel::DetachedBufferChannel: metadata size too big.");
+ return;
+ }
+
+ if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
+ ALOGE(
+ "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
+ "buffer: %s",
+ strerror(-ret));
+ return;
+ }
+
+ // Buffer metadata has two parts: 1) a fixed sized metadata header; and 2)
+ // user requested metadata.
+ const size_t size = BufferHubDefs::kMetadataHeaderSize + user_metadata_size_;
+ if (int ret = metadata_buffer_.Alloc(size,
+ /*height=*/1,
+ /*layer_count=*/1,
+ BufferHubDefs::kMetadataFormat,
+ BufferHubDefs::kMetadataUsage)) {
+ ALOGE(
+ "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
+ "metadata: %s",
+ strerror(-ret));
+ return;
+ }
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/services/vr/bufferhubd/buffer_node.h b/services/vr/bufferhubd/buffer_node.h
new file mode 100644
index 0000000..4bcf4e3
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_node.h
@@ -0,0 +1,55 @@
+#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
+#define ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
+
+#include <private/dvr/ion_buffer.h>
+
+namespace android {
+namespace dvr {
+
+class BufferNode {
+ public:
+ // Creates a BufferNode from existing IonBuffers, i.e. creating from an
+ // existing ProducerChannel.
+ BufferNode(IonBuffer buffer, IonBuffer metadata_buffer,
+ size_t user_metadata_size);
+
+ // Allocates a new BufferNode.
+ BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
+ uint32_t format, uint64_t usage, size_t user_metadata_size);
+
+ // Returns whether the object holds a valid graphic buffer.
+ bool IsValid() const {
+ return buffer_.IsValid() && metadata_buffer_.IsValid();
+ }
+
+ size_t user_metadata_size() const { return user_metadata_size_; }
+ uint64_t active_buffer_bit_mask() const { return active_buffer_bit_mask_; }
+ void set_buffer_state_bit(uint64_t buffer_state_bit) {
+ active_buffer_bit_mask_ |= buffer_state_bit;
+ }
+
+ // Used to take out IonBuffers.
+ IonBuffer& buffer() { return buffer_; }
+ IonBuffer& metadata_buffer() { return metadata_buffer_; }
+
+ // Used to access IonBuffers.
+ const IonBuffer& buffer() const { return buffer_; }
+ const IonBuffer& metadata_buffer() const { return metadata_buffer_; }
+
+ private:
+ // Gralloc buffer handles.
+ IonBuffer buffer_;
+ IonBuffer metadata_buffer_;
+
+ // Size of user requested metadata.
+ const size_t user_metadata_size_;
+
+ // All active buffer bits. Valid bits are the lower 63 bits, while the
+ // highest bit is reserved for the exclusive writing and should not be set.
+ uint64_t active_buffer_bit_mask_ = 0ULL;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
diff --git a/services/vr/bufferhubd/detached_buffer_channel.cpp b/services/vr/bufferhubd/detached_buffer_channel.cpp
deleted file mode 100644
index 3061805..0000000
--- a/services/vr/bufferhubd/detached_buffer_channel.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-#include "detached_buffer_channel.h"
-#include "producer_channel.h"
-
-using android::pdx::BorrowedHandle;
-using android::pdx::ErrorStatus;
-using android::pdx::Message;
-using android::pdx::RemoteChannelHandle;
-using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
-
-namespace android {
-namespace dvr {
-
-DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
- int buffer_id, int channel_id,
- IonBuffer buffer,
- IonBuffer metadata_buffer,
- size_t user_metadata_size)
- : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
- buffer_(std::move(buffer)),
- metadata_buffer_(std::move(metadata_buffer)),
- user_metadata_size_(user_metadata_size) {
-}
-
-DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
- int buffer_id, uint32_t width,
- uint32_t height,
- uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t user_metadata_size)
- : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
- user_metadata_size_(user_metadata_size) {
- // The size the of metadata buffer is used as the "width" parameter during
- // allocation. Thus it cannot overflow uint32_t.
- if (user_metadata_size_ >= (std::numeric_limits<uint32_t>::max() -
- BufferHubDefs::kMetadataHeaderSize)) {
- ALOGE(
- "DetachedBufferChannel::DetachedBufferChannel: metadata size too big.");
- return;
- }
-
- if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
- ALOGE(
- "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
- "buffer: %s",
- strerror(-ret));
- return;
- }
-
- // Buffer metadata has two parts: 1) a fixed sized metadata header; and 2)
- // user requested metadata.
- const size_t size = BufferHubDefs::kMetadataHeaderSize + user_metadata_size_;
- if (int ret = metadata_buffer_.Alloc(size,
- /*height=*/1,
- /*layer_count=*/1,
- BufferHubDefs::kMetadataFormat,
- BufferHubDefs::kMetadataUsage)) {
- ALOGE(
- "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
- "metadata: %s",
- strerror(-ret));
- return;
- }
-}
-
-DetachedBufferChannel::~DetachedBufferChannel() {
- ALOGD_IF(TRACE,
- "DetachedBufferChannel::~DetachedBufferChannel: channel_id=%d "
- "buffer_id=%d.",
- channel_id(), buffer_id());
- Hangup();
-}
-
-BufferHubChannel::BufferInfo DetachedBufferChannel::GetBufferInfo() const {
- return BufferInfo(buffer_id(), /*consumer_count=*/0, buffer_.width(),
- buffer_.height(), buffer_.layer_count(), buffer_.format(),
- buffer_.usage(), /*pending_count=*/0, /*state=*/0,
- /*signaled_mask=*/0, /*index=*/0);
-}
-
-void DetachedBufferChannel::HandleImpulse(Message& /*message*/) {
- ATRACE_NAME("DetachedBufferChannel::HandleImpulse");
-}
-
-bool DetachedBufferChannel::HandleMessage(Message& message) {
- ATRACE_NAME("DetachedBufferChannel::HandleMessage");
- switch (message.GetOp()) {
- case DetachedBufferRPC::Import::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Import>(
- *this, &DetachedBufferChannel::OnImport, message);
- return true;
-
- case DetachedBufferRPC::Promote::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Promote>(
- *this, &DetachedBufferChannel::OnPromote, message);
- return true;
-
- default:
- return false;
- }
-}
-
-Status<BufferDescription<BorrowedHandle>> DetachedBufferChannel::OnImport(
- Message& /*message*/) {
- ATRACE_NAME("DetachedBufferChannel::OnGetBuffer");
- ALOGD_IF(TRACE, "DetachedBufferChannel::OnGetBuffer: buffer=%d.",
- buffer_id());
-
- return BufferDescription<BorrowedHandle>{buffer_,
- metadata_buffer_,
- buffer_id(),
- channel_id(),
- /*buffer_state_bit=*/0,
- BorrowedHandle{},
- BorrowedHandle{}};
-}
-
-Status<RemoteChannelHandle> DetachedBufferChannel::OnPromote(
- Message& message) {
- ATRACE_NAME("DetachedBufferChannel::OnPromote");
- ALOGD_IF(TRACE, "DetachedBufferChannel::OnPromote: buffer_id=%d",
- buffer_id());
-
- // Note that the new ProducerChannel will have different channel_id, but
- // inherits the buffer_id from the DetachedBuffer.
- int channel_id;
- auto status = message.PushChannel(0, nullptr, &channel_id);
- if (!status) {
- ALOGE(
- "DetachedBufferChannel::OnPromote: Failed to push ProducerChannel: %s.",
- status.GetErrorMessage().c_str());
- return ErrorStatus(ENOMEM);
- }
-
- std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
- service(), buffer_id(), channel_id, std::move(buffer_),
- std::move(metadata_buffer_), user_metadata_size_);
- if (!channel) {
- ALOGE(
- "DetachedBufferChannel::OnPromote: Failed to create ProducerChannel "
- "from a DetachedBufferChannel, buffer_id=%d.",
- buffer_id());
- }
-
- const auto channel_status =
- service()->SetChannel(channel_id, std::move(channel));
- if (!channel_status) {
- // Technically, this should never fail, as we just pushed the channel. Note
- // that LOG_FATAL will be stripped out in non-debug build.
- LOG_FATAL(
- "DetachedBufferChannel::OnPromote: Failed to set new producer buffer "
- "channel: %s.",
- channel_status.GetErrorMessage().c_str());
- }
-
- return status;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/bufferhubd/detached_buffer_channel.h b/services/vr/bufferhubd/detached_buffer_channel.h
deleted file mode 100644
index 8b6dab8..0000000
--- a/services/vr/bufferhubd/detached_buffer_channel.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
-#define ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
-
-#include "buffer_hub.h"
-
-#include <pdx/channel_handle.h>
-#include <pdx/file_handle.h>
-
-namespace android {
-namespace dvr {
-
-class DetachedBufferChannel : public BufferHubChannel {
- public:
- ~DetachedBufferChannel() override;
-
- template <typename... Args>
- static std::unique_ptr<DetachedBufferChannel> Create(Args&&... args) {
- auto buffer = std::unique_ptr<DetachedBufferChannel>(
- new DetachedBufferChannel(std::forward<Args>(args)...));
- return buffer->IsValid() ? std::move(buffer) : nullptr;
- }
-
- // Returns whether the object holds a valid graphic buffer.
- bool IsValid() const {
- return buffer_.IsValid() && metadata_buffer_.IsValid();
- }
-
- size_t user_metadata_size() const { return user_metadata_size_; }
-
- // Captures buffer info for use by BufferHubService::DumpState().
- BufferInfo GetBufferInfo() const override;
-
- bool HandleMessage(pdx::Message& message) override;
- void HandleImpulse(pdx::Message& message) override;
-
- private:
- // Creates a detached buffer from existing IonBuffers.
- DetachedBufferChannel(BufferHubService* service, int buffer_id,
- int channel_id, IonBuffer buffer,
- IonBuffer metadata_buffer, size_t user_metadata_size);
-
- // Allocates a new detached buffer.
- DetachedBufferChannel(BufferHubService* service, int buffer_id,
- uint32_t width, uint32_t height, uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t user_metadata_size);
-
- pdx::Status<BufferDescription<pdx::BorrowedHandle>> OnImport(
- pdx::Message& message);
- pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
-
- // Gralloc buffer handles.
- IonBuffer buffer_;
- IonBuffer metadata_buffer_;
-
- // Size of user requested metadata.
- const size_t user_metadata_size_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 97af660..19d48f2 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -12,8 +12,8 @@
#include <thread>
#include <private/dvr/bufferhub_rpc.h>
+#include "buffer_channel.h"
#include "consumer_channel.h"
-#include "detached_buffer_channel.h"
using android::pdx::BorrowedHandle;
using android::pdx::ErrorStatus;
@@ -27,14 +27,6 @@
namespace android {
namespace dvr {
-namespace {
-
-static inline uint64_t FindNextClearedBit(uint64_t bits) {
- return ~bits - (~bits & (~bits - 1));
-}
-
-} // namespace
-
ProducerChannel::ProducerChannel(BufferHubService* service, int buffer_id,
int channel_id, IonBuffer buffer,
IonBuffer metadata_buffer,
@@ -270,7 +262,7 @@
// Try find the next consumer state bit which has not been claimed by any
// consumer yet.
- uint64_t consumer_state_bit = FindNextClearedBit(
+ uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
BufferHubDefs::kProducerStateBit);
if (consumer_state_bit == 0ULL) {
@@ -419,10 +411,9 @@
return ErrorStatus(-ret);
};
- std::unique_ptr<DetachedBufferChannel> channel =
- DetachedBufferChannel::Create(
- service(), buffer_id(), channel_id, std::move(buffer_),
- std::move(metadata_buffer_), user_metadata_size_);
+ std::unique_ptr<BufferChannel> channel = BufferChannel::Create(
+ service(), buffer_id(), channel_id, std::move(buffer_),
+ std::move(metadata_buffer_), user_metadata_size_);
if (!channel) {
ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
return ErrorStatus(EINVAL);