Merge "Android doesn't support Pixmaps"
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