diff options
Diffstat (limited to 'libs')
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 |