diff options
34 files changed, 925 insertions, 538 deletions
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 75c5e26fb0..5ab0abc561 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -46,9 +46,11 @@ using namespace aidl::android::hardware::graphics; namespace android { +using gui::DisplayCaptureArgs; using gui::IDisplayEventConnection; using gui::IRegionSamplingListener; using gui::IWindowInfosListener; +using gui::LayerCaptureArgs; using ui::ColorMode; class BpSurfaceComposer : public BpInterface<ISurfaceComposer> @@ -118,36 +120,6 @@ public: remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); } - status_t captureDisplay(const DisplayCaptureArgs& args, - const sp<IScreenCaptureListener>& captureListener) override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(args.write, data); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener)); - - return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply); - } - - status_t captureDisplay(DisplayId displayId, - const sp<IScreenCaptureListener>& captureListener) override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeUint64, displayId.value); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener)); - - return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply); - } - - status_t captureLayers(const LayerCaptureArgs& args, - const sp<IScreenCaptureListener>& captureListener) override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(args.write, data); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener)); - - return remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply); - } - bool authenticateSurfaceTexture( const sp<IGraphicBufferProducer>& bufferProducer) const override { Parcel data, reply; @@ -1451,36 +1423,6 @@ status_t BnSurfaceComposer::onTransact( bootFinished(); return NO_ERROR; } - case CAPTURE_DISPLAY: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - DisplayCaptureArgs args; - sp<IScreenCaptureListener> captureListener; - SAFE_PARCEL(args.read, data); - SAFE_PARCEL(data.readStrongBinder, &captureListener); - - return captureDisplay(args, captureListener); - } - case CAPTURE_DISPLAY_BY_ID: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - uint64_t value; - SAFE_PARCEL(data.readUint64, &value); - const auto id = DisplayId::fromValue(value); - if (!id) return BAD_VALUE; - - sp<IScreenCaptureListener> captureListener; - SAFE_PARCEL(data.readStrongBinder, &captureListener); - - return captureDisplay(*id, captureListener); - } - case CAPTURE_LAYERS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - LayerCaptureArgs args; - sp<IScreenCaptureListener> captureListener; - SAFE_PARCEL(args.read, data); - SAFE_PARCEL(data.readStrongBinder, &captureListener); - - return captureLayers(args, captureListener); - } case AUTHENTICATE_SURFACE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<IGraphicBufferProducer> bufferProducer = diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 9022e7d5a4..6944d38dfe 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -686,85 +686,89 @@ bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrame // ---------------------------------------------------------------------------- -status_t CaptureArgs::write(Parcel& output) const { - SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(pixelFormat)); - SAFE_PARCEL(output.write, sourceCrop); - SAFE_PARCEL(output.writeFloat, frameScaleX); - SAFE_PARCEL(output.writeFloat, frameScaleY); - SAFE_PARCEL(output.writeBool, captureSecureLayers); - SAFE_PARCEL(output.writeInt32, uid); - SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(dataspace)); - SAFE_PARCEL(output.writeBool, allowProtected); - SAFE_PARCEL(output.writeBool, grayscale); +namespace gui { + +status_t CaptureArgs::writeToParcel(Parcel* output) const { + SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(pixelFormat)); + SAFE_PARCEL(output->write, sourceCrop); + SAFE_PARCEL(output->writeFloat, frameScaleX); + SAFE_PARCEL(output->writeFloat, frameScaleY); + SAFE_PARCEL(output->writeBool, captureSecureLayers); + SAFE_PARCEL(output->writeInt32, uid); + SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(dataspace)); + SAFE_PARCEL(output->writeBool, allowProtected); + SAFE_PARCEL(output->writeBool, grayscale); return NO_ERROR; } -status_t CaptureArgs::read(const Parcel& input) { +status_t CaptureArgs::readFromParcel(const Parcel* input) { int32_t value = 0; - SAFE_PARCEL(input.readInt32, &value); + SAFE_PARCEL(input->readInt32, &value); pixelFormat = static_cast<ui::PixelFormat>(value); - SAFE_PARCEL(input.read, sourceCrop); - SAFE_PARCEL(input.readFloat, &frameScaleX); - SAFE_PARCEL(input.readFloat, &frameScaleY); - SAFE_PARCEL(input.readBool, &captureSecureLayers); - SAFE_PARCEL(input.readInt32, &uid); - SAFE_PARCEL(input.readInt32, &value); + SAFE_PARCEL(input->read, sourceCrop); + SAFE_PARCEL(input->readFloat, &frameScaleX); + SAFE_PARCEL(input->readFloat, &frameScaleY); + SAFE_PARCEL(input->readBool, &captureSecureLayers); + SAFE_PARCEL(input->readInt32, &uid); + SAFE_PARCEL(input->readInt32, &value); dataspace = static_cast<ui::Dataspace>(value); - SAFE_PARCEL(input.readBool, &allowProtected); - SAFE_PARCEL(input.readBool, &grayscale); + SAFE_PARCEL(input->readBool, &allowProtected); + SAFE_PARCEL(input->readBool, &grayscale); return NO_ERROR; } -status_t DisplayCaptureArgs::write(Parcel& output) const { - SAFE_PARCEL(CaptureArgs::write, output); +status_t DisplayCaptureArgs::writeToParcel(Parcel* output) const { + SAFE_PARCEL(CaptureArgs::writeToParcel, output); - SAFE_PARCEL(output.writeStrongBinder, displayToken); - SAFE_PARCEL(output.writeUint32, width); - SAFE_PARCEL(output.writeUint32, height); - SAFE_PARCEL(output.writeBool, useIdentityTransform); + SAFE_PARCEL(output->writeStrongBinder, displayToken); + SAFE_PARCEL(output->writeUint32, width); + SAFE_PARCEL(output->writeUint32, height); + SAFE_PARCEL(output->writeBool, useIdentityTransform); return NO_ERROR; } -status_t DisplayCaptureArgs::read(const Parcel& input) { - SAFE_PARCEL(CaptureArgs::read, input); +status_t DisplayCaptureArgs::readFromParcel(const Parcel* input) { + SAFE_PARCEL(CaptureArgs::readFromParcel, input); - SAFE_PARCEL(input.readStrongBinder, &displayToken); - SAFE_PARCEL(input.readUint32, &width); - SAFE_PARCEL(input.readUint32, &height); - SAFE_PARCEL(input.readBool, &useIdentityTransform); + SAFE_PARCEL(input->readStrongBinder, &displayToken); + SAFE_PARCEL(input->readUint32, &width); + SAFE_PARCEL(input->readUint32, &height); + SAFE_PARCEL(input->readBool, &useIdentityTransform); return NO_ERROR; } -status_t LayerCaptureArgs::write(Parcel& output) const { - SAFE_PARCEL(CaptureArgs::write, output); +status_t LayerCaptureArgs::writeToParcel(Parcel* output) const { + SAFE_PARCEL(CaptureArgs::writeToParcel, output); - SAFE_PARCEL(output.writeStrongBinder, layerHandle); - SAFE_PARCEL(output.writeInt32, excludeHandles.size()); + SAFE_PARCEL(output->writeStrongBinder, layerHandle); + SAFE_PARCEL(output->writeInt32, excludeHandles.size()); for (auto el : excludeHandles) { - SAFE_PARCEL(output.writeStrongBinder, el); + SAFE_PARCEL(output->writeStrongBinder, el); } - SAFE_PARCEL(output.writeBool, childrenOnly); + SAFE_PARCEL(output->writeBool, childrenOnly); return NO_ERROR; } -status_t LayerCaptureArgs::read(const Parcel& input) { - SAFE_PARCEL(CaptureArgs::read, input); +status_t LayerCaptureArgs::readFromParcel(const Parcel* input) { + SAFE_PARCEL(CaptureArgs::readFromParcel, input); - SAFE_PARCEL(input.readStrongBinder, &layerHandle); + SAFE_PARCEL(input->readStrongBinder, &layerHandle); int32_t numExcludeHandles = 0; - SAFE_PARCEL_READ_SIZE(input.readInt32, &numExcludeHandles, input.dataSize()); + SAFE_PARCEL_READ_SIZE(input->readInt32, &numExcludeHandles, input->dataSize()); excludeHandles.reserve(numExcludeHandles); for (int i = 0; i < numExcludeHandles; i++) { sp<IBinder> binder; - SAFE_PARCEL(input.readStrongBinder, &binder); + SAFE_PARCEL(input->readStrongBinder, &binder); excludeHandles.emplace(binder); } - SAFE_PARCEL(input.readBool, &childrenOnly); + SAFE_PARCEL(input->readBool, &childrenOnly); return NO_ERROR; } +}; // namespace gui + ReleaseCallbackId BufferData::generateReleaseCallbackId() const { return {buffer->getId(), frameNumber}; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 9269c3e5a7..26ccda580a 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -46,6 +46,7 @@ #include <ui/DynamicDisplayInfo.h> #include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> // This server size should always be smaller than the server cache size #define BUFFER_CACHE_MAX_SIZE 64 @@ -62,6 +63,7 @@ using ui::ColorMode; // --------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService); +ANDROID_SINGLETON_STATIC_INSTANCE(ComposerServiceAIDL); namespace { // Initialize transaction id counter used to generate transaction ids @@ -120,6 +122,52 @@ void ComposerService::composerServiceDied() mDeathObserver = nullptr; } +ComposerServiceAIDL::ComposerServiceAIDL() : Singleton<ComposerServiceAIDL>() { + std::scoped_lock lock(mMutex); + connectLocked(); +} + +bool ComposerServiceAIDL::connectLocked() { + const String16 name("SurfaceFlingerAIDL"); + mComposerService = waitForService<gui::ISurfaceComposer>(name); + if (mComposerService == nullptr) { + return false; // fatal error or permission problem + } + + // Create the death listener. + class DeathObserver : public IBinder::DeathRecipient { + ComposerServiceAIDL& mComposerService; + virtual void binderDied(const wp<IBinder>& who) { + ALOGW("ComposerService aidl remote (surfaceflinger) died [%p]", who.unsafe_get()); + mComposerService.composerServiceDied(); + } + + public: + explicit DeathObserver(ComposerServiceAIDL& mgr) : mComposerService(mgr) {} + }; + + mDeathObserver = new DeathObserver(*const_cast<ComposerServiceAIDL*>(this)); + IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver); + return true; +} + +/*static*/ sp<gui::ISurfaceComposer> ComposerServiceAIDL::getComposerService() { + ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance(); + std::scoped_lock lock(instance.mMutex); + if (instance.mComposerService == nullptr) { + if (ComposerServiceAIDL::getInstance().connectLocked()) { + ALOGD("ComposerServiceAIDL reconnected"); + } + } + return instance.mComposerService; +} + +void ComposerServiceAIDL::composerServiceDied() { + std::scoped_lock lock(mMutex); + mComposerService = nullptr; + mDeathObserver = nullptr; +} + class DefaultComposerClient: public Singleton<DefaultComposerClient> { Mutex mLock; sp<SurfaceComposerClient> mClient; @@ -2267,26 +2315,29 @@ status_t SurfaceComposerClient::removeWindowInfosListener( status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs, const sp<IScreenCaptureListener>& captureListener) { - sp<ISurfaceComposer> s(ComposerService::getComposerService()); + sp<gui::ISurfaceComposer> s(ComposerServiceAIDL::getComposerService()); if (s == nullptr) return NO_INIT; - return s->captureDisplay(captureArgs, captureListener); + binder::Status status = s->captureDisplay(captureArgs, captureListener); + return status.transactionError(); } status_t ScreenshotClient::captureDisplay(DisplayId displayId, const sp<IScreenCaptureListener>& captureListener) { - sp<ISurfaceComposer> s(ComposerService::getComposerService()); + sp<gui::ISurfaceComposer> s(ComposerServiceAIDL::getComposerService()); if (s == nullptr) return NO_INIT; - return s->captureDisplay(displayId, captureListener); + binder::Status status = s->captureDisplayById(displayId.value, captureListener); + return status.transactionError(); } status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs, const sp<IScreenCaptureListener>& captureListener) { - sp<ISurfaceComposer> s(ComposerService::getComposerService()); + sp<gui::ISurfaceComposer> s(ComposerServiceAIDL::getComposerService()); if (s == nullptr) return NO_INIT; - return s->captureLayers(captureArgs, captureListener); + binder::Status status = s->captureLayers(captureArgs, captureListener); + return status.transactionError(); } // --------------------------------------------------------------------------------- diff --git a/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl b/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl new file mode 100644 index 0000000000..2caa2b9f61 --- /dev/null +++ b/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2021 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. + */ + +package android.gui; + +parcelable DisplayCaptureArgs cpp_header "gui/DisplayCaptureArgs.h"; diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl new file mode 100644 index 0000000000..07921a59a5 --- /dev/null +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -0,0 +1,42 @@ +/* + * Copyright 2021 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. + */ + +package android.gui; + +import android.gui.DisplayCaptureArgs; +import android.gui.LayerCaptureArgs; +import android.gui.IScreenCaptureListener; + +/** @hide */ +interface ISurfaceComposer { + /** + * Capture the specified screen. This requires READ_FRAME_BUFFER + * permission. This function will fail if there is a secure window on + * screen and DisplayCaptureArgs.captureSecureLayers is false. + * + * This function can capture a subregion (the source crop) of the screen. + * The subregion can be optionally rotated. It will also be scaled to + * match the size of the output buffer. + */ + void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener); + void captureDisplayById(long displayId, IScreenCaptureListener listener); + /** + * Capture a subtree of the layer hierarchy, potentially ignoring the root node. + * This requires READ_FRAME_BUFFER permission. This function will fail if there + * is a secure window on screen + */ + void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener); +} diff --git a/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl b/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl new file mode 100644 index 0000000000..f0def5019a --- /dev/null +++ b/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2021 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. + */ + +package android.gui; + +parcelable LayerCaptureArgs cpp_header "gui/LayerCaptureArgs.h"; diff --git a/libs/gui/android/gui/FocusRequest.aidl b/libs/gui/android/gui/FocusRequest.aidl index 90186351c5..b13c60049c 100644 --- a/libs/gui/android/gui/FocusRequest.aidl +++ b/libs/gui/android/gui/FocusRequest.aidl @@ -21,7 +21,7 @@ parcelable FocusRequest { /** * Input channel token used to identify the window that should gain focus. */ - IBinder token; + @nullable IBinder token; @utf8InCpp String windowName; /** * The token that the caller expects currently to be focused. If the diff --git a/libs/gui/include/gui/DisplayCaptureArgs.h b/libs/gui/include/gui/DisplayCaptureArgs.h new file mode 100644 index 0000000000..ec884cfa8c --- /dev/null +++ b/libs/gui/include/gui/DisplayCaptureArgs.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <stdint.h> +#include <sys/types.h> + +#include <binder/IBinder.h> +#include <binder/Parcel.h> +#include <binder/Parcelable.h> +#include <ui/GraphicTypes.h> +#include <ui/PixelFormat.h> + +namespace android::gui { + +struct CaptureArgs : public Parcelable { + const static int32_t UNSET_UID = -1; + virtual ~CaptureArgs() = default; + + ui::PixelFormat pixelFormat{ui::PixelFormat::RGBA_8888}; + Rect sourceCrop; + float frameScaleX{1}; + float frameScaleY{1}; + bool captureSecureLayers{false}; + int32_t uid{UNSET_UID}; + // Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured + // result will be in the display's colorspace. + // The display may use non-RGB dataspace (ex. displayP3) that could cause pixel data could be + // different from SRGB (byte per color), and failed when checking colors in tests. + // NOTE: In normal cases, we want the screen to be captured in display's colorspace. + ui::Dataspace dataspace = ui::Dataspace::UNKNOWN; + + // The receiver of the capture can handle protected buffer. A protected buffer has + // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour. + // Any read/write access from unprotected context will result in undefined behaviour. + // Protected contents are typically DRM contents. This has no direct implication to the + // secure property of the surface, which is specified by the application explicitly to avoid + // the contents being accessed/captured by screenshot or unsecure display. + bool allowProtected = false; + + bool grayscale = false; + + virtual status_t writeToParcel(Parcel* output) const; + virtual status_t readFromParcel(const Parcel* input); +}; + +struct DisplayCaptureArgs : CaptureArgs { + sp<IBinder> displayToken; + uint32_t width{0}; + uint32_t height{0}; + bool useIdentityTransform{false}; + + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; +}; + +}; // namespace android::gui diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 0a59f52fcd..4dfc383b57 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -58,11 +58,9 @@ namespace android { struct client_cache_t; struct ComposerState; -struct DisplayCaptureArgs; struct DisplayStatInfo; struct DisplayState; struct InputWindowCommands; -struct LayerCaptureArgs; class LayerDebugInfo; class HdrCapabilities; class IGraphicBufferProducer; @@ -75,6 +73,13 @@ using gui::IRegionSamplingListener; using gui::IScreenCaptureListener; using gui::SpHash; +namespace gui { + +struct DisplayCaptureArgs; +struct LayerCaptureArgs; + +} // namespace gui + namespace ui { struct DisplayMode; @@ -261,27 +266,6 @@ public: */ virtual void setGameContentType(const sp<IBinder>& display, bool on) = 0; - /** - * Capture the specified screen. This requires READ_FRAME_BUFFER - * permission. This function will fail if there is a secure window on - * screen and DisplayCaptureArgs.captureSecureLayers is false. - * - * This function can capture a subregion (the source crop) of the screen. - * The subregion can be optionally rotated. It will also be scaled to - * match the size of the output buffer. - */ - virtual status_t captureDisplay(const DisplayCaptureArgs&, - const sp<IScreenCaptureListener>&) = 0; - - virtual status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) = 0; - - /** - * Capture a subtree of the layer hierarchy, potentially ignoring the root node. - * This requires READ_FRAME_BUFFER permission. This function will fail if there - * is a secure window on screen - */ - virtual status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) = 0; - /* Clears the frame statistics for animations. * * Requires the ACCESS_SURFACE_FLINGER permission. @@ -621,8 +605,8 @@ public: GET_DISPLAY_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. GET_ACTIVE_DISPLAY_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. GET_DISPLAY_STATE, - CAPTURE_DISPLAY, - CAPTURE_LAYERS, + CAPTURE_DISPLAY, // Deprecated. Autogenerated by .aidl now. + CAPTURE_LAYERS, // Deprecated. Autogenerated by .aidl now. CLEAR_ANIMATION_FRAME_STATS, GET_ANIMATION_FRAME_STATS, SET_POWER_MODE, @@ -649,7 +633,7 @@ public: GET_DESIRED_DISPLAY_MODE_SPECS, GET_DISPLAY_BRIGHTNESS_SUPPORT, SET_DISPLAY_BRIGHTNESS, - CAPTURE_DISPLAY_BY_ID, + CAPTURE_DISPLAY_BY_ID, // Deprecated. Autogenerated by .aidl now. NOTIFY_POWER_BOOST, SET_GLOBAL_SHADOW_SETTINGS, GET_AUTO_LOW_LATENCY_MODE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. diff --git a/libs/gui/include/gui/LayerCaptureArgs.h b/libs/gui/include/gui/LayerCaptureArgs.h new file mode 100644 index 0000000000..05ff9d5b7b --- /dev/null +++ b/libs/gui/include/gui/LayerCaptureArgs.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/DisplayCaptureArgs.h> +#include <gui/SpHash.h> +#include <unordered_set> + +namespace android::gui { + +struct LayerCaptureArgs : CaptureArgs { + sp<IBinder> layerHandle; + std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles; + bool childrenOnly{false}; + + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; +}; + +}; // namespace android::gui diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index f7206193cd..7a36fdaaec 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -29,7 +29,9 @@ #include <android/gui/DropInputMode.h> #include <android/gui/FocusRequest.h> +#include <gui/DisplayCaptureArgs.h> #include <gui/ISurfaceComposer.h> +#include <gui/LayerCaptureArgs.h> #include <gui/LayerMetadata.h> #include <gui/SpHash.h> #include <gui/SurfaceControl.h> @@ -370,56 +372,6 @@ static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy, const char* functionName, bool privileged = false); -struct CaptureArgs { - const static int32_t UNSET_UID = -1; - virtual ~CaptureArgs() = default; - - ui::PixelFormat pixelFormat{ui::PixelFormat::RGBA_8888}; - Rect sourceCrop; - float frameScaleX{1}; - float frameScaleY{1}; - bool captureSecureLayers{false}; - int32_t uid{UNSET_UID}; - // Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured - // result will be in the display's colorspace. - // The display may use non-RGB dataspace (ex. displayP3) that could cause pixel data could be - // different from SRGB (byte per color), and failed when checking colors in tests. - // NOTE: In normal cases, we want the screen to be captured in display's colorspace. - ui::Dataspace dataspace = ui::Dataspace::UNKNOWN; - - // The receiver of the capture can handle protected buffer. A protected buffer has - // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour. - // Any read/write access from unprotected context will result in undefined behaviour. - // Protected contents are typically DRM contents. This has no direct implication to the - // secure property of the surface, which is specified by the application explicitly to avoid - // the contents being accessed/captured by screenshot or unsecure display. - bool allowProtected = false; - - bool grayscale = false; - - virtual status_t write(Parcel& output) const; - virtual status_t read(const Parcel& input); -}; - -struct DisplayCaptureArgs : CaptureArgs { - sp<IBinder> displayToken; - uint32_t width{0}; - uint32_t height{0}; - bool useIdentityTransform{false}; - - status_t write(Parcel& output) const override; - status_t read(const Parcel& input) override; -}; - -struct LayerCaptureArgs : CaptureArgs { - sp<IBinder> layerHandle; - std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles; - bool childrenOnly{false}; - - status_t write(Parcel& output) const override; - status_t read(const Parcel& input) override; -}; - }; // namespace android #endif // ANDROID_SF_LAYER_STATE_H diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 25637efce2..6c79b5bbbc 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -57,7 +57,9 @@ class IGraphicBufferProducer; class ITunnelModeEnabledListener; class Region; +using gui::DisplayCaptureArgs; using gui::IRegionSamplingListener; +using gui::LayerCaptureArgs; struct SurfaceControlStats { SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime, diff --git a/libs/gui/include/private/gui/ComposerService.h b/libs/gui/include/private/gui/ComposerService.h index fa1071a4e3..05ed0a0576 100644 --- a/libs/gui/include/private/gui/ComposerService.h +++ b/libs/gui/include/private/gui/ComposerService.h @@ -37,7 +37,7 @@ class ISurfaceComposer; // Users of this class should not retain the value from // getComposerService() for an extended period. // -// (It's not clear that using Singleton is useful here anymore.) +// (TODO: b/219785927, It's not clear that using Singleton is useful here anymore.) class ComposerService : public Singleton<ComposerService> { sp<ISurfaceComposer> mComposerService; diff --git a/libs/gui/include/private/gui/ComposerServiceAIDL.h b/libs/gui/include/private/gui/ComposerServiceAIDL.h new file mode 100644 index 0000000000..fee37eefe0 --- /dev/null +++ b/libs/gui/include/private/gui/ComposerServiceAIDL.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <stdint.h> +#include <sys/types.h> + +#include <android/gui/ISurfaceComposer.h> + +#include <utils/Singleton.h> +#include <utils/StrongPointer.h> + +namespace android { + +// --------------------------------------------------------------------------- + +// --------------------------------------------------------------------------- + +// This holds our connection to the composer service (i.e. SurfaceFlinger). +// If the remote side goes away, we will re-establish the connection. +// Users of this class should not retain the value from +// getComposerService() for an extended period. +// +// (TODO: b/219785927, It's not clear that using Singleton is useful here anymore.) +class ComposerServiceAIDL : public Singleton<ComposerServiceAIDL> { + sp<gui::ISurfaceComposer> mComposerService; + sp<IBinder::DeathRecipient> mDeathObserver; + mutable std::mutex mMutex; + + ComposerServiceAIDL(); + bool connectLocked(); + void composerServiceDied(); + friend class Singleton<ComposerServiceAIDL>; + +public: + // Get a connection to the Composer Service. This will block until + // a connection is established. Returns null if permission is denied. + static sp<gui::ISurfaceComposer> getComposerService(); +}; + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 42a32f3b42..179bdd76aa 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -29,6 +29,7 @@ #include <gui/SyncScreenCaptureListener.h> #include <gui/test/CallbackUtils.h> #include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <ui/DisplayMode.h> #include <ui/GraphicBuffer.h> #include <ui/GraphicTypes.h> @@ -283,13 +284,13 @@ protected: static status_t captureDisplay(DisplayCaptureArgs& captureArgs, ScreenCaptureResults& captureResults) { - const auto sf = ComposerService::getComposerService(); + const auto sf = ComposerServiceAIDL::getComposerService(); SurfaceComposerClient::Transaction().apply(true); const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); - status_t status = sf->captureDisplay(captureArgs, captureListener); - if (status != NO_ERROR) { - return status; + binder::Status status = sf->captureDisplay(captureArgs, captureListener); + if (status.transactionError() != NO_ERROR) { + return status.transactionError(); } captureResults = captureListener->waitForResults(); return captureResults.result; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 605628096d..a885e926a3 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -31,6 +31,7 @@ #include <gui/SyncScreenCaptureListener.h> #include <inttypes.h> #include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <sys/types.h> #include <ui/BufferQueueDefs.h> #include <ui/DisplayMode.h> @@ -205,13 +206,13 @@ protected: static status_t captureDisplay(DisplayCaptureArgs& captureArgs, ScreenCaptureResults& captureResults) { - const auto sf = ComposerService::getComposerService(); + const auto sf = ComposerServiceAIDL::getComposerService(); SurfaceComposerClient::Transaction().apply(true); const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); - status_t status = sf->captureDisplay(captureArgs, captureListener); - if (status != NO_ERROR) { - return status; + binder::Status status = sf->captureDisplay(captureArgs, captureListener); + if (status.transactionError() != NO_ERROR) { + return status.transactionError(); } captureResults = captureListener->waitForResults(); return captureResults.result; @@ -766,16 +767,6 @@ public: void setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {} void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {} - status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&) override { - return NO_ERROR; - } - status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) override { - return NO_ERROR; - } - status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) override { - return NO_ERROR; - } - status_t clearAnimationFrameStats() override { return NO_ERROR; } status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override { return NO_ERROR; diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 381900e4ba..576941f06a 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -353,12 +353,12 @@ int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** out return INVALID_OPERATION; } - GraphicBuffer* gBuffer = new GraphicBuffer(); + sp<GraphicBuffer> gBuffer(new GraphicBuffer()); status_t err = gBuffer->unflatten(data, dataLen, fdData, fdCount); if (err != NO_ERROR) { return err; } - *outBuffer = AHardwareBuffer_from_GraphicBuffer(gBuffer); + *outBuffer = AHardwareBuffer_from_GraphicBuffer(gBuffer.get()); // Ensure the buffer has a positive ref-count. AHardwareBuffer_acquire(*outBuffer); diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index cd20a646a7..9691ad8a79 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -61,18 +61,13 @@ private: ALOGE("There is no focused window for %s", applicationHandle->getName().c_str()); } - void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, + void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, std::optional<int32_t> pid, const std::string& reason) override { ALOGE("Window is not responding: %s", reason.c_str()); } - void notifyWindowResponsive(const sp<IBinder>& connectionToken) override {} - - void notifyMonitorUnresponsive(int32_t pid, const std::string& reason) override { - ALOGE("Monitor is not responding: %s", reason.c_str()); - } - - void notifyMonitorResponsive(int32_t pid) override {} + void notifyWindowResponsive(const sp<IBinder>& connectionToken, + std::optional<int32_t> pid) override {} void notifyInputChannelBroken(const sp<IBinder>&) override {} diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 58c93036bb..cecfc4dc03 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -118,10 +118,7 @@ const std::chrono::duration DEFAULT_INPUT_DISPATCHING_TIMEOUT = std::chrono::mil // when an application takes too long to respond and the user has pressed an app switch key. constexpr nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec -// Amount of time to allow for an event to be dispatched (measured since its eventTime) -// before considering it stale and dropping it. -const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL // 10sec - * HwTimeoutMultiplier(); +const std::chrono::duration STALE_EVENT_TIMEOUT = std::chrono::seconds(10) * HwTimeoutMultiplier(); // Log a warning when an event takes longer than this to process, even if an ANR does not occur. constexpr nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec @@ -322,10 +319,6 @@ bool haveSameApplicationToken(const WindowInfo* first, const WindowInfo* second) first->applicationInfo.token == second->applicationInfo.token; } -bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry) { - return currentTime - entry.eventTime >= STALE_EVENT_TIMEOUT; -} - std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget, std::shared_ptr<EventEntry> eventEntry, int32_t inputTargetFlags) { @@ -526,6 +519,10 @@ bool isPointerFromStylus(const MotionEntry& entry, int32_t pointerIndex) { // --- InputDispatcher --- InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) + : InputDispatcher(policy, STALE_EVENT_TIMEOUT) {} + +InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy, + std::chrono::nanoseconds staleEventTimeout) : mPolicy(policy), mPendingEvent(nullptr), mLastDropReason(DropReason::NOT_DROPPED), @@ -544,6 +541,7 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mMaximumObscuringOpacityForTouch(1.0f), mFocusedDisplayId(ADISPLAY_ID_DEFAULT), mWindowTokenWithPointerCapture(nullptr), + mStaleEventTimeout(staleEventTimeout), mLatencyAggregator(), mLatencyTracker(&mLatencyAggregator) { mLooper = new Looper(false); @@ -901,6 +899,10 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { } } +bool InputDispatcher::isStaleEvent(nsecs_t currentTime, const EventEntry& entry) { + return std::chrono::nanoseconds(currentTime - entry.eventTime) >= mStaleEventTimeout; +} + /** * Return true if the events preceding this incoming motion event should be dropped * Return false otherwise (the default behaviour) @@ -5816,35 +5818,21 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingCommand(const sp<IBinder>& } } -void InputDispatcher::sendMonitorUnresponsiveCommandLocked(int32_t pid, std::string reason) { - auto command = [this, pid, reason = std::move(reason)]() REQUIRES(mLock) { - scoped_unlock unlock(mLock); - mPolicy->notifyMonitorUnresponsive(pid, reason); - }; - postCommandLocked(std::move(command)); -} - void InputDispatcher::sendWindowUnresponsiveCommandLocked(const sp<IBinder>& token, + std::optional<int32_t> pid, std::string reason) { - auto command = [this, token, reason = std::move(reason)]() REQUIRES(mLock) { - scoped_unlock unlock(mLock); - mPolicy->notifyWindowUnresponsive(token, reason); - }; - postCommandLocked(std::move(command)); -} - -void InputDispatcher::sendMonitorResponsiveCommandLocked(int32_t pid) { - auto command = [this, pid]() REQUIRES(mLock) { + auto command = [this, token, pid, reason = std::move(reason)]() REQUIRES(mLock) { scoped_unlock unlock(mLock); - mPolicy->notifyMonitorResponsive(pid); + mPolicy->notifyWindowUnresponsive(token, pid, reason); }; postCommandLocked(std::move(command)); } -void InputDispatcher::sendWindowResponsiveCommandLocked(const sp<IBinder>& connectionToken) { - auto command = [this, connectionToken]() REQUIRES(mLock) { +void InputDispatcher::sendWindowResponsiveCommandLocked(const sp<IBinder>& token, + std::optional<int32_t> pid) { + auto command = [this, token, pid]() REQUIRES(mLock) { scoped_unlock unlock(mLock); - mPolicy->notifyWindowResponsive(connectionToken); + mPolicy->notifyWindowResponsive(token, pid); }; postCommandLocked(std::move(command)); } @@ -5857,22 +5845,21 @@ void InputDispatcher::sendWindowResponsiveCommandLocked(const sp<IBinder>& conne void InputDispatcher::processConnectionUnresponsiveLocked(const Connection& connection, std::string reason) { const sp<IBinder>& connectionToken = connection.inputChannel->getConnectionToken(); + std::optional<int32_t> pid; if (connection.monitor) { ALOGW("Monitor %s is unresponsive: %s", connection.inputChannel->getName().c_str(), reason.c_str()); - std::optional<int32_t> pid = findMonitorPidByTokenLocked(connectionToken); - if (!pid.has_value()) { - ALOGE("Could not find unresponsive monitor for connection %s", - connection.inputChannel->getName().c_str()); - return; + pid = findMonitorPidByTokenLocked(connectionToken); + } else { + // The connection is a window + ALOGW("Window %s is unresponsive: %s", connection.inputChannel->getName().c_str(), + reason.c_str()); + const sp<WindowInfoHandle> handle = getWindowHandleLocked(connectionToken); + if (handle != nullptr) { + pid = handle->getInfo()->ownerPid; } - sendMonitorUnresponsiveCommandLocked(pid.value(), std::move(reason)); - return; } - // If not a monitor, must be a window - ALOGW("Window %s is unresponsive: %s", connection.inputChannel->getName().c_str(), - reason.c_str()); - sendWindowUnresponsiveCommandLocked(connectionToken, std::move(reason)); + sendWindowUnresponsiveCommandLocked(connectionToken, pid, std::move(reason)); } /** @@ -5880,18 +5867,17 @@ void InputDispatcher::processConnectionUnresponsiveLocked(const Connection& conn */ void InputDispatcher::processConnectionResponsiveLocked(const Connection& connection) { const sp<IBinder>& connectionToken = connection.inputChannel->getConnectionToken(); + std::optional<int32_t> pid; if (connection.monitor) { - std::optional<int32_t> pid = findMonitorPidByTokenLocked(connectionToken); - if (!pid.has_value()) { - ALOGE("Could not find responsive monitor for connection %s", - connection.inputChannel->getName().c_str()); - return; + pid = findMonitorPidByTokenLocked(connectionToken); + } else { + // The connection is a window + const sp<WindowInfoHandle> handle = getWindowHandleLocked(connectionToken); + if (handle != nullptr) { + pid = handle->getInfo()->ownerPid; } - sendMonitorResponsiveCommandLocked(pid.value()); - return; } - // If not a monitor, must be a window - sendWindowResponsiveCommandLocked(connectionToken); + sendWindowResponsiveCommandLocked(connectionToken, pid); } bool InputDispatcher::afterKeyEventLockedInterruptable(const sp<Connection>& connection, diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index e162c78b81..3c79c988c4 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -84,6 +84,8 @@ public: static constexpr bool kDefaultInTouchMode = true; explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy); + explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy, + std::chrono::nanoseconds staleEventTimeout); ~InputDispatcher() override; void dump(std::string& dump) override; @@ -471,6 +473,11 @@ private: */ std::optional<nsecs_t> mNoFocusedWindowTimeoutTime GUARDED_BY(mLock); + // Amount of time to allow for an event to be dispatched (measured since its eventTime) + // before considering it stale and dropping it. + const std::chrono::nanoseconds mStaleEventTimeout; + bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry); + bool shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) REQUIRES(mLock); /** @@ -503,11 +510,11 @@ private: */ void processConnectionResponsiveLocked(const Connection& connection) REQUIRES(mLock); - void sendMonitorUnresponsiveCommandLocked(int32_t pid, std::string reason) REQUIRES(mLock); - void sendWindowUnresponsiveCommandLocked(const sp<IBinder>& connectionToken, std::string reason) + void sendWindowUnresponsiveCommandLocked(const sp<IBinder>& connectionToken, + std::optional<int32_t> pid, std::string reason) REQUIRES(mLock); - void sendMonitorResponsiveCommandLocked(int32_t pid) REQUIRES(mLock); - void sendWindowResponsiveCommandLocked(const sp<IBinder>& connectionToken) REQUIRES(mLock); + void sendWindowResponsiveCommandLocked(const sp<IBinder>& connectionToken, + std::optional<int32_t> pid) REQUIRES(mLock); // Optimization: AnrTracker is used to quickly find which connection is due for a timeout next. // AnrTracker must be kept in-sync with all responsive connection.waitQueues. diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h index 3c1e6370b7..de0b6da884 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h @@ -51,30 +51,19 @@ public: const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) = 0; /* Notifies the system that a window just became unresponsive. This indicates that ANR - * should be raised for this window. The window is identified via token. - * The string reason contains information about the input event that we haven't received - * a response for. + * should be raised for this window. The window can be identified via its input token and the + * pid of the owner. The string reason contains information about the input event that we + * haven't received a response for. */ - virtual void notifyWindowUnresponsive(const sp<IBinder>& token, const std::string& reason) = 0; - /* Notifies the system that a monitor just became unresponsive. This indicates that ANR - * should be raised for this monitor. The monitor is identified via its pid. - * The string reason contains information about the input event that we haven't received - * a response for. - */ - virtual void notifyMonitorUnresponsive(int32_t pid, const std::string& reason) = 0; + virtual void notifyWindowUnresponsive(const sp<IBinder>& token, std::optional<int32_t> pid, + const std::string& reason) = 0; /* Notifies the system that a window just became responsive. This is only called after the * window was first marked "unresponsive". This indicates that ANR dialog (if any) should * no longer should be shown to the user. The window is eligible to cause a new ANR in the * future. */ - virtual void notifyWindowResponsive(const sp<IBinder>& token) = 0; - /* Notifies the system that a monitor just became responsive. This is only called after the - * monitor was first marked "unresponsive". This indicates that ANR dialog (if any) should - * no longer should be shown to the user. The monitor is eligible to cause a new ANR in the - * future. - */ - virtual void notifyMonitorResponsive(int32_t pid) = 0; + virtual void notifyWindowResponsive(const sp<IBinder>& token, std::optional<int32_t> pid) = 0; /* Notifies the system that an input channel is unrecoverably broken. */ virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0; diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp index 41a8426e42..8f5dc9bfd5 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp @@ -31,23 +31,15 @@ static constexpr size_t MAX_SLOTS = 32; MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : mCurrentSlot(-1), - mSlots(nullptr), - mSlotCount(0), mUsingSlotsProtocol(false), mHaveStylus(false) {} -MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { - delete[] mSlots; -} - void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol) { - mSlotCount = slotCount; mUsingSlotsProtocol = usingSlotsProtocol; mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE); - delete[] mSlots; - mSlots = new Slot[slotCount]; + mSlots = std::vector<Slot>(slotCount); } void MultiTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) { @@ -76,10 +68,8 @@ void MultiTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) { } void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { - if (mSlots) { - for (size_t i = 0; i < mSlotCount; i++) { - mSlots[i].clear(); - } + for (Slot& slot : mSlots) { + slot.clear(); } mCurrentSlot = initialSlot; } @@ -96,68 +86,68 @@ void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { mCurrentSlot = 0; } - if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { + if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) { if (DEBUG_POINTERS) { if (newSlot) { ALOGW("MultiTouch device emitted invalid slot index %d but it " "should be between 0 and %zd; ignoring this slot.", - mCurrentSlot, mSlotCount - 1); + mCurrentSlot, mSlots.size() - 1); } } } else { - Slot* slot = &mSlots[mCurrentSlot]; + Slot& slot = mSlots[mCurrentSlot]; // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while // updating the slot. if (!mUsingSlotsProtocol) { - slot->mInUse = true; + slot.mInUse = true; } switch (rawEvent->code) { case ABS_MT_POSITION_X: - slot->mAbsMTPositionX = rawEvent->value; - warnIfNotInUse(*rawEvent, *slot); + slot.mAbsMTPositionX = rawEvent->value; + warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_POSITION_Y: - slot->mAbsMTPositionY = rawEvent->value; - warnIfNotInUse(*rawEvent, *slot); + slot.mAbsMTPositionY = rawEvent->value; + warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_TOUCH_MAJOR: - slot->mAbsMTTouchMajor = rawEvent->value; + slot.mAbsMTTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: - slot->mAbsMTTouchMinor = rawEvent->value; - slot->mHaveAbsMTTouchMinor = true; + slot.mAbsMTTouchMinor = rawEvent->value; + slot.mHaveAbsMTTouchMinor = true; break; case ABS_MT_WIDTH_MAJOR: - slot->mAbsMTWidthMajor = rawEvent->value; + slot.mAbsMTWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: - slot->mAbsMTWidthMinor = rawEvent->value; - slot->mHaveAbsMTWidthMinor = true; + slot.mAbsMTWidthMinor = rawEvent->value; + slot.mHaveAbsMTWidthMinor = true; break; case ABS_MT_ORIENTATION: - slot->mAbsMTOrientation = rawEvent->value; + slot.mAbsMTOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: if (mUsingSlotsProtocol && rawEvent->value < 0) { // The slot is no longer in use but it retains its previous contents, // which may be reused for subsequent touches. - slot->mInUse = false; + slot.mInUse = false; } else { - slot->mInUse = true; - slot->mAbsMTTrackingId = rawEvent->value; + slot.mInUse = true; + slot.mAbsMTTrackingId = rawEvent->value; } break; case ABS_MT_PRESSURE: - slot->mAbsMTPressure = rawEvent->value; + slot.mAbsMTPressure = rawEvent->value; break; case ABS_MT_DISTANCE: - slot->mAbsMTDistance = rawEvent->value; + slot.mAbsMTDistance = rawEvent->value; break; case ABS_MT_TOOL_TYPE: - slot->mAbsMTToolType = rawEvent->value; - slot->mHaveAbsMTToolType = true; + slot.mAbsMTToolType = rawEvent->value; + slot.mHaveAbsMTToolType = true; break; } } @@ -186,28 +176,6 @@ void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Sl // --- MultiTouchMotionAccumulator::Slot --- -MultiTouchMotionAccumulator::Slot::Slot() { - clear(); -} - -void MultiTouchMotionAccumulator::Slot::clear() { - mInUse = false; - mHaveAbsMTTouchMinor = false; - mHaveAbsMTWidthMinor = false; - mHaveAbsMTToolType = false; - mAbsMTPositionX = 0; - mAbsMTPositionY = 0; - mAbsMTTouchMajor = 0; - mAbsMTTouchMinor = 0; - mAbsMTWidthMajor = 0; - mAbsMTWidthMinor = 0; - mAbsMTOrientation = 0; - mAbsMTTrackingId = -1; - mAbsMTPressure = 0; - mAbsMTDistance = 0; - mAbsMTToolType = 0; -} - int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { if (mHaveAbsMTToolType) { switch (mAbsMTToolType) { @@ -264,14 +232,14 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { mHavePointerIds = true; for (size_t inIndex = 0; inIndex < inCount; inIndex++) { - const MultiTouchMotionAccumulator::Slot* inSlot = + const MultiTouchMotionAccumulator::Slot& inSlot = mMultiTouchMotionAccumulator.getSlot(inIndex); - if (!inSlot->isInUse()) { + if (!inSlot.isInUse()) { continue; } - if (inSlot->getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) { - std::optional<int32_t> id = getActiveBitId(*inSlot); + if (inSlot.getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) { + std::optional<int32_t> id = getActiveBitId(inSlot); if (id) { outState->rawPointerData.canceledIdBits.markBit(id.value()); } @@ -292,19 +260,19 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { } RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount]; - outPointer.x = inSlot->getX(); - outPointer.y = inSlot->getY(); - outPointer.pressure = inSlot->getPressure(); - outPointer.touchMajor = inSlot->getTouchMajor(); - outPointer.touchMinor = inSlot->getTouchMinor(); - outPointer.toolMajor = inSlot->getToolMajor(); - outPointer.toolMinor = inSlot->getToolMinor(); - outPointer.orientation = inSlot->getOrientation(); - outPointer.distance = inSlot->getDistance(); + outPointer.x = inSlot.getX(); + outPointer.y = inSlot.getY(); + outPointer.pressure = inSlot.getPressure(); + outPointer.touchMajor = inSlot.getTouchMajor(); + outPointer.touchMinor = inSlot.getTouchMinor(); + outPointer.toolMajor = inSlot.getToolMajor(); + outPointer.toolMinor = inSlot.getToolMinor(); + outPointer.orientation = inSlot.getOrientation(); + outPointer.distance = inSlot.getDistance(); outPointer.tiltX = 0; outPointer.tiltY = 0; - outPointer.toolType = inSlot->getToolType(); + outPointer.toolType = inSlot.getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = mTouchButtonAccumulator.getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { @@ -318,12 +286,12 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && (mTouchButtonAccumulator.isHovering() || - (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0)); + (mRawPointerAxes.pressure.valid && inSlot.getPressure() <= 0)); outPointer.isHovering = isHovering; // Assign pointer id using tracking id if available. if (mHavePointerIds) { - int32_t trackingId = inSlot->getTrackingId(); + int32_t trackingId = inSlot.getTrackingId(); int32_t id = -1; if (trackingId >= 0) { for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) { diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h index b7c3457285..fe8af5d818 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h @@ -46,29 +46,27 @@ public: private: friend class MultiTouchMotionAccumulator; - bool mInUse; - bool mHaveAbsMTTouchMinor; - bool mHaveAbsMTWidthMinor; - bool mHaveAbsMTToolType; - - int32_t mAbsMTPositionX; - int32_t mAbsMTPositionY; - int32_t mAbsMTTouchMajor; - int32_t mAbsMTTouchMinor; - int32_t mAbsMTWidthMajor; - int32_t mAbsMTWidthMinor; - int32_t mAbsMTOrientation; - int32_t mAbsMTTrackingId; - int32_t mAbsMTPressure; - int32_t mAbsMTDistance; - int32_t mAbsMTToolType; - - Slot(); - void clear(); + bool mInUse = false; + bool mHaveAbsMTTouchMinor = false; + bool mHaveAbsMTWidthMinor = false; + bool mHaveAbsMTToolType = false; + + int32_t mAbsMTPositionX = 0; + int32_t mAbsMTPositionY = 0; + int32_t mAbsMTTouchMajor = 0; + int32_t mAbsMTTouchMinor = 0; + int32_t mAbsMTWidthMajor = 0; + int32_t mAbsMTWidthMinor = 0; + int32_t mAbsMTOrientation = 0; + int32_t mAbsMTTrackingId = -1; + int32_t mAbsMTPressure = 0; + int32_t mAbsMTDistance = 0; + int32_t mAbsMTToolType = 0; + + void clear() { *this = Slot(); } }; MultiTouchMotionAccumulator(); - ~MultiTouchMotionAccumulator(); void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol); void reset(InputDeviceContext& deviceContext); @@ -76,13 +74,15 @@ public: void finishSync(); bool hasStylus() const; - inline size_t getSlotCount() const { return mSlotCount; } - inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } + inline size_t getSlotCount() const { return mSlots.size(); } + inline const Slot& getSlot(size_t index) const { + LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index); + return mSlots[index]; + } private: int32_t mCurrentSlot; - Slot* mSlots; - size_t mSlotCount; + std::vector<Slot> mSlots; bool mUsingSlotsProtocol; bool mHaveStylus; diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp index ffce9f68cc..91be4a30bf 100644 --- a/services/inputflinger/tests/FocusResolver_test.cpp +++ b/services/inputflinger/tests/FocusResolver_test.cpp @@ -84,6 +84,30 @@ TEST(FocusResolverTest, SetFocusedWindow) { ASSERT_FALSE(changes); } +TEST(FocusResolverTest, RemoveFocusFromFocusedWindow) { + sp<IBinder> focusableWindowToken = new BBinder(); + std::vector<sp<WindowInfoHandle>> windows; + windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */, + true /* visible */)); + + FocusRequest request; + request.displayId = 42; + request.token = focusableWindowToken; + FocusResolver focusResolver; + // Focusable window gets focus. + request.token = focusableWindowToken; + std::optional<FocusResolver::FocusChanges> changes = + focusResolver.setFocusedWindow(request, windows); + ASSERT_FOCUS_CHANGE(changes, nullptr, focusableWindowToken); + + // Window token of a request is null, focus should be revoked. + request.token = NULL; + changes = focusResolver.setFocusedWindow(request, windows); + ASSERT_EQ(focusableWindowToken, changes->oldFocus); + ASSERT_EQ(nullptr, changes->newFocus); + ASSERT_FOCUS_CHANGE(changes, focusableWindowToken, nullptr); +} + TEST(FocusResolverTest, SetFocusedMirroredWindow) { sp<IBinder> focusableWindowToken = new BBinder(); sp<IBinder> invisibleWindowToken = new BBinder(); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index ae8358aa5d..3fb406c92c 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -60,6 +60,8 @@ static const int32_t INJECTOR_UID = 1001; // An arbitrary pid of the gesture monitor window static constexpr int32_t MONITOR_PID = 2001; +static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms; + struct PointF { float x; float y; @@ -88,6 +90,8 @@ static void assertMotionAction(int32_t expectedAction, int32_t receivedAction) { class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { InputDispatcherConfiguration mConfig; + using AnrResult = std::pair<sp<IBinder>, int32_t /*pid*/>; + protected: virtual ~FakeInputDispatcherPolicy() {} @@ -161,122 +165,71 @@ public: void assertNotifyNoFocusedWindowAnrWasCalled( std::chrono::nanoseconds timeout, const std::shared_ptr<InputApplicationHandle>& expectedApplication) { + std::unique_lock lock(mLock); + android::base::ScopedLockAssertion assumeLocked(mLock); std::shared_ptr<InputApplicationHandle> application; - { // acquire lock - std::unique_lock lock(mLock); - android::base::ScopedLockAssertion assumeLocked(mLock); - ASSERT_NO_FATAL_FAILURE( - application = getAnrTokenLockedInterruptible(timeout, mAnrApplications, lock)); - } // release lock + ASSERT_NO_FATAL_FAILURE( + application = getAnrTokenLockedInterruptible(timeout, mAnrApplications, lock)); ASSERT_EQ(expectedApplication, application); } void assertNotifyWindowUnresponsiveWasCalled(std::chrono::nanoseconds timeout, - const sp<IBinder>& expectedConnectionToken) { - sp<IBinder> connectionToken = getUnresponsiveWindowToken(timeout); - ASSERT_EQ(expectedConnectionToken, connectionToken); - } - - void assertNotifyWindowResponsiveWasCalled(const sp<IBinder>& expectedConnectionToken) { - sp<IBinder> connectionToken = getResponsiveWindowToken(); - ASSERT_EQ(expectedConnectionToken, connectionToken); - } - - void assertNotifyMonitorUnresponsiveWasCalled(std::chrono::nanoseconds timeout) { - int32_t pid = getUnresponsiveMonitorPid(timeout); - ASSERT_EQ(MONITOR_PID, pid); - } - - void assertNotifyMonitorResponsiveWasCalled() { - int32_t pid = getResponsiveMonitorPid(); - ASSERT_EQ(MONITOR_PID, pid); + const sp<WindowInfoHandle>& window) { + LOG_ALWAYS_FATAL_IF(window == nullptr, "window should not be null"); + assertNotifyWindowUnresponsiveWasCalled(timeout, window->getToken(), + window->getInfo()->ownerPid); } - sp<IBinder> getUnresponsiveWindowToken(std::chrono::nanoseconds timeout) { + void assertNotifyWindowUnresponsiveWasCalled(std::chrono::nanoseconds timeout, + const sp<IBinder>& expectedToken, + int32_t expectedPid) { std::unique_lock lock(mLock); android::base::ScopedLockAssertion assumeLocked(mLock); - return getAnrTokenLockedInterruptible(timeout, mAnrWindowTokens, lock); + AnrResult result; + ASSERT_NO_FATAL_FAILURE(result = + getAnrTokenLockedInterruptible(timeout, mAnrWindows, lock)); + const auto& [token, pid] = result; + ASSERT_EQ(expectedToken, token); + ASSERT_EQ(expectedPid, pid); } - sp<IBinder> getResponsiveWindowToken() { + /** Wrap call with ASSERT_NO_FATAL_FAILURE() to ensure the return value is valid. */ + sp<IBinder> getUnresponsiveWindowToken(std::chrono::nanoseconds timeout) { std::unique_lock lock(mLock); android::base::ScopedLockAssertion assumeLocked(mLock); - return getAnrTokenLockedInterruptible(0s, mResponsiveWindowTokens, lock); + AnrResult result = getAnrTokenLockedInterruptible(timeout, mAnrWindows, lock); + const auto& [token, _] = result; + return token; } - int32_t getUnresponsiveMonitorPid(std::chrono::nanoseconds timeout) { + void assertNotifyWindowResponsiveWasCalled(const sp<IBinder>& expectedToken, + int32_t expectedPid) { std::unique_lock lock(mLock); android::base::ScopedLockAssertion assumeLocked(mLock); - return getAnrTokenLockedInterruptible(timeout, mAnrMonitorPids, lock); + AnrResult result; + ASSERT_NO_FATAL_FAILURE( + result = getAnrTokenLockedInterruptible(0s, mResponsiveWindows, lock)); + const auto& [token, pid] = result; + ASSERT_EQ(expectedToken, token); + ASSERT_EQ(expectedPid, pid); } - int32_t getResponsiveMonitorPid() { + /** Wrap call with ASSERT_NO_FATAL_FAILURE() to ensure the return value is valid. */ + sp<IBinder> getResponsiveWindowToken() { std::unique_lock lock(mLock); android::base::ScopedLockAssertion assumeLocked(mLock); - return getAnrTokenLockedInterruptible(0s, mResponsiveMonitorPids, lock); - } - - // All three ANR-related callbacks behave the same way, so we use this generic function to wait - // for a specific container to become non-empty. When the container is non-empty, return the - // first entry from the container and erase it. - template <class T> - T getAnrTokenLockedInterruptible(std::chrono::nanoseconds timeout, std::queue<T>& storage, - std::unique_lock<std::mutex>& lock) REQUIRES(mLock) { - // If there is an ANR, Dispatcher won't be idle because there are still events - // in the waitQueue that we need to check on. So we can't wait for dispatcher to be idle - // before checking if ANR was called. - // Since dispatcher is not guaranteed to call notifyNoFocusedWindowAnr right away, we need - // to provide it some time to act. 100ms seems reasonable. - std::chrono::duration timeToWait = timeout + 100ms; // provide some slack - const std::chrono::time_point start = std::chrono::steady_clock::now(); - std::optional<T> token = - getItemFromStorageLockedInterruptible(timeToWait, storage, lock, mNotifyAnr); - if (!token.has_value()) { - ADD_FAILURE() << "Did not receive the ANR callback"; - return {}; - } - - const std::chrono::duration waited = std::chrono::steady_clock::now() - start; - // Ensure that the ANR didn't get raised too early. We can't be too strict here because - // the dispatcher started counting before this function was called - if (std::chrono::abs(timeout - waited) > 100ms) { - ADD_FAILURE() << "ANR was raised too early or too late. Expected " - << std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count() - << "ms, but waited " - << std::chrono::duration_cast<std::chrono::milliseconds>(waited).count() - << "ms instead"; - } - return *token; - } - - template <class T> - std::optional<T> getItemFromStorageLockedInterruptible(std::chrono::nanoseconds timeout, - std::queue<T>& storage, - std::unique_lock<std::mutex>& lock, - std::condition_variable& condition) - REQUIRES(mLock) { - condition.wait_for(lock, timeout, - [&storage]() REQUIRES(mLock) { return !storage.empty(); }); - if (storage.empty()) { - ADD_FAILURE() << "Did not receive the expected callback"; - return std::nullopt; - } - T item = storage.front(); - storage.pop(); - return std::make_optional(item); + AnrResult result = getAnrTokenLockedInterruptible(0s, mResponsiveWindows, lock); + const auto& [token, _] = result; + return token; } void assertNotifyAnrWasNotCalled() { std::scoped_lock lock(mLock); ASSERT_TRUE(mAnrApplications.empty()); - ASSERT_TRUE(mAnrWindowTokens.empty()); - ASSERT_TRUE(mAnrMonitorPids.empty()); - ASSERT_TRUE(mResponsiveWindowTokens.empty()) + ASSERT_TRUE(mAnrWindows.empty()); + ASSERT_TRUE(mResponsiveWindows.empty()) << "ANR was not called, but please also consume the 'connection is responsive' " "signal"; - ASSERT_TRUE(mResponsiveMonitorPids.empty()) - << "Monitor ANR was not called, but please also consume the 'monitor is responsive'" - " signal"; } void setKeyRepeatConfiguration(nsecs_t timeout, nsecs_t delay) { @@ -344,10 +297,8 @@ private: // ANR handling std::queue<std::shared_ptr<InputApplicationHandle>> mAnrApplications GUARDED_BY(mLock); - std::queue<sp<IBinder>> mAnrWindowTokens GUARDED_BY(mLock); - std::queue<sp<IBinder>> mResponsiveWindowTokens GUARDED_BY(mLock); - std::queue<int32_t> mAnrMonitorPids GUARDED_BY(mLock); - std::queue<int32_t> mResponsiveMonitorPids GUARDED_BY(mLock); + std::queue<AnrResult> mAnrWindows GUARDED_BY(mLock); + std::queue<AnrResult> mResponsiveWindows GUARDED_BY(mLock); std::condition_variable mNotifyAnr; std::queue<sp<IBinder>> mBrokenInputChannels GUARDED_BY(mLock); std::condition_variable mNotifyInputChannelBroken; @@ -355,32 +306,74 @@ private: sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock); bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false; - void notifyConfigurationChanged(nsecs_t when) override { - std::scoped_lock lock(mLock); - mConfigurationChangedTime = when; + // All three ANR-related callbacks behave the same way, so we use this generic function to wait + // for a specific container to become non-empty. When the container is non-empty, return the + // first entry from the container and erase it. + template <class T> + T getAnrTokenLockedInterruptible(std::chrono::nanoseconds timeout, std::queue<T>& storage, + std::unique_lock<std::mutex>& lock) REQUIRES(mLock) { + // If there is an ANR, Dispatcher won't be idle because there are still events + // in the waitQueue that we need to check on. So we can't wait for dispatcher to be idle + // before checking if ANR was called. + // Since dispatcher is not guaranteed to call notifyNoFocusedWindowAnr right away, we need + // to provide it some time to act. 100ms seems reasonable. + std::chrono::duration timeToWait = timeout + 100ms; // provide some slack + const std::chrono::time_point start = std::chrono::steady_clock::now(); + std::optional<T> token = + getItemFromStorageLockedInterruptible(timeToWait, storage, lock, mNotifyAnr); + if (!token.has_value()) { + ADD_FAILURE() << "Did not receive the ANR callback"; + return {}; + } + + const std::chrono::duration waited = std::chrono::steady_clock::now() - start; + // Ensure that the ANR didn't get raised too early. We can't be too strict here because + // the dispatcher started counting before this function was called + if (std::chrono::abs(timeout - waited) > 100ms) { + ADD_FAILURE() << "ANR was raised too early or too late. Expected " + << std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count() + << "ms, but waited " + << std::chrono::duration_cast<std::chrono::milliseconds>(waited).count() + << "ms instead"; + } + return *token; } - void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, const std::string&) override { - std::scoped_lock lock(mLock); - mAnrWindowTokens.push(connectionToken); - mNotifyAnr.notify_all(); + template <class T> + std::optional<T> getItemFromStorageLockedInterruptible(std::chrono::nanoseconds timeout, + std::queue<T>& storage, + std::unique_lock<std::mutex>& lock, + std::condition_variable& condition) + REQUIRES(mLock) { + condition.wait_for(lock, timeout, + [&storage]() REQUIRES(mLock) { return !storage.empty(); }); + if (storage.empty()) { + ADD_FAILURE() << "Did not receive the expected callback"; + return std::nullopt; + } + T item = storage.front(); + storage.pop(); + return std::make_optional(item); } - void notifyMonitorUnresponsive(int32_t pid, const std::string&) override { + void notifyConfigurationChanged(nsecs_t when) override { std::scoped_lock lock(mLock); - mAnrMonitorPids.push(pid); - mNotifyAnr.notify_all(); + mConfigurationChangedTime = when; } - void notifyWindowResponsive(const sp<IBinder>& connectionToken) override { + void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, std::optional<int32_t> pid, + const std::string&) override { std::scoped_lock lock(mLock); - mResponsiveWindowTokens.push(connectionToken); + ASSERT_TRUE(pid.has_value()); + mAnrWindows.push({connectionToken, *pid}); mNotifyAnr.notify_all(); } - void notifyMonitorResponsive(int32_t pid) override { + void notifyWindowResponsive(const sp<IBinder>& connectionToken, + std::optional<int32_t> pid) override { std::scoped_lock lock(mLock); - mResponsiveMonitorPids.push(pid); + ASSERT_TRUE(pid.has_value()); + mResponsiveWindows.push({connectionToken, *pid}); mNotifyAnr.notify_all(); } @@ -493,7 +486,7 @@ protected: void SetUp() override { mFakePolicy = new FakeInputDispatcherPolicy(); - mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy); + mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy, STALE_EVENT_TIMEOUT); mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); // Start InputDispatcher thread ASSERT_EQ(OK, mDispatcher->start()); @@ -1245,6 +1238,8 @@ public: mInfo.ownerUid = ownerUid; } + int32_t getPid() const { return mInfo.ownerPid; } + void destroyReceiver() { mInputReceiver = nullptr; } int getChannelFd() { return mInputReceiver->getChannelFd(); } @@ -4364,13 +4359,13 @@ TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) { std::optional<uint32_t> sequenceNum = mWindow->receiveEvent(); // ACTION_DOWN ASSERT_TRUE(sequenceNum); const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken()); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); mWindow->finishEvent(*sequenceNum); mWindow->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, ADISPLAY_ID_DEFAULT, 0 /*flags*/); ASSERT_TRUE(mDispatcher->waitForIdle()); - mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken()); + mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid()); } // Send a key to the app and have the app not respond right away. @@ -4380,7 +4375,7 @@ TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) { std::optional<uint32_t> sequenceNum = mWindow->receiveEvent(); ASSERT_TRUE(sequenceNum); const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken()); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); ASSERT_TRUE(mDispatcher->waitForIdle()); } @@ -4410,6 +4405,38 @@ TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) { ASSERT_TRUE(mDispatcher->waitForIdle()); } +/** + * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window, + * there will not be an ANR. + */ +TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) { + mWindow->setFocusable(false); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mWindow->consumeFocusEvent(false); + + KeyEvent event; + const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) - + std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count(); + + // Define a valid key down event that is stale (too old). + event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, + INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /* flags */ 0, AKEYCODE_A, KEY_A, + AMETA_NONE, 1 /*repeatCount*/, eventTime, eventTime); + + const int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER; + + InputEventInjectionResult result = + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + InputEventInjectionSync::WAIT_FOR_RESULT, + INJECT_EVENT_TIMEOUT, policyFlags); + ASSERT_EQ(InputEventInjectionResult::FAILED, result) + << "Injection should fail because the event is stale"; + + ASSERT_TRUE(mDispatcher->waitForIdle()); + mFakePolicy->assertNotifyAnrWasNotCalled(); + mWindow->assertNoEvents(); +} + // We have a focused application, but no focused window // Make sure that we don't notify policy twice about the same ANR. TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) { @@ -4485,7 +4512,7 @@ TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) // We have now sent down and up. Let's consume first event and then ANR on the second. mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken()); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); } // A spy window can receive an ANR @@ -4500,13 +4527,13 @@ TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) { std::optional<uint32_t> sequenceNum = spy->receiveEvent(); // ACTION_DOWN ASSERT_TRUE(sequenceNum); const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy->getToken()); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy); spy->finishEvent(*sequenceNum); spy->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, ADISPLAY_ID_DEFAULT, 0 /*flags*/); ASSERT_TRUE(mDispatcher->waitForIdle()); - mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken()); + mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid()); } // If an app is not responding to a key event, spy windows should continue to receive @@ -4521,7 +4548,7 @@ TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) // Stuck on the ACTION_UP const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken()); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); // New tap will go to the spy window, but not to the window tapOnWindow(); @@ -4530,7 +4557,7 @@ TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion mDispatcher->waitForIdle(); - mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken()); + mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid()); mWindow->assertNoEvents(); spy->assertNoEvents(); } @@ -4547,7 +4574,7 @@ TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMoti mWindow->consumeMotionDown(); // Stuck on the ACTION_UP const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken()); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); // New tap will go to the spy window, but not to the window tapOnWindow(); @@ -4556,7 +4583,7 @@ TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMoti mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion mDispatcher->waitForIdle(); - mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken()); + mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid()); mWindow->assertNoEvents(); spy->assertNoEvents(); } @@ -4574,13 +4601,13 @@ TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) { const std::optional<uint32_t> consumeSeq = monitor.receiveEvent(); ASSERT_TRUE(consumeSeq); - mFakePolicy->assertNotifyMonitorUnresponsiveWasCalled(30ms); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(30ms, monitor.getToken(), MONITOR_PID); monitor.finishEvent(*consumeSeq); monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT); ASSERT_TRUE(mDispatcher->waitForIdle()); - mFakePolicy->assertNotifyMonitorResponsiveWasCalled(); + mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID); } // If a window is unresponsive, then you get anr. if the window later catches up and starts to @@ -4595,19 +4622,19 @@ TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) { mWindow->consumeMotionDown(); // Block on ACTION_UP const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken()); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); mWindow->consumeMotionUp(); // Now the connection should be healthy again mDispatcher->waitForIdle(); - mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken()); + mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid()); mWindow->assertNoEvents(); tapOnWindow(); mWindow->consumeMotionDown(); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken()); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow); mWindow->consumeMotionUp(); mDispatcher->waitForIdle(); - mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken()); + mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid()); mFakePolicy->assertNotifyAnrWasNotCalled(); mWindow->assertNoEvents(); } @@ -4620,7 +4647,7 @@ TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) { WINDOW_LOCATION)); const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow->getToken()); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow); std::this_thread::sleep_for(windowTimeout); // 'notifyConnectionUnresponsive' should only be called once per connection mFakePolicy->assertNotifyAnrWasNotCalled(); @@ -4630,7 +4657,7 @@ TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) { ADISPLAY_ID_DEFAULT, 0 /*flags*/); mWindow->assertNoEvents(); mDispatcher->waitForIdle(); - mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken()); + mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid()); mFakePolicy->assertNotifyAnrWasNotCalled(); } @@ -4792,7 +4819,7 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) { const std::chrono::duration timeout = mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow->getToken()); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow); // Because we injected two DOWN events in a row, CANCEL is enqueued for the first event // sequence to make it consistent mFocusedWindow->consumeMotionCancel(); @@ -4803,7 +4830,8 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) { mFocusedWindow->assertNoEvents(); mUnfocusedWindow->assertNoEvents(); ASSERT_TRUE(mDispatcher->waitForIdle()); - mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken()); + mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(), + mFocusedWindow->getPid()); mFakePolicy->assertNotifyAnrWasNotCalled(); } @@ -4817,8 +4845,9 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout tapOnFocusedWindow(); // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window - sp<IBinder> anrConnectionToken1 = mFakePolicy->getUnresponsiveWindowToken(10ms); - sp<IBinder> anrConnectionToken2 = mFakePolicy->getUnresponsiveWindowToken(0ms); + sp<IBinder> anrConnectionToken1, anrConnectionToken2; + ASSERT_NO_FATAL_FAILURE(anrConnectionToken1 = mFakePolicy->getUnresponsiveWindowToken(10ms)); + ASSERT_NO_FATAL_FAILURE(anrConnectionToken2 = mFakePolicy->getUnresponsiveWindowToken(0ms)); // We don't know which window will ANR first. But both of them should happen eventually. ASSERT_TRUE(mFocusedWindow->getToken() == anrConnectionToken1 || @@ -4833,8 +4862,9 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout mFocusedWindow->consumeMotionUp(); mUnfocusedWindow->consumeMotionOutside(); - sp<IBinder> responsiveToken1 = mFakePolicy->getResponsiveWindowToken(); - sp<IBinder> responsiveToken2 = mFakePolicy->getResponsiveWindowToken(); + sp<IBinder> responsiveToken1, responsiveToken2; + ASSERT_NO_FATAL_FAILURE(responsiveToken1 = mFakePolicy->getResponsiveWindowToken()); + ASSERT_NO_FATAL_FAILURE(responsiveToken2 = mFakePolicy->getResponsiveWindowToken()); // Both applications should be marked as responsive, in any order ASSERT_TRUE(mFocusedWindow->getToken() == responsiveToken1 || @@ -4858,7 +4888,7 @@ TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) { ASSERT_TRUE(upEventSequenceNum); const std::chrono::duration timeout = mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow->getToken()); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow); // Tap once again // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success @@ -4879,7 +4909,8 @@ TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) { // The second tap did not go to the focused window mFocusedWindow->assertNoEvents(); // Since all events are finished, connection should be deemed healthy again - mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken()); + mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(), + mFocusedWindow->getPid()); mFakePolicy->assertNotifyAnrWasNotCalled(); } @@ -4991,7 +5022,7 @@ TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) { const std::chrono::duration timeout = mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow->getToken()); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow); mUnfocusedWindow->consumeMotionDown(); mFocusedWindow->consumeMotionDown(); @@ -5010,7 +5041,8 @@ TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) { ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction()); } ASSERT_TRUE(mDispatcher->waitForIdle()); - mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken()); + mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(), + mFocusedWindow->getPid()); mUnfocusedWindow->assertNoEvents(); mFocusedWindow->assertNoEvents(); diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index d9958f31c5..000a2cb0d3 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -76,6 +76,7 @@ cc_defaults { "libaidlcommonsupport", "libcompositionengine", "libframetimeline", + "libgui_aidl_static", "libperfetto_client_experimental", "librenderengine", "libscheduler", diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2cd34e9cb8..815febe53d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5473,9 +5473,6 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case SET_FRAME_RATE: case GET_DISPLAY_BRIGHTNESS_SUPPORT: case GET_DISPLAY_DECORATION_SUPPORT: - // captureLayers and captureDisplay will handle the permission check in the function - case CAPTURE_LAYERS: - case CAPTURE_DISPLAY: case SET_FRAME_TIMELINE_INFO: case GET_GPU_CONTEXT_PRIORITY: case GET_MAX_ACQUIRED_BUFFER_COUNT: { @@ -5510,8 +5507,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } return OK; } - case ADD_TRANSACTION_TRACE_LISTENER: - case CAPTURE_DISPLAY_BY_ID: { + case ADD_TRANSACTION_TRACE_LISTENER: { IPCThreadState* ipc = IPCThreadState::self(); const int uid = ipc->getCallingUid(); if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) { @@ -5541,6 +5537,11 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } return PERMISSION_DENIED; } + case CAPTURE_LAYERS: + case CAPTURE_DISPLAY: + case CAPTURE_DISPLAY_BY_ID: + LOG_FATAL("Deprecated opcode: %d", code); + return PERMISSION_DENIED; } // These codes are used for the IBinder protocol to either interrogate the recipient @@ -7189,6 +7190,34 @@ bool SurfaceFlinger::commitCreatedLayers() { mLayersAdded = true; return true; } + +// gui::ISurfaceComposer +binder::Status SurfaceComposerAIDL::captureDisplay( + const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) { + status_t status = mFlinger->captureDisplay(args, captureListener); + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::captureDisplayById( + int64_t displayId, const sp<IScreenCaptureListener>& captureListener) { + status_t status; + IPCThreadState* ipc = IPCThreadState::self(); + const int uid = ipc->getCallingUid(); + if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) { + std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId)); + status = mFlinger->captureDisplay(*id, captureListener); + } else { + status = PERMISSION_DENIED; + } + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::captureLayers( + const LayerCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) { + status_t status = mFlinger->captureLayers(args, captureListener); + return binder::Status::fromStatusT(status); +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 3ecce33d33..f09ee5fad0 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -23,6 +23,7 @@ */ #include <android-base/thread_annotations.h> +#include <android/gui/BnSurfaceComposer.h> #include <cutils/atomic.h> #include <cutils/compiler.h> #include <gui/BufferQueue.h> @@ -106,9 +107,13 @@ class RegionSamplingThread; class RenderArea; class TimeStats; class FrameTracer; +class ScreenCapturer; class WindowInfosListenerInvoker; +using gui::CaptureArgs; +using gui::DisplayCaptureArgs; using gui::IRegionSamplingListener; +using gui::LayerCaptureArgs; using gui::ScreenCaptureResults; namespace frametimeline { @@ -540,9 +545,9 @@ private: ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp, ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) override; - status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&) override; - status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) override; - status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) override; + status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&); + status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&); + status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&); status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override; status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*) @@ -1401,6 +1406,22 @@ private: } mPowerHintSessionData GUARDED_BY(SF_MAIN_THREAD); nsecs_t mAnimationTransactionTimeout = s2ns(5); + + friend class SurfaceComposerAIDL; +}; + +class SurfaceComposerAIDL : public gui::BnSurfaceComposer { +public: + SurfaceComposerAIDL(sp<SurfaceFlinger> sf) { mFlinger = sf; } + + binder::Status captureDisplay(const DisplayCaptureArgs&, + const sp<IScreenCaptureListener>&) override; + binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override; + binder::Status captureLayers(const LayerCaptureArgs&, + const sp<IScreenCaptureListener>&) override; + +private: + sp<SurfaceFlinger> mFlinger; }; } // namespace android diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp index b0b6bf14ab..7350e09cb5 100644 --- a/services/surfaceflinger/fuzzer/Android.bp +++ b/services/surfaceflinger/fuzzer/Android.bp @@ -127,3 +127,13 @@ cc_fuzz { "surfaceflinger_layer_fuzzer.cpp", ], } + +cc_fuzz { + name: "surfaceflinger_frametracer_fuzzer", + defaults: [ + "surfaceflinger_fuzz_defaults", + ], + srcs: [ + "surfaceflinger_frametracer_fuzzer.cpp", + ], +} diff --git a/services/surfaceflinger/fuzzer/README.md b/services/surfaceflinger/fuzzer/README.md index 78a7596ef3..7a5f229ae9 100644 --- a/services/surfaceflinger/fuzzer/README.md +++ b/services/surfaceflinger/fuzzer/README.md @@ -4,6 +4,7 @@ + [DisplayHardware](#DisplayHardware) + [Scheduler](#Scheduler) + [Layer](#Layer) ++ [FrameTracer](#FrameTracer) # <a name="SurfaceFlinger"></a> Fuzzer for SurfaceFlinger @@ -93,3 +94,16 @@ You can find the possible values in the fuzzer's source code. $ adb sync data $ adb shell /data/fuzz/arm64/surfaceflinger_layer_fuzzer/surfaceflinger_layer_fuzzer ``` + +# <a name="FrameTracer"></a> Fuzzer for FrameTracer + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) surfaceflinger_frametracer_fuzzer +``` +2. To run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/surfaceflinger_frametracer_fuzzer/surfaceflinger_frametracer_fuzzer +``` diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp new file mode 100644 index 0000000000..a22a778989 --- /dev/null +++ b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp @@ -0,0 +1,132 @@ +/* + * Copyright 2021 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 <FrameTracer/FrameTracer.h> +#include <fuzzer/FuzzedDataProvider.h> +#include <perfetto/trace/trace.pb.h> + +namespace android::fuzz { + +using namespace google::protobuf; + +constexpr size_t kMaxStringSize = 100; +constexpr size_t kMinLayerIds = 1; +constexpr size_t kMaxLayerIds = 10; +constexpr int32_t kConfigDuration = 500; +constexpr int32_t kBufferSize = 1024; +constexpr int32_t kTimeOffset = 100000; + +class FrameTracerFuzzer { +public: + FrameTracerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) { + // Fuzzer is single-threaded, so no need to be thread-safe. + static bool wasInitialized = false; + if (!wasInitialized) { + perfetto::TracingInitArgs args; + args.backends = perfetto::kInProcessBackend; + perfetto::Tracing::Initialize(args); + wasInitialized = true; + } + mFrameTracer = std::make_unique<android::FrameTracer>(); + } + ~FrameTracerFuzzer() { mFrameTracer.reset(); } + void process(); + +private: + std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest(); + void traceTimestamp(); + std::vector<int32_t> generateLayerIds(size_t numLayerIds); + void traceTimestamp(std::vector<int32_t> layerIds, size_t numLayerIds); + void traceFence(std::vector<int32_t> layerIds, size_t numLayerIds); + std::unique_ptr<android::FrameTracer> mFrameTracer = nullptr; + FuzzedDataProvider mFdp; + android::FenceToFenceTimeMap mFenceFactory; +}; + +std::unique_ptr<perfetto::TracingSession> FrameTracerFuzzer::getTracingSessionForTest() { + perfetto::TraceConfig cfg; + cfg.set_duration_ms(kConfigDuration); + cfg.add_buffers()->set_size_kb(kBufferSize); + auto* dsCfg = cfg.add_data_sources()->mutable_config(); + dsCfg->set_name(android::FrameTracer::kFrameTracerDataSource); + + auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend); + tracingSession->Setup(cfg); + return tracingSession; +} + +std::vector<int32_t> FrameTracerFuzzer::generateLayerIds(size_t numLayerIds) { + std::vector<int32_t> layerIds; + for (size_t i = 0; i < numLayerIds; ++i) { + layerIds.push_back(mFdp.ConsumeIntegral<int32_t>()); + } + return layerIds; +} + +void FrameTracerFuzzer::traceTimestamp(std::vector<int32_t> layerIds, size_t numLayerIds) { + int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange<size_t>(0, numLayerIds - 1)); + mFrameTracer->traceTimestamp(layerId, mFdp.ConsumeIntegral<uint64_t>() /*bufferID*/, + mFdp.ConsumeIntegral<uint64_t>() /*frameNumber*/, + mFdp.ConsumeIntegral<nsecs_t>() /*timestamp*/, + android::FrameTracer::FrameEvent::UNSPECIFIED, + mFdp.ConsumeIntegral<nsecs_t>() /*duration*/); +} + +void FrameTracerFuzzer::traceFence(std::vector<int32_t> layerIds, size_t numLayerIds) { + const nsecs_t signalTime = systemTime(); + const nsecs_t startTime = signalTime + kTimeOffset; + auto fence = mFenceFactory.createFenceTimeForTest(android::Fence::NO_FENCE); + mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, signalTime); + int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange<size_t>(0, numLayerIds - 1)); + mFrameTracer->traceFence(layerId, mFdp.ConsumeIntegral<uint64_t>() /*bufferID*/, + mFdp.ConsumeIntegral<uint64_t>() /*frameNumber*/, fence, + android::FrameTracer::FrameEvent::ACQUIRE_FENCE, startTime); +} + +void FrameTracerFuzzer::process() { + mFrameTracer->registerDataSource(); + + auto tracingSession = getTracingSessionForTest(); + tracingSession->StartBlocking(); + + size_t numLayerIds = mFdp.ConsumeIntegralInRange<size_t>(kMinLayerIds, kMaxLayerIds); + std::vector<int32_t> layerIds = generateLayerIds(numLayerIds); + + for (auto it = layerIds.begin(); it != layerIds.end(); ++it) { + mFrameTracer->traceNewLayer(*it /*layerId*/, + mFdp.ConsumeRandomLengthString(kMaxStringSize) /*layerName*/); + } + + traceTimestamp(layerIds, numLayerIds); + traceFence(layerIds, numLayerIds); + + mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, systemTime()); + + tracingSession->StopBlocking(); + + for (auto it = layerIds.begin(); it != layerIds.end(); ++it) { + mFrameTracer->onDestroy(*it); + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FrameTracerFuzzer frameTracerFuzzer(data, size); + frameTracerFuzzer.process(); + return 0; +} + +} // namespace android::fuzz diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp index caeff4ab21..ec180548e1 100644 --- a/services/surfaceflinger/main_surfaceflinger.cpp +++ b/services/surfaceflinger/main_surfaceflinger.cpp @@ -152,6 +152,11 @@ int main(int, char**) { sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false, IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO); + // publish gui::ISurfaceComposer, the new AIDL interface + sp<SurfaceComposerAIDL> composerAIDL = new SurfaceComposerAIDL(flinger); + sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO); + startDisplayService(); // dependency on SF getting registered above if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) { diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp index fa1a5ed6b0..094b0ffc0f 100644 --- a/services/surfaceflinger/tests/LayerState_test.cpp +++ b/services/surfaceflinger/tests/LayerState_test.cpp @@ -22,6 +22,8 @@ #include <gui/LayerState.h> namespace android { +using gui::DisplayCaptureArgs; +using gui::LayerCaptureArgs; using gui::ScreenCaptureResults; namespace test { @@ -40,11 +42,11 @@ TEST(LayerStateTest, ParcellingDisplayCaptureArgs) { args.grayscale = true; Parcel p; - args.write(p); + args.writeToParcel(&p); p.setDataPosition(0); DisplayCaptureArgs args2; - args2.read(p); + args2.readFromParcel(&p); ASSERT_EQ(args.pixelFormat, args2.pixelFormat); ASSERT_EQ(args.sourceCrop, args2.sourceCrop); @@ -71,11 +73,11 @@ TEST(LayerStateTest, ParcellingLayerCaptureArgs) { args.grayscale = true; Parcel p; - args.write(p); + args.writeToParcel(&p); p.setDataPosition(0); LayerCaptureArgs args2; - args2.read(p); + args2.readFromParcel(&p); ASSERT_EQ(args.pixelFormat, args2.pixelFormat); ASSERT_EQ(args.sourceCrop, args2.sourceCrop); diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h index cae76849bf..ee7e92cbf6 100644 --- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -16,6 +16,7 @@ #pragma once #include <gui/SyncScreenCaptureListener.h> +#include <private/gui/ComposerServiceAIDL.h> #include <ui/Rect.h> #include <utils/String8.h> #include <functional> @@ -31,15 +32,15 @@ class ScreenCapture : public RefBase { public: static status_t captureDisplay(DisplayCaptureArgs& captureArgs, ScreenCaptureResults& captureResults) { - const auto sf = ComposerService::getComposerService(); + const auto sf = ComposerServiceAIDL::getComposerService(); SurfaceComposerClient::Transaction().apply(true); captureArgs.dataspace = ui::Dataspace::V0_SRGB; const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); - status_t status = sf->captureDisplay(captureArgs, captureListener); + binder::Status status = sf->captureDisplay(captureArgs, captureListener); - if (status != NO_ERROR) { - return status; + if (status.transactionError() != NO_ERROR) { + return status.transactionError(); } captureResults = captureListener->waitForResults(); return captureResults.result; @@ -64,14 +65,14 @@ public: static status_t captureLayers(LayerCaptureArgs& captureArgs, ScreenCaptureResults& captureResults) { - const auto sf = ComposerService::getComposerService(); + const auto sf = ComposerServiceAIDL::getComposerService(); SurfaceComposerClient::Transaction().apply(true); captureArgs.dataspace = ui::Dataspace::V0_SRGB; const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); - status_t status = sf->captureLayers(captureArgs, captureListener); - if (status != NO_ERROR) { - return status; + binder::Status status = sf->captureLayers(captureArgs, captureListener); + if (status.transactionError() != NO_ERROR) { + return status.transactionError(); } captureResults = captureListener->waitForResults(); return captureResults.result; |