Merge "Use updated AppOps API in SensorService"
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index bbf4f8d..c6f656b 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -54,6 +54,7 @@
ReparentChildrenChange reparent_children = 20;
BackgroundBlurRadiusChange background_blur_radius = 21;
ShadowRadiusChange shadow_radius = 22;
+ BlurRegionsChange blur_regions = 23;
}
}
@@ -207,6 +208,23 @@
required float radius = 1;
}
+message BlurRegionsChange {
+ repeated BlurRegionChange blur_regions = 1;
+}
+
+message BlurRegionChange {
+ required uint32 blur_radius = 1;
+ required float corner_radius_tl = 2;
+ required float corner_radius_tr = 3;
+ required float corner_radius_bl = 4;
+ required float corner_radius_br = 5;
+ required float alpha = 6;
+ required int32 left = 7;
+ required int32 top = 8;
+ required int32 right = 9;
+ required int32 bottom = 10;
+}
+
message Origin {
required int32 pid = 1;
required int32 uid = 2;
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index c186801..5849212 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -423,6 +423,9 @@
case SurfaceChange::SurfaceChangeCase::kShadowRadius:
setShadowRadiusChange(transaction, change.id(), change.shadow_radius());
break;
+ case SurfaceChange::SurfaceChangeCase::kBlurRegions:
+ setBlurRegionsChange(transaction, change.id(), change.blur_regions());
+ break;
default:
status = 1;
break;
@@ -728,3 +731,24 @@
layer_id id, const ShadowRadiusChange& c) {
t.setShadowRadius(mLayers[id], c.radius());
}
+
+void Replayer::setBlurRegionsChange(SurfaceComposerClient::Transaction& t,
+ layer_id id, const BlurRegionsChange& c) {
+ std::vector<BlurRegion> regions;
+ for(size_t i=0; i < c.blur_regions_size(); i++) {
+ auto protoRegion = c.blur_regions(i);
+ regions.push_back(BlurRegion{
+ .blurRadius = protoRegion.blur_radius(),
+ .alpha = protoRegion.alpha(),
+ .cornerRadiusTL = protoRegion.corner_radius_tl(),
+ .cornerRadiusTR = protoRegion.corner_radius_tr(),
+ .cornerRadiusBL = protoRegion.corner_radius_bl(),
+ .cornerRadiusBR = protoRegion.corner_radius_br(),
+ .left = protoRegion.left(),
+ .top = protoRegion.top(),
+ .right = protoRegion.right(),
+ .bottom = protoRegion.bottom()
+ });
+ }
+ t.setBlurRegions(mLayers[id], regions);
+}
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index e439718..a22262a 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -96,6 +96,8 @@
layer_id id, const CornerRadiusChange& cc);
void setBackgroundBlurRadius(SurfaceComposerClient::Transaction& t,
layer_id id, const BackgroundBlurRadiusChange& cc);
+ void setBlurRegions(SurfaceComposerClient::Transaction& t,
+ layer_id id, const BlurRegionsChange& cc);
void setMatrix(SurfaceComposerClient::Transaction& t,
layer_id id, const MatrixChange& mc);
void setTransparentRegionHint(SurfaceComposerClient::Transaction& t,
@@ -120,6 +122,8 @@
layer_id id, const ReparentChildrenChange& c);
void setShadowRadiusChange(SurfaceComposerClient::Transaction& t,
layer_id id, const ShadowRadiusChange& c);
+ void setBlurRegionsChange(SurfaceComposerClient::Transaction& t,
+ layer_id id, const BlurRegionsChange& c);
void setDisplaySurface(SurfaceComposerClient::Transaction& t,
display_id id, const DispSurfaceChange& dsc);
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 4333126..9722f36 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -147,6 +147,20 @@
SAFE_PARCEL(output.writeUint32, fixedTransformHint);
SAFE_PARCEL(output.writeUint64, frameNumber);
SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId);
+
+ SAFE_PARCEL(output.writeUint32, blurRegions.size());
+ for (auto region : blurRegions) {
+ SAFE_PARCEL(output.writeUint32, region.blurRadius);
+ SAFE_PARCEL(output.writeFloat, region.cornerRadiusTL);
+ SAFE_PARCEL(output.writeFloat, region.cornerRadiusTR);
+ SAFE_PARCEL(output.writeFloat, region.cornerRadiusBL);
+ SAFE_PARCEL(output.writeFloat, region.cornerRadiusBR);
+ SAFE_PARCEL(output.writeFloat, region.alpha);
+ SAFE_PARCEL(output.writeInt32, region.left);
+ SAFE_PARCEL(output.writeInt32, region.top);
+ SAFE_PARCEL(output.writeInt32, region.right);
+ SAFE_PARCEL(output.writeInt32, region.bottom);
+ }
return NO_ERROR;
}
@@ -252,6 +266,24 @@
fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
SAFE_PARCEL(input.readUint64, &frameNumber);
SAFE_PARCEL(input.readInt64, &frameTimelineVsyncId);
+
+ uint32_t numRegions = 0;
+ SAFE_PARCEL(input.readUint32, &numRegions);
+ blurRegions.clear();
+ for (uint32_t i = 0; i < numRegions; i++) {
+ BlurRegion region;
+ SAFE_PARCEL(input.readUint32, ®ion.blurRadius);
+ SAFE_PARCEL(input.readFloat, ®ion.cornerRadiusTL);
+ SAFE_PARCEL(input.readFloat, ®ion.cornerRadiusTR);
+ SAFE_PARCEL(input.readFloat, ®ion.cornerRadiusBL);
+ SAFE_PARCEL(input.readFloat, ®ion.cornerRadiusBR);
+ SAFE_PARCEL(input.readFloat, ®ion.alpha);
+ SAFE_PARCEL(input.readInt32, ®ion.left);
+ SAFE_PARCEL(input.readInt32, ®ion.top);
+ SAFE_PARCEL(input.readInt32, ®ion.right);
+ SAFE_PARCEL(input.readInt32, ®ion.bottom);
+ blurRegions.push_back(region);
+ }
return NO_ERROR;
}
@@ -375,6 +407,10 @@
what |= eBackgroundBlurRadiusChanged;
backgroundBlurRadius = other.backgroundBlurRadius;
}
+ if (other.what & eBlurRegionsChanged) {
+ what |= eBlurRegionsChanged;
+ blurRegions = other.blurRegions;
+ }
if (other.what & eDeferTransaction_legacy) {
what |= eDeferTransaction_legacy;
barrierSurfaceControl_legacy = other.barrierSurfaceControl_legacy;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 32f9695..039e900 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1017,6 +1017,18 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBlurRegions(
+ const sp<SurfaceControl>& sc, const std::vector<BlurRegion>& blurRegions) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eBlurRegionsChanged;
+ s->blurRegions = blurRegions;
+ return *this;
+}
+
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(
const sp<SurfaceControl>& sc, const sp<SurfaceControl>& barrierSurfaceControl,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index ff3a87d..a73d9a6 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -51,6 +51,7 @@
#include <gui/LayerMetadata.h>
#include <gui/SurfaceControl.h>
#include <math/vec3.h>
+#include <ui/BlurRegion.h>
#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -128,6 +129,7 @@
eFixedTransformHintChanged = 0x200'00000000,
eFrameNumberChanged = 0x400'00000000,
eFrameTimelineVsyncChanged = 0x800'00000000,
+ eBlurRegionsChanged = 0x1000'00000000,
};
layer_state_t();
@@ -186,6 +188,7 @@
int32_t api;
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
+ std::vector<BlurRegion> blurRegions;
#ifndef NO_INPUT
sp<InputWindowHandle> inputHandle = new InputWindowHandle();
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 13abed2..73909a3 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -29,6 +29,7 @@
#include <utils/SortedVector.h>
#include <utils/threads.h>
+#include <ui/BlurRegion.h>
#include <ui/ConfigStoreTypes.h>
#include <ui/DisplayedFrameStats.h>
#include <ui/FrameStats.h>
@@ -439,6 +440,8 @@
Transaction& setCornerRadius(const sp<SurfaceControl>& sc, float cornerRadius);
Transaction& setBackgroundBlurRadius(const sp<SurfaceControl>& sc,
int backgroundBlurRadius);
+ Transaction& setBlurRegions(const sp<SurfaceControl>& sc,
+ const std::vector<BlurRegion>& regions);
Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p);
// Defers applying any changes made in this transaction until the Layer
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 95e9367..d8d989e 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -21,6 +21,7 @@
#include <math/mat4.h>
#include <math/vec3.h>
#include <renderengine/Texture.h>
+#include <ui/BlurRegion.h>
#include <ui/Fence.h>
#include <ui/FloatRect.h>
#include <ui/GraphicBuffer.h>
@@ -151,6 +152,8 @@
ShadowSettings shadow;
int backgroundBlurRadius = 0;
+
+ std::vector<BlurRegion> blurRegions;
};
// Keep in sync with custom comparison function in
@@ -182,7 +185,29 @@
lhs.length == rhs.length && lhs.casterIsTranslucent == rhs.casterIsTranslucent;
}
+static inline bool operator==(const BlurRegion& lhs, const BlurRegion& rhs) {
+ return lhs.alpha == rhs.alpha && lhs.cornerRadiusTL == rhs.cornerRadiusTL &&
+ lhs.cornerRadiusTR == rhs.cornerRadiusTR && lhs.cornerRadiusBL == rhs.cornerRadiusBL &&
+ lhs.cornerRadiusBR == rhs.cornerRadiusBR && lhs.blurRadius == rhs.blurRadius &&
+ lhs.left == rhs.left && lhs.top == rhs.top && lhs.right == rhs.right &&
+ lhs.bottom == rhs.bottom;
+}
+
+static inline bool operator!=(const BlurRegion& lhs, const BlurRegion& rhs) {
+ return !(lhs == rhs);
+}
+
static inline bool operator==(const LayerSettings& lhs, const LayerSettings& rhs) {
+ if (lhs.blurRegions.size() != rhs.blurRegions.size()) {
+ return false;
+ }
+ const auto size = lhs.blurRegions.size();
+ for (size_t i = 0; i < size; i++) {
+ if (lhs.blurRegions[i] != rhs.blurRegions[i]) {
+ return false;
+ }
+ }
+
return lhs.geometry == rhs.geometry && lhs.source == rhs.source && lhs.alpha == rhs.alpha &&
lhs.sourceDataspace == rhs.sourceDataspace &&
lhs.colorTransform == rhs.colorTransform &&
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 69ad189..03c8e80 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -23,6 +23,14 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
+#include <sync/sync.h>
+#include <ui/BlurRegion.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Trace.h>
+#include "../gl/GLExtensions.h"
+#include "SkiaGLRenderEngine.h"
+#include "filters/BlurFilter.h"
+
#include <GrContextOptions.h>
#include <SkCanvas.h>
#include <SkColorFilter.h>
@@ -500,10 +508,25 @@
SkPaint paint;
const auto& bounds = layer->geometry.boundaries;
const auto dest = getSkRect(bounds);
+ std::unordered_map<uint32_t, sk_sp<SkSurface>> cachedBlurs;
- if (layer->backgroundBlurRadius > 0) {
- ATRACE_NAME("BackgroundBlur");
- mBlurFilter->draw(canvas, surface, layer->backgroundBlurRadius);
+ if (mBlurFilter) {
+ if (layer->backgroundBlurRadius > 0) {
+ ATRACE_NAME("BackgroundBlur");
+ auto blurredSurface =
+ mBlurFilter->draw(canvas, surface, layer->backgroundBlurRadius);
+ cachedBlurs[layer->backgroundBlurRadius] = blurredSurface;
+ }
+ if (layer->blurRegions.size() > 0) {
+ for (auto region : layer->blurRegions) {
+ if (cachedBlurs[region.blurRadius]) {
+ continue;
+ }
+ ATRACE_NAME("BlurRegion");
+ auto blurredSurface = mBlurFilter->generate(canvas, surface, region.blurRadius);
+ cachedBlurs[region.blurRadius] = blurredSurface;
+ }
+ }
}
if (layer->source.buffer.buffer) {
@@ -571,7 +594,11 @@
} else {
ATRACE_NAME("DrawColor");
const auto color = layer->source.solidColor;
- paint.setColor(SkColor4f{.fR = color.r, .fG = color.g, .fB = color.b, layer->alpha});
+ paint.setShader(SkShaders::Color(SkColor4f{.fR = color.r,
+ .fG = color.g,
+ .fB = color.b,
+ layer->alpha},
+ nullptr));
}
paint.setColorFilter(SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)));
@@ -580,6 +607,10 @@
canvas->save();
canvas->concat(getSkM44(layer->geometry.positionTransform));
+ for (const auto effectRegion : layer->blurRegions) {
+ drawBlurRegion(canvas, effectRegion, dest, cachedBlurs[effectRegion.blurRadius]);
+ }
+
if (layer->shadow.length > 0) {
const auto rect = layer->geometry.roundedCornersRadius > 0
? getSkRect(layer->geometry.roundedCornersCrop)
@@ -592,6 +623,7 @@
} else {
canvas->drawRect(dest, paint);
}
+
canvas->restore();
}
{
@@ -678,6 +710,34 @@
flags);
}
+void SkiaGLRenderEngine::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
+ const SkRect& layerBoundaries,
+ sk_sp<SkSurface> blurredSurface) {
+ ATRACE_CALL();
+ SkPaint paint;
+ paint.setAlpha(static_cast<int>(effectRegion.alpha * 255));
+ const auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
+ effectRegion.bottom);
+
+ const auto matrix = mBlurFilter->getShaderMatrix(
+ SkMatrix::MakeTrans(layerBoundaries.left(), layerBoundaries.top()));
+ paint.setShader(blurredSurface->makeImageSnapshot()->makeShader(matrix));
+
+ if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 ||
+ effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) {
+ const SkVector radii[4] =
+ {SkVector::Make(effectRegion.cornerRadiusTL, effectRegion.cornerRadiusTL),
+ SkVector::Make(effectRegion.cornerRadiusTR, effectRegion.cornerRadiusTR),
+ SkVector::Make(effectRegion.cornerRadiusBL, effectRegion.cornerRadiusBL),
+ SkVector::Make(effectRegion.cornerRadiusBR, effectRegion.cornerRadiusBR)};
+ SkRRect roundedRect;
+ roundedRect.setRectRadii(rect, radii);
+ canvas->drawRRect(roundedRect, paint);
+ } else {
+ canvas->drawRect(rect, paint);
+ }
+}
+
EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
EGLContext shareContext, bool useContextPriority,
Protection protection) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index ed4ba11..0143445 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -75,6 +75,8 @@
bool waitFence(base::unique_fd fenceFd);
void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
const ShadowSettings& shadowSettings);
+ void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& layerBounds,
+ sk_sp<SkSurface> blurrendSurface);
EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 8704b3a..f6a316f 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -55,8 +55,10 @@
mBlurEffect = std::move(blurEffect);
}
-void BlurFilter::draw(SkCanvas* canvas, sk_sp<SkSurface> input, const uint32_t blurRadius) const {
+sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
+ const uint32_t blurRadius) const {
ATRACE_CALL();
+
// Kawase is an approximation of Gaussian, but it behaves differently from it.
// A radius transformation is required for approximating them, and also to introduce
// non-integer steps, necessary to smoothly interpolate large radii.
@@ -111,25 +113,35 @@
drawSurface->getCanvas()->drawIRect(scaledInfo.bounds(), paint);
// Swap buffers for next iteration
- auto tmp = drawSurface;
+ const auto tmp = drawSurface;
drawSurface = readSurface;
readSurface = tmp;
blurBuilder.child("input") = nullptr;
}
lastDrawTarget = readSurface;
}
+ lastDrawTarget->flushAndSubmit();
+ return lastDrawTarget;
+}
- drawSurface->flushAndSubmit();
+sk_sp<SkSurface> BlurFilter::draw(SkCanvas* canvas, const sk_sp<SkSurface> input,
+ const uint32_t blurRadius) const {
+ ATRACE_CALL();
+ auto surface = generate(canvas, input, blurRadius);
- // do the final composition, with alpha blending to hide downscaling artifacts.
- {
- SkPaint paint;
- paint.setShader(lastDrawTarget->makeImageSnapshot()->makeShader(
- SkMatrix::MakeScale(kInverseInputScale)));
- paint.setFilterQuality(kLow_SkFilterQuality);
- paint.setAlpha(std::min(1.0f, (float)blurRadius / kMaxCrossFadeRadius) * 255);
- canvas->drawIRect(SkIRect::MakeWH(input->width(), input->height()), paint);
- }
+ SkPaint paint;
+ const auto image = surface->makeImageSnapshot();
+ paint.setShader(image->makeShader(SkMatrix::MakeScale(kInverseInputScale)));
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ paint.setAlpha(std::min(1.0f, (float)blurRadius / kMaxCrossFadeRadius) * 255);
+ canvas->drawIRect(SkIRect::MakeWH(input->width(), input->height()), paint);
+ return surface;
+}
+
+SkMatrix BlurFilter::getShaderMatrix(const SkMatrix& transformMatrix) const {
+ SkMatrix matrix;
+ matrix.setConcat(transformMatrix, SkMatrix::MakeScale(kInverseInputScale));
+ return matrix;
}
} // namespace skia
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
index 94b3673..6f973d7 100644
--- a/libs/renderengine/skia/filters/BlurFilter.h
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -47,8 +47,14 @@
explicit BlurFilter();
virtual ~BlurFilter(){};
- // Execute blur passes, rendering to a canvas.
- void draw(SkCanvas* canvas, sk_sp<SkSurface> input, const uint32_t radius) const;
+ // Execute blur, saving it to a texture
+ sk_sp<SkSurface> generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
+ const uint32_t radius) const;
+ // Same as generate but also drawing to the screen
+ sk_sp<SkSurface> draw(SkCanvas* canvas, const sk_sp<SkSurface> input,
+ const uint32_t radius) const;
+ // Returns a matrix that should be applied to the blur shader
+ SkMatrix getShaderMatrix(const SkMatrix& transformMatrix) const;
private:
sk_sp<SkRuntimeEffect> mBlurEffect;
diff --git a/libs/ui/include/ui/BlurRegion.h b/libs/ui/include/ui/BlurRegion.h
new file mode 100644
index 0000000..c5a5d47
--- /dev/null
+++ b/libs/ui/include/ui/BlurRegion.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+
+namespace android {
+
+struct BlurRegion {
+ uint32_t blurRadius;
+ float cornerRadiusTL;
+ float cornerRadiusTR;
+ float cornerRadiusBL;
+ float cornerRadiusBR;
+ float alpha;
+ int left;
+ int top;
+ int right;
+ int bottom;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp b/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp
index afde5f7..f5c5a5a 100644
--- a/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp
+++ b/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp
@@ -52,7 +52,7 @@
// Fuzzer for Serialization operations, this is mostly just lifted from the
// existing test cases to use fuzzed values as inputs.
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+void FuzzSerializeDeserialize(const uint8_t* data, size_t size) {
FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
Payload result;
@@ -106,6 +106,183 @@
Deserialize(&vec_val, &result);
Serialize(t1_val, &result);
Deserialize(&t1_val, &result);
+}
+
+void FuzzDeserializeUint8(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ Payload buffer = {ENCODING_TYPE_UINT8, fdp.ConsumeIntegral<uint8_t>()};
+ std::uint8_t result;
+ Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeUint16(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ Payload buffer = {ENCODING_TYPE_UINT16, fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>()};
+ std::uint16_t result;
+ Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeUint32(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ Payload buffer = {ENCODING_TYPE_UINT32, fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>()};
+ std::uint32_t result;
+ Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeUint64(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ Payload buffer = {
+ ENCODING_TYPE_UINT64, fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(), fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(), fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(), fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>()};
+ std::uint64_t result;
+ Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeInt8(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ Payload buffer = {ENCODING_TYPE_INT8, fdp.ConsumeIntegral<uint8_t>()};
+ std::int8_t result;
+ Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeInt16(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ Payload buffer = {ENCODING_TYPE_INT16, fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>()};
+ std::int16_t result;
+ Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeInt32(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ Payload buffer = {ENCODING_TYPE_INT32, fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>()};
+ std::int32_t result;
+ Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeInt64(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ Payload buffer = {ENCODING_TYPE_INT64,
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>()};
+ std::int64_t result;
+ Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeFloat32(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ Payload buffer = {ENCODING_TYPE_FLOAT32, fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>()};
+ float floatResult;
+ Deserialize(&floatResult, &buffer);
+
+ buffer.Rewind();
+ double doubleResult;
+ Deserialize(&doubleResult, &buffer);
+}
+
+void FuzzDeserializeFloat64(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ Payload buffer = {
+ ENCODING_TYPE_FLOAT64, fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(), fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(), fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(), fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>()};
+ double result;
+ Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeFixstr(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ std::string s_val = fdp.ConsumeRemainingBytesAsString();
+ Payload buffer = {ENCODING_TYPE_FIXSTR_MAX};
+ for (std::string::iterator iter = s_val.begin(); iter != s_val.end();
+ iter++) {
+ buffer.Append(1, *iter);
+ }
+ std::string result;
+ Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeFixmap(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ Payload buffer = {ENCODING_TYPE_FIXMAP_MAX};
+ // Fill the map with the fuzzed data, not attempting to
+ // make a valid map
+ while (fdp.remaining_bytes() > 0) {
+ buffer.Append(1, fdp.ConsumeIntegral<uint8_t>());
+ }
+
+ std::map<std::uint32_t, std::uint32_t> result;
+ Deserialize(&result, &buffer);
+
+ buffer.Rewind();
+ std::unordered_map<std::uint32_t, std::uint32_t> unorderedResult;
+ Deserialize(&unorderedResult, &buffer);
+}
+
+void FuzzDeserializeVariant(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ Payload buffer = {ENCODING_TYPE_INT16,
+ ENCODING_TYPE_FLOAT32,
+ ENCODING_TYPE_FIXSTR_MAX,
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>(),
+ fdp.ConsumeIntegral<uint8_t>()};
+ // Add the rest of the data as a string
+ std::string s_val = fdp.ConsumeRemainingBytesAsString();
+ for (std::string::iterator iter = s_val.begin(); iter != s_val.end();
+ iter++) {
+ buffer.Append(1, *iter);
+ }
+ Variant<int, float, std::string> result;
+ Deserialize(&result, &buffer);
+}
+
+// Attempts to deserialize fuzzed data as various types
+void FuzzDeserialize(const uint8_t* data, size_t size) {
+ FuzzDeserializeUint8(data, size);
+ FuzzDeserializeUint16(data, size);
+ FuzzDeserializeUint32(data, size);
+ FuzzDeserializeUint64(data, size);
+ FuzzDeserializeInt8(data, size);
+ FuzzDeserializeInt16(data, size);
+ FuzzDeserializeInt32(data, size);
+ FuzzDeserializeInt64(data, size);
+ FuzzDeserializeFloat32(data, size);
+ FuzzDeserializeFloat64(data, size);
+ FuzzDeserializeFixstr(data, size);
+ FuzzDeserializeFixmap(data, size);
+ FuzzDeserializeVariant(data, size);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzSerializeDeserialize(data, size);
+ FuzzDeserialize(data, size);
return 0;
}
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 9c3fdbb..d302f98 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -204,8 +204,8 @@
layer.frameNumber = mCurrentFrameNumber;
layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
- // TODO: we could be more subtle with isFixedSize()
- const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
+ const bool useFiltering =
+ targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering();
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
@@ -822,6 +822,10 @@
}
}
+bool BufferLayer::bufferNeedsFiltering() const {
+ return isFixedSize();
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index e6a0f81..deaf846 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -115,6 +115,10 @@
ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; }
+ // Returns true if the transformed buffer size does not match the layer size and we need
+ // to apply filtering.
+ virtual bool bufferNeedsFiltering() const;
+
protected:
struct BufferInfo {
nsecs_t mDesiredPresentTime;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index ec828d4..9ab2974 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -442,7 +442,8 @@
}
auto surfaceFrame =
- mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId);
+ mFlinger->mFrameTimeline->createSurfaceFrameForToken(mOwnerUid, mName, mName,
+ mFrameTimelineVsyncId);
surfaceFrame->setActualQueueTime(systemTime());
mQueueItems.push_back({item, std::move(surfaceFrame)});
@@ -480,7 +481,8 @@
}
auto surfaceFrame =
- mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId);
+ mFlinger->mFrameTimeline->createSurfaceFrameForToken(mOwnerUid, mName, mName,
+ mFrameTimelineVsyncId);
surfaceFrame->setActualQueueTime(systemTime());
mQueueItems[mQueueItems.size() - 1].item = item;
mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 6f344c7..a64b243 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -277,7 +277,7 @@
const int32_t layerId = getSequence();
mFlinger->mTimeStats->setPostTime(layerId, mCurrentState.frameNumber, getName().c_str(),
- postTime);
+ mOwnerUid, postTime);
desiredPresentTime = desiredPresentTime <= 0 ? 0 : desiredPresentTime;
mCurrentState.desiredPresentTime = desiredPresentTime;
@@ -744,6 +744,31 @@
static_cast<float>(s.active.transform.ty() + s.active.h)),
radius);
}
+
+bool BufferStateLayer::bufferNeedsFiltering() const {
+ const State& s(getDrawingState());
+ if (!s.buffer) {
+ return false;
+ }
+
+ uint32_t bufferWidth = s.buffer->width;
+ uint32_t bufferHeight = s.buffer->height;
+
+ // Undo any transformations on the buffer and return the result.
+ if (s.transform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+
+ if (s.transformToDisplayInverse) {
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
+ if (invTransform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+ }
+
+ const Rect layerSize{getBounds()};
+ return layerSize.width() != bufferWidth || layerSize.height() != bufferHeight;
+}
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 4773286..104a13b 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -143,6 +143,8 @@
bool willPresentCurrentTransaction() const;
+ bool bufferNeedsFiltering() const override;
+
static const std::array<float, 16> IDENTITY_MATRIX;
std::unique_ptr<renderengine::Image> mTextureImage;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 77400eb..5a3b9ac 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -20,6 +20,7 @@
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
+#include <ui/BlurRegion.h>
#include <ui/FloatRect.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -118,6 +119,9 @@
// length of the shadow in screen space
float shadowRadius{0.f};
+ // List of regions that require blur
+ std::vector<BlurRegion> blurRegions;
+
/*
* Geometry state
*/
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index c625b2e..3852f45 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -669,7 +669,8 @@
compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const {
compositionengine::OutputLayer* layerRequestingBgComposition = nullptr;
for (auto* layer : getOutputLayersOrderedByZ()) {
- if (layer->getLayerFE().getCompositionState()->backgroundBlurRadius > 0) {
+ if (layer->getLayerFE().getCompositionState()->backgroundBlurRadius > 0 ||
+ layer->getLayerFE().getCompositionState()->blurRegions.size() > 0) {
layerRequestingBgComposition = layer;
}
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 3dd1839..9badb99 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -4014,6 +4014,34 @@
mOutput->updateAndWriteCompositionState(args);
}
+TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) {
+ InjectedLayer layer1;
+ InjectedLayer layer2;
+ InjectedLayer layer3;
+
+ // Layer requesting blur, or below, should request client composition.
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(false));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(false));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(false));
+
+ BlurRegion region;
+ layer2.layerFEState.blurRegions.push_back(region);
+
+ injectOutputLayer(layer1);
+ injectOutputLayer(layer2);
+ injectOutputLayer(layer3);
+
+ mOutput->editState().isEnabled = true;
+
+ CompositionRefreshArgs args;
+ args.updatingGeometryThisFrame = false;
+ args.devOptForceClientComposition = false;
+ mOutput->updateAndWriteCompositionState(args);
+}
+
TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenRequests) {
// In split-screen landscape mode, the screen is rotated 90 degrees, with
// one layer on the left covering the left side of the output, and one layer
diff --git a/services/surfaceflinger/FrameTimeline/Android.bp b/services/surfaceflinger/FrameTimeline/Android.bp
index 6ba4c43..e075d3e 100644
--- a/services/surfaceflinger/FrameTimeline/Android.bp
+++ b/services/surfaceflinger/FrameTimeline/Android.bp
@@ -5,10 +5,12 @@
"FrameTimeline.cpp",
],
shared_libs: [
+ "android.hardware.graphics.composer@2.4",
"libbase",
"libcutils",
"liblog",
"libgui",
+ "libtimestats",
"libui",
"libutils",
],
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 43176a3..996479c 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -93,19 +93,19 @@
}
}
-std::string toString(JankType jankType) {
+std::string toString(TimeStats::JankType jankType) {
switch (jankType) {
- case JankType::None:
+ case TimeStats::JankType::None:
return "None";
- case JankType::Display:
+ case TimeStats::JankType::Display:
return "Composer/Display - outside SF and App";
- case JankType::SurfaceFlingerDeadlineMissed:
+ case TimeStats::JankType::SurfaceFlingerDeadlineMissed:
return "SurfaceFlinger Deadline Missed";
- case JankType::AppDeadlineMissed:
+ case TimeStats::JankType::AppDeadlineMissed:
return "App Deadline Missed";
- case JankType::PredictionExpired:
+ case TimeStats::JankType::PredictionExpired:
return "Prediction Expired";
- case JankType::SurfaceFlingerEarlyLatch:
+ case TimeStats::JankType::SurfaceFlingerEarlyLatch:
return "SurfaceFlinger Early Latch";
default:
return "Unclassified";
@@ -177,15 +177,18 @@
}
}
-SurfaceFrame::SurfaceFrame(const std::string& layerName, PredictionState predictionState,
+SurfaceFrame::SurfaceFrame(uid_t ownerUid, std::string layerName, std::string debugName,
+ PredictionState predictionState,
frametimeline::TimelineItem&& predictions)
- : mLayerName(layerName),
+ : mOwnerUid(ownerUid),
+ mLayerName(std::move(layerName)),
+ mDebugName(std::move(debugName)),
mPresentState(PresentState::Unknown),
mPredictionState(predictionState),
mPredictions(predictions),
mActuals({0, 0, 0}),
mActualQueueTime(0),
- mJankType(JankType::None),
+ mJankType(TimeStats::JankType::None),
mJankMetadata(0) {}
void SurfaceFrame::setPresentState(PresentState state) {
@@ -227,17 +230,25 @@
mActuals.presentTime = presentTime;
}
-void SurfaceFrame::setJankInfo(JankType jankType, int32_t jankMetadata) {
+void SurfaceFrame::setJankInfo(TimeStats::JankType jankType, int32_t jankMetadata) {
std::lock_guard<std::mutex> lock(mMutex);
mJankType = jankType;
mJankMetadata = jankMetadata;
}
-JankType SurfaceFrame::getJankType() const {
+TimeStats::JankType SurfaceFrame::getJankType() const {
std::lock_guard<std::mutex> lock(mMutex);
return mJankType;
}
+uid_t SurfaceFrame::getOwnerUid() const {
+ return mOwnerUid;
+}
+
+const std::string& SurfaceFrame::getName() const {
+ return mLayerName;
+}
+
nsecs_t SurfaceFrame::getBaseTime() const {
std::lock_guard<std::mutex> lock(mMutex);
nsecs_t baseTime = std::numeric_limits<nsecs_t>::max();
@@ -267,8 +278,8 @@
void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) {
std::lock_guard<std::mutex> lock(mMutex);
StringAppendF(&result, "%s", indent.c_str());
- StringAppendF(&result, "Layer - %s", mLayerName.c_str());
- if (mJankType != JankType::None) {
+ StringAppendF(&result, "Layer - %s", mDebugName.c_str());
+ if (mJankType != TimeStats::JankType::None) {
// Easily identify a janky Surface Frame in the dump
StringAppendF(&result, " [*] ");
}
@@ -285,33 +296,35 @@
dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
}
-FrameTimeline::FrameTimeline()
+FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats)
: mCurrentDisplayFrame(std::make_shared<DisplayFrame>()),
- mMaxDisplayFrames(kDefaultMaxDisplayFrames) {}
+ mMaxDisplayFrames(kDefaultMaxDisplayFrames),
+ mTimeStats(std::move(timeStats)) {}
FrameTimeline::DisplayFrame::DisplayFrame()
: surfaceFlingerPredictions(TimelineItem()),
surfaceFlingerActuals(TimelineItem()),
predictionState(PredictionState::None),
- jankType(JankType::None),
+ jankType(TimeStats::JankType::None),
jankMetadata(0) {
this->surfaceFrames.reserve(kNumSurfaceFramesInitial);
}
std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
- const std::string& layerName, std::optional<int64_t> token) {
+ uid_t uid, std::string layerName, std::string debugName, std::optional<int64_t> token) {
ATRACE_CALL();
if (!token) {
- return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::None,
- TimelineItem());
+ return std::make_unique<impl::SurfaceFrame>(uid, std::move(layerName), std::move(debugName),
+ PredictionState::None, TimelineItem());
}
std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token);
if (predictions) {
- return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Valid,
+ return std::make_unique<impl::SurfaceFrame>(uid, std::move(layerName), std::move(debugName),
+ PredictionState::Valid,
std::move(*predictions));
}
- return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Expired,
- TimelineItem());
+ return std::make_unique<impl::SurfaceFrame>(uid, std::move(layerName), std::move(debugName),
+ PredictionState::Expired, TimelineItem());
}
void FrameTimeline::addSurfaceFrame(
@@ -359,6 +372,7 @@
}
}
if (signalTime != Fence::SIGNAL_TIME_INVALID) {
+ int32_t totalJankReasons = TimeStats::JankType::None;
auto& displayFrame = pendingPresentFence.second;
displayFrame->surfaceFlingerActuals.presentTime = signalTime;
@@ -377,21 +391,26 @@
displayFrame->jankMetadata |= EarlyFinish;
}
- if (displayFrame->jankMetadata & EarlyFinish & EarlyPresent) {
- displayFrame->jankType = JankType::SurfaceFlingerEarlyLatch;
- } else if (displayFrame->jankMetadata & LateFinish & LatePresent) {
- displayFrame->jankType = JankType::SurfaceFlingerDeadlineMissed;
+ if ((displayFrame->jankMetadata & EarlyFinish) &&
+ (displayFrame->jankMetadata & EarlyPresent)) {
+ displayFrame->jankType = TimeStats::JankType::SurfaceFlingerEarlyLatch;
+ } else if ((displayFrame->jankMetadata & LateFinish) &&
+ (displayFrame->jankMetadata & LatePresent)) {
+ displayFrame->jankType = TimeStats::JankType::SurfaceFlingerDeadlineMissed;
} else if (displayFrame->jankMetadata & EarlyPresent ||
displayFrame->jankMetadata & LatePresent) {
// Cases where SF finished early but frame was presented late and vice versa
- displayFrame->jankType = JankType::Display;
+ displayFrame->jankType = TimeStats::JankType::Display;
}
}
+
if (std::abs(sfActuals.startTime - sfPredictions.startTime) > kSFStartThreshold) {
displayFrame->jankMetadata |=
sfActuals.startTime > sfPredictions.startTime ? LateStart : EarlyStart;
}
+ totalJankReasons |= displayFrame->jankType;
+
for (auto& surfaceFrame : displayFrame->surfaceFrames) {
if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) {
// Only presented SurfaceFrames need to be updated
@@ -401,13 +420,13 @@
const auto& predictionState = surfaceFrame->getPredictionState();
if (predictionState == PredictionState::Expired) {
// Jank analysis cannot be done on apps that don't use predictions
- surfaceFrame->setJankInfo(JankType::PredictionExpired, 0);
+ surfaceFrame->setJankInfo(TimeStats::JankType::PredictionExpired, 0);
continue;
} else if (predictionState == PredictionState::Valid) {
const auto& actuals = surfaceFrame->getActuals();
const auto& predictions = surfaceFrame->getPredictions();
int32_t jankMetadata = 0;
- JankType jankType = JankType::None;
+ TimeStats::JankType jankType = TimeStats::JankType::None;
if (std::abs(actuals.endTime - predictions.endTime) > kDeadlineThreshold) {
jankMetadata |= actuals.endTime > predictions.endTime ? LateFinish
: EarlyFinish;
@@ -419,19 +438,26 @@
: EarlyPresent;
}
if (jankMetadata & EarlyPresent) {
- jankType = JankType::SurfaceFlingerEarlyLatch;
+ jankType = TimeStats::JankType::SurfaceFlingerEarlyLatch;
} else if (jankMetadata & LatePresent) {
if (jankMetadata & EarlyFinish) {
// TODO(b/169890654): Classify this properly
- jankType = JankType::Display;
+ jankType = TimeStats::JankType::Display;
} else {
- jankType = JankType::AppDeadlineMissed;
+ jankType = TimeStats::JankType::AppDeadlineMissed;
}
}
+
+ totalJankReasons |= jankType;
+ mTimeStats->incrementJankyFrames(surfaceFrame->getOwnerUid(),
+ surfaceFrame->getName(),
+ jankType | displayFrame->jankType);
surfaceFrame->setJankInfo(jankType, jankMetadata);
}
}
}
+
+ mTimeStats->incrementJankyFrames(totalJankReasons);
}
mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i));
@@ -467,7 +493,7 @@
void FrameTimeline::dumpDisplayFrame(std::string& result,
const std::shared_ptr<DisplayFrame>& displayFrame,
nsecs_t baseTime) {
- if (displayFrame->jankType != JankType::None) {
+ if (displayFrame->jankType != TimeStats::JankType::None) {
// Easily identify a janky Display Frame in the dump
StringAppendF(&result, " [*] ");
}
@@ -501,11 +527,11 @@
nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : findBaseTime(mDisplayFrames[0]);
for (size_t i = 0; i < mDisplayFrames.size(); i++) {
const auto& displayFrame = mDisplayFrames[i];
- if (displayFrame->jankType == JankType::None) {
+ if (displayFrame->jankType == TimeStats::JankType::None) {
// Check if any Surface Frame has been janky
bool isJanky = false;
for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
- if (surfaceFrame->getJankType() != JankType::None) {
+ if (surfaceFrame->getJankType() != TimeStats::JankType::None) {
isJanky = true;
break;
}
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index bd637df..33821e5 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -16,9 +16,7 @@
#pragma once
-#include <deque>
-#include <mutex>
-
+#include <../TimeStats/TimeStats.h>
#include <gui/ISurfaceComposer.h>
#include <ui/FenceTime.h>
#include <utils/RefBase.h>
@@ -26,26 +24,10 @@
#include <utils/Timers.h>
#include <utils/Vector.h>
-namespace android::frametimeline {
+#include <deque>
+#include <mutex>
-/*
- * The type of jank that is associated with a Display/Surface frame
- */
-enum class JankType {
- // No Jank
- None,
- // Jank not related to SurfaceFlinger or the App
- Display,
- // SF took too long on the CPU
- SurfaceFlingerDeadlineMissed,
- // Either App or GPU took too long on the frame
- AppDeadlineMissed,
- // Predictions live for 120ms, if prediction is expired for a frame, there is definitely a jank
- // associated with the App if this is for a SurfaceFrame, and SF for a DisplayFrame.
- PredictionExpired,
- // Latching a buffer early might cause an early present of the frame
- SurfaceFlingerEarlyLatch,
-};
+namespace android::frametimeline {
enum JankMetadata {
// Frame was presented earlier than expected
@@ -147,8 +129,10 @@
// Create a new surface frame, set the predictions based on a token and return it to the caller.
// Sets the PredictionState of SurfaceFrame.
+ // Debug name is the human-readable debugging string for dumpsys.
virtual std::unique_ptr<SurfaceFrame> createSurfaceFrameForToken(
- const std::string& layerName, std::optional<int64_t> token) = 0;
+ uid_t uid, std::string layerName, std::string debugName,
+ std::optional<int64_t> token) = 0;
// Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be
// composited into one display frame.
@@ -206,8 +190,8 @@
class SurfaceFrame : public android::frametimeline::SurfaceFrame {
public:
- SurfaceFrame(const std::string& layerName, PredictionState predictionState,
- TimelineItem&& predictions);
+ SurfaceFrame(uid_t uid, std::string layerName, std::string debugName,
+ PredictionState predictionState, TimelineItem&& predictions);
~SurfaceFrame() = default;
TimelineItem getPredictions() const override { return mPredictions; };
@@ -221,32 +205,37 @@
void setAcquireFenceTime(nsecs_t acquireFenceTime) override;
void setPresentState(PresentState state) override;
void setActualPresentTime(nsecs_t presentTime);
- void setJankInfo(JankType jankType, int32_t jankMetadata);
- JankType getJankType() const;
+ void setJankInfo(TimeStats::JankType jankType, int32_t jankMetadata);
+ TimeStats::JankType getJankType() const;
nsecs_t getBaseTime() const;
+ uid_t getOwnerUid() const;
+ const std::string& getName() const;
// All the timestamps are dumped relative to the baseTime
void dump(std::string& result, const std::string& indent, nsecs_t baseTime);
private:
+ const uid_t mOwnerUid;
const std::string mLayerName;
+ const std::string mDebugName;
PresentState mPresentState GUARDED_BY(mMutex);
const PredictionState mPredictionState;
const TimelineItem mPredictions;
TimelineItem mActuals GUARDED_BY(mMutex);
nsecs_t mActualQueueTime GUARDED_BY(mMutex);
mutable std::mutex mMutex;
- JankType mJankType GUARDED_BY(mMutex); // Enum for the type of jank
+ TimeStats::JankType mJankType GUARDED_BY(mMutex); // Enum for the type of jank
int32_t mJankMetadata GUARDED_BY(mMutex); // Additional details about the jank
};
class FrameTimeline : public android::frametimeline::FrameTimeline {
public:
- FrameTimeline();
+ FrameTimeline(std::shared_ptr<TimeStats> timeStats);
~FrameTimeline() = default;
frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
std::unique_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken(
- const std::string& layerName, std::optional<int64_t> token) override;
+ uid_t ownerUid, std::string layerName, std::string debugName,
+ std::optional<int64_t> token) override;
void addSurfaceFrame(std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame,
SurfaceFrame::PresentState state) override;
void setSfWakeUp(int64_t token, nsecs_t wakeupTime) override;
@@ -278,7 +267,7 @@
std::vector<std::unique_ptr<SurfaceFrame>> surfaceFrames;
PredictionState predictionState;
- JankType jankType = JankType::None; // Enum for the type of jank
+ TimeStats::JankType jankType = TimeStats::JankType::None; // Enum for the type of jank
int32_t jankMetadata = 0x0; // Additional details about the jank
};
@@ -300,6 +289,7 @@
TokenManager mTokenManager;
std::mutex mMutex;
uint32_t mMaxDisplayFrames;
+ std::shared_ptr<TimeStats> mTimeStats;
static constexpr uint32_t kDefaultMaxDisplayFrames = 64;
// The initial container size for the vector<SurfaceFrames> inside display frame. Although this
// number doesn't represent any bounds on the number of surface frames that can go in a display
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f657a00..ffae56f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -482,6 +482,7 @@
compositionState->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
compositionState->alpha = alpha;
compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
+ compositionState->blurRegions = drawingState.blurRegions;
}
void Layer::prepareGeometryCompositionState() {
@@ -550,7 +551,8 @@
isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
// Force client composition for special cases known only to the front-end.
- if (isHdrY410() || usesRoundedCorners || drawShadows()) {
+ if (isHdrY410() || usesRoundedCorners || drawShadows() ||
+ getDrawingState().blurRegions.size() > 0) {
compositionState->forceClientComposition = true;
}
}
@@ -646,6 +648,7 @@
layerSettings.alpha = alpha;
layerSettings.sourceDataspace = getDataSpace();
layerSettings.backgroundBlurRadius = getBackgroundBlurRadius();
+ layerSettings.blurRegions = getBlurRegions();
return layerSettings;
}
@@ -897,7 +900,8 @@
: std::make_optional(stateToCommit->frameTimelineVsyncId);
auto surfaceFrame =
- mFlinger->mFrameTimeline->createSurfaceFrameForToken(mTransactionName, vsyncId);
+ mFlinger->mFrameTimeline->createSurfaceFrameForToken(getOwnerUid(), mName,
+ mTransactionName, vsyncId);
surfaceFrame->setActualQueueTime(stateToCommit->postTime);
// For transactions we set the acquire fence time to the post time as we
// don't have a buffer. For BufferStateLayer it is overridden in
@@ -1285,6 +1289,14 @@
return true;
}
+bool Layer::setBlurRegions(const std::vector<BlurRegion>& blurRegions) {
+ mCurrentState.sequence++;
+ mCurrentState.blurRegions = blurRegions;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
bool Layer::setFlags(uint8_t flags, uint8_t mask) {
const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
if (mCurrentState.flags == newFlags) return false;
@@ -1728,7 +1740,7 @@
FrameEventHistoryDelta* outDelta) {
if (newTimestamps) {
mFlinger->mTimeStats->setPostTime(getSequence(), newTimestamps->frameNumber,
- getName().c_str(), newTimestamps->postedTime);
+ getName().c_str(), mOwnerUid, newTimestamps->postedTime);
mFlinger->mTimeStats->setAcquireFence(getSequence(), newTimestamps->frameNumber,
newTimestamps->acquireFence);
}
@@ -2172,6 +2184,10 @@
return getDrawingState().backgroundBlurRadius;
}
+const std::vector<BlurRegion>& Layer::getBlurRegions() const {
+ return getDrawingState().blurRegions;
+}
+
Layer::RoundedCornerState Layer::getRoundedCornerState() const {
const auto& p = mDrawingParent.promote();
if (p != nullptr) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 7112cbc..5cb56a5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -26,6 +26,7 @@
#include <renderengine/Mesh.h>
#include <renderengine/Texture.h>
#include <sys/types.h>
+#include <ui/BlurRegion.h>
#include <ui/FloatRect.h>
#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
@@ -255,6 +256,9 @@
// be rendered around the layer.
float shadowRadius;
+ // Layer regions that are made of custom materials, like frosted glass
+ std::vector<BlurRegion> blurRegions;
+
// Priority of the layer assigned by Window Manager.
int32_t frameRateSelectionPriority;
@@ -391,6 +395,7 @@
// When non-zero, everything below this layer will be blurred by backgroundBlurRadius, which
// is specified in pixels.
virtual bool setBackgroundBlurRadius(int backgroundBlurRadius);
+ virtual bool setBlurRegions(const std::vector<BlurRegion>& effectRegions);
virtual bool setTransparentRegionHint(const Region& transparent);
virtual bool setFlags(uint8_t flags, uint8_t mask);
virtual bool setLayerStack(uint32_t layerStack);
@@ -1038,6 +1043,10 @@
// Can only be accessed with the SF state lock held.
std::unique_ptr<frametimeline::SurfaceFrame> mSurfaceFrame;
+ // The owner of the layer. If created from a non system process, it will be the calling uid.
+ // If created from a system process, the value can be passed in.
+ uid_t mOwnerUid;
+
private:
virtual void setTransformHint(ui::Transform::RotationFlags) {}
@@ -1096,10 +1105,6 @@
pid_t mCallingPid;
uid_t mCallingUid;
- // The owner of the layer. If created from a non system process, it will be the calling uid.
- // If created from a system process, the value can be passed in.
- uid_t mOwnerUid;
-
// The current layer is a clone of mClonedFrom. This means that this layer will update it's
// properties based on mClonedFrom. When mClonedFrom latches a new buffer for BufferLayers,
// this layer will update it's buffer. When mClonedFrom updates it's drawing state, children,
@@ -1110,6 +1115,9 @@
// final shadow radius for this layer. If a shadow is specified for a layer, then effective
// shadow radius is the set shadow radius, otherwise its the parent's shadow radius.
float mEffectiveShadowRadius = 0.f;
+
+ // A list of regions on this layer that should have blurs.
+ const std::vector<BlurRegion>& getBlurRegions() const;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3977e2b..fde38c9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -331,7 +331,7 @@
mInterceptor(mFactory.createSurfaceInterceptor()),
mTimeStats(std::make_shared<impl::TimeStats>()),
mFrameTracer(std::make_unique<FrameTracer>()),
- mFrameTimeline(std::make_unique<frametimeline::impl::FrameTimeline>()),
+ mFrameTimeline(std::make_unique<frametimeline::impl::FrameTimeline>(mTimeStats)),
mEventQueue(mFactory.createMessageQueue()),
mCompositionEngine(mFactory.createCompositionEngine()),
mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
@@ -3684,6 +3684,9 @@
if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs && mSupportsBlur) {
if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded;
}
+ if (what & layer_state_t::eBlurRegionsChanged) {
+ if (layer->setBlurRegions(s.blurRegions)) flags |= eTraversalNeeded;
+ }
if (what & layer_state_t::eLayerStackChanged) {
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
// We only allow setting layer stacks for top level layers,
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 2d5566f..3548923 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -140,6 +140,7 @@
addCropLocked(transaction, layerId, layer->mCurrentState.crop_legacy);
addCornerRadiusLocked(transaction, layerId, layer->mCurrentState.cornerRadius);
addBackgroundBlurRadiusLocked(transaction, layerId, layer->mCurrentState.backgroundBlurRadius);
+ addBlurRegionsLocked(transaction, layerId, layer->mCurrentState.blurRegions);
if (layer->mCurrentState.barrierLayer_legacy != nullptr) {
addDeferTransactionLocked(transaction, layerId,
layer->mCurrentState.barrierLayer_legacy.promote(),
@@ -361,6 +362,25 @@
blurRadiusChange->set_background_blur_radius(backgroundBlurRadius);
}
+void SurfaceInterceptor::addBlurRegionsLocked(Transaction* transaction, int32_t layerId,
+ const std::vector<BlurRegion>& blurRegions) {
+ SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
+ BlurRegionsChange* blurRegionsChange(change->mutable_blur_regions());
+ for (const auto blurRegion : blurRegions) {
+ const auto blurRegionChange = blurRegionsChange->add_blur_regions();
+ blurRegionChange->set_blur_radius(blurRegion.blurRadius);
+ blurRegionChange->set_corner_radius_tl(blurRegion.cornerRadiusTL);
+ blurRegionChange->set_corner_radius_tr(blurRegion.cornerRadiusTR);
+ blurRegionChange->set_corner_radius_bl(blurRegion.cornerRadiusBL);
+ blurRegionChange->set_corner_radius_br(blurRegion.cornerRadiusBR);
+ blurRegionChange->set_alpha(blurRegion.alpha);
+ blurRegionChange->set_left(blurRegion.left);
+ blurRegionChange->set_top(blurRegion.top);
+ blurRegionChange->set_right(blurRegion.right);
+ blurRegionChange->set_bottom(blurRegion.bottom);
+ }
+}
+
void SurfaceInterceptor::addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
const sp<const Layer>& layer, uint64_t frameNumber)
{
@@ -456,6 +476,9 @@
if (state.what & layer_state_t::eBackgroundBlurRadiusChanged) {
addBackgroundBlurRadiusLocked(transaction, layerId, state.backgroundBlurRadius);
}
+ if (state.what & layer_state_t::eBlurRegionsChanged) {
+ addBlurRegionsLocked(transaction, layerId, state.blurRegions);
+ }
if (state.what & layer_state_t::eDeferTransaction_legacy) {
sp<Layer> otherLayer = nullptr;
if (state.barrierSurfaceControl_legacy != nullptr) {
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 97ff547..3df79c6 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -165,6 +165,8 @@
void addCornerRadiusLocked(Transaction* transaction, int32_t layerId, float cornerRadius);
void addBackgroundBlurRadiusLocked(Transaction* transaction, int32_t layerId,
int32_t backgroundBlurRadius);
+ void addBlurRegionsLocked(Transaction* transaction, int32_t layerId,
+ const std::vector<BlurRegion>& effectRegions);
void addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
const sp<const Layer>& layer, uint64_t frameNumber);
void addSurfaceChangesLocked(Transaction* transaction, const layer_state_t& state);
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 37194c6..fe9e737 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -14,9 +14,6 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
#undef LOG_TAG
#define LOG_TAG "TimeStats"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -33,6 +30,8 @@
#include <algorithm>
#include <chrono>
+#include "timestatsproto/TimeStatsHelper.h"
+
namespace android {
namespace impl {
@@ -115,6 +114,13 @@
mMaxPulledHistogramBuckets);
mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)renderEngineTimingBytes.c_str(),
renderEngineTimingBytes.size());
+
+ mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalFrames);
+ mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalJankyFrames);
+ mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFLongCpu);
+ mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFLongGpu);
+ mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFUnattributed);
+ mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalAppUnattributed);
mStatsDelegate->statsEventBuild(event);
clearGlobalLocked();
@@ -160,6 +166,13 @@
mStatsDelegate->statsEventWriteInt64(event, layer->lateAcquireFrames);
mStatsDelegate->statsEventWriteInt64(event, layer->badDesiredPresentFrames);
+ mStatsDelegate->statsEventWriteInt32(event, layer->uid);
+ mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalFrames);
+ mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalJankyFrames);
+ mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFLongCpu);
+ mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFLongGpu);
+ mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFUnattributed);
+ mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalAppUnattributed);
mStatsDelegate->statsEventBuild(event);
}
@@ -397,11 +410,13 @@
timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
if (prevTimeRecord.ready) {
+ uid_t uid = layerRecord.uid;
const std::string& layerName = layerRecord.layerName;
- if (!mTimeStats.stats.count(layerName)) {
- mTimeStats.stats[layerName].layerName = layerName;
+ if (!mTimeStats.stats.count({uid, layerName})) {
+ mTimeStats.stats[{uid, layerName}].uid = uid;
+ mTimeStats.stats[{uid, layerName}].layerName = layerName;
}
- TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[layerName];
+ TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[{uid, layerName}];
timeStatsLayer.totalFrames++;
timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
timeStatsLayer.lateAcquireFrames += layerRecord.lateAcquireFrames;
@@ -462,8 +477,13 @@
layerName.compare(0, kMinLenLayerName, kPopupWindowPrefix) != 0;
}
+bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName) {
+ return mTimeStats.stats.count({uid, layerName}) > 0 ||
+ mTimeStats.stats.size() < MAX_NUM_LAYER_STATS;
+}
+
void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
- nsecs_t postTime) {
+ uid_t uid, nsecs_t postTime) {
if (!mEnabled.load()) return;
ATRACE_CALL();
@@ -471,11 +491,12 @@
postTime);
std::lock_guard<std::mutex> lock(mMutex);
- if (!mTimeStats.stats.count(layerName) && mTimeStats.stats.size() >= MAX_NUM_LAYER_STATS) {
+ if (!canAddNewAggregatedStats(uid, layerName)) {
return;
}
if (!mTimeStatsTracker.count(layerId) && mTimeStatsTracker.size() < MAX_NUM_LAYER_RECORDS &&
layerNameIsValid(layerName)) {
+ mTimeStatsTracker[layerId].uid = uid;
mTimeStatsTracker[layerId].layerName = layerName;
}
if (!mTimeStatsTracker.count(layerId)) return;
@@ -655,6 +676,66 @@
flushAvailableRecordsToStatsLocked(layerId);
}
+template <class T>
+static void updateJankPayload(T& t, int32_t reasons) {
+ t.jankPayload.totalFrames++;
+
+ static const constexpr int32_t kValidJankyReason =
+ TimeStats::JankType::SurfaceFlingerDeadlineMissed |
+ TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed |
+ TimeStats::JankType::AppDeadlineMissed | TimeStats::JankType::Display;
+ if (reasons & kValidJankyReason) {
+ t.jankPayload.totalJankyFrames++;
+ if ((reasons & TimeStats::JankType::SurfaceFlingerDeadlineMissed) != 0) {
+ t.jankPayload.totalSFLongCpu++;
+ }
+ if ((reasons & TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed) != 0) {
+ t.jankPayload.totalSFLongGpu++;
+ }
+ if ((reasons & TimeStats::JankType::Display) != 0) {
+ t.jankPayload.totalSFUnattributed++;
+ }
+ if ((reasons & TimeStats::JankType::AppDeadlineMissed) != 0) {
+ t.jankPayload.totalAppUnattributed++;
+ }
+ }
+}
+
+void TimeStats::incrementJankyFrames(int32_t reasons) {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ updateJankPayload<TimeStatsHelper::TimeStatsGlobal>(mTimeStats, reasons);
+}
+
+void TimeStats::incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ // Only update layer stats if we're allowed to do so.
+ // As an implementation detail, we do this because this method is expected to be
+ // called from FrameTimeline, which is allowed to do jank analysis well after a frame is
+ // presented. This means that we can't rely on TimeStats to flush layer records over to the
+ // aggregated stats.
+ if (!canAddNewAggregatedStats(uid, layerName)) {
+ return;
+ }
+
+ // Defensively initialize the stats in case FrameTimeline flushes its signaled present fences
+ // before TimeStats does.
+ if (!mTimeStats.stats.count({uid, layerName})) {
+ mTimeStats.stats[{uid, layerName}].uid = uid;
+ mTimeStats.stats[{uid, layerName}].layerName = layerName;
+ }
+
+ TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[{uid, layerName}];
+ updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, reasons);
+}
+
void TimeStats::onDestroy(int32_t layerId) {
ATRACE_CALL();
ALOGV("[%d]-onDestroy", layerId);
@@ -860,6 +941,7 @@
mTimeStats.presentToPresent.hist.clear();
mTimeStats.frameDuration.hist.clear();
mTimeStats.renderEngineTiming.hist.clear();
+ mTimeStats.jankPayload = TimeStatsHelper::JankPayload();
mTimeStats.refreshRateStats.clear();
mPowerTime.prevTime = systemTime();
mGlobalRecord.prevPresentTime = 0;
@@ -905,6 +987,3 @@
} // namespace impl
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 8de5d0c..4fa0a02 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -17,6 +17,7 @@
#pragma once
// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#include <cstdint>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
@@ -85,7 +86,7 @@
const std::shared_ptr<FenceTime>& readyFence) = 0;
virtual void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
- nsecs_t postTime) = 0;
+ uid_t uid, nsecs_t postTime) = 0;
virtual void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) = 0;
// Reasons why latching a particular buffer may be skipped
enum class LatchSkipReason {
@@ -108,6 +109,40 @@
virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) = 0;
virtual void setPresentFence(int32_t layerId, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& presentFence) = 0;
+
+ // Subset of jank metadata tracked by FrameTimeline for the purpose of funneling to telemetry.
+ enum JankType {
+ // No Jank
+ None = 0x0,
+ // Jank not related to SurfaceFlinger or the App
+ Display = 0x1,
+ // SF took too long on the CPU
+ SurfaceFlingerDeadlineMissed = 0x2,
+ // SF took too long on the GPU
+ SurfaceFlingerGpuDeadlineMissed = 0x4,
+ // Either App or GPU took too long on the frame
+ AppDeadlineMissed = 0x8,
+ // Predictions live for 120ms, if prediction is expired for a frame, there is definitely a
+ // jank
+ // associated with the App if this is for a SurfaceFrame, and SF for a DisplayFrame.
+ PredictionExpired = 0x10,
+ // Latching a buffer early might cause an early present of the frame
+ SurfaceFlingerEarlyLatch = 0x20,
+ };
+
+ // Increments janky frames, tracked globally. Because FrameTimeline is the infrastructure
+ // responsible for computing jank in the system, this is expected to be called from
+ // FrameTimeline, rather than directly from SurfaceFlinger or individual layers. If there are no
+ // jank reasons, then total frames are incremented but jank is not, for accurate accounting of
+ // janky frames.
+ virtual void incrementJankyFrames(int32_t reasons) = 0;
+ // Increments janky frames, blamed to the provided {uid, layerName} key, with JankMetadata as
+ // supplementary reasons for the jank. Because FrameTimeline is the infrastructure responsible
+ // for computing jank in the system, this is expected to be called from FrameTimeline, rather
+ // than directly from SurfaceFlinger or individual layers.
+ // If there are no jank reasons, then total frames are incremented but jank is not, for accurate
+ // accounting of janky frames.
+ virtual void incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) = 0;
// Clean up the layer record
virtual void onDestroy(int32_t layerId) = 0;
// If SF skips or rejects a buffer, remove the corresponding TimeRecord.
@@ -142,6 +177,7 @@
};
struct LayerRecord {
+ uid_t uid;
std::string layerName;
// This is the index in timeRecords, at which the timestamps for that
// specific frame are still not fully received. This is not waiting for
@@ -241,7 +277,7 @@
void recordRenderEngineDuration(nsecs_t startTime,
const std::shared_ptr<FenceTime>& readyFence) override;
- void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
+ void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, uid_t uid,
nsecs_t postTime) override;
void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) override;
void incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) override;
@@ -253,6 +289,8 @@
void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) override;
void setPresentFence(int32_t layerId, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& presentFence) override;
+ void incrementJankyFrames(int32_t reasons) override;
+ void incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) override;
// Clean up the layer record
void onDestroy(int32_t layerId) override;
// If SF skips or rejects a buffer, remove the corresponding TimeRecord.
@@ -276,6 +314,7 @@
void flushAvailableRecordsToStatsLocked(int32_t layerId);
void flushPowerTimeLocked();
void flushAvailableGlobalRecordsToStatsLocked();
+ bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName);
void enable();
void disable();
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index d77387a..0fb748f 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -77,14 +77,28 @@
return result;
}
+std::string TimeStatsHelper::JankPayload::toString() const {
+ std::string result;
+ StringAppendF(&result, "totalTimelineFrames = %d\n", totalFrames);
+ StringAppendF(&result, "jankyFrames = %d\n", totalJankyFrames);
+ StringAppendF(&result, "sfLongCpuJankyFrames = %d\n", totalSFLongCpu);
+ StringAppendF(&result, "sfLongGpuJankyFrames = %d\n", totalSFLongGpu);
+ StringAppendF(&result, "sfUnattributedJankyFrame = %d\n", totalSFUnattributed);
+ StringAppendF(&result, "appUnattributedJankyFrame = %d\n", totalAppUnattributed);
+ return result;
+}
+
std::string TimeStatsHelper::TimeStatsLayer::toString() const {
std::string result = "\n";
+ StringAppendF(&result, "uid = %d\n", uid);
StringAppendF(&result, "layerName = %s\n", layerName.c_str());
StringAppendF(&result, "packageName = %s\n", packageName.c_str());
StringAppendF(&result, "totalFrames = %d\n", totalFrames);
StringAppendF(&result, "droppedFrames = %d\n", droppedFrames);
StringAppendF(&result, "lateAcquireFrames = %d\n", lateAcquireFrames);
StringAppendF(&result, "badDesiredPresentFrames = %d\n", badDesiredPresentFrames);
+ result.append("Jank payload for this layer:\n");
+ result.append(jankPayload.toString());
const auto iter = deltas.find("present2present");
if (iter != deltas.end()) {
const float averageTime = iter->second.averageTime();
@@ -110,6 +124,8 @@
StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitches);
StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChanges);
StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
+ result.append("Global aggregated jank payload:\n");
+ result.append(jankPayload.toString());
StringAppendF(&result, "displayConfigStats is as below:\n");
for (const auto& [fps, duration] : refreshRateStats) {
StringAppendF(&result, "%dfps = %ldms\n", fps, ns2ms(duration));
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 0c75f96..033eb5d 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -40,14 +40,28 @@
std::string toString() const;
};
+ struct JankPayload {
+ // note that transactions are counted for these frames.
+ int32_t totalFrames = 0;
+ int32_t totalJankyFrames = 0;
+ int32_t totalSFLongCpu = 0;
+ int32_t totalSFLongGpu = 0;
+ int32_t totalSFUnattributed = 0;
+ int32_t totalAppUnattributed = 0;
+
+ std::string toString() const;
+ };
+
class TimeStatsLayer {
public:
+ uid_t uid;
std::string layerName;
std::string packageName;
int32_t totalFrames = 0;
int32_t droppedFrames = 0;
int32_t lateAcquireFrames = 0;
int32_t badDesiredPresentFrames = 0;
+ JankPayload jankPayload;
std::unordered_map<std::string, Histogram> deltas;
std::string toString() const;
@@ -69,8 +83,17 @@
Histogram presentToPresent;
Histogram frameDuration;
Histogram renderEngineTiming;
- std::unordered_map<std::string, TimeStatsLayer> stats;
+
+ struct StatsHasher {
+ size_t operator()(const std::pair<uid_t, std::string>& p) const {
+ // Normally this isn't a very good hash function due to symmetry reasons,
+ // but these are distinct types so this should be good enough
+ return std::hash<uid_t>{}(p.first) ^ std::hash<std::string>{}(p.second);
+ }
+ };
+ std::unordered_map<std::pair<uid_t, std::string>, TimeStatsLayer, StatsHasher> stats;
std::unordered_map<uint32_t, nsecs_t> refreshRateStats;
+ JankPayload jankPayload;
std::string toString(std::optional<uint32_t> maxLayers) const;
SFTimeStatsGlobalProto toProto(std::optional<uint32_t> maxLayers) const;
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index f3f5626..9f25674 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -125,6 +125,9 @@
int32 background_blur_radius = 52;
uint32 owner_uid = 53;
+
+ // Regions of a layer, where blur should be applied.
+ repeated BlurRegion blur_regions = 54;
}
message PositionProto {
@@ -211,3 +214,16 @@
// This will be a 4x4 matrix of float values
repeated float val = 1;
}
+
+message BlurRegion {
+ uint32 blur_radius = 1;
+ uint32 corner_radius_tl = 2;
+ uint32 corner_radius_tr = 3;
+ uint32 corner_radius_bl = 4;
+ float corner_radius_br = 5;
+ float alpha = 6;
+ int32 left = 7;
+ int32 top = 8;
+ int32 right = 9;
+ int32 bottom = 10;
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index a5a569b..81e648a 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -51,6 +51,7 @@
constexpr float POSITION_UPDATE = 121;
const Rect CROP_UPDATE(16, 16, 32, 32);
const float SHADOW_RADIUS_UPDATE = 35.0f;
+std::vector<BlurRegion> BLUR_REGIONS_UPDATE;
const String8 DISPLAY_NAME("SurfaceInterceptor Display Test");
constexpr auto TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface";
@@ -181,6 +182,7 @@
bool cornerRadiusUpdateFound(const SurfaceChange& change, bool foundCornerRadius);
bool backgroundBlurRadiusUpdateFound(const SurfaceChange& change,
bool foundBackgroundBlurRadius);
+ bool blurRegionsUpdateFound(const SurfaceChange& change, bool foundBlurRegions);
bool matrixUpdateFound(const SurfaceChange& change, bool foundMatrix);
bool scalingModeUpdateFound(const SurfaceChange& change, bool foundScalingMode);
bool transparentRegionHintUpdateFound(const SurfaceChange& change, bool foundTransparentRegion);
@@ -219,6 +221,7 @@
void cropUpdate(Transaction&);
void cornerRadiusUpdate(Transaction&);
void backgroundBlurRadiusUpdate(Transaction&);
+ void blurRegionsUpdate(Transaction&);
void matrixUpdate(Transaction&);
void transparentRegionHintUpdate(Transaction&);
void layerStackUpdate(Transaction&);
@@ -357,6 +360,12 @@
t.setBackgroundBlurRadius(mBGSurfaceControl, BACKGROUND_BLUR_RADIUS_UPDATE);
}
+void SurfaceInterceptorTest::blurRegionsUpdate(Transaction& t) {
+ BLUR_REGIONS_UPDATE.empty();
+ BLUR_REGIONS_UPDATE.push_back(BlurRegion());
+ t.setBlurRegions(mBGSurfaceControl, BLUR_REGIONS_UPDATE);
+}
+
void SurfaceInterceptorTest::layerUpdate(Transaction& t) {
t.setLayer(mBGSurfaceControl, LAYER_UPDATE);
}
@@ -430,6 +439,7 @@
runInTransaction(&SurfaceInterceptorTest::alphaUpdate);
runInTransaction(&SurfaceInterceptorTest::cornerRadiusUpdate);
runInTransaction(&SurfaceInterceptorTest::backgroundBlurRadiusUpdate);
+ runInTransaction(&SurfaceInterceptorTest::blurRegionsUpdate);
runInTransaction(&SurfaceInterceptorTest::layerUpdate);
runInTransaction(&SurfaceInterceptorTest::cropUpdate);
runInTransaction(&SurfaceInterceptorTest::matrixUpdate);
@@ -518,6 +528,17 @@
return foundBackgroundBlur;
}
+bool SurfaceInterceptorTest::blurRegionsUpdateFound(const SurfaceChange& change,
+ bool foundBlurRegions) {
+ bool hasBlurRegions(change.blur_regions().blur_regions_size() == BLUR_REGIONS_UPDATE.size());
+ if (hasBlurRegions && !foundBlurRegions) {
+ foundBlurRegions = true;
+ } else if (hasBlurRegions && foundBlurRegions) {
+ []() { FAIL(); }();
+ }
+ return foundBlurRegions;
+}
+
bool SurfaceInterceptorTest::layerUpdateFound(const SurfaceChange& change, bool foundLayer) {
bool hasLayer(change.layer().layer() == LAYER_UPDATE);
if (hasLayer && !foundLayer) {
@@ -706,6 +727,9 @@
case SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius:
foundUpdate = backgroundBlurRadiusUpdateFound(change, foundUpdate);
break;
+ case SurfaceChange::SurfaceChangeCase::kBlurRegions:
+ foundUpdate = blurRegionsUpdateFound(change, foundUpdate);
+ break;
case SurfaceChange::SurfaceChangeCase::kMatrix:
foundUpdate = matrixUpdateFound(change, foundUpdate);
break;
@@ -889,6 +913,11 @@
SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius);
}
+TEST_F(SurfaceInterceptorTest, InterceptBlurRegionsUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::blurRegionsUpdate,
+ SurfaceChange::SurfaceChangeCase::kBlurRegions);
+}
+
TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix);
}
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 2861013..8d094e4 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -8,6 +8,7 @@
"FakeComposerUtils.cpp",
"SFFakeHwc_test.cpp"
],
+ require_root: true,
shared_libs: [
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 69efd7f..5e9d64a 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "gmock/gmock-spec-builders.h"
+#include "mock/MockTimeStats.h"
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
@@ -23,6 +25,11 @@
#include <cinttypes>
using namespace std::chrono_literals;
+using testing::Contains;
+
+MATCHER_P(HasBit, bit, "") {
+ return (arg & bit) != 0;
+}
namespace android::frametimeline {
@@ -41,7 +48,8 @@
}
void SetUp() override {
- mFrameTimeline = std::make_unique<impl::FrameTimeline>();
+ mTimeStats = std::make_shared<mock::TimeStats>();
+ mFrameTimeline = std::make_unique<impl::FrameTimeline>(mTimeStats);
mTokenManager = &mFrameTimeline->mTokenManager;
maxDisplayFrames = &mFrameTimeline->mMaxDisplayFrames;
maxTokenRetentionTime = mTokenManager->kMaxRetentionTime;
@@ -76,6 +84,7 @@
return static_cast<uint32_t>(mFrameTimeline->mDisplayFrames.size());
}
+ std::shared_ptr<mock::TimeStats> mTimeStats;
std::unique_ptr<impl::FrameTimeline> mFrameTimeline;
impl::TokenManager* mTokenManager;
FenceToFenceTimeMap fenceFactory;
@@ -83,6 +92,10 @@
nsecs_t maxTokenRetentionTime;
};
+static const std::string sLayerNameOne = "layer1";
+static const std::string sLayerNameTwo = "layer2";
+static constexpr const uid_t sUidOne = 0;
+
TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) {
int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0});
EXPECT_EQ(getPredictions().size(), 1);
@@ -99,21 +112,24 @@
}
TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) {
- auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", std::nullopt);
+ auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne,
+ sLayerNameOne, std::nullopt);
EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::None);
}
TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) {
int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0});
flushTokens(systemTime() + maxTokenRetentionTime);
- auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", token1);
+ auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne,
+ sLayerNameOne, token1);
EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Expired);
}
TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validToken) {
int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
- auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", token1);
+ auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne,
+ sLayerNameOne, token1);
EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Valid);
EXPECT_EQ(compareTimelineItems(surfaceFrame->getPredictions(), TimelineItem(10, 20, 30)), true);
@@ -125,7 +141,8 @@
int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
- auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken("layer1", token1);
+ auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne,
+ sLayerNameOne, token1);
// Set up the display frame
mFrameTimeline->setSfWakeUp(token1, 20);
@@ -148,8 +165,12 @@
int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 60});
- auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken("layer1", surfaceFrameToken1);
- auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken("layer2", surfaceFrameToken1);
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne, sLayerNameOne,
+ surfaceFrameToken1);
+ auto surfaceFrame2 =
+ mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameTwo, sLayerNameTwo,
+ surfaceFrameToken1);
mFrameTimeline->setSfWakeUp(sfToken1, 22);
mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
SurfaceFrame::PresentState::Presented);
@@ -168,7 +189,9 @@
// Trigger a flush by finalizing the next DisplayFrame
auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto surfaceFrame3 = mFrameTimeline->createSurfaceFrameForToken("layer1", surfaceFrameToken2);
+ auto surfaceFrame3 =
+ mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne, sLayerNameOne,
+ surfaceFrameToken2);
mFrameTimeline->setSfWakeUp(sfToken2, 52);
mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame3), SurfaceFrame::PresentState::Dropped);
mFrameTimeline->setSfPresent(56, presentFence2);
@@ -189,7 +212,9 @@
{10 + frameTimeFactor, 20 + frameTimeFactor, 30 + frameTimeFactor});
int64_t sfToken = mTokenManager->generateTokenForPredictions(
{22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor});
- auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", surfaceFrameToken);
+ auto surfaceFrame =
+ mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne, sLayerNameOne,
+ surfaceFrameToken);
mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor);
mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
SurfaceFrame::PresentState::Presented);
@@ -209,7 +234,9 @@
{10 + frameTimeFactor, 20 + frameTimeFactor, 30 + frameTimeFactor});
int64_t sfToken = mTokenManager->generateTokenForPredictions(
{22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor});
- auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", surfaceFrameToken);
+ auto surfaceFrame =
+ mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne, sLayerNameOne,
+ surfaceFrameToken);
mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor);
mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame), SurfaceFrame::PresentState::Presented);
mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
@@ -224,7 +251,8 @@
TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceAfterQueue) {
auto surfaceFrame =
- mFrameTimeline->createSurfaceFrameForToken("acquireFenceAfterQueue", std::nullopt);
+ mFrameTimeline->createSurfaceFrameForToken(0, "acquireFenceAfterQueue",
+ "acquireFenceAfterQueue", std::nullopt);
surfaceFrame->setActualQueueTime(123);
surfaceFrame->setAcquireFenceTime(456);
EXPECT_EQ(surfaceFrame->getActuals().endTime, 456);
@@ -232,7 +260,8 @@
TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceBeforeQueue) {
auto surfaceFrame =
- mFrameTimeline->createSurfaceFrameForToken("acquireFenceAfterQueue", std::nullopt);
+ mFrameTimeline->createSurfaceFrameForToken(0, "acquireFenceAfterQueue",
+ "acquireFenceAfterQueue", std::nullopt);
surfaceFrame->setActualQueueTime(456);
surfaceFrame->setAcquireFenceTime(123);
EXPECT_EQ(surfaceFrame->getActuals().endTime, 456);
@@ -244,7 +273,8 @@
// Size shouldn't exceed maxDisplayFrames - 64
for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
- auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", std::nullopt);
+ auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne,
+ sLayerNameOne, std::nullopt);
int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
mFrameTimeline->setSfWakeUp(sfToken, 22);
mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
@@ -258,7 +288,8 @@
EXPECT_EQ(*maxDisplayFrames, 256);
for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
- auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", std::nullopt);
+ auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne,
+ sLayerNameOne, std::nullopt);
int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
mFrameTimeline->setSfWakeUp(sfToken, 22);
mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
@@ -272,7 +303,8 @@
EXPECT_EQ(*maxDisplayFrames, 128);
for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
- auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", std::nullopt);
+ auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne,
+ sLayerNameOne, std::nullopt);
int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
mFrameTimeline->setSfWakeUp(sfToken, 22);
mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
@@ -281,4 +313,90 @@
}
EXPECT_EQ(getNumberOfDisplayFrames(), *maxDisplayFrames);
}
+
+TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(sUidOne, sLayerNameOne,
+ HasBit(TimeStats::JankType::SurfaceFlingerDeadlineMissed)));
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(HasBit(TimeStats::JankType::SurfaceFlingerDeadlineMissed)));
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne, sLayerNameOne,
+ surfaceFrameToken1);
+ mFrameTimeline->setSfWakeUp(sfToken1,
+ std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
+ mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+ SurfaceFrame::PresentState::Presented);
+ presentFence1->signalForTest(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
+
+ mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(59ms).count(),
+ presentFence1);
+}
+
+TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(sUidOne, sLayerNameOne, HasBit(TimeStats::JankType::Display)));
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(TimeStats::JankType::Display)));
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne, sLayerNameOne,
+ surfaceFrameToken1);
+ mFrameTimeline->setSfWakeUp(sfToken1,
+ std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
+ mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+ SurfaceFrame::PresentState::Presented);
+ presentFence1->signalForTest(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
+ mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(59ms).count(),
+ presentFence1);
+}
+
+TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(sUidOne, sLayerNameOne,
+ HasBit(TimeStats::JankType::AppDeadlineMissed)));
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(TimeStats::JankType::AppDeadlineMissed)));
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken(sUidOne, sLayerNameOne, sLayerNameOne,
+ surfaceFrameToken1);
+ surfaceFrame1->setAcquireFenceTime(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(45ms).count());
+ mFrameTimeline->setSfWakeUp(sfToken1,
+ std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
+
+ mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+ SurfaceFrame::PresentState::Presented);
+ presentFence1->signalForTest(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
+ mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
+ presentFence1);
+}
+
} // namespace android::frametimeline
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 0a24650..a90f424 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -58,6 +58,7 @@
#define FMT_STRING false
#define LAYER_ID_0 0
#define LAYER_ID_1 1
+#define UID_0 123
#define LAYER_ID_INVALID -1
#define NUM_LAYERS 1
#define NUM_LAYERS_INVALID "INVALID"
@@ -227,7 +228,8 @@
void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts) {
switch (type) {
case TimeStamp::POST:
- ASSERT_NO_FATAL_FAILURE(mTimeStats->setPostTime(id, frameNumber, genLayerName(id), ts));
+ ASSERT_NO_FATAL_FAILURE(
+ mTimeStats->setPostTime(id, frameNumber, genLayerName(id), UID_0, ts));
break;
case TimeStamp::ACQUIRE:
ASSERT_NO_FATAL_FAILURE(mTimeStats->setAcquireTime(id, frameNumber, ts));
@@ -349,6 +351,61 @@
EXPECT_THAT(result, HasSubstr(expectedResult));
}
+TEST_F(TimeStatsTest, canIncreaseJankyFrames) {
+ // this stat is not in the proto so verify by checking the string dump
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ mTimeStats->incrementJankyFrames(TimeStats::JankType::SurfaceFlingerDeadlineMissed);
+ mTimeStats->incrementJankyFrames(TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed);
+ mTimeStats->incrementJankyFrames(TimeStats::JankType::Display);
+ mTimeStats->incrementJankyFrames(TimeStats::JankType::AppDeadlineMissed);
+ mTimeStats->incrementJankyFrames(TimeStats::JankType::None);
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ std::string expectedResult = "totalTimelineFrames = " + std::to_string(5);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "jankyFrames = " + std::to_string(4);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfUnattributedJankyFrame = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "appUnattributedJankyFrame = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
+TEST_F(TimeStatsTest, canIncreaseJankyFramesForLayer) {
+ // this stat is not in the proto so verify by checking the string dump
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+ TimeStats::JankType::SurfaceFlingerDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+ TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), TimeStats::JankType::Display);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+ TimeStats::JankType::AppDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), TimeStats::JankType::None);
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ std::string expectedResult = "totalTimelineFrames = " + std::to_string(5);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "jankyFrames = " + std::to_string(4);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfUnattributedJankyFrame = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "appUnattributedJankyFrame = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) {
// this stat is not in the proto so verify by checking the string dump
constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2;
@@ -789,6 +846,16 @@
.count());
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+ TimeStats::JankType::SurfaceFlingerDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+ TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), TimeStats::JankType::Display);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+ TimeStats::JankType::AppDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), TimeStats::JankType::None);
+
EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
@@ -797,6 +864,11 @@
EXPECT_THAT(result, HasSubstr("compositionStrategyChanges = 0"));
EXPECT_THAT(result, HasSubstr("averageFrameDuration = 0.000 ms"));
EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 0.000 ms"));
+ EXPECT_THAT(result, HasSubstr("jankyFrames = 0"));
+ EXPECT_THAT(result, HasSubstr("sfLongCpuJankyFrames = 0"));
+ EXPECT_THAT(result, HasSubstr("sfLongGpuJankyFrames = 0"));
+ EXPECT_THAT(result, HasSubstr("sfUnattributedJankyFrame = 0"));
+ EXPECT_THAT(result, HasSubstr("appUnattributedJankyFrame = 0"));
}
TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
@@ -904,6 +976,8 @@
mTimeStats->incrementClientCompositionFrames();
}
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+
mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS);
mTimeStats->setPowerMode(PowerMode::ON);
mTimeStats->recordFrameDuration(1000000, 3000000);
@@ -913,6 +987,12 @@
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+ mTimeStats->incrementJankyFrames(TimeStats::JankType::SurfaceFlingerDeadlineMissed);
+ mTimeStats->incrementJankyFrames(TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed);
+ mTimeStats->incrementJankyFrames(TimeStats::JankType::Display);
+ mTimeStats->incrementJankyFrames(TimeStats::JankType::AppDeadlineMissed);
+ mTimeStats->incrementJankyFrames(TimeStats::JankType::None);
+
EXPECT_THAT(mDelegate->mAtomTags,
UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
android::util::SURFACEFLINGER_STATS_LAYER_INFO));
@@ -944,6 +1024,12 @@
expectedRenderEngineTiming.c_str(),
expectedRenderEngineTiming.size()),
expectedRenderEngineTiming.size()));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 5));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 4));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
}
EXPECT_EQ(AStatsManager_PULL_SUCCESS,
@@ -975,6 +1061,15 @@
}
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+ TimeStats::JankType::SurfaceFlingerDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+ TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), TimeStats::JankType::Display);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+ TimeStats::JankType::AppDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), TimeStats::JankType::None);
+
EXPECT_THAT(mDelegate->mAtomTags,
UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
android::util::SURFACEFLINGER_STATS_LAYER_INFO));
@@ -1033,6 +1128,14 @@
EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, LATE_ACQUIRE_FRAMES));
EXPECT_CALL(*mDelegate,
statsEventWriteInt64(mDelegate->mEvent, BAD_DESIRED_PRESENT_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, UID_0));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 5));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 4));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+
EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
}
EXPECT_EQ(AStatsManager_PULL_SUCCESS,
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index ff37ec8..99ec353 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -41,7 +41,7 @@
MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr<FenceTime>&));
- MOCK_METHOD4(setPostTime, void(int32_t, uint64_t, const std::string&, nsecs_t));
+ MOCK_METHOD5(setPostTime, void(int32_t, uint64_t, const std::string&, uid_t, nsecs_t));
MOCK_METHOD2(incrementLatchSkipped, void(int32_t layerId, LatchSkipReason reason));
MOCK_METHOD1(incrementBadDesiredPresent, void(int32_t layerId));
MOCK_METHOD3(setLatchTime, void(int32_t, uint64_t, nsecs_t));
@@ -50,6 +50,8 @@
MOCK_METHOD3(setAcquireFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
MOCK_METHOD3(setPresentTime, void(int32_t, uint64_t, nsecs_t));
MOCK_METHOD3(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
+ MOCK_METHOD1(incrementJankyFrames, void(int32_t));
+ MOCK_METHOD3(incrementJankyFrames, void(uid_t, const std::string&, int32_t));
MOCK_METHOD1(onDestroy, void(int32_t));
MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t));
MOCK_METHOD1(setPowerMode,