Merge "vndservicemanager: load vendor service_contexts." into oc-dev
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..03af56d
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+
+AccessModifierOffset: -4
+AlignOperands: false
+AllowShortFunctionsOnASingleLine: Inline
+AlwaysBreakBeforeMultilineStrings: false
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ConstructorInitializerIndentWidth: 6
+ContinuationIndentWidth: 8
+IndentWidth: 4
+PenaltyBreakBeforeFirstCallParameter: 100000
+SpacesBeforeTrailingComments: 1
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index cba8f36..5421a75 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -820,28 +820,33 @@
if (timeout < 20000) {
timeout = 20000;
}
- RunCommand("SYSTEM LOG", {"logcat", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
+ RunCommand("SYSTEM LOG",
+ {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid",
+ "-d", "*:v"},
CommandOptions::WithTimeout(timeout / 1000).Build());
timeout = logcat_timeout("events");
if (timeout < 20000) {
timeout = 20000;
}
RunCommand("EVENT LOG",
- {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
+ {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid",
+ "-d", "*:v"},
CommandOptions::WithTimeout(timeout / 1000).Build());
timeout = logcat_timeout("radio");
if (timeout < 20000) {
timeout = 20000;
}
RunCommand("RADIO LOG",
- {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
+ {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid",
+ "-d", "*:v"},
CommandOptions::WithTimeout(timeout / 1000).Build());
RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
/* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
RunCommand("LAST LOGCAT",
- {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-d", "*:v"});
+ {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-v", "uid",
+ "-d", "*:v"});
}
static void DumpIpTables() {
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 381e90c..c604ca0 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -289,6 +289,46 @@
return 0;
}
+/**
+ * Ensure that we have a hard-limit quota to protect against abusive apps;
+ * they should never use more than 90% of blocks or 50% of inodes.
+ */
+static int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std::string& device,
+ uid_t uid) {
+ if (device.empty()) return 0;
+
+ struct dqblk dq;
+ if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ PLOG(WARNING) << "Failed to find quota for " << uid;
+ return -1;
+ }
+
+ if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) {
+ auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
+ struct statvfs stat;
+ if (statvfs(path.c_str(), &stat) != 0) {
+ PLOG(WARNING) << "Failed to statvfs " << path;
+ return -1;
+ }
+
+ dq.dqb_valid = QIF_LIMITS;
+ dq.dqb_bhardlimit = (((stat.f_blocks * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE;
+ dq.dqb_ihardlimit = (stat.f_files / 2);
+ if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ PLOG(WARNING) << "Failed to set hard quota for " << uid;
+ return -1;
+ } else {
+ LOG(DEBUG) << "Applied hard quotas for " << uid;
+ return 0;
+ }
+ } else {
+ // Hard quota already set; assume it's reasonable
+ return 0;
+ }
+}
+
binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
@@ -358,6 +398,10 @@
return error("Failed to restorecon " + path);
}
+ if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) {
+ return error("Failed to set hard quota " + path);
+ }
+
if (property_get_bool("dalvik.vm.usejitprofiles", false)) {
const std::string profile_dir =
create_primary_current_profile_package_dir_path(userId, pkgname);
@@ -709,6 +753,14 @@
}
}
}
+
+ // Data under /data/media doesn't have an app, but we still want
+ // to limit it to prevent abuse.
+ if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid),
+ multiuser_get_uid(userId, AID_MEDIA_RW))) {
+ return error("Failed to set hard quota for media_rw");
+ }
+
return ok();
}
@@ -2006,6 +2058,17 @@
reinterpret_cast<char*>(&dq)) == 0) {
LOG(DEBUG) << "Found " << source << " with quota";
mQuotaDevices[target] = source;
+
+ // ext4 only enables DQUOT_USAGE_ENABLED by default, so we
+ // need to kick it again to enable DQUOT_LIMITS_ENABLED.
+ if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
+ && errno != EBUSY) {
+ PLOG(ERROR) << "Failed to enable USRQUOTA on " << source;
+ }
+ if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
+ && errno != EBUSY) {
+ PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source;
+ }
}
}
}
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 360f71a..174ce77 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -99,7 +99,7 @@
static int64_t free() {
struct statvfs buf;
if (!statvfs("/data/local/tmp", &buf)) {
- return buf.f_bavail * buf.f_bsize;
+ return buf.f_bavail * buf.f_frsize;
} else {
PLOG(ERROR) << "Failed to statvfs";
return -1;
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index fbe6edf..24c0b45 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -629,11 +629,10 @@
return res;
}
-int64_t data_disk_free(const std::string& data_path)
-{
+int64_t data_disk_free(const std::string& data_path) {
struct statvfs sfs;
if (statvfs(data_path.c_str(), &sfs) == 0) {
- return sfs.f_bavail * sfs.f_bsize;
+ return sfs.f_bavail * sfs.f_frsize;
} else {
PLOG(ERROR) << "Couldn't statvfs " << data_path;
return -1;
@@ -1030,6 +1029,10 @@
} else if (st.st_gid == gid && actual_mode == target_mode) {
// Everything looks good!
return 0;
+ } else {
+ // Mismatched GID/mode is recoverable; fall through to update
+ LOG(DEBUG) << "Mismatched cache GID/mode at " << path << ": found " << st.st_gid
+ << " but expected " << gid;
}
// Directory is owned correctly, but GID or mode mismatch means it's
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index aee7bd8..aec211a 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -1,5 +1,5 @@
service servicemanager /system/bin/servicemanager
- class core
+ class core animation
user system
group system readproc
critical
@@ -12,4 +12,3 @@
onrestart restart drm
onrestart restart cameraserver
writepid /dev/cpuset/system-background/tasks
-
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 62f6cad..88ef010 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -257,10 +257,25 @@
virtual int query(int what, int* value) const;
virtual int connect(int api, const sp<IProducerListener>& listener);
+
+ // When reportBufferRemoval is true, clients must call getAndFlushRemovedBuffers to fetch
+ // GraphicBuffers removed from this surface after a dequeueBuffer, detachNextBuffer or
+ // attachBuffer call. This allows clients with their own buffer caches to free up buffers no
+ // longer in use by this surface.
+ virtual int connect(
+ int api, const sp<IProducerListener>& listener,
+ bool reportBufferRemoval);
virtual int detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence);
virtual int attachBuffer(ANativeWindowBuffer*);
+ // When client connects to Surface with reportBufferRemoval set to true, any buffers removed
+ // from this Surface will be collected and returned here. Once this method returns, these
+ // buffers will no longer be referenced by this Surface unless they are attached to this
+ // Surface later. The list of removed buffers will only be stored until the next dequeueBuffer,
+ // detachNextBuffer, or attachBuffer call.
+ status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out);
+
protected:
enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
@@ -414,6 +429,9 @@
// A cached copy of the FrameEventHistory maintained by the consumer.
bool mEnableFrameTimestamps = false;
std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory;
+
+ bool mReportRemovedBuffers = false;
+ std::vector<sp<GraphicBuffer>> mRemovedBuffers;
};
} // namespace android
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 8acdfed..d4e4dc3 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -287,6 +287,9 @@
}
if (item->mGraphicBuffer != NULL) {
+ if (mSlots[item->mSlot].mGraphicBuffer != NULL) {
+ freeBufferLocked(item->mSlot);
+ }
mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 06fc31d..1149b89 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -505,7 +505,11 @@
mFrameEventHistory->applyDelta(frameTimestamps);
}
- if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
+ if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {
+ if (mReportRemovedBuffers && (gbuf != nullptr)) {
+ mRemovedBuffers.clear();
+ mRemovedBuffers.push_back(gbuf);
+ }
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
if (result != NO_ERROR) {
ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
@@ -1075,10 +1079,16 @@
}
int Surface::connect(int api, const sp<IProducerListener>& listener) {
+ return connect(api, listener, false);
+}
+
+int Surface::connect(
+ int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) {
ATRACE_CALL();
ALOGV("Surface::connect");
Mutex::Autolock lock(mMutex);
IGraphicBufferProducer::QueueBufferOutput output;
+ mReportRemovedBuffers = reportBufferRemoval;
int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);
if (err == NO_ERROR) {
mDefaultWidth = output.width;
@@ -1109,6 +1119,7 @@
ATRACE_CALL();
ALOGV("Surface::disconnect");
Mutex::Autolock lock(mMutex);
+ mRemovedBuffers.clear();
mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
mSharedBufferHasBeenQueued = false;
freeAllBuffers();
@@ -1156,9 +1167,16 @@
*outFence = Fence::NO_FENCE;
}
+ if (mReportRemovedBuffers) {
+ mRemovedBuffers.clear();
+ }
+
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
if (mSlots[i].buffer != NULL &&
mSlots[i].buffer->handle == buffer->handle) {
+ if (mReportRemovedBuffers) {
+ mRemovedBuffers.push_back(mSlots[i].buffer);
+ }
mSlots[i].buffer = NULL;
}
}
@@ -1184,6 +1202,10 @@
graphicBuffer->mGenerationNumber = priorGeneration;
return result;
}
+ if (mReportRemovedBuffers && (mSlots[attachedSlot].buffer != nullptr)) {
+ mRemovedBuffers.clear();
+ mRemovedBuffers.push_back(mSlots[attachedSlot].buffer);
+ }
mSlots[attachedSlot].buffer = graphicBuffer;
return NO_ERROR;
@@ -1617,4 +1639,16 @@
return mGraphicBufferProducer->getUniqueId(outId);
}
+status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) {
+ if (out == nullptr) {
+ ALOGE("%s: out must not be null!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mMutex);
+ *out = mRemovedBuffers;
+ mRemovedBuffers.clear();
+ return OK;
+}
+
}; // namespace android
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
index 03297ca..e35bfc9 100644
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -538,6 +538,12 @@
for (auto& change : mChanges->getTypeChanges()) {
auto layerId = change.first;
auto type = change.second;
+ if (mDevice.mLayers.count(layerId) == 0) {
+ // This should never happen but somehow does.
+ ALOGW("Cannot accept change for unknown layer (%" PRIu64 ")",
+ layerId);
+ continue;
+ }
auto layer = mDevice.mLayers[layerId];
layer->setCompositionType(type);
}
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 1ed150b..a38b4dc 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -28,6 +28,7 @@
#include <ui/GraphicBuffer.h>
#include <system/graphics.h>
#include <hardware/gralloc1.h>
+#include <grallocusage/GrallocUsageConversion.h>
#include <private/android/AHardwareBufferHelpers.h>
@@ -100,8 +101,12 @@
outDesc->width = gbuffer->getWidth();
outDesc->height = gbuffer->getHeight();
outDesc->layers = gbuffer->getLayerCount();
+
+ uint64_t producerUsage = 0;
+ uint64_t consumerUsage = 0;
+ android_convertGralloc0To1Usage(gbuffer->getUsage(), &producerUsage, &consumerUsage);
AHardwareBuffer_convertFromGrallocUsageBits(&outDesc->usage0, &outDesc->usage1,
- gbuffer->getUsage(), gbuffer->getUsage());
+ producerUsage, consumerUsage);
outDesc->format = AHardwareBuffer_convertFromPixelFormat(
static_cast<uint32_t>(gbuffer->getPixelFormat()));
}
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index c0c4ac0..6c67cf8 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -25,6 +25,8 @@
#include <private/android/AHardwareBufferHelpers.h>
+#include <ui/GraphicBuffer.h>
+
using namespace android;
static int32_t query(ANativeWindow* window, int what) {
@@ -105,6 +107,10 @@
* vndk-stable
**************************************************************************************************/
+AHardwareBuffer* ANativeWindowBuffer_getHardwareBuffer(ANativeWindowBuffer* anwb) {
+ return AHardwareBuffer_from_GraphicBuffer(static_cast<GraphicBuffer*>(anwb));
+}
+
int ANativeWindow_OemStorageSet(ANativeWindow* window, uint32_t slot, intptr_t value) {
if (slot < 4) {
window->oem[slot] = value;
diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h
index 310e1e5..067046b 100644
--- a/libs/nativewindow/include/vndk/window.h
+++ b/libs/nativewindow/include/vndk/window.h
@@ -99,8 +99,12 @@
typedef struct ANativeWindowBuffer ANativeWindowBuffer;
-/*****************************************************************************/
+/*
+ * Convert this ANativeWindowBuffer into a AHardwareBuffer
+ */
+AHardwareBuffer* ANativeWindowBuffer_getHardwareBuffer(ANativeWindowBuffer* anwb);
+/*****************************************************************************/
/*
* Stores a value into one of the 4 available slots
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 2d96638..0fa1f01 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -42,7 +42,7 @@
cc_library {
name: "libbufferhubqueue",
- cflags = [
+ cflags: [
"-DLOG_TAG=\"libbufferhubqueue\"",
"-DTRACE=0",
],
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index bd6511d..031401a 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -146,7 +146,7 @@
ALOGW(
"Receives EPOLLHUP at slot: %zu, buffer event fd: %d, EPOLLHUP "
"pending: %d",
- slot, buffer->event_fd(), epollhup_pending_[slot]);
+ slot, buffer->event_fd(), int{epollhup_pending_[slot]});
if (epollhup_pending_[slot]) {
epollhup_pending_[slot] = false;
} else {
diff --git a/libs/vr/libpdx_uds/client_channel_factory.cpp b/libs/vr/libpdx_uds/client_channel_factory.cpp
index 1879127..f059453 100644
--- a/libs/vr/libpdx_uds/client_channel_factory.cpp
+++ b/libs/vr/libpdx_uds/client_channel_factory.cpp
@@ -6,10 +6,16 @@
#include <sys/un.h>
#include <unistd.h>
+#include <chrono>
+#include <thread>
+
#include <uds/channel_manager.h>
#include <uds/client_channel.h>
#include <uds/ipc_helper.h>
+using std::chrono::duration_cast;
+using std::chrono::steady_clock;
+
namespace android {
namespace pdx {
namespace uds {
@@ -41,13 +47,11 @@
Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(
int64_t timeout_ms) const {
- auto status = WaitForEndpoint(endpoint_path_, timeout_ms);
- if (!status)
- return ErrorStatus(status.error());
+ Status<void> status;
LocalHandle socket_fd{socket(AF_UNIX, SOCK_STREAM, 0)};
if (!socket_fd) {
- ALOGE("ClientChannelFactory::Connect: socket error %s", strerror(errno));
+ ALOGE("ClientChannelFactory::Connect: socket error: %s", strerror(errno));
return ErrorStatus(errno);
}
@@ -56,16 +60,55 @@
strncpy(remote.sun_path, endpoint_path_.c_str(), sizeof(remote.sun_path));
remote.sun_path[sizeof(remote.sun_path) - 1] = '\0';
- int ret = RETRY_EINTR(connect(
- socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
- if (ret == -1) {
- ALOGE(
- "ClientChannelFactory::Connect: Failed to initialize connection when "
- "connecting %s",
- strerror(errno));
- return ErrorStatus(errno);
- }
+ bool use_timeout = (timeout_ms >= 0);
+ auto now = steady_clock::now();
+ auto time_end = now + std::chrono::milliseconds{timeout_ms};
+ bool connected = false;
+ while (!connected) {
+ int64_t timeout = -1;
+ if (use_timeout) {
+ auto remaining = time_end - now;
+ timeout = duration_cast<std::chrono::milliseconds>(remaining).count();
+ if (timeout < 0)
+ return ErrorStatus(ETIMEDOUT);
+ }
+ ALOGD("ClientChannelFactory: Waiting for endpoint at %s", remote.sun_path);
+ status = WaitForEndpoint(endpoint_path_, timeout);
+ if (!status)
+ return ErrorStatus(status.error());
+
+ ALOGD("ClientChannelFactory: Connecting to %s", remote.sun_path);
+ int ret = RETRY_EINTR(connect(
+ socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
+ if (ret == -1) {
+ ALOGD("ClientChannelFactory: Connect error %d: %s", errno,
+ strerror(errno));
+ if (errno == ECONNREFUSED) {
+ // Connection refused can be the result of connecting too early (the
+ // service socket is created but not being listened to yet).
+ ALOGD("ClientChannelFactory: Connection refused, waiting...");
+ using namespace std::literals::chrono_literals;
+ std::this_thread::sleep_for(100ms);
+ } else if (errno != ENOENT && errno != ENOTDIR) {
+ // ENOENT/ENOTDIR might mean that the socket file/directory containing
+ // it has been just deleted. Try to wait for its creation and do not
+ // return an error immediately.
+ ALOGE(
+ "ClientChannelFactory::Connect: Failed to initialize connection "
+ "when connecting: %s",
+ strerror(errno));
+ return ErrorStatus(errno);
+ }
+ } else {
+ connected = true;
+ }
+ if (use_timeout)
+ now = steady_clock::now();
+ } // while (!connected)
+
+ ALOGD("ClientChannelFactory: Connected successfully to %s...",
+ remote.sun_path);
RequestHeader<BorrowedHandle> request;
InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false);
status = SendData(socket_fd.Get(), request);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f82b363..834c1c4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1903,7 +1903,8 @@
// etc.) but no internal state (i.e. a DisplayDevice).
if (state.surface != NULL) {
- if (mUseHwcVirtualDisplays) {
+ // Allow VR composer to use virtual displays.
+ if (mUseHwcVirtualDisplays || mHwc == mVrHwc) {
int width = 0;
int status = state.surface->query(
NATIVE_WINDOW_WIDTH, &width);
@@ -2839,15 +2840,17 @@
sp<Layer> layer;
+ String8 uniqueName = getUniqueLayerName(name);
+
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceNormal:
result = createNormalLayer(client,
- name, w, h, flags, format,
+ uniqueName, w, h, flags, format,
handle, gbp, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceDim:
result = createDimLayer(client,
- name, w, h, flags,
+ uniqueName, w, h, flags,
handle, gbp, &layer);
break;
default:
@@ -2871,6 +2874,30 @@
return result;
}
+String8 SurfaceFlinger::getUniqueLayerName(const String8& name)
+{
+ bool matchFound = true;
+ uint32_t dupeCounter = 0;
+
+ // Tack on our counter whether there is a hit or not, so everyone gets a tag
+ String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str());
+
+ // Loop over layers until we're sure there is no matching name
+ while (matchFound) {
+ matchFound = false;
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
+ if (layer->getName() == uniqueName) {
+ matchFound = true;
+ uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str());
+ }
+ });
+ }
+
+ ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str());
+
+ return uniqueName;
+}
+
status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 581bbfd..4ecbddd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -364,6 +364,8 @@
uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
+ String8 getUniqueLayerName(const String8& name);
+
// called in response to the window-manager calling
// ISurfaceComposerClient::destroySurface()
status_t onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle);
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index c26847f..a6c0b9c 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2637,15 +2637,17 @@
sp<Layer> layer;
+ String8 uniqueName = getUniqueLayerName(name);
+
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceNormal:
result = createNormalLayer(client,
- name, w, h, flags, format,
+ uniqueName, w, h, flags, format,
handle, gbp, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceDim:
result = createDimLayer(client,
- name, w, h, flags,
+ uniqueName, w, h, flags,
handle, gbp, &layer);
break;
default:
@@ -2669,6 +2671,30 @@
return result;
}
+String8 SurfaceFlinger::getUniqueLayerName(const String8& name)
+{
+ bool matchFound = true;
+ uint32_t dupeCounter = 0;
+
+ // Tack on our counter whether there is a hit or not, so everyone gets a tag
+ String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str());
+
+ // Loop over layers until we're sure there is no matching name
+ while (matchFound) {
+ matchFound = false;
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
+ if (layer->getName() == uniqueName) {
+ matchFound = true;
+ uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str());
+ }
+ });
+ }
+
+ ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str());
+
+ return uniqueName;
+}
+
status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index 435aa0c..0b482f7 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -1,5 +1,5 @@
service surfaceflinger /system/bin/surfaceflinger
- class core
+ class core animation
user system
group graphics drmrpc readproc
onrestart restart zygote
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
index c1a0b6f..b3d777e 100644
--- a/services/vr/bufferhubd/Android.mk
+++ b/services/vr/bufferhubd/Android.mk
@@ -30,7 +30,6 @@
sharedLibraries := \
libbase \
libcutils \
- libhardware \
liblog \
libsync \
libutils \
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 98a419f..43010b0 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -238,7 +238,7 @@
ClearAvailable();
producer_owns_ = true;
- post_fence_.get_fd();
+ post_fence_.close();
return std::move(returned_fence_);
}
diff --git a/services/vr/hardware_composer/vr_hwc.rc b/services/vr/hardware_composer/vr_hwc.rc
index 5d3c4f7..52d4da8 100644
--- a/services/vr/hardware_composer/vr_hwc.rc
+++ b/services/vr/hardware_composer/vr_hwc.rc
@@ -3,4 +3,3 @@
user system
group system graphics
onrestart restart surfaceflinger
- disabled
diff --git a/services/vr/vr_window_manager/Android.bp b/services/vr/vr_window_manager/Android.bp
index a7a341c..0406331 100644
--- a/services/vr/vr_window_manager/Android.bp
+++ b/services/vr/vr_window_manager/Android.bp
@@ -41,6 +41,7 @@
"libperformance",
"libpdx_default_transport",
"libcutils",
+ "libvr_hwc-binder",
"libvr_manager",
"libvirtualtouchpadclient",
]
diff --git a/services/vr/vr_window_manager/hwc_callback.cpp b/services/vr/vr_window_manager/hwc_callback.cpp
index 19b220b..43f5042 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -38,26 +38,29 @@
HwcCallback::~HwcCallback() {
}
-base::unique_fd HwcCallback::OnNewFrame(const ComposerView::Frame& display_frame) {
- auto& frame = display_frame.layers;
- std::vector<HwcLayer> hwc_frame(frame.size());
-
- for (size_t i = 0; i < frame.size(); ++i) {
+binder::Status HwcCallback::onNewFrame(
+ const ParcelableComposerFrame& parcelable_frame,
+ ParcelableUniqueFd* fence) {
+ ComposerView::Frame frame = parcelable_frame.frame();
+ std::vector<HwcLayer> hwc_frame(frame.layers.size());
+ for (size_t i = 0; i < frame.layers.size(); ++i) {
+ const ComposerView::ComposerLayer& layer = frame.layers[i];
hwc_frame[i] = HwcLayer{
- .fence = frame[i].fence,
- .buffer = frame[i].buffer,
- .crop = frame[i].crop,
- .display_frame = frame[i].display_frame,
- .blending = static_cast<int32_t>(frame[i].blend_mode),
- .appid = frame[i].app_id,
- .type = static_cast<HwcLayer::LayerType>(frame[i].type),
- .alpha = frame[i].alpha,
+ .fence = layer.fence,
+ .buffer = layer.buffer,
+ .crop = layer.crop,
+ .display_frame = layer.display_frame,
+ .blending = static_cast<int32_t>(layer.blend_mode),
+ .appid = layer.app_id,
+ .type = static_cast<HwcLayer::LayerType>(layer.type),
+ .alpha = layer.alpha,
};
}
- return client_->OnFrame(std::make_unique<Frame>(
- std::move(hwc_frame), display_frame.display_id, display_frame.removed,
- display_frame.display_width, display_frame.display_height));
+ fence->set_fence(client_->OnFrame(std::make_unique<Frame>(
+ std::move(hwc_frame), frame.display_id, frame.removed,
+ frame.display_width, frame.display_height)));
+ return binder::Status::ok();
}
HwcCallback::Frame::Frame(std::vector<HwcLayer>&& layers, uint32_t display_id,
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index c0d965a..f1f91a1 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -1,14 +1,16 @@
#ifndef VR_WINDOW_MANAGER_HWC_CALLBACK_H_
#define VR_WINDOW_MANAGER_HWC_CALLBACK_H_
+#include <android/dvr/BnVrComposerCallback.h>
+#include <android-base/unique_fd.h>
+
#include <deque>
#include <functional>
#include <mutex>
#include <vector>
-#include <android-base/unique_fd.h>
-#include <impl/vr_composer_view.h>
-#include <impl/vr_hwc.h>
+#include "impl/vr_composer_view.h"
+#include "impl/vr_hwc.h"
namespace android {
@@ -20,7 +22,7 @@
using Recti = ComposerView::ComposerLayer::Recti;
using Rectf = ComposerView::ComposerLayer::Rectf;
-class HwcCallback : public VrComposerView::Callback {
+class HwcCallback : public BnVrComposerCallback {
public:
struct HwcLayer {
enum LayerType : uint32_t {
@@ -110,7 +112,8 @@
~HwcCallback() override;
private:
- base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
+ binder::Status onNewFrame(const ParcelableComposerFrame& frame,
+ ParcelableUniqueFd* fence) override;
Client *client_;
diff --git a/services/vr/vr_window_manager/surface_flinger_view.cpp b/services/vr/vr_window_manager/surface_flinger_view.cpp
index c0ee1fc..aef23a1 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -1,5 +1,7 @@
#include "surface_flinger_view.h"
+#include <android/dvr/IVrComposer.h>
+#include <binder/IServiceManager.h>
#include <impl/vr_composer_view.h>
#include <private/dvr/native_buffer.h>
@@ -14,22 +16,20 @@
SurfaceFlingerView::~SurfaceFlingerView() {}
bool SurfaceFlingerView::Initialize(HwcCallback::Client *client) {
- const char vr_hwcomposer_name[] = "vr";
- vr_hwcomposer_ = HIDL_FETCH_IComposer(vr_hwcomposer_name);
- if (!vr_hwcomposer_.get()) {
- ALOGE("Failed to get vr_hwcomposer");
+ sp<IServiceManager> sm(defaultServiceManager());
+ vr_composer_ = interface_cast<IVrComposer>(
+ sm->getService(IVrComposer::SERVICE_NAME()));
+
+ String8 service_name(IVrComposer::SERVICE_NAME().string());
+ if (!vr_composer_.get()) {
+ ALOGE("Faild to connect to %s", service_name.c_str());
return false;
}
- if (vr_hwcomposer_->isRemote()) {
- ALOGE("vr_hwcomposer service is remote");
- return false;
- }
-
- const android::status_t vr_hwcomposer_status =
- vr_hwcomposer_->registerAsService(vr_hwcomposer_name);
- if (vr_hwcomposer_status != OK) {
- ALOGE("Failed to register vr_hwcomposer service");
+ composer_callback_ = new HwcCallback(client);
+ binder::Status status = vr_composer_->registerObserver(composer_callback_);
+ if (!status.isOk()) {
+ ALOGE("Failed to register observer with %s", service_name.c_str());
return false;
}
diff --git a/services/vr/vr_window_manager/surface_flinger_view.h b/services/vr/vr_window_manager/surface_flinger_view.h
index 3ea2b21..1bea38d 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.h
+++ b/services/vr/vr_window_manager/surface_flinger_view.h
@@ -3,14 +3,13 @@
#include <memory>
-#include <impl/vr_composer_view.h>
-
#include "hwc_callback.h"
namespace android {
namespace dvr {
class IDisplay;
+class IVrComposer;
class Texture;
struct TextureLayer {
@@ -34,8 +33,8 @@
bool skip_first_layer) const;
private:
- sp<IComposer> vr_hwcomposer_;
- std::unique_ptr<VrComposerView> vr_composer_view_;
+ sp<IVrComposer> vr_composer_;
+ sp<HwcCallback> composer_callback_;
SurfaceFlingerView(const SurfaceFlingerView&) = delete;
void operator=(const SurfaceFlingerView&) = delete;
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 5574da2..2fee8a5 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -183,7 +183,9 @@
: surface(surface_),
num_images(num_images_),
mailbox_mode(present_mode == VK_PRESENT_MODE_MAILBOX_KHR),
- frame_timestamps_enabled(false) {
+ frame_timestamps_enabled(false),
+ shared(present_mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
+ present_mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
ANativeWindow* window = surface.window.get();
int64_t rdur;
native_window_get_refresh_cycle_duration(
@@ -197,6 +199,7 @@
bool mailbox_mode;
bool frame_timestamps_enabled;
uint64_t refresh_duration;
+ bool shared;
struct Image {
Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
@@ -927,6 +930,25 @@
return VK_ERROR_SURFACE_LOST_KHR;
}
+ VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0;
+ if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
+ create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
+ swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID;
+ err = native_window_set_shared_buffer_mode(surface.window.get(), true);
+ if (err != 0) {
+ ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ }
+
+ if (create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
+ err = native_window_set_auto_refresh(surface.window.get(), true);
+ if (err != 0) {
+ ALOGE("native_window_set_auto_refresh failed: %s (%d)", strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ }
+
int query_value;
err = surface.window->query(surface.window.get(),
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
@@ -941,7 +963,13 @@
uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
uint32_t num_images =
(create_info->minImageCount - 1) + min_undequeued_buffers;
- err = native_window_set_buffer_count(surface.window.get(), num_images);
+
+ // Lower layer insists that we have at least two buffers. This is wasteful
+ // and we'd like to relax it in the shared case, but not all the pieces are
+ // in place for that to work yet. Note we only lie to the lower layer-- we
+ // don't want to give the app back a swapchain with extra images (which they
+ // can't actually use!).
+ err = native_window_set_buffer_count(surface.window.get(), std::max(2u, num_images));
if (err != 0) {
// TODO(jessehall): Improve error reporting. Can we enumerate possible
// errors and translate them to valid Vulkan result codes?
@@ -950,26 +978,6 @@
return VK_ERROR_SURFACE_LOST_KHR;
}
- VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0;
- if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
- create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
- swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID;
-
- err = native_window_set_shared_buffer_mode(surface.window.get(), true);
- if (err != 0) {
- ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- }
-
- if (create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
- err = native_window_set_auto_refresh(surface.window.get(), true);
- if (err != 0) {
- ALOGE("native_window_set_auto_refresh failed: %s (%d)", strerror(-err), err);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- }
-
int gralloc_usage = 0;
if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
uint64_t consumer_usage, producer_usage;
@@ -1106,17 +1114,19 @@
//
// TODO(jessehall): The error path here is the same as DestroySwapchain,
// but not the non-error path. Should refactor/unify.
- for (uint32_t i = 0; i < num_images; i++) {
- Swapchain::Image& img = swapchain->images[i];
- if (img.dequeued) {
- surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
- img.dequeue_fence);
- img.dequeue_fence = -1;
- img.dequeued = false;
- }
- if (result != VK_SUCCESS) {
- if (img.image)
- dispatch.DestroyImage(device, img.image, nullptr);
+ if (!swapchain->shared) {
+ for (uint32_t i = 0; i < num_images; i++) {
+ Swapchain::Image& img = swapchain->images[i];
+ if (img.dequeued) {
+ surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
+ img.dequeue_fence);
+ img.dequeue_fence = -1;
+ img.dequeued = false;
+ }
+ if (result != VK_SUCCESS) {
+ if (img.image)
+ dispatch.DestroyImage(device, img.image, nullptr);
+ }
}
}
@@ -1200,6 +1210,16 @@
timeout != UINT64_MAX,
"vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
+ if (swapchain.shared) {
+ // In shared mode, we keep the buffer dequeued all the time, so we don't
+ // want to dequeue a buffer here. Instead, just ask the driver to ensure
+ // the semaphore and fence passed to us will be signalled.
+ *image_index = 0;
+ result = GetData(device).driver.AcquireImageANDROID(
+ device, swapchain.images[*image_index].image, -1, semaphore, vk_fence);
+ return result;
+ }
+
ANativeWindowBuffer* buffer;
int fence_fd;
err = window->dequeueBuffer(window, &buffer, &fence_fd);
@@ -1420,6 +1440,7 @@
static_cast<int64_t>(time->desiredPresentTime));
}
}
+
err = window->queueBuffer(window, img.buffer.get(), fence);
// queueBuffer always closes fence, even on error
if (err != 0) {
@@ -1434,6 +1455,30 @@
img.dequeue_fence = -1;
}
img.dequeued = false;
+
+ // If the swapchain is in shared mode, immediately dequeue the
+ // buffer so it can be presented again without an intervening
+ // call to AcquireNextImageKHR. We expect to get the same buffer
+ // back from every call to dequeueBuffer in this mode.
+ if (swapchain.shared && swapchain_result == VK_SUCCESS) {
+ ANativeWindowBuffer* buffer;
+ int fence_fd;
+ err = window->dequeueBuffer(window, &buffer, &fence_fd);
+ if (err != 0) {
+ ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
+ swapchain_result = WorstPresentResult(swapchain_result,
+ VK_ERROR_SURFACE_LOST_KHR);
+ }
+ else if (img.buffer != buffer) {
+ ALOGE("got wrong image back for shared swapchain");
+ swapchain_result = WorstPresentResult(swapchain_result,
+ VK_ERROR_SURFACE_LOST_KHR);
+ }
+ else {
+ img.dequeue_fence = fence_fd;
+ img.dequeued = true;
+ }
+ }
}
if (swapchain_result != VK_SUCCESS) {
ReleaseSwapchainImage(device, window, fence, img);