Merge changes from topic "egl1.5-master"
* changes:
Add EGL 1.5 Sync functions
Add eglCreatePlatformWindowSurface
Early exit to prep for refactoring
Implement getPlatformDisplay with ANGLE support
Implement eglCreateImage and eglDestroyImage
Determine EGL version
Generated EGL 1.5 support
Update EGL headers to version 1.5
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
index 1a9018a..e37c388 100644
--- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -42,8 +42,8 @@
/**
* analog using std::shared_ptr for internally held refcount
*
- * ref must be called at least one time during the lifetime of this object. The recommended way to construct
- * this object is with SharedRefBase::make.
+ * ref must be called at least one time during the lifetime of this object. The recommended way to
+ * construct this object is with SharedRefBase::make.
*/
class SharedRefBase {
public:
@@ -77,7 +77,7 @@
/**
* Convenience method for making an object directly with a reference.
*/
- template<class T, class... Args>
+ template <class T, class... Args>
static std::shared_ptr<T> make(Args&&... args) {
T* t = new T(std::forward<Args>(args)...);
return t->template ref<T>();
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 3328ad7..e53f7fd 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -68,7 +68,9 @@
}
void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
- const std::string appPref, bool developerOptIn) {
+ const std::string appPref, bool developerOptIn,
+ const int rulesFd, const long rulesOffset,
+ const long rulesLength) {
if (!mAnglePath.empty()) {
ALOGV("ignoring attempt to change ANGLE path from '%s' to '%s'", mAnglePath.c_str(),
path.c_str());
@@ -94,6 +96,13 @@
}
mAngleDeveloperOptIn = developerOptIn;
+
+ ALOGV("setting ANGLE rules file descriptor to '%i'", rulesFd);
+ mAngleRulesFd = rulesFd;
+ ALOGV("setting ANGLE rules offset to '%li'", rulesOffset);
+ mAngleRulesOffset = rulesOffset;
+ ALOGV("setting ANGLE rules length to '%li'", rulesLength);
+ mAngleRulesLength = rulesLength;
}
void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) {
@@ -124,6 +133,18 @@
return mAngleAppPref.c_str();
}
+int GraphicsEnv::getAngleRulesFd() {
+ return mAngleRulesFd;
+}
+
+long GraphicsEnv::getAngleRulesOffset() {
+ return mAngleRulesOffset;
+}
+
+long GraphicsEnv::getAngleRulesLength() {
+ return mAngleRulesLength;
+}
+
const std::string GraphicsEnv::getLayerPaths(){
return mLayerPaths;
}
@@ -192,6 +213,15 @@
const char* android_getAngleAppPref() {
return android::GraphicsEnv::getInstance().getAngleAppPref();
}
+int android_getAngleRulesFd() {
+ return android::GraphicsEnv::getInstance().getAngleRulesFd();
+}
+long android_getAngleRulesOffset() {
+ return android::GraphicsEnv::getInstance().getAngleRulesOffset();
+}
+long android_getAngleRulesLength() {
+ return android::GraphicsEnv::getInstance().getAngleRulesLength();
+}
const char* android_getLayerPaths() {
return android::GraphicsEnv::getInstance().getLayerPaths().c_str();
}
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 1783429..404823a 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -45,11 +45,15 @@
// in the search path must have a '!' after the zip filename, e.g.
// /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
void setAngleInfo(const std::string path, const std::string appName, const std::string appPref,
- bool devOptIn);
+ bool devOptIn, const int rulesFd, const long rulesOffset,
+ const long rulesLength);
android_namespace_t* getAngleNamespace();
const char* getAngleAppName();
const char* getAngleAppPref();
bool getAngleDeveloperOptIn();
+ int getAngleRulesFd();
+ long getAngleRulesOffset();
+ long getAngleRulesLength();
void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths);
NativeLoaderNamespace* getAppNamespace();
@@ -66,6 +70,9 @@
std::string mAngleAppName;
std::string mAngleAppPref;
bool mAngleDeveloperOptIn;
+ int mAngleRulesFd;
+ long mAngleRulesOffset;
+ long mAngleRulesLength;
std::string mDebugLayers;
std::string mLayerPaths;
android_namespace_t* mDriverNamespace = nullptr;
@@ -92,6 +99,9 @@
const char* android_getAngleAppName();
const char* android_getAngleAppPref();
bool android_getAngleDeveloperOptIn();
+ int android_getAngleRulesFd();
+ long android_getAngleRulesOffset();
+ long android_getAngleRulesLength();
const char* android_getLayerPaths();
const char* android_getDebugLayers();
}
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
index 3dac037..1a7c2d3 100644
--- a/libs/gui/BufferHubProducer.cpp
+++ b/libs/gui/BufferHubProducer.cpp
@@ -400,19 +400,8 @@
ALOGE("attachBuffer: DetachedBufferHandle cannot be NULL.");
return BAD_VALUE;
}
- auto detached_buffer = BufferHubBuffer::Import(std::move(detached_handle->handle()));
- if (detached_buffer == nullptr) {
- ALOGE("attachBuffer: BufferHubBuffer cannot be NULL.");
- return BAD_VALUE;
- }
- auto status_or_handle = detached_buffer->Promote();
- if (!status_or_handle.ok()) {
- ALOGE("attachBuffer: Failed to promote a BufferHubBuffer into a BufferProducer, error=%d.",
- status_or_handle.error());
- return BAD_VALUE;
- }
std::shared_ptr<BufferProducer> buffer_producer =
- BufferProducer::Import(status_or_handle.take());
+ BufferProducer::Import(std::move(detached_handle->handle()));
if (buffer_producer == nullptr) {
ALOGE("attachBuffer: Failed to import BufferProducer.");
return BAD_VALUE;
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 2696c6c..44a947e 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -174,26 +174,6 @@
return poll(&p, 1, timeoutMs);
}
-Status<LocalChannelHandle> BufferHubBuffer::Promote() {
- ATRACE_CALL();
-
- // TODO(b/112338294) remove after migrate producer buffer to binder
- ALOGW("BufferHubBuffer::Promote: not supported operation during migration");
- return {};
-
- ALOGD("BufferHubBuffer::Promote: id=%d.", mId);
-
- auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Promote>();
- if (statusOrHandle.ok()) {
- // Invalidate the buffer.
- mBufferHandle = {};
- } else {
- ALOGE("BufferHubBuffer::Promote: Failed to promote buffer (id=%d): %s.", mId,
- statusOrHandle.GetErrorMessage().c_str());
- }
- return statusOrHandle;
-}
-
Status<LocalChannelHandle> BufferHubBuffer::Duplicate() {
ATRACE_CALL();
ALOGD("BufferHubBuffer::Duplicate: id=%d.", mId);
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index d33be8c..cefe5b3 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -112,11 +112,6 @@
// Polls the fd for |timeoutMs| milliseconds (-1 for infinity).
int Poll(int timeoutMs);
- // Promotes a BufferHubBuffer to become a ProducerBuffer. Once promoted the BufferHubBuffer
- // channel will be closed automatically on successful IPC return. Further IPCs towards this
- // channel will return error.
- pdx::Status<pdx::LocalChannelHandle> Promote();
-
// Creates a BufferHubBuffer client from an existing one. The new client will
// share the same underlying gralloc buffer and ashmem region for metadata.
pdx::Status<pdx::LocalChannelHandle> Duplicate();
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index e71c99c..be06ad2 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -113,12 +113,6 @@
// TODO(b/112338294): rewrite test after migration
return;
-
- // Promote the detached buffer should fail as b1 is no longer the exclusive
- // owner of the buffer..
- statusOrHandle = b1->Promote();
- EXPECT_FALSE(statusOrHandle.ok());
- EXPECT_EQ(statusOrHandle.error(), EINVAL);
}
} // namespace android
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 571d382..8c6e7e2 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -794,43 +794,42 @@
EXPECT_EQ(d->id(), p_id);
}
-TEST_F(LibBufferHubTest, TestPromoteBufferHubBuffer) {
- // TODO(b/112338294) rewrite test after migration
- return;
+TEST_F(LibBufferHubTest, TestCreateBufferHubBufferFails) {
+ // Buffer Creation will fail: BLOB format requires height to be 1.
+ auto b1 = BufferHubBuffer::Create(kWidth, /*height=2*/ 2, kLayerCount,
+ /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage,
+ kUserMetadataSize);
- auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
- kUsage, kUserMetadataSize);
- int b1_id = b1->id();
- EXPECT_TRUE(b1->IsValid());
-
- auto status_or_handle = b1->Promote();
- EXPECT_TRUE(status_or_handle);
-
- // The detached buffer should have hangup.
- EXPECT_GT(RETRY_EINTR(b1->Poll(kPollTimeoutMs)), 0);
- auto status_or_int = b1->GetEventMask(POLLHUP);
- EXPECT_TRUE(status_or_int.ok());
- EXPECT_EQ(status_or_int.get(), POLLHUP);
-
- // The buffer client is still considered as connected but invalid.
- EXPECT_TRUE(b1->IsConnected());
+ EXPECT_FALSE(b1->IsConnected());
EXPECT_FALSE(b1->IsValid());
- // Gets the channel handle for the producer.
- LocalChannelHandle h1 = status_or_handle.take();
- EXPECT_TRUE(h1.valid());
+ // Buffer Creation will fail: user metadata size too large.
+ auto b2 = BufferHubBuffer::Create(
+ kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ /*user_metadata_size=*/std::numeric_limits<size_t>::max());
- std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Import(std::move(h1));
- EXPECT_FALSE(h1.valid());
- ASSERT_TRUE(p1 != nullptr);
- int p1_id = p1->id();
+ EXPECT_FALSE(b2->IsConnected());
+ EXPECT_FALSE(b2->IsValid());
- // A newly promoted ProducerBuffer should inherit the same buffer id.
- EXPECT_EQ(b1_id, p1_id);
- EXPECT_TRUE(IsBufferGained(p1->buffer_state()));
+ // Buffer Creation will fail: user metadata size too large.
+ auto b3 = BufferHubBuffer::Create(
+ kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ /*user_metadata_size=*/std::numeric_limits<size_t>::max() -
+ kMetadataHeaderSize);
+
+ EXPECT_FALSE(b3->IsConnected());
+ EXPECT_FALSE(b3->IsValid());
}
-TEST_F(LibBufferHubTest, TestDetachThenPromote) {
+TEST_F(LibBufferHubTest, TestCreateBufferHubBuffer) {
+ auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, kUserMetadataSize);
+ EXPECT_TRUE(b1->IsConnected());
+ EXPECT_TRUE(b1->IsValid());
+ EXPECT_NE(b1->id(), 0);
+}
+
+TEST_F(LibBufferHubTest, TestDetach) {
// TODO(b/112338294) rewrite test after migration
return;
@@ -852,24 +851,48 @@
EXPECT_TRUE(b1->IsValid());
int b1_id = b1->id();
EXPECT_EQ(b1_id, p1_id);
+}
- // Promote the detached buffer.
- status_or_handle = b1->Promote();
- // The buffer client is still considered as connected but invalid.
+TEST_F(LibBufferHubTest, TestDuplicateBufferHubBuffer) {
+ auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, kUserMetadataSize);
+ int b1_id = b1->id();
+ EXPECT_TRUE(b1->IsValid());
+ EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
+
+ auto status_or_handle = b1->Duplicate();
+ EXPECT_TRUE(status_or_handle);
+
+ // The detached buffer should still be valid.
EXPECT_TRUE(b1->IsConnected());
- EXPECT_FALSE(b1->IsValid());
- EXPECT_TRUE(status_or_handle.ok());
+ EXPECT_TRUE(b1->IsValid());
- // Gets the channel handle for the producer.
+ // Gets the channel handle for the duplicated buffer.
LocalChannelHandle h2 = status_or_handle.take();
EXPECT_TRUE(h2.valid());
- std::unique_ptr<ProducerBuffer> p2 = ProducerBuffer::Import(std::move(h2));
+ std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(h2));
EXPECT_FALSE(h2.valid());
- ASSERT_TRUE(p2 != nullptr);
- int p2_id = p2->id();
+ ASSERT_TRUE(b2 != nullptr);
+ EXPECT_TRUE(b2->IsValid());
+ EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
- // A newly promoted ProducerBuffer should inherit the same buffer id.
- EXPECT_EQ(b1_id, p2_id);
- EXPECT_TRUE(IsBufferGained(p2->buffer_state()));
+ int b2_id = b2->id();
+
+ // These two buffer instances are based on the same physical buffer under the
+ // hood, so they should share the same id.
+ EXPECT_EQ(b1_id, b2_id);
+ // We use buffer_state_bit() to tell those two instances apart.
+ EXPECT_NE(b1->buffer_state_bit(), b2->buffer_state_bit());
+ EXPECT_NE(b1->buffer_state_bit(), 0ULL);
+ EXPECT_NE(b2->buffer_state_bit(), 0ULL);
+ EXPECT_NE(b1->buffer_state_bit(), kProducerStateBit);
+ EXPECT_NE(b2->buffer_state_bit(), kProducerStateBit);
+
+ // Both buffer instances should be in gained state.
+ EXPECT_TRUE(IsBufferGained(b1->buffer_state()));
+ EXPECT_TRUE(IsBufferGained(b2->buffer_state()));
+
+ // TODO(b/112338294) rewrite test after migration
+ return;
}
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index 6d28d41..49f9c3e 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -191,11 +191,6 @@
// Imports the given channel handle to a DetachedBuffer, taking ownership.
kOpImport,
- // Promotes a DetachedBuffer to become a ProducerBuffer. Once promoted the
- // DetachedBuffer channel will be closed automatically on successful IPC
- // return. Further IPCs towards this channel will return error.
- kOpPromote,
-
// Creates a DetachedBuffer client from an existing one. The new client will
// share the same underlying gralloc buffer and ashmem region for metadata.
kOpDuplicate,
@@ -212,10 +207,9 @@
uint32_t format, uint64_t usage,
size_t user_metadata_size));
PDX_REMOTE_METHOD(Import, kOpImport, BufferTraits<LocalHandle>(Void));
- PDX_REMOTE_METHOD(Promote, kOpPromote, LocalChannelHandle(Void));
PDX_REMOTE_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));
- PDX_REMOTE_API(API, Create, Import, Promote, Duplicate);
+ PDX_REMOTE_API(API, Create, Import, Duplicate);
};
} // namespace dvr
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 31712fc..6f792ec 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -51,6 +51,14 @@
typedef bool (*fpANGLEUseForApplication)(const char* appName, const char* deviceMfr,
const char* deviceModel, ANGLEPreference developerOption,
ANGLEPreference appPreference);
+
+ // TODO(ianelliott@): Get this from an ANGLE header:
+ typedef bool (*fpANGLEGetUtilityAPI)(unsigned int* versionToUse);
+
+ // TODO(ianelliott@): Get this from an ANGLE header:
+ typedef bool (*fpAndroidUseANGLEForApplication)(int fd, long offset, long length,
+ const char* appName, const char* deviceMfr,
+ const char* deviceModel);
}
// ----------------------------------------------------------------------------
@@ -511,7 +519,7 @@
return ANGLE_NO_PREFERENCE;
}
-static void* load_angle(const char* kind, egl_connection_t* cnx) {
+static void* load_angle(const char* kind, android_namespace_t* ns, egl_connection_t* cnx) {
// Only attempt to load ANGLE libs
if (strcmp(kind, "EGL") != 0 && strcmp(kind, "GLESv2") != 0 && strcmp(kind, "GLESv1_CM") != 0)
return nullptr;
@@ -520,10 +528,12 @@
std::string name;
char prop[PROPERTY_VALUE_MAX];
- android_namespace_t* ns = android_getAngleNamespace();
const char* app_name = android_getAngleAppName();
const char* app_pref = android_getAngleAppPref();
bool developer_opt_in = android_getAngleDeveloperOptIn();
+ const int rules_fd = android_getAngleRulesFd();
+ const long rules_offset = android_getAngleRulesOffset();
+ const long rules_length = android_getAngleRulesLength();
// Determine whether or not to use ANGLE:
ANGLEPreference developer_option = developer_opt_in ? ANGLE_PREFER_ANGLE : ANGLE_NO_PREFERENCE;
@@ -539,21 +549,51 @@
char model[PROPERTY_VALUE_MAX];
property_get("ro.product.manufacturer", manufacturer, "UNSET");
property_get("ro.product.model", model, "UNSET");
- ANGLEPreference app_preference = getAnglePref(android_getAngleAppPref());
-
so = load_angle_from_namespace("feature_support", ns);
if (so) {
ALOGV("Temporarily loaded ANGLE's opt-in/out logic from namespace");
- fpANGLEUseForApplication fp =
- (fpANGLEUseForApplication)dlsym(so, "ANGLEUseForApplication");
- if (fp) {
- use_angle = (fp)(app_name_str.c_str(), manufacturer, model, developer_option,
- app_preference);
- ALOGV("Result of opt-in/out logic is %s", use_angle ? "true" : "false");
+ bool use_version0_API = false;
+ bool use_version1_API = false;
+ fpANGLEGetUtilityAPI ANGLEGetUtilityAPI =
+ (fpANGLEGetUtilityAPI)dlsym(so, "ANGLEGetUtilityAPI");
+ if (ANGLEGetUtilityAPI) {
+ unsigned int versionToUse = 1;
+ if ((ANGLEGetUtilityAPI)(&versionToUse)) {
+ if (versionToUse == 1) {
+ use_version1_API = true;
+ } else {
+ use_version0_API = true;
+ }
+ }
} else {
- ALOGW("Cannot find ANGLEUseForApplication in library");
+ use_version0_API = true;
}
-
+ if (use_version1_API) {
+ // Use the new version 1 API to determine if the
+ // application should use the ANGLE or the native driver.
+ fpAndroidUseANGLEForApplication AndroidUseANGLEForApplication =
+ (fpAndroidUseANGLEForApplication)dlsym(so, "AndroidUseANGLEForApplication");
+ if (AndroidUseANGLEForApplication) {
+ use_angle = (AndroidUseANGLEForApplication)(rules_fd, rules_offset,
+ rules_length, app_name_str.c_str(),
+ manufacturer, model);
+ } else {
+ ALOGW("Cannot find AndroidUseANGLEForApplication in library");
+ }
+ } else if (use_version0_API) {
+ // Use the old version 0 API to determine if the
+ // application should use the ANGLE or the native driver.
+ fpANGLEUseForApplication ANGLEUseForApplication =
+ (fpANGLEUseForApplication)dlsym(so, "ANGLEUseForApplication");
+ if (ANGLEUseForApplication) {
+ ANGLEPreference app_preference = getAnglePref(android_getAngleAppPref());
+ use_angle = (ANGLEUseForApplication)(app_name_str.c_str(), manufacturer, model,
+ developer_option, app_preference);
+ ALOGV("Result of opt-in/out logic is %s", use_angle ? "true" : "false");
+ } else {
+ ALOGW("Cannot find ANGLEUseForApplication in library");
+ }
+ }
ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
dlclose(so);
so = nullptr;
@@ -620,7 +660,10 @@
ATRACE_CALL();
void* dso = nullptr;
- dso = load_angle(kind, cnx);
+ android_namespace_t* ns = android_getAngleNamespace();
+ if (ns) {
+ dso = load_angle(kind, ns, cnx);
+ }
#ifndef __ANDROID_VNDK__
if (!dso) {
android_namespace_t* ns = android_getDriverNamespace();
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 38104c4..2cad986 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -852,7 +852,8 @@
return true;
}
- addMonitoringTargetsLocked(inputTargets);
+ // Add monitor channels from event's or focused display.
+ addMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
// Dispatch the key.
dispatchEventLocked(currentTime, entry, inputTargets);
@@ -919,7 +920,8 @@
return true;
}
- addMonitoringTargetsLocked(inputTargets);
+ // Add monitor channels from event's or focused display.
+ addMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
// Dispatch the motion.
if (conflictingPointerActions) {
@@ -1665,17 +1667,29 @@
target.pointerIds = pointerIds;
}
-void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets) {
- for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
- inputTargets.push();
+void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets,
+ int32_t displayId) {
+ std::unordered_map<int32_t, Vector<sp<InputChannel>>>::const_iterator it =
+ mMonitoringChannelsByDisplay.find(displayId);
- InputTarget& target = inputTargets.editTop();
- target.inputChannel = mMonitoringChannels[i];
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
- target.xOffset = 0;
- target.yOffset = 0;
- target.pointerIds.clear();
- target.scaleFactor = 1.0f;
+ if (it != mMonitoringChannelsByDisplay.end()) {
+ const Vector<sp<InputChannel>>& monitoringChannels = it->second;
+ const size_t numChannels = monitoringChannels.size();
+ for (size_t i = 0; i < numChannels; i++) {
+ inputTargets.push();
+
+ InputTarget& target = inputTargets.editTop();
+ target.inputChannel = monitoringChannels[i];
+ target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ target.xOffset = 0;
+ target.yOffset = 0;
+ target.pointerIds.clear();
+ target.scaleFactor = 1.0f;
+ }
+ } else {
+ // If there is no monitor channel registered or all monitor channel unregistered,
+ // the display can't detect the extra system gesture by a copy of input events.
+ ALOGW("There is no monitor channel found in display=%" PRId32, displayId);
}
}
@@ -2294,8 +2308,12 @@
void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked(
const CancelationOptions& options) {
- for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
- synthesizeCancelationEventsForInputChannelLocked(mMonitoringChannels[i], options);
+ for (auto& it : mMonitoringChannelsByDisplay) {
+ const Vector<sp<InputChannel>>& monitoringChannels = it.second;
+ const size_t numChannels = monitoringChannels.size();
+ for (size_t i = 0; i < numChannels; i++) {
+ synthesizeCancelationEventsForInputChannelLocked(monitoringChannels[i], options);
+ }
}
}
@@ -3486,12 +3504,16 @@
dump += INDENT "Displays: <none>\n";
}
- if (!mMonitoringChannels.isEmpty()) {
- dump += INDENT "MonitoringChannels:\n";
- for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
- const sp<InputChannel>& channel = mMonitoringChannels[i];
- dump += StringPrintf(INDENT2 "%zu: '%s'\n", i, channel->getName().c_str());
- }
+ if (!mMonitoringChannelsByDisplay.empty()) {
+ for (auto& it : mMonitoringChannelsByDisplay) {
+ const Vector<sp<InputChannel>>& monitoringChannels = it.second;
+ dump += INDENT "MonitoringChannels in Display %d:\n";
+ const size_t numChannels = monitoringChannels.size();
+ for (size_t i = 0; i < numChannels; i++) {
+ const sp<InputChannel>& channel = monitoringChannels[i];
+ dump += StringPrintf(INDENT2 "%zu: '%s'\n", i, channel->getName().c_str());
+ }
+ }
} else {
dump += INDENT "MonitoringChannels: <none>\n";
}
@@ -3609,10 +3631,10 @@
}
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
+ const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId) {
#if DEBUG_REGISTRATION
- ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().c_str(),
- toString(monitor));
+ ALOGD("channel '%s' ~ registerInputChannel - displayId=%" PRId32,
+ inputChannel->getName().c_str(), displayId);
#endif
{ // acquire lock
@@ -3624,13 +3646,20 @@
return BAD_VALUE;
}
+ // If InputWindowHandle is null and displayId is not ADISPLAY_ID_NONE,
+ // treat inputChannel as monitor channel for displayId.
+ bool monitor = inputWindowHandle == nullptr && displayId != ADISPLAY_ID_NONE;
+
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);
+ // Store monitor channel by displayId.
if (monitor) {
- mMonitoringChannels.push(inputChannel);
+ Vector<sp<InputChannel>>& monitoringChannels =
+ mMonitoringChannelsByDisplay[displayId];
+ monitoringChannels.push(inputChannel);
}
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
@@ -3687,11 +3716,21 @@
}
void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) {
- for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
- if (mMonitoringChannels[i] == inputChannel) {
- mMonitoringChannels.removeAt(i);
- break;
- }
+ for (auto it = mMonitoringChannelsByDisplay.begin();
+ it != mMonitoringChannelsByDisplay.end(); ) {
+ Vector<sp<InputChannel>>& monitoringChannels = it->second;
+ const size_t numChannels = monitoringChannels.size();
+ for (size_t i = 0; i < numChannels; i++) {
+ if (monitoringChannels[i] == inputChannel) {
+ monitoringChannels.removeAt(i);
+ break;
+ }
+ }
+ if (monitoringChannels.empty()) {
+ it = mMonitoringChannelsByDisplay.erase(it);
+ } else {
+ ++it;
+ }
}
}
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index aedad2f..5efb2fa 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -346,13 +346,19 @@
virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
const sp<InputChannel>& toChannel) = 0;
- /* Registers or unregister input channels that may be used as targets for input events.
- * If monitor is true, the channel will receive a copy of all input events.
+ /* Registers input channels that may be used as targets for input events.
+ * If inputWindowHandle is null, and displayId is not ADISPLAY_ID_NONE,
+ * the channel will receive a copy of all input events form the specific displayId.
*
- * These methods may be called on any thread (usually by the input manager).
+ * This method may be called on any thread (usually by the input manager).
*/
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor) = 0;
+ const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId) = 0;
+
+ /* Unregister input channels that will no longer receive input events.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
};
@@ -407,7 +413,7 @@
const sp<InputChannel>& toChannel);
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
+ const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId);
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
private:
@@ -914,8 +920,8 @@
ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
- // Input channels that will receive a copy of all input events.
- Vector<sp<InputChannel> > mMonitoringChannels;
+ // Input channels that will receive a copy of all input events sent to the provided display.
+ std::unordered_map<int32_t, Vector<sp<InputChannel>>> mMonitoringChannelsByDisplay;
// Event injection and synchronization.
Condition mInjectionResultAvailableCondition;
@@ -1070,7 +1076,7 @@
void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets);
- void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets);
+ void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets, int32_t displayId);
void pokeUserActivityLocked(const EventEntry* eventEntry);
bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index f75b0b6..c6eaf9f 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -278,68 +278,8 @@
}
};
-class FakeWindowHandle : public InputWindowHandle {
+class FakeInputReceiver {
public:
- static const int32_t WIDTH = 600;
- static const int32_t HEIGHT = 800;
-
- FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<InputDispatcher>& dispatcher, const std::string name) :
- InputWindowHandle(inputApplicationHandle), mDispatcher(dispatcher),
- mName(name), mFocused(false), mDisplayId(ADISPLAY_ID_DEFAULT) {
- InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
- mConsumer = new InputConsumer(mClientChannel);
- mDispatcher->registerInputChannel(mServerChannel, this, false);
- }
-
- virtual ~FakeWindowHandle() {
- mDispatcher->unregisterInputChannel(mServerChannel);
- mServerChannel.clear();
- mClientChannel.clear();
- mDispatcher.clear();
-
- if (mConsumer != nullptr) {
- delete mConsumer;
- }
- }
-
- virtual bool updateInfo() {
- if (!mInfo) {
- mInfo = new InputWindowInfo();
- }
- mInfo->inputChannel = mServerChannel;
- mInfo->name = mName;
- mInfo->layoutParamsFlags = 0;
- mInfo->layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
- mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
- mInfo->frameLeft = 0;
- mInfo->frameTop = 0;
- mInfo->frameRight = WIDTH;
- mInfo->frameBottom = HEIGHT;
- mInfo->scaleFactor = 1.0;
- mInfo->addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
- mInfo->visible = true;
- mInfo->canReceiveKeys = true;
- mInfo->hasFocus = mFocused;
- mInfo->hasWallpaper = false;
- mInfo->paused = false;
- mInfo->layer = 0;
- mInfo->ownerPid = INJECTOR_PID;
- mInfo->ownerUid = INJECTOR_UID;
- mInfo->inputFeatures = 0;
- mInfo->displayId = mDisplayId;
-
- return true;
- }
-
- void setFocus() {
- mFocused = true;
- }
-
- void setDisplayId(int32_t displayId) {
- mDisplayId = displayId;
- }
-
void consumeEvent(int32_t expectedEventType, int32_t expectedDisplayId,
int32_t expectedFlags = 0) {
uint32_t consumeSeq;
@@ -376,7 +316,7 @@
ASSERT_EQ(expectedFlags, flags)
<< mName.c_str() << ": event flags should be the same as expected.";
- status = mConsumer->sendFinishedSignal(consumeSeq, true /*handled*/);
+ status = mConsumer->sendFinishedSignal(consumeSeq, handled());
ASSERT_EQ(OK, status)
<< mName.c_str() << ": consumer sendFinishedSignal should return OK.";
}
@@ -391,17 +331,94 @@
<< ": should not have received any events, so consume(..) should not return OK.";
}
- private:
+protected:
+ explicit FakeInputReceiver(const sp<InputDispatcher>& dispatcher,
+ const std::string name, int32_t displayId) :
+ mDispatcher(dispatcher), mName(name), mDisplayId(displayId) {
+ InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
+ mConsumer = new InputConsumer(mClientChannel);
+ }
+
+ virtual ~FakeInputReceiver() {
+ }
+
+ // return true if the event has been handled.
+ virtual bool handled() {
+ return false;
+ }
+
sp<InputDispatcher> mDispatcher;
sp<InputChannel> mServerChannel, mClientChannel;
InputConsumer *mConsumer;
PreallocatedInputEventFactory mEventFactory;
std::string mName;
- bool mFocused;
int32_t mDisplayId;
};
+class FakeWindowHandle : public InputWindowHandle, public FakeInputReceiver {
+public:
+ static const int32_t WIDTH = 600;
+ static const int32_t HEIGHT = 800;
+
+ FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
+ const sp<InputDispatcher>& dispatcher, const std::string name, int32_t displayId) :
+ InputWindowHandle(inputApplicationHandle),
+ FakeInputReceiver(dispatcher, name, displayId),
+ mFocused(false) {
+ mDispatcher->registerInputChannel(mServerChannel, this, displayId);
+ }
+
+ virtual bool updateInfo() {
+ if (!mInfo) {
+ mInfo = new InputWindowInfo();
+ }
+ mInfo->inputChannel = mServerChannel;
+ mInfo->name = mName;
+ mInfo->layoutParamsFlags = 0;
+ mInfo->layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
+ mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
+ mInfo->frameLeft = 0;
+ mInfo->frameTop = 0;
+ mInfo->frameRight = WIDTH;
+ mInfo->frameBottom = HEIGHT;
+ mInfo->scaleFactor = 1.0;
+ mInfo->addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
+ mInfo->visible = true;
+ mInfo->canReceiveKeys = true;
+ mInfo->hasFocus = mFocused;
+ mInfo->hasWallpaper = false;
+ mInfo->paused = false;
+ mInfo->layer = 0;
+ mInfo->ownerPid = INJECTOR_PID;
+ mInfo->ownerUid = INJECTOR_UID;
+ mInfo->inputFeatures = 0;
+ mInfo->displayId = mDisplayId;
+
+ return true;
+ }
+
+ void setFocus() {
+ mFocused = true;
+ }
+
+ void assertNoEvents() {
+ uint32_t consumeSeq;
+ InputEvent* event;
+ status_t status = mConsumer->consume(&mEventFactory, false /*consumeBatches*/, -1,
+ &consumeSeq, &event);
+ ASSERT_NE(OK, status)
+ << mName.c_str()
+ << ": should not have received any events, so consume(..) should not return OK.";
+ }
+protected:
+ virtual bool handled() {
+ return true;
+ }
+
+ bool mFocused;
+};
+
static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher,
int32_t displayId = ADISPLAY_ID_NONE) {
KeyEvent event;
@@ -419,7 +436,8 @@
INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
}
-static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t displayId) {
+static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t source,
+ int32_t displayId) {
MotionEvent event;
PointerProperties pointerProperties[1];
PointerCoords pointerCoords[1];
@@ -434,7 +452,7 @@
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
// Define a valid motion down event.
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, displayId,
+ event.initialize(DEVICE_ID, source, displayId,
AMOTION_EVENT_ACTION_DOWN, /* actionButton */0, /* flags */ 0, /* edgeFlags */ 0,
AMETA_NONE, /* buttonState */ 0, /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
/* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties,
@@ -449,13 +467,15 @@
TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
- sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window");
+ sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window",
+ ADISPLAY_ID_DEFAULT);
Vector<sp<InputWindowHandle>> inputWindowHandles;
inputWindowHandles.add(window);
mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
- ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
// Window should receive motion event.
@@ -465,15 +485,18 @@
// The foreground window should receive the first touch down event.
TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
- sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top");
- sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second");
+ sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
+ ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
+ ADISPLAY_ID_DEFAULT);
Vector<sp<InputWindowHandle>> inputWindowHandles;
inputWindowHandles.add(windowTop);
inputWindowHandles.add(windowSecond);
mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
- ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
// Top window should receive the touch down event. Second window should not receive anything.
@@ -483,8 +506,10 @@
TEST_F(InputDispatcherTest, SetInputWindow_FocusedWindow) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
- sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top");
- sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second");
+ sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
+ ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
+ ADISPLAY_ID_DEFAULT);
// Set focus application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -504,61 +529,70 @@
windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
}
-TEST_F(InputDispatcherTest, SetInputWindow_MultiDisplayTouch) {
- sp<FakeApplicationHandle> application = new FakeApplicationHandle();
- sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1");
- sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application, mDispatcher, "D_2");
+/* Test InputDispatcher for MultiDisplay */
+class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
+public:
+ static constexpr int32_t SECOND_DISPLAY_ID = 1;
+ virtual void SetUp() {
+ InputDispatcherTest::SetUp();
- // Test the primary display touch down.
- Vector<sp<InputWindowHandle>> inputWindowHandles;
- inputWindowHandles.push(windowInPrimary);
+ application1 = new FakeApplicationHandle();
+ windowInPrimary = new FakeWindowHandle(application1, mDispatcher, "D_1",
+ ADISPLAY_ID_DEFAULT);
+ Vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.push(windowInPrimary);
+ // Set focus window for primary display, but focused display would be second one.
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
+ windowInPrimary->setFocus();
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
- mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
- ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ application2 = new FakeApplicationHandle();
+ windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2",
+ SECOND_DISPLAY_ID);
+ // Set focus to second display window.
+ Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
+ inputWindowHandles_Second.push(windowInSecondary);
+ // Set focus display to second one.
+ mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
+ // Set focus window for second display.
+ mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
+ windowInSecondary->setFocus();
+ mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
+ }
+
+ virtual void TearDown() {
+ InputDispatcherTest::TearDown();
+
+ application1.clear();
+ windowInPrimary.clear();
+ application2.clear();
+ windowInSecondary.clear();
+ }
+
+protected:
+ sp<FakeApplicationHandle> application1;
+ sp<FakeWindowHandle> windowInPrimary;
+ sp<FakeApplicationHandle> application2;
+ sp<FakeWindowHandle> windowInSecondary;
+};
+
+TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) {
+ // Test touch down on primary display.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
windowInPrimary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
windowInSecondary->assertNoEvents();
- // Test the second display touch down.
- constexpr int32_t SECOND_DISPLAY_ID = 1;
- windowInSecondary->setDisplayId(SECOND_DISPLAY_ID);
- Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
- inputWindowHandles_Second.push(windowInSecondary);
-
- mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
- ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, SECOND_DISPLAY_ID))
+ // Test touch down on second display.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
windowInPrimary->assertNoEvents();
windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID);
}
-TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) {
- sp<FakeApplicationHandle> application = new FakeApplicationHandle();
- sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1");
- sp<FakeApplicationHandle> application2 = new FakeApplicationHandle();
- sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2");
-
- constexpr int32_t SECOND_DISPLAY_ID = 1;
-
- // Set focus to primary display window.
- mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
- windowInPrimary->setFocus();
-
- // Set focus to second display window.
- mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
- mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
- windowInSecondary->setFocus();
-
- // Update all windows per displays.
- Vector<sp<InputWindowHandle>> inputWindowHandles;
- inputWindowHandles.push(windowInPrimary);
- mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
-
- windowInSecondary->setDisplayId(SECOND_DISPLAY_ID);
- Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
- inputWindowHandles_Second.push(windowInSecondary);
- mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
-
+TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
// Test inject a key down with display id specified.
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
<< "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
@@ -572,8 +606,8 @@
windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
// Remove secondary display.
- inputWindowHandles_Second.clear();
- mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
+ Vector<sp<InputWindowHandle>> noWindows;
+ mDispatcher->setInputWindows(noWindows, SECOND_DISPLAY_ID);
// Expect old focus should receive a cancel event.
windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE,
@@ -586,4 +620,66 @@
windowInSecondary->assertNoEvents();
}
+class FakeMonitorReceiver : public FakeInputReceiver, public RefBase {
+public:
+ FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
+ int32_t displayId) : FakeInputReceiver(dispatcher, name, displayId) {
+ mDispatcher->registerInputChannel(mServerChannel, nullptr, displayId);
+ }
+};
+
+// Test per-display input monitors for motion event.
+TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
+ sp<FakeMonitorReceiver> monitorInPrimary =
+ new FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
+ sp<FakeMonitorReceiver> monitorInSecondary =
+ new FakeMonitorReceiver(mDispatcher, "M_2", SECOND_DISPLAY_ID);
+
+ // Test touch down on primary display.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ windowInPrimary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+ monitorInPrimary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+ windowInSecondary->assertNoEvents();
+ monitorInSecondary->assertNoEvents();
+
+ // Test touch down on second display.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ windowInPrimary->assertNoEvents();
+ monitorInPrimary->assertNoEvents();
+ windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID);
+ monitorInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID);
+
+ // Test inject a non-pointer motion event.
+ // If specific a display, it will dispatch to the focused window of particular display,
+ // or it will dispatch to the focused window of focused display.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ windowInPrimary->assertNoEvents();
+ monitorInPrimary->assertNoEvents();
+ windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_NONE);
+ monitorInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_NONE);
+}
+
+// Test per-display input monitors for key event.
+TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
+ //Input monitor per display.
+ sp<FakeMonitorReceiver> monitorInPrimary =
+ new FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
+ sp<FakeMonitorReceiver> monitorInSecondary =
+ new FakeMonitorReceiver(mDispatcher, "M_2", SECOND_DISPLAY_ID);
+
+ // Test inject a key down.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ windowInPrimary->assertNoEvents();
+ monitorInPrimary->assertNoEvents();
+ windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+ monitorInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+}
+
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 341dfd5..60cad02 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -767,9 +767,12 @@
*outMode = iter->second.colorMode;
*outIntent = iter->second.renderIntent;
} else {
- ALOGE("map unknown (%s)/(%s) to default color mode",
- dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
- decodeRenderIntent(intent).c_str());
+ // this is unexpected on a WCG display
+ if (hasWideColorGamut()) {
+ ALOGE("map unknown (%s)/(%s) to default color mode",
+ dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
+ decodeRenderIntent(intent).c_str());
+ }
*outDataspace = Dataspace::UNKNOWN;
*outMode = ColorMode::NATIVE;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 8afd3b3..7e6b5d3 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -102,6 +102,7 @@
mCurrentState.hdrMetadata.validTypes = 0;
mCurrentState.surfaceDamageRegion.clear();
mCurrentState.api = -1;
+ mCurrentState.hasColorTransform = false;
// drawing state & current state are identical
mDrawingState = mCurrentState;
@@ -1547,11 +1548,15 @@
}
bool Layer::setColorTransform(const mat4& matrix) {
+ static const mat4 identityMatrix = mat4();
+
if (mCurrentState.colorTransform == matrix) {
return false;
}
++mCurrentState.sequence;
mCurrentState.colorTransform = matrix;
+ mCurrentState.hasColorTransform = matrix != identityMatrix;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -1561,8 +1566,7 @@
}
bool Layer::hasColorTransform() const {
- static const mat4 identityMatrix = mat4();
- return getDrawingState().colorTransform != identityMatrix;
+ return getDrawingState().hasColorTransform;
}
bool Layer::isLegacyDataSpace() const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e2d1178..5d05f05 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -182,6 +182,7 @@
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
+ bool hasColorTransform;
};
explicit Layer(const LayerCreationArgs& args);
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
index dcc6ea4..ee85746 100644
--- a/services/vr/bufferhubd/buffer_channel.cpp
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -1,3 +1,4 @@
+#include <errno.h>
#include <private/dvr/buffer_channel.h>
#include <private/dvr/producer_channel.h>
@@ -16,9 +17,8 @@
size_t user_metadata_size)
: BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
buffer_node_(
- std::make_shared<BufferNode>(std::move(buffer), user_metadata_size)),
- buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
- buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+ std::make_shared<BufferNode>(std::move(buffer), user_metadata_size)) {
+ buffer_state_bit_ = buffer_node_->AddNewActiveClientsBitToMask();
}
BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
@@ -27,24 +27,28 @@
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_);
+ width, height, layer_count, format, usage, user_metadata_size)) {
+ buffer_state_bit_ = buffer_node_->AddNewActiveClientsBitToMask();
}
BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
int channel_id,
- std::shared_ptr<BufferNode> buffer_node,
- uint64_t buffer_state_bit)
+ std::shared_ptr<BufferNode> buffer_node)
: 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_);
+ buffer_node_(buffer_node) {
+ buffer_state_bit_ = buffer_node_->AddNewActiveClientsBitToMask();
+ if (buffer_state_bit_ == 0ULL) {
+ ALOGE("BufferChannel::BufferChannel: %s", strerror(errno));
+ buffer_node_ = nullptr;
+ }
}
BufferChannel::~BufferChannel() {
ALOGD_IF(TRACE, "BufferChannel::~BufferChannel: channel_id=%d buffer_id=%d.",
channel_id(), buffer_id());
+ if (buffer_state_bit_ != 0ULL) {
+ buffer_node_->RemoveClientsBitFromMask(buffer_state_bit_);
+ }
Hangup();
}
@@ -74,11 +78,6 @@
*this, &BufferChannel::OnDuplicate, message);
return true;
- case DetachedBufferRPC::Promote::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Promote>(
- *this, &BufferChannel::OnPromote, message);
- return true;
-
default:
return false;
}
@@ -106,38 +105,22 @@
/*released_fence_fd=*/BorrowedHandle{}};
}
-Status<RemoteChannelHandle> BufferChannel::OnDuplicate(
- Message& message) {
+Status<RemoteChannelHandle> BufferChannel::OnDuplicate(Message& message) {
ATRACE_NAME("BufferChannel::OnDuplicate");
- ALOGD_IF(TRACE, "BufferChannel::OnDuplicate: buffer=%d.",
- buffer_id());
+ 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());
+ if (!status.ok()) {
+ 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.");
+ auto channel = std::shared_ptr<BufferChannel>(
+ new BufferChannel(service(), buffer_id(), channel_id, buffer_node_));
+ if (!channel->IsValid()) {
+ ALOGE("BufferChannel::OnDuplicate: Invalid buffer. %s", strerror(errno));
return ErrorStatus(EINVAL);
}
@@ -154,69 +137,5 @@
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;
- if (int ret = metadata_buffer.Alloc(buffer_node_->metadata().metadata_size(),
- /*height=*/1,
- /*layer_count=*/1,
- BufferHubDefs::kMetadataFormat,
- BufferHubDefs::kMetadataUsage)) {
- ALOGE("BufferChannel::OnPromote: Failed to allocate metadata: %s",
- strerror(-ret));
- return ErrorStatus(EINVAL);
- }
-
- 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_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index 15391da..6421a0b 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -265,14 +265,6 @@
SetChannel(channel->channel_id(), nullptr);
return {};
- case DetachedBufferRPC::Promote::Opcode:
- // 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.
- SetChannel(channel->channel_id(), nullptr);
- return {};
-
default:
return DefaultHandleMessage(message);
}
diff --git a/services/vr/bufferhubd/buffer_node.cpp b/services/vr/bufferhubd/buffer_node.cpp
index 782b9c2..bedec6f 100644
--- a/services/vr/bufferhubd/buffer_node.cpp
+++ b/services/vr/bufferhubd/buffer_node.cpp
@@ -1,12 +1,24 @@
+#include <errno.h>
#include <private/dvr/buffer_hub_defs.h>
#include <private/dvr/buffer_node.h>
namespace android {
namespace dvr {
+void BufferNode::InitializeMetadata() {
+ // Using placement new here to reuse shared memory instead of new allocation
+ // Initialize the atomic variables to zero.
+ BufferHubDefs::MetadataHeader* metadata_header = metadata_.metadata_header();
+ buffer_state_ = new (&metadata_header->buffer_state) std::atomic<uint64_t>(0);
+ fence_state_ = new (&metadata_header->fence_state) std::atomic<uint64_t>(0);
+ active_clients_bit_mask_ =
+ new (&metadata_header->active_clients_bit_mask) std::atomic<uint64_t>(0);
+}
+
BufferNode::BufferNode(IonBuffer buffer, size_t user_metadata_size)
: buffer_(std::move(buffer)) {
metadata_ = BufferHubMetadata::Create(user_metadata_size);
+ InitializeMetadata();
}
// Allocates a new BufferNode.
@@ -22,6 +34,37 @@
}
metadata_ = BufferHubMetadata::Create(user_metadata_size);
+ InitializeMetadata();
+}
+
+uint64_t BufferNode::GetActiveClientsBitMask() const {
+ return active_clients_bit_mask_->load(std::memory_order_acquire);
+}
+
+uint64_t BufferNode::AddNewActiveClientsBitToMask() {
+ uint64_t current_active_clients_bit_mask = GetActiveClientsBitMask();
+ uint64_t buffer_state_bit = 0ULL;
+ uint64_t updated_active_clients_bit_mask = 0ULL;
+ do {
+ buffer_state_bit =
+ BufferHubDefs::FindNextClearedBit(current_active_clients_bit_mask);
+ if (buffer_state_bit == 0ULL) {
+ ALOGE(
+ "BufferNode::AddNewActiveClientsBitToMask: reached the maximum "
+ "mumber of channels per buffer node: 32.");
+ errno = E2BIG;
+ return 0ULL;
+ }
+ updated_active_clients_bit_mask =
+ current_active_clients_bit_mask | buffer_state_bit;
+ } while (!(active_clients_bit_mask_->compare_exchange_weak(
+ current_active_clients_bit_mask, updated_active_clients_bit_mask,
+ std::memory_order_acq_rel, std::memory_order_acquire)));
+ return buffer_state_bit;
+}
+
+void BufferNode::RemoveClientsBitFromMask(const uint64_t& value) {
+ active_clients_bit_mask_->fetch_and(~value);
}
} // namespace dvr
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
index 1697251..e9bdb37 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
@@ -42,21 +42,20 @@
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.
+ // Creates a detached buffer from an existing BufferNode. This method is used
+ // in OnDuplicate method.
BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
- std::shared_ptr<BufferNode> buffer_node,
- uint64_t buffer_state_bit);
+ std::shared_ptr<BufferNode> buffer_node);
pdx::Status<BufferTraits<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_;
+ std::shared_ptr<BufferNode> buffer_node_ = nullptr;
// The state bit of this buffer. Must be one the lower 63 bits.
- uint64_t buffer_state_bit_;
+ uint64_t buffer_state_bit_ = 0ULL;
};
} // namespace dvr
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_node.h b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
index d6c6105..e1e8057 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_node.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
@@ -10,7 +10,7 @@
class BufferNode {
public:
// Creates a BufferNode from existing IonBuffers, i.e. creating from an
- // existing ProducerChannel.
+ // existing ProducerChannel. Allocate a new BufferHubMetadata.
BufferNode(IonBuffer buffer, size_t user_metadata_size);
// Allocates a new BufferNode.
@@ -21,26 +21,56 @@
bool IsValid() const { return buffer_.IsValid() && metadata_.IsValid(); }
size_t user_metadata_size() const { return metadata_.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;
- }
- // Accessor of the IonBuffer.
+ // Accessors of the IonBuffer.
IonBuffer& buffer() { return buffer_; }
const IonBuffer& buffer() const { return buffer_; }
- // Accessor of the metadata.
+ // Accessors of metadata.
const BufferHubMetadata& metadata() const { return metadata_; }
+ // Gets the current value of active_clients_bit_mask in metadata_ with
+ // std::memory_order_acquire, so that all previous releases of
+ // active_clients_bit_mask from all threads will be returned here.
+ uint64_t GetActiveClientsBitMask() const;
+
+ // Find and add a new buffer_state_bit to active_clients_bit_mask in
+ // metadata_.
+ // Return the new buffer_state_bit that is added to active_clients_bit_mask.
+ // Return 0ULL if there are already 32 bp clients of the buffer.
+ uint64_t AddNewActiveClientsBitToMask();
+
+ // Removes the value from active_clients_bit_mask in metadata_ with
+ // std::memory_order_release, so that the change will be visible to any
+ // acquire of active_clients_bit_mask_ in any threads after the succeed of
+ // this operation.
+ void RemoveClientsBitFromMask(const uint64_t& value);
+
private:
+ // Helper method for constructors to initialize atomic metadata header
+ // variables in shared memory.
+ void InitializeMetadata();
+
// Gralloc buffer handles.
IonBuffer buffer_;
+
+ // Metadata in shared memory.
BufferHubMetadata metadata_;
- // 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;
+ // The following variables are atomic variables in metadata_ that are visible
+ // to Bn object and Bp objects. Please find more info in
+ // BufferHubDefs::MetadataHeader.
+
+ // buffer_state_ tracks the state of the buffer. Buffer can be in one of these
+ // four states: gained, posted, acquired, released.
+ std::atomic<uint64_t>* buffer_state_ = nullptr;
+
+ // TODO(b/112012161): add comments to fence_state_.
+ std::atomic<uint64_t>* fence_state_ = nullptr;
+
+ // active_clients_bit_mask_ tracks all the bp clients of the buffer. It is the
+ // union of all buffer_state_bit of all bp clients.
+ std::atomic<uint64_t>* active_clients_bit_mask_ = nullptr;
};
} // namespace dvr
diff --git a/services/vr/bufferhubd/tests/Android.bp b/services/vr/bufferhubd/tests/Android.bp
index bf8ea5b..a80691f 100644
--- a/services/vr/bufferhubd/tests/Android.bp
+++ b/services/vr/bufferhubd/tests/Android.bp
@@ -23,4 +23,31 @@
// TODO(b/117568153): Temporarily opt out using libcrt.
no_libcrt: true,
-}
\ No newline at end of file
+}
+
+cc_test {
+ name: "buffer_node-test",
+ srcs: ["buffer_node-test.cpp"],
+ cflags: [
+ "-DLOG_TAG=\"buffer_node-test\"",
+ "-DTRACE=0",
+ "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
+ ],
+ header_libs: ["libdvr_headers"],
+ static_libs: [
+ "libbufferhub",
+ "libbufferhubd",
+ "libgmock",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libpdx_default_transport",
+ "libui",
+ "libutils",
+ ],
+ // TODO(b/117568153): Temporarily opt out using libcrt.
+ no_libcrt: true,
+}
+
diff --git a/services/vr/bufferhubd/tests/buffer_node-test.cpp b/services/vr/bufferhubd/tests/buffer_node-test.cpp
new file mode 100644
index 0000000..c2526fe
--- /dev/null
+++ b/services/vr/bufferhubd/tests/buffer_node-test.cpp
@@ -0,0 +1,89 @@
+#include <errno.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <private/dvr/buffer_node.h>
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+const uint32_t kWidth = 640;
+const uint32_t kHeight = 480;
+const uint32_t kLayerCount = 1;
+const uint32_t kFormat = 1;
+const uint64_t kUsage = 0;
+const size_t kUserMetadataSize = 0;
+
+class BufferNodeTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ buffer_node = new BufferNode(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ kUserMetadataSize);
+ ASSERT_TRUE(buffer_node->IsValid());
+ }
+
+ void TearDown() override {
+ if (buffer_node != nullptr) {
+ delete buffer_node;
+ }
+ }
+
+ BufferNode* buffer_node = nullptr;
+};
+
+TEST_F(BufferNodeTest, TestCreateBufferNode) {
+ EXPECT_EQ(buffer_node->user_metadata_size(), kUserMetadataSize);
+}
+
+TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_twoNewClients) {
+ uint64_t new_buffer_state_bit_1 = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), new_buffer_state_bit_1);
+
+ // Request and add a new buffer_state_bit again.
+ // Active clients bit mask should be the union of the two new
+ // buffer_state_bits.
+ uint64_t new_buffer_state_bit_2 = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_EQ(buffer_node->GetActiveClientsBitMask(),
+ new_buffer_state_bit_1 | new_buffer_state_bit_2);
+}
+
+TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_32NewClients) {
+ uint64_t new_buffer_state_bit = 0ULL;
+ uint64_t current_mask = 0ULL;
+ uint64_t expected_mask = 0ULL;
+
+ for (int i = 0; i < 64; ++i) {
+ new_buffer_state_bit = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_NE(new_buffer_state_bit, 0);
+ EXPECT_FALSE(new_buffer_state_bit & current_mask);
+ expected_mask = current_mask | new_buffer_state_bit;
+ current_mask = buffer_node->GetActiveClientsBitMask();
+ EXPECT_EQ(current_mask, expected_mask);
+ }
+
+ // Method should fail upon requesting for more than maximum allowable clients.
+ new_buffer_state_bit = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_EQ(new_buffer_state_bit, 0ULL);
+ EXPECT_EQ(errno, E2BIG);
+}
+
+TEST_F(BufferNodeTest, TestRemoveActiveClientsBitFromMask) {
+ buffer_node->AddNewActiveClientsBitToMask();
+ uint64_t current_mask = buffer_node->GetActiveClientsBitMask();
+ uint64_t new_buffer_state_bit = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_NE(buffer_node->GetActiveClientsBitMask(), current_mask);
+
+ buffer_node->RemoveClientsBitFromMask(new_buffer_state_bit);
+ EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
+
+ // Remove the test_mask again to the active client bit mask should not modify
+ // the value of active clients bit mask.
+ buffer_node->RemoveClientsBitFromMask(new_buffer_state_bit);
+ EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
+}
+
+} // namespace
+
+} // namespace dvr
+} // namespace android