summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/Android.bp5
-rw-r--r--libs/hwui/HardwareBitmapUploader.cpp21
-rw-r--r--libs/hwui/Outline.h6
-rw-r--r--libs/hwui/RenderNode.cpp2
-rw-r--r--libs/hwui/RenderNode.h3
-rw-r--r--libs/hwui/hwui/AnimatedImageDrawable.cpp6
-rw-r--r--libs/hwui/hwui/ImageDecoder.cpp15
-rw-r--r--libs/hwui/hwui/ImageDecoder.h1
-rw-r--r--libs/hwui/pipeline/skia/ATraceMemoryDump.cpp11
-rw-r--r--libs/hwui/pipeline/skia/ReorderBarrierDrawables.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp6
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp10
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h4
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp5
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.h2
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp63
-rw-r--r--libs/hwui/renderthread/CanvasContext.h3
-rw-r--r--libs/hwui/renderthread/IRenderPipeline.h4
-rw-r--r--libs/hwui/renderthread/ReliableSurface.cpp265
-rw-r--r--libs/hwui/renderthread/ReliableSurface.h66
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp3
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp2
-rw-r--r--libs/hwui/service/GraphicsStatsService.cpp143
-rw-r--r--libs/hwui/service/GraphicsStatsService.h8
-rw-r--r--libs/hwui/tests/common/TestContext.cpp74
-rw-r--r--libs/hwui/tests/common/TestContext.h11
-rw-r--r--libs/hwui/tests/macrobench/TestSceneRunner.cpp8
-rw-r--r--libs/hwui/tests/unit/FatVectorTests.cpp2
-rw-r--r--libs/hwui/tests/unit/SkiaPipelineTests.cpp2
-rw-r--r--libs/hwui/utils/FatVector.h105
-rw-r--r--libs/incident/Android.bp69
-rw-r--r--libs/incident/include/incident/incident_report.h192
-rw-r--r--libs/incident/include_priv/android/os/IncidentReportArgs.h (renamed from libs/incident/include/android/os/IncidentReportArgs.h)10
-rw-r--r--libs/incident/libincident.map.txt15
-rw-r--r--libs/incident/src/incident_report.cpp83
-rw-r--r--libs/incident/tests/IncidentReportArgs_test.cpp74
-rw-r--r--libs/incident/tests/IncidentReportRequest_test.cpp65
-rw-r--r--libs/incident/tests/c_api_compile_test.c11
-rw-r--r--libs/input/PointerController.cpp33
-rw-r--r--libs/input/tests/PointerController_test.cpp54
-rw-r--r--libs/services/Android.bp1
-rw-r--r--libs/services/include/android/os/StatsDimensionsValue.h70
-rw-r--r--libs/services/src/os/StatsDimensionsValue.cpp126
44 files changed, 956 insertions, 707 deletions
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 51270f5bcebd..debb38b2c1b0 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -92,9 +92,12 @@ cc_defaults {
"libandroidfw",
"libcrypto",
"libsync",
+ "libstatspull",
+ "libstatssocket",
],
static_libs: [
"libEGL_blobCache",
+ "libprotoutil",
],
},
host: {
@@ -168,7 +171,6 @@ cc_defaults {
"renderthread/RenderTask.cpp",
"renderthread/TimeLord.cpp",
"hwui/AnimatedImageDrawable.cpp",
- "hwui/AnimatedImageThread.cpp",
"hwui/Bitmap.cpp",
"hwui/Canvas.cpp",
"hwui/ImageDecoder.cpp",
@@ -210,6 +212,7 @@ cc_defaults {
android: {
srcs: [
+ "hwui/AnimatedImageThread.cpp",
"pipeline/skia/ATraceMemoryDump.cpp",
"pipeline/skia/GLFunctorDrawable.cpp",
"pipeline/skia/LayerDrawable.cpp",
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 3681c69e912b..a3d552faeb0a 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -187,7 +187,9 @@ private:
EGLSyncKHR fence = mUploadThread->queue().runSync([&]() -> EGLSyncKHR {
AutoSkiaGlTexture glTexture;
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
- GL_CHECKPOINT(MODERATE);
+ if (GLUtils::dumpGLErrors()) {
+ return EGL_NO_SYNC_KHR;
+ }
// glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
// provide.
@@ -195,19 +197,26 @@ private:
// when we first use it in drawing
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
format.format, format.type, bitmap.getPixels());
- GL_CHECKPOINT(MODERATE);
+ if (GLUtils::dumpGLErrors()) {
+ return EGL_NO_SYNC_KHR;
+ }
EGLSyncKHR uploadFence =
eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
- LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR,
- "Could not create sync fence %#x", eglGetError());
+ if (uploadFence == EGL_NO_SYNC_KHR) {
+ ALOGW("Could not create sync fence %#x", eglGetError());
+ };
glFlush();
+ GLUtils::dumpGLErrors();
return uploadFence;
});
+ if (fence == EGL_NO_SYNC_KHR) {
+ return false;
+ }
EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
- LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
- "Failed to wait for the fence %#x", eglGetError());
+ ALOGE_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
+ "Failed to wait for the fence %#x", eglGetError());
eglDestroySyncKHR(display, fence);
}
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index f1c38031980e..2eb2c7c7e299 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -26,7 +26,7 @@ namespace uirenderer {
class Outline {
public:
- enum class Type { None = 0, Empty = 1, ConvexPath = 2, RoundRect = 3 };
+ enum class Type { None = 0, Empty = 1, Path = 2, RoundRect = 3 };
Outline() : mShouldClip(false), mType(Type::None), mRadius(0), mAlpha(0.0f) {}
@@ -57,12 +57,12 @@ public:
}
}
- void setConvexPath(const SkPath* outline, float alpha) {
+ void setPath(const SkPath* outline, float alpha) {
if (!outline) {
setEmpty();
return;
}
- mType = Type::ConvexPath;
+ mType = Type::Path;
mPath = *outline;
mBounds.set(outline->getBounds());
mAlpha = alpha;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 6761435a8171..31e45558139d 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -27,7 +27,6 @@
#include "DamageAccumulator.h"
#include "pipeline/skia/SkiaDisplayList.h"
#endif
-#include "utils/FatVector.h"
#include "utils/MathUtils.h"
#include "utils/StringUtils.h"
#include "utils/TraceUtils.h"
@@ -37,6 +36,7 @@
#include <atomic>
#include <sstream>
#include <string>
+#include <ui/FatVector.h>
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index d55e5b0ce836..c0ec2174bb35 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -27,6 +27,8 @@
#include <androidfw/ResourceTypes.h>
+#include <ui/FatVector.h>
+
#include "AnimatorManager.h"
#include "CanvasTransform.h"
#include "Debug.h"
@@ -35,7 +37,6 @@
#include "RenderProperties.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaLayer.h"
-#include "utils/FatVector.h"
#include <vector>
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index 4544beae5df8..638de850a6c5 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -15,7 +15,9 @@
*/
#include "AnimatedImageDrawable.h"
+#ifdef __ANDROID__ // Layoutlib does not support AnimatedImageThread
#include "AnimatedImageThread.h"
+#endif
#include "utils/TraceUtils.h"
@@ -160,8 +162,10 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) {
} else if (starting) {
// The image has animated, and now is being reset. Queue up the first
// frame, but keep showing the current frame until the first is ready.
+#ifdef __ANDROID__ // Layoutlib does not support AnimatedImageThread
auto& thread = uirenderer::AnimatedImageThread::getInstance();
mNextSnapshot = thread.reset(sk_ref_sp(this));
+#endif
}
bool finalFrame = false;
@@ -187,8 +191,10 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) {
}
if (mRunning && !mNextSnapshot.valid()) {
+#ifdef __ANDROID__ // Layoutlib does not support AnimatedImageThread
auto& thread = uirenderer::AnimatedImageThread::getInstance();
mNextSnapshot = thread.decodeNextFrame(sk_ref_sp(this));
+#endif
}
if (!drawDirectly) {
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index 4b2857f6c290..afd82aca07c5 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -24,6 +24,19 @@
using namespace android;
+sk_sp<SkColorSpace> ImageDecoder::getDefaultColorSpace() const {
+ const skcms_ICCProfile* encodedProfile = mCodec->getICCProfile();
+ if (encodedProfile) {
+ // If the profile maps directly to an SkColorSpace, that SkColorSpace
+ // will be returned. Otherwise, nullptr will be returned. In either
+ // case, using this SkColorSpace results in doing no color correction.
+ return SkColorSpace::Make(*encodedProfile);
+ }
+
+ // The image has no embedded color profile, and should be treated as SRGB.
+ return SkColorSpace::MakeSRGB();
+}
+
ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker)
: mCodec(std::move(codec))
, mPeeker(std::move(peeker))
@@ -31,7 +44,7 @@ ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChu
, mDecodeSize(mTargetSize)
, mOutColorType(mCodec->computeOutputColorType(kN32_SkColorType))
, mUnpremultipliedRequired(false)
- , mOutColorSpace(mCodec->computeOutputColorSpace(mOutColorType, nullptr))
+ , mOutColorSpace(getDefaultColorSpace())
, mSampleSize(1)
{
}
diff --git a/libs/hwui/hwui/ImageDecoder.h b/libs/hwui/hwui/ImageDecoder.h
index 0c99f84cbb72..a1b51573db3f 100644
--- a/libs/hwui/hwui/ImageDecoder.h
+++ b/libs/hwui/hwui/ImageDecoder.h
@@ -43,6 +43,7 @@ public:
bool setUnpremultipliedRequired(bool unpremultipliedRequired);
+ sk_sp<SkColorSpace> getDefaultColorSpace() const;
void setOutColorSpace(sk_sp<SkColorSpace> cs);
// The size is the final size after scaling and cropping.
diff --git a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
index 551bdc63121d..234f42d79cb7 100644
--- a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
+++ b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
@@ -39,14 +39,13 @@ namespace skiapipeline {
* ATraceMemoryDump calculates memory category first by looking at the "type" string passed to
* dumpStringValue and then by looking at "backingType" passed to setMemoryBacking.
* Only GPU Texture memory is tracked separately and everything else is grouped as one
- * "GPU Memory" category.
+ * "Misc Memory" category.
*/
static std::unordered_map<const char*, const char*> sResourceMap = {
{"malloc", "HWUI CPU Memory"}, // taken from setMemoryBacking(backingType)
{"gl_texture", "HWUI Texture Memory"}, // taken from setMemoryBacking(backingType)
- {"Texture",
- "HWUI Texture Memory"}, // taken from dumpStringValue(value, valueName="type")
- // Uncomment categories below to split "GPU Memory" into more brackets for debugging.
+ {"Texture", "HWUI Texture Memory"}, // taken from dumpStringValue(value, valueName="type")
+ // Uncomment categories below to split "Misc Memory" into more brackets for debugging.
/*{"vk_buffer", "vk_buffer"},
{"gl_renderbuffer", "gl_renderbuffer"},
{"gl_buffer", "gl_buffer"},
@@ -169,8 +168,8 @@ void ATraceMemoryDump::resetCurrentCounter(const char* dumpName) {
mLastDumpValue = 0;
mLastPurgeableDumpValue = INVALID_MEMORY_SIZE;
mLastDumpName = dumpName;
- // Categories not listed in sResourceMap are reported as "GPU memory"
- mCategory = "HWUI GPU Memory";
+ // Categories not listed in sResourceMap are reported as "Misc Memory"
+ mCategory = "HWUI Misc Memory";
}
} /* namespace skiapipeline */
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
index cfc0f9b258da..d669f84c5ee2 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
@@ -21,7 +21,7 @@
#include <SkCanvas.h>
#include <SkDrawable.h>
-#include <utils/FatVector.h>
+#include <ui/FatVector.h>
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index e7efe2ff798b..8d5acc631274 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -171,17 +171,15 @@ static void setBufferCount(ANativeWindow* window, uint32_t extraBuffers) {
}
bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
- ColorMode colorMode, uint32_t extraBuffers) {
+ uint32_t extraBuffers) {
if (mEglSurface != EGL_NO_SURFACE) {
mEglManager.destroySurface(mEglSurface);
mEglSurface = EGL_NO_SURFACE;
}
- setSurfaceColorProperties(colorMode);
-
if (surface) {
mRenderThread.requireGlContext();
- auto newSurface = mEglManager.createSurface(surface, colorMode, mSurfaceColorSpace);
+ auto newSurface = mEglManager.createSurface(surface, mColorMode, mSurfaceColorSpace);
if (!newSurface) {
return false;
}
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 3fe0f92b1924..e482cad6c953 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -44,7 +44,7 @@ public:
FrameInfo* currentFrameInfo, bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
- renderthread::ColorMode colorMode, uint32_t extraBuffers) override;
+ uint32_t extraBuffers) override;
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index b940cff04713..29b4dd7f32e7 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -24,6 +24,7 @@
#include <SkOverdrawColorFilter.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
+#include <SkTypeface.h>
#include <SkSerialProcs.h>
#include "LightingInfo.h"
#include "VectorDrawable.h"
@@ -43,6 +44,7 @@ namespace uirenderer {
namespace skiapipeline {
SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) {
+ setSurfaceColorProperties(mColorMode);
}
SkiaPipeline::~SkiaPipeline() {
@@ -264,6 +266,9 @@ bool SkiaPipeline::setupMultiFrameCapture() {
SkSerialProcs procs;
procs.fImageProc = SkSharingSerialContext::serializeImage;
procs.fImageCtx = mSerialContext.get();
+ procs.fTypefaceProc = [](SkTypeface* tf, void* ctx){
+ return tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
+ };
// SkDocuments don't take owership of the streams they write.
// we need to keep it until after mMultiPic.close()
// procs is passed as a pointer, but just as a method of having an optional default.
@@ -405,6 +410,10 @@ void SkiaPipeline::endCapture(SkSurface* surface) {
std::invoke(mPictureCapturedCallback, std::move(picture));
} else {
// single frame skp to file
+ SkSerialProcs procs;
+ procs.fTypefaceProc = [](SkTypeface* tf, void* ctx){
+ return tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
+ };
auto data = picture->serialize();
savePictureAsync(data, mCapturedFile);
mCaptureSequence = 0;
@@ -576,6 +585,7 @@ void SkiaPipeline::dumpResourceCacheUsage() const {
}
void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) {
+ mColorMode = colorMode;
if (colorMode == ColorMode::SRGB) {
mSurfaceColorType = SkColorType::kN32_SkColorType;
mSurfaceColorSpace = SkColorSpace::MakeSRGB();
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index af8414de4bc1..8341164edc19 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -50,6 +50,7 @@ public:
bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
ErrorHandler* errorHandler) override;
+ void setSurfaceColorProperties(renderthread::ColorMode colorMode) override;
SkColorType getSurfaceColorType() const override { return mSurfaceColorType; }
sk_sp<SkColorSpace> getSurfaceColorSpace() override { return mSurfaceColorSpace; }
@@ -72,9 +73,10 @@ public:
protected:
void dumpResourceCacheUsage() const;
- void setSurfaceColorProperties(renderthread::ColorMode colorMode);
renderthread::RenderThread& mRenderThread;
+
+ renderthread::ColorMode mColorMode = renderthread::ColorMode::SRGB;
SkColorType mSurfaceColorType;
sk_sp<SkColorSpace> mSurfaceColorSpace;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index ad7c70614239..535a19956e03 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -117,17 +117,16 @@ DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
void SkiaVulkanPipeline::onStop() {}
bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
- ColorMode colorMode, uint32_t extraBuffers) {
+ uint32_t extraBuffers) {
if (mVkSurface) {
mVkManager.destroySurface(mVkSurface);
mVkSurface = nullptr;
}
- setSurfaceColorProperties(colorMode);
if (surface) {
mRenderThread.requireVkContext();
mVkSurface =
- mVkManager.createSurface(surface, colorMode, mSurfaceColorSpace, mSurfaceColorType,
+ mVkManager.createSurface(surface, mColorMode, mSurfaceColorSpace, mSurfaceColorType,
mRenderThread.getGrContext(), extraBuffers);
}
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 31734783de7f..c8bf233d8e1c 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -43,7 +43,7 @@ public:
FrameInfo* currentFrameInfo, bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
- renderthread::ColorMode colorMode, uint32_t extraBuffers) override;
+ uint32_t extraBuffers) override;
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5993e176f0b8..91f9447a3d59 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -143,10 +143,11 @@ void CanvasContext::setSurface(sp<Surface>&& surface, bool enableTimeout) {
ATRACE_CALL();
if (surface) {
- mNativeSurface = new ReliableSurface{std::move(surface)};
+ mNativeSurface = std::make_unique<ReliableSurface>(std::move(surface));
+ mNativeSurface->init();
if (enableTimeout) {
// TODO: Fix error handling & re-shorten timeout
- ANativeWindow_setDequeueTimeout(mNativeSurface.get(), 4000_ms);
+ ANativeWindow_setDequeueTimeout(mNativeSurface->getNativeWindow(), 4000_ms);
}
} else {
mNativeSurface = nullptr;
@@ -160,9 +161,9 @@ void CanvasContext::setSurface(sp<Surface>&& surface, bool enableTimeout) {
mRenderAheadCapacity = mRenderAheadDepth;
}
- ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
- bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode,
- mRenderAheadCapacity);
+ bool hasSurface = mRenderPipeline->setSurface(
+ mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior,
+ mRenderAheadCapacity);
mFrameNumber = -1;
@@ -172,7 +173,7 @@ void CanvasContext::setSurface(sp<Surface>&& surface, bool enableTimeout) {
// Enable frame stats after the surface has been bound to the appropriate graphics API.
// Order is important when new and old surfaces are the same, because old surface has
// its frame stats disabled automatically.
- mNativeSurface->enableFrameTimestamps(true);
+ native_window_enable_frame_timestamps(mNativeSurface->getNativeWindow(), true);
} else {
mRenderThread.removeFrameCallback(this);
mGenerationID++;
@@ -203,7 +204,8 @@ void CanvasContext::setStopped(bool stopped) {
void CanvasContext::allocateBuffers() {
if (mNativeSurface) {
- mNativeSurface->allocateBuffers();
+ ANativeWindow* anw = mNativeSurface->getNativeWindow();
+ ANativeWindow_allocateBuffers(anw);
}
}
@@ -222,7 +224,8 @@ void CanvasContext::setOpaque(bool opaque) {
}
void CanvasContext::setWideGamut(bool wideGamut) {
- mWideColorGamut = wideGamut;
+ ColorMode colorMode = wideGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
+ mRenderPipeline->setSurfaceColorProperties(colorMode);
}
bool CanvasContext::makeCurrent() {
@@ -426,9 +429,10 @@ void CanvasContext::setPresentTime() {
if (renderAhead) {
presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) +
- (frameIntervalNanos * (renderAhead + 1));
+ (frameIntervalNanos * (renderAhead + 1)) - DeviceInfo::get()->getAppOffset() +
+ (frameIntervalNanos / 2);
}
- native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime);
+ native_window_set_buffers_timestamp(mNativeSurface->getNativeWindow(), presentTime);
}
void CanvasContext::draw() {
@@ -489,16 +493,18 @@ void CanvasContext::draw() {
swap.swapCompletedTime = systemTime(SYSTEM_TIME_MONOTONIC);
swap.vsyncTime = mRenderThread.timeLord().latestVsync();
if (didDraw) {
- nsecs_t dequeueStart = ANativeWindow_getLastDequeueStartTime(mNativeSurface.get());
+ nsecs_t dequeueStart =
+ ANativeWindow_getLastDequeueStartTime(mNativeSurface->getNativeWindow());
if (dequeueStart < mCurrentFrameInfo->get(FrameInfoIndex::SyncStart)) {
// Ignoring dequeue duration as it happened prior to frame render start
// and thus is not part of the frame.
swap.dequeueDuration = 0;
} else {
swap.dequeueDuration =
- ANativeWindow_getLastDequeueDuration(mNativeSurface.get());
+ ANativeWindow_getLastDequeueDuration(mNativeSurface->getNativeWindow());
}
- swap.queueDuration = ANativeWindow_getLastQueueDuration(mNativeSurface.get());
+ swap.queueDuration =
+ ANativeWindow_getLastQueueDuration(mNativeSurface->getNativeWindow());
} else {
swap.dequeueDuration = 0;
swap.queueDuration = 0;
@@ -550,8 +556,9 @@ void CanvasContext::draw() {
FrameInfo* forthBehind = mLast4FrameInfos.front().first;
int64_t composedFrameId = mLast4FrameInfos.front().second;
nsecs_t acquireTime = -1;
- mNativeSurface->getFrameTimestamps(composedFrameId, nullptr, &acquireTime, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr);
+ native_window_get_frame_timestamps(mNativeSurface->getNativeWindow(), composedFrameId,
+ nullptr, &acquireTime, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr);
// Ignore default -1, NATIVE_WINDOW_TIMESTAMP_INVALID and NATIVE_WINDOW_TIMESTAMP_PENDING
forthBehind->set(FrameInfoIndex::GpuCompleted) = acquireTime > 0 ? acquireTime : -1;
mJankTracker.finishGpuDraw(*forthBehind);
@@ -567,14 +574,16 @@ void CanvasContext::doFrame() {
}
SkISize CanvasContext::getNextFrameSize() const {
- ReliableSurface* surface = mNativeSurface.get();
- if (surface) {
- SkISize size;
- size.fWidth = ANativeWindow_getWidth(surface);
- size.fHeight = ANativeWindow_getHeight(surface);
- return size;
+ static constexpr SkISize defaultFrameSize = {INT32_MAX, INT32_MAX};
+ if (mNativeSurface == nullptr) {
+ return defaultFrameSize;
}
- return {INT32_MAX, INT32_MAX};
+ ANativeWindow* anw = mNativeSurface->getNativeWindow();
+
+ SkISize size;
+ size.fWidth = ANativeWindow_getWidth(anw);
+ size.fHeight = ANativeWindow_getHeight(anw);
+ return size;
}
void CanvasContext::prepareAndDraw(RenderNode* node) {
@@ -693,7 +702,7 @@ void CanvasContext::enqueueFrameWork(std::function<void()>&& func) {
int64_t CanvasContext::getFrameNumber() {
// mFrameNumber is reset to -1 when the surface changes or we swap buffers
if (mFrameNumber == -1 && mNativeSurface.get()) {
- mFrameNumber = static_cast<int64_t>(mNativeSurface->getNextFrameNumber());
+ mFrameNumber = ANativeWindow_getNextFrameId(mNativeSurface->getNativeWindow());
}
return mFrameNumber;
}
@@ -702,11 +711,9 @@ bool CanvasContext::surfaceRequiresRedraw() {
if (!mNativeSurface) return false;
if (mHaveNewSurface) return true;
- int width = -1;
- int height = -1;
- ReliableSurface* surface = mNativeSurface.get();
- surface->query(NATIVE_WINDOW_WIDTH, &width);
- surface->query(NATIVE_WINDOW_HEIGHT, &height);
+ ANativeWindow* anw = mNativeSurface->getNativeWindow();
+ const int width = ANativeWindow_getWidth(anw);
+ const int height = ANativeWindow_getHeight(anw);
return width != mLastFrameWidth || height != mLastFrameHeight;
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 4490f80eb8af..629c741e8757 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -220,7 +220,7 @@ private:
int32_t mLastFrameHeight = 0;
RenderThread& mRenderThread;
- sp<ReliableSurface> mNativeSurface;
+ std::unique_ptr<ReliableSurface> mNativeSurface;
// stopped indicates the CanvasContext will reject actual redraw operations,
// and defer repaint until it is un-stopped
bool mStopped = false;
@@ -251,7 +251,6 @@ private:
nsecs_t mLastDropVsync = 0;
bool mOpaque;
- bool mWideColorGamut = false;
bool mUseForceDark = false;
LightInfo mLightInfo;
LightGeometry mLightGeometry = {{0, 0, 0}, 0};
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index ef0aa98d4220..ba0d64c5492d 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -66,7 +66,7 @@ public:
virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
virtual DeferredLayerUpdater* createTextureLayer() = 0;
- virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, ColorMode colorMode,
+ virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior,
uint32_t extraBuffers) = 0;
virtual void onStop() = 0;
virtual bool isSurfaceReady() = 0;
@@ -80,6 +80,8 @@ public:
virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0;
virtual void unpinImages() = 0;
+
+ virtual void setSurfaceColorProperties(ColorMode colorMode) = 0;
virtual SkColorType getSurfaceColorType() const = 0;
virtual sk_sp<SkColorSpace> getSurfaceColorSpace() = 0;
virtual GrSurfaceOrigin getSurfaceOrigin() = 0;
diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp
index 864780fb6ae8..e92500f5be51 100644
--- a/libs/hwui/renderthread/ReliableSurface.cpp
+++ b/libs/hwui/renderthread/ReliableSurface.cpp
@@ -26,64 +26,38 @@ namespace android::uirenderer::renderthread {
// to propagate this error back to the caller
constexpr bool DISABLE_BUFFER_PREFETCH = true;
-// TODO: Make surface less protected
-// This exists because perform is a varargs, and ANativeWindow has no va_list perform.
-// So wrapping/chaining that is hard. Telling the compiler to ignore protected is easy, so we do
-// that instead
-struct SurfaceExposer : Surface {
- // Make warnings happy
- SurfaceExposer() = delete;
-
- using Surface::cancelBuffer;
- using Surface::dequeueBuffer;
- using Surface::lockBuffer_DEPRECATED;
- using Surface::perform;
- using Surface::queueBuffer;
- using Surface::setBufferCount;
- using Surface::setSwapInterval;
-};
-
-#define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__)
-
ReliableSurface::ReliableSurface(sp<Surface>&& surface) : mSurface(std::move(surface)) {
LOG_ALWAYS_FATAL_IF(!mSurface, "Error, unable to wrap a nullptr");
-
- ANativeWindow::setSwapInterval = hook_setSwapInterval;
- ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
- ANativeWindow::cancelBuffer = hook_cancelBuffer;
- ANativeWindow::queueBuffer = hook_queueBuffer;
- ANativeWindow::query = hook_query;
- ANativeWindow::perform = hook_perform;
-
- ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
- ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
- ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
- ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
}
ReliableSurface::~ReliableSurface() {
clearReservedBuffer();
+ // Clear out the interceptors for proper hygiene.
+ // As a concrete example, if the underlying ANativeWindow is associated with
+ // an EGLSurface that is still in use, then if we don't clear out the
+ // interceptors then we walk into undefined behavior.
+ ANativeWindow_setCancelBufferInterceptor(mSurface.get(), nullptr, nullptr);
+ ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), nullptr, nullptr);
+ ANativeWindow_setQueueBufferInterceptor(mSurface.get(), nullptr, nullptr);
+ ANativeWindow_setPerformInterceptor(mSurface.get(), nullptr, nullptr);
}
-void ReliableSurface::perform(int operation, va_list args) {
- std::lock_guard _lock{mMutex};
+void ReliableSurface::init() {
+ int result = ANativeWindow_setCancelBufferInterceptor(mSurface.get(), hook_cancelBuffer, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set cancelBuffer interceptor: error = %d",
+ result);
- switch (operation) {
- case NATIVE_WINDOW_SET_USAGE:
- mUsage = va_arg(args, uint32_t);
- break;
- case NATIVE_WINDOW_SET_USAGE64:
- mUsage = va_arg(args, uint64_t);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
- /* width */ va_arg(args, uint32_t);
- /* height */ va_arg(args, uint32_t);
- mFormat = va_arg(args, PixelFormat);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
- mFormat = va_arg(args, PixelFormat);
- break;
- }
+ result = ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), hook_dequeueBuffer, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set dequeueBuffer interceptor: error = %d",
+ result);
+
+ result = ANativeWindow_setQueueBufferInterceptor(mSurface.get(), hook_queueBuffer, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set queueBuffer interceptor: error = %d",
+ result);
+
+ result = ANativeWindow_setPerformInterceptor(mSurface.get(), hook_perform, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set perform interceptor: error = %d",
+ result);
}
int ReliableSurface::reserveNext() {
@@ -111,7 +85,9 @@ int ReliableSurface::reserveNext() {
int fenceFd = -1;
ANativeWindowBuffer* buffer = nullptr;
- int result = callProtected(mSurface, dequeueBuffer, &buffer, &fenceFd);
+
+ // Note that this calls back into our own hooked method.
+ int result = ANativeWindow_dequeueBuffer(mSurface.get(), &buffer, &fenceFd);
{
std::lock_guard _lock{mMutex};
@@ -138,59 +114,11 @@ void ReliableSurface::clearReservedBuffer() {
mHasDequeuedBuffer = false;
}
if (buffer) {
- callProtected(mSurface, cancelBuffer, buffer, releaseFd);
- }
-}
-
-int ReliableSurface::cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
- clearReservedBuffer();
- if (isFallbackBuffer(buffer)) {
- if (fenceFd > 0) {
- close(fenceFd);
- }
- return OK;
- }
- int result = callProtected(mSurface, cancelBuffer, buffer, fenceFd);
- return result;
-}
-
-int ReliableSurface::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) {
- {
- std::lock_guard _lock{mMutex};
- if (mReservedBuffer) {
- *buffer = mReservedBuffer;
- *fenceFd = mReservedFenceFd.release();
- mReservedBuffer = nullptr;
- return OK;
- }
- }
-
-
- int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd);
- if (result != OK) {
- ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
- *buffer = acquireFallbackBuffer(result);
- *fenceFd = -1;
- return *buffer ? OK : INVALID_OPERATION;
- } else {
- std::lock_guard _lock{mMutex};
- mHasDequeuedBuffer = true;
- }
- return OK;
-}
-
-int ReliableSurface::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
- clearReservedBuffer();
-
- if (isFallbackBuffer(buffer)) {
- if (fenceFd > 0) {
- close(fenceFd);
- }
- return OK;
+ // Note that clearReservedBuffer may be reentrant here, so
+ // mReservedBuffer must be cleared once we reach here to avoid recursing
+ // forever.
+ ANativeWindow_cancelBuffer(mSurface.get(), buffer, releaseFd);
}
-
- int result = callProtected(mSurface, queueBuffer, buffer, fenceFd);
- return result;
}
bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const {
@@ -229,82 +157,95 @@ ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer(int error) {
return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer);
}
-Surface* ReliableSurface::getWrapped(const ANativeWindow* window) {
- return getSelf(window)->mSurface.get();
-}
-
-int ReliableSurface::hook_setSwapInterval(ANativeWindow* window, int interval) {
- return callProtected(getWrapped(window), setSwapInterval, interval);
-}
-
-int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
- int* fenceFd) {
- return getSelf(window)->dequeueBuffer(buffer, fenceFd);
-}
-
-int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
- int fenceFd) {
- return getSelf(window)->cancelBuffer(buffer, fenceFd);
-}
-
-int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
- int fenceFd) {
- return getSelf(window)->queueBuffer(buffer, fenceFd);
-}
+int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window,
+ ANativeWindow_dequeueBufferFn dequeueBuffer, void* data,
+ ANativeWindowBuffer** buffer, int* fenceFd) {
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ {
+ std::lock_guard _lock{rs->mMutex};
+ if (rs->mReservedBuffer) {
+ *buffer = rs->mReservedBuffer;
+ *fenceFd = rs->mReservedFenceFd.release();
+ rs->mReservedBuffer = nullptr;
+ return OK;
+ }
+ }
-int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer** buffer) {
- ANativeWindowBuffer* buf;
- int fenceFd = -1;
- int result = window->dequeueBuffer(window, &buf, &fenceFd);
+ int result = dequeueBuffer(window, buffer, fenceFd);
if (result != OK) {
- return result;
- }
- sp<Fence> fence(new Fence(fenceFd));
- int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
- if (waitResult != OK) {
- ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", waitResult);
- window->cancelBuffer(window, buf, -1);
- return waitResult;
+ ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
+ *buffer = rs->acquireFallbackBuffer(result);
+ *fenceFd = -1;
+ return *buffer ? OK : INVALID_OPERATION;
+ } else {
+ std::lock_guard _lock{rs->mMutex};
+ rs->mHasDequeuedBuffer = true;
}
- *buffer = buf;
- return result;
+ return OK;
}
-int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- return window->cancelBuffer(window, buffer, -1);
+int ReliableSurface::hook_cancelBuffer(ANativeWindow* window,
+ ANativeWindow_cancelBufferFn cancelBuffer, void* data,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ rs->clearReservedBuffer();
+ if (rs->isFallbackBuffer(buffer)) {
+ if (fenceFd > 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
+ return cancelBuffer(window, buffer, fenceFd);
}
-int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- // This method is a no-op in Surface as well
- return OK;
-}
+int ReliableSurface::hook_queueBuffer(ANativeWindow* window,
+ ANativeWindow_queueBufferFn queueBuffer, void* data,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ rs->clearReservedBuffer();
-int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- return window->queueBuffer(window, buffer, -1);
-}
+ if (rs->isFallbackBuffer(buffer)) {
+ if (fenceFd > 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
-int ReliableSurface::hook_query(const ANativeWindow* window, int what, int* value) {
- return getWrapped(window)->query(what, value);
+ return queueBuffer(window, buffer, fenceFd);
}
-int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) {
+int ReliableSurface::hook_perform(ANativeWindow* window, ANativeWindow_performFn perform,
+ void* data, int operation, va_list args) {
// Drop the reserved buffer if there is one since this (probably) mutated buffer dimensions
// TODO: Filter to things that only affect the reserved buffer
// TODO: Can we mutate the reserved buffer in some cases?
- getSelf(window)->clearReservedBuffer();
- va_list args;
- va_start(args, operation);
- int result = callProtected(getWrapped(window), perform, operation, args);
- va_end(args);
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ rs->clearReservedBuffer();
- va_start(args, operation);
- getSelf(window)->perform(operation, args);
- va_end(args);
+ va_list argsCopy;
+ va_copy(argsCopy, args);
+ int result = perform(window, operation, argsCopy);
+ {
+ std::lock_guard _lock{rs->mMutex};
+
+ switch (operation) {
+ case ANATIVEWINDOW_PERFORM_SET_USAGE:
+ rs->mUsage = va_arg(args, uint32_t);
+ break;
+ case ANATIVEWINDOW_PERFORM_SET_USAGE64:
+ rs->mUsage = va_arg(args, uint64_t);
+ break;
+ case ANATIVEWINDOW_PERFORM_SET_BUFFERS_GEOMETRY:
+ /* width */ va_arg(args, uint32_t);
+ /* height */ va_arg(args, uint32_t);
+ rs->mFormat = va_arg(args, PixelFormat);
+ break;
+ case ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT:
+ rs->mFormat = va_arg(args, PixelFormat);
+ break;
+ }
+ }
return result;
}
diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h
index f768df37ba7d..e3cd8c019a23 100644
--- a/libs/hwui/renderthread/ReliableSurface.h
+++ b/libs/hwui/renderthread/ReliableSurface.h
@@ -16,6 +16,7 @@
#pragma once
+#include <apex/window.h>
#include <gui/Surface.h>
#include <utils/Macros.h>
#include <utils/StrongPointer.h>
@@ -24,20 +25,23 @@
namespace android::uirenderer::renderthread {
-class ReliableSurface : public ANativeObjectBase<ANativeWindow, ReliableSurface, RefBase> {
+class ReliableSurface {
PREVENT_COPY_AND_ASSIGN(ReliableSurface);
public:
ReliableSurface(sp<Surface>&& surface);
~ReliableSurface();
- int reserveNext();
+ // Performs initialization that is not safe to do in the constructor.
+ // For instance, registering ANativeWindow interceptors with ReliableSurface
+ // passed as the data pointer is not safe.
+ void init();
- void allocateBuffers() { mSurface->allocateBuffers(); }
+ ANativeWindow* getNativeWindow() { return mSurface.get(); }
- int query(int what, int* value) const { return mSurface->query(what, value); }
+ int reserveNext();
- uint64_t getNextFrameNumber() const { return mSurface->getNextFrameNumber(); }
+ int query(int what, int* value) const { return mSurface->query(what, value); }
int getAndClearError() {
int ret = mBufferQueueState;
@@ -45,23 +49,8 @@ public:
return ret;
}
- status_t getFrameTimestamps(uint64_t frameNumber,
- nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
- nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
- nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
- nsecs_t* outDisplayPresentTime, nsecs_t* outDequeueReadyTime,
- nsecs_t* outReleaseTime) {
- return mSurface->getFrameTimestamps(frameNumber, outRequestedPresentTime, outAcquireTime,
- outLatchTime, outFirstRefreshStartTime, outLastRefreshStartTime,
- outGlCompositionDoneTime, outDisplayPresentTime, outDequeueReadyTime, outReleaseTime);
- }
-
- void enableFrameTimestamps(bool enable) {
- return mSurface->enableFrameTimestamps(enable);
- }
-
private:
- const sp<Surface> mSurface;
+ sp<Surface> mSurface;
mutable std::mutex mMutex;
@@ -78,27 +67,20 @@ private:
ANativeWindowBuffer* acquireFallbackBuffer(int error);
void clearReservedBuffer();
- void perform(int operation, va_list args);
- int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
- int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
- int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
-
- static Surface* getWrapped(const ANativeWindow*);
-
- // ANativeWindow hooks
- static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
- static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
- int* fenceFd);
- static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
-
- static int hook_perform(ANativeWindow* window, int operation, ...);
- static int hook_query(const ANativeWindow* window, int what, int* value);
- static int hook_setSwapInterval(ANativeWindow* window, int interval);
-
- static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer);
- static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ // ANativeWindow hooks. When an ANativeWindow_* method is called on the
+ // underlying ANativeWindow, these methods will intercept the original call.
+ // For example, an EGL driver would call into these hooks instead of the
+ // original methods.
+ static int hook_cancelBuffer(ANativeWindow* window, ANativeWindow_cancelBufferFn cancelBuffer,
+ void* data, ANativeWindowBuffer* buffer, int fenceFd);
+ static int hook_dequeueBuffer(ANativeWindow* window,
+ ANativeWindow_dequeueBufferFn dequeueBuffer, void* data,
+ ANativeWindowBuffer** buffer, int* fenceFd);
+ static int hook_queueBuffer(ANativeWindow* window, ANativeWindow_queueBufferFn queueBuffer,
+ void* data, ANativeWindowBuffer* buffer, int fenceFd);
+
+ static int hook_perform(ANativeWindow* window, ANativeWindow_performFn perform, void* data,
+ int operation, va_list args);
};
}; // namespace android::uirenderer::renderthread
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index cae3e3b5188c..206b58f62ea7 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -27,7 +27,6 @@
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/SkiaVulkanPipeline.h"
#include "renderstate/RenderState.h"
-#include "utils/FatVector.h"
#include "utils/TimeUtils.h"
#include "utils/TraceUtils.h"
@@ -40,6 +39,8 @@
#include <utils/Mutex.h>
#include <thread>
+#include <ui/FatVector.h>
+
namespace android {
namespace uirenderer {
namespace renderthread {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index a5355fc3499d..ba70afc8b8d2 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -23,13 +23,13 @@
#include <GrContext.h>
#include <GrTypes.h>
#include <android/sync.h>
+#include <ui/FatVector.h>
#include <vk/GrVkExtensions.h>
#include <vk/GrVkTypes.h>
#include "Properties.h"
#include "RenderThread.h"
#include "renderstate/RenderState.h"
-#include "utils/FatVector.h"
#include "utils/TraceUtils.h"
namespace android {
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index c4186174b637..644d5fbd5bf9 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -26,9 +26,9 @@
#include <sys/types.h>
#include <unistd.h>
-#include <algorithm>
-#include <map>
-#include <vector>
+#include <android/util/ProtoOutputStream.h>
+#include <stats_event.h>
+#include <statslog.h>
#include "JankTracker.h"
#include "protos/graphicsstats.pb.h"
@@ -61,7 +61,7 @@ public:
}
}
bool valid() { return mFd != -1; }
- operator int() { return mFd; } // NOLINT(google-explicit-constructor)
+ operator int() { return mFd; } // NOLINT(google-explicit-constructor)
private:
int mFd;
@@ -485,79 +485,82 @@ void GraphicsStatsService::finishDump(Dump* dump) {
delete dump;
}
-class MemOutputStreamLite : public io::ZeroCopyOutputStream {
-public:
- explicit MemOutputStreamLite() : mCopyAdapter(), mImpl(&mCopyAdapter) {}
- virtual ~MemOutputStreamLite() {}
-
- virtual bool Next(void** data, int* size) override { return mImpl.Next(data, size); }
-
- virtual void BackUp(int count) override { mImpl.BackUp(count); }
-
- virtual int64 ByteCount() const override { return mImpl.ByteCount(); }
-
- bool Flush() { return mImpl.Flush(); }
-
- void copyData(const DumpMemoryFn& reader, void* param1, void* param2) {
- int bufferOffset = 0;
- int totalSize = mCopyAdapter.mBuffersSize - mCopyAdapter.mCurrentBufferUnusedSize;
- int totalDataLeft = totalSize;
- for (auto& it : mCopyAdapter.mBuffers) {
- int bufferSize = std::min(totalDataLeft, (int)it.size()); // last buffer is not full
- reader(it.data(), bufferOffset, bufferSize, totalSize, param1, param2);
- bufferOffset += bufferSize;
- totalDataLeft -= bufferSize;
- }
- }
-
-private:
- struct MemAdapter : public io::CopyingOutputStream {
- // Data is stored in an array of buffers.
- // JNI SetByteArrayRegion assembles data in one continuous Java byte[] buffer.
- std::vector<std::vector<unsigned char>> mBuffers;
- int mBuffersSize = 0; // total bytes allocated in mBuffers
- int mCurrentBufferUnusedSize = 0; // unused bytes in the last buffer mBuffers.back()
- unsigned char* mCurrentBuffer = nullptr; // pointer to next free byte in mBuffers.back()
+using namespace google::protobuf;
- explicit MemAdapter() {}
- virtual ~MemAdapter() {}
+// Field ids taken from FrameTimingHistogram message in atoms.proto
+#define TIME_MILLIS_BUCKETS_FIELD_NUMBER 1
+#define FRAME_COUNTS_FIELD_NUMBER 2
+
+static void writeCpuHistogram(AStatsEvent* event,
+ const uirenderer::protos::GraphicsStatsProto& stat) {
+ util::ProtoOutputStream proto;
+ for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) {
+ auto& bucket = stat.histogram(bucketIndex);
+ proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
+ TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */,
+ (int)bucket.render_millis());
+ }
+ for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) {
+ auto& bucket = stat.histogram(bucketIndex);
+ proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
+ FRAME_COUNTS_FIELD_NUMBER /* field id */,
+ (long long)bucket.frame_count());
+ }
+ std::vector<uint8_t> outVector;
+ proto.serializeToVector(&outVector);
+ AStatsEvent_writeByteArray(event, outVector.data(), outVector.size());
+}
- virtual bool Write(const void* buffer, int size) override {
- while (size > 0) {
- if (0 == mCurrentBufferUnusedSize) {
- mCurrentBufferUnusedSize =
- std::max(size, mBuffersSize ? 2 * mBuffersSize : 10000);
- mBuffers.emplace_back();
- mBuffers.back().resize(mCurrentBufferUnusedSize);
- mCurrentBuffer = mBuffers.back().data();
- mBuffersSize += mCurrentBufferUnusedSize;
- }
- int dataMoved = std::min(mCurrentBufferUnusedSize, size);
- memcpy(mCurrentBuffer, buffer, dataMoved);
- mCurrentBufferUnusedSize -= dataMoved;
- mCurrentBuffer += dataMoved;
- buffer = reinterpret_cast<const unsigned char*>(buffer) + dataMoved;
- size -= dataMoved;
- }
- return true;
- }
- };
+static void writeGpuHistogram(AStatsEvent* event,
+ const uirenderer::protos::GraphicsStatsProto& stat) {
+ util::ProtoOutputStream proto;
+ for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) {
+ auto& bucket = stat.gpu_histogram(bucketIndex);
+ proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
+ TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */,
+ (int)bucket.render_millis());
+ }
+ for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) {
+ auto& bucket = stat.gpu_histogram(bucketIndex);
+ proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
+ FRAME_COUNTS_FIELD_NUMBER /* field id */,
+ (long long)bucket.frame_count());
+ }
+ std::vector<uint8_t> outVector;
+ proto.serializeToVector(&outVector);
+ AStatsEvent_writeByteArray(event, outVector.data(), outVector.size());
+}
- MemOutputStreamLite::MemAdapter mCopyAdapter;
- io::CopyingOutputStreamAdaptor mImpl;
-};
-void GraphicsStatsService::finishDumpInMemory(Dump* dump, const DumpMemoryFn& reader, void* param1,
- void* param2) {
- MemOutputStreamLite stream;
+void GraphicsStatsService::finishDumpInMemory(Dump* dump, AStatsEventList* data,
+ bool lastFullDay) {
dump->updateProto();
- bool success = dump->proto().SerializeToZeroCopyStream(&stream) && stream.Flush();
- delete dump;
- if (!success) {
- return;
+ auto& serviceDump = dump->proto();
+ for (int stat_index = 0; stat_index < serviceDump.stats_size(); stat_index++) {
+ auto& stat = serviceDump.stats(stat_index);
+ AStatsEvent* event = AStatsEventList_addStatsEvent(data);
+ AStatsEvent_setAtomId(event, android::util::GRAPHICS_STATS);
+ AStatsEvent_writeString(event, stat.package_name().c_str());
+ AStatsEvent_writeInt64(event, (int64_t)stat.version_code());
+ AStatsEvent_writeInt64(event, (int64_t)stat.stats_start());
+ AStatsEvent_writeInt64(event, (int64_t)stat.stats_end());
+ AStatsEvent_writeInt32(event, (int32_t)stat.pipeline());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().total_frames());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_vsync_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().high_input_latency_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_ui_thread_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_bitmap_upload_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_draw_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_deadline_count());
+ writeCpuHistogram(event, stat);
+ writeGpuHistogram(event, stat);
+ // TODO: fill in UI mainline module version, when the feature is available.
+ AStatsEvent_writeInt64(event, (int64_t)0);
+ AStatsEvent_writeBool(event, !lastFullDay);
+ AStatsEvent_build(event);
}
- stream.copyData(reader, param1, param2);
}
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/service/GraphicsStatsService.h b/libs/hwui/service/GraphicsStatsService.h
index 4bed96330a52..59e21d039c9d 100644
--- a/libs/hwui/service/GraphicsStatsService.h
+++ b/libs/hwui/service/GraphicsStatsService.h
@@ -20,6 +20,7 @@
#include "JankTracker.h"
#include "utils/Macros.h"
+#include <stats_pull_atom_callback.h>
namespace android {
namespace uirenderer {
@@ -27,9 +28,6 @@ namespace protos {
class GraphicsStatsProto;
}
-typedef void (*DumpMemoryFn)(void* buffer, int bufferOffset, int bufferSize, int totalSize,
- void* param1, void* param2);
-
/*
* The exported entry points used by GraphicsStatsService.java in f/b/services/core
*
@@ -56,8 +54,8 @@ public:
int64_t startTime, int64_t endTime, const ProfileData* data);
ANDROID_API static void addToDump(Dump* dump, const std::string& path);
ANDROID_API static void finishDump(Dump* dump);
- ANDROID_API static void finishDumpInMemory(Dump* dump, const DumpMemoryFn& reader, void* param1,
- void* param2);
+ ANDROID_API static void finishDumpInMemory(Dump* dump, AStatsEventList* data,
+ bool lastFullDay);
// Visible for testing
static bool parseFromFile(const std::string& path, protos::GraphicsStatsProto* output);
diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp
index e075d806126b..06f158f25fc5 100644
--- a/libs/hwui/tests/common/TestContext.cpp
+++ b/libs/hwui/tests/common/TestContext.cpp
@@ -22,43 +22,50 @@ namespace android {
namespace uirenderer {
namespace test {
-static const int IDENT_DISPLAYEVENT = 1;
-
-static android::DisplayInfo DUMMY_DISPLAY{
- 1080, // w
- 1920, // h
- 320.0, // xdpi
- 320.0, // ydpi
- 60.0, // fps
- 2.0, // density
- ui::ROTATION_0, // orientation
- false, // secure?
- 0, // appVsyncOffset
- 0, // presentationDeadline
-};
-
-DisplayInfo getInternalDisplay() {
-#if !HWUI_NULL_GPU
- DisplayInfo display;
- const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken();
- LOG_ALWAYS_FATAL_IF(token == nullptr,
- "Failed to get display info because internal display is disconnected\n");
- status_t status = SurfaceComposerClient::getDisplayInfo(token, &display);
- LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
- return display;
+const DisplayInfo& getDisplayInfo() {
+ static DisplayInfo info = [] {
+ DisplayInfo info;
+#if HWUI_NULL_GPU
+ info.density = 2.f;
#else
- return DUMMY_DISPLAY;
+ const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken();
+ LOG_ALWAYS_FATAL_IF(!token, "%s: No internal display", __FUNCTION__);
+
+ const status_t status = SurfaceComposerClient::getDisplayInfo(token, &info);
+ LOG_ALWAYS_FATAL_IF(status, "%s: Failed to get display info", __FUNCTION__);
#endif
+ return info;
+ }();
+
+ return info;
}
-// Initialize to a dummy default
-android::DisplayInfo gDisplay = DUMMY_DISPLAY;
+const DisplayConfig& getActiveDisplayConfig() {
+ static DisplayConfig config = [] {
+ DisplayConfig config;
+#if HWUI_NULL_GPU
+ config.resolution = ui::Size(1080, 1920);
+ config.xDpi = config.yDpi = 320.f;
+ config.refreshRate = 60.f;
+#else
+ const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken();
+ LOG_ALWAYS_FATAL_IF(!token, "%s: No internal display", __FUNCTION__);
+
+ const status_t status = SurfaceComposerClient::getActiveDisplayConfig(token, &config);
+ LOG_ALWAYS_FATAL_IF(status, "%s: Failed to get active display config", __FUNCTION__);
+#endif
+ return config;
+ }();
+
+ return config;
+}
TestContext::TestContext() {
mLooper = new Looper(true);
mSurfaceComposerClient = new SurfaceComposerClient();
- mLooper->addFd(mDisplayEventReceiver.getFd(), IDENT_DISPLAYEVENT, Looper::EVENT_INPUT, nullptr,
- nullptr);
+
+ constexpr int EVENT_ID = 1;
+ mLooper->addFd(mDisplayEventReceiver.getFd(), EVENT_ID, Looper::EVENT_INPUT, nullptr, nullptr);
}
TestContext::~TestContext() {}
@@ -79,8 +86,10 @@ void TestContext::createSurface() {
}
void TestContext::createWindowSurface() {
- mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"), gDisplay.w,
- gDisplay.h, PIXEL_FORMAT_RGBX_8888);
+ const ui::Size& resolution = getActiveDisplayResolution();
+ mSurfaceControl =
+ mSurfaceComposerClient->createSurface(String8("HwuiTest"), resolution.getWidth(),
+ resolution.getHeight(), PIXEL_FORMAT_RGBX_8888);
SurfaceComposerClient::Transaction t;
t.setLayer(mSurfaceControl, 0x7FFFFFF).show(mSurfaceControl).apply();
@@ -94,7 +103,8 @@ void TestContext::createOffscreenSurface() {
producer->setMaxDequeuedBufferCount(3);
producer->setAsyncMode(true);
mConsumer = new BufferItemConsumer(consumer, GRALLOC_USAGE_HW_COMPOSER, 4);
- mConsumer->setDefaultBufferSize(gDisplay.w, gDisplay.h);
+ const ui::Size& resolution = getActiveDisplayResolution();
+ mConsumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight());
mSurface = new Surface(producer);
}
diff --git a/libs/hwui/tests/common/TestContext.h b/libs/hwui/tests/common/TestContext.h
index 116d4de8090a..a012ecb1a1d3 100644
--- a/libs/hwui/tests/common/TestContext.h
+++ b/libs/hwui/tests/common/TestContext.h
@@ -23,20 +23,25 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
+#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
#include <utils/Looper.h>
#include <atomic>
#include <thread>
+#define dp(x) ((x) * android::uirenderer::test::getDisplayInfo().density)
+
namespace android {
namespace uirenderer {
namespace test {
-extern DisplayInfo gDisplay;
-#define dp(x) ((x)*android::uirenderer::test::gDisplay.density)
+const DisplayInfo& getDisplayInfo();
+const DisplayConfig& getActiveDisplayConfig();
-DisplayInfo getInternalDisplay();
+inline const ui::Size& getActiveDisplayResolution() {
+ return getActiveDisplayConfig().resolution;
+}
class TestContext {
public:
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index 22d5abbd3dbc..3b6baa70db9a 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -109,16 +109,14 @@ void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options
void run(const TestScene::Info& info, const TestScene::Options& opts,
benchmark::BenchmarkReporter* reporter) {
- // Switch to the real display
- gDisplay = getInternalDisplay();
-
Properties::forceDrawFrame = true;
TestContext testContext;
testContext.setRenderOffscreen(opts.renderOffscreen);
// create the native surface
- const int width = gDisplay.w;
- const int height = gDisplay.h;
+ const ui::Size& resolution = getActiveDisplayResolution();
+ const int width = resolution.getWidth();
+ const int height = resolution.getHeight();
sp<Surface> surface = testContext.surface();
std::unique_ptr<TestScene> scene(info.createScene(opts));
diff --git a/libs/hwui/tests/unit/FatVectorTests.cpp b/libs/hwui/tests/unit/FatVectorTests.cpp
index 8523e6c9e973..6585a6249b44 100644
--- a/libs/hwui/tests/unit/FatVectorTests.cpp
+++ b/libs/hwui/tests/unit/FatVectorTests.cpp
@@ -15,7 +15,7 @@
*/
#include <gtest/gtest.h>
-#include <utils/FatVector.h>
+#include <ui/FatVector.h>
#include <tests/common/TestUtils.h>
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 307d13606cb8..90bcd1c0e370 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -398,7 +398,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) {
auto surface = context.surface();
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
EXPECT_FALSE(pipeline->isSurfaceReady());
- EXPECT_TRUE(pipeline->setSurface(surface.get(), SwapBehavior::kSwap_default, ColorMode::SRGB, 0));
+ EXPECT_TRUE(pipeline->setSurface(surface.get(), SwapBehavior::kSwap_default, 0));
EXPECT_TRUE(pipeline->isSurfaceReady());
renderThread.destroyRenderingContext();
EXPECT_FALSE(pipeline->isSurfaceReady());
diff --git a/libs/hwui/utils/FatVector.h b/libs/hwui/utils/FatVector.h
deleted file mode 100644
index 8cc4d1010ab6..000000000000
--- a/libs/hwui/utils/FatVector.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2015, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ANDROID_FAT_VECTOR_H
-#define ANDROID_FAT_VECTOR_H
-
-#include "utils/Macros.h"
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <utils/Log.h>
-#include <type_traits>
-
-#include <vector>
-
-namespace android {
-namespace uirenderer {
-
-template <typename T, size_t SIZE>
-class InlineStdAllocator {
-public:
- struct Allocation {
- PREVENT_COPY_AND_ASSIGN(Allocation);
-
- public:
- Allocation(){};
- // char array instead of T array, so memory is uninitialized, with no destructors run
- char array[sizeof(T) * SIZE];
- bool inUse = false;
- };
-
- typedef T value_type; // needed to implement std::allocator
- typedef T* pointer; // needed to implement std::allocator
-
- explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {}
- InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {}
- ~InlineStdAllocator() {}
-
- T* allocate(size_t num, const void* = 0) {
- if (!mAllocation.inUse && num <= SIZE) {
- mAllocation.inUse = true;
- return (T*)mAllocation.array;
- } else {
- return (T*)malloc(num * sizeof(T));
- }
- }
-
- void deallocate(pointer p, size_t num) {
- if (p == (T*)mAllocation.array) {
- mAllocation.inUse = false;
- } else {
- // 'free' instead of delete here - destruction handled separately
- free(p);
- }
- }
- Allocation& mAllocation;
-};
-
-/**
- * std::vector with SIZE elements preallocated into an internal buffer.
- *
- * Useful for avoiding the cost of malloc in cases where only SIZE or
- * fewer elements are needed in the common case.
- */
-template <typename T, size_t SIZE>
-class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
-public:
- FatVector()
- : std::vector<T, InlineStdAllocator<T, SIZE>>(
- InlineStdAllocator<T, SIZE>(mAllocation)) {
- this->reserve(SIZE);
- }
-
- explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); }
-
-private:
- typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
-};
-
-} // namespace uirenderer
-} // namespace android
-
-#endif // ANDROID_FAT_VECTOR_H
diff --git a/libs/incident/Android.bp b/libs/incident/Android.bp
index 150f6dcde5d0..512b8c439dcf 100644
--- a/libs/incident/Android.bp
+++ b/libs/incident/Android.bp
@@ -12,8 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-cc_library_shared {
- name: "libincident",
+
+cc_defaults {
+ name: "libincidentpriv_defaults",
cflags: [
"-Wall",
@@ -50,6 +51,70 @@ cc_library_shared {
":libincident_aidl",
"src/IncidentReportArgs.cpp",
],
+}
+
+cc_library_shared {
+ name: "libincidentpriv",
+ defaults: ["libincidentpriv_defaults"],
+ export_include_dirs: ["include_priv"],
+}
+
+cc_library_shared {
+ name: "libincident",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-missing-field-initializers",
+ "-Wno-unused-variable",
+ "-Wunused-parameter",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ "libincidentpriv",
+ ],
+
+ srcs: [
+ "src/incident_report.cpp",
+ ],
export_include_dirs: ["include"],
+
+ stubs: {
+ symbol_file: "libincident.map.txt",
+ versions: [
+ "30",
+ ],
+ },
}
+
+cc_test {
+ name: "libincident_test",
+ defaults: ["libincidentpriv_defaults"],
+ test_suites: ["device-tests"],
+
+ include_dirs: [
+ "frameworks/base/libs/incident/include",
+ "frameworks/base/libs/incident/include_priv",
+ ],
+
+ srcs: [
+ "tests/IncidentReportArgs_test.cpp",
+ "tests/IncidentReportRequest_test.cpp",
+ "tests/c_api_compile_test.c",
+ ],
+
+ shared_libs: [
+ "libincident",
+ ],
+
+ static_libs: [
+ "libgmock",
+ ],
+}
+
+
+
diff --git a/libs/incident/include/incident/incident_report.h b/libs/incident/include/incident/incident_report.h
new file mode 100644
index 000000000000..49fe5b9b73b4
--- /dev/null
+++ b/libs/incident/include/incident/incident_report.h
@@ -0,0 +1,192 @@
+/**
+ * Copyright (c) 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.
+ */
+
+/**
+ * @file incident_report.h
+ */
+
+#ifndef ANDROID_INCIDENT_INCIDENT_REPORT_H
+#define ANDROID_INCIDENT_INCIDENT_REPORT_H
+
+#include <stdbool.h>
+
+#if __cplusplus
+#include <set>
+#include <string>
+#include <vector>
+
+extern "C" {
+#endif // __cplusplus
+
+struct AIncidentReportArgs;
+/**
+ * Opaque class to represent the arguments to an incident report request.
+ * Incident reports contain debugging data about the device at runtime.
+ * For more information see the android.os.IncidentManager java class.
+ */
+typedef struct AIncidentReportArgs AIncidentReportArgs;
+
+// Privacy policy enum value, sync with frameworks/base/core/proto/android/privacy.proto,
+// IncidentReportArgs.h and IncidentReportArgs.java.
+enum {
+ /**
+ * Flag marking fields and incident reports than can be taken
+ * off the device only via adb.
+ */
+ INCIDENT_REPORT_PRIVACY_POLICY_LOCAL = 0,
+
+ /**
+ * Flag marking fields and incident reports than can be taken
+ * off the device with contemporary consent.
+ */
+ INCIDENT_REPORT_PRIVACY_POLICY_EXPLICIT = 100,
+
+ /**
+ * Flag marking fields and incident reports than can be taken
+ * off the device with prior consent.
+ */
+ INCIDENT_REPORT_PRIVACY_POLICY_AUTOMATIC = 200,
+
+ /**
+ * Flag to indicate that a given field has not been marked
+ * with a privacy policy.
+ */
+ INCIDENT_REPORT_PRIVACY_POLICY_UNSET = 255
+};
+
+/**
+ * Allocate and initialize an AIncidentReportArgs object.
+ */
+AIncidentReportArgs* AIncidentReportArgs_init();
+
+/**
+ * Duplicate an existing AIncidentReportArgs object.
+ */
+AIncidentReportArgs* AIncidentReportArgs_clone(AIncidentReportArgs* that);
+
+/**
+ * Clean up and delete an AIncidentReportArgs object.
+ */
+void AIncidentReportArgs_delete(AIncidentReportArgs* args);
+
+/**
+ * Set this incident report to include all sections.
+ */
+void AIncidentReportArgs_setAll(AIncidentReportArgs* args, bool all);
+
+/**
+ * Set this incident report privacy policy spec.
+ */
+void AIncidentReportArgs_setPrivacyPolicy(AIncidentReportArgs* args, int privacyPolicy);
+
+/**
+ * Add this section to the incident report. The section IDs are the field numbers
+ * from the android.os.IncidentProto protobuf message.
+ */
+void AIncidentReportArgs_addSection(AIncidentReportArgs* args, int section);
+
+/**
+ * Set the apk package name that will be sent a broadcast when the incident
+ * report completes. Must be called in conjunction with AIncidentReportArgs_setReceiverClass.
+ */
+void AIncidentReportArgs_setReceiverPackage(AIncidentReportArgs* args, char const* pkg);
+
+/**
+ * Set the fully qualified class name of the java BroadcastReceiver class that will be
+ * sent a broadcast when the report completes. Must be called in conjunction with
+ * AIncidentReportArgs_setReceiverPackage.
+ */
+void AIncidentReportArgs_setReceiverClass(AIncidentReportArgs* args, char const* cls);
+
+/**
+ * Add protobuf data as a header to the incident report. The buffer should be a serialized
+ * android.os.IncidentHeaderProto object.
+ */
+void AIncidentReportArgs_addHeader(AIncidentReportArgs* args, uint8_t const* buf, size_t size);
+
+/**
+ * Initiate taking the report described in the args object. Returns 0 on success,
+ * and non-zero otherwise.
+ */
+int AIncidentReportArgs_takeReport(AIncidentReportArgs* args);
+
+#if __cplusplus
+} // extern "C"
+
+namespace android {
+namespace os {
+
+class IncidentReportRequest {
+public:
+ inline IncidentReportRequest() {
+ mImpl = AIncidentReportArgs_init();
+ }
+
+ inline IncidentReportRequest(const IncidentReportRequest& that) {
+ mImpl = AIncidentReportArgs_clone(that.mImpl);
+ }
+
+ inline ~IncidentReportRequest() {
+ AIncidentReportArgs_delete(mImpl);
+ }
+
+ inline AIncidentReportArgs* getImpl() {
+ return mImpl;
+ }
+
+ inline void setAll(bool all) {
+ AIncidentReportArgs_setAll(mImpl, all);
+ }
+
+ inline void setPrivacyPolicy(int privacyPolicy) {
+ AIncidentReportArgs_setPrivacyPolicy(mImpl, privacyPolicy);
+ }
+
+ inline void addSection(int section) {
+ AIncidentReportArgs_addSection(mImpl, section);
+ }
+
+ inline void setReceiverPackage(const std::string& pkg) {
+ AIncidentReportArgs_setReceiverPackage(mImpl, pkg.c_str());
+ };
+
+ inline void setReceiverClass(const std::string& cls) {
+ AIncidentReportArgs_setReceiverClass(mImpl, cls.c_str());
+ };
+
+ inline void addHeader(const std::vector<uint8_t>& headerProto) {
+ AIncidentReportArgs_addHeader(mImpl, headerProto.data(), headerProto.size());
+ };
+
+ inline void addHeader(const uint8_t* buf, size_t size) {
+ AIncidentReportArgs_addHeader(mImpl, buf, size);
+ };
+
+ // returns a status_t
+ inline int takeReport() {
+ return AIncidentReportArgs_takeReport(mImpl);
+ }
+
+private:
+ AIncidentReportArgs* mImpl;
+};
+
+} // namespace os
+} // namespace android
+
+#endif // __cplusplus
+
+#endif // ANDROID_INCIDENT_INCIDENT_REPORT_H
diff --git a/libs/incident/include/android/os/IncidentReportArgs.h b/libs/incident/include_priv/android/os/IncidentReportArgs.h
index 94b4ad6eae31..0e6159032e45 100644
--- a/libs/incident/include/android/os/IncidentReportArgs.h
+++ b/libs/incident/include_priv/android/os/IncidentReportArgs.h
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-#ifndef ANDROID_OS_DUMPSTATE_ARGS_H_
-#define ANDROID_OS_DUMPSTATE_ARGS_H_
+#ifndef ANDROID_OS_INCIDENT_REPORT_ARGS_H
+#define ANDROID_OS_INCIDENT_REPORT_ARGS_H
+#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <utils/String16.h>
@@ -29,7 +30,8 @@ namespace os {
using namespace std;
-// DESTINATION enum value, sync with frameworks/base/core/proto/android/privacy.proto
+// DESTINATION enum value, sync with frameworks/base/core/proto/android/privacy.proto,
+// incident/incident_report.h and IncidentReportArgs.java
const uint8_t PRIVACY_POLICY_LOCAL = 0;
const uint8_t PRIVACY_POLICY_EXPLICIT = 100;
const uint8_t PRIVACY_POLICY_AUTOMATIC = 200;
@@ -74,4 +76,4 @@ private:
}
}
-#endif // ANDROID_OS_DUMPSTATE_ARGS_H_
+#endif // ANDROID_OS_INCIDENT_REPORT_ARGS_H
diff --git a/libs/incident/libincident.map.txt b/libs/incident/libincident.map.txt
new file mode 100644
index 000000000000..f157763f1a03
--- /dev/null
+++ b/libs/incident/libincident.map.txt
@@ -0,0 +1,15 @@
+LIBINCIDENT {
+ global:
+ AIncidentReportArgs_init; # apex # introduced=30
+ AIncidentReportArgs_clone; # apex # introduced=30
+ AIncidentReportArgs_delete; # apex # introduced=30
+ AIncidentReportArgs_setAll; # apex # introduced=30
+ AIncidentReportArgs_setPrivacyPolicy; # apex # introduced=30
+ AIncidentReportArgs_addSection; # apex # introduced=30
+ AIncidentReportArgs_setReceiverPackage; # apex # introduced=30
+ AIncidentReportArgs_setReceiverClass; # apex # introduced=30
+ AIncidentReportArgs_addHeader; # apex # introduced=30
+ AIncidentReportArgs_takeReport; # apex # introduced=30
+ local:
+ *;
+};
diff --git a/libs/incident/src/incident_report.cpp b/libs/incident/src/incident_report.cpp
new file mode 100644
index 000000000000..7897ddf6d251
--- /dev/null
+++ b/libs/incident/src/incident_report.cpp
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 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.
+ */
+
+#define LOG_TAG "libincident"
+
+#include <incident/incident_report.h>
+
+#include <android/os/IIncidentManager.h>
+#include <android/os/IncidentReportArgs.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <log/log.h>
+
+using android::sp;
+using android::binder::Status;
+using android::os::IncidentReportArgs;
+using android::os::IIncidentManager;
+using std::string;
+using std::vector;
+
+AIncidentReportArgs* AIncidentReportArgs_init() {
+ return reinterpret_cast<AIncidentReportArgs*>(new IncidentReportArgs());
+}
+
+AIncidentReportArgs* AIncidentReportArgs_clone(AIncidentReportArgs* that) {
+ return reinterpret_cast<AIncidentReportArgs*>(
+ new IncidentReportArgs(*reinterpret_cast<IncidentReportArgs*>(that)));
+}
+
+void AIncidentReportArgs_delete(AIncidentReportArgs* args) {
+ delete reinterpret_cast<IncidentReportArgs*>(args);
+}
+
+void AIncidentReportArgs_setAll(AIncidentReportArgs* args, bool all) {
+ reinterpret_cast<IncidentReportArgs*>(args)->setAll(all);
+}
+
+void AIncidentReportArgs_setPrivacyPolicy(AIncidentReportArgs* args, int privacyPolicy) {
+ reinterpret_cast<IncidentReportArgs*>(args)->setPrivacyPolicy(privacyPolicy);
+}
+
+void AIncidentReportArgs_addSection(AIncidentReportArgs* args, int section) {
+ reinterpret_cast<IncidentReportArgs*>(args)->addSection(section);
+}
+
+void AIncidentReportArgs_setReceiverPackage(AIncidentReportArgs* args, char const* pkg) {
+ reinterpret_cast<IncidentReportArgs*>(args)->setReceiverPkg(string(pkg));
+}
+
+void AIncidentReportArgs_setReceiverClass(AIncidentReportArgs* args, char const* cls) {
+ reinterpret_cast<IncidentReportArgs*>(args)->setReceiverCls(string(cls));
+}
+
+void AIncidentReportArgs_addHeader(AIncidentReportArgs* args, uint8_t const* buf, size_t size) {
+ vector<uint8_t> vec(buf, buf+size);
+ reinterpret_cast<IncidentReportArgs*>(args)->addHeader(vec);
+}
+
+int AIncidentReportArgs_takeReport(AIncidentReportArgs* argp) {
+ IncidentReportArgs* args = reinterpret_cast<IncidentReportArgs*>(argp);
+
+ sp<IIncidentManager> service = android::interface_cast<IIncidentManager>(
+ android::defaultServiceManager()->getService(android::String16("incident")));
+ if (service == nullptr) {
+ ALOGW("Failed to fetch incident service.");
+ return false;
+ }
+ Status s = service->reportIncident(*args);
+ return s.transactionError();
+}
diff --git a/libs/incident/tests/IncidentReportArgs_test.cpp b/libs/incident/tests/IncidentReportArgs_test.cpp
new file mode 100644
index 000000000000..224b343c554a
--- /dev/null
+++ b/libs/incident/tests/IncidentReportArgs_test.cpp
@@ -0,0 +1,74 @@
+// Copyright (C) 2018 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.
+
+#include <android/os/IncidentReportArgs.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// Checks that all of the inline methods on IncidentReportRequest and the real C functions
+// result in a working IncidentReportArgs.
+TEST(IncidentReportArgsTest, testSerialization) {
+ IncidentReportArgs args;
+ args.setAll(0);
+ args.addSection(1000);
+ args.addSection(1001);
+
+ vector<uint8_t> header1;
+ header1.push_back(0x1);
+ header1.push_back(0x2);
+ vector<uint8_t> header2;
+ header1.push_back(0x22);
+ header1.push_back(0x33);
+
+ args.addHeader(header1);
+ args.addHeader(header2);
+
+ args.setPrivacyPolicy(1);
+
+ args.setReceiverPkg("com.android.os");
+ args.setReceiverCls("com.android.os.Receiver");
+
+ Parcel out;
+ status_t err = args.writeToParcel(&out);
+ EXPECT_EQ(NO_ERROR, err);
+
+ out.setDataPosition(0);
+
+ IncidentReportArgs args2;
+ err = args2.readFromParcel(&out);
+ EXPECT_EQ(NO_ERROR, err);
+
+ EXPECT_EQ(0, args2.all());
+ set<int> sections;
+ sections.insert(1000);
+ sections.insert(1001);
+ EXPECT_EQ(sections, args2.sections());
+ EXPECT_EQ(1, args2.getPrivacyPolicy());
+
+ EXPECT_EQ(string("com.android.os"), args2.receiverPkg());
+ EXPECT_EQ(string("com.android.os.Receiver"), args2.receiverCls());
+
+ vector<vector<uint8_t>> headers;
+ headers.push_back(header1);
+ headers.push_back(header2);
+ EXPECT_EQ(headers, args2.headers());
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/libs/incident/tests/IncidentReportRequest_test.cpp b/libs/incident/tests/IncidentReportRequest_test.cpp
new file mode 100644
index 000000000000..6d218b6682a3
--- /dev/null
+++ b/libs/incident/tests/IncidentReportRequest_test.cpp
@@ -0,0 +1,65 @@
+// Copyright (C) 2018 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.
+
+#include <android/os/IncidentReportArgs.h>
+#include <incident/incident_report.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TEST(IncidentReportRequestTest, testWrite) {
+ IncidentReportRequest request;
+ request.setAll(0);
+ request.addSection(1000);
+ request.addSection(1001);
+
+ vector<uint8_t> header1;
+ header1.push_back(0x1);
+ header1.push_back(0x2);
+ vector<uint8_t> header2;
+ header1.push_back(0x22);
+ header1.push_back(0x33);
+
+ request.addHeader(header1);
+ request.addHeader(header2);
+
+ request.setPrivacyPolicy(1);
+
+ request.setReceiverPackage("com.android.os");
+ request.setReceiverClass("com.android.os.Receiver");
+
+ IncidentReportArgs* args = reinterpret_cast<IncidentReportArgs*>(request.getImpl());
+
+ EXPECT_EQ(0, args->all());
+ set<int> sections;
+ sections.insert(1000);
+ sections.insert(1001);
+ EXPECT_EQ(sections, args->sections());
+ EXPECT_EQ(1, args->getPrivacyPolicy());
+
+ EXPECT_EQ(string("com.android.os"), args->receiverPkg());
+ EXPECT_EQ(string("com.android.os.Receiver"), args->receiverCls());
+
+ vector<vector<uint8_t>> headers;
+ headers.push_back(header1);
+ headers.push_back(header2);
+ EXPECT_EQ(headers, args->headers());
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/libs/incident/tests/c_api_compile_test.c b/libs/incident/tests/c_api_compile_test.c
new file mode 100644
index 000000000000..e1620dfe3280
--- /dev/null
+++ b/libs/incident/tests/c_api_compile_test.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include <incident/incident_report.h>
+
+/*
+ * This file ensures that incident/incident_report.h actually compiles with C,
+ * since there is no other place in the tree that actually uses it from C.
+ */
+int not_called() {
+ return 0;
+}
+
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index e4348f2a9b21..3b494e9129db 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -251,19 +251,24 @@ void PointerController::unfade(Transition transition) {
void PointerController::setPresentation(Presentation presentation) {
AutoMutex _l(mLock);
- if (presentation == PRESENTATION_POINTER && mLocked.additionalMouseResources.empty()) {
- mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
- &mLocked.animationResources, mLocked.viewport.displayId);
+ if (mLocked.presentation == presentation) {
+ return;
}
- if (mLocked.presentation != presentation) {
- mLocked.presentation = presentation;
- mLocked.presentationChanged = true;
+ mLocked.presentation = presentation;
+ mLocked.presentationChanged = true;
- if (presentation != PRESENTATION_SPOT) {
- fadeOutAndReleaseAllSpotsLocked();
- }
+ if (!mLocked.viewport.isValid()) {
+ return;
+ }
+ if (presentation == PRESENTATION_POINTER) {
+ if (mLocked.additionalMouseResources.empty()) {
+ mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
+ &mLocked.animationResources,
+ mLocked.viewport.displayId);
+ }
+ fadeOutAndReleaseAllSpotsLocked();
updatePointerLocked();
}
}
@@ -285,6 +290,9 @@ void PointerController::setSpots(const PointerCoords* spotCoords,
#endif
AutoMutex _l(mLock);
+ if (!mLocked.viewport.isValid()) {
+ return;
+ }
std::vector<Spot*> newSpots;
std::map<int32_t, std::vector<Spot*>>::const_iterator iter =
@@ -331,6 +339,9 @@ void PointerController::clearSpots() {
#endif
AutoMutex _l(mLock);
+ if (!mLocked.viewport.isValid()) {
+ return;
+ }
fadeOutAndReleaseAllSpotsLocked();
}
@@ -752,6 +763,10 @@ void PointerController::fadeOutAndReleaseAllSpotsLocked() {
}
void PointerController::loadResourcesLocked() REQUIRES(mLock) {
+ if (!mLocked.viewport.isValid()) {
+ return;
+ }
+
mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId);
mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index b36406d6a703..a15742671dc7 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -39,8 +39,8 @@ enum TestCursorType {
using ::testing::AllOf;
using ::testing::Field;
-using ::testing::NiceMock;
using ::testing::Mock;
+using ::testing::NiceMock;
using ::testing::Return;
using ::testing::Test;
@@ -57,12 +57,20 @@ public:
virtual int32_t getDefaultPointerIconId() override;
virtual int32_t getCustomPointerIconId() override;
+ bool allResourcesAreLoaded();
+ bool noResourcesAreLoaded();
+
private:
void loadPointerIconForType(SpriteIcon* icon, int32_t cursorType);
+
+ bool pointerIconLoaded{false};
+ bool pointerResourcesLoaded{false};
+ bool additionalMouseResourcesLoaded{false};
};
void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, int32_t) {
loadPointerIconForType(icon, CURSOR_TYPE_DEFAULT);
+ pointerIconLoaded = true;
}
void MockPointerControllerPolicyInterface::loadPointerResources(PointerResources* outResources,
@@ -70,6 +78,7 @@ void MockPointerControllerPolicyInterface::loadPointerResources(PointerResources
loadPointerIconForType(&outResources->spotHover, CURSOR_TYPE_HOVER);
loadPointerIconForType(&outResources->spotTouch, CURSOR_TYPE_TOUCH);
loadPointerIconForType(&outResources->spotAnchor, CURSOR_TYPE_ANCHOR);
+ pointerResourcesLoaded = true;
}
void MockPointerControllerPolicyInterface::loadAdditionalMouseResources(
@@ -91,6 +100,8 @@ void MockPointerControllerPolicyInterface::loadAdditionalMouseResources(
anim.durationPerFrame = 10;
(*outResources)[cursorType] = icon;
(*outAnimationResources)[cursorType] = anim;
+
+ additionalMouseResourcesLoaded = true;
}
int32_t MockPointerControllerPolicyInterface::getDefaultPointerIconId() {
@@ -101,18 +112,27 @@ int32_t MockPointerControllerPolicyInterface::getCustomPointerIconId() {
return CURSOR_TYPE_CUSTOM;
}
+bool MockPointerControllerPolicyInterface::allResourcesAreLoaded() {
+ return pointerIconLoaded && pointerResourcesLoaded && additionalMouseResourcesLoaded;
+}
+
+bool MockPointerControllerPolicyInterface::noResourcesAreLoaded() {
+ return !(pointerIconLoaded || pointerResourcesLoaded || additionalMouseResourcesLoaded);
+}
+
void MockPointerControllerPolicyInterface::loadPointerIconForType(SpriteIcon* icon, int32_t type) {
icon->style = type;
std::pair<float, float> hotSpot = getHotSpotCoordinatesForType(type);
icon->hotSpotX = hotSpot.first;
icon->hotSpotY = hotSpot.second;
}
-
class PointerControllerTest : public Test {
protected:
PointerControllerTest();
~PointerControllerTest();
+ void ensureDisplayViewportIsSet();
+
sp<MockSprite> mPointerSprite;
sp<MockPointerControllerPolicyInterface> mPolicy;
sp<MockSpriteController> mSpriteController;
@@ -141,7 +161,14 @@ PointerControllerTest::PointerControllerTest() : mPointerSprite(new NiceMock<Moc
.WillOnce(Return(mPointerSprite));
mPointerController = new PointerController(mPolicy, mLooper, mSpriteController);
+}
+
+PointerControllerTest::~PointerControllerTest() {
+ mRunning.store(false, std::memory_order_relaxed);
+ mThread.join();
+}
+void PointerControllerTest::ensureDisplayViewportIsSet() {
DisplayViewport viewport;
viewport.displayId = ADISPLAY_ID_DEFAULT;
viewport.logicalRight = 1600;
@@ -151,11 +178,9 @@ PointerControllerTest::PointerControllerTest() : mPointerSprite(new NiceMock<Moc
viewport.deviceWidth = 400;
viewport.deviceHeight = 300;
mPointerController->setDisplayViewport(viewport);
-}
-PointerControllerTest::~PointerControllerTest() {
- mRunning.store(false, std::memory_order_relaxed);
- mThread.join();
+ // The first call to setDisplayViewport should trigger the loading of the necessary resources.
+ EXPECT_TRUE(mPolicy->allResourcesAreLoaded());
}
void PointerControllerTest::loopThread() {
@@ -167,6 +192,7 @@ void PointerControllerTest::loopThread() {
}
TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) {
+ ensureDisplayViewportIsSet();
mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
std::pair<float, float> hotspot = getHotSpotCoordinatesForType(CURSOR_TYPE_DEFAULT);
@@ -181,6 +207,7 @@ TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) {
}
TEST_F(PointerControllerTest, updatePointerIcon) {
+ ensureDisplayViewportIsSet();
mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
int32_t type = CURSOR_TYPE_ADDITIONAL;
@@ -196,6 +223,7 @@ TEST_F(PointerControllerTest, updatePointerIcon) {
}
TEST_F(PointerControllerTest, setCustomPointerIcon) {
+ ensureDisplayViewportIsSet();
mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
int32_t style = CURSOR_TYPE_CUSTOM;
@@ -217,4 +245,18 @@ TEST_F(PointerControllerTest, setCustomPointerIcon) {
mPointerController->setCustomPointerIcon(icon);
}
+TEST_F(PointerControllerTest, doesNotGetResourcesBeforeSettingViewport) {
+ mPointerController->setPresentation(PointerController::PRESENTATION_POINTER);
+ mPointerController->setSpots(nullptr, nullptr, BitSet32(), -1);
+ mPointerController->clearSpots();
+ mPointerController->setPosition(1.0f, 1.0f);
+ mPointerController->move(1.0f, 1.0f);
+ mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+ mPointerController->fade(PointerController::TRANSITION_IMMEDIATE);
+
+ EXPECT_TRUE(mPolicy->noResourcesAreLoaded());
+
+ ensureDisplayViewportIsSet();
+}
+
} // namespace android
diff --git a/libs/services/Android.bp b/libs/services/Android.bp
index 9b047ca22d19..1e621079b532 100644
--- a/libs/services/Android.bp
+++ b/libs/services/Android.bp
@@ -20,7 +20,6 @@ cc_library_shared {
":IDropBoxManagerService.aidl",
"src/content/ComponentName.cpp",
"src/os/DropBoxManager.cpp",
- "src/os/StatsDimensionsValue.cpp",
],
shared_libs: [
diff --git a/libs/services/include/android/os/StatsDimensionsValue.h b/libs/services/include/android/os/StatsDimensionsValue.h
deleted file mode 100644
index cc0b05644f2c..000000000000
--- a/libs/services/include/android/os/StatsDimensionsValue.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-#ifndef STATS_DIMENSIONS_VALUE_H
-#define STATS_DIMENSIONS_VALUE_H
-
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
-#include <binder/Status.h>
-#include <utils/String16.h>
-#include <vector>
-
-namespace android {
-namespace os {
-
-// Represents a parcelable object. Used to send data from statsd to StatsCompanionService.java.
-class StatsDimensionsValue : public android::Parcelable {
-public:
- StatsDimensionsValue();
-
- StatsDimensionsValue(int32_t field, String16 value);
- StatsDimensionsValue(int32_t field, int32_t value);
- StatsDimensionsValue(int32_t field, int64_t value);
- StatsDimensionsValue(int32_t field, bool value);
- StatsDimensionsValue(int32_t field, float value);
- StatsDimensionsValue(int32_t field, std::vector<StatsDimensionsValue> value);
-
- virtual ~StatsDimensionsValue();
-
- virtual android::status_t writeToParcel(android::Parcel* out) const override;
- virtual android::status_t readFromParcel(const android::Parcel* in) override;
-
-private:
- // Keep constants in sync with android/os/StatsDimensionsValue.java
- // and stats_log.proto's DimensionValue.
- static const int kStrValueType = 2;
- static const int kIntValueType = 3;
- static const int kLongValueType = 4;
- static const int kBoolValueType = 5;
- static const int kFloatValueType = 6;
- static const int kTupleValueType = 7;
-
- int32_t mField;
- int32_t mValueType;
-
- // This isn't very clever, but it isn't used for long-term storage, so it'll do.
- String16 mStrValue;
- int32_t mIntValue;
- int64_t mLongValue;
- bool mBoolValue;
- float mFloatValue;
- std::vector<StatsDimensionsValue> mTupleValue;
-};
-
-} // namespace os
-} // namespace android
-
-#endif // STATS_DIMENSIONS_VALUE_H
diff --git a/libs/services/src/os/StatsDimensionsValue.cpp b/libs/services/src/os/StatsDimensionsValue.cpp
deleted file mode 100644
index 0052e0baa905..000000000000
--- a/libs/services/src/os/StatsDimensionsValue.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "StatsDimensionsValue"
-
-#include "android/os/StatsDimensionsValue.h"
-
-#include <cutils/log.h>
-
-using android::Parcel;
-using android::Parcelable;
-using android::status_t;
-using std::vector;
-
-namespace android {
-namespace os {
-
-StatsDimensionsValue::StatsDimensionsValue() {};
-
-StatsDimensionsValue::StatsDimensionsValue(int32_t field, String16 value) :
- mField(field),
- mValueType(kStrValueType),
- mStrValue(value) {
-}
-StatsDimensionsValue::StatsDimensionsValue(int32_t field, int32_t value) :
- mField(field),
- mValueType(kIntValueType),
- mIntValue(value) {
-}
-StatsDimensionsValue::StatsDimensionsValue(int32_t field, int64_t value) :
- mField(field),
- mValueType(kLongValueType),
- mLongValue(value) {
-}
-StatsDimensionsValue::StatsDimensionsValue(int32_t field, bool value) :
- mField(field),
- mValueType(kBoolValueType),
- mBoolValue(value) {
-}
-StatsDimensionsValue::StatsDimensionsValue(int32_t field, float value) :
- mField(field),
- mValueType(kFloatValueType),
- mFloatValue(value) {
-}
-StatsDimensionsValue::StatsDimensionsValue(int32_t field, vector<StatsDimensionsValue> value) :
- mField(field),
- mValueType(kTupleValueType),
- mTupleValue(value) {
-}
-
-StatsDimensionsValue::~StatsDimensionsValue() {}
-
-status_t
-StatsDimensionsValue::writeToParcel(Parcel* out) const {
- status_t err ;
-
- err = out->writeInt32(mField);
- if (err != NO_ERROR) {
- return err;
- }
- err = out->writeInt32(mValueType);
- if (err != NO_ERROR) {
- return err;
- }
- switch (mValueType) {
- case kStrValueType:
- err = out->writeString16(mStrValue);
- break;
- case kIntValueType:
- err = out->writeInt32(mIntValue);
- break;
- case kLongValueType:
- err = out->writeInt64(mLongValue);
- break;
- case kBoolValueType:
- err = out->writeBool(mBoolValue);
- break;
- case kFloatValueType:
- err = out->writeFloat(mFloatValue);
- break;
- case kTupleValueType:
- {
- int sz = mTupleValue.size();
- err = out->writeInt32(sz);
- if (err != NO_ERROR) {
- return err;
- }
- for (int i = 0; i < sz; ++i) {
- err = mTupleValue[i].writeToParcel(out);
- if (err != NO_ERROR) {
- return err;
- }
- }
- }
- break;
- default:
- err = UNKNOWN_ERROR;
- break;
- }
- return err;
-}
-
-status_t
-StatsDimensionsValue::readFromParcel(const Parcel* in)
-{
- // Implement me if desired. We don't currently use this.
- ALOGE("Cannot do c++ StatsDimensionsValue.readFromParcel(); it is not implemented.");
- (void)in; // To prevent compile error of unused parameter 'in'
- return UNKNOWN_ERROR;
-}
-
-} // namespace os
-} // namespace android