Merge "lshal: uses instances API for --init-vintf" into pi-dev
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 57745ef..21d9ace 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -116,7 +116,8 @@
{ "database", "Database", ATRACE_TAG_DATABASE, { } },
{ "network", "Network", ATRACE_TAG_NETWORK, { } },
{ "adb", "ADB", ATRACE_TAG_ADB, { } },
- { "vibrator", "Vibrator", ATRACE_TAG_VIBRATOR, {}},
+ { "vibrator", "Vibrator", ATRACE_TAG_VIBRATOR, { } },
+ { "aidl", "AIDL calls", ATRACE_TAG_AIDL, { } },
{ k_coreServiceCategory, "Core services", 0, { } },
{ k_pdxServiceCategory, "PDX services", 0, { } },
{ "sched", "CPU Scheduling", 0, {
@@ -774,22 +775,10 @@
return ok;
}
-// Set all the kernel tracing settings to the desired state for this trace
-// capture.
-static bool setUpTrace()
+static bool setUpUserspaceTracing()
{
bool ok = true;
- // Set up the tracing options.
- ok &= setCategoriesEnableFromFile(g_categoriesFile);
- ok &= setTraceOverwriteEnable(g_traceOverwrite);
- ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
- // TODO: Re-enable after stabilization
- //ok &= setCmdlineSize();
- ok &= setClock();
- ok &= setPrintTgidEnableIfPresent(true);
- ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
-
// Set up the tags property.
uint64_t tags = 0;
for (size_t i = 0; i < arraysize(k_categories); i++) {
@@ -827,6 +816,37 @@
ok &= ServiceUtility::PokeServices();
}
+ return ok;
+}
+
+static void cleanUpUserspaceTracing()
+{
+ setTagsProperty(0);
+ clearAppProperties();
+ pokeBinderServices();
+
+ if (g_tracePdx) {
+ ServiceUtility::PokeServices();
+ }
+}
+
+
+// Set all the kernel tracing settings to the desired state for this trace
+// capture.
+static bool setUpKernelTracing()
+{
+ bool ok = true;
+
+ // Set up the tracing options.
+ ok &= setCategoriesEnableFromFile(g_categoriesFile);
+ ok &= setTraceOverwriteEnable(g_traceOverwrite);
+ ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
+ // TODO: Re-enable after stabilization
+ //ok &= setCmdlineSize();
+ ok &= setClock();
+ ok &= setPrintTgidEnableIfPresent(true);
+ ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
+
// Disable all the sysfs enables. This is done as a separate loop from
// the enables to allow the same enable to exist in multiple categories.
ok &= disableKernelTraceEvents();
@@ -854,20 +874,11 @@
}
// Reset all the kernel tracing settings to their default state.
-static void cleanUpTrace()
+static void cleanUpKernelTracing()
{
// Disable all tracing that we're able to.
disableKernelTraceEvents();
- // Reset the system properties.
- setTagsProperty(0);
- clearAppProperties();
- pokeBinderServices();
-
- if (g_tracePdx) {
- ServiceUtility::PokeServices();
- }
-
// Set the options back to their defaults.
setTraceOverwriteEnable(true);
setTraceBufferSizeKB(1);
@@ -875,7 +886,6 @@
setKernelTraceFuncs(NULL);
}
-
// Enable tracing in the kernel.
static bool startTrace()
{
@@ -1107,6 +1117,7 @@
bool traceStop = true;
bool traceDump = true;
bool traceStream = false;
+ bool onlyUserspace = false;
if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
showHelp(argv[0]);
@@ -1122,12 +1133,13 @@
int ret;
int option_index = 0;
static struct option long_options[] = {
- {"async_start", no_argument, 0, 0 },
- {"async_stop", no_argument, 0, 0 },
- {"async_dump", no_argument, 0, 0 },
- {"list_categories", no_argument, 0, 0 },
- {"stream", no_argument, 0, 0 },
- { 0, 0, 0, 0 }
+ {"async_start", no_argument, 0, 0 },
+ {"async_stop", no_argument, 0, 0 },
+ {"async_dump", no_argument, 0, 0 },
+ {"only_userspace", no_argument, 0, 0 },
+ {"list_categories", no_argument, 0, 0 },
+ {"stream", no_argument, 0, 0 },
+ { 0, 0, 0, 0 }
};
ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:",
@@ -1197,6 +1209,8 @@
async = true;
traceStart = false;
traceStop = false;
+ } else if (!strcmp(long_options[option_index].name, "only_userspace")) {
+ onlyUserspace = true;
} else if (!strcmp(long_options[option_index].name, "stream")) {
traceStream = true;
traceDump = false;
@@ -1214,6 +1228,14 @@
}
}
+ if (onlyUserspace) {
+ if (!async || !(traceStart || traceStop)) {
+ fprintf(stderr, "--only_userspace can only be used with "
+ "--async_start or --async_stop\n");
+ exit(1);
+ }
+ }
+
registerSigHandler();
if (g_initialSleepSecs > 0) {
@@ -1221,13 +1243,19 @@
}
bool ok = true;
+
if (traceStart) {
- ok &= setUpTrace();
+ ok &= setUpUserspaceTracing();
+ }
+
+ if (ok && traceStart && !onlyUserspace) {
+ ok &= setUpKernelTracing();
ok &= startTrace();
}
if (ok && traceStart) {
- if (!traceStream) {
+
+ if (!traceStream && !onlyUserspace) {
printf("capturing trace...");
fflush(stdout);
}
@@ -1237,9 +1265,12 @@
// contain entries from only one CPU can cause "begin" entries without a
// matching "end" entry to show up if a task gets migrated from one CPU to
// another.
- ok = clearTrace();
+ if (!onlyUserspace)
+ ok = clearTrace();
- writeClockSyncMarker();
+ if (!onlyUserspace)
+ writeClockSyncMarker();
+
if (ok && !async && !traceStream) {
// Sleep to allow the trace to be captured.
struct timespec timeLeft;
@@ -1258,10 +1289,10 @@
}
// Stop the trace and restore the default settings.
- if (traceStop)
+ if (traceStop && !onlyUserspace)
stopTrace();
- if (ok && traceDump) {
+ if (ok && traceDump && !onlyUserspace) {
if (!g_traceAborted) {
printf(" done\n");
fflush(stdout);
@@ -1288,8 +1319,11 @@
}
// Reset the trace buffer size to 1.
- if (traceStop)
- cleanUpTrace();
+ if (traceStop) {
+ cleanUpUserspaceTracing();
+ if (!onlyUserspace)
+ cleanUpKernelTracing();
+ }
return g_traceAborted ? 1 : 0;
}
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index 4b90765..bbf157b 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -427,14 +427,15 @@
* use cases, corresponding to index OMX_IndexParamVideoAndroidImageGrid.
*
* OMX_VIDEO_CodingImageHEIC encoders must handle this param type. When this param is set
- * on the component with bEnabled set to true, nGrid* indicates the desired grid config
- * by the client. The component can use this as a heuristic, but is free to choose any
- * suitable grid configs, and the client shall always get the actual from the component
- * after the param is set. Encoder will receive each input image in full, and shall encode
- * it into tiles in row-major, top-row first, left-to-right order, and send each encoded
- * tile in a separate output buffer. All output buffers for the same input buffer shall
- * carry the same timestamp as the input buffer. If the input buffer is marked EOS,
- * the EOS should only appear on the last output buffer for that input buffer.
+ * on the component with bEnabled set to true, nTileWidth, nTileHeight, nGridRows,
+ * nGridCols indicates the desired grid config by the client. The component can use this
+ * as a heuristic, and is free to choose any suitable grid configs. The client shall
+ * always get the actual from the component after the param is set. Encoder will receive
+ * each input image in full, and shall encode it into tiles in row-major, top-row first,
+ * left-to-right order, and send each encoded tile in a separate output buffer. All output
+ * buffers for the same input buffer shall carry the same timestamp as the input buffer.
+ * If the input buffer is marked EOS, the EOS should only appear on the last output buffer
+ * for that input buffer.
*
* OMX_VIDEO_CodingHEVC encoders might also receive this param when it's used for image
* encoding, although in this case the param only serves as a hint. The encoder will
@@ -446,10 +447,10 @@
* nSize : Size of the structure in bytes
* nVersion : OMX specification version information
* nPortIndex : Port that this structure applies to (output port for encoders)
- * bEnabled : Whether grid is enabled. If true, nGrid* specifies the grid
- * config; otherwise nGrid* shall be ignored.
- * nGridWidth : Width of each tile.
- * nGridHeight : Height of each tile.
+ * bEnabled : Whether grid is enabled. If true, the other parameters
+ * specifies the grid config; otherwise they shall be ignored.
+ * nTileWidth : Width of each tile.
+ * nTileHeight : Height of each tile.
* nGridRows : Number of rows in the grid.
* nGridCols : Number of cols in the grid.
*/
@@ -458,8 +459,8 @@
OMX_VERSIONTYPE nVersion;
OMX_U32 nPortIndex;
OMX_BOOL bEnabled;
- OMX_U32 nGridWidth;
- OMX_U32 nGridHeight;
+ OMX_U32 nTileWidth;
+ OMX_U32 nTileHeight;
OMX_U32 nGridRows;
OMX_U32 nGridCols;
} OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE;
diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp
index e1cc5da..9adac26 100644
--- a/libs/binder/ActivityManager.cpp
+++ b/libs/binder/ActivityManager.cpp
@@ -80,4 +80,20 @@
}
}
+status_t ActivityManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient) {
+ sp<IActivityManager> service = getService();
+ if (service != NULL) {
+ return IInterface::asBinder(service)->linkToDeath(recipient);
+ }
+ return INVALID_OPERATION;
+}
+
+status_t ActivityManager::unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient) {
+ sp<IActivityManager> service = getService();
+ if (service != NULL) {
+ return IInterface::asBinder(service)->unlinkToDeath(recipient);
+ }
+ return INVALID_OPERATION;
+}
+
}; // namespace android
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
index 408c428..397382f 100644
--- a/libs/binder/include/binder/ActivityManager.h
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -51,6 +51,9 @@
const String16& callingPackage);
void unregisterUidObserver(const sp<IUidObserver>& observer);
+ status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+ status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+
private:
Mutex mLock;
sp<IActivityManager> mService;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 61ed976..38f0eb7 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -612,7 +612,25 @@
uint32_t windowType,
uint32_t ownerUid)
{
+ sp<SurfaceControl> s;
+ createSurfaceChecked(name, w, h, format, &s, flags, parent, windowType, ownerUid);
+ return s;
+}
+
+status_t SurfaceComposerClient::createSurfaceChecked(
+ const String8& name,
+ uint32_t w,
+ uint32_t h,
+ PixelFormat format,
+ sp<SurfaceControl>* outSurface,
+ uint32_t flags,
+ SurfaceControl* parent,
+ uint32_t windowType,
+ uint32_t ownerUid)
+{
sp<SurfaceControl> sur;
+ status_t err = NO_ERROR;
+
if (mStatus == NO_ERROR) {
sp<IBinder> handle;
sp<IBinder> parentHandle;
@@ -621,14 +639,14 @@
if (parent != nullptr) {
parentHandle = parent->getHandle();
}
- status_t err = mClient->createSurface(name, w, h, format, flags, parentHandle,
+ err = mClient->createSurface(name, w, h, format, flags, parentHandle,
windowType, ownerUid, &handle, &gbp);
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
- sur = new SurfaceControl(this, handle, gbp, true /* owned */);
+ *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */);
}
}
- return sur;
+ return err;
}
status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 162fe6e..5ce20ad 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -115,6 +115,18 @@
uint32_t ownerUid = 0 // UID of the task
);
+ status_t createSurfaceChecked(
+ const String8& name,// name of the surface
+ uint32_t w, // width in pixel
+ uint32_t h, // height in pixel
+ PixelFormat format, // pixel-format desired
+ sp<SurfaceControl>* outSurface,
+ uint32_t flags = 0, // usage flags
+ SurfaceControl* parent = nullptr, // parent
+ uint32_t windowType = 0, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
+ uint32_t ownerUid = 0 // UID of the task
+ );
+
//! Create a virtual display
static sp<IBinder> createDisplay(const String8& displayName, bool secure);
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index b7a6099..3ce5c9f 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -25,7 +25,9 @@
using android::dvr::BufferHubDefs::IsBufferAcquired;
using android::dvr::BufferHubDefs::IsBufferReleased;
using android::dvr::BufferProducer;
+using android::pdx::LocalChannelHandle;
using android::pdx::LocalHandle;
+using android::pdx::Status;
const int kWidth = 640;
const int kHeight = 480;
@@ -717,3 +719,59 @@
// Producer should be able to gain no matter what.
EXPECT_EQ(0, p->GainAsync(&meta, &fence));
}
+
+TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(p.get() != nullptr);
+ ASSERT_TRUE(c.get() != nullptr);
+
+ DvrNativeBufferMetadata metadata;
+ LocalHandle invalid_fence;
+
+ // Detach in posted state should fail.
+ EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+ EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+ auto s1 = p->Detach();
+ EXPECT_FALSE(s1);
+
+ // Detach in acquired state should fail.
+ EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+ s1 = p->Detach();
+ EXPECT_FALSE(s1);
+
+ // Detach in released state should fail.
+ EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
+ EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+ s1 = p->Detach();
+ EXPECT_FALSE(s1);
+
+ // Detach in gained state should succeed.
+ EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
+ s1 = p->Detach();
+ EXPECT_TRUE(s1);
+
+ LocalChannelHandle detached_buffer = s1.take();
+ EXPECT_TRUE(detached_buffer.valid());
+
+ // Both producer and consumer should have hangup.
+ EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+ auto s2 = p->GetEventMask(POLLHUP);
+ EXPECT_TRUE(s2);
+ EXPECT_EQ(s2.get(), POLLHUP);
+
+ EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+ s2 = p->GetEventMask(POLLHUP);
+ EXPECT_TRUE(s2);
+ EXPECT_EQ(s2.get(), POLLHUP);
+
+ auto s3 = p->CreateConsumer();
+ EXPECT_FALSE(s3);
+ EXPECT_EQ(s3.error(), EOPNOTSUPP);
+
+ s3 = c->CreateConsumer();
+ EXPECT_FALSE(s3);
+ EXPECT_EQ(s3.error(), EOPNOTSUPP);
+}
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index 6db09a9..13971eb 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -608,5 +608,23 @@
: LocalChannelHandle{nullptr, -status.error()});
}
+Status<LocalChannelHandle> BufferProducer::Detach() {
+ uint64_t buffer_state = buffer_state_->load();
+ if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+ // Can only detach a BufferProducer when it's in gained state.
+ ALOGW("BufferProducer::Detach: The buffer (id=%d, state=0x%" PRIx64
+ ") is not in gained state.",
+ id(), buffer_state);
+ return {};
+ }
+
+ Status<LocalChannelHandle> status =
+ InvokeRemoteMethod<BufferHubRPC::ProducerBufferDetach>();
+ ALOGE_IF(!status,
+ "BufferProducer::Detach: Failed to detach buffer (id=%d): %s.", id(),
+ status.GetErrorMessage().c_str());
+ return status;
+}
+
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index c791250..32448a1 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -217,6 +217,14 @@
// succeeded, or a negative errno code if local error check fails.
int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+ // Detaches a ProducerBuffer from an existing producer/consumer set. Can only
+ // be called when a producer buffer has exclusive access to the buffer (i.e.
+ // in the gain'ed state). On the successful return of the IPC call, a new
+ // LocalChannelHandle representing a detached buffer will be returned and all
+ // existing producer and consumer channels will be closed. Further IPCs
+ // towards those channels will return error.
+ Status<LocalChannelHandle> Detach();
+
private:
friend BASE;
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index c70fffc..fabefd5 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -373,6 +373,10 @@
kOpConsumerAcquire,
kOpConsumerRelease,
kOpConsumerSetIgnore,
+ kOpProducerBufferDetach,
+ kOpConsumerBufferDetach,
+ kOpCreateDetachedBuffer,
+ kOpDetachedBufferPromote,
kOpCreateProducerQueue,
kOpCreateConsumerQueue,
kOpGetQueueInfo,
@@ -400,6 +404,28 @@
PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease,
void(LocalFence release_fence));
PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, void(bool ignore));
+ PDX_REMOTE_METHOD(ProducerBufferDetach, kOpProducerBufferDetach,
+ LocalChannelHandle(Void));
+
+ // Detaches a ConsumerBuffer from an existing producer/consumer set. Can only
+ // be called when the consumer is the only consumer and it has exclusive
+ // access to the buffer (i.e. in the acquired'ed state). On the successful
+ // return of the IPC call, a new DetachedBufferChannel handle will be returned
+ // and all existing producer and consumer channels will be closed. Further
+ // IPCs towards those channels will return error.
+ PDX_REMOTE_METHOD(ConsumerBufferDetach, kOpConsumerBufferDetach,
+ LocalChannelHandle(Void));
+
+ // Creates a standalone DetachedBuffer not associated with any
+ // producer/consumer set.
+ PDX_REMOTE_METHOD(CreateDetachedBuffer, kOpCreateDetachedBuffer,
+ LocalChannelHandle(Void));
+
+ // 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.
+ PDX_REMOTE_METHOD(DetachedBufferPromote, kOpDetachedBufferPromote,
+ LocalChannelHandle(Void));
// Buffer Queue Methods.
PDX_REMOTE_METHOD(CreateProducerQueue, kOpCreateProducerQueue,
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index b7bf964..47f4e46 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -144,31 +144,31 @@
void Device::onHotplug(hwc2_display_t displayId, Connection connection) {
if (connection == Connection::Connected) {
- auto display = getDisplayById(displayId);
- if (display) {
- if (display->isConnected()) {
- ALOGW("Attempt to hotplug connect display %" PRIu64
- " , which is already connected.", displayId);
- } else {
- display->setConnected(true);
- }
- } else {
- DisplayType displayType;
- auto intError = mComposer->getDisplayType(displayId,
- reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(
- &displayType));
- auto error = static_cast<Error>(intError);
- if (error != Error::None) {
- ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d). "
- "Aborting hotplug attempt.",
- displayId, to_string(error).c_str(), intError);
- return;
- }
-
- auto newDisplay = std::make_unique<Display>(
- *mComposer.get(), mCapabilities, displayId, displayType);
- mDisplays.emplace(displayId, std::move(newDisplay));
+ // If we get a hotplug connected event for a display we already have,
+ // destroy the display and recreate it. This will force us to requery
+ // the display params and recreate all layers on that display.
+ auto oldDisplay = getDisplayById(displayId);
+ if (oldDisplay != nullptr && oldDisplay->isConnected()) {
+ ALOGI("Hotplug connecting an already connected display."
+ " Clearing old display state.");
}
+ mDisplays.erase(displayId);
+
+ DisplayType displayType;
+ auto intError = mComposer->getDisplayType(displayId,
+ reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(
+ &displayType));
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d). "
+ "Aborting hotplug attempt.",
+ displayId, to_string(error).c_str(), intError);
+ return;
+ }
+
+ auto newDisplay = std::make_unique<Display>(
+ *mComposer.get(), mCapabilities, displayId, displayType);
+ mDisplays.emplace(displayId, std::move(newDisplay));
} else if (connection == Connection::Disconnected) {
// The display will later be destroyed by a call to
// destroyDisplay(). For now we just mark it disconnected.
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 7a43ea9..6a34981 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -305,15 +305,24 @@
if (needs.hasToneMapping()) {
fs << R"__SHADER__(
- float ToneMapChannel(const float color) {
+ float CalculateY(const vec3 color) {
+ // BT2020 standard uses the unadjusted KR = 0.2627,
+ // KB = 0.0593 luminance interpretation for RGB conversion.
+ return color.r * 0.262700 + color.g * 0.677998 +
+ color.b * 0.059302;
+ }
+ vec3 ToneMap(const vec3 color) {
const float maxLumi = 10000.0;
const float maxMasteringLumi = 1000.0;
const float maxContentLumi = 1000.0;
const float maxInLumi = min(maxMasteringLumi, maxContentLumi);
const float maxOutLumi = 500.0;
+ // Calculate Y value in XYZ color space.
+ float colorY = CalculateY(color);
+
// convert to nits first
- float nits = color * maxLumi;
+ float nits = colorY * maxLumi;
// clamp to max input luminance
nits = clamp(nits, 0.0, maxInLumi);
@@ -360,12 +369,8 @@
}
// convert back to [0.0, 1.0]
- return nits / maxOutLumi;
- }
-
- vec3 ToneMap(const vec3 color) {
- return vec3(ToneMapChannel(color.r), ToneMapChannel(color.g),
- ToneMapChannel(color.b));
+ float targetY = nits / maxOutLumi;
+ return color * (targetY / max(1e-6, colorY));
}
)__SHADER__";
} else {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 11658e8..a6e0a9e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2120,16 +2120,16 @@
getBE().mHwc->onHotplug(event.display, displayType, event.connection);
if (event.connection == HWC2::Connection::Connected) {
- ALOGV("Creating built in display %d", displayType);
- ALOGW_IF(mBuiltinDisplays[displayType],
- "Overwriting display token for display type %d", displayType);
- mBuiltinDisplays[displayType] = new BBinder();
- // All non-virtual displays are currently considered secure.
- DisplayDeviceState info(displayType, true);
- info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ?
- "Built-in Screen" : "External Screen";
- mCurrentState.displays.add(mBuiltinDisplays[displayType], info);
- mInterceptor.saveDisplayCreation(info);
+ if (!mBuiltinDisplays[displayType].get()) {
+ ALOGV("Creating built in display %d", displayType);
+ mBuiltinDisplays[displayType] = new BBinder();
+ // All non-virtual displays are currently considered secure.
+ DisplayDeviceState info(displayType, true);
+ info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ?
+ "Built-in Screen" : "External Screen";
+ mCurrentState.displays.add(mBuiltinDisplays[displayType], info);
+ mInterceptor.saveDisplayCreation(info);
+ }
} else {
ALOGV("Removing built in display %d", displayType);
@@ -3980,7 +3980,7 @@
LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
- result.append(LayerProtoParser::layersToString(layerTree).c_str());
+ result.append(LayerProtoParser::layersToString(std::move(layerTree)).c_str());
/*
* Dump Display state
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index bf37e1e..c9b7fe5 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#include <android-base/stringprintf.h>
#include <layerproto/LayerProtoParser.h>
#include <ui/DebugUtils.h>
@@ -24,7 +23,7 @@
namespace android {
namespace surfaceflinger {
-bool sortLayers(const LayerProtoParser::Layer* lhs, const LayerProtoParser::Layer* rhs) {
+bool sortLayers(LayerProtoParser::Layer* lhs, const LayerProtoParser::Layer* rhs) {
uint32_t ls = lhs->layerStack;
uint32_t rs = rhs->layerStack;
if (ls != rs) return ls < rs;
@@ -38,20 +37,25 @@
return lhs->id < rhs->id;
}
-std::vector<const LayerProtoParser::Layer*> LayerProtoParser::generateLayerTree(
+bool sortLayerUniquePtrs(const std::unique_ptr<LayerProtoParser::Layer>& lhs,
+ const std::unique_ptr<LayerProtoParser::Layer>& rhs) {
+ return sortLayers(lhs.get(), rhs.get());
+}
+
+std::vector<std::unique_ptr<LayerProtoParser::Layer>> LayerProtoParser::generateLayerTree(
const LayersProto& layersProto) {
- auto layerMap = generateMap(layersProto);
+ std::unordered_map<int32_t, LayerProtoParser::Layer*> layerMap = generateMap(layersProto);
+ std::vector<std::unique_ptr<LayerProtoParser::Layer>> layers;
- std::vector<const Layer*> layers;
- std::for_each(layerMap.begin(), layerMap.end(),
- [&](const std::pair<const int32_t, Layer*>& ref) {
- if (ref.second->parent == nullptr) {
- // only save top level layers
- layers.push_back(ref.second);
- }
- });
+ for (std::pair<int32_t, Layer*> kv : layerMap) {
+ if (kv.second->parent == nullptr) {
+ // Make unique_ptr for top level layers since they are not children. This ensures there
+ // will only be one unique_ptr made for each layer.
+ layers.push_back(std::unique_ptr<Layer>(kv.second));
+ }
+ }
- std::sort(layers.begin(), layers.end(), sortLayers);
+ std::sort(layers.begin(), layers.end(), sortLayerUniquePtrs);
return layers;
}
@@ -155,63 +159,61 @@
for (int i = 0; i < layerProto.children_size(); i++) {
if (layerMap.count(layerProto.children(i)) > 0) {
- auto childLayer = layerMap[layerProto.children(i)];
- currLayer->children.push_back(childLayer);
+ // Only make unique_ptrs for children since they are guaranteed to be unique, only one
+ // parent per child. This ensures there will only be one unique_ptr made for each layer.
+ currLayer->children.push_back(std::unique_ptr<Layer>(layerMap[layerProto.children(i)]));
}
}
for (int i = 0; i < layerProto.relatives_size(); i++) {
if (layerMap.count(layerProto.relatives(i)) > 0) {
- auto relativeLayer = layerMap[layerProto.relatives(i)];
- currLayer->relatives.push_back(relativeLayer);
+ currLayer->relatives.push_back(layerMap[layerProto.relatives(i)]);
}
}
if (layerProto.has_parent()) {
if (layerMap.count(layerProto.parent()) > 0) {
- auto parentLayer = layerMap[layerProto.parent()];
- currLayer->parent = parentLayer;
+ currLayer->parent = layerMap[layerProto.parent()];
}
}
if (layerProto.has_z_order_relative_of()) {
if (layerMap.count(layerProto.z_order_relative_of()) > 0) {
- auto relativeLayer = layerMap[layerProto.z_order_relative_of()];
- currLayer->zOrderRelativeOf = relativeLayer;
+ currLayer->zOrderRelativeOf = layerMap[layerProto.z_order_relative_of()];
}
}
}
std::string LayerProtoParser::layersToString(
- const std::vector<const LayerProtoParser::Layer*> layers) {
+ std::vector<std::unique_ptr<LayerProtoParser::Layer>> layers) {
std::string result;
- for (const LayerProtoParser::Layer* layer : layers) {
+ for (std::unique_ptr<LayerProtoParser::Layer>& layer : layers) {
if (layer->zOrderRelativeOf != nullptr) {
continue;
}
- result.append(layerToString(layer).c_str());
+ result.append(layerToString(layer.get()).c_str());
}
return result;
}
-std::string LayerProtoParser::layerToString(const LayerProtoParser::Layer* layer) {
+std::string LayerProtoParser::layerToString(LayerProtoParser::Layer* layer) {
std::string result;
- std::vector<const Layer*> traverse(layer->relatives);
- for (const LayerProtoParser::Layer* child : layer->children) {
+ std::vector<Layer*> traverse(layer->relatives);
+ for (std::unique_ptr<LayerProtoParser::Layer>& child : layer->children) {
if (child->zOrderRelativeOf != nullptr) {
continue;
}
- traverse.push_back(child);
+ traverse.push_back(child.get());
}
std::sort(traverse.begin(), traverse.end(), sortLayers);
size_t i = 0;
for (; i < traverse.size(); i++) {
- const auto& relative = traverse[i];
+ auto& relative = traverse[i];
if (relative->z >= 0) {
break;
}
@@ -220,7 +222,7 @@
result.append(layer->to_string().c_str());
result.append("\n");
for (; i < traverse.size(); i++) {
- const auto& relative = traverse[i];
+ auto& relative = traverse[i];
result.append(layerToString(relative).c_str());
}
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 78c6cd1..b81a959 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -18,6 +18,7 @@
#include <math/vec4.h>
+#include <memory>
#include <unordered_map>
#include <vector>
@@ -68,8 +69,8 @@
public:
int32_t id;
std::string name;
- std::vector<const Layer*> children;
- std::vector<const Layer*> relatives;
+ std::vector<std::unique_ptr<Layer>> children;
+ std::vector<Layer*> relatives;
std::string type;
LayerProtoParser::Region transparentRegion;
LayerProtoParser::Region visibleRegion;
@@ -99,8 +100,8 @@
std::string to_string() const;
};
- static std::vector<const Layer*> generateLayerTree(const LayersProto& layersProto);
- static std::string layersToString(const std::vector<const LayerProtoParser::Layer*> layers);
+ static std::vector<std::unique_ptr<Layer>> generateLayerTree(const LayersProto& layersProto);
+ static std::string layersToString(std::vector<std::unique_ptr<LayerProtoParser::Layer>> layers);
private:
static std::unordered_map<int32_t, Layer*> generateMap(const LayersProto& layersProto);
@@ -113,7 +114,7 @@
static void updateChildrenAndRelative(const LayerProto& layerProto,
std::unordered_map<int32_t, Layer*>& layerMap);
- static std::string layerToString(const LayerProtoParser::Layer* layer);
+ static std::string layerToString(LayerProtoParser::Layer* layer);
};
} // namespace surfaceflinger
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 7d3da32..7523399 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -33,6 +33,7 @@
"libEGL",
"libGLESv2",
"libgui",
+ "liblayers_proto",
"liblog",
"libprotobuf-cpp-full",
"libui",
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
index 33dd2f5..4577153 100644
--- a/services/surfaceflinger/tests/Stress_test.cpp
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -22,7 +22,7 @@
#include <thread>
#include <functional>
-
+#include <layerproto/LayerProtoParser.h>
namespace android {
@@ -47,4 +47,66 @@
}
}
+surfaceflinger::LayersProto generateLayerProto() {
+ surfaceflinger::LayersProto layersProto;
+ std::array<surfaceflinger::LayerProto*, 10> layers = {};
+ for (size_t i = 0; i < layers.size(); ++i) {
+ layers[i] = layersProto.add_layers();
+ layers[i]->set_id(i);
+ }
+
+ layers[0]->add_children(1);
+ layers[1]->set_parent(0);
+ layers[0]->add_children(2);
+ layers[2]->set_parent(0);
+ layers[0]->add_children(3);
+ layers[3]->set_parent(0);
+ layers[2]->add_children(4);
+ layers[4]->set_parent(2);
+ layers[3]->add_children(5);
+ layers[5]->set_parent(3);
+ layers[5]->add_children(6);
+ layers[6]->set_parent(5);
+ layers[5]->add_children(7);
+ layers[7]->set_parent(5);
+ layers[6]->add_children(8);
+ layers[8]->set_parent(6);
+
+ layers[4]->set_z_order_relative_of(3);
+ layers[3]->add_relatives(4);
+ layers[8]->set_z_order_relative_of(9);
+ layers[9]->add_relatives(8);
+ layers[3]->set_z_order_relative_of(1);
+ layers[1]->add_relatives(3);
+
+/* ----------------------------
+ * - 0 - - 9 -
+ * / | \
+ * 1 2 3(1)
+ * | |
+ * 4(3) 5
+ * / \
+ * 6 7
+ * |
+ * 8(9)
+ * -------------------------- */
+
+ return layersProto;
+}
+
+TEST(LayerProtoStress, mem_info) {
+ std::string cmd = "dumpsys meminfo ";
+ cmd += std::to_string(getpid());
+ system(cmd.c_str());
+ for (int i = 0; i < 100000; i++) {
+ surfaceflinger::LayersProto layersProto = generateLayerProto();
+ auto layerTree = surfaceflinger::LayerProtoParser::generateLayerTree(layersProto);
+ // Allow some layerTrees to just fall out of scope (instead of std::move)
+ if (i % 2) {
+ surfaceflinger::LayerProtoParser::layersToString(std::move(layerTree));
+ }
+ }
+ system(cmd.c_str());
+}
+
}
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 6009a95..6122846 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -17,6 +17,7 @@
"bufferhubd.cpp",
"consumer_channel.cpp",
"producer_channel.cpp",
+ "detached_buffer_channel.cpp",
"consumer_queue_channel.cpp",
"producer_queue_channel.cpp",
]
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index 1eb4ef9..e4e19c7 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -100,6 +100,41 @@
stream << std::setw(8) << info.index;
stream << std::endl;
}
+
+ if (channel->channel_type() == BufferHubChannel::kDetachedBufferType) {
+ BufferHubChannel::BufferInfo info = channel->GetBufferInfo();
+
+ stream << std::right;
+ stream << std::setw(6) << info.id;
+ stream << " ";
+ stream << std::setw(9) << "N/A";
+ stream << " ";
+ if (info.format == HAL_PIXEL_FORMAT_BLOB) {
+ std::string size = std::to_string(info.width) + " B";
+ stream << std::setw(14) << size;
+ } else {
+ std::string dimensions = std::to_string(info.width) + "x" +
+ std::to_string(info.height) + "x" +
+ std::to_string(info.layer_count);
+ stream << std::setw(14) << dimensions;
+ }
+ stream << " ";
+ stream << std::setw(6) << info.format;
+ stream << " ";
+ stream << "0x" << std::hex << std::setfill('0');
+ stream << std::setw(8) << info.usage;
+ stream << std::dec << std::setfill(' ');
+ stream << " ";
+ stream << std::setw(9) << "N/A";
+ stream << " ";
+ stream << std::hex << std::setfill(' ');
+ stream << std::setw(18) << "Detached";
+ stream << " ";
+ stream << std::setw(18) << "N/A";
+ stream << " ";
+ stream << std::setw(10) << "N/A";
+ stream << std::endl;
+ }
}
stream << std::endl;
@@ -215,6 +250,15 @@
*this, &BufferHubService::OnCreateProducerQueue, message);
return {};
+ case BufferHubRPC::ProducerBufferDetach::Opcode:
+ // In addition to the message handler in the ProducerChannel's
+ // HandleMessage method, we also need to invalid the producer channel (and
+ // all associated consumer channels). 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_hub.h b/services/vr/bufferhubd/buffer_hub.h
index b487b0b..e04967a 100644
--- a/services/vr/bufferhubd/buffer_hub.h
+++ b/services/vr/bufferhubd/buffer_hub.h
@@ -23,6 +23,7 @@
enum ChannelType {
kProducerType,
kConsumerType,
+ kDetachedBufferType,
kProducerQueueType,
kConsumerQueueType,
};
diff --git a/services/vr/bufferhubd/detached_buffer_channel.cpp b/services/vr/bufferhubd/detached_buffer_channel.cpp
new file mode 100644
index 0000000..edb2111
--- /dev/null
+++ b/services/vr/bufferhubd/detached_buffer_channel.cpp
@@ -0,0 +1,57 @@
+#include "detached_buffer_channel.h"
+
+using android::pdx::ErrorStatus;
+using android::pdx::Message;
+using android::pdx::RemoteChannelHandle;
+using android::pdx::Status;
+using android::pdx::rpc::DispatchRemoteMethod;
+
+namespace android {
+namespace dvr {
+
+DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
+ int buffer_id, int channel_id,
+ IonBuffer buffer,
+ IonBuffer metadata_buffer,
+ size_t user_metadata_size)
+ : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
+ buffer_(std::move(buffer)),
+ metadata_buffer_(std::move(metadata_buffer)),
+ user_metadata_size_(user_metadata_size) {}
+
+BufferHubChannel::BufferInfo DetachedBufferChannel::GetBufferInfo() const {
+ return BufferInfo(buffer_id(), /*consumer_count=*/0, buffer_.width(),
+ buffer_.height(), buffer_.layer_count(), buffer_.format(),
+ buffer_.usage(), /*pending_count=*/0, /*state=*/0,
+ /*signaled_mask=*/0, /*index=*/0);
+}
+
+void DetachedBufferChannel::HandleImpulse(Message& /*message*/) {
+ ATRACE_NAME("DetachedBufferChannel::HandleImpulse");
+}
+
+bool DetachedBufferChannel::HandleMessage(Message& message) {
+ ATRACE_NAME("DetachedBufferChannel::HandleMessage");
+ switch (message.GetOp()) {
+ case BufferHubRPC::DetachedBufferPromote::Opcode:
+ DispatchRemoteMethod<BufferHubRPC::DetachedBufferPromote>(
+ *this, &DetachedBufferChannel::OnPromote, message);
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+Status<RemoteChannelHandle> DetachedBufferChannel::OnPromote(
+ Message& /*message*/) {
+ ATRACE_NAME("DetachedBufferChannel::OnPromote");
+ ALOGD_IF(TRACE, "DetachedBufferChannel::OnPromote: buffer_id=%d",
+ buffer_id());
+
+ // TODO(b/69982239): Implement the logic to promote a detached buffer.
+ return ErrorStatus(ENOSYS);
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/services/vr/bufferhubd/detached_buffer_channel.h b/services/vr/bufferhubd/detached_buffer_channel.h
new file mode 100644
index 0000000..7ce4aed
--- /dev/null
+++ b/services/vr/bufferhubd/detached_buffer_channel.h
@@ -0,0 +1,43 @@
+#ifndef ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
+#define ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
+
+#include "buffer_hub.h"
+
+// #include <pdx/channel_handle.h>
+// #include <pdx/file_handle.h>
+// #include <pdx/rpc/buffer_wrapper.h>
+// #include <private/dvr/ion_buffer.h>
+
+namespace android {
+namespace dvr {
+
+class DetachedBufferChannel : public BufferHubChannel {
+ public:
+ // Creates a detached buffer.
+ DetachedBufferChannel(BufferHubService* service, int buffer_id,
+ int channel_id, IonBuffer buffer,
+ IonBuffer metadata_buffer, size_t user_metadata_size);
+
+ size_t user_metadata_size() const { return user_metadata_size_; }
+
+ // Captures buffer info for use by BufferHubService::DumpState().
+ BufferInfo GetBufferInfo() const override;
+
+ bool HandleMessage(pdx::Message& message) override;
+ void HandleImpulse(pdx::Message& message) override;
+
+ private:
+ pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
+
+ // Gralloc buffer handles.
+ IonBuffer buffer_;
+ IonBuffer metadata_buffer_;
+
+ // Size of user requested metadata.
+ const size_t user_metadata_size_;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 8160193..e141b91 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -13,6 +13,7 @@
#include <private/dvr/bufferhub_rpc.h>
#include "consumer_channel.h"
+#include "detached_buffer_channel.h"
using android::pdx::BorrowedHandle;
using android::pdx::ErrorStatus;
@@ -131,8 +132,11 @@
"ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
"state=%" PRIx64 ".",
channel_id(), buffer_id(), buffer_state_->load());
- for (auto consumer : consumer_channels_)
+ for (auto consumer : consumer_channels_) {
consumer->OnProducerClosed();
+ service()->SetChannel(consumer->channel_id(), nullptr);
+ }
+ Hangup();
}
BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
@@ -183,6 +187,11 @@
*this, &ProducerChannel::OnProducerGain, message);
return true;
+ case BufferHubRPC::ProducerBufferDetach::Opcode:
+ DispatchRemoteMethod<BufferHubRPC::ProducerBufferDetach>(
+ *this, &ProducerChannel::OnProducerDetach, message);
+ return true;
+
default:
return false;
}
@@ -337,6 +346,55 @@
return {std::move(returned_fence_)};
}
+Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
+ Message& message) {
+ ATRACE_NAME("ProducerChannel::OnProducerDetach");
+ ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
+ buffer_id());
+
+ uint64_t buffer_state = buffer_state_->load();
+ if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+ // Can only detach a BufferProducer when it's in gained state.
+ ALOGW(
+ "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=0x%" PRIx64
+ ") is not in gained state.",
+ buffer_id(), buffer_state);
+ return {};
+ }
+
+ int channel_id;
+ auto status = message.PushChannel(0, nullptr, &channel_id);
+ if (!status) {
+ ALOGE(
+ "ProducerChannel::OnProducerDetach: Failed to push detached buffer "
+ "channel: %s",
+ status.GetErrorMessage().c_str());
+ return ErrorStatus(ENOMEM);
+ }
+
+ // Make sure we unlock the buffer.
+ if (int ret = metadata_buffer_.Unlock()) {
+ ALOGE("ProducerChannel::OnProducerDetach: Failed to unlock metadata.");
+ return ErrorStatus(-ret);
+ };
+
+ auto channel = std::make_shared<DetachedBufferChannel>(
+ service(), buffer_id(), channel_id, std::move(buffer_),
+ std::move(metadata_buffer_), user_metadata_size_);
+
+ const auto channel_status = service()->SetChannel(channel_id, 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(
+ "ProducerChannel::OnProducerDetach: Failed to set new detached buffer "
+ "channel: %s.",
+ channel_status.GetErrorMessage().c_str());
+ }
+
+ return status;
+}
+
Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
diff --git a/services/vr/bufferhubd/producer_channel.h b/services/vr/bufferhubd/producer_channel.h
index c5dbf0e..de9ff31 100644
--- a/services/vr/bufferhubd/producer_channel.h
+++ b/services/vr/bufferhubd/producer_channel.h
@@ -99,6 +99,7 @@
pdx::Status<BufferDescription<BorrowedHandle>> OnGetBuffer(Message& message);
pdx::Status<void> OnProducerPost(Message& message, LocalFence acquire_fence);
pdx::Status<LocalFence> OnProducerGain(Message& message);
+ pdx::Status<RemoteChannelHandle> OnProducerDetach(Message& message);
ProducerChannel(const ProducerChannel&) = delete;
void operator=(const ProducerChannel&) = delete;
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 313c022..11ffc3f 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -868,7 +868,7 @@
Error status = Error::NONE;
sp<VrComposerClient> client;
- if (client_ == nullptr) {
+ if (!client_.promote().get()) {
client = new VrComposerClient(*this);
} else {
ALOGE("Already have a client");