Merge "thermalservice: plumb up Thermal HAL 2.0 and add dump"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index cd0fbd4..16abc1e 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -4,6 +4,7 @@
[Builtin Hooks Options]
# Only turn on clang-format check for the following subfolders.
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+ libs/graphicsenv/
libs/gui/
libs/ui/
libs/vr/
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index e4990b0..86ec8f8 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -77,7 +77,6 @@
static constexpr const char* kCpPath = "/system/bin/cp";
static constexpr const char* kXattrDefault = "user.default";
-static constexpr const char* kPropHasReserved = "vold.has_reserved";
static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
@@ -343,55 +342,6 @@
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 ATTRIBUTE_UNUSED,
- const std::string& device, uid_t uid) {
- // Skip when reserved blocks are protecting us against abusive apps
- if (android::base::GetBoolProperty(kPropHasReserved, false)) return 0;
- // Skip when device no quotas present
- 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 APPLY_HARD_QUOTAS
- 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 =
- (((static_cast<uint64_t>(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;
- }
-#else
- // Hard quotas disabled
- return 0;
-#endif
-}
-
static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
return true;
@@ -506,10 +456,6 @@
return error("Failed to restorecon " + path);
}
- if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) {
- return error("Failed to set hard quota " + path);
- }
-
if (!prepare_app_profile_dir(packageName, appId, userId)) {
return error("Failed to prepare profiles for " + packageName);
}
@@ -988,13 +934,6 @@
}
}
- // 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();
}
@@ -2644,21 +2583,6 @@
reinterpret_cast<char*>(&dq)) == 0) {
LOG(DEBUG) << "Found quota mount " << source << " at " << target;
mQuotaReverseMounts[target] = source;
-
- // ext4 only enables DQUOT_USAGE_ENABLED by default, so we
- // need to kick it again to enable DQUOT_LIMITS_ENABLED. We
- // only need hard limits enabled when we're not being protected
- // by reserved blocks.
- if (!android::base::GetBoolProperty(kPropHasReserved, false)) {
- 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;
- }
- }
}
}
#endif
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 28c7658..b2e7047 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -322,21 +322,8 @@
return false;
}
const char* isa = parameters_.instruction_set;
-
- // Check whether the file exists where expected.
std::string dalvik_cache = GetOTADataDirectory() + "/" + DALVIK_CACHE;
std::string isa_path = dalvik_cache + "/" + isa;
- std::string art_path = isa_path + "/system@framework@boot.art";
- std::string oat_path = isa_path + "/system@framework@boot.oat";
- bool cleared = false;
- if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) {
- // Files exist, assume everything is alright if not forced. Otherwise clean up.
- if (!force) {
- return true;
- }
- ClearDirectory(isa_path);
- cleared = true;
- }
// Reset umask in otapreopt, so that we control the the access for the files we create.
umask(0);
@@ -355,17 +342,34 @@
}
}
- // Prepare to create.
+ // Check whether we have files in /data.
+ // TODO: check that the files are correct wrt/ jars.
+ std::string art_path = isa_path + "/system@framework@boot.art";
+ std::string oat_path = isa_path + "/system@framework@boot.oat";
+ bool cleared = false;
+ if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) {
+ // Files exist, assume everything is alright if not forced. Otherwise clean up.
+ if (!force) {
+ return true;
+ }
+ ClearDirectory(isa_path);
+ cleared = true;
+ }
+
+ // Check whether we have an image in /system.
+ // TODO: check that the files are correct wrt/ jars.
+ std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
+ if (access(preopted_boot_art_path.c_str(), F_OK) == 0) {
+ // Note: we ignore |force| here.
+ return true;
+ }
+
+
if (!cleared) {
ClearDirectory(isa_path);
}
- std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
- if (access(preopted_boot_art_path.c_str(), F_OK) != 0) {
- // No preopted boot image. Try to compile.
- return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
- }
- return true;
+ return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
}
static bool CreatePath(const std::string& path) {
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 5829c4f..d05724a 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -36,8 +36,6 @@
#define BYPASS_QUOTA 0
#define BYPASS_SDCARDFS 0
-#define APPLY_HARD_QUOTAS 0
-
namespace android {
namespace installd {
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index d776682..79cd6b5 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -274,6 +274,7 @@
// Note that we ignore the strict_policy and don't propagate it
// further (since we do no outbound RPCs anyway).
strict_policy = bio_get_uint32(msg);
+ bio_get_uint32(msg); // Ignore worksource header.
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index 507ce53..0b89879 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -86,7 +86,7 @@
virtual void* getBase() const;
virtual size_t getSize() const;
virtual uint32_t getFlags() const;
- virtual uint32_t getOffset() const;
+ off_t getOffset() const override;
private:
friend class IMemory;
@@ -113,7 +113,7 @@
mutable void* mBase;
mutable size_t mSize;
mutable uint32_t mFlags;
- mutable uint32_t mOffset;
+ mutable off_t mOffset;
mutable bool mRealHeap;
mutable Mutex mLock;
};
@@ -187,13 +187,16 @@
data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
sp<IBinder> heap = reply.readStrongBinder();
- ssize_t o = reply.readInt32();
- size_t s = reply.readInt32();
if (heap != nullptr) {
mHeap = interface_cast<IMemoryHeap>(heap);
if (mHeap != nullptr) {
+ const int64_t offset64 = reply.readInt64();
+ const uint64_t size64 = reply.readUint64();
+ const ssize_t o = (ssize_t)offset64;
+ const size_t s = (size_t)size64;
size_t heapSize = mHeap->getSize();
- if (s <= heapSize
+ if (s == size64 && o == offset64 // ILP32 bounds check
+ && s <= heapSize
&& o >= 0
&& (static_cast<size_t>(o) <= heapSize - s)) {
mOffset = o;
@@ -233,8 +236,8 @@
ssize_t offset;
size_t size;
reply->writeStrongBinder( IInterface::asBinder(getMemory(&offset, &size)) );
- reply->writeInt32(offset);
- reply->writeInt32(size);
+ reply->writeInt64(offset);
+ reply->writeUint64(size);
return NO_ERROR;
} break;
default:
@@ -313,18 +316,23 @@
data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
status_t err = remote()->transact(HEAP_ID, data, &reply);
int parcel_fd = reply.readFileDescriptor();
- ssize_t size = reply.readInt32();
- uint32_t flags = reply.readInt32();
- uint32_t offset = reply.readInt32();
-
- ALOGE_IF(err, "binder=%p transaction failed fd=%d, size=%zd, err=%d (%s)",
- IInterface::asBinder(this).get(),
- parcel_fd, size, err, strerror(-err));
+ const uint64_t size64 = reply.readUint64();
+ const int64_t offset64 = reply.readInt64();
+ const uint32_t flags = reply.readUint32();
+ const size_t size = (size_t)size64;
+ const off_t offset = (off_t)offset64;
+ if (err != NO_ERROR || // failed transaction
+ size != size64 || offset != offset64) { // ILP32 size check
+ ALOGE("binder=%p transaction failed fd=%d, size=%zu, err=%d (%s)",
+ IInterface::asBinder(this).get(),
+ parcel_fd, size, err, strerror(-err));
+ return;
+ }
Mutex::Autolock _l(mLock);
if (mHeapId.load(memory_order_relaxed) == -1) {
int fd = fcntl(parcel_fd, F_DUPFD_CLOEXEC, 0);
- ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, err=%d (%s)",
+ ALOGE_IF(fd == -1, "cannot dup fd=%d, size=%zu, err=%d (%s)",
parcel_fd, size, err, strerror(errno));
int access = PROT_READ;
@@ -334,7 +342,7 @@
mRealHeap = true;
mBase = mmap(nullptr, size, access, MAP_SHARED, fd, offset);
if (mBase == MAP_FAILED) {
- ALOGE("cannot map BpMemoryHeap (binder=%p), size=%zd, fd=%d (%s)",
+ ALOGE("cannot map BpMemoryHeap (binder=%p), size=%zu, fd=%d (%s)",
IInterface::asBinder(this).get(), size, fd, strerror(errno));
close(fd);
} else {
@@ -368,7 +376,7 @@
return mFlags;
}
-uint32_t BpMemoryHeap::getOffset() const {
+off_t BpMemoryHeap::getOffset() const {
assertMapped();
return mOffset;
}
@@ -390,9 +398,9 @@
case HEAP_ID: {
CHECK_INTERFACE(IMemoryHeap, data, reply);
reply->writeFileDescriptor(getHeapID());
- reply->writeInt32(getSize());
- reply->writeInt32(getFlags());
- reply->writeInt32(getOffset());
+ reply->writeUint64(getSize());
+ reply->writeInt64(getOffset());
+ reply->writeUint32(getFlags());
return NO_ERROR;
} break;
default:
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index f052bcb..7a47724 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -109,6 +109,10 @@
"BC_DEAD_BINDER_DONE"
};
+// The work source represents the UID of the process we should attribute the transaction to.
+// We use -1 to specify that the work source was not set using #setWorkSource.
+static const int kUnsetWorkSource = -1;
+
static const char* getReturnString(uint32_t cmd)
{
size_t idx = cmd & 0xff;
@@ -383,6 +387,25 @@
return mStrictModePolicy;
}
+uid_t IPCThreadState::setWorkSource(uid_t uid)
+{
+ uid_t returnValue = mWorkSource;
+ mWorkSource = uid;
+ return returnValue;
+}
+
+uid_t IPCThreadState::getWorkSource() const
+{
+ return mWorkSource;
+}
+
+uid_t IPCThreadState::clearWorkSource()
+{
+ uid_t returnValue = mWorkSource;
+ mWorkSource = kUnsetWorkSource;
+ return returnValue;
+}
+
void IPCThreadState::setLastTransactionBinderFlags(int32_t flags)
{
mLastTransactionBinderFlags = flags;
@@ -736,6 +759,7 @@
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
+ mWorkSource(kUnsetWorkSource),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0)
{
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index 9850ad9..4c300b4 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -76,7 +76,7 @@
}
}
-MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, uint32_t offset)
+MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, off_t offset)
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
@@ -85,7 +85,7 @@
mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), size, offset);
}
-status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
+status_t MemoryHeapBase::init(int fd, void *base, size_t size, int flags, const char* device)
{
if (mFD != -1) {
return INVALID_OPERATION;
@@ -98,13 +98,20 @@
return NO_ERROR;
}
-status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset)
+status_t MemoryHeapBase::mapfd(int fd, size_t size, off_t offset)
{
if (size == 0) {
// try to figure out the size automatically
struct stat sb;
- if (fstat(fd, &sb) == 0)
- size = sb.st_size;
+ if (fstat(fd, &sb) == 0) {
+ size = (size_t)sb.st_size;
+ // sb.st_size is off_t which on ILP32 may be 64 bits while size_t is 32 bits.
+ if ((off_t)size != sb.st_size) {
+ ALOGE("%s: size of file %lld cannot fit in memory",
+ __func__, (long long)sb.st_size);
+ return INVALID_OPERATION;
+ }
+ }
// if it didn't work, let mmap() fail.
}
@@ -112,12 +119,12 @@
void* base = (uint8_t*)mmap(nullptr, size,
PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
if (base == MAP_FAILED) {
- ALOGE("mmap(fd=%d, size=%u) failed (%s)",
- fd, uint32_t(size), strerror(errno));
+ ALOGE("mmap(fd=%d, size=%zu) failed (%s)",
+ fd, size, strerror(errno));
close(fd);
return -errno;
}
- //ALOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size);
+ //ALOGD("mmap(fd=%d, base=%p, size=%zu)", fd, base, size);
mBase = base;
mNeedUnmap = true;
} else {
@@ -140,7 +147,7 @@
int fd = android_atomic_or(-1, &mFD);
if (fd >= 0) {
if (mNeedUnmap) {
- //ALOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize);
+ //ALOGD("munmap(fd=%d, base=%p, size=%zu)", fd, mBase, mSize);
munmap(mBase, mSize);
}
mBase = nullptr;
@@ -169,7 +176,7 @@
return mDevice;
}
-uint32_t MemoryHeapBase::getOffset() const {
+off_t MemoryHeapBase::getOffset() const {
return mOffset;
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 87c9842..bc1a71c 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -601,6 +601,7 @@
{
writeInt32(IPCThreadState::self()->getStrictModePolicy() |
STRICT_MODE_PENALTY_GATHER);
+ writeInt32(IPCThreadState::self()->getWorkSource());
// currently the interface identification token is just its name as a string
return writeString16(interface);
}
@@ -613,6 +614,7 @@
bool Parcel::enforceInterface(const String16& interface,
IPCThreadState* threadState) const
{
+ // StrictModePolicy.
int32_t strictPolicy = readInt32();
if (threadState == nullptr) {
threadState = IPCThreadState::self();
@@ -627,6 +629,10 @@
} else {
threadState->setStrictModePolicy(strictPolicy);
}
+ // WorkSource.
+ int32_t workSource = readInt32();
+ threadState->setWorkSource(workSource);
+ // Interface descriptor.
const String16 str(readString16());
if (str == interface) {
return true;
diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h
index 3099bf5..11f7efa 100644
--- a/libs/binder/include/binder/IMemory.h
+++ b/libs/binder/include/binder/IMemory.h
@@ -43,7 +43,7 @@
virtual void* getBase() const = 0;
virtual size_t getSize() const = 0;
virtual uint32_t getFlags() const = 0;
- virtual uint32_t getOffset() const = 0;
+ virtual off_t getOffset() const = 0;
// these are there just for backward source compatibility
int32_t heapID() const { return getHeapID(); }
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 40b51ad..5888e14 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -47,6 +47,13 @@
void setStrictModePolicy(int32_t policy);
int32_t getStrictModePolicy() const;
+ // See Binder#setThreadWorkSource in Binder.java.
+ uid_t setWorkSource(uid_t uid);
+ // See Binder#getThreadWorkSource in Binder.java.
+ uid_t getWorkSource() const;
+ // See Binder#clearThreadWorkSource in Binder.java.
+ uid_t clearWorkSource();
+
void setLastTransactionBinderFlags(int32_t flags);
int32_t getLastTransactionBinderFlags() const;
@@ -155,6 +162,9 @@
status_t mLastError;
pid_t mCallingPid;
uid_t mCallingUid;
+ // The UID of the process who is responsible for this transaction.
+ // This is used for resource attribution.
+ int32_t mWorkSource;
int32_t mStrictModePolicy;
int32_t mLastTransactionBinderFlags;
IPCThreadStateBase *mIPCThreadStateBase;
diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
index 5e0a382..2f5039d 100644
--- a/libs/binder/include/binder/MemoryHeapBase.h
+++ b/libs/binder/include/binder/MemoryHeapBase.h
@@ -42,7 +42,7 @@
* maps the memory referenced by fd. but DOESN'T take ownership
* of the filedescriptor (it makes a copy with dup()
*/
- MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, uint32_t offset = 0);
+ MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, off_t offset = 0);
/*
* maps memory from the given device
@@ -64,7 +64,7 @@
virtual size_t getSize() const;
virtual uint32_t getFlags() const;
- virtual uint32_t getOffset() const;
+ off_t getOffset() const override;
const char* getDevice() const;
@@ -82,11 +82,11 @@
protected:
MemoryHeapBase();
// init() takes ownership of fd
- status_t init(int fd, void *base, int size,
+ status_t init(int fd, void *base, size_t size,
int flags = 0, const char* device = nullptr);
private:
- status_t mapfd(int fd, size_t size, uint32_t offset = 0);
+ status_t mapfd(int fd, size_t size, off_t offset = 0);
int mFD;
size_t mSize;
@@ -94,7 +94,7 @@
uint32_t mFlags;
const char* mDevice;
bool mNeedUnmap;
- uint32_t mOffset;
+ off_t mOffset;
};
// ---------------------------------------------------------------------------
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
index faeb78f..bf0c956 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -76,34 +76,18 @@
(*vec)[index] = value;
}
-/**
- * Writes a vector to the next location in a non-null parcel.
- */
-template <typename T>
-static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<T>& vec);
-
-/**
- * Reads a vector to the next location in a non-null parcel.
- */
-template <typename T>
-static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<T>* vec);
-
// @START
/**
* Writes a vector of int32_t to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<int32_t>(AParcel* parcel,
- const std::vector<int32_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) {
return AParcel_writeInt32Array(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of int32_t from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<int32_t>(const AParcel* parcel,
- std::vector<int32_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int32_t>* vec) {
void* vectorData = static_cast<void*>(vec);
return AParcel_readInt32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int32_t>,
AParcel_stdVectorGetter<int32_t>);
@@ -112,18 +96,14 @@
/**
* Writes a vector of uint32_t to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<uint32_t>(AParcel* parcel,
- const std::vector<uint32_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) {
return AParcel_writeUint32Array(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of uint32_t from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<uint32_t>(const AParcel* parcel,
- std::vector<uint32_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint32_t>* vec) {
void* vectorData = static_cast<void*>(vec);
return AParcel_readUint32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint32_t>,
AParcel_stdVectorGetter<uint32_t>);
@@ -132,18 +112,14 @@
/**
* Writes a vector of int64_t to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<int64_t>(AParcel* parcel,
- const std::vector<int64_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) {
return AParcel_writeInt64Array(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of int64_t from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<int64_t>(const AParcel* parcel,
- std::vector<int64_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int64_t>* vec) {
void* vectorData = static_cast<void*>(vec);
return AParcel_readInt64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int64_t>,
AParcel_stdVectorGetter<int64_t>);
@@ -152,18 +128,14 @@
/**
* Writes a vector of uint64_t to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<uint64_t>(AParcel* parcel,
- const std::vector<uint64_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) {
return AParcel_writeUint64Array(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of uint64_t from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<uint64_t>(const AParcel* parcel,
- std::vector<uint64_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint64_t>* vec) {
void* vectorData = static_cast<void*>(vec);
return AParcel_readUint64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint64_t>,
AParcel_stdVectorGetter<uint64_t>);
@@ -172,16 +144,14 @@
/**
* Writes a vector of float to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<float>(AParcel* parcel, const std::vector<float>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) {
return AParcel_writeFloatArray(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of float from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<float>(const AParcel* parcel, std::vector<float>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<float>* vec) {
void* vectorData = static_cast<void*>(vec);
return AParcel_readFloatArray(parcel, &vectorData, &AParcel_stdVectorReallocator<float>,
AParcel_stdVectorGetter<float>);
@@ -190,17 +160,14 @@
/**
* Writes a vector of double to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<double>(AParcel* parcel,
- const std::vector<double>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) {
return AParcel_writeDoubleArray(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of double from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<double>(const AParcel* parcel, std::vector<double>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<double>* vec) {
void* vectorData = static_cast<void*>(vec);
return AParcel_readDoubleArray(parcel, &vectorData, &AParcel_stdVectorReallocator<double>,
AParcel_stdVectorGetter<double>);
@@ -209,8 +176,7 @@
/**
* Writes a vector of bool to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<bool>(AParcel* parcel, const std::vector<bool>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) {
return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec),
AParcel_stdVectorGetter<bool>, vec.size());
}
@@ -218,8 +184,7 @@
/**
* Reads a vector of bool from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<bool>(const AParcel* parcel, std::vector<bool>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<bool>* vec) {
void* vectorData = static_cast<void*>(vec);
return AParcel_readBoolArray(parcel, &vectorData, &AParcel_stdVectorReallocator<bool>,
AParcel_stdVectorSetter<bool>);
@@ -228,18 +193,14 @@
/**
* Writes a vector of char16_t to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<char16_t>(AParcel* parcel,
- const std::vector<char16_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) {
return AParcel_writeCharArray(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of char16_t from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<char16_t>(const AParcel* parcel,
- std::vector<char16_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<char16_t>* vec) {
void* vectorData = static_cast<void*>(vec);
return AParcel_readCharArray(parcel, &vectorData, &AParcel_stdVectorReallocator<char16_t>,
AParcel_stdVectorGetter<char16_t>);
@@ -248,17 +209,14 @@
/**
* Writes a vector of int8_t to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<int8_t>(AParcel* parcel,
- const std::vector<int8_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int8_t>& vec) {
return AParcel_writeByteArray(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of int8_t from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<int8_t>(const AParcel* parcel, std::vector<int8_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int8_t>* vec) {
void* vectorData = static_cast<void*>(vec);
return AParcel_readByteArray(parcel, &vectorData, &AParcel_stdVectorReallocator<int8_t>,
AParcel_stdVectorGetter<int8_t>);
diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
index 45f8d06..2cf10d3 100755
--- a/libs/binder/ndk/scripts/gen_parcel_helper.py
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -152,8 +152,7 @@
cpp_helper += "/**\n"
cpp_helper += " * Writes a vector of " + cpp + " to the next location in a non-null parcel.\n"
cpp_helper += " */\n"
- cpp_helper += "template<>\n"
- cpp_helper += "inline binder_status_t AParcel_writeVector<" + cpp + ">(AParcel* parcel, const std::vector<" + cpp + ">& vec) {\n"
+ cpp_helper += "inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<" + cpp + ">& vec) {\n"
write_args = "vec.data()"
if nca: write_args = "static_cast<const void*>(&vec), AParcel_stdVectorGetter<" + cpp + ">"
cpp_helper += " return AParcel_write" + pretty + "Array(parcel, " + write_args + ", vec.size());\n"
@@ -162,8 +161,7 @@
cpp_helper += "/**\n"
cpp_helper += " * Reads a vector of " + cpp + " from the next location in a non-null parcel.\n"
cpp_helper += " */\n"
- cpp_helper += "template<>\n"
- cpp_helper += "inline binder_status_t AParcel_readVector<" + cpp + ">(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n"
+ cpp_helper += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n"
cpp_helper += " void* vectorData = static_cast<void*>(vec);\n"
read_args = []
read_args += ["parcel"]
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 73c2eba..7bcfffd 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -71,6 +71,7 @@
BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION,
BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION,
BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
+ BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION,
};
pid_t start_server_process(int arg2, bool usePoll = false)
@@ -938,6 +939,43 @@
EXPECT_EQ(NO_ERROR, ret);
}
+TEST_F(BinderLibTest, WorkSourceUnsetByDefault)
+{
+ status_t ret;
+ Parcel data, reply;
+ data.writeInterfaceToken(binderLibTestServiceName);
+ ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+ EXPECT_EQ(-1, reply.readInt32());
+ EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, WorkSourceSet)
+{
+ status_t ret;
+ Parcel data, reply;
+ uid_t previousWorkSource = IPCThreadState::self()->setWorkSource(100);
+ data.writeInterfaceToken(binderLibTestServiceName);
+ ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+ EXPECT_EQ(100, reply.readInt32());
+ EXPECT_EQ(-1, previousWorkSource);
+ EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, WorkSourceCleared)
+{
+ status_t ret;
+ Parcel data, reply;
+
+ IPCThreadState::self()->setWorkSource(100);
+ uid_t previousWorkSource = IPCThreadState::self()->clearWorkSource();
+ data.writeInterfaceToken(binderLibTestServiceName);
+ ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+
+ EXPECT_EQ(-1, reply.readInt32());
+ EXPECT_EQ(100, previousWorkSource);
+ EXPECT_EQ(NO_ERROR, ret);
+}
+
class BinderLibTestService : public BBinder
{
public:
@@ -1236,6 +1274,11 @@
}
return NO_ERROR;
}
+ case BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION: {
+ data.enforceInterface(binderLibTestServiceName);
+ reply->writeInt32(IPCThreadState::self()->getWorkSource());
+ return NO_ERROR;
+ }
default:
return UNKNOWN_TRANSACTION;
};
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index e53f7fd..024d72b 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -167,7 +167,7 @@
auto sphalNamespace = android_get_exported_namespace("sphal");
if (!sphalNamespace) return;
mDriverNamespace = android_create_namespace("gfx driver",
- nullptr, // ld_library_path
+ mDriverPath.c_str(), // ld_library_path
mDriverPath.c_str(), // default_library_path
ANDROID_NAMESPACE_TYPE_SHARED |
ANDROID_NAMESPACE_TYPE_ISOLATED,
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index f99bc53..cf9d4c5 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -103,11 +103,15 @@
}
virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
+ const ui::Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+ ISurfaceComposer::Rotation rotation) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(display);
+ data.writeInt32(static_cast<int32_t>(reqDataspace));
+ data.writeInt32(static_cast<int32_t>(reqPixelFormat));
data.write(sourceCrop);
data.writeUint32(reqWidth);
data.writeUint32(reqHeight);
@@ -126,15 +130,19 @@
*outBuffer = new GraphicBuffer();
reply.read(**outBuffer);
+
return result;
}
virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
- sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+ sp<GraphicBuffer>* outBuffer, const ui::Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
float frameScale, bool childrenOnly) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(layerHandleBinder);
+ data.writeInt32(static_cast<int32_t>(reqDataspace));
+ data.writeInt32(static_cast<int32_t>(reqPixelFormat));
data.write(sourceCrop);
data.writeFloat(frameScale);
data.writeBool(childrenOnly);
@@ -148,6 +156,7 @@
ALOGE("captureLayers failed to readInt32: %d", result);
return result;
}
+
*outBuffer = new GraphicBuffer();
reply.read(**outBuffer);
@@ -645,6 +654,8 @@
case CAPTURE_SCREEN: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = data.readStrongBinder();
+ ui::Dataspace reqDataspace = static_cast<ui::Dataspace>(data.readInt32());
+ ui::PixelFormat reqPixelFormat = static_cast<ui::PixelFormat>(data.readInt32());
sp<GraphicBuffer> outBuffer;
Rect sourceCrop(Rect::EMPTY_RECT);
data.read(sourceCrop);
@@ -653,8 +664,8 @@
bool useIdentityTransform = static_cast<bool>(data.readInt32());
int32_t rotation = data.readInt32();
- status_t res = captureScreen(display, &outBuffer, sourceCrop, reqWidth, reqHeight,
- useIdentityTransform,
+ status_t res = captureScreen(display, &outBuffer, reqDataspace, reqPixelFormat,
+ sourceCrop, reqWidth, reqHeight, useIdentityTransform,
static_cast<ISurfaceComposer::Rotation>(rotation));
reply->writeInt32(res);
if (res == NO_ERROR) {
@@ -665,14 +676,16 @@
case CAPTURE_LAYERS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> layerHandleBinder = data.readStrongBinder();
+ ui::Dataspace reqDataspace = static_cast<ui::Dataspace>(data.readInt32());
+ ui::PixelFormat reqPixelFormat = static_cast<ui::PixelFormat>(data.readInt32());
sp<GraphicBuffer> outBuffer;
Rect sourceCrop(Rect::EMPTY_RECT);
data.read(sourceCrop);
float frameScale = data.readFloat();
bool childrenOnly = data.readBool();
- status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale,
- childrenOnly);
+ status_t res = captureLayers(layerHandleBinder, &outBuffer, reqDataspace,
+ reqPixelFormat, sourceCrop, frameScale, childrenOnly);
reply->writeInt32(res);
if (res == NO_ERROR) {
reply->write(*outBuffer);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 1ac9609..7498f36 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -887,13 +887,14 @@
// ----------------------------------------------------------------------------
-status_t ScreenshotClient::capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
- uint32_t reqHeight, bool useIdentityTransform, uint32_t rotation,
- sp<GraphicBuffer>* outBuffer) {
+status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+ uint32_t rotation, sp<GraphicBuffer>* outBuffer) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight,
- useIdentityTransform,
+ status_t ret = s->captureScreen(display, outBuffer, reqDataSpace, reqPixelFormat, sourceCrop,
+ reqWidth, reqHeight, useIdentityTransform,
static_cast<ISurfaceComposer::Rotation>(rotation));
if (ret != NO_ERROR) {
return ret;
@@ -901,21 +902,25 @@
return ret;
}
-status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
+ const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
float frameScale, sp<GraphicBuffer>* outBuffer) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
- false /* childrenOnly */);
+ status_t ret = s->captureLayers(layerHandle, outBuffer, reqDataSpace, reqPixelFormat,
+ sourceCrop, frameScale, false /* childrenOnly */);
return ret;
}
-status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle,
+ const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
float frameScale, sp<GraphicBuffer>* outBuffer) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
- true /* childrenOnly */);
+ status_t ret = s->captureLayers(layerHandle, outBuffer, reqDataSpace, reqPixelFormat,
+ sourceCrop, frameScale, true /* childrenOnly */);
return ret;
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index a55cfe0..781e062 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -180,6 +180,36 @@
* The subregion can be optionally rotated. It will also be scaled to
* match the size of the output buffer.
*
+ * reqDataspace and reqPixelFormat specify the data space and pixel format
+ * of the buffer. The caller should pick the data space and pixel format
+ * that it can consume.
+ *
+ * At the moment, sourceCrop is ignored and is always set to the visible
+ * region (projected display viewport) of the screen.
+ *
+ * reqWidth and reqHeight specifies the size of the buffer. When either
+ * of them is 0, they are set to the size of the logical display viewport.
+ *
+ * When useIdentityTransform is true, layer transformations are disabled.
+ *
+ * rotation specifies the rotation of the source crop (and the pixels in
+ * it) around its center.
+ */
+ virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
+ const ui::Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+ Rotation rotation = eRotateNone) = 0;
+ /**
+ * Capture the specified screen. This requires READ_FRAME_BUFFER
+ * permission. This function will fail if there is a secure window on
+ * screen.
+ *
+ * This function can capture a subregion (the source crop) of the screen
+ * into an sRGB buffer with RGBA_8888 pixel format.
+ * The subregion can be optionally rotated. It will also be scaled to
+ * match the size of the output buffer.
+ *
* At the moment, sourceCrop is ignored and is always set to the visible
* region (projected display viewport) of the screen.
*
@@ -193,15 +223,34 @@
*/
virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- bool useIdentityTransform, Rotation rotation = eRotateNone) = 0;
+ bool useIdentityTransform, Rotation rotation = eRotateNone) {
+ return captureScreen(display, outBuffer, ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888,
+ sourceCrop, reqWidth, reqHeight, useIdentityTransform, rotation);
+ }
/**
* Capture a subtree of the layer hierarchy, potentially ignoring the root node.
+ *
+ * reqDataspace and reqPixelFormat specify the data space and pixel format
+ * of the buffer. The caller should pick the data space and pixel format
+ * that it can consume.
*/
virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
- sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+ sp<GraphicBuffer>* outBuffer, const ui::Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
float frameScale = 1.0, bool childrenOnly = false) = 0;
+ /**
+ * Capture a subtree of the layer hierarchy into an sRGB buffer with RGBA_8888 pixel format,
+ * potentially ignoring the root node.
+ */
+ status_t captureLayers(const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer,
+ const Rect& sourceCrop, float frameScale = 1.0,
+ bool childrenOnly = false) {
+ return captureLayers(layerHandleBinder, outBuffer, ui::Dataspace::V0_SRGB,
+ ui::PixelFormat::RGBA_8888, sourceCrop, frameScale, childrenOnly);
+ }
+
/* Clears the frame statistics for animations.
*
* Requires the ACCESS_SURFACE_FLINGER permission.
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 69a759f..1b4eda7 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -329,12 +329,16 @@
public:
// if cropping isn't required, callers may pass in a default Rect, e.g.:
// capture(display, producer, Rect(), reqWidth, ...);
- static status_t capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
- uint32_t reqHeight, bool useIdentityTransform, uint32_t rotation,
- sp<GraphicBuffer>* outBuffer);
- static status_t captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, float frameScale,
- sp<GraphicBuffer>* outBuffer);
- static status_t captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+ static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+ uint32_t rotation, sp<GraphicBuffer>* outBuffer);
+ static status_t captureLayers(const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ float frameScale, sp<GraphicBuffer>* outBuffer);
+ static status_t captureChildLayers(const sp<IBinder>& layerHandle,
+ const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
float frameScale, sp<GraphicBuffer>* outBuffer);
};
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index bc80899..500df05 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -134,8 +134,9 @@
sp<IBinder> display(sf->getBuiltInDisplay(
ISurfaceComposer::eDisplayIdMain));
sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(),
- 64, 64, false));
+ ASSERT_EQ(NO_ERROR,
+ sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB,
+ ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false));
ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(),
NATIVE_WINDOW_API_CPU));
@@ -165,8 +166,9 @@
&buf));
ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
}
- ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(),
- 64, 64, false));
+ ASSERT_EQ(NO_ERROR,
+ sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB,
+ ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false));
}
TEST_F(SurfaceTest, ConcreteTypeIsSurface) {
@@ -596,14 +598,19 @@
}
status_t setActiveColorMode(const sp<IBinder>& /*display*/,
ColorMode /*colorMode*/) override { return NO_ERROR; }
- status_t captureScreen(const sp<IBinder>& /*display*/,
- sp<GraphicBuffer>* /*outBuffer*/,
- Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
- bool /*useIdentityTransform*/,
- Rotation /*rotation*/) override { return NO_ERROR; }
+ status_t captureScreen(const sp<IBinder>& /*display*/, sp<GraphicBuffer>* /*outBuffer*/,
+ const ui::Dataspace /*reqDataspace*/,
+ const ui::PixelFormat /*reqPixelFormat*/, Rect /*sourceCrop*/,
+ uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
+ bool /*useIdentityTransform*/, Rotation /*rotation*/) override {
+ return NO_ERROR;
+ }
virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
- sp<GraphicBuffer>* /*outBuffer*/, const Rect& /*sourceCrop*/,
- float /*frameScale*/, bool /*childrenOnly*/) override {
+ sp<GraphicBuffer>* /*outBuffer*/,
+ const ui::Dataspace /*reqDataspace*/,
+ const ui::PixelFormat /*reqPixelFormat*/,
+ const Rect& /*sourceCrop*/, float /*frameScale*/,
+ bool /*childrenOnly*/) override {
return NO_ERROR;
}
status_t clearAnimationFrameStats() override { return NO_ERROR; }
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index ba5cfcd..43ac79e 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -22,6 +22,7 @@
"buffer_hub_base.cpp",
"buffer_hub_rpc.cpp",
"consumer_buffer.cpp",
+ "buffer_client_impl.cpp",
"ion_buffer.cpp",
"producer_buffer.cpp",
]
diff --git a/libs/vr/libbufferhub/buffer_client_impl.cpp b/libs/vr/libbufferhub/buffer_client_impl.cpp
new file mode 100644
index 0000000..6bef98a
--- /dev/null
+++ b/libs/vr/libbufferhub/buffer_client_impl.cpp
@@ -0,0 +1,55 @@
+#include <log/log.h>
+#include <private/dvr/IBufferClient.h>
+
+namespace android {
+namespace dvr {
+
+class BpBufferClient : public BpInterface<IBufferClient> {
+ public:
+ explicit BpBufferClient(const sp<IBinder>& impl)
+ : BpInterface<IBufferClient>(impl) {}
+
+ bool isValid() override;
+};
+
+IMPLEMENT_META_INTERFACE(BufferClient, "android.dvr.IBufferClient");
+
+// Transaction code
+enum {
+ IS_VALID = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+bool BpBufferClient::isValid() {
+ Parcel data, reply;
+ status_t ret =
+ data.writeInterfaceToken(IBufferClient::getInterfaceDescriptor());
+ if (ret != NO_ERROR) {
+ ALOGE("BpBufferClient::isValid: failed to write into parcel; errno=%d",
+ ret);
+ return false;
+ }
+
+ ret = remote()->transact(IS_VALID, data, &reply);
+ if (ret == NO_ERROR) {
+ return reply.readBool();
+ } else {
+ ALOGE("BpBufferClient::isValid: failed to transact; errno=%d", ret);
+ return false;
+ }
+}
+
+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;
+ default:
+ // Should not reach except binder defined transactions such as dumpsys
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+} // namespace dvr
+} // namespace android
\ No newline at end of file
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 8c6e7e2..8351efc 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -214,13 +214,12 @@
ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
- uint64_t context;
LocalHandle fence;
// The producer buffer starts in gained state.
// Acquire, release, and gain in gained state should fail.
- EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence));
EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
EXPECT_EQ(-EALREADY, p->Gain(&fence));
@@ -233,10 +232,10 @@
EXPECT_EQ(-EBUSY, p->Gain(&fence));
// Acquire in posted state should succeed.
- EXPECT_LE(0, c->Acquire(&fence, &context));
+ EXPECT_LE(0, c->Acquire(&fence));
// Acquire, post, and gain in acquired state should fail.
- EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence));
EXPECT_EQ(-EBUSY, p->Post(LocalHandle()));
EXPECT_EQ(-EBUSY, p->Gain(&fence));
@@ -246,14 +245,14 @@
// Release, acquire, and post in released state should fail.
EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
- EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence));
EXPECT_EQ(-EBUSY, p->Post(LocalHandle()));
// Gain in released state should succeed.
EXPECT_EQ(0, p->Gain(&fence));
// Acquire, release, and gain in gained state should fail.
- EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence));
EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
EXPECT_EQ(-EALREADY, p->Gain(&fence));
}
@@ -329,6 +328,36 @@
EXPECT_FALSE(invalid_fence.IsValid());
}
+TEST_F(LibBufferHubTest, TestGainPostedBuffer) {
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+
+ // The producer buffer starts in gained state. Post the buffer.
+ ASSERT_EQ(0, p->Post(LocalHandle()));
+
+ // Gain in posted state should only succeed with gain_posted_buffer = true.
+ LocalHandle invalid_fence;
+ EXPECT_EQ(-EBUSY, p->Gain(&invalid_fence, false));
+ EXPECT_EQ(0, p->Gain(&invalid_fence, true));
+}
+
+TEST_F(LibBufferHubTest, TestGainPostedBufferAsync) {
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+
+ // The producer buffer starts in gained state. Post the buffer.
+ ASSERT_EQ(0, p->Post(LocalHandle()));
+
+ // GainAsync in posted state should only succeed with gain_posted_buffer
+ // equals true.
+ DvrNativeBufferMetadata metadata;
+ LocalHandle invalid_fence;
+ EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence, false));
+ EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence, true));
+}
+
TEST_F(LibBufferHubTest, TestZeroConsumer) {
std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
@@ -491,7 +520,7 @@
EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
LocalHandle fence;
Metadata m2 = {};
- EXPECT_EQ(0, c->Acquire(&fence, &m2));
+ EXPECT_EQ(0, c->Acquire(&fence, &m2, sizeof(m2)));
EXPECT_EQ(m.field1, m2.field1);
EXPECT_EQ(m.field2, m2.field2);
EXPECT_EQ(0, c->Release(LocalHandle()));
@@ -552,11 +581,11 @@
// It is illegal to acquire metadata larger than originally requested during
// buffer allocation.
- EXPECT_NE(0, c->Acquire(&fence, &e));
+ EXPECT_NE(0, c->Acquire(&fence, &e, sizeof(e)));
// It is ok to acquire metadata smaller than originally requested during
// buffer allocation.
- EXPECT_EQ(0, c->Acquire(&fence, &sequence));
+ EXPECT_EQ(0, c->Acquire(&fence, &sequence, sizeof(sequence)));
EXPECT_EQ(m.field1, sequence);
}
diff --git a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
new file mode 100644
index 0000000..03f2d95
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
@@ -0,0 +1,29 @@
+#ifndef ANDROID_DVR_IBUFFERCLIENT_H
+#define ANDROID_DVR_IBUFFERCLIENT_H
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+namespace dvr {
+
+// Interface for acessing BufferHubBuffer remotely.
+class IBufferClient : public IInterface {
+ public:
+ DECLARE_META_INTERFACE(BufferClient);
+
+ // Checks if the buffer node is valid.
+ virtual bool isValid() = 0;
+};
+
+// BnInterface for IBufferClient. Should only be created in bufferhub service.
+class BnBufferClient : public BnInterface<IBufferClient> {
+ public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_IBUFFERCLIENT_H
\ No newline at end of file
diff --git a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
index 2044c53..7349779 100644
--- a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
@@ -45,15 +45,6 @@
// Returns zero on success, or a negative errno code otherwise.
int Acquire(LocalHandle* ready_fence, void* meta, size_t user_metadata_size);
- // Attempt to retrieve a post event from buffer hub. If successful,
- // |ready_fence| is set to a fence to wait on until the buffer is ready. This
- // call will only succeed after the fd is signaled. This returns zero or a
- // negative unix error code.
- template <typename Meta>
- int Acquire(LocalHandle* ready_fence, Meta* meta) {
- return Acquire(ready_fence, meta, sizeof(*meta));
- }
-
// Asynchronously acquires a bufer.
int AcquireAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
diff --git a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
index d2d4d1e..2761416 100644
--- a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
@@ -52,11 +52,14 @@
// Attempt to re-gain the buffer for writing. If |release_fence| is valid, it
// must be waited on before using the buffer. If it is not valid then the
- // buffer is free for immediate use. This call will only succeed if the buffer
- // is in the released state.
- // This returns zero or a negative unix error code.
- int Gain(LocalHandle* release_fence);
- int GainAsync();
+ // buffer is free for immediate use. This call will succeed if the buffer
+ // is in the released state, or in posted state and gain_posted_buffer is
+ // true.
+ //
+ // @param release_fence output fence.
+ // @param gain_posted_buffer whether to gain posted buffer or not.
+ // @return This returns zero or a negative unix error code.
+ int Gain(LocalHandle* release_fence, bool gain_posted_buffer = false);
// Asynchronously marks a released buffer as gained. This method is similar to
// the synchronous version above, except that it does not wait for BufferHub
@@ -64,7 +67,13 @@
// the underlying message, no error is returned if this method is called when
// the buffer is in an incorrect state. Returns zero if sending the message
// succeeded, or a negative errno code if local error check fails.
- int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+ // TODO(b/112007999): gain_posted_buffer true is only used to prevent
+ // libdvrtracking from starving when there are non-responding clients. This
+ // gain_posted_buffer param can be removed once libdvrtracking start to use
+ // the new AHardwareBuffer API.
+ int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence,
+ bool gain_posted_buffer = false);
+ int GainAsync();
// 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.
@@ -92,7 +101,8 @@
explicit ProducerBuffer(LocalChannelHandle channel);
// Local state transition helpers.
- int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+ int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence,
+ bool gain_posted_buffer = false);
int LocalPost(const DvrNativeBufferMetadata* meta,
const LocalHandle& ready_fence);
};
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index 7b6f77a..8f0e3e3 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -134,7 +134,7 @@
}
int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta,
- LocalHandle* out_fence) {
+ LocalHandle* out_fence, bool gain_posted_buffer) {
uint64_t buffer_state = buffer_state_->load();
ALOGD_IF(TRACE, "ProducerBuffer::LocalGain: buffer=%d, state=%" PRIx64 ".",
id(), buffer_state);
@@ -142,13 +142,14 @@
if (!out_meta)
return -EINVAL;
- if (!BufferHubDefs::IsBufferReleased(buffer_state)) {
- if (BufferHubDefs::IsBufferGained(buffer_state)) {
- // We don't want to log error when gaining a newly allocated
- // buffer.
- ALOGI("ProducerBuffer::LocalGain: already gained id=%d.", id());
- return -EALREADY;
- }
+ if (BufferHubDefs::IsBufferGained(buffer_state)) {
+ // We don't want to log error when gaining a newly allocated
+ // buffer.
+ ALOGI("ProducerBuffer::LocalGain: already gained id=%d.", id());
+ return -EALREADY;
+ }
+ if (BufferHubDefs::IsBufferAcquired(buffer_state) ||
+ (BufferHubDefs::IsBufferPosted(buffer_state) && !gain_posted_buffer)) {
ALOGE("ProducerBuffer::LocalGain: not released id=%d state=%" PRIx64 ".",
id(), buffer_state);
return -EBUSY;
@@ -180,11 +181,11 @@
return 0;
}
-int ProducerBuffer::Gain(LocalHandle* release_fence) {
+int ProducerBuffer::Gain(LocalHandle* release_fence, bool gain_posted_buffer) {
ATRACE_NAME("ProducerBuffer::Gain");
DvrNativeBufferMetadata meta;
- if (const int error = LocalGain(&meta, release_fence))
+ if (const int error = LocalGain(&meta, release_fence, gain_posted_buffer))
return error;
auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>();
@@ -194,10 +195,11 @@
}
int ProducerBuffer::GainAsync(DvrNativeBufferMetadata* out_meta,
- LocalHandle* release_fence) {
+ LocalHandle* release_fence,
+ bool gain_posted_buffer) {
ATRACE_NAME("ProducerBuffer::GainAsync");
- if (const int error = LocalGain(out_meta, release_fence))
+ if (const int error = LocalGain(out_meta, release_fence, gain_posted_buffer))
return error;
return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode));
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 6f792ec..a7fea33 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -549,7 +549,14 @@
char model[PROPERTY_VALUE_MAX];
property_get("ro.product.manufacturer", manufacturer, "UNSET");
property_get("ro.product.model", model, "UNSET");
- so = load_angle_from_namespace("feature_support", ns);
+
+ // Check if ANGLE is enabled. Workaround for b/118375731
+ // We suspect that loading & unloading a library somehow corrupts
+ // the process.
+ property_get("debug.angle.enable", prop, "0");
+ if (atoi(prop)) {
+ so = load_angle_from_namespace("feature_support", ns);
+ }
if (so) {
ALOGV("Temporarily loaded ANGLE's opt-in/out logic from namespace");
bool use_version0_API = false;
diff --git a/opengl/tools/glgen/stubs/egl/EGL15Header.java-if b/opengl/tools/glgen/stubs/egl/EGL15Header.java-if
index 7409d93..859380f 100644
--- a/opengl/tools/glgen/stubs/egl/EGL15Header.java-if
+++ b/opengl/tools/glgen/stubs/egl/EGL15Header.java-if
@@ -20,7 +20,9 @@
* EGL 1.5
*
*/
-public class EGL15 {
+public final class EGL15 {
+
+ private EGL15() {};
public static final int EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT = 0x00000001;
public static final int EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT = 0x00000002;
diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp
index f1d3726..2da2a70 100644
--- a/services/inputflinger/host/InputFlinger.cpp
+++ b/services/inputflinger/host/InputFlinger.cpp
@@ -53,7 +53,7 @@
if ((uid != AID_SHELL)
&& !PermissionCache::checkPermission(sDumpPermission, pid, uid)) {
result.appendFormat("Permission Denial: "
- "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
+ "can't dump InputFlinger from pid=%d, uid=%d\n", pid, uid);
} else {
dumpInternal(result);
}
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index ab677e1..440f1e2 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -70,6 +70,8 @@
mName.string());
destroyAllHwcLayers();
}
+
+ mTimeStats.onDestroy(getSequence());
}
void BufferLayer::useSurfaceDamage() {
@@ -335,8 +337,8 @@
nsecs_t desiredPresentTime = getDesiredPresentTime();
mFrameTracker.setDesiredPresentTime(desiredPresentTime);
- const std::string layerName(getName().c_str());
- mTimeStats.setDesiredTime(layerName, mCurrentFrameNumber, desiredPresentTime);
+ const int32_t layerID = getSequence();
+ mTimeStats.setDesiredTime(layerID, mCurrentFrameNumber, desiredPresentTime);
std::shared_ptr<FenceTime> frameReadyFence = getCurrentFenceTime();
if (frameReadyFence->isValid()) {
@@ -348,14 +350,14 @@
}
if (presentFence->isValid()) {
- mTimeStats.setPresentFence(layerName, mCurrentFrameNumber, presentFence);
+ mTimeStats.setPresentFence(layerID, mCurrentFrameNumber, presentFence);
mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
} else if (mFlinger->getHwComposer().isConnected(HWC_DISPLAY_PRIMARY)) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
const nsecs_t actualPresentTime =
mFlinger->getHwComposer().getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
- mTimeStats.setPresentTime(layerName, mCurrentFrameNumber, actualPresentTime);
+ mTimeStats.setPresentTime(layerID, mCurrentFrameNumber, actualPresentTime);
mFrameTracker.setActualPresentTime(actualPresentTime);
}
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 6cbc4c4..e592a8b 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -227,6 +227,7 @@
// BufferItem's that weren't actually queued. This can happen in shared
// buffer mode.
bool queuedBuffer = false;
+ const int32_t layerID = getSequence();
LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
getTransformToDisplayInverse(), mFreezeGeometryUpdates);
@@ -247,7 +248,7 @@
// and return early
if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
- mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
+ mTimeStats.removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
mQueueItems.removeAt(0);
mQueuedFrames--;
}
@@ -261,7 +262,7 @@
Mutex::Autolock lock(mQueueItemLock);
mQueueItems.clear();
mQueuedFrames = 0;
- mTimeStats.clearLayerRecord(getName().c_str());
+ mTimeStats.clearLayerRecord(layerID);
}
// Once we have hit this state, the shadow queue may no longer
@@ -282,14 +283,13 @@
// Remove any stale buffers that have been dropped during
// updateTexImage
while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
- mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
+ mTimeStats.removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
mQueueItems.removeAt(0);
mQueuedFrames--;
}
- const std::string layerName(getName().c_str());
- mTimeStats.setAcquireFence(layerName, currentFrameNumber, mQueueItems[0].mFenceTime);
- mTimeStats.setLatchTime(layerName, currentFrameNumber, latchTime);
+ mTimeStats.setAcquireFence(layerID, currentFrameNumber, mQueueItems[0].mFenceTime);
+ mTimeStats.setLatchTime(layerID, currentFrameNumber, latchTime);
mQueueItems.removeAt(0);
}
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index e52b35a..5df8ade 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -377,6 +377,8 @@
return NO_ERROR;
}
+ const int32_t layerID = getSequence();
+
// Reject if the layer is invalid
uint32_t bufferWidth = s.buffer->width;
uint32_t bufferHeight = s.buffer->height;
@@ -397,7 +399,7 @@
ALOGE("[%s] rejecting buffer: "
"bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
mName.string(), bufferWidth, bufferHeight, s.active.w, s.active.h);
- mTimeStats.removeTimeRecord(getName().c_str(), getFrameNumber());
+ mTimeStats.removeTimeRecord(layerID, getFrameNumber());
return BAD_VALUE;
}
@@ -405,7 +407,7 @@
if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
// TODO(alecmouri): Fail somewhere upstream if the fence is invalid.
if (!releaseFence->isValid()) {
- mTimeStats.clearLayerRecord(getName().c_str());
+ mTimeStats.clearLayerRecord(layerID);
return UNKNOWN_ERROR;
}
@@ -415,7 +417,7 @@
auto currentStatus = s.acquireFence->getStatus();
if (currentStatus == Fence::Status::Invalid) {
ALOGE("Existing fence has invalid state");
- mTimeStats.clearLayerRecord(getName().c_str());
+ mTimeStats.clearLayerRecord(layerID);
return BAD_VALUE;
}
@@ -423,7 +425,7 @@
if (incomingStatus == Fence::Status::Invalid) {
ALOGE("New fence has invalid state");
mDrawingState.acquireFence = releaseFence;
- mTimeStats.clearLayerRecord(getName().c_str());
+ mTimeStats.clearLayerRecord(layerID);
return BAD_VALUE;
}
@@ -439,7 +441,7 @@
// synchronization is broken, the best we can do is hope fences
// signal in order so the new fence will act like a union
mDrawingState.acquireFence = releaseFence;
- mTimeStats.clearLayerRecord(getName().c_str());
+ mTimeStats.clearLayerRecord(layerID);
return BAD_VALUE;
}
mDrawingState.acquireFence = mergedFence;
@@ -462,16 +464,16 @@
// a GL-composited layer) not at all.
status_t err = bindTextureImage();
if (err != NO_ERROR) {
- mTimeStats.clearLayerRecord(getName().c_str());
+ mTimeStats.clearLayerRecord(layerID);
return BAD_VALUE;
}
}
// TODO(marissaw): properly support mTimeStats
- const std::string layerName(getName().c_str());
- mTimeStats.setPostTime(getName().c_str(), getFrameNumber(), latchTime);
- mTimeStats.setAcquireFence(layerName, getFrameNumber(), getCurrentFenceTime());
- mTimeStats.setLatchTime(layerName, getFrameNumber(), latchTime);
+ mTimeStats.setLayerName(layerID, getName().c_str());
+ mTimeStats.setPostTime(layerID, getFrameNumber(), latchTime);
+ mTimeStats.setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime());
+ mTimeStats.setLatchTime(layerID, getFrameNumber(), latchTime);
return NO_ERROR;
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 38482c9..918f7de 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -349,10 +349,11 @@
DisplayRenderArea(const sp<const DisplayDevice> device,
ui::Transform::orientation_flags rotation = ui::Transform::ROT_0)
: DisplayRenderArea(device, device->getBounds(), device->getWidth(), device->getHeight(),
- rotation) {}
+ device->getCompositionDataSpace(), rotation) {}
DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqWidth,
- uint32_t reqHeight, ui::Transform::orientation_flags rotation)
- : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE,
+ uint32_t reqHeight, ui::Dataspace reqDataSpace,
+ ui::Transform::orientation_flags rotation)
+ : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, reqDataSpace,
getDisplayRotation(rotation, device->getInstallOrientation())),
mDevice(device),
mSourceCrop(sourceCrop) {}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 3a40648..393041d 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -184,7 +184,6 @@
auto newDisplay = std::make_unique<Display>(
*mComposer.get(), mPowerAdvisor, mCapabilities, displayId, displayType);
- newDisplay->setFrequencyScaleParameters(mFrequencyScaler);
newDisplay->setConnected(true);
mDisplays.emplace(displayId, std::move(newDisplay));
} else if (connection == Connection::Disconnected) {
@@ -224,14 +223,6 @@
return static_cast<Error>(mComposer->executeCommands());
}
-void Device::setDisplayFrequencyScaleParameters(Device::FrequencyScaler frequencyScaler) {
- mFrequencyScaler = frequencyScaler;
-}
-
-Device::FrequencyScaler Device::getDisplayFrequencyScaleParameters() {
- return mFrequencyScaler;
-}
-
// Display methods
Display::Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
@@ -271,7 +262,6 @@
mWidth(-1),
mHeight(-1),
mVsyncPeriod(-1),
- mFrequencyScaler(display.mFrequencyScaler),
mDpiX(-1),
mDpiY(-1) {}
@@ -711,10 +701,6 @@
mIsConnected = connected;
}
-void Display::setFrequencyScaleParameters(Device::FrequencyScaler frequencyScaler) {
- mFrequencyScaler = frequencyScaler;
-}
-
int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute)
{
int32_t value = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 363adb5..d274631 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -23,7 +23,6 @@
#undef HWC2_INCLUDE_STRINGIFICATION
#undef HWC2_USE_CPP11
-#include <cutils/properties.h>
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
#include <ui/GraphicTypes.h>
@@ -85,11 +84,6 @@
public:
explicit Device(std::unique_ptr<android::Hwc2::Composer> composer);
- struct FrequencyScaler {
- int32_t multiplier = 1;
- int32_t divisor = 1;
- };
-
void registerCallback(ComposerCallback* callback, int32_t sequenceId);
// Required by HWC2
@@ -121,9 +115,6 @@
// This method provides an explicit way to flush state changes to HWC.
Error flushCommands();
- void setDisplayFrequencyScaleParameters(FrequencyScaler frequecyScaler);
- FrequencyScaler getDisplayFrequencyScaleParameters();
-
private:
// Initialization methods
@@ -134,7 +125,6 @@
std::unordered_set<Capability> mCapabilities;
std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays;
android::Hwc2::impl::PowerAdvisor mPowerAdvisor;
- FrequencyScaler mFrequencyScaler;
bool mRegisteredCallback = false;
};
@@ -199,8 +189,7 @@
int32_t getWidth() const { return mWidth; }
int32_t getHeight() const { return mHeight; }
- nsecs_t getVsyncPeriod() const {
- return mVsyncPeriod * mFrequencyScaler.multiplier / mFrequencyScaler.divisor; }
+ nsecs_t getVsyncPeriod() const { return mVsyncPeriod; }
float getDpiX() const { return mDpiX; }
float getDpiY() const { return mDpiY; }
@@ -213,7 +202,6 @@
int32_t mWidth;
int32_t mHeight;
nsecs_t mVsyncPeriod;
- Device::FrequencyScaler mFrequencyScaler;
float mDpiX;
float mDpiY;
};
@@ -281,7 +269,6 @@
hwc2_display_t getId() const { return mId; }
bool isConnected() const { return mIsConnected; }
void setConnected(bool connected); // For use by Device only
- void setFrequencyScaleParameters(Device::FrequencyScaler frequencyScaler);
private:
int32_t getAttribute(hwc2_config_t configId, Attribute attribute);
@@ -306,7 +293,6 @@
hwc2_display_t mId;
bool mIsConnected;
DisplayType mType;
- Device::FrequencyScaler mFrequencyScaler;
std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
};
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 6b56ca4..d827fd2 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -814,15 +814,4 @@
return mDisplayData[displayId].hwcDisplay->getId();
}
-void HWComposer::setDisplayFrequencyScaleParameters(
- HWC2::Device::FrequencyScaler frequencyScaler)
-{
- mHwcDevice->setDisplayFrequencyScaleParameters(frequencyScaler);
-}
-
-HWC2::Device::FrequencyScaler HWComposer::getDisplayFrequencyScaleParameters()
-{
- return mHwcDevice->getDisplayFrequencyScaleParameters();
-}
-
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index cca1f3b..4777ca9 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -186,14 +186,6 @@
android::Hwc2::Composer* getComposer() const { return mHwcDevice->getComposer(); }
std::optional<hwc2_display_t> getHwcDisplayId(int32_t displayId) const;
-
- // ------------------------------------------------------------------------
- // These functions set and get the frequencyScaler. The frequencyScaler holds
- // a multiplier and divisor for virtually scaling the panel frequency in
- // software. This is used to simulate different panel frequencies when
- // panel hardware is not available.
- void setDisplayFrequencyScaleParameters(HWC2::Device::FrequencyScaler frequencyScaler);
- HWC2::Device::FrequencyScaler getDisplayFrequencyScaleParameters();
private:
// For unit tests
friend TestableSurfaceFlinger;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3a3f5eb..88c3c8a 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1470,14 +1470,15 @@
void Layer::onDisconnect() {
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.onDisconnect();
- mTimeStats.onDisconnect(getName().c_str());
+ mTimeStats.onDisconnect(getSequence());
}
void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) {
if (newTimestamps) {
- mTimeStats.setPostTime(getName().c_str(), newTimestamps->frameNumber,
- newTimestamps->postedTime);
+ const int32_t layerID = getSequence();
+ mTimeStats.setLayerName(layerID, getName().c_str());
+ mTimeStats.setPostTime(layerID, newTimestamps->frameNumber, newTimestamps->postedTime);
}
Mutex::Autolock lock(mFrameEventHistoryMutex);
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 3c11e73..9bad6de 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -1,5 +1,6 @@
#pragma once
+#include <ui/GraphicTypes.h>
#include <ui/Transform.h>
#include <functional>
@@ -19,9 +20,11 @@
static float getCaptureFillValue(CaptureFill captureFill);
RenderArea(uint32_t reqWidth, uint32_t reqHeight, CaptureFill captureFill,
+ ui::Dataspace reqDataSpace,
ui::Transform::orientation_flags rotation = ui::Transform::ROT_0)
: mReqWidth(reqWidth),
mReqHeight(reqHeight),
+ mReqDataSpace(reqDataSpace),
mCaptureFill(captureFill),
mRotationFlags(rotation) {}
@@ -66,6 +69,9 @@
int getReqWidth() const { return mReqWidth; };
int getReqHeight() const { return mReqHeight; };
+ // Returns the composition data space of the render area.
+ ui::Dataspace getReqDataSpace() const { return mReqDataSpace; }
+
// Returns the fill color of the physical render area. Regions not
// covered by any rendered layer should be filled with this color.
CaptureFill getCaptureFill() const { return mCaptureFill; };
@@ -73,6 +79,7 @@
private:
const uint32_t mReqWidth;
const uint32_t mReqHeight;
+ const ui::Dataspace mReqDataSpace;
const CaptureFill mCaptureFill;
const ui::Transform::orientation_flags mRotationFlags;
};
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index cba9181..172c418 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -25,6 +25,7 @@
#include <algorithm>
#include <log/log.h>
+#include <cutils/properties.h>
#include <utils/String8.h>
#include <utils/Thread.h>
#include <utils/Trace.h>
@@ -520,27 +521,12 @@
void DispSync::setPeriod(nsecs_t period) {
Mutex::Autolock lock(mMutex);
- mPeriodBase = mPeriod = period;
+ mPeriod = period;
mPhase = 0;
mReferenceTime = 0;
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
}
-void DispSync::scalePeriod(HWC2::Device::FrequencyScaler frequencyScaler) {
- Mutex::Autolock lock(mMutex);
-
- // if only 1 of the properties is updated, we will get to this
- // point "attempting" to set the scale to 1 when it is already
- // 1. Check that special case so that we don't do a useless
- // update of the model.
- if ((frequencyScaler.multiplier == 1) &&
- (frequencyScaler.divisor == 1) &&
- (mPeriod == mPeriodBase)) return;
-
- mPeriod = mPeriodBase * frequencyScaler.multiplier / frequencyScaler.divisor;
- mThread->updateModel(mPeriod, mPhase, mReferenceTime);
-}
-
nsecs_t DispSync::getPeriod() {
// lock mutex as mPeriod changes multiple times in updateModelLocked
Mutex::Autolock lock(mMutex);
@@ -565,7 +551,7 @@
// Exclude the min and max from the average
durationSum -= minDuration + maxDuration;
- mPeriodBase = mPeriod = durationSum / (mNumResyncSamples - 3);
+ mPeriod = durationSum / (mNumResyncSamples - 3);
ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod));
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 5b511f4..5d19093 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -24,7 +24,6 @@
#include <utils/Timers.h>
#include <ui/FenceTime.h>
-#include <DisplayHardware/HWC2.h>
#include <memory>
@@ -49,7 +48,6 @@
virtual bool addResyncSample(nsecs_t timestamp) = 0;
virtual void endResync() = 0;
virtual void setPeriod(nsecs_t period) = 0;
- virtual void scalePeriod(HWC2::Device::FrequencyScaler) = 0;
virtual nsecs_t getPeriod() = 0;
virtual void setRefreshSkipCount(int count) = 0;
virtual status_t addEventListener(const char* name, nsecs_t phase, Callback* callback) = 0;
@@ -120,12 +118,6 @@
// turned on. It should NOT be used after that.
void setPeriod(nsecs_t period) override;
- // The scalePeriod method applies the multiplier and divisor to
- // scale the vsync event model's period. The function is added
- // for an experimental test mode and should not be used outside
- // of that purpose.
- void scalePeriod(HWC2::Device::FrequencyScaler frequencyScaler);
-
// The getPeriod method returns the current vsync period.
nsecs_t getPeriod() override;
@@ -188,7 +180,6 @@
// mPeriod is the computed period of the modeled vsync events in
// nanoseconds.
nsecs_t mPeriod;
- nsecs_t mPeriodBase;
// mPhase is the phase offset of the modeled vsync events. It is the
// number of nanoseconds from time 0 to the first vsync event.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1a5a389..c5a4cac 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1905,6 +1905,8 @@
mTimeStats.incrementClientCompositionFrames();
}
+ mTimeStats.setPresentFenceGlobal(presentFenceTime);
+
if (display && getHwComposer().isConnected(display->getId()) &&
display->getPowerMode() == HWC_POWER_MODE_OFF) {
return;
@@ -3980,6 +3982,10 @@
getHwComposer().setPowerMode(type, mode);
}
+ if (display->isPrimary()) {
+ mTimeStats.setPowerMode(mode);
+ }
+
ALOGD("Finished setting power mode %d on display %d", mode, displayId);
}
@@ -4772,9 +4778,9 @@
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1029 are currently use for backdoors. The code
+ // Numbers from 1000 to 1030 are currently use for backdoors. The code
// in onTransact verifies that the user is root, and has access to use SF.
- if (code >= 1000 && code <= 1029) {
+ if (code >= 1000 && code <= 1030) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -4970,11 +4976,9 @@
repaintEverything();
return NO_ERROR;
}
- // TODO(b/111505327): Find out whether the usage of 1024 can switch to 1030,
- // deprecate 1024 if they can.
- case 1024: { // Does device have wide color gamut display?
- reply->writeBool(hasWideColorDisplay);
- return NO_ERROR;
+ // Deprecate, use 1030 to check whether the device is color managed.
+ case 1024: {
+ return NAME_NOT_FOUND;
}
case 1025: { // Set layer tracing
n = data.readInt32();
@@ -5025,54 +5029,6 @@
reply->writeBool(getBE().mHwc->isUsingVrComposer());
return NO_ERROR;
}
- case 1029: {
- // Code 1029 is an experimental feature that allows applications to
- // simulate a high frequency panel by setting a multiplier and divisor
- // on the VSYNC-sf clock. If either the multiplier or divisor are
- // 0, then the code simply return the current multiplier and divisor.
- HWC2::Device::FrequencyScaler frequencyScaler;
- frequencyScaler.multiplier = data.readInt32();
- frequencyScaler.divisor = data.readInt32();
-
- if ((frequencyScaler.multiplier == 0) || (frequencyScaler.divisor == 0)) {
- frequencyScaler = getBE().mHwc->getDisplayFrequencyScaleParameters();
- reply->writeInt32(frequencyScaler.multiplier);
- reply->writeInt32(frequencyScaler.divisor);
- return NO_ERROR;
- }
-
- if ((frequencyScaler.multiplier == 1) && (frequencyScaler.divisor == 1)) {
- if (mUseScheduler) {
- mScheduler->enableHardwareVsync();
- } else {
- enableHardwareVsync();
- }
- } else {
- if (mUseScheduler) {
- mScheduler->disableHardwareVsync(true);
- } else {
- disableHardwareVsync(true);
- }
- }
- mPrimaryDispSync->scalePeriod(frequencyScaler);
- getBE().mHwc->setDisplayFrequencyScaleParameters(frequencyScaler);
-
- ATRACE_INT("PeriodMultiplier", frequencyScaler.multiplier);
- ATRACE_INT("PeriodDivisor", frequencyScaler.divisor);
-
- const hwc2_display_t hwcDisplayId = getBE().mHwc->getActiveConfig(
- DisplayDevice::DISPLAY_PRIMARY)->getDisplayId();
-
- onHotplugReceived(getBE().mComposerSequenceId,
- hwcDisplayId, HWC2::Connection::Disconnected);
- onHotplugReceived(getBE().mComposerSequenceId,
- hwcDisplayId, HWC2::Connection::Connected);
- frequencyScaler = getBE().mHwc->getDisplayFrequencyScaleParameters();
- reply->writeInt32(frequencyScaler.multiplier);
- reply->writeInt32(frequencyScaler.divisor);
-
- return NO_ERROR;
- }
// Is device color managed?
case 1030: {
reply->writeBool(useColorManagement);
@@ -5102,7 +5058,8 @@
};
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& displayToken,
- sp<GraphicBuffer>* outBuffer, Rect sourceCrop,
+ sp<GraphicBuffer>* outBuffer, const Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
uint32_t reqWidth, uint32_t reqHeight,
bool useIdentityTransform,
ISurfaceComposer::Rotation rotation) {
@@ -5131,23 +5088,27 @@
}
}
- DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, renderAreaRotation);
+ DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace,
+ renderAreaRotation);
auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
display, std::placeholders::_1);
- return captureScreenCommon(renderArea, traverseLayers, outBuffer, useIdentityTransform);
+ return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat,
+ useIdentityTransform);
}
status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
- sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+ sp<GraphicBuffer>* outBuffer, const Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
float frameScale, bool childrenOnly) {
ATRACE_CALL();
class LayerRenderArea : public RenderArea {
public:
LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
- int32_t reqWidth, int32_t reqHeight, bool childrenOnly)
- : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR),
+ int32_t reqWidth, int32_t reqHeight, Dataspace reqDataSpace,
+ bool childrenOnly)
+ : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR, reqDataSpace),
mLayer(layer),
mCrop(crop),
mNeedsFiltering(false),
@@ -5254,7 +5215,7 @@
reqHeight = 1;
}
- LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, childrenOnly);
+ LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, reqDataspace, childrenOnly);
auto traverseLayers = [parent, childrenOnly](const LayerVector::Visitor& visitor) {
parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
@@ -5266,19 +5227,22 @@
visitor(layer);
});
};
- return captureScreenCommon(renderArea, traverseLayers, outBuffer, false);
+ return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, false);
}
status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
sp<GraphicBuffer>* outBuffer,
+ const ui::PixelFormat reqPixelFormat,
bool useIdentityTransform) {
ATRACE_CALL();
+ // TODO(b/116112787) Make buffer usage a parameter.
const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
*outBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
- HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot");
+ static_cast<android_pixel_format>(reqPixelFormat), 1, usage,
+ "screenshot");
// This mutex protects syncFd and captureResult for communication of the return values from the
// main thread back to this Binder thread
@@ -5354,8 +5318,7 @@
const auto sourceCrop = renderArea.getSourceCrop();
const auto rotation = renderArea.getRotationFlags();
- // assume ColorMode::SRGB / RenderIntent::COLORIMETRIC
- engine.setOutputDataSpace(Dataspace::SRGB);
+ engine.setOutputDataSpace(renderArea.getReqDataSpace());
engine.setDisplayMaxLuminance(DisplayDevice::sDefaultMaxLumiance);
// make sure to clear all GL error flags
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 658f04e..8045246 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -433,10 +433,14 @@
virtual sp<IDisplayEventConnection> createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp);
virtual status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- bool useIdentityTransform, ISurfaceComposer::Rotation rotation);
+ const ui::Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+ ISurfaceComposer::Rotation rotation);
virtual status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
- const Rect& sourceCrop, float frameScale, bool childrenOnly);
+ const ui::Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
+ float frameScale, bool childrenOnly);
virtual status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
virtual status_t getDisplayConfigs(const sp<IBinder>& displayToken,
Vector<DisplayInfo>* configs);
@@ -586,7 +590,7 @@
void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
bool useIdentityTransform);
status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
- sp<GraphicBuffer>* outBuffer,
+ sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat,
bool useIdentityTransform);
status_t captureScreenImplLocked(const RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 2e1231b..43fa262 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -24,6 +24,7 @@
#include <log/log.h>
#include <utils/String8.h>
+#include <utils/Timers.h>
#include <utils/Trace.h>
#include <algorithm>
@@ -82,7 +83,7 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- timeStats.totalFrames++;
+ mTimeStats.totalFrames++;
}
void TimeStats::incrementMissedFrames() {
@@ -91,7 +92,7 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- timeStats.missedFrames++;
+ mTimeStats.missedFrames++;
}
void TimeStats::incrementClientCompositionFrames() {
@@ -100,12 +101,12 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- timeStats.clientCompositionFrames++;
+ mTimeStats.clientCompositionFrames++;
}
-bool TimeStats::recordReadyLocked(const std::string& layerName, TimeRecord* timeRecord) {
+bool TimeStats::recordReadyLocked(int32_t layerID, TimeRecord* timeRecord) {
if (!timeRecord->ready) {
- ALOGV("[%s]-[%" PRIu64 "]-presentFence is still not received", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-presentFence is still not received", layerID,
timeRecord->frameTime.frameNumber);
return false;
}
@@ -118,7 +119,7 @@
timeRecord->frameTime.acquireTime = timeRecord->acquireFence->getSignalTime();
timeRecord->acquireFence = nullptr;
} else {
- ALOGV("[%s]-[%" PRIu64 "]-acquireFence signal time is invalid", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-acquireFence signal time is invalid", layerID,
timeRecord->frameTime.frameNumber);
}
}
@@ -131,7 +132,7 @@
timeRecord->frameTime.presentTime = timeRecord->presentFence->getSignalTime();
timeRecord->presentFence = nullptr;
} else {
- ALOGV("[%s]-[%" PRIu64 "]-presentFence signal time invalid", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-presentFence signal time invalid", layerID,
timeRecord->frameTime.frameNumber);
}
}
@@ -161,60 +162,61 @@
return "";
}
-void TimeStats::flushAvailableRecordsToStatsLocked(const std::string& layerName) {
+void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerID) {
ATRACE_CALL();
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
while (!timeRecords.empty()) {
- if (!recordReadyLocked(layerName, &timeRecords[0])) break;
- ALOGV("[%s]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerName.c_str(),
+ if (!recordReadyLocked(layerID, &timeRecords[0])) break;
+ ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID,
timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
if (prevTimeRecord.ready) {
- if (!timeStats.stats.count(layerName)) {
- timeStats.stats[layerName].layerName = layerName;
- timeStats.stats[layerName].packageName = getPackageName(layerName);
+ const std::string& layerName = layerRecord.layerName;
+ if (!mTimeStats.stats.count(layerName)) {
+ mTimeStats.stats[layerName].layerName = layerName;
+ mTimeStats.stats[layerName].packageName = getPackageName(layerName);
}
- TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timeStats.stats[layerName];
+ TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[layerName];
timeStatsLayer.totalFrames++;
timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
layerRecord.droppedFrames = 0;
const int32_t postToAcquireMs = msBetween(timeRecords[0].frameTime.postTime,
timeRecords[0].frameTime.acquireTime);
- ALOGV("[%s]-[%" PRIu64 "]-post2acquire[%d]", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-post2acquire[%d]", layerID,
timeRecords[0].frameTime.frameNumber, postToAcquireMs);
timeStatsLayer.deltas["post2acquire"].insert(postToAcquireMs);
const int32_t postToPresentMs = msBetween(timeRecords[0].frameTime.postTime,
timeRecords[0].frameTime.presentTime);
- ALOGV("[%s]-[%" PRIu64 "]-post2present[%d]", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-post2present[%d]", layerID,
timeRecords[0].frameTime.frameNumber, postToPresentMs);
timeStatsLayer.deltas["post2present"].insert(postToPresentMs);
const int32_t acquireToPresentMs = msBetween(timeRecords[0].frameTime.acquireTime,
timeRecords[0].frameTime.presentTime);
- ALOGV("[%s]-[%" PRIu64 "]-acquire2present[%d]", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-acquire2present[%d]", layerID,
timeRecords[0].frameTime.frameNumber, acquireToPresentMs);
timeStatsLayer.deltas["acquire2present"].insert(acquireToPresentMs);
const int32_t latchToPresentMs = msBetween(timeRecords[0].frameTime.latchTime,
timeRecords[0].frameTime.presentTime);
- ALOGV("[%s]-[%" PRIu64 "]-latch2present[%d]", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-latch2present[%d]", layerID,
timeRecords[0].frameTime.frameNumber, latchToPresentMs);
timeStatsLayer.deltas["latch2present"].insert(latchToPresentMs);
const int32_t desiredToPresentMs = msBetween(timeRecords[0].frameTime.desiredTime,
timeRecords[0].frameTime.presentTime);
- ALOGV("[%s]-[%" PRIu64 "]-desired2present[%d]", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-desired2present[%d]", layerID,
timeRecords[0].frameTime.frameNumber, desiredToPresentMs);
timeStatsLayer.deltas["desired2present"].insert(desiredToPresentMs);
const int32_t presentToPresentMs = msBetween(prevTimeRecord.frameTime.presentTime,
timeRecords[0].frameTime.presentTime);
- ALOGV("[%s]-[%" PRIu64 "]-present2present[%d]", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-present2present[%d]", layerID,
timeRecords[0].frameTime.frameNumber, presentToPresentMs);
timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
}
@@ -239,23 +241,33 @@
return std::regex_match(layerName.begin(), layerName.end(), layerNameRegex);
}
-void TimeStats::setPostTime(const std::string& layerName, uint64_t frameNumber, nsecs_t postTime) {
+void TimeStats::setLayerName(int32_t layerID, const std::string& layerName) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-PostTime[%" PRId64 "]", layerName.c_str(), frameNumber, postTime);
+ ALOGV("[%d]-[%s]", layerID, layerName.c_str());
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName) && !layerNameIsValid(layerName)) {
- return;
+ if (!mTimeStatsTracker.count(layerID) && layerNameIsValid(layerName)) {
+ mTimeStatsTracker[layerID].layerName = layerName;
}
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+}
+
+void TimeStats::setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime) {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+ ALOGV("[%d]-[%" PRIu64 "]-PostTime[%" PRId64 "]", layerID, frameNumber, postTime);
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
if (layerRecord.timeRecords.size() == MAX_NUM_TIME_RECORDS) {
- ALOGV("[%s]-timeRecords is already at its maximum size[%zu]", layerName.c_str(),
- MAX_NUM_TIME_RECORDS);
- // TODO(zzyiwei): if this happens, there must be a present fence missing
- // or waitData is not in the correct position. Need to think out a
- // reasonable way to recover from this state.
+ ALOGE("[%d]-[%s]-timeRecords is already at its maximum size[%zu]. Please file a bug.",
+ layerID, layerRecord.layerName.c_str(), MAX_NUM_TIME_RECORDS);
+ layerRecord.timeRecords.clear();
+ layerRecord.prevTimeRecord.ready = false;
+ layerRecord.waitData = -1;
return;
}
// For most media content, the acquireFence is invalid because the buffer is
@@ -275,84 +287,77 @@
layerRecord.waitData = layerRecord.timeRecords.size() - 1;
}
-void TimeStats::setLatchTime(const std::string& layerName, uint64_t frameNumber,
- nsecs_t latchTime) {
+void TimeStats::setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-LatchTime[%" PRId64 "]", layerName.c_str(), frameNumber, latchTime);
+ ALOGV("[%d]-[%" PRIu64 "]-LatchTime[%" PRId64 "]", layerID, frameNumber, latchTime);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.frameTime.latchTime = latchTime;
}
}
-void TimeStats::setDesiredTime(const std::string& layerName, uint64_t frameNumber,
- nsecs_t desiredTime) {
+void TimeStats::setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-DesiredTime[%" PRId64 "]", layerName.c_str(), frameNumber,
- desiredTime);
+ ALOGV("[%d]-[%" PRIu64 "]-DesiredTime[%" PRId64 "]", layerID, frameNumber, desiredTime);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.frameTime.desiredTime = desiredTime;
}
}
-void TimeStats::setAcquireTime(const std::string& layerName, uint64_t frameNumber,
- nsecs_t acquireTime) {
+void TimeStats::setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-AcquireTime[%" PRId64 "]", layerName.c_str(), frameNumber,
- acquireTime);
+ ALOGV("[%d]-[%" PRIu64 "]-AcquireTime[%" PRId64 "]", layerID, frameNumber, acquireTime);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.frameTime.acquireTime = acquireTime;
}
}
-void TimeStats::setAcquireFence(const std::string& layerName, uint64_t frameNumber,
+void TimeStats::setAcquireFence(int32_t layerID, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& acquireFence) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-AcquireFenceTime[%" PRId64 "]", layerName.c_str(), frameNumber,
+ ALOGV("[%d]-[%" PRIu64 "]-AcquireFenceTime[%" PRId64 "]", layerID, frameNumber,
acquireFence->getSignalTime());
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.acquireFence = acquireFence;
}
}
-void TimeStats::setPresentTime(const std::string& layerName, uint64_t frameNumber,
- nsecs_t presentTime) {
+void TimeStats::setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-PresentTime[%" PRId64 "]", layerName.c_str(), frameNumber,
- presentTime);
+ ALOGV("[%d]-[%" PRIu64 "]-PresentTime[%" PRId64 "]", layerID, frameNumber, presentTime);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.frameTime.presentTime = presentTime;
@@ -360,20 +365,20 @@
layerRecord.waitData++;
}
- flushAvailableRecordsToStatsLocked(layerName);
+ flushAvailableRecordsToStatsLocked(layerID);
}
-void TimeStats::setPresentFence(const std::string& layerName, uint64_t frameNumber,
+void TimeStats::setPresentFence(int32_t layerID, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& presentFence) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-PresentFenceTime[%" PRId64 "]", layerName.c_str(), frameNumber,
+ ALOGV("[%d]-[%" PRIu64 "]-PresentFenceTime[%" PRId64 "]", layerID, frameNumber,
presentFence->getSignalTime());
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.presentFence = presentFence;
@@ -381,45 +386,57 @@
layerRecord.waitData++;
}
- flushAvailableRecordsToStatsLocked(layerName);
+ flushAvailableRecordsToStatsLocked(layerID);
}
-void TimeStats::onDisconnect(const std::string& layerName) {
+void TimeStats::onDisconnect(int32_t layerID) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-onDisconnect", layerName.c_str());
+ ALOGV("[%d]-onDisconnect", layerID);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- flushAvailableRecordsToStatsLocked(layerName);
- timeStatsTracker.erase(layerName);
+ if (!mTimeStatsTracker.count(layerID)) return;
+ flushAvailableRecordsToStatsLocked(layerID);
+ mTimeStatsTracker.erase(layerID);
}
-void TimeStats::clearLayerRecord(const std::string& layerName) {
+void TimeStats::onDestroy(int32_t layerID) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-clearLayerRecord", layerName.c_str());
+ ALOGV("[%d]-onDestroy", layerID);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ flushAvailableRecordsToStatsLocked(layerID);
+ mTimeStatsTracker.erase(layerID);
+}
+
+void TimeStats::clearLayerRecord(int32_t layerID) {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+ ALOGV("[%d]-clearLayerRecord", layerID);
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
layerRecord.timeRecords.clear();
layerRecord.prevTimeRecord.ready = false;
layerRecord.waitData = -1;
layerRecord.droppedFrames = 0;
}
-void TimeStats::removeTimeRecord(const std::string& layerName, uint64_t frameNumber) {
+void TimeStats::removeTimeRecord(int32_t layerID, uint64_t frameNumber) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-removeTimeRecord", layerName.c_str(), frameNumber);
+ ALOGV("[%d]-[%" PRIu64 "]-removeTimeRecord", layerID, frameNumber);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
size_t removeAt = 0;
for (const TimeRecord& record : layerRecord.timeRecords) {
if (record.frameTime.frameNumber == frameNumber) break;
@@ -433,6 +450,87 @@
layerRecord.droppedFrames++;
}
+void TimeStats::flushPowerTimeLocked() {
+ nsecs_t curTime = systemTime();
+ // elapsedTime is in milliseconds.
+ int64_t elapsedTime = (curTime - mPowerTime.prevTime) / 1000000;
+
+ switch (mPowerTime.powerMode) {
+ case HWC_POWER_MODE_NORMAL:
+ mTimeStats.displayOnTime += elapsedTime;
+ break;
+ case HWC_POWER_MODE_OFF:
+ case HWC_POWER_MODE_DOZE:
+ case HWC_POWER_MODE_DOZE_SUSPEND:
+ default:
+ break;
+ }
+
+ mPowerTime.prevTime = curTime;
+}
+
+void TimeStats::setPowerMode(int32_t powerMode) {
+ if (!mEnabled.load()) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mPowerTime.powerMode = powerMode;
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (powerMode == mPowerTime.powerMode) return;
+
+ flushPowerTimeLocked();
+ mPowerTime.powerMode = powerMode;
+}
+
+void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
+ ATRACE_CALL();
+
+ while (!mGlobalRecord.presentFences.empty()) {
+ const nsecs_t curPresentTime = mGlobalRecord.presentFences.front()->getSignalTime();
+ if (curPresentTime == Fence::SIGNAL_TIME_PENDING) break;
+
+ if (curPresentTime == Fence::SIGNAL_TIME_INVALID) {
+ ALOGE("GlobalPresentFence is invalid!");
+ mGlobalRecord.prevPresentTime = 0;
+ mGlobalRecord.presentFences.pop_front();
+ continue;
+ }
+
+ ALOGV("GlobalPresentFenceTime[%" PRId64 "]",
+ mGlobalRecord.presentFences.front()->getSignalTime());
+
+ const int32_t presentToPresentMs = msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
+ ALOGV("Global present2present[%d]", presentToPresentMs);
+
+ mTimeStats.presentToPresent.insert(presentToPresentMs);
+ mGlobalRecord.prevPresentTime = curPresentTime;
+ mGlobalRecord.presentFences.pop_front();
+ }
+}
+
+void TimeStats::setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (presentFence == nullptr) {
+ mGlobalRecord.prevPresentTime = 0;
+ return;
+ }
+
+ if (mGlobalRecord.presentFences.size() == MAX_NUM_TIME_RECORDS) {
+ // The front presentFence must be trapped in pending status in this
+ // case. Try dequeuing the front one to recover.
+ ALOGE("GlobalPresentFences is already at its maximum size[%zu]", MAX_NUM_TIME_RECORDS);
+ mGlobalRecord.prevPresentTime = 0;
+ mGlobalRecord.presentFences.pop_front();
+ }
+
+ mGlobalRecord.presentFences.emplace_back(presentFence);
+ flushAvailableGlobalRecordsToStatsLocked();
+}
+
void TimeStats::enable() {
if (mEnabled.load()) return;
@@ -441,7 +539,8 @@
std::lock_guard<std::mutex> lock(mMutex);
ALOGD("Enabled");
mEnabled.store(true);
- timeStats.statsStart = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
+ mPowerTime.prevTime = systemTime();
}
void TimeStats::disable() {
@@ -452,7 +551,7 @@
std::lock_guard<std::mutex> lock(mMutex);
ALOGD("Disabled");
mEnabled.store(false);
- timeStats.statsEnd = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
}
void TimeStats::clear() {
@@ -460,12 +559,15 @@
std::lock_guard<std::mutex> lock(mMutex);
ALOGD("Cleared");
- timeStats.stats.clear();
- timeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
- timeStats.statsEnd = 0;
- timeStats.totalFrames = 0;
- timeStats.missedFrames = 0;
- timeStats.clientCompositionFrames = 0;
+ mTimeStats.stats.clear();
+ mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
+ mTimeStats.statsEnd = 0;
+ mTimeStats.totalFrames = 0;
+ mTimeStats.missedFrames = 0;
+ mTimeStats.clientCompositionFrames = 0;
+ mTimeStats.displayOnTime = 0;
+ mTimeStats.presentToPresent.hist.clear();
+ mPowerTime.prevTime = systemTime();
}
bool TimeStats::isEnabled() {
@@ -476,19 +578,21 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- if (timeStats.statsStart == 0) {
+ if (mTimeStats.statsStart == 0) {
return;
}
- timeStats.statsEnd = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+
+ flushPowerTimeLocked();
if (asProto) {
ALOGD("Dumping TimeStats as proto");
- SFTimeStatsGlobalProto timeStatsProto = timeStats.toProto(maxLayers);
+ SFTimeStatsGlobalProto timeStatsProto = mTimeStats.toProto(maxLayers);
result.append(timeStatsProto.SerializeAsString().c_str(), timeStatsProto.ByteSize());
} else {
ALOGD("Dumping TimeStats as text");
- result.append(timeStats.toString(maxLayers).c_str());
+ result.append(mTimeStats.toString(maxLayers).c_str());
result.append("\n");
}
}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 5ab3934..d1e554c 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -19,6 +19,8 @@
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
+#include <hardware/hwcomposer_defs.h>
+
#include <ui/FenceTime.h>
#include <utils/String16.h>
@@ -57,6 +59,7 @@
};
struct LayerRecord {
+ std::string layerName;
// This is the index in timeRecords, at which the timestamps for that
// specific frame are still not fully received. This is not waiting for
// fences to signal, but rather waiting to receive those fences/timestamps.
@@ -66,6 +69,16 @@
std::deque<TimeRecord> timeRecords;
};
+ struct PowerTime {
+ int32_t powerMode = HWC_POWER_MODE_OFF;
+ nsecs_t prevTime = 0;
+ };
+
+ struct GlobalRecord {
+ nsecs_t prevPresentTime = 0;
+ std::deque<std::shared_ptr<FenceTime>> presentFences;
+ };
+
public:
static TimeStats& getInstance();
void parseArgs(bool asProto, const Vector<String16>& args, size_t& index, String8& result);
@@ -73,27 +86,35 @@
void incrementMissedFrames();
void incrementClientCompositionFrames();
- void setPostTime(const std::string& layerName, uint64_t frameNumber, nsecs_t postTime);
- void setLatchTime(const std::string& layerName, uint64_t frameNumber, nsecs_t latchTime);
- void setDesiredTime(const std::string& layerName, uint64_t frameNumber, nsecs_t desiredTime);
- void setAcquireTime(const std::string& layerName, uint64_t frameNumber, nsecs_t acquireTime);
- void setAcquireFence(const std::string& layerName, uint64_t frameNumber,
+ void setLayerName(int32_t layerID, const std::string& layerName);
+ void setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime);
+ void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime);
+ void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime);
+ void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime);
+ void setAcquireFence(int32_t layerID, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& acquireFence);
- void setPresentTime(const std::string& layerName, uint64_t frameNumber, nsecs_t presentTime);
- void setPresentFence(const std::string& layerName, uint64_t frameNumber,
+ void setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime);
+ void setPresentFence(int32_t layerID, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& presentFence);
// On producer disconnect with BufferQueue.
- void onDisconnect(const std::string& layerName);
+ void onDisconnect(int32_t layerID);
+ // On layer tear down.
+ void onDestroy(int32_t layerID);
// When SF is cleaning up the queue, clear the LayerRecord as well.
- void clearLayerRecord(const std::string& layerName);
+ void clearLayerRecord(int32_t layerID);
// If SF skips or rejects a buffer, remove the corresponding TimeRecord.
- void removeTimeRecord(const std::string& layerName, uint64_t frameNumber);
+ void removeTimeRecord(int32_t layerID, uint64_t frameNumber);
+
+ void setPowerMode(int32_t powerMode);
+ void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence);
private:
TimeStats() = default;
- bool recordReadyLocked(const std::string& layerName, TimeRecord* timeRecord);
- void flushAvailableRecordsToStatsLocked(const std::string& layerName);
+ bool recordReadyLocked(int32_t layerID, TimeRecord* timeRecord);
+ void flushAvailableRecordsToStatsLocked(int32_t layerID);
+ void flushPowerTimeLocked();
+ void flushAvailableGlobalRecordsToStatsLocked();
void enable();
void disable();
@@ -103,8 +124,11 @@
std::atomic<bool> mEnabled = false;
std::mutex mMutex;
- TimeStatsHelper::TimeStatsGlobal timeStats;
- std::unordered_map<std::string, LayerRecord> timeStatsTracker;
+ TimeStatsHelper::TimeStatsGlobal mTimeStats;
+ // Hashmap for LayerRecord with layerID as the hash key
+ std::unordered_map<int32_t, LayerRecord> mTimeStatsTracker;
+ PowerTime mPowerTime;
+ GlobalRecord mGlobalRecord;
};
} // namespace android
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index b7b2778..c701224 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -49,7 +49,7 @@
float TimeStatsHelper::Histogram::averageTime() const {
int64_t ret = 0;
int64_t count = 0;
- for (auto& ele : hist) {
+ for (const auto& ele : hist) {
count += ele.second;
ret += ele.first * ele.second;
}
@@ -73,13 +73,13 @@
StringAppendF(&result, "packageName = %s\n", packageName.c_str());
StringAppendF(&result, "totalFrames = %d\n", totalFrames);
StringAppendF(&result, "droppedFrames = %d\n", droppedFrames);
- auto iter = deltas.find("present2present");
+ const auto iter = deltas.find("present2present");
if (iter != deltas.end()) {
StringAppendF(&result, "averageFPS = %.3f\n", 1000.0 / iter->second.averageTime());
}
- for (auto& ele : deltas) {
+ for (const auto& ele : deltas) {
StringAppendF(&result, "%s histogram is as below:\n", ele.first.c_str());
- StringAppendF(&result, "%s", ele.second.toString().c_str());
+ result.append(ele.second.toString());
}
return result;
@@ -92,9 +92,12 @@
StringAppendF(&result, "totalFrames = %d\n", totalFrames);
StringAppendF(&result, "missedFrames = %d\n", missedFrames);
StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
+ StringAppendF(&result, "displayOnTime = %lld ms\n", static_cast<long long int>(displayOnTime));
+ StringAppendF(&result, "presentToPresent histogram is as below:\n");
+ result.append(presentToPresent.toString());
const auto dumpStats = generateDumpStats(maxLayers);
- for (auto& ele : dumpStats) {
- StringAppendF(&result, "%s", ele->toString().c_str());
+ for (const auto& ele : dumpStats) {
+ result.append(ele->toString());
}
return result;
@@ -106,10 +109,10 @@
layerProto.set_package_name(packageName);
layerProto.set_total_frames(totalFrames);
layerProto.set_dropped_frames(droppedFrames);
- for (auto& ele : deltas) {
+ for (const auto& ele : deltas) {
SFTimeStatsDeltaProto* deltaProto = layerProto.add_deltas();
deltaProto->set_delta_name(ele.first);
- for (auto& histEle : ele.second.hist) {
+ for (const auto& histEle : ele.second.hist) {
SFTimeStatsHistogramBucketProto* histProto = deltaProto->add_histograms();
histProto->set_time_millis(histEle.first);
histProto->set_frame_count(histEle.second);
@@ -126,8 +129,14 @@
globalProto.set_total_frames(totalFrames);
globalProto.set_missed_frames(missedFrames);
globalProto.set_client_composition_frames(clientCompositionFrames);
+ globalProto.set_display_on_time(displayOnTime);
+ for (const auto& histEle : presentToPresent.hist) {
+ SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present();
+ histProto->set_time_millis(histEle.first);
+ histProto->set_frame_count(histEle.second);
+ }
const auto dumpStats = generateDumpStats(maxLayers);
- for (auto& ele : dumpStats) {
+ for (const auto& ele : dumpStats) {
SFTimeStatsLayerProto* layerProto = globalProto.add_stats();
layerProto->CopyFrom(ele->toProto());
}
@@ -137,7 +146,7 @@
std::vector<TimeStatsHelper::TimeStatsLayer const*>
TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional<uint32_t> maxLayers) const {
std::vector<TimeStatsLayer const*> dumpStats;
- for (auto& ele : stats) {
+ for (const auto& ele : stats) {
dumpStats.push_back(&ele.second);
}
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 99c891b..7d0fe79 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -57,6 +57,8 @@
int32_t totalFrames = 0;
int32_t missedFrames = 0;
int32_t clientCompositionFrames = 0;
+ int64_t displayOnTime = 0;
+ Histogram presentToPresent;
std::unordered_map<std::string, TimeStatsLayer> stats;
std::string toString(std::optional<uint32_t> maxLayers) const;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
index b8f38c2..377612a 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
+++ b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
@@ -20,13 +20,12 @@
option optimize_for = LITE_RUNTIME;
-// //depot/google3/java/com/google/android/apps/graphics/stats/proto/
+// //depot/google3/wireless/android/graphics/surfaceflingerstats/proto/
// timestats.proto is based on this proto. Please only make valid protobuf
-// changes to these messages, and keep the other file in sync per Android
-// release. Please also do not include "option optimize_for = LITE_RUNTIME;" at
-// google3 side.
+// changes to these messages, and keep google3 side proto messages in sync if
+// the end to end pipeline needs to be updated.
-// Next tag: 7
+// Next tag: 9
message SFTimeStatsGlobalProto {
// The stats start time in UTC as seconds since January 1, 1970
optional int64 stats_start = 1;
@@ -38,6 +37,10 @@
optional int32 missed_frames = 4;
// Total frames fallback to client composition.
optional int32 client_composition_frames = 5;
+ // Primary display on time in milliseconds.
+ optional int64 display_on_time = 7;
+ // Present to present histogram.
+ repeated SFTimeStatsHistogramBucketProto present_to_present = 8;
// Stats per layer. Apps could have multiple layers.
repeated SFTimeStatsLayerProto stats = 6;
}
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 9e762f0..a73ec6c 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -267,8 +267,9 @@
sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
std::function<status_t()> condition = [=]() {
sp<GraphicBuffer> outBuffer;
- return ScreenshotClient::capture(display, Rect(), 0 /*reqWidth*/, 0 /*reqHeight*/, false,
- ROTATION, &outBuffer);
+ return ScreenshotClient::capture(display, ui::Dataspace::V0_SRGB,
+ ui::PixelFormat::RGBA_8888, Rect(), 0 /*reqWidth*/,
+ 0 /*reqHeight*/, false, ROTATION, &outBuffer);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
@@ -278,8 +279,9 @@
sp<GraphicBuffer> outBuffer;
std::function<status_t()> condition = [=]() {
sp<GraphicBuffer> outBuffer;
- return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(), Rect(), FRAME_SCALE,
- &outBuffer);
+ return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(),
+ ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888,
+ Rect(), FRAME_SCALE, &outBuffer);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 3719a3d..1352df5 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -190,7 +190,8 @@
constexpr bool forSystem = true;
DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH,
- DEFAULT_DISPLAY_HEIGHT, ui::Transform::ROT_0);
+ DEFAULT_DISPLAY_HEIGHT, ui::Dataspace::V0_SRGB,
+ ui::Transform::ROT_0);
auto traverseLayers = [this](const LayerVector::Visitor& visitor) {
return mFlinger.traverseLayersInDisplay(mDisplay, visitor);
@@ -288,7 +289,7 @@
EXPECT_CALL(*test->mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd())));
EXPECT_CALL(*test->mRenderEngine, finish()).WillOnce(Return(true));
- EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::SRGB)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(_)).Times(1);
EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
.Times(1);
// This expectation retires on saturation as setViewportAndProjection is
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
index 495b3f2..34e71cb 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -35,7 +35,6 @@
MOCK_METHOD1(addResyncSample, bool(nsecs_t));
MOCK_METHOD0(endResync, void());
MOCK_METHOD1(setPeriod, void(nsecs_t));
- MOCK_METHOD1(scalePeriod, void(HWC2::Device::FrequencyScaler));
MOCK_METHOD0(getPeriod, nsecs_t());
MOCK_METHOD1(setRefreshSkipCount, void(int));
MOCK_METHOD3(addEventListener, status_t(const char*, nsecs_t, Callback*));
diff --git a/services/vr/bufferhubd/IBufferHub.cpp b/services/vr/bufferhubd/IBufferHub.cpp
index 9d5b91a..2f39e41 100644
--- a/services/vr/bufferhubd/IBufferHub.cpp
+++ b/services/vr/bufferhubd/IBufferHub.cpp
@@ -4,14 +4,69 @@
namespace android {
namespace dvr {
+class BpBufferHub : public BpInterface<IBufferHub> {
+ public:
+ explicit BpBufferHub(const sp<IBinder>& impl)
+ : BpInterface<IBufferHub>(impl) {}
+
+ 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;
+};
+
IMPLEMENT_META_INTERFACE(BufferHub, "android.dvr.IBufferHub");
+// Transaction code
+enum {
+ CREATE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+sp<IBufferClient> BpBufferHub::createBuffer(uint32_t width, uint32_t height,
+ uint32_t layer_count,
+ uint32_t format, uint64_t usage,
+ uint64_t user_metadata_size) {
+ Parcel data, reply;
+ status_t ret = NO_ERROR;
+ ret |= data.writeInterfaceToken(IBufferHub::getInterfaceDescriptor());
+ ret |= data.writeUint32(width);
+ ret |= data.writeUint32(height);
+ ret |= data.writeUint32(layer_count);
+ ret |= data.writeUint32(format);
+ ret |= data.writeUint64(usage);
+ ret |= data.writeUint64(user_metadata_size);
+
+ if (ret != NO_ERROR) {
+ ALOGE("BpBufferHub::createBuffer: failed to write into parcel");
+ return nullptr;
+ }
+
+ ret = remote()->transact(CREATE_BUFFER, data, &reply);
+ if (ret == NO_ERROR) {
+ return interface_cast<IBufferClient>(reply.readStrongBinder());
+ } else {
+ ALOGE("BpBufferHub::createBuffer: failed to transact; errno=%d", ret);
+ return nullptr;
+ }
+}
+
status_t BnBufferHub::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
switch (code) {
+ case CREATE_BUFFER: {
+ CHECK_INTERFACE(IBufferHub, data, reply);
+ uint32_t width = data.readUint32();
+ uint32_t height = data.readUint32();
+ uint32_t layer_count = data.readUint32();
+ uint32_t format = data.readUint32();
+ uint64_t usage = data.readUint64();
+ uint64_t user_metadata_size = data.readUint64();
+ sp<IBufferClient> ret = createBuffer(width, height, layer_count, format,
+ usage, user_metadata_size);
+ return reply->writeStrongBinder(IInterface::asBinder(ret));
+ } break;
default:
- // Should not reach
- ALOGE("onTransact(): unknown code %u received!", code);
+ // Should not reach except binder defined transactions such as dumpsys
return BBinder::onTransact(code, data, reply, flags);
}
}
diff --git a/services/vr/bufferhubd/buffer_hub_binder.cpp b/services/vr/bufferhubd/buffer_hub_binder.cpp
index de82c09..f8a9758 100644
--- a/services/vr/bufferhubd/buffer_hub_binder.cpp
+++ b/services/vr/bufferhubd/buffer_hub_binder.cpp
@@ -5,6 +5,7 @@
#include <binder/ProcessState.h>
#include <log/log.h>
#include <private/dvr/buffer_hub_binder.h>
+#include <private/dvr/buffer_node.h>
namespace android {
namespace dvr {
@@ -45,8 +46,14 @@
"Input arguments are ignored.\n");
}
- // TODO(b/116526156): output real data in this class once we have it
+ fprintf(out, "Binder service:\n");
+ // Active buffers
+ fprintf(out, "Active BufferClients: %zu\n", client_list_.size());
+ // TODO(b/117790952): print buffer information after BufferNode has it
+ // TODO(b/116526156): print more information once we have them
+
if (pdx_service_) {
+ fprintf(out, "\nPDX service:\n");
// BufferHubService::Dumpstate(size_t) is not actually using the param
// So just using 0 as the length
fprintf(out, "%s", pdx_service_->DumpState(0).c_str());
@@ -58,23 +65,17 @@
return NO_ERROR;
}
-sp<IBufferHub> BufferHubBinderService::getServiceProxy() {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> service = sm->checkService(String16(getServiceName()));
+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);
- if (service == nullptr) {
- ALOGE("getServiceProxy(): %s binder service not found!", getServiceName());
- return nullptr;
- }
+ sp<BufferClient> client = new BufferClient(node);
+ // Add it to list for bookkeeping and dumpsys.
+ client_list_.push_back(client);
- sp<IBufferHub> ret = interface_cast<IBufferHub>(service);
- if (ret == nullptr) {
- ALOGE("getServiceProxy(): %s binder service type casting error!",
- getServiceName());
- return nullptr;
- }
-
- return ret;
+ return client;
}
} // namespace dvr
diff --git a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
index 266ae88..bd5f9cf 100644
--- a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
+++ b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
@@ -3,6 +3,7 @@
#include <binder/IInterface.h>
#include <binder/Parcel.h>
+#include <private/dvr/IBufferClient.h>
namespace android {
namespace dvr {
@@ -10,6 +11,12 @@
class IBufferHub : public IInterface {
public:
DECLARE_META_INTERFACE(BufferHub);
+
+ static const char* getServiceName() { return "bufferhubd"; }
+ virtual sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
+ uint32_t layer_count, uint32_t format,
+ uint64_t usage,
+ uint64_t user_metadata_size) = 0;
};
class BnBufferHub : public BnInterface<IBufferHub> {
@@ -18,13 +25,7 @@
uint32_t flags = 0);
};
-class BpBufferHub : public BpInterface<IBufferHub> {
- public:
- explicit BpBufferHub(const sp<IBinder>& impl)
- : BpInterface<IBufferHub>(impl) {}
-};
-
} // namespace dvr
} // namespace android
-#endif
\ No newline at end of file
+#endif // ANDROID_DVR_IBUFFERHUB_H
\ No newline at end of file
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_client.h b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
new file mode 100644
index 0000000..20d51ee
--- /dev/null
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
@@ -0,0 +1,29 @@
+#ifndef ANDROID_DVR_BUFFERCLIENT_H
+#define ANDROID_DVR_BUFFERCLIENT_H
+
+#include <private/dvr/IBufferClient.h>
+#include <private/dvr/buffer_node.h>
+
+namespace android {
+namespace dvr {
+
+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)){};
+
+ // Binder IPC functions
+ bool isValid() override {
+ return buffer_node_ ? buffer_node_->IsValid() : false;
+ };
+
+ private:
+ std::shared_ptr<BufferNode> buffer_node_;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_IBUFFERCLIENT_H
\ No newline at end of file
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 e266ff8..9064d87 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
@@ -1,8 +1,11 @@
#ifndef ANDROID_DVR_BUFFER_HUB_BINDER_H
#define ANDROID_DVR_BUFFER_HUB_BINDER_H
+#include <vector>
+
#include <binder/BinderService.h>
#include <private/dvr/IBufferHub.h>
+#include <private/dvr/buffer_client.h>
#include <private/dvr/buffer_hub.h>
namespace android {
@@ -12,16 +15,20 @@
public BnBufferHub {
public:
static status_t start(const std::shared_ptr<BufferHubService>& pdx_service);
- static const char* getServiceName() { return "bufferhubd"; }
// Dump bufferhub related information to given fd (usually stdout)
// usage: adb shell dumpsys bufferhubd
virtual status_t dump(int fd, const Vector<String16>& args) override;
- // Helper function to get the BpReference to this service
- static sp<IBufferHub> getServiceProxy();
+ // 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;
private:
std::shared_ptr<BufferHubService> pdx_service_;
+
+ std::vector<sp<BufferClient>> client_list_;
};
} // namespace dvr
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 587e6db..7fa2226 100644
--- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
@@ -1,23 +1,41 @@
+#include <binder/IServiceManager.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <private/dvr/buffer_hub_binder.h>
+#include <private/dvr/IBufferClient.h>
+#include <private/dvr/IBufferHub.h>
+#include <ui/PixelFormat.h>
namespace android {
namespace dvr {
namespace {
-using testing::Ne;
+using testing::NotNull;
+
+const int kWidth = 640;
+const int kHeight = 480;
+const int kLayerCount = 1;
+const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+const int kUsage = 0;
+const size_t kUserMetadataSize = 0;
class BufferHubBinderServiceTest : public ::testing::Test {
- // Add setup and teardown if necessary
+ protected:
+ void SetUp() override {
+ status_t ret = getService<IBufferHub>(
+ String16(IBufferHub::getServiceName()), &service);
+ ASSERT_EQ(ret, OK);
+ ASSERT_THAT(service, NotNull());
+ }
+
+ sp<IBufferHub> service;
};
-TEST_F(BufferHubBinderServiceTest, TestInitialize) {
- // Create a new service will kill the current one.
- // So just check if Binder service is running
- sp<IBufferHub> service = BufferHubBinderService::getServiceProxy();
- EXPECT_THAT(service, Ne(nullptr));
+TEST_F(BufferHubBinderServiceTest, TestCreateBuffer) {
+ sp<IBufferClient> bufferClient = service->createBuffer(
+ kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+ ASSERT_THAT(bufferClient, NotNull());
+ EXPECT_TRUE(bufferClient->isValid());
}
} // namespace