Merge "Move basic events into the sched category in atrace." into qt-dev
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 2cc1b32..671c788 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2697,7 +2697,15 @@
MYLOGI(
"Did not receive user consent yet."
" Will not copy the bugreport artifacts to caller.\n");
- // TODO(b/111441001): cancel outstanding requests
+ const String16 incidentcompanion("incidentcompanion");
+ sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
+ if (ics != nullptr) {
+ MYLOGD("Canceling user consent request via incidentcompanion service\n");
+ android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
+ consent_callback_.get());
+ } else {
+ MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
+ }
}
}
diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp
index 2f4dbee..aba4967 100644
--- a/libs/binder/IAppOpsCallback.cpp
+++ b/libs/binder/IAppOpsCallback.cpp
@@ -57,7 +57,8 @@
case OP_CHANGED_TRANSACTION: {
CHECK_INTERFACE(IAppOpsCallback, data, reply);
int32_t op = data.readInt32();
- String16 packageName = data.readString16();
+ String16 packageName;
+ (void)data.readString16(&packageName);
opChanged(op, packageName);
reply->writeNoException();
return NO_ERROR;
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index 70ed80d..90980b8 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -74,4 +74,11 @@
* LOCATION_PRODUCT: getApplicationInfo(packageName).isProduct()
*/
int getLocationFlags(in @utf8InCpp String packageName);
+
+ /**
+ * Returns the target SDK version for the given package.
+ * Unknown packages will cause the call to fail. The caller must check the
+ * returned Status before using the result of this function.
+ */
+ int getTargetSdkVersionForPackage(in String packageName);
}
diff --git a/libs/graphicsenv/GpuStatsInfo.cpp b/libs/graphicsenv/GpuStatsInfo.cpp
index 0fa0d9e..cbf6e50 100644
--- a/libs/graphicsenv/GpuStatsInfo.cpp
+++ b/libs/graphicsenv/GpuStatsInfo.cpp
@@ -34,6 +34,7 @@
if ((status = parcel->writeInt32(glLoadingFailureCount)) != OK) return status;
if ((status = parcel->writeInt32(vkLoadingCount)) != OK) return status;
if ((status = parcel->writeInt32(vkLoadingFailureCount)) != OK) return status;
+ if ((status = parcel->writeInt32(vulkanVersion)) != OK) return status;
return OK;
}
@@ -47,6 +48,7 @@
if ((status = parcel->readInt32(&glLoadingFailureCount)) != OK) return status;
if ((status = parcel->readInt32(&vkLoadingCount)) != OK) return status;
if ((status = parcel->readInt32(&vkLoadingFailureCount)) != OK) return status;
+ if ((status = parcel->readInt32(&vulkanVersion)) != OK) return status;
return OK;
}
@@ -60,6 +62,7 @@
StringAppendF(&result, "glLoadingFailureCount = %d\n", glLoadingFailureCount);
StringAppendF(&result, "vkLoadingCount = %d\n", vkLoadingCount);
StringAppendF(&result, "vkLoadingFailureCount = %d\n", vkLoadingFailureCount);
+ StringAppendF(&result, "vulkanVersion = %d\n", vulkanVersion);
return result;
}
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 13c0d87..8728f03 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -162,7 +162,8 @@
void GraphicsEnv::setGpuStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
- int64_t driverBuildTime, const std::string& appPackageName) {
+ int64_t driverBuildTime, const std::string& appPackageName,
+ const int vulkanVersion) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mStatsLock);
@@ -171,15 +172,17 @@
"\tdriverVersionName[%s]\n"
"\tdriverVersionCode[%" PRIu64 "]\n"
"\tdriverBuildTime[%" PRId64 "]\n"
- "\tappPackageName[%s]\n",
+ "\tappPackageName[%s]\n"
+ "\tvulkanVersion[%d]\n",
driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
- appPackageName.c_str());
+ appPackageName.c_str(), vulkanVersion);
mGpuStats.driverPackageName = driverPackageName;
mGpuStats.driverVersionName = driverVersionName;
mGpuStats.driverVersionCode = driverVersionCode;
mGpuStats.driverBuildTime = driverBuildTime;
mGpuStats.appPackageName = appPackageName;
+ mGpuStats.vulkanVersion = vulkanVersion;
}
void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) {
@@ -270,19 +273,20 @@
"\tdriverVersionCode[%" PRIu64 "]\n"
"\tdriverBuildTime[%" PRId64 "]\n"
"\tappPackageName[%s]\n"
+ "\tvulkanVersion[%d]\n"
"\tdriver[%d]\n"
"\tisDriverLoaded[%d]\n"
"\tdriverLoadingTime[%" PRId64 "]",
mGpuStats.driverPackageName.c_str(), mGpuStats.driverVersionName.c_str(),
mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, mGpuStats.appPackageName.c_str(),
- static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
+ mGpuStats.vulkanVersion, static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
const sp<IGpuService> gpuService = getGpuService();
if (gpuService) {
gpuService->setGpuStats(mGpuStats.driverPackageName, mGpuStats.driverVersionName,
mGpuStats.driverVersionCode, mGpuStats.driverBuildTime,
- mGpuStats.appPackageName, driver, isDriverLoaded,
- driverLoadingTime);
+ mGpuStats.appPackageName, mGpuStats.vulkanVersion, driver,
+ isDriverLoaded, driverLoadingTime);
}
}
diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp
index 1dc1c0e..100dca5 100644
--- a/libs/graphicsenv/IGpuService.cpp
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -30,8 +30,8 @@
virtual void setGpuStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
int64_t driverBuildTime, const std::string& appPackageName,
- GraphicsEnv::Driver driver, bool isDriverLoaded,
- int64_t driverLoadingTime) {
+ const int32_t vulkanVersion, GraphicsEnv::Driver driver,
+ bool isDriverLoaded, int64_t driverLoadingTime) {
Parcel data, reply;
data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
@@ -40,6 +40,7 @@
data.writeUint64(driverVersionCode);
data.writeInt64(driverBuildTime);
data.writeUtf8AsUtf16(appPackageName);
+ data.writeInt32(vulkanVersion);
data.writeInt32(static_cast<int32_t>(driver));
data.writeBool(isDriverLoaded);
data.writeInt64(driverLoadingTime);
@@ -118,6 +119,9 @@
std::string appPackageName;
if ((status = data.readUtf8FromUtf16(&appPackageName)) != OK) return status;
+ int32_t vulkanVersion;
+ if ((status = data.readInt32(&vulkanVersion)) != OK) return status;
+
int32_t driver;
if ((status = data.readInt32(&driver)) != OK) return status;
@@ -128,8 +132,8 @@
if ((status = data.readInt64(&driverLoadingTime)) != OK) return status;
setGpuStats(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
- appPackageName, static_cast<GraphicsEnv::Driver>(driver), isDriverLoaded,
- driverLoadingTime);
+ appPackageName, vulkanVersion, static_cast<GraphicsEnv::Driver>(driver),
+ isDriverLoaded, driverLoadingTime);
return OK;
}
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
index a92ca70..e96c932 100644
--- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
@@ -44,6 +44,7 @@
int32_t glLoadingFailureCount = 0;
int32_t vkLoadingCount = 0;
int32_t vkLoadingFailureCount = 0;
+ int32_t vulkanVersion = 0;
};
/*
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index cb4239f..b10cab7 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -50,6 +50,7 @@
uint64_t driverVersionCode;
int64_t driverBuildTime;
std::string appPackageName;
+ int32_t vulkanVersion;
Driver glDriverToLoad;
Driver glDriverFallback;
Driver vkDriverToLoad;
@@ -61,6 +62,7 @@
driverVersionCode(0),
driverBuildTime(0),
appPackageName(""),
+ vulkanVersion(0),
glDriverToLoad(Driver::NONE),
glDriverFallback(Driver::NONE),
vkDriverToLoad(Driver::NONE),
@@ -84,7 +86,7 @@
android_namespace_t* getDriverNamespace();
void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
uint64_t versionCode, int64_t driverBuildTime,
- const std::string& appPackageName);
+ const std::string& appPackageName, const int32_t vulkanVersion);
void setDriverToLoad(Driver driver);
void setDriverLoaded(Api api, bool isDriverLoaded, int64_t driverLoadingTime);
void clearDriverLoadingInfo(Api api);
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
index ac022b5..5bf0269 100644
--- a/libs/graphicsenv/include/graphicsenv/IGpuService.h
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -37,8 +37,8 @@
virtual void setGpuStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
int64_t driverBuildTime, const std::string& appPackageName,
- GraphicsEnv::Driver driver, bool isDriverLoaded,
- int64_t driverLoadingTime) = 0;
+ const int32_t vulkanVersion, GraphicsEnv::Driver driver,
+ bool isDriverLoaded, int64_t driverLoadingTime) = 0;
// get GPU global stats from GpuStats module.
virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const = 0;
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index fcbfba9..34575f5 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -25,49 +25,19 @@
},
double_loadable: true,
- clang: true,
- cflags: [
- "-Wall",
- "-Werror",
- ],
- cppflags: [
- "-Wextra",
- "-DDEBUG_ONLY_CODE=0",
- ],
-
- product_variables: {
- eng: {
- cppflags: [
- "-UDEBUG_ONLY_CODE",
- "-DDEBUG_ONLY_CODE=1",
- ],
- },
- },
+ defaults: ["libgui_bufferqueue-defaults"],
srcs: [
"BitTube.cpp",
"BufferHubConsumer.cpp",
"BufferHubProducer.cpp",
- "BufferItem.cpp",
"BufferItemConsumer.cpp",
- "BufferQueue.cpp",
- "BufferQueueConsumer.cpp",
- "BufferQueueCore.cpp",
- "BufferQueueProducer.cpp",
- "BufferQueueThreadState.cpp",
- "BufferSlot.cpp",
"ConsumerBase.cpp",
"CpuConsumer.cpp",
"DisplayEventReceiver.cpp",
- "FrameTimestamps.cpp",
"GLConsumer.cpp",
"GuiConfig.cpp",
- "HdrMetadata.cpp",
"IDisplayEventConnection.cpp",
- "IConsumerListener.cpp",
- "IGraphicBufferConsumer.cpp",
- "IGraphicBufferProducer.cpp",
- "IProducerListener.cpp",
"IRegionSamplingListener.cpp",
"ISurfaceComposer.cpp",
"ISurfaceComposerClient.cpp",
@@ -75,50 +45,20 @@
"LayerDebugInfo.cpp",
"LayerMetadata.cpp",
"LayerState.cpp",
- "OccupancyTracker.cpp",
"StreamSplitter.cpp",
"Surface.cpp",
"SurfaceControl.cpp",
"SurfaceComposerClient.cpp",
"SyncFeatures.cpp",
"view/Surface.cpp",
- "bufferqueue/1.0/B2HProducerListener.cpp",
- "bufferqueue/1.0/Conversion.cpp",
- "bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
- "bufferqueue/1.0/H2BProducerListener.cpp",
- "bufferqueue/1.0/WProducerListener.cpp",
- "bufferqueue/2.0/B2HGraphicBufferProducer.cpp",
- "bufferqueue/2.0/B2HProducerListener.cpp",
- "bufferqueue/2.0/H2BGraphicBufferProducer.cpp",
- "bufferqueue/2.0/H2BProducerListener.cpp",
- "bufferqueue/2.0/types.cpp",
],
shared_libs: [
"android.frameworks.bufferhub@1.0",
- "android.hardware.graphics.bufferqueue@1.0",
- "android.hardware.graphics.bufferqueue@2.0",
- "android.hardware.graphics.common@1.1",
- "android.hardware.graphics.common@1.2",
- "android.hidl.token@1.0-utils",
- "libbase",
- "libbinder",
"libbufferhub",
"libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
- "libcutils",
- "libEGL",
- "libGLESv2",
- "libhidlbase",
- "libhidltransport",
- "libhwbinder",
"libinput",
- "liblog",
- "libnativewindow",
"libpdx_default_transport",
- "libsync",
- "libui",
- "libutils",
- "libvndksupport",
],
// bufferhub is not used when building libgui for vendors
@@ -144,9 +84,100 @@
header_libs: [
"libdvr_headers",
+ "libpdx_headers",
+ ],
+}
+
+// Used by media codec services exclusively as a static lib for
+// core bufferqueue support only.
+cc_library_static {
+ name: "libgui_bufferqueue_static",
+ vendor_available: true,
+
+ cflags: [
+ "-DNO_BUFFERHUB",
+ ],
+
+ defaults: ["libgui_bufferqueue-defaults"],
+}
+
+// Common build config shared by libgui and libgui_bufferqueue_static.
+cc_defaults {
+ name: "libgui_bufferqueue-defaults",
+
+ clang: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ cppflags: [
+ "-Wextra",
+ "-DDEBUG_ONLY_CODE=0",
+ ],
+
+ product_variables: {
+ eng: {
+ cppflags: [
+ "-UDEBUG_ONLY_CODE",
+ "-DDEBUG_ONLY_CODE=1",
+ ],
+ },
+ },
+
+ srcs: [
+ "BufferItem.cpp",
+ "BufferQueue.cpp",
+ "BufferQueueConsumer.cpp",
+ "BufferQueueCore.cpp",
+ "BufferQueueProducer.cpp",
+ "BufferQueueThreadState.cpp",
+ "BufferSlot.cpp",
+ "FrameTimestamps.cpp",
+ "GLConsumerUtils.cpp",
+ "HdrMetadata.cpp",
+ "IConsumerListener.cpp",
+ "IGraphicBufferConsumer.cpp",
+ "IGraphicBufferProducer.cpp",
+ "IProducerListener.cpp",
+ "OccupancyTracker.cpp",
+ "bufferqueue/1.0/B2HProducerListener.cpp",
+ "bufferqueue/1.0/Conversion.cpp",
+ "bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
+ "bufferqueue/1.0/H2BProducerListener.cpp",
+ "bufferqueue/1.0/WProducerListener.cpp",
+ "bufferqueue/2.0/B2HGraphicBufferProducer.cpp",
+ "bufferqueue/2.0/B2HProducerListener.cpp",
+ "bufferqueue/2.0/H2BGraphicBufferProducer.cpp",
+ "bufferqueue/2.0/H2BProducerListener.cpp",
+ "bufferqueue/2.0/types.cpp",
+ ],
+
+ shared_libs: [
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.bufferqueue@2.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hidl.token@1.0-utils",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libnativewindow",
+ "libsync",
+ "libui",
+ "libutils",
+ "libvndksupport",
+ ],
+
+ header_libs: [
"libgui_headers",
"libnativebase_headers",
- "libpdx_headers",
],
export_shared_lib_headers: [
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index d87228f..5fb3f0b 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -59,13 +59,6 @@
}
}
-void BufferQueue::ProxyConsumerListener::onBufferAllocated(const BufferItem& item) {
- sp<ConsumerListener> listener(mConsumerListener.promote());
- if (listener != nullptr) {
- listener->onBufferAllocated(item);
- }
-}
-
void BufferQueue::ProxyConsumerListener::onBuffersReleased() {
sp<ConsumerListener> listener(mConsumerListener.promote());
if (listener != nullptr) {
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index e226136..528bfb1 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -94,8 +94,6 @@
// Skip this if we're in shared buffer mode and the queue is empty,
// since in that case we'll just return the shared buffer.
if (expectedPresent != 0 && !mCore->mQueue.empty()) {
- const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
-
// The 'expectedPresent' argument indicates when the buffer is expected
// to be presented on-screen. If the buffer's desired present time is
// earlier (less) than expectedPresent -- meaning it will be displayed
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index c94c6b3..3928bb9 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -539,13 +539,6 @@
return NO_INIT;
}
- if (mCore->mConsumerListener != nullptr) {
- BufferItem item;
- item.mGraphicBuffer = graphicBuffer;
- item.mSlot = *outSlot;
- mCore->mConsumerListener->onBufferAllocated(item);
- }
-
VALIDATE_CONSISTENCY();
} // Autolock scope
}
@@ -975,9 +968,6 @@
item.mGraphicBuffer.clear();
}
- // Don't send the slot number through the callback since the consumer shouldn't need it
- item.mSlot = BufferItem::INVALID_BUFFER_SLOT;
-
// Call back without the main BufferQueue lock held, but with the callback
// lock held so we can ensure that callbacks occur in order
@@ -1433,13 +1423,6 @@
BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d",
*slot);
- if (mCore->mConsumerListener != nullptr) {
- BufferItem item;
- item.mGraphicBuffer = buffers[i];
- item.mSlot = *slot;
- mCore->mConsumerListener->onBufferAllocated(item);
- }
-
// Make sure the erase is done after all uses of the slot
// iterator since it will be invalid after this point.
mCore->mFreeSlots.erase(slot);
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 1e94cc1..abd9921 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -131,8 +131,6 @@
}
}
-void ConsumerBase::onBufferAllocated(const BufferItem& /*item*/) {}
-
void ConsumerBase::onBuffersReleased() {
Mutex::Autolock lock(mMutex);
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index faf02f3..8d66154 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -745,104 +745,6 @@
mCurrentTransform, mFilteringEnabled);
}
-void GLConsumer::computeTransformMatrix(float outTransform[16],
- const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
- bool filtering) {
- // Transform matrices
- static const mat4 mtxFlipH(
- -1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 1, 0, 0, 1
- );
- static const mat4 mtxFlipV(
- 1, 0, 0, 0,
- 0, -1, 0, 0,
- 0, 0, 1, 0,
- 0, 1, 0, 1
- );
- static const mat4 mtxRot90(
- 0, 1, 0, 0,
- -1, 0, 0, 0,
- 0, 0, 1, 0,
- 1, 0, 0, 1
- );
-
- mat4 xform;
- if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
- xform *= mtxFlipH;
- }
- if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
- xform *= mtxFlipV;
- }
- if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
- xform *= mtxRot90;
- }
-
- if (!cropRect.isEmpty()) {
- float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
- float bufferWidth = buf->getWidth();
- float bufferHeight = buf->getHeight();
- float shrinkAmount = 0.0f;
- if (filtering) {
- // In order to prevent bilinear sampling beyond the edge of the
- // crop rectangle we may need to shrink it by 2 texels in each
- // dimension. Normally this would just need to take 1/2 a texel
- // off each end, but because the chroma channels of YUV420 images
- // are subsampled we may need to shrink the crop region by a whole
- // texel on each side.
- switch (buf->getPixelFormat()) {
- case PIXEL_FORMAT_RGBA_8888:
- case PIXEL_FORMAT_RGBX_8888:
- case PIXEL_FORMAT_RGBA_FP16:
- case PIXEL_FORMAT_RGBA_1010102:
- case PIXEL_FORMAT_RGB_888:
- case PIXEL_FORMAT_RGB_565:
- case PIXEL_FORMAT_BGRA_8888:
- // We know there's no subsampling of any channels, so we
- // only need to shrink by a half a pixel.
- shrinkAmount = 0.5;
- break;
-
- default:
- // If we don't recognize the format, we must assume the
- // worst case (that we care about), which is YUV420.
- shrinkAmount = 1.0;
- break;
- }
- }
-
- // Only shrink the dimensions that are not the size of the buffer.
- if (cropRect.width() < bufferWidth) {
- tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
- sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
- bufferWidth;
- }
- if (cropRect.height() < bufferHeight) {
- ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
- bufferHeight;
- sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
- bufferHeight;
- }
-
- mat4 crop(
- sx, 0, 0, 0,
- 0, sy, 0, 0,
- 0, 0, 1, 0,
- tx, ty, 0, 1
- );
- xform = crop * xform;
- }
-
- // GLConsumer uses the GL convention where (0, 0) is the bottom-left
- // corner and (1, 1) is the top-right corner. Add an additional vertical
- // flip after all other transforms to map from GL convention to buffer
- // queue memory layout, where (0, 0) is the top-left corner.
- xform = mtxFlipV * xform;
-
- memcpy(outTransform, xform.asArray(), sizeof(xform));
-}
-
Rect GLConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) {
Rect outCrop = crop;
diff --git a/libs/gui/GLConsumerUtils.cpp b/libs/gui/GLConsumerUtils.cpp
new file mode 100644
index 0000000..7a06c3d
--- /dev/null
+++ b/libs/gui/GLConsumerUtils.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GLConsumerUtils"
+//#define LOG_NDEBUG 0
+
+#include <gui/GLConsumer.h>
+#include <math/mat4.h>
+#include <system/window.h>
+#include <utils/Log.h>
+
+namespace android {
+
+void GLConsumer::computeTransformMatrix(float outTransform[16],
+ const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
+ bool filtering) {
+ // Transform matrices
+ static const mat4 mtxFlipH(
+ -1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 1, 0, 0, 1
+ );
+ static const mat4 mtxFlipV(
+ 1, 0, 0, 0,
+ 0, -1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 1, 0, 1
+ );
+ static const mat4 mtxRot90(
+ 0, 1, 0, 0,
+ -1, 0, 0, 0,
+ 0, 0, 1, 0,
+ 1, 0, 0, 1
+ );
+
+ mat4 xform;
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+ xform *= mtxFlipH;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+ xform *= mtxFlipV;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ xform *= mtxRot90;
+ }
+
+ if (!cropRect.isEmpty()) {
+ float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
+ float bufferWidth = buf->getWidth();
+ float bufferHeight = buf->getHeight();
+ float shrinkAmount = 0.0f;
+ if (filtering) {
+ // In order to prevent bilinear sampling beyond the edge of the
+ // crop rectangle we may need to shrink it by 2 texels in each
+ // dimension. Normally this would just need to take 1/2 a texel
+ // off each end, but because the chroma channels of YUV420 images
+ // are subsampled we may need to shrink the crop region by a whole
+ // texel on each side.
+ switch (buf->getPixelFormat()) {
+ case PIXEL_FORMAT_RGBA_8888:
+ case PIXEL_FORMAT_RGBX_8888:
+ case PIXEL_FORMAT_RGBA_FP16:
+ case PIXEL_FORMAT_RGBA_1010102:
+ case PIXEL_FORMAT_RGB_888:
+ case PIXEL_FORMAT_RGB_565:
+ case PIXEL_FORMAT_BGRA_8888:
+ // We know there's no subsampling of any channels, so we
+ // only need to shrink by a half a pixel.
+ shrinkAmount = 0.5;
+ break;
+
+ default:
+ // If we don't recognize the format, we must assume the
+ // worst case (that we care about), which is YUV420.
+ shrinkAmount = 1.0;
+ break;
+ }
+ }
+
+ // Only shrink the dimensions that are not the size of the buffer.
+ if (cropRect.width() < bufferWidth) {
+ tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
+ sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
+ bufferWidth;
+ }
+ if (cropRect.height() < bufferHeight) {
+ ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
+ bufferHeight;
+ sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
+ bufferHeight;
+ }
+
+ mat4 crop(
+ sx, 0, 0, 0,
+ 0, sy, 0, 0,
+ 0, 0, 1, 0,
+ tx, ty, 0, 1
+ );
+ xform = crop * xform;
+ }
+
+ // GLConsumer uses the GL convention where (0, 0) is the bottom-left
+ // corner and (1, 1) is the top-right corner. Add an additional vertical
+ // flip after all other transforms to map from GL convention to buffer
+ // queue memory layout, where (0, 0) is the top-left corner.
+ xform = mtxFlipV * xform;
+
+ memcpy(outTransform, xform.asArray(), sizeof(xform));
+}
+
+}; // namespace android
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index ea9045c..85ac304 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -28,8 +28,7 @@
ON_FRAME_REPLACED,
ON_BUFFERS_RELEASED,
ON_SIDEBAND_STREAM_CHANGED,
- ON_BUFFER_ALLOCATED,
- LAST = ON_BUFFER_ALLOCATED,
+ LAST = ON_SIDEBAND_STREAM_CHANGED,
};
} // Anonymous namespace
@@ -55,11 +54,6 @@
item);
}
- void onBufferAllocated(const BufferItem& item) override {
- callRemoteAsync<decltype(&IConsumerListener::onBufferAllocated)>(Tag::ON_BUFFER_ALLOCATED,
- item);
- }
-
void onBuffersReleased() override {
callRemoteAsync<decltype(&IConsumerListener::onBuffersReleased)>(Tag::ON_BUFFERS_RELEASED);
}
@@ -95,8 +89,6 @@
return callLocalAsync(data, reply, &IConsumerListener::onFrameAvailable);
case Tag::ON_FRAME_REPLACED:
return callLocalAsync(data, reply, &IConsumerListener::onFrameReplaced);
- case Tag::ON_BUFFER_ALLOCATED:
- return callLocalAsync(data, reply, &IConsumerListener::onBufferAllocated);
case Tag::ON_BUFFERS_RELEASED:
return callLocalAsync(data, reply, &IConsumerListener::onBuffersReleased);
case Tag::ON_SIDEBAND_STREAM_CHANGED:
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 2083a2b..437cdd7 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1149,8 +1149,12 @@
int x = dst.left;
int y = dst.top;
- float xScale = dst.getWidth() / static_cast<float>(source.getWidth());
- float yScale = dst.getHeight() / static_cast<float>(source.getHeight());
+
+ float sourceWidth = source.getWidth();
+ float sourceHeight = source.getHeight();
+
+ float xScale = sourceWidth < 0 ? 1.0f : dst.getWidth() / sourceWidth;
+ float yScale = sourceHeight < 0 ? 1.0f : dst.getHeight() / sourceHeight;
float matrix[4] = {1, 0, 0, 1};
switch (transform) {
diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
index 721427b..da95274 100644
--- a/libs/gui/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -61,7 +61,6 @@
void onDisconnect() override;
void onFrameAvailable(const BufferItem& item) override;
void onFrameReplaced(const BufferItem& item) override;
- void onBufferAllocated(const BufferItem& item) override;
void onBuffersReleased() override;
void onSidebandStreamChanged() override;
void addAndGetFrameTimestamps(
diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
index aa13c0c..7db69ec 100644
--- a/libs/gui/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -171,6 +171,9 @@
// End functions required for backwards compatibility
+ // Value used to determine if present time is valid.
+ constexpr static int MAX_REASONABLE_NSEC = 1'000'000'000ULL; // 1 second
+
private:
sp<BufferQueueCore> mCore;
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index 7c26482..366ced3 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -141,7 +141,6 @@
// classes if they want the notification.
virtual void onFrameAvailable(const BufferItem& item) override;
virtual void onFrameReplaced(const BufferItem& item) override;
- virtual void onBufferAllocated(const BufferItem& item) override;
virtual void onBuffersReleased() override;
virtual void onSidebandStreamChanged() override;
diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h
index 03fefbe..c082882 100644
--- a/libs/gui/include/gui/IConsumerListener.h
+++ b/libs/gui/include/gui/IConsumerListener.h
@@ -61,13 +61,6 @@
// This is called without any lock held and can be called concurrently by multiple threads.
virtual void onFrameReplaced(const BufferItem& /* item */) {} /* Asynchronous */
- // onBufferAllocated is called to notify the buffer consumer that the BufferQueue has allocated
- // a GraphicBuffer for a particular slot. Only the GraphicBuffer pointer and the slot ID will
- // be populated.
- //
- // This is called without any lock held and can be called concurrently by multiple threads.
- virtual void onBufferAllocated(const BufferItem& /* item */) {} /* Asynchronous */
-
// onBuffersReleased is called to notify the buffer consumer that the BufferQueue has released
// its references to one or more GraphicBuffers contained in its slots. The buffer consumer
// should then call BufferQueue::getReleasedBuffers to retrieve the list of buffers.
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index faf6d2a..46a8e9e 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -271,13 +271,6 @@
extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
- // In order to have protected contents in GPU composition, the OpenGL ES extension
- // GL_EXT_protected_textures must be supported. If it's not supported, reset
- // protected context to EGL_NO_CONTEXT to indicate that protected contents is not supported.
- if (!extensions.hasProtectedTexture()) {
- protectedContext = EGL_NO_CONTEXT;
- }
-
EGLSurface protectedDummy = EGL_NO_SURFACE;
if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) {
protectedDummy =
@@ -540,16 +533,14 @@
return false;
}
- EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
+ // release the fd and transfer the ownership to EGLSync
+ EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd.release(), EGL_NONE};
EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
if (sync == EGL_NO_SYNC_KHR) {
ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
return false;
}
- // fenceFd is now owned by EGLSync
- (void)fenceFd.release();
-
// XXX: The spec draft is inconsistent as to whether this should return an
// EGLint or void. Ignore the return value for now, as it's not strictly
// needed.
@@ -618,10 +609,6 @@
const GLenum target = GL_TEXTURE_EXTERNAL_OES;
glBindTexture(target, texName);
- if (supportsProtectedContent()) {
- glTexParameteri(target, GL_TEXTURE_PROTECTED_EXT,
- glImage.isProtected() ? GL_TRUE : GL_FALSE);
- }
if (glImage.getEGLImage() != EGL_NO_IMAGE_KHR) {
glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(glImage.getEGLImage()));
}
@@ -801,10 +788,6 @@
// Bind the texture and turn our EGLImage into a texture
glBindTexture(GL_TEXTURE_2D, textureName);
- if (supportsProtectedContent()) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_PROTECTED_EXT,
- mInProtectedContext ? GL_TRUE : GL_FALSE);
- }
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)eglImage);
// Bind the Framebuffer to render into
@@ -1313,7 +1296,9 @@
StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
extensions.getVersion());
StringAppendF(&result, "%s\n", extensions.getExtensions());
- StringAppendF(&result, "RenderEngine is in protected context : %d\n", mInProtectedContext);
+ StringAppendF(&result, "RenderEngine supports protected context: %d\n",
+ supportsProtectedContent());
+ StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext);
StringAppendF(&result, "RenderEngine program cache size for unprotected context: %zu\n",
cache.getSize(mEGLContext));
StringAppendF(&result, "RenderEngine program cache size for protected context: %zu\n",
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index d9a986e..139987e 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -22,6 +22,13 @@
#include <binder/IPermissionController.h>
#include <binder/IServiceManager.h>
+/*
+ * The permission to use for activity recognition sensors (like step counter).
+ * See sensor types for more details on what sensors should require this
+ * permission.
+ */
+#define SENSOR_PERMISSION_ACTIVITY_RECOGNITION "android.permission.ACTIVITY_RECOGNITION"
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -116,7 +123,7 @@
mStringType = SENSOR_STRING_TYPE_HEART_RATE;
mRequiredPermission = SENSOR_PERMISSION_BODY_SENSORS;
AppOpsManager appOps;
- mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS));
+ mRequiredAppOp = appOps.permissionToOpCode(String16(mRequiredPermission));
mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
} break;
case SENSOR_TYPE_LIGHT:
@@ -165,14 +172,22 @@
mFlags |= SENSOR_FLAG_WAKE_UP;
}
break;
- case SENSOR_TYPE_STEP_COUNTER:
+ case SENSOR_TYPE_STEP_COUNTER: {
mStringType = SENSOR_STRING_TYPE_STEP_COUNTER;
+ mRequiredPermission = SENSOR_PERMISSION_ACTIVITY_RECOGNITION;
+ AppOpsManager appOps;
+ mRequiredAppOp =
+ appOps.permissionToOpCode(String16(mRequiredPermission));
mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
- break;
- case SENSOR_TYPE_STEP_DETECTOR:
+ } break;
+ case SENSOR_TYPE_STEP_DETECTOR: {
mStringType = SENSOR_STRING_TYPE_STEP_DETECTOR;
+ mRequiredPermission = SENSOR_PERMISSION_ACTIVITY_RECOGNITION;
+ AppOpsManager appOps;
+ mRequiredAppOp =
+ appOps.permissionToOpCode(String16(mRequiredPermission));
mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE;
- break;
+ } break;
case SENSOR_TYPE_TEMPERATURE:
mStringType = SENSOR_STRING_TYPE_TEMPERATURE;
mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 5a67dc4..0861a1f 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -60,6 +60,15 @@
GraphicBufferAllocator::~GraphicBufferAllocator() {}
+size_t GraphicBufferAllocator::getTotalSize() const {
+ Mutex::Autolock _l(sLock);
+ size_t total = 0;
+ for (size_t i = 0; i < sAllocList.size(); ++i) {
+ total += sAllocList.valueAt(i).size;
+ }
+ return total;
+}
+
void GraphicBufferAllocator::dump(std::string& result) const {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
index 3a547b6..25d4512 100644
--- a/libs/ui/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -49,6 +49,8 @@
status_t free(buffer_handle_t handle);
+ size_t getTotalSize() const;
+
void dump(std::string& res) const;
static void dumpToSystemLog();
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 10dd8cb..d5c46c6 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -69,41 +69,6 @@
return loader;
}
-/* This function is called to check whether we run inside the emulator,
- * and if this is the case whether GLES GPU emulation is supported.
- *
- * Returned values are:
- * -1 -> not running inside the emulator
- * 0 -> running inside the emulator, but GPU emulation not supported
- * 1 -> running inside the emulator, GPU emulation is supported
- * through the "emulation" host-side OpenGL ES implementation.
- * 2 -> running inside the emulator, GPU emulation is supported
- * through a guest-side vendor driver's OpenGL ES implementation.
- */
-static int
-checkGlesEmulationStatus(void)
-{
- /* We're going to check for the following kernel parameters:
- *
- * qemu=1 -> tells us that we run inside the emulator
- * android.qemu.gles=<number> -> tells us the GLES GPU emulation status
- *
- * Note that we will return <number> if we find it. This let us support
- * more additionnal emulation modes in the future.
- */
- char prop[PROPERTY_VALUE_MAX];
- int result = -1;
-
- /* First, check for qemu=1 */
- property_get("ro.kernel.qemu",prop,"0");
- if (atoi(prop) != 1)
- return -1;
-
- /* We are in the emulator, get GPU status value */
- property_get("qemu.gles",prop,"0");
- return atoi(prop);
-}
-
static void* do_dlopen(const char* path, int mode) {
ATRACE_CALL();
return dlopen(path, mode);
@@ -208,6 +173,13 @@
}
}
+static const char* DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl";
+
+static const char* HAL_SUBNAME_KEY_PROPERTIES[2] = {
+ DRIVER_SUFFIX_PROPERTY,
+ "ro.board.platform",
+};
+
void* Loader::open(egl_connection_t* cnx)
{
ATRACE_CALL();
@@ -228,13 +200,39 @@
// Secondly, try to load from driver apk.
hnd = attempt_to_load_updated_driver(cnx);
}
+
+ bool failToLoadFromDriverSuffixProperty = false;
if (!hnd) {
- // Thirdly, try to load emulation driver.
- hnd = attempt_to_load_emulation_driver(cnx);
+ // Finally, try to load system driver, start by searching for the library name appended by
+ // the system properties of the GLES userspace driver in both locations.
+ // i.e.:
+ // libGLES_${prop}.so, or:
+ // libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so
+ char prop[PROPERTY_VALUE_MAX + 1];
+ for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
+ if (property_get(key, prop, nullptr) <= 0) {
+ continue;
+ }
+ hnd = attempt_to_load_system_driver(cnx, prop, true);
+ if (hnd) {
+ break;
+ } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
+ failToLoadFromDriverSuffixProperty = true;
+ }
+ }
}
+
if (!hnd) {
- // Finally, load system driver.
- hnd = attempt_to_load_system_driver(cnx);
+ // Can't find graphics driver by appending system properties, now search for the exact name
+ // without any suffix of the GLES userspace driver in both locations.
+ // i.e.:
+ // libGLES.so, or:
+ // libEGL.so, libGLESv1_CM.so, libGLESv2.so
+ hnd = attempt_to_load_system_driver(cnx, nullptr, true);
+ }
+
+ if (!hnd && !failToLoadFromDriverSuffixProperty) {
+ hnd = attempt_to_load_system_driver(cnx, nullptr, false);
}
if (!hnd) {
@@ -242,7 +240,9 @@
false, systemTime() - openTime);
}
- LOG_ALWAYS_FATAL_IF(!hnd, "couldn't find an OpenGL ES implementation");
+ LOG_ALWAYS_FATAL_IF(!hnd,
+ "couldn't find an OpenGL ES implementation, make sure you set %s or %s",
+ HAL_SUBNAME_KEY_PROPERTIES[0], HAL_SUBNAME_KEY_PROPERTIES[1]);
cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
@@ -350,71 +350,11 @@
}
}
-static void* load_emulation_driver(const char* kind) {
- const int emulationStatus = checkGlesEmulationStatus();
-
- // Invalid emulation status, abort.
- if (emulationStatus < 0 || emulationStatus > 2) {
- return nullptr;
- }
-
- std::string absolutePath;
- switch (emulationStatus) {
- case 0:
-#if defined(__LP64__)
- absolutePath = "/vendor/lib64/egl/libGLES_android.so";
-#else
- absolutePath = "/vendor/lib/egl/libGLES_android.so";
-#endif
- break;
- case 1:
- // Use host-side OpenGL through the "emulation" library
-#if defined(__LP64__)
- absolutePath = std::string("/vendor/lib64/egl/lib") + kind + "_emulation.so";
-#else
- absolutePath = std::string("/vendor/lib/egl/lib") + kind + "_emulation.so";
-#endif
- break;
- case 2:
- // Use guest side swiftshader library
-#if defined(__LP64__)
- absolutePath = std::string("/vendor/lib64/egl/lib") + kind + "_swiftshader.so";
-#else
- absolutePath = std::string("/vendor/lib/egl/lib") + kind + "_swiftshader.so";
-#endif
- break;
- default:
- // Not in emulator, or use other guest-side implementation
- break;
- }
- if (absolutePath.empty()) {
- // this happens often, we don't want to log an error
- return nullptr;
- }
- const char* const driver_absolute_path = absolutePath.c_str();
-
- // Try to load drivers from the 'sphal' namespace, if it exist. Fall back to
- // the original routine when the namespace does not exist.
- // See /system/core/rootdir/etc/ld.config.txt for the configuration of the
- // sphal namespace.
- void* dso = do_android_load_sphal_library(driver_absolute_path,
- RTLD_NOW | RTLD_LOCAL);
- if (dso == nullptr) {
- const char* err = dlerror();
- ALOGE("load_driver(%s): %s", driver_absolute_path, err ? err : "unknown");
- return nullptr;
- }
- ALOGD("loaded %s", driver_absolute_path);
- return dso;
-}
-
-static void* load_system_driver(const char* kind) {
+static void* load_system_driver(const char* kind, const char* suffix, const bool exact) {
ATRACE_CALL();
class MatchFile {
public:
- static std::string find(const char* kind) {
- std::string result;
- std::string pattern = std::string("lib") + kind;
+ static std::string find(const char* libraryName, const bool exact) {
const char* const searchPaths[] = {
#if defined(__LP64__)
"/vendor/lib64/egl",
@@ -425,35 +365,16 @@
#endif
};
- // first, we search for the exact name of the GLES userspace
- // driver in both locations.
- // i.e.:
- // libGLES.so, or:
- // libEGL.so, libGLESv1_CM.so, libGLESv2.so
-
- for (size_t i=0 ; i<NELEM(searchPaths) ; i++) {
- if (find(result, pattern, searchPaths[i], true)) {
- return result;
+ for (auto dir : searchPaths) {
+ std::string absolutePath;
+ if (find(absolutePath, libraryName, dir, exact)) {
+ return absolutePath;
}
}
- // for compatibility with the old "egl.cfg" naming convention
- // we look for files that match:
- // libGLES_*.so, or:
- // libEGL_*.so, libGLESv1_CM_*.so, libGLESv2_*.so
-
- pattern.append("_");
- for (size_t i=0 ; i<NELEM(searchPaths) ; i++) {
- if (find(result, pattern, searchPaths[i], false)) {
- return result;
- }
- }
-
- // we didn't find the driver. gah.
- result.clear();
- return result;
+ // Driver not found. gah.
+ return std::string();
}
-
private:
static bool find(std::string& result,
const std::string& pattern, const char* const search, bool exact) {
@@ -491,8 +412,16 @@
}
};
-
- std::string absolutePath = MatchFile::find(kind);
+ std::string libraryName = std::string("lib") + kind;
+ if (suffix) {
+ libraryName += std::string("_") + suffix;
+ } else if (!exact) {
+ // Deprecated: we look for files that match
+ // libGLES_*.so, or:
+ // libEGL_*.so, libGLESv1_CM_*.so, libGLESv2_*.so
+ libraryName += std::string("_");
+ }
+ std::string absolutePath = MatchFile::find(libraryName.c_str(), exact);
if (absolutePath.empty()) {
// this happens often, we don't want to log an error
return nullptr;
@@ -574,7 +503,20 @@
cnx->angleBackend = angleBackendDefault;
if (!cnx->vendorEGL && (cnx->angleBackend == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)) {
// Find and load vendor libEGL for ANGLE's GL back-end to use.
- cnx->vendorEGL = load_system_driver("EGL");
+ char prop[PROPERTY_VALUE_MAX + 1];
+ for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
+ if (property_get(key, prop, nullptr) <= 0) {
+ continue;
+ }
+ void* dso = load_system_driver("EGL", prop, true);
+ if (dso) {
+ cnx->vendorEGL = dso;
+ break;
+ }
+ }
+ if (!cnx->vendorEGL) {
+ cnx->vendorEGL = load_system_driver("EGL", nullptr, true);
+ }
}
} else {
ALOGV("Loaded native %s library for '%s' (instead of ANGLE)", kind,
@@ -586,11 +528,6 @@
return so;
}
-static const char* HAL_SUBNAME_KEY_PROPERTIES[2] = {
- "ro.hardware.egl",
- "ro.board.platform",
-};
-
static void* load_updated_driver(const char* kind, android_namespace_t* ns) {
ATRACE_CALL();
const android_dlextinfo dlextinfo = {
@@ -600,12 +537,13 @@
void* so = nullptr;
char prop[PROPERTY_VALUE_MAX + 1];
for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
- if (property_get(key, prop, nullptr) > 0) {
- std::string name = std::string("lib") + kind + "_" + prop + ".so";
- so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
- if (so) {
- return so;
- }
+ if (property_get(key, prop, nullptr) <= 0) {
+ continue;
+ }
+ std::string name = std::string("lib") + kind + "_" + prop + ".so";
+ so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+ if (so) {
+ return so;
}
}
return nullptr;
@@ -674,52 +612,27 @@
#endif
}
-Loader::driver_t* Loader::attempt_to_load_emulation_driver(egl_connection_t* cnx) {
+Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix,
+ const bool exact) {
ATRACE_CALL();
android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL);
driver_t* hnd = nullptr;
- void* dso = load_emulation_driver("GLES");
+ void* dso = load_system_driver("GLES", suffix, exact);
if (dso) {
initialize_api(dso, cnx, EGL | GLESv1_CM | GLESv2);
hnd = new driver_t(dso);
return hnd;
}
- dso = load_emulation_driver("EGL");
+ dso = load_system_driver("EGL", suffix, exact);
if (dso) {
initialize_api(dso, cnx, EGL);
hnd = new driver_t(dso);
- dso = load_emulation_driver("GLESv1_CM");
+ dso = load_system_driver("GLESv1_CM", suffix, exact);
initialize_api(dso, cnx, GLESv1_CM);
hnd->set(dso, GLESv1_CM);
- dso = load_emulation_driver("GLESv2");
- initialize_api(dso, cnx, GLESv2);
- hnd->set(dso, GLESv2);
- }
- return hnd;
-}
-
-Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx) {
- ATRACE_CALL();
- android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL);
- driver_t* hnd = nullptr;
- void* dso = load_system_driver("GLES");
- if (dso) {
- initialize_api(dso, cnx, EGL | GLESv1_CM | GLESv2);
- hnd = new driver_t(dso);
- return hnd;
- }
- dso = load_system_driver("EGL");
- if (dso) {
- initialize_api(dso, cnx, EGL);
- hnd = new driver_t(dso);
-
- dso = load_system_driver("GLESv1_CM");
- initialize_api(dso, cnx, GLESv1_CM);
- hnd->set(dso, GLESv1_CM);
-
- dso = load_system_driver("GLESv2");
+ dso = load_system_driver("GLESv2", suffix, exact);
initialize_api(dso, cnx, GLESv2);
hnd->set(dso, GLESv2);
}
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index c0f1b75..0292d02 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -57,8 +57,7 @@
Loader();
driver_t* attempt_to_load_angle(egl_connection_t* cnx);
driver_t* attempt_to_load_updated_driver(egl_connection_t* cnx);
- driver_t* attempt_to_load_emulation_driver(egl_connection_t* cnx);
- driver_t* attempt_to_load_system_driver(egl_connection_t* cnx);
+ driver_t* attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix, const bool exact);
void initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask);
static __attribute__((noinline))
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 59fa1c0..b42884e 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -51,12 +51,12 @@
void GpuService::setGpuStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
int64_t driverBuildTime, const std::string& appPackageName,
- GraphicsEnv::Driver driver, bool isDriverLoaded,
- int64_t driverLoadingTime) {
+ const int32_t vulkanVersion, GraphicsEnv::Driver driver,
+ bool isDriverLoaded, int64_t driverLoadingTime) {
ATRACE_CALL();
mGpuStats->insert(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
- appPackageName, driver, isDriverLoaded, driverLoadingTime);
+ appPackageName, vulkanVersion, driver, isDriverLoaded, driverLoadingTime);
}
status_t GpuService::getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const {
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index 7a9b2d4..3e02b4a 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -45,8 +45,9 @@
*/
void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
uint64_t driverVersionCode, int64_t driverBuildTime,
- const std::string& appPackageName, GraphicsEnv::Driver driver,
- bool isDriverLoaded, int64_t driverLoadingTime) override;
+ const std::string& appPackageName, const int32_t vulkanVersion,
+ GraphicsEnv::Driver driver, bool isDriverLoaded,
+ int64_t driverLoadingTime) override;
status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const override;
status_t getGpuStatsAppInfo(std::vector<GpuStatsAppInfo>* outStats) const override;
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
index 6185305..1cb78db 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -68,8 +68,8 @@
void GpuStats::insert(const std::string& driverPackageName, const std::string& driverVersionName,
uint64_t driverVersionCode, int64_t driverBuildTime,
- const std::string& appPackageName, GraphicsEnv::Driver driver,
- bool isDriverLoaded, int64_t driverLoadingTime) {
+ const std::string& appPackageName, const int32_t vulkanVersion,
+ GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mLock);
@@ -79,11 +79,13 @@
"\tdriverVersionCode[%" PRIu64 "]\n"
"\tdriverBuildTime[%" PRId64 "]\n"
"\tappPackageName[%s]\n"
+ "\tvulkanVersion[%d]\n"
"\tdriver[%d]\n"
"\tisDriverLoaded[%d]\n"
"\tdriverLoadingTime[%" PRId64 "]",
driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
- appPackageName.c_str(), static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
+ appPackageName.c_str(), vulkanVersion, static_cast<int32_t>(driver), isDriverLoaded,
+ driverLoadingTime);
if (!mGlobalStats.count(driverVersionCode)) {
GpuStatsGlobalInfo globalInfo;
@@ -94,6 +96,7 @@
globalInfo.driverVersionName = driverVersionName;
globalInfo.driverVersionCode = driverVersionCode;
globalInfo.driverBuildTime = driverBuildTime;
+ globalInfo.vulkanVersion = vulkanVersion;
mGlobalStats.insert({driverVersionCode, globalInfo});
} else if (!addLoadingCount(driver, isDriverLoaded, &mGlobalStats[driverVersionCode])) {
return;
diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h
index d942154..bb74fbb 100644
--- a/services/gpuservice/gpustats/GpuStats.h
+++ b/services/gpuservice/gpustats/GpuStats.h
@@ -35,8 +35,8 @@
// Insert new gpu stats into global stats and app stats.
void insert(const std::string& driverPackageName, const std::string& driverVersionName,
uint64_t driverVersionCode, int64_t driverBuildTime,
- const std::string& appPackageName, GraphicsEnv::Driver driver, bool isDriverLoaded,
- int64_t driverLoadingTime);
+ const std::string& appPackageName, const int32_t vulkanVersion,
+ GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime);
// dumpsys interface
void dump(const Vector<String16>& args, std::string* result);
// Pull gpu global stats
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index b4db338..4a6efa6 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -507,19 +507,53 @@
// --- MotionClassifier ---
-MotionClassifier::MotionClassifier(
- sp<android::hardware::input::classifier::V1_0::IInputClassifier> service) :
- mEvents(MAX_EVENTS), mService(service) {
+MotionClassifier::MotionClassifier(sp<android::hardware::hidl_death_recipient> deathRecipient) :
+ mDeathRecipient(deathRecipient), mEvents(MAX_EVENTS) {
mHalThread = std::thread(&MotionClassifier::callInputClassifierHal, this);
#if defined(__linux__)
// Set the thread name for debugging
pthread_setname_np(mHalThread.native_handle(), "InputClassifier");
#endif
+}
+
+/**
+ * This function may block for some time to initialize the HAL, so it should only be called
+ * from the "InputClassifier HAL" thread.
+ */
+bool MotionClassifier::init() {
+ ensureHalThread(__func__);
+ sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
+ classifier::V1_0::IInputClassifier::getService();
+ if (!service) {
+ // Not really an error, maybe the device does not have this HAL,
+ // but somehow the feature flag is flipped
+ ALOGI("Could not obtain InputClassifier HAL");
+ return false;
+ }
+
+ sp<android::hardware::hidl_death_recipient> recipient = mDeathRecipient.promote();
+ if (recipient != nullptr) {
+ const bool linked = service->linkToDeath(recipient, 0 /* cookie */).withDefault(false);
+ if (!linked) {
+ ALOGE("Could not link MotionClassifier to the HAL death");
+ return false;
+ }
+ }
+
// Under normal operation, we do not need to reset the HAL here. But in the case where system
// crashed, but HAL didn't, we may be connecting to an existing HAL process that might already
// have received events in the past. That means, that HAL could be in an inconsistent state
// once it receives events from the newly created MotionClassifier.
mEvents.push(ClassifierEvent::createHalResetEvent());
+
+ {
+ std::scoped_lock lock(mLock);
+ if (mService) {
+ ALOGE("MotionClassifier::%s should only be called once", __func__);
+ }
+ mService = service;
+ }
+ return true;
}
MotionClassifier::~MotionClassifier() {
@@ -530,7 +564,7 @@
void MotionClassifier::ensureHalThread(const char* function) {
if (DEBUG) {
if (std::this_thread::get_id() != mHalThread.get_id()) {
- ALOGE("Function %s should only be called from InputClassifier thread", function);
+ LOG_FATAL("Function %s should only be called from InputClassifier thread", function);
}
}
}
@@ -547,6 +581,21 @@
*/
void MotionClassifier::callInputClassifierHal() {
ensureHalThread(__func__);
+ const bool initialized = init();
+ if (!initialized) {
+ // MotionClassifier no longer useful.
+ // Deliver death notification from a separate thread
+ // because ~MotionClassifier may be invoked, which calls mHalThread.join()
+ std::thread([deathRecipient = mDeathRecipient](){
+ sp<android::hardware::hidl_death_recipient> recipient = deathRecipient.promote();
+ if (recipient != nullptr) {
+ recipient->serviceDied(0 /*cookie*/, nullptr);
+ }
+ }).detach();
+ return;
+ }
+ // From this point on, mService is guaranteed to be non-null.
+
while (true) {
ClassifierEvent event = mEvents.pop();
bool halResponseOk = true;
@@ -666,10 +715,19 @@
enqueueEvent(std::make_unique<NotifyDeviceResetArgs>(args));
}
+const char* MotionClassifier::getServiceStatus() REQUIRES(mLock) {
+ if (!mService) {
+ return "null";
+ }
+ if (mService->ping().isOk()) {
+ return "running";
+ }
+ return "not responding";
+}
+
void MotionClassifier::dump(std::string& dump) {
std::scoped_lock lock(mLock);
- std::string serviceStatus = mService->ping().isOk() ? "running" : " not responding";
- dump += StringPrintf(INDENT2 "mService status: %s\n", serviceStatus.c_str());
+ dump += StringPrintf(INDENT2 "mService status: %s\n", getServiceStatus());
dump += StringPrintf(INDENT2 "mEvents: %zu element(s) (max=%zu)\n",
mEvents.size(), MAX_EVENTS);
dump += INDENT2 "mClassifications, mLastDownTimes:\n";
@@ -700,28 +758,14 @@
}
void InputClassifier::onFirstRef() {
- std::scoped_lock lock(mLock);
if (!deepPressEnabled()) {
- // If feature is not enabled, the InputClassifier will just be in passthrough
- // mode, and will forward all events to the next InputListener, unmodified
+ // If feature is not enabled, MotionClassifier should stay null to avoid unnecessary work.
+ // When MotionClassifier is null, InputClassifier will forward all events
+ // to the next InputListener, unmodified.
return;
}
-
- sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
- classifier::V1_0::IInputClassifier::getService();
- if (!service) {
- // Not really an error, maybe the device does not have this HAL,
- // but somehow the feature flag is flipped
- ALOGI("Could not obtain InputClassifier HAL");
- return;
- }
- const bool linked = service->linkToDeath(this, 0 /* cookie */).withDefault(false);
- if (!linked) {
- ALOGE("Could not link android::InputClassifier to the HAL death");
- return;
- }
-
- mMotionClassifier = std::make_unique<MotionClassifier>(service);
+ std::scoped_lock lock(mLock);
+ mMotionClassifier = std::make_unique<MotionClassifier>(this);
}
void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
@@ -786,4 +830,4 @@
dump += "\n";
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index 0b1483f..47e20db 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -114,15 +114,22 @@
class MotionClassifier final : public MotionClassifierInterface {
public:
/**
- * The provided pointer to the service cannot be null.
+ * The deathRecipient will be subscribed to the HAL death. If the death recipient
+ * owns MotionClassifier and receives HAL death, it should delete its copy of it.
+ * The callback serviceDied will also be sent if the MotionClassifier itself fails
+ * to initialize. If the MotionClassifier fails to initialize, it is not useful, and
+ * should be deleted.
+ * If no death recipient is supplied, then the registration step will be skipped, so there will
+ * be no listeners registered for the HAL death. This is useful for testing
+ * MotionClassifier in isolation.
*/
- MotionClassifier(sp<android::hardware::input::classifier::V1_0::IInputClassifier> service);
+ explicit MotionClassifier(sp<android::hardware::hidl_death_recipient> deathRecipient = nullptr);
~MotionClassifier();
+
/**
* Classifies events asynchronously; that is, it doesn't block events on a classification,
- * but instead sends them over to the classifier HAL
- * and after a classification is determined,
- * it then marks the next event it sees in the stream with it.
+ * but instead sends them over to the classifier HAL and after a classification is
+ * determined, it then marks the next event it sees in the stream with it.
*
* Therefore, it is acceptable to have the classifications be delayed by 1-2 events
* in a particular gesture.
@@ -134,6 +141,16 @@
virtual void dump(std::string& dump) override;
private:
+ /**
+ * Initialize MotionClassifier.
+ * Return true if initializaion is successful.
+ */
+ bool init();
+ /**
+ * Entity that will be notified of the HAL death (most likely InputClassifier).
+ */
+ wp<android::hardware::hidl_death_recipient> mDeathRecipient;
+
// The events that need to be sent to the HAL.
BlockingQueue<ClassifierEvent> mEvents;
/**
@@ -148,7 +165,7 @@
std::thread mHalThread;
/**
* Print an error message if the caller is not on the InputClassifier thread.
- * Caller must supply the name of the calling function as __function__
+ * Caller must supply the name of the calling function as __func__
*/
void ensureHalThread(const char* function);
/**
@@ -156,9 +173,14 @@
*/
void callInputClassifierHal();
/**
- * Access to the InputClassifier HAL. Can always be safely dereferenced.
+ * Access to the InputClassifier HAL. May be null if init() hasn't completed yet.
+ * When init() successfully completes, mService is guaranteed to remain non-null and to not
+ * change its value until MotionClassifier is destroyed.
+ * This variable is *not* guarded by mLock in the InputClassifier thread, because
+ * that thread knows exactly when this variable is initialized.
+ * When accessed in any other thread, mService is checked for nullness with a lock.
*/
- const sp<android::hardware::input::classifier::V1_0::IInputClassifier> mService;
+ sp<android::hardware::input::classifier::V1_0::IInputClassifier> mService;
std::mutex mLock;
/**
* Per-device input classifications. Should only be accessed using the
@@ -195,6 +217,10 @@
* Useful for tests to ensure proper cleanup.
*/
void requestExit();
+ /**
+ * Return string status of mService
+ */
+ const char* getServiceStatus() REQUIRES(mLock);
};
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp
index 1651057..7cc17a2 100644
--- a/services/inputflinger/tests/InputClassifier_test.cpp
+++ b/services/inputflinger/tests/InputClassifier_test.cpp
@@ -136,11 +136,7 @@
std::unique_ptr<MotionClassifierInterface> mMotionClassifier;
virtual void SetUp() override {
- sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
- classifier::V1_0::IInputClassifier::getService();
- if (service) {
- mMotionClassifier = std::make_unique<MotionClassifier>(service);
- }
+ mMotionClassifier = std::make_unique<MotionClassifier>();
}
};
@@ -165,9 +161,7 @@
// We are not checking the return value, because we can't be making assumptions
// about the HAL operation, since it will be highly hardware-dependent
- if (mMotionClassifier) {
- ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
- }
+ ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
}
/**
@@ -183,9 +177,7 @@
// We are not checking the return value, because we can't be making assumptions
// about the HAL operation, since it will be highly hardware-dependent
- if (mMotionClassifier) {
- ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
- }
+ ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
}
/**
@@ -206,18 +198,14 @@
// We are not checking the return value, because we can't be making assumptions
// about the HAL operation, since it will be highly hardware-dependent
- if (mMotionClassifier) {
- ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
- }
+ ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
}
/**
* Make sure MotionClassifier does not crash when it is reset.
*/
TEST_F(MotionClassifierTest, Reset_DoesNotCrash) {
- if (mMotionClassifier) {
- ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset());
- }
+ ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset());
}
/**
@@ -225,9 +213,7 @@
*/
TEST_F(MotionClassifierTest, DeviceReset_DoesNotCrash) {
NotifyDeviceResetArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*deviceId*/);
- if (mMotionClassifier) {
- ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset(args));
- }
+ ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset(args));
}
} // namespace android
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index c4cfdc6..0e40940 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -285,8 +285,9 @@
scratch[count++] = buffer[i];
}
} else {
- // Regular sensor event, just copy it to the scratch buffer.
- if (hasSensorAccess()) {
+ // Regular sensor event, just copy it to the scratch buffer after checking
+ // the AppOp.
+ if (hasSensorAccess() && noteOpIfRequired(buffer[i])) {
scratch[count++] = buffer[i];
}
}
@@ -386,6 +387,16 @@
return mHasSensorAccess && !mService->mSensorPrivacyPolicy->isSensorPrivacyEnabled();
}
+bool SensorService::SensorEventConnection::noteOpIfRequired(const sensors_event_t& event) {
+ bool success = true;
+ const auto iter = mHandleToAppOp.find(event.sensor);
+ if (iter != mHandleToAppOp.end()) {
+ int32_t appOpMode = mService->sAppOpsManager.noteOp((*iter).second, mUid, mOpPackageName);
+ success = (appOpMode == AppOpsManager::MODE_ALLOWED);
+ }
+ return success;
+}
+
void SensorService::SensorEventConnection::reAllocateCacheLocked(sensors_event_t const* scratch,
int count) {
sensors_event_t *eventCache_new;
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 7077880..fd881cb 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <unordered_map>
#include <utils/Vector.h>
#include <utils/SortedVector.h>
@@ -134,6 +135,9 @@
// privacy not being enabled.
bool hasSensorAccess();
+ // Call noteOp for the sensor if the sensor requires a permission
+ bool noteOpIfRequired(const sensors_event_t& event);
+
sp<SensorService> const mService;
sp<BitTube> mChannel;
uid_t mUid;
@@ -181,6 +185,10 @@
mutable Mutex mDestroyLock;
bool mDestroyed;
bool mHasSensorAccess;
+
+ // Store a mapping of sensor handles to required AppOp for a sensor. This map only contains a
+ // valid mapping for sensors that require a permission in order to reduce the lookup time.
+ std::unordered_map<int32_t, int32_t> mHandleToAppOp;
};
} // namepsace android
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 0269990..639ce78 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <android/content/pm/IPackageManagerNative.h>
#include <binder/ActivityManager.h>
-#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
@@ -75,6 +75,9 @@
const char* SensorService::WAKE_LOCK_NAME = "SensorService_wakelock";
uint8_t SensorService::sHmacGlobalKey[128] = {};
bool SensorService::sHmacGlobalKeyIsValid = false;
+std::map<String16, int> SensorService::sPackageTargetVersion;
+Mutex SensorService::sPackageTargetVersionLock;
+AppOpsManager SensorService::sAppOpsManager;
#define SENSOR_SERVICE_DIR "/data/system/sensor_service"
#define SENSOR_SERVICE_HMAC_KEY_FILE SENSOR_SERVICE_DIR "/hmac_key"
@@ -1394,6 +1397,14 @@
checkWakeLockStateLocked();
}
+ {
+ Mutex::Autolock packageLock(sPackageTargetVersionLock);
+ auto iter = sPackageTargetVersion.find(c->mOpPackageName);
+ if (iter != sPackageTargetVersion.end()) {
+ sPackageTargetVersion.erase(iter);
+ }
+ }
+
SensorDevice& dev(SensorDevice::getInstance());
dev.notifyConnectionDestroyed(c);
}
@@ -1539,6 +1550,10 @@
if (err == NO_ERROR) {
connection->updateLooperRegistration(mLooper);
+ if (sensor->getSensor().getRequiredPermission().size() > 0) {
+ connection->mHandleToAppOp[handle] = sensor->getSensor().getRequiredAppOp();
+ }
+
mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) =
SensorRegistrationInfo(handle, connection->getPackageName(),
samplingPeriodNs, maxBatchReportLatencyNs, true);
@@ -1663,13 +1678,50 @@
bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation,
const String16& opPackageName) {
- const String8& requiredPermission = sensor.getRequiredPermission();
-
- if (requiredPermission.length() <= 0) {
+ // Check if a permission is required for this sensor
+ if (sensor.getRequiredPermission().length() <= 0) {
return true;
}
+ const int32_t opCode = sensor.getRequiredAppOp();
+ const int32_t appOpMode = sAppOpsManager.checkOp(opCode,
+ IPCThreadState::self()->getCallingUid(), opPackageName);
+
+ // Ensure that the AppOp is allowed
+ //
+ // This check is also required to ensure that the user hasn't revoked the necessary permissions
+ // to access the Step Detector and Step Counter when the application targets pre-Q. Without this
+ // check, if the user revokes the pre-Q install-time GMS Core AR permission, the app would
+ // still be able to receive Step Counter and Step Detector events.
+ bool canAccess = false;
+ if (opCode >= 0 && appOpMode == AppOpsManager::MODE_ALLOWED) {
+ if (hasPermissionForSensor(sensor)) {
+ canAccess = true;
+ } else if (sensor.getType() == SENSOR_TYPE_STEP_COUNTER ||
+ sensor.getType() == SENSOR_TYPE_STEP_DETECTOR) {
+ int targetSdkVersion = getTargetSdkVersion(opPackageName);
+ // Allow access to the sensor if the application targets pre-Q, which is before the
+ // requirement to hold the AR permission to access Step Counter and Step Detector events
+ // was introduced.
+ if (targetSdkVersion > 0 && targetSdkVersion <= __ANDROID_API_P__) {
+ canAccess = true;
+ }
+ }
+ }
+
+ if (canAccess) {
+ sAppOpsManager.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName);
+ } else {
+ ALOGE("%s a sensor (%s) without holding its required permission: %s",
+ operation, sensor.getName().string(), sensor.getRequiredPermission().string());
+ }
+
+ return canAccess;
+}
+
+bool SensorService::hasPermissionForSensor(const Sensor& sensor) {
bool hasPermission = false;
+ const String8& requiredPermission = sensor.getRequiredPermission();
// Runtime permissions can't use the cache as they may change.
if (sensor.isRequiredPermissionRuntime()) {
@@ -1678,25 +1730,31 @@
} else {
hasPermission = PermissionCache::checkCallingPermission(String16(requiredPermission));
}
+ return hasPermission;
+}
- if (!hasPermission) {
- ALOGE("%s a sensor (%s) without holding its required permission: %s",
- operation, sensor.getName().string(), sensor.getRequiredPermission().string());
- return false;
- }
-
- const int32_t opCode = sensor.getRequiredAppOp();
- if (opCode >= 0) {
- AppOpsManager appOps;
- if (appOps.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName)
- != AppOpsManager::MODE_ALLOWED) {
- ALOGE("%s a sensor (%s) without enabled required app op: %d",
- operation, sensor.getName().string(), opCode);
- return false;
+int SensorService::getTargetSdkVersion(const String16& opPackageName) {
+ Mutex::Autolock packageLock(sPackageTargetVersionLock);
+ int targetSdkVersion = -1;
+ auto entry = sPackageTargetVersion.find(opPackageName);
+ if (entry != sPackageTargetVersion.end()) {
+ targetSdkVersion = entry->second;
+ } else {
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("package_native"));
+ if (binder != nullptr) {
+ sp<content::pm::IPackageManagerNative> packageManager =
+ interface_cast<content::pm::IPackageManagerNative>(binder);
+ if (packageManager != nullptr) {
+ binder::Status status = packageManager->getTargetSdkVersionForPackage(
+ opPackageName, &targetSdkVersion);
+ if (!status.isOk()) {
+ targetSdkVersion = -1;
+ }
+ }
}
+ sPackageTargetVersion[opPackageName] = targetSdkVersion;
}
-
- return true;
+ return targetSdkVersion;
}
void SensorService::checkWakeLockState() {
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 5076967..e6ec96d 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -20,6 +20,7 @@
#include "SensorList.h"
#include "RecentEventLogger.h"
+#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
#include <binder/IUidObserver.h>
#include <cutils/compiler.h>
@@ -243,6 +244,8 @@
sensors_event_t const* buffer, const int count);
static bool canAccessSensor(const Sensor& sensor, const char* operation,
const String16& opPackageName);
+ static bool hasPermissionForSensor(const Sensor& sensor);
+ static int getTargetSdkVersion(const String16& opPackageName);
// SensorService acquires a partial wakelock for delivering events from wake up sensors. This
// method checks whether all the events from these wake up sensors have been delivered to the
// corresponding applications, if yes the wakelock is released.
@@ -343,6 +346,10 @@
sp<UidPolicy> mUidPolicy;
sp<SensorPrivacyPolicy> mSensorPrivacyPolicy;
+
+ static AppOpsManager sAppOpsManager;
+ static std::map<String16, int> sPackageTargetVersion;
+ static Mutex sPackageTargetVersionLock;
};
} // namespace android
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 4ea587d..06caf1e 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -534,11 +534,13 @@
// transaction
void BufferLayer::notifyAvailableFrames() {
- auto headFrameNumber = getHeadFrameNumber();
- bool headFenceSignaled = fenceHasSignaled();
+ const auto headFrameNumber = getHeadFrameNumber();
+ const bool headFenceSignaled = fenceHasSignaled();
+ const bool presentTimeIsCurrent = framePresentTimeIsCurrent();
Mutex::Autolock lock(mLocalSyncPointMutex);
for (auto& point : mLocalSyncPoints) {
- if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
+ if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled &&
+ presentTimeIsCurrent) {
point->setFrameAvailable();
}
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index dc103cb..b679380 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -114,6 +114,7 @@
// -----------------------------------------------------------------------
private:
virtual bool fenceHasSignaled() const = 0;
+ virtual bool framePresentTimeIsCurrent() const = 0;
virtual nsecs_t getDesiredPresentTime() = 0;
virtual std::shared_ptr<FenceTime> getCurrentFenceTime() const = 0;
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index fc98dc8..6709fb4 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -478,20 +478,15 @@
}
}
-void BufferLayerConsumer::onBufferAllocated(const BufferItem& item) {
- if (item.mGraphicBuffer != nullptr) {
- std::shared_ptr<Image> image = std::make_shared<Image>(item.mGraphicBuffer, mRE);
- std::shared_ptr<Image> oldImage;
- {
- std::lock_guard<std::mutex> lock(mImagesMutex);
- oldImage = mImages[item.mSlot];
- if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr ||
- oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) {
- mImages[item.mSlot] = std::make_shared<Image>(item.mGraphicBuffer, mRE);
- }
- image = mImages[item.mSlot];
+void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) {
+ if (item.mGraphicBuffer != nullptr && item.mSlot != BufferQueue::INVALID_BUFFER_SLOT) {
+ std::lock_guard<std::mutex> lock(mImagesMutex);
+ const std::shared_ptr<Image>& oldImage = mImages[item.mSlot];
+ if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr ||
+ oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) {
+ mImages[item.mSlot] = std::make_shared<Image>(item.mGraphicBuffer, mRE);
+ mRE.cacheExternalTextureBuffer(item.mGraphicBuffer);
}
- mRE.cacheExternalTextureBuffer(image->graphicBuffer());
}
}
@@ -533,5 +528,4 @@
mRE.unbindExternalTextureBuffer(mGraphicBuffer->getId());
}
}
-
}; // namespace android
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 0f0655d..e3f6100 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -176,6 +176,7 @@
// setConsumerUsageBits overrides the ConsumerBase method to OR
// DEFAULT_USAGE_FLAGS to usage.
status_t setConsumerUsageBits(uint64_t usage);
+ void onBufferAvailable(const BufferItem& item) EXCLUDES(mImagesMutex);
protected:
// abandonLocked overrides the ConsumerBase method to clear
@@ -241,7 +242,6 @@
// IConsumerListener interface
void onDisconnect() override;
- void onBufferAllocated(const BufferItem& item) override EXCLUDES(mImagesMutex);
void onSidebandStreamChanged() override;
void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) override;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index ff5f271..3d51ec3 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -14,11 +14,15 @@
* limitations under the License.
*/
+#undef LOG_TAG
+#define LOG_TAG "BufferQueueLayer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <gui/BufferQueueConsumer.h>
#include <system/window.h>
#include "BufferQueueLayer.h"
@@ -133,6 +137,15 @@
return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
}
+bool BufferQueueLayer::framePresentTimeIsCurrent() const {
+ if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
+ return true;
+ }
+
+ Mutex::Autolock lock(mQueueItemLock);
+ return mQueueItems[0].mTimestamp <= mFlinger->mScheduler->expectedPresentTime();
+}
+
nsecs_t BufferQueueLayer::getDesiredPresentTime() {
return mConsumer->getTimestamp();
}
@@ -185,7 +198,37 @@
uint64_t BufferQueueLayer::getFrameNumber() const {
Mutex::Autolock lock(mQueueItemLock);
- return mQueueItems[0].mFrameNumber;
+ uint64_t frameNumber = mQueueItems[0].mFrameNumber;
+
+ // The head of the queue will be dropped if there are signaled and timely frames behind it
+ nsecs_t expectedPresentTime = mFlinger->mScheduler->expectedPresentTime();
+
+ if (isRemovedFromCurrentState()) {
+ expectedPresentTime = 0;
+ }
+
+ for (int i = 1; i < mQueueItems.size(); i++) {
+ const bool fenceSignaled =
+ mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+ if (!fenceSignaled) {
+ break;
+ }
+
+ // We don't drop frames without explicit timestamps
+ if (mQueueItems[i].mIsAutoTimestamp) {
+ break;
+ }
+
+ const nsecs_t desiredPresent = mQueueItems[i].mTimestamp;
+ if (desiredPresent < expectedPresentTime - BufferQueueConsumer::MAX_REASONABLE_NSEC ||
+ desiredPresent > expectedPresentTime) {
+ break;
+ }
+
+ frameNumber = mQueueItems[i].mFrameNumber;
+ }
+
+ return frameNumber;
}
bool BufferQueueLayer::getAutoRefresh() const {
@@ -395,6 +438,7 @@
}
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
+ ATRACE_CALL();
// Add this buffer from our internal queue tracker
{ // Autolock scope
if (mFlinger->mUseSmart90ForVideo) {
@@ -435,9 +479,11 @@
} else {
mFlinger->signalLayerUpdate();
}
+ mConsumer->onBufferAvailable(item);
}
void BufferQueueLayer::onFrameReplaced(const BufferItem& item) {
+ ATRACE_CALL();
{ // Autolock scope
Mutex::Autolock lock(mQueueItemLock);
@@ -459,6 +505,7 @@
mLastFrameNumberReceived = item.mFrameNumber;
mQueueItemCondition.broadcast();
}
+ mConsumer->onBufferAvailable(item);
}
void BufferQueueLayer::onSidebandStreamChanged() {
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index a2aad17..7def33a 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -61,6 +61,7 @@
// -----------------------------------------------------------------------
public:
bool fenceHasSignaled() const override;
+ bool framePresentTimeIsCurrent() const override;
private:
nsecs_t getDesiredPresentTime() override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 6ef4518..a740afb 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -374,6 +374,14 @@
return getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
}
+bool BufferStateLayer::framePresentTimeIsCurrent() const {
+ if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
+ return true;
+ }
+
+ return mDesiredPresentTime <= mFlinger->mScheduler->expectedPresentTime();
+}
+
nsecs_t BufferStateLayer::getDesiredPresentTime() {
return mDesiredPresentTime;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 13186dd..4e2bc45 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -101,6 +101,7 @@
// Interface implementation for BufferLayer
// -----------------------------------------------------------------------
bool fenceHasSignaled() const override;
+ bool framePresentTimeIsCurrent() const override;
private:
nsecs_t getDesiredPresentTime() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index e69b99f..e21128c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -50,6 +50,9 @@
// Returns the bounds of the surface
virtual const ui::Size& getSize() const = 0;
+ // Returns whether the surface is protected.
+ virtual bool isProtected() const = 0;
+
// Gets the latest fence to pass to the HWC to signal that the surface
// buffer is done rendering
virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 3c79084..0f57315 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -45,6 +45,7 @@
bool isValid() const override;
void initialize() override;
const ui::Size& getSize() const override;
+ bool isProtected() const override { return mProtected; }
const sp<Fence>& getClientTargetAcquireFence() const override;
void setBufferDataspace(ui::Dataspace) override;
@@ -78,6 +79,7 @@
sp<GraphicBuffer> mGraphicBuffer;
const sp<DisplaySurface> mDisplaySurface;
ui::Size mSize;
+ bool mProtected{false};
std::uint32_t mPageFlipCount{0};
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index 1562f58..ca2299a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -31,6 +31,7 @@
MOCK_CONST_METHOD0(isValid, bool());
MOCK_METHOD0(initialize, void());
MOCK_CONST_METHOD0(getSize, const ui::Size&());
+ MOCK_CONST_METHOD0(isProtected, bool());
MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&());
MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
MOCK_METHOD1(setProtected, void(bool));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 2893031..01b5781 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -89,14 +89,14 @@
}
void Output::setColorTransform(const mat4& transform) {
+ if (mState.colorTransformMat == transform) {
+ return;
+ }
+
const bool isIdentity = (transform == mat4());
const auto newColorTransform =
isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
- if (mState.colorTransform == newColorTransform) {
- return;
- }
-
mState.colorTransform = newColorTransform;
mState.colorTransformMat = transform;
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index b5a6678..3fcd9d1 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -101,6 +101,9 @@
}
const int status = native_window_set_usage(mNativeWindow.get(), usageFlags);
ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status);
+ if (status == NO_ERROR) {
+ mProtected = useProtected;
+ }
}
status_t RenderSurface::beginFrame(bool mustRecompose) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index a84af3a..fee0c11 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -172,16 +172,29 @@
mOutput.setColorTransform(identity);
EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mOutput.getState().colorTransform);
+ EXPECT_EQ(identity, mOutput.getState().colorTransformMat);
// Since identity is the default, the dirty region should be unchanged (empty)
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
// Non-identity matrix sets a non-identity state value
- const mat4 nonIdentity = mat4() * 2;
+ const mat4 nonIdentityHalf = mat4() * 0.5;
- mOutput.setColorTransform(nonIdentity);
+ mOutput.setColorTransform(nonIdentityHalf);
EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
+ EXPECT_EQ(nonIdentityHalf, mOutput.getState().colorTransformMat);
+
+ // Since this is a state change, the entire output should now be dirty.
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+
+ // Non-identity matrix sets a non-identity state value
+ const mat4 nonIdentityQuarter = mat4() * 0.25;
+
+ mOutput.setColorTransform(nonIdentityQuarter);
+
+ EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
+ EXPECT_EQ(nonIdentityQuarter, mOutput.getState().colorTransformMat);
// Since this is a state change, the entire output should now be dirty.
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 9960478..f75a4dc 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -143,16 +143,40 @@
*/
TEST_F(RenderSurfaceTest, setProtectedTrueEnablesProtection) {
+ EXPECT_FALSE(mSurface.isProtected());
EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PROTECTED))
.WillOnce(Return(NO_ERROR));
mSurface.setProtected(true);
+ EXPECT_TRUE(mSurface.isProtected());
}
TEST_F(RenderSurfaceTest, setProtectedFalseDisablesProtection) {
+ EXPECT_FALSE(mSurface.isProtected());
EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
mSurface.setProtected(false);
+ EXPECT_FALSE(mSurface.isProtected());
+}
+
+TEST_F(RenderSurfaceTest, setProtectedEnableAndDisable) {
+ EXPECT_FALSE(mSurface.isProtected());
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PROTECTED))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
+
+ mSurface.setProtected(true);
+ EXPECT_TRUE(mSurface.isProtected());
+ mSurface.setProtected(false);
+ EXPECT_FALSE(mSurface.isProtected());
+}
+
+TEST_F(RenderSurfaceTest, setProtectedEnableWithError) {
+ EXPECT_FALSE(mSurface.isProtected());
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PROTECTED))
+ .WillOnce(Return(INVALID_OPERATION));
+ mSurface.setProtected(true);
+ EXPECT_FALSE(mSurface.isProtected());
}
/* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 46ca0b6..cbe8b29 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -130,7 +130,7 @@
}
mFrameTracker.logAndResetStats(mName);
- mFlinger->onLayerDestroyed();
+ mFlinger->onLayerDestroyed(this);
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index fcde8da..1e5c25f 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -38,7 +38,7 @@
}
mLayer = mClient->getLayerUser(mIBinder);
- mLayer->setCrop_legacy(Rect(0, 0, 200, 100), true);
+ mLayer->setCrop_legacy(Rect(50, 70, 200, 100), true);
mLayer->setLayer(INT32_MAX - 2);
return true;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 252ff0d..0d14267 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -377,10 +377,15 @@
mFlinger.traverseLayersInDisplay(device, filterVisitor);
};
- const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(sampledArea.getWidth(), sampledArea.getHeight(),
- PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
+ sp<GraphicBuffer> buffer = nullptr;
+ if (mCachedBuffer && mCachedBuffer->getWidth() == sampledArea.getWidth() &&
+ mCachedBuffer->getHeight() == sampledArea.getHeight()) {
+ buffer = mCachedBuffer;
+ } else {
+ const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
+ buffer = new GraphicBuffer(sampledArea.getWidth(), sampledArea.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
+ }
// When calling into SF, we post a message into the SF message queue (so the
// screen capture runs on the main thread). This message blocks until the
@@ -415,6 +420,12 @@
for (size_t d = 0; d < activeDescriptors.size(); ++d) {
activeDescriptors[d].listener->onSampleCollected(lumas[d]);
}
+
+ // Extend the lifetime of mCachedBuffer from the previous frame to here to ensure that:
+ // 1) The region sampling thread is the last owner of the buffer, and the freeing of the buffer
+ // happens in this thread, as opposed to the main thread.
+ // 2) The listener(s) receive their notifications prior to freeing the buffer.
+ mCachedBuffer = buffer;
ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::noWorkNeeded));
}
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index 9796429..72b2042 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -24,13 +24,13 @@
#include <android-base/thread_annotations.h>
#include <binder/IBinder.h>
+#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
#include <utils/StrongPointer.h>
#include "Scheduler/IdleTimer.h"
namespace android {
-class GraphicBuffer;
class IRegionSamplingListener;
class Layer;
class Scheduler;
@@ -121,6 +121,8 @@
std::unordered_map<wp<IBinder>, Descriptor, WpHash> mDescriptors GUARDED_BY(mMutex);
std::chrono::nanoseconds lastSampleTime GUARDED_BY(mMutex);
bool mDiscardedFrames GUARDED_BY(mMutex) = false;
+
+ sp<GraphicBuffer> mCachedBuffer GUARDED_BY(mMutex) = nullptr;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 871f556..abf7b71 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -210,17 +210,14 @@
const nsecs_t baseTime = now - mReferenceTime;
const nsecs_t numPeriodsSinceReference = baseTime / mPeriod;
const nsecs_t predictedReference = mReferenceTime + numPeriodsSinceReference * mPeriod;
- listener.mLastEventTime = predictedReference + mPhase + listener.mPhase;
- // If we're very close in time to the predicted last event time,
- // and we're not very close to the next predicted last event time
- // then we need to back up the last event time so that we can
- // attempt to fire an event immediately.
- //
- // Otherwise, keep the last event time that we predicted so that
- // we don't wake up early.
- if (isShorterThanPeriod(now - listener.mLastEventTime) &&
- !isShorterThanPeriod(listener.mLastEventTime + mPeriod - now)) {
- listener.mLastEventTime -= mPeriod;
+ const nsecs_t phaseCorrection = mPhase + listener.mPhase;
+ const nsecs_t predictedLastEventTime = predictedReference + phaseCorrection;
+ if (predictedLastEventTime >= now) {
+ // Make sure that the last event time does not exceed the current time.
+ // If it would, then back the last event time by a period.
+ listener.mLastEventTime = predictedLastEventTime - mPeriod;
+ } else {
+ listener.mLastEventTime = predictedLastEventTime;
}
} else {
listener.mLastEventTime = now + mPhase - mWakeupLatency;
@@ -316,7 +313,7 @@
// Sanity check that the duration is close enough in length to a period without
// falling into double-rate vsyncs.
- bool isShorterThanPeriod(nsecs_t duration) {
+ bool isCloseToPeriod(nsecs_t duration) {
// Ratio of 3/5 is arbitrary, but it must be greater than 1/2.
return duration < (3 * mPeriod) / 5;
}
@@ -332,7 +329,7 @@
nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);
if (t < now) {
- if (isShorterThanPeriod(now - eventListener.mLastCallbackTime)) {
+ if (isCloseToPeriod(now - eventListener.mLastCallbackTime)) {
eventListener.mLastEventTime = t;
ALOGV("[%s] [%s] Skipping event due to model error", mName,
eventListener.mName);
@@ -392,7 +389,7 @@
// Check that it's been slightly more than half a period since the last
// event so that we don't accidentally fall into double-rate vsyncs
- if (isShorterThanPeriod(t - listener.mLastEventTime)) {
+ if (isCloseToPeriod(t - listener.mLastEventTime)) {
t += mPeriod;
ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
}
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 16f6729..276bce1 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -65,6 +65,13 @@
property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "1000000");
const int highFpsLateSfOffsetNs = atoi(value);
+ // Below defines the threshold when an offset is considered to be negative, i.e. targeting
+ // for the N+2 vsync instead of N+1. This means that:
+ // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync.
+ // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync.
+ property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1");
+ const int phaseOffsetThresholdForNextVsyncNs = atoi(value);
+
mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs
: sfVsyncPhaseOffsetNs,
earlyAppOffsetNs != -1 ? earlyAppOffsetNs
@@ -84,6 +91,10 @@
highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
: highFpsLateAppOffsetNs};
mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs};
+
+ mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1
+ ? phaseOffsetThresholdForNextVsyncNs
+ : std::numeric_limits<nsecs_t>::max();
}
PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index 08747a5..dc71e6e 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -46,6 +46,7 @@
RefreshRateConfigs::RefreshRateType refreshRateType) const = 0;
virtual Offsets getCurrentOffsets() const = 0;
virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0;
+ virtual nsecs_t getOffsetThresholdForNextVsync() const = 0;
virtual void dump(std::string& result) const = 0;
};
@@ -72,6 +73,8 @@
mRefreshRateType = refreshRateType;
}
+ nsecs_t getOffsetThresholdForNextVsync() const override { return mOffsetThresholdForNextVsync; }
+
// Returns current offsets in human friendly format.
void dump(std::string& result) const override;
@@ -84,6 +87,7 @@
Offsets mDefaultRefreshRateOffsets;
Offsets mHighRefreshRateOffsets;
+ nsecs_t mOffsetThresholdForNextVsync;
};
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index 1a0de08..81a7864 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -139,6 +139,19 @@
}
}
+ Offsets getOffsets() {
+ // Early offsets are used if we're in the middle of a refresh rate
+ // change, or if we recently begin a transaction.
+ if (mTransactionStart == Scheduler::TransactionStart::EARLY ||
+ mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) {
+ return mEarlyOffsets;
+ } else if (mLastFrameUsedRenderEngine) {
+ return mEarlyGlOffsets;
+ } else {
+ return mLateOffsets;
+ }
+ }
+
private:
void updateOffsets() {
const Offsets desired = getOffsets();
@@ -167,19 +180,6 @@
}
}
- Offsets getOffsets() {
- // Early offsets are used if we're in the middle of a refresh rate
- // change, or if we recently begin a transaction.
- if (mTransactionStart == Scheduler::TransactionStart::EARLY ||
- mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) {
- return mEarlyOffsets;
- } else if (mLastFrameUsedRenderEngine) {
- return mEarlyGlOffsets;
- } else {
- return mLateOffsets;
- }
- }
-
Offsets mLateOffsets;
Offsets mEarlyOffsets;
Offsets mEarlyGlOffsets;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index bd286c3..f8745f7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -977,8 +977,7 @@
bool SurfaceFlinger::performSetActiveConfig() {
ATRACE_CALL();
if (mCheckPendingFence) {
- if (mPreviousPresentFence != Fence::NO_FENCE &&
- (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled)) {
+ if (previousFrameMissed()) {
// fence has not signaled yet. wait for the next invalidate
mEventQueue->invalidateForHWC();
return true;
@@ -1587,12 +1586,23 @@
setTransactionFlags(eDisplayTransactionNeeded);
}
+bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS {
+ // We are storing the last 2 present fences. If sf's phase offset is to be
+ // woken up before the actual vsync but targeting the next vsync, we need to check
+ // fence N-2
+ const sp<Fence>& fence =
+ mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
+ ? mPreviousPresentFences[0]
+ : mPreviousPresentFences[1];
+
+ return fence != Fence::NO_FENCE && (fence->getStatus() == Fence::Status::Unsignaled);
+}
+
void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
- bool frameMissed = mPreviousPresentFence != Fence::NO_FENCE &&
- (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled);
+ bool frameMissed = previousFrameMissed();
bool hwcFrameMissed = mHadDeviceComposition && frameMissed;
bool gpuFrameMissed = mHadClientComposition && frameMissed;
ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
@@ -1622,7 +1632,7 @@
}
// For now, only propagate backpressure when missing a hwc frame.
- if (hwcFrameMissed) {
+ if (hwcFrameMissed && !gpuFrameMissed) {
if (mPropagateBackpressure) {
signalLayerUpdate();
break;
@@ -1982,9 +1992,11 @@
}
getBE().mDisplayTimeline.updateSignalTimes();
- mPreviousPresentFence = displayDevice ? getHwComposer().getPresentFence(*displayDevice->getId())
- : Fence::NO_FENCE;
- auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
+ mPreviousPresentFences[1] = mPreviousPresentFences[0];
+ mPreviousPresentFences[0] = displayDevice
+ ? getHwComposer().getPresentFence(*displayDevice->getId())
+ : Fence::NO_FENCE;
+ auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]);
getBE().mDisplayTimeline.push(presentFenceTime);
DisplayStatInfo stats;
@@ -2075,12 +2087,18 @@
}
}
- mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
+ mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]);
mTransactionCompletedThread.sendCallbacks();
if (mLumaSampling && mRegionSamplingThread) {
mRegionSamplingThread->notifyNewContent();
}
+
+ // Even though ATRACE_INT64 already checks if tracing is enabled, it doesn't prevent the
+ // side-effect of getTotalSize(), so we check that again here
+ if (ATRACE_ENABLED()) {
+ ATRACE_INT64("Total Buffer Size", GraphicBufferAllocator::get().getTotalSize());
+ }
}
void SurfaceFlinger::computeLayerBounds() {
@@ -2932,6 +2950,13 @@
if (l->isRemovedFromCurrentState()) {
latchAndReleaseBuffer(l);
}
+
+ // If the layer has been removed and has no parent, then it will not be reachable
+ // when traversing layers on screen. Add the layer to the offscreenLayers set to
+ // ensure we can copy its current to drawing state.
+ if (!l->getParent()) {
+ mOffscreenLayers.emplace(l.get());
+ }
}
mLayersPendingRemoval.clear();
}
@@ -2945,7 +2970,17 @@
// clear the "changed" flags in current state
mCurrentState.colorMatrixChanged = false;
- mDrawingState.traverseInZOrder([](Layer* layer) { layer->commitChildList(); });
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
+ layer->commitChildList();
+
+ // If the layer can be reached when traversing mDrawingState, then the layer is no
+ // longer offscreen. Remove the layer from the offscreenLayer set.
+ if (mOffscreenLayers.count(layer)) {
+ mOffscreenLayers.erase(layer);
+ }
+ });
+
+ commitOffscreenLayers();
});
mTransactionPending = false;
@@ -2973,6 +3008,18 @@
}
}
+void SurfaceFlinger::commitOffscreenLayers() {
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [](Layer* layer) {
+ uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
+ if (!trFlags) return;
+
+ layer->doTransaction(0);
+ layer->commitChildList();
+ });
+ }
+}
+
void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
Region& outDirtyRegion, Region& outOpaqueRegion) {
ATRACE_CALL();
@@ -3254,8 +3301,11 @@
break;
}
}
- if (needsProtected != renderEngine.isProtected() &&
- renderEngine.useProtectedContext(needsProtected)) {
+ if (needsProtected != renderEngine.isProtected()) {
+ renderEngine.useProtectedContext(needsProtected);
+ }
+ if (needsProtected != display->getRenderSurface()->isProtected() &&
+ needsProtected == renderEngine.isProtected()) {
display->getRenderSurface()->setProtected(needsProtected);
}
}
@@ -3473,29 +3523,42 @@
}
bool SurfaceFlinger::flushTransactionQueues() {
- Mutex::Autolock _l(mStateLock);
+ // to prevent onHandleDestroyed from being called while the lock is held,
+ // we must keep a copy of the transactions (specifically the composer
+ // states) around outside the scope of the lock
+ std::vector<const TransactionState> transactions;
bool flushedATransaction = false;
+ {
+ Mutex::Autolock _l(mStateLock);
- auto it = mTransactionQueues.begin();
- while (it != mTransactionQueues.end()) {
- auto& [applyToken, transactionQueue] = *it;
+ auto it = mTransactionQueues.begin();
+ while (it != mTransactionQueues.end()) {
+ auto& [applyToken, transactionQueue] = *it;
- while (!transactionQueue.empty()) {
- const auto&
- [states, displays, flags, desiredPresentTime, uncacheBuffer, listenerCallbacks,
- postTime, privileged] = transactionQueue.front();
- if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
- setTransactionFlags(eTransactionFlushNeeded);
- break;
+ while (!transactionQueue.empty()) {
+ const auto& transaction = transactionQueue.front();
+ if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime,
+ transaction.states)) {
+ setTransactionFlags(eTransactionFlushNeeded);
+ break;
+ }
+ transactions.push_back(transaction);
+ applyTransactionState(transaction.states, transaction.displays, transaction.flags,
+ mPendingInputWindowCommands, transaction.desiredPresentTime,
+ transaction.buffer, transaction.callback,
+ transaction.postTime, transaction.privileged,
+ /*isMainThread*/ true);
+ transactionQueue.pop();
+ flushedATransaction = true;
}
- applyTransactionState(states, displays, flags, mPendingInputWindowCommands,
- desiredPresentTime, uncacheBuffer, listenerCallbacks, postTime,
- privileged, /*isMainThread*/ true);
- transactionQueue.pop();
- flushedATransaction = true;
- }
- it = (transactionQueue.empty()) ? mTransactionQueues.erase(it) : std::next(it, 1);
+ if (transactionQueue.empty()) {
+ it = mTransactionQueues.erase(it);
+ mTransactionCV.broadcast();
+ } else {
+ std::next(it, 1);
+ }
+ }
}
return flushedATransaction;
}
@@ -3568,7 +3631,22 @@
}
// If its TransactionQueue already has a pending TransactionState or if it is pending
- if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
+ auto itr = mTransactionQueues.find(applyToken);
+ // if this is an animation frame, wait until prior animation frame has
+ // been applied by SF
+ if (flags & eAnimation) {
+ while (itr != mTransactionQueues.end()) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ ALOGW_IF(err == TIMED_OUT,
+ "setTransactionState timed out "
+ "waiting for animation frame to apply");
+ break;
+ }
+ itr = mTransactionQueues.find(applyToken);
+ }
+ }
+ if (itr != mTransactionQueues.end() ||
!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
uncacheBuffer, listenerCallbacks, postTime,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 72e2ff9..5871774 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -308,7 +308,10 @@
const sp<IGraphicBufferProducer>& bufferProducer) const;
inline void onLayerCreated() { mNumLayers++; }
- inline void onLayerDestroyed() { mNumLayers--; }
+ inline void onLayerDestroyed(Layer* layer) {
+ mNumLayers--;
+ mOffscreenLayers.erase(layer);
+ }
TransactionCompletedThread& getTransactionCompletedThread() {
return mTransactionCompletedThread;
@@ -563,6 +566,7 @@
uint32_t setTransactionFlags(uint32_t flags, Scheduler::TransactionStart transactionStart);
void latchAndReleaseBuffer(const sp<Layer>& layer);
void commitTransaction() REQUIRES(mStateLock);
+ void commitOffscreenLayers();
bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
const Vector<ComposerState>& states);
@@ -824,6 +828,8 @@
return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
}
+ bool previousFrameMissed();
+
/*
* Debugging & dumpsys
*/
@@ -956,7 +962,7 @@
std::vector<sp<Layer>> mLayersWithQueuedFrames;
// Tracks layers that need to update a display's dirty region.
std::vector<sp<Layer>> mLayersPendingRefresh;
- sp<Fence> mPreviousPresentFence = Fence::NO_FENCE;
+ std::array<sp<Fence>, 2> mPreviousPresentFences = {Fence::NO_FENCE, Fence::NO_FENCE};
// True if in the previous frame at least one layer was composed via the GPU.
bool mHadClientComposition = false;
// True if in the previous frame at least one layer was composed via HW Composer.
@@ -1150,6 +1156,12 @@
// Flag used to set override allowed display configs from backdoor
bool mDebugDisplayConfigSetByBackdoor = false;
+
+ // A set of layers that have no parent so they are not drawn on screen.
+ // Should only be accessed by the main thread.
+ // The Layer pointer is removed from the set when the destructor is called so there shouldn't
+ // be any issues with a raw pointer referencing an invalid object.
+ std::unordered_set<Layer*> mOffscreenLayers;
};
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
index cfa8337..96121bb 100644
--- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -49,6 +49,8 @@
// refresh rates, to properly update the offsets.
void setRefreshRateType(RefreshRateConfigs::RefreshRateType /*refreshRateType*/) override {}
+ nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; }
+
// Returns current offsets in human friendly format.
void dump(std::string& /*result*/) const override {}
};