Merge "Clean up featuresutils library"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 4ccb917..08218b8 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -9,6 +9,7 @@
libs/renderengine/
libs/ui/
libs/vr/
+ services/bufferhub/
services/surfaceflinger/
services/vr/
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index cf9d4c5..cc0a307 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -583,6 +583,21 @@
}
return error;
}
+
+ virtual bool isColorManagementUsed() const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::IS_COLOR_MANAGEMET_USED, data, &reply);
+ int32_t result = 0;
+ status_t err = reply.readInt32(&result);
+ if (err != NO_ERROR) {
+ ALOGE("ISurfaceComposer::isColorManagementUsed: error "
+ "retrieving result: %s (%d)",
+ strerror(-err), -err);
+ return false;
+ }
+ return result != 0;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -920,6 +935,12 @@
}
return NO_ERROR;
}
+ case IS_COLOR_MANAGEMET_USED: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ int32_t result = isColorManagementUsed() ? 1 : 0;
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 781e062..35cb3be 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -282,6 +282,8 @@
virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
ui::PixelFormat* pixelFormat) const = 0;
+
+ virtual bool isColorManagementUsed() const = 0;
};
// ----------------------------------------------------------------------------
@@ -320,6 +322,7 @@
GET_LAYER_DEBUG_INFO,
CREATE_SCOPED_CONNECTION,
GET_COMPOSITION_PREFERENCE,
+ IS_COLOR_MANAGEMET_USED,
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 500df05..25f762b 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -633,6 +633,8 @@
return NO_ERROR;
}
+ virtual bool isColorManagementUsed() const { return false; }
+
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 228d202..e8bda67 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -37,8 +37,18 @@
cc_test {
name: "BufferHubBuffer_test",
- header_libs: ["libbufferhub_headers", "libdvr_headers"],
- shared_libs: ["libpdx_default_transport", "libui", "libutils"],
+ header_libs: [
+ "libbufferhub_headers",
+ "libdvr_headers"
+ ],
+ shared_libs: [
+ "android.frameworks.bufferhub@1.0",
+ "libhidlbase",
+ "libhwbinder",
+ "libpdx_default_transport",
+ "libui",
+ "libutils"
+ ],
srcs: ["BufferHubBuffer_test.cpp"],
cflags: ["-Wall", "-Werror"],
}
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index da7fae1..108b005 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,7 +16,10 @@
#define LOG_TAG "BufferHubBufferTest"
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/IPCThreadState.h>
#include <ui/BufferHubBuffer.h>
namespace android {
@@ -32,13 +35,18 @@
} // namespace
-using BufferHubBufferTest = ::testing::Test;
-
using dvr::BufferHubDefs::IsBufferGained;
using dvr::BufferHubDefs::kMetadataHeaderSize;
using dvr::BufferHubDefs::kProducerStateBit;
+using frameworks::bufferhub::V1_0::IBufferHub;
+using hardware::hidl_handle;
+using hidl::base::V1_0::IBase;
using pdx::LocalChannelHandle;
+class BufferHubBufferTest : public ::testing::Test {
+ void SetUp() override { android::hardware::ProcessState::self()->startThreadPool(); }
+};
+
TEST_F(BufferHubBufferTest, CreateBufferHubBufferFails) {
// Buffer Creation will fail: BLOB format requires height to be 1.
auto b1 = BufferHubBuffer::Create(kWidth, /*height=*/2, kLayerCount,
@@ -115,4 +123,14 @@
return;
}
+TEST_F(BufferHubBufferTest, ConnectHidlServer) {
+ sp<IBufferHub> bufferhub = IBufferHub::getService();
+ ASSERT_NE(nullptr, bufferhub.get());
+
+ // TODO(b/116681016): Fill in real test once the interface gets implemented..
+ hidl_handle handle;
+ sp<IBase> interface = bufferhub->importBuffer(handle);
+ EXPECT_EQ(nullptr, interface.get());
+}
+
} // namespace android
diff --git a/libs/vr/libbufferhub/buffer_client_impl.cpp b/libs/vr/libbufferhub/buffer_client_impl.cpp
index 6bef98a..30cbb9f 100644
--- a/libs/vr/libbufferhub/buffer_client_impl.cpp
+++ b/libs/vr/libbufferhub/buffer_client_impl.cpp
@@ -10,6 +10,8 @@
: BpInterface<IBufferClient>(impl) {}
bool isValid() override;
+
+ status_t duplicate(uint64_t* outToken) override;
};
IMPLEMENT_META_INTERFACE(BufferClient, "android.dvr.IBufferClient");
@@ -17,6 +19,7 @@
// Transaction code
enum {
IS_VALID = IBinder::FIRST_CALL_TRANSACTION,
+ DUPLICATE,
};
bool BpBufferClient::isValid() {
@@ -38,13 +41,42 @@
}
}
+status_t BpBufferClient::duplicate(uint64_t* outToken) {
+ Parcel data, reply;
+ status_t ret =
+ data.writeInterfaceToken(IBufferClient::getInterfaceDescriptor());
+ if (ret != NO_ERROR) {
+ ALOGE("BpBufferClient::duplicate: failed to write into parcel; errno=%d",
+ ret);
+ return ret;
+ }
+
+ ret = remote()->transact(DUPLICATE, data, &reply);
+ if (ret == NO_ERROR) {
+ *outToken = reply.readUint64();
+ return NO_ERROR;
+ } else {
+ ALOGE("BpBufferClient::duplicate: failed to transact; errno=%d", ret);
+ return ret;
+ }
+}
+
status_t BnBufferClient::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
switch (code) {
case IS_VALID: {
CHECK_INTERFACE(IBufferClient, data, reply);
return reply->writeBool(isValid());
- } break;
+ }
+ case DUPLICATE: {
+ CHECK_INTERFACE(IBufferClient, data, reply);
+ uint64_t token = 0;
+ status_t ret = duplicate(&token);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ return reply->writeUint64(token);
+ }
default:
// Should not reach except binder defined transactions such as dumpsys
return BBinder::onTransact(code, data, reply, flags);
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
index b4c5d42..68cc766 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -123,17 +123,17 @@
buffer_state_ = &metadata_header_->buffer_state;
ALOGD_IF(TRACE,
"BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
- id(), buffer_state_->load());
+ id(), buffer_state_->load(std::memory_order_acquire));
fence_state_ = &metadata_header_->fence_state;
ALOGD_IF(TRACE,
"BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx64 ".", id(),
- fence_state_->load());
+ fence_state_->load(std::memory_order_acquire));
active_clients_bit_mask_ = &metadata_header_->active_clients_bit_mask;
ALOGD_IF(
TRACE,
"BufferHubBase::ImportBuffer: id=%d, active_clients_bit_mask=%" PRIx64
".",
- id(), active_clients_bit_mask_->load());
+ id(), active_clients_bit_mask_->load(std::memory_order_acquire));
return 0;
}
diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp
index a91e842..83d6951 100644
--- a/libs/vr/libbufferhub/consumer_buffer.cpp
+++ b/libs/vr/libbufferhub/consumer_buffer.cpp
@@ -38,7 +38,7 @@
// Only check producer bit and this consumer buffer's particular consumer bit.
// The buffer is can be acquired iff: 1) producer bit is set; 2) consumer bit
// is not set.
- uint64_t buffer_state = buffer_state_->load();
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferPosted(buffer_state, client_state_mask())) {
ALOGE("ConsumerBuffer::LocalAcquire: not posted, id=%d state=%" PRIx64
" client_state_mask=%" PRIx64 ".",
@@ -57,7 +57,7 @@
out_meta->user_metadata_ptr = 0;
}
- uint64_t fence_state = fence_state_->load();
+ uint64_t fence_state = fence_state_->load(std::memory_order_acquire);
// If there is an acquire fence from producer, we need to return it.
if (fence_state & BufferHubDefs::kProducerStateBit) {
*out_fence = shared_acquire_fence_.Duplicate();
@@ -118,7 +118,7 @@
return error;
// Check invalid state transition.
- uint64_t buffer_state = buffer_state_->load();
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferAcquired(buffer_state)) {
ALOGE("ConsumerBuffer::LocalRelease: not acquired id=%d state=%" PRIx64 ".",
id(), buffer_state);
diff --git a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
index 03f2d95..31bf79d 100644
--- a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
+++ b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
@@ -14,6 +14,10 @@
// Checks if the buffer node is valid.
virtual bool isValid() = 0;
+
+ // Duplicates the client. Token_out will be set to a new token when succeed,
+ // and not changed when failed.
+ virtual status_t duplicate(uint64_t* outToken) = 0;
};
// BnInterface for IBufferClient. Should only be created in bufferhub service.
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index 1ea8302..09feb73 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -90,7 +90,9 @@
int cid() const { return cid_; }
// Returns the buffer buffer state.
- uint64_t buffer_state() { return buffer_state_->load(); };
+ uint64_t buffer_state() {
+ return buffer_state_->load(std::memory_order_acquire);
+ };
// A state mask which is unique to a buffer hub client among all its siblings
// sharing the same concrete graphic buffer.
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index 489692b..80a00be 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -40,7 +40,7 @@
uint64_t old_state;
uint64_t new_state;
do {
- old_state = buffer_state->load();
+ old_state = buffer_state->load(std::memory_order_acquire);
new_state = (old_state & ~clear_mask) | set_mask;
} while (!buffer_state->compare_exchange_weak(old_state, new_state));
}
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index 3730e7d..10517c5 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -80,7 +80,7 @@
return error;
// Check invalid state transition.
- uint64_t buffer_state = buffer_state_->load();
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferGained(buffer_state)) {
ALOGE("ProducerBuffer::LocalPost: not gained, id=%d state=%" PRIx64 ".",
id(), buffer_state);
@@ -135,7 +135,7 @@
int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta,
LocalHandle* out_fence, bool gain_posted_buffer) {
- uint64_t buffer_state = buffer_state_->load();
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
ALOGD_IF(TRACE, "ProducerBuffer::LocalGain: buffer=%d, state=%" PRIx64 ".",
id(), buffer_state);
@@ -168,7 +168,7 @@
out_meta->user_metadata_ptr = 0;
}
- uint64_t fence_state = fence_state_->load();
+ uint64_t fence_state = fence_state_->load(std::memory_order_acquire);
// If there is an release fence from consumer, we need to return it.
if (fence_state & BufferHubDefs::kConsumerStateMask) {
*out_fence = shared_release_fence_.Duplicate();
@@ -230,7 +230,7 @@
// TODO(b/112338294) Keep here for reference. Remove it after new logic is
// written.
- /* uint64_t buffer_state = buffer_state_->load();
+ /* uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferGained(buffer_state)) {
// Can only detach a ProducerBuffer when it's in gained state.
ALOGW("ProducerBuffer::Detach: The buffer (id=%d, state=0x%" PRIx64
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
new file mode 100644
index 0000000..a9af22f
--- /dev/null
+++ b/services/bufferhub/Android.bp
@@ -0,0 +1,61 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_shared {
+ name: "libbufferhubservice",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ srcs: [
+ "BufferHubService.cpp",
+ ],
+ shared_libs: [
+ "android.frameworks.bufferhub@1.0",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ ],
+ export_include_dirs: [
+ "include"
+ ],
+}
+
+cc_binary {
+ name: "android.frameworks.bufferhub@1.0-service",
+ relative_install_path: "hw",
+ srcs: [
+ "main_bufferhub.cpp"
+ ],
+ shared_libs: [
+ "android.frameworks.bufferhub@1.0",
+ "libbufferhubservice",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ init_rc: ["android.frameworks.bufferhub@1.0-service.rc"],
+ vintf_fragments: ["android.frameworks.bufferhub@1.0-service.xml"],
+}
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
new file mode 100644
index 0000000..8be85a5
--- /dev/null
+++ b/services/bufferhub/BufferHubService.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bufferhub/BufferHubService.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::status_t;
+using ::android::hardware::Void;
+
+Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& /*description*/,
+ allocateBuffer_cb /*hidl_cb*/) {
+ return Void();
+}
+
+Return<sp<IBase>> BufferHubService::importBuffer(const hidl_handle& /*nativeHandle*/) {
+ return nullptr;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
diff --git a/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc b/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc
new file mode 100644
index 0000000..36fbede
--- /dev/null
+++ b/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc
@@ -0,0 +1,6 @@
+service system_bufferhub /system/bin/hw/android.frameworks.bufferhub@1.0-service
+ class hal animation
+ user system
+ group system graphics
+ onrestart restart surfaceflinger
+ writepid /dev/cpuset/system-background/tasks
diff --git a/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml b/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml
new file mode 100644
index 0000000..bd958d3
--- /dev/null
+++ b/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+ <hal>
+ <name>android.frameworks.bufferhub</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IBufferHub</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
new file mode 100644
index 0000000..b273e5b
--- /dev/null
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
+#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
+
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::Return;
+using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
+using ::android::hidl::base::V1_0::IBase;
+
+class BufferHubService : public IBufferHub {
+public:
+ Return<void> allocateBuffer(const HardwareBufferDescription& /*description*/,
+ allocateBuffer_cb /*hidl_cb*/) override;
+ Return<sp<IBase>> importBuffer(const hidl_handle& /*nativeHandle*/) override;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
+
+#endif // ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
diff --git a/services/bufferhub/main_bufferhub.cpp b/services/bufferhub/main_bufferhub.cpp
new file mode 100644
index 0000000..084460d
--- /dev/null
+++ b/services/bufferhub/main_bufferhub.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bufferhub/BufferHubService.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+#include <log/log.h>
+
+using android::sp;
+using android::frameworks::bufferhub::V1_0::IBufferHub;
+using android::frameworks::bufferhub::V1_0::implementation::BufferHubService;
+
+int main(int /*argc*/, char** /*argv*/) {
+ ALOGI("Bootstrap bufferhub HIDL service.");
+
+ android::hardware::configureRpcThreadpool(/*numThreads=*/1, /*willJoin=*/true);
+
+ sp<IBufferHub> service = new BufferHubService();
+ LOG_ALWAYS_FATAL_IF(service->registerAsService() != android::OK, "Failed to register service");
+
+ android::hardware::joinRpcThreadpool();
+
+ return 0;
+}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ab07bc6..fc8ca54 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -513,6 +513,10 @@
return mDisplayTokens[id];
}
+bool SurfaceFlinger::isColorManagementUsed() const {
+ return useColorManagement;
+}
+
void SurfaceFlinger::bootFinished()
{
if (mStartPropertySetThread->join() != NO_ERROR) {
@@ -4744,6 +4748,7 @@
case SET_TRANSACTION_STATE:
// Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
case CREATE_SCOPED_CONNECTION:
+ case IS_COLOR_MANAGEMET_USED:
case GET_COMPOSITION_PREFERENCE: {
return OK;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9e47b3f..73c9d95 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -462,6 +462,7 @@
virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
status_t getCompositionPreference(ui::Dataspace* outDataSpace,
ui::PixelFormat* outPixelFormat) const override;
+ virtual bool isColorManagementUsed() const;
/* ------------------------------------------------------------------------
* DeathRecipient interface
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 43fa262..c219afd 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -451,6 +451,8 @@
}
void TimeStats::flushPowerTimeLocked() {
+ if (!mEnabled.load()) return;
+
nsecs_t curTime = systemTime();
// elapsedTime is in milliseconds.
int64_t elapsedTime = (curTime - mPowerTime.prevTime) / 1000000;
@@ -500,10 +502,14 @@
ALOGV("GlobalPresentFenceTime[%" PRId64 "]",
mGlobalRecord.presentFences.front()->getSignalTime());
- const int32_t presentToPresentMs = msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
- ALOGV("Global present2present[%d]", presentToPresentMs);
+ if (mGlobalRecord.prevPresentTime != 0) {
+ const int32_t presentToPresentMs =
+ msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
+ ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]",
+ presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime);
+ mTimeStats.presentToPresent.insert(presentToPresentMs);
+ }
- mTimeStats.presentToPresent.insert(presentToPresentMs);
mGlobalRecord.prevPresentTime = curPresentTime;
mGlobalRecord.presentFences.pop_front();
}
@@ -514,7 +520,15 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- if (presentFence == nullptr) {
+ if (presentFence == nullptr || !presentFence->isValid()) {
+ mGlobalRecord.prevPresentTime = 0;
+ return;
+ }
+
+ if (mPowerTime.powerMode != HWC_POWER_MODE_NORMAL) {
+ // Try flushing the last present fence on HWC_POWER_MODE_NORMAL.
+ flushAvailableGlobalRecordsToStatsLocked();
+ mGlobalRecord.presentFences.clear();
mGlobalRecord.prevPresentTime = 0;
return;
}
@@ -537,10 +551,10 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- ALOGD("Enabled");
mEnabled.store(true);
mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
mPowerTime.prevTime = systemTime();
+ ALOGD("Enabled");
}
void TimeStats::disable() {
@@ -549,16 +563,17 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- ALOGD("Disabled");
+ flushPowerTimeLocked();
mEnabled.store(false);
mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+ ALOGD("Disabled");
}
void TimeStats::clear() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- ALOGD("Cleared");
+ mTimeStatsTracker.clear();
mTimeStats.stats.clear();
mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
mTimeStats.statsEnd = 0;
@@ -568,6 +583,9 @@
mTimeStats.displayOnTime = 0;
mTimeStats.presentToPresent.hist.clear();
mPowerTime.prevTime = systemTime();
+ mGlobalRecord.prevPresentTime = 0;
+ mGlobalRecord.presentFences.clear();
+ ALOGD("Cleared");
}
bool TimeStats::isEnabled() {
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index c701224..599ff5c 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -39,7 +39,7 @@
if (delta < 0) return;
// std::lower_bound won't work on out of range values
if (delta > histogramConfig[HISTOGRAM_SIZE - 1]) {
- hist[histogramConfig[HISTOGRAM_SIZE - 1]]++;
+ hist[histogramConfig[HISTOGRAM_SIZE - 1]] += delta / histogramConfig[HISTOGRAM_SIZE - 1];
return;
}
auto iter = std::lower_bound(histogramConfig.begin(), histogramConfig.end(), delta);
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 3166a8c..c814142 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -30,6 +30,7 @@
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
+#include <ui/ColorSpace.h>
#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
#include <utils/String8.h>
@@ -314,6 +315,10 @@
ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<IBinder> binder = sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ mColorManagementUsed = sf->isColorManagementUsed();
}
virtual void TearDown() {
@@ -470,6 +475,8 @@
void setMatrixWithResizeHelper(uint32_t layerType);
sp<SurfaceControl> mBlackBgSurface;
+ bool mColorManagementUsed;
+
private:
void SetUpDisplay() {
mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
@@ -2064,6 +2071,47 @@
Transaction().setSidebandStream(layer, nullptr).apply();
}
+class ColorTransformHelper {
+public:
+ static void DegammaColorSingle(half& s) {
+ if (s <= 0.03928f)
+ s = s / 12.92f;
+ else
+ s = pow((s + 0.055f) / 1.055f, 2.4f);
+ }
+
+ static void DegammaColor(half3& color) {
+ DegammaColorSingle(color.r);
+ DegammaColorSingle(color.g);
+ DegammaColorSingle(color.b);
+ }
+
+ static void GammaColorSingle(half& s) {
+ if (s <= 0.0031308f) {
+ s = s * 12.92f;
+ } else {
+ s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f;
+ }
+ }
+
+ static void GammaColor(half3& color) {
+ GammaColorSingle(color.r);
+ GammaColorSingle(color.g);
+ GammaColorSingle(color.b);
+ }
+
+ static void applyMatrix(half3& color, const mat3& mat) {
+ half3 ret = half3(0);
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ ret[i] = ret[i] + color[j] * mat[j][i];
+ }
+ }
+ color = ret;
+ }
+};
+
TEST_F(LayerTransactionTest, SetColorTransformBasic) {
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(
@@ -2076,19 +2124,35 @@
}
const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
- const Color expected = {90, 90, 90, 255};
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
+ half3 expected = color;
mat3 matrix;
matrix[0][0] = 0.3; matrix[1][0] = 0.59; matrix[2][0] = 0.11;
matrix[0][1] = 0.3; matrix[1][1] = 0.59; matrix[2][1] = 0.11;
matrix[0][2] = 0.3; matrix[1][2] = 0.59; matrix[2][2] = 0.11;
+
+ // degamma before applying the matrix
+ if (mColorManagementUsed) {
+ ColorTransformHelper::DegammaColor(expected);
+ }
+
+ ColorTransformHelper::applyMatrix(expected, matrix);
+
+ if (mColorManagementUsed) {
+ ColorTransformHelper::GammaColor(expected);
+ }
+
+ const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+ uint8_t(expected.b * 255), 255};
+
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+
Transaction().setColor(colorLayer, color)
.setColorTransform(colorLayer, matrix, vec3()).apply();
{
SCOPED_TRACE("new color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
+ screenshot()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
}
}
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index c35ddd4..ea9bb1f 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -29,6 +29,7 @@
name: "libbufferhubd",
srcs: [
"buffer_channel.cpp",
+ "buffer_client.cpp",
"buffer_hub.cpp",
"buffer_hub_binder.cpp",
"buffer_node.cpp",
diff --git a/services/vr/bufferhubd/IBufferHub.cpp b/services/vr/bufferhubd/IBufferHub.cpp
index 2f39e41..022a9cc 100644
--- a/services/vr/bufferhubd/IBufferHub.cpp
+++ b/services/vr/bufferhubd/IBufferHub.cpp
@@ -13,6 +13,8 @@
uint32_t layer_count, uint32_t format,
uint64_t usage,
uint64_t user_metadata_size) override;
+
+ status_t importBuffer(uint64_t token, sp<IBufferClient>* outClient) override;
};
IMPLEMENT_META_INTERFACE(BufferHub, "android.dvr.IBufferHub");
@@ -20,6 +22,7 @@
// Transaction code
enum {
CREATE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+ IMPORT_BUFFER,
};
sp<IBufferClient> BpBufferHub::createBuffer(uint32_t width, uint32_t height,
@@ -50,6 +53,27 @@
}
}
+status_t BpBufferHub::importBuffer(uint64_t token,
+ sp<IBufferClient>* outClient) {
+ Parcel data, reply;
+ status_t ret = NO_ERROR;
+ ret |= data.writeInterfaceToken(IBufferHub::getInterfaceDescriptor());
+ ret |= data.writeUint64(token);
+ if (ret != NO_ERROR) {
+ ALOGE("BpBufferHub::importBuffer: failed to write into parcel");
+ return ret;
+ }
+
+ ret = remote()->transact(IMPORT_BUFFER, data, &reply);
+ if (ret == NO_ERROR) {
+ *outClient = interface_cast<IBufferClient>(reply.readStrongBinder());
+ return NO_ERROR;
+ } else {
+ ALOGE("BpBufferHub::importBuffer: failed to transact; errno=%d", ret);
+ return ret;
+ }
+}
+
status_t BnBufferHub::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
switch (code) {
@@ -64,7 +88,18 @@
sp<IBufferClient> ret = createBuffer(width, height, layer_count, format,
usage, user_metadata_size);
return reply->writeStrongBinder(IInterface::asBinder(ret));
- } break;
+ }
+ case IMPORT_BUFFER: {
+ CHECK_INTERFACE(IBufferHub, data, reply);
+ uint64_t token = data.readUint64();
+ sp<IBufferClient> client;
+ status_t ret = importBuffer(token, &client);
+ if (ret == NO_ERROR) {
+ return reply->writeStrongBinder(IInterface::asBinder(client));
+ } else {
+ return ret;
+ }
+ }
default:
// Should not reach except binder defined transactions such as dumpsys
return BBinder::onTransact(code, data, reply, flags);
diff --git a/services/vr/bufferhubd/buffer_client.cpp b/services/vr/bufferhubd/buffer_client.cpp
new file mode 100644
index 0000000..f14faf7
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_client.cpp
@@ -0,0 +1,18 @@
+#include <private/dvr/buffer_client.h>
+#include <private/dvr/buffer_hub_binder.h>
+
+namespace android {
+namespace dvr {
+
+status_t BufferClient::duplicate(uint64_t* outToken) {
+ if (!buffer_node_) {
+ // Should never happen
+ ALOGE("BufferClient::duplicate: node is missing.");
+ return UNEXPECTED_NULL;
+ }
+ return service_->registerToken(std::weak_ptr<BufferNode>(buffer_node_),
+ outToken);
+}
+
+} // namespace dvr
+} // namespace android
\ No newline at end of file
diff --git a/services/vr/bufferhubd/buffer_hub_binder.cpp b/services/vr/bufferhubd/buffer_hub_binder.cpp
index f8a9758..afd34aa 100644
--- a/services/vr/bufferhubd/buffer_hub_binder.cpp
+++ b/services/vr/bufferhubd/buffer_hub_binder.cpp
@@ -65,18 +65,65 @@
return NO_ERROR;
}
+status_t BufferHubBinderService::registerToken(
+ const std::weak_ptr<BufferNode> node, uint64_t* outToken) {
+ do {
+ *outToken = token_engine_();
+ } while (token_map_.find(*outToken) != token_map_.end());
+
+ token_map_.emplace(*outToken, node);
+ return NO_ERROR;
+}
+
sp<IBufferClient> BufferHubBinderService::createBuffer(
uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
uint64_t usage, uint64_t user_metadata_size) {
std::shared_ptr<BufferNode> node = std::make_shared<BufferNode>(
width, height, layer_count, format, usage, user_metadata_size);
- sp<BufferClient> client = new BufferClient(node);
+ sp<BufferClient> client = new BufferClient(node, this);
// Add it to list for bookkeeping and dumpsys.
client_list_.push_back(client);
return client;
}
+status_t BufferHubBinderService::importBuffer(uint64_t token,
+ sp<IBufferClient>* outClient) {
+ auto iter = token_map_.find(token);
+
+ if (iter == token_map_.end()) { // Not found
+ ALOGE("BufferHubBinderService::importBuffer: token %" PRIu64
+ "does not exist.",
+ token);
+ return PERMISSION_DENIED;
+ }
+
+ if (iter->second.expired()) { // Gone
+ ALOGW(
+ "BufferHubBinderService::importBuffer: the original node of token "
+ "%" PRIu64 "has gone.",
+ token);
+ token_map_.erase(iter);
+ return DEAD_OBJECT;
+ }
+
+ // Promote the weak_ptr
+ std::shared_ptr<BufferNode> node(iter->second);
+ if (!node) {
+ ALOGE("BufferHubBinderService::importBuffer: promote weak_ptr failed.");
+ token_map_.erase(iter);
+ return DEAD_OBJECT;
+ }
+
+ sp<BufferClient> client = new BufferClient(node, this);
+ *outClient = client;
+
+ token_map_.erase(iter);
+ client_list_.push_back(client);
+
+ return NO_ERROR;
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
index bd5f9cf..502c6d6 100644
--- a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
+++ b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
@@ -17,6 +17,9 @@
uint32_t layer_count, uint32_t format,
uint64_t usage,
uint64_t user_metadata_size) = 0;
+
+ virtual status_t importBuffer(uint64_t token,
+ sp<IBufferClient>* outClient) = 0;
};
class BnBufferHub : public BnInterface<IBufferHub> {
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_client.h b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
index 20d51ee..d79ec0a 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_client.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
@@ -7,19 +7,31 @@
namespace android {
namespace dvr {
+// Forward declaration to avoid circular dependency
+class BufferHubBinderService;
+
class BufferClient : public BnBufferClient {
public:
// Creates a server-side buffer client from an existing BufferNode. Note that
// this funciton takes ownership of the shared_ptr.
- explicit BufferClient(std::shared_ptr<BufferNode> node)
- : buffer_node_(std::move(node)){};
+ explicit BufferClient(std::shared_ptr<BufferNode> node,
+ BufferHubBinderService* service)
+ : service_(service), buffer_node_(std::move(node)){};
// Binder IPC functions
bool isValid() override {
return buffer_node_ ? buffer_node_->IsValid() : false;
};
+ status_t duplicate(uint64_t* outToken) override;
+
private:
+ // Hold a pointer to the service to bypass binder interface, as BufferClient
+ // and the service will be in the same process. Also, since service owns
+ // Client, if service dead the clients will be destroyed, so this pointer is
+ // guaranteed to be valid.
+ BufferHubBinderService* service_;
+
std::shared_ptr<BufferNode> buffer_node_;
};
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
index 9064d87..cf6124b 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
@@ -1,12 +1,15 @@
#ifndef ANDROID_DVR_BUFFER_HUB_BINDER_H
#define ANDROID_DVR_BUFFER_HUB_BINDER_H
+#include <random>
+#include <unordered_map>
#include <vector>
#include <binder/BinderService.h>
#include <private/dvr/IBufferHub.h>
#include <private/dvr/buffer_client.h>
#include <private/dvr/buffer_hub.h>
+#include <private/dvr/buffer_node.h>
namespace android {
namespace dvr {
@@ -15,20 +18,33 @@
public BnBufferHub {
public:
static status_t start(const std::shared_ptr<BufferHubService>& pdx_service);
- // Dump bufferhub related information to given fd (usually stdout)
+ // Dumps bufferhub related information to given fd (usually stdout)
// usage: adb shell dumpsys bufferhubd
virtual status_t dump(int fd, const Vector<String16>& args) override;
+ // Marks a BufferNode to be duplicated.
+ // TODO(b/116681016): add importToken(int64_t)
+ status_t registerToken(const std::weak_ptr<BufferNode> node,
+ uint64_t* outToken);
+
// Binder IPC functions
sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format,
uint64_t usage,
uint64_t user_metadata_size) override;
+ status_t importBuffer(uint64_t token, sp<IBufferClient>* outClient) override;
+
private:
std::shared_ptr<BufferHubService> pdx_service_;
std::vector<sp<BufferClient>> client_list_;
+
+ // TODO(b/118180214): use a more secure implementation
+ std::mt19937_64 token_engine_;
+ // The mapping from token to a specific node. This is a many-to-one mapping.
+ // One node could be refered by 0 to multiple tokens.
+ std::unordered_map<uint64_t, std::weak_ptr<BufferNode>> token_map_;
};
} // namespace dvr
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index c4c2ad2..5868b09 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -42,7 +42,9 @@
~ProducerChannel() override;
- uint64_t buffer_state() const { return buffer_state_->load(); }
+ uint64_t buffer_state() const {
+ return buffer_state_->load(std::memory_order_acquire);
+ }
bool HandleMessage(Message& message) override;
void HandleImpulse(Message& message) override;
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 476eca3..162065b 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -161,7 +161,8 @@
ALOGD_IF(TRACE,
"ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
"state=%" PRIx64 ".",
- channel_id(), buffer_id(), buffer_state_->load());
+ channel_id(), buffer_id(),
+ buffer_state_->load(std::memory_order_acquire));
for (auto consumer : consumer_channels_) {
consumer->OnProducerClosed();
}
@@ -177,7 +178,8 @@
return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
buffer_.height(), buffer_.layer_count(), buffer_.format(),
- buffer_.usage(), pending_consumers_, buffer_state_->load(),
+ buffer_.usage(), pending_consumers_,
+ buffer_state_->load(std::memory_order_acquire),
signaled_mask, metadata_header_->queue_index);
}
@@ -236,7 +238,7 @@
Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnGetBuffer");
ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
- buffer_id(), buffer_state_->load());
+ buffer_id(), buffer_state_->load(std::memory_order_acquire));
return {GetBuffer(BufferHubDefs::kProducerStateBit)};
}
@@ -304,8 +306,8 @@
return ErrorStatus(ENOMEM);
}
- if (!producer_owns_ &&
- !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
+ if (!producer_owns_ && !BufferHubDefs::IsBufferReleased(
+ buffer_state_->load(std::memory_order_acquire))) {
// Signal the new consumer when adding it to a posted producer.
if (consumer->OnProducerPosted())
pending_consumers_++;
@@ -406,7 +408,7 @@
ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
buffer_id());
- uint64_t buffer_state = buffer_state_->load();
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferGained(buffer_state)) {
// Can only detach a BufferProducer when it's in gained state.
ALOGW(
@@ -506,7 +508,7 @@
ALOGD_IF(TRACE,
"ProducerChannel::OnConsumerRelease: releasing last consumer: "
"buffer_id=%d state=%" PRIx64 ".",
- buffer_id(), buffer_state_->load());
+ buffer_id(), buffer_state_->load(std::memory_order_acquire));
if (orphaned_consumer_bit_mask_) {
ALOGW(
@@ -521,11 +523,12 @@
SignalAvailable();
}
- ALOGE_IF(pending_consumers_ &&
- BufferHubDefs::IsBufferReleased(buffer_state_->load()),
- "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
- "pending_consumers=%d, buffer buffer is in releaed state.",
- pending_consumers_);
+ ALOGE_IF(
+ pending_consumers_ && BufferHubDefs::IsBufferReleased(
+ buffer_state_->load(std::memory_order_acquire)),
+ "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
+ "pending_consumers=%d, buffer buffer is in releaed state.",
+ pending_consumers_);
return {};
}
@@ -564,7 +567,8 @@
"buffer_id=%d client_state_mask=%" PRIx64 " queue_index=%" PRIu64
" buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
buffer_id(), client_state_mask, metadata_header_->queue_index,
- buffer_state_->load(), fence_state_->load());
+ buffer_state_->load(std::memory_order_acquire),
+ fence_state_->load(std::memory_order_acquire));
}
void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
@@ -579,7 +583,7 @@
active_clients_bit_mask_->fetch_and(~channel->client_state_mask(),
std::memory_order_release);
- const uint64_t buffer_state = buffer_state_->load();
+ const uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (BufferHubDefs::IsBufferPosted(buffer_state) ||
BufferHubDefs::IsBufferAcquired(buffer_state)) {
// The consumer client is being destoryed without releasing. This could
@@ -592,7 +596,8 @@
BufferHubDefs::IsBufferGained(buffer_state)) {
// The consumer is being close while it is suppose to signal a release
// fence. Signal the dummy fence here.
- if (fence_state_->load() & channel->client_state_mask()) {
+ if (fence_state_->load(std::memory_order_acquire) &
+ channel->client_state_mask()) {
epoll_event event;
event.events = EPOLLIN;
event.data.u64 = channel->client_state_mask();
diff --git a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
index 7fa2226..7c00fa6 100644
--- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
@@ -10,6 +10,7 @@
namespace {
+using testing::IsNull;
using testing::NotNull;
const int kWidth = 640;
@@ -38,6 +39,46 @@
EXPECT_TRUE(bufferClient->isValid());
}
+TEST_F(BufferHubBinderServiceTest, TestDuplicateAndImportBuffer) {
+ sp<IBufferClient> bufferClient = service->createBuffer(
+ kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+ ASSERT_THAT(bufferClient, NotNull());
+ EXPECT_TRUE(bufferClient->isValid());
+
+ uint64_t token1 = 0ULL;
+ status_t ret = bufferClient->duplicate(&token1);
+ EXPECT_EQ(ret, NO_ERROR);
+
+ // Tokens should be unique even corresponding to the same buffer
+ uint64_t token2 = 0ULL;
+ ret = bufferClient->duplicate(&token2);
+ EXPECT_EQ(ret, NO_ERROR);
+ EXPECT_NE(token2, token1);
+
+ sp<IBufferClient> bufferClient1;
+ ret = service->importBuffer(token1, &bufferClient1);
+ EXPECT_EQ(ret, NO_ERROR);
+ ASSERT_THAT(bufferClient1, NotNull());
+ EXPECT_TRUE(bufferClient1->isValid());
+
+ // Consumes the token to keep the service clean
+ sp<IBufferClient> bufferClient2;
+ ret = service->importBuffer(token2, &bufferClient2);
+ EXPECT_EQ(ret, NO_ERROR);
+ ASSERT_THAT(bufferClient2, NotNull());
+ EXPECT_TRUE(bufferClient2->isValid());
+}
+
+TEST_F(BufferHubBinderServiceTest, TestImportUnexistingToken) {
+ // There is very little chance that this test fails if there is a token = 0
+ // in the service.
+ uint64_t unexistingToken = 0ULL;
+ sp<IBufferClient> bufferClient;
+ status_t ret = service->importBuffer(unexistingToken, &bufferClient);
+ EXPECT_EQ(ret, PERMISSION_DENIED);
+ EXPECT_THAT(bufferClient, IsNull());
+}
+
} // namespace
} // namespace dvr