diff options
17 files changed, 288 insertions, 119 deletions
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index ef052bd928..cefcf6404c 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -175,8 +175,10 @@ class OTAPreoptService { private: bool ReadSystemProperties() { + // TODO This file does not have a stable format. It should be read by + // code shared by init and otapreopt. See b/181182967#comment80 static constexpr const char* kPropertyFiles[] = { - "/default.prop", "/system/build.prop" + "/system/build.prop" }; for (size_t i = 0; i < arraysize(kPropertyFiles); ++i) { @@ -193,28 +195,38 @@ private: // export NAME VALUE // For simplicity, don't respect string quotation. The values we are interested in can be // encoded without them. + // init.environ.rc and etc/classpath have the same format for + // environment variable exports and can be matched by the same regex. + // TODO Just like with the system-properties above we really should have + // common code between init and otapreopt to deal with reading these + // things. See b/181182967 + static constexpr const char* kEnvironmentVariableSources[] = { + "/init.environ.rc", "/etc/classpath" + }; + std::regex export_regex("\\s*export\\s+(\\S+)\\s+(\\S+)"); - bool parse_result = ParseFile("/init.environ.rc", [&](const std::string& line) { - std::smatch export_match; - if (!std::regex_match(line, export_match, export_regex)) { - return true; - } + for (const char* env_vars_file : kEnvironmentVariableSources) { + bool parse_result = ParseFile(env_vars_file, [&](const std::string& line) { + std::smatch export_match; + if (!std::regex_match(line, export_match, export_regex)) { + return true; + } - if (export_match.size() != 3) { - return true; - } + if (export_match.size() != 3) { + return true; + } - std::string name = export_match[1].str(); - std::string value = export_match[2].str(); + std::string name = export_match[1].str(); + std::string value = export_match[2].str(); - system_properties_.SetProperty(name, value); + system_properties_.SetProperty(name, value); - return true; - }); - if (!parse_result) { - return false; + return true; + }); + if (!parse_result) { + return false; + } } - if (system_properties_.GetProperty(kAndroidDataPathPropertyName) == nullptr) { return false; } diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp index 72c03bf14b..fb07840730 100644 --- a/cmds/installd/otapreopt_chroot.cpp +++ b/cmds/installd/otapreopt_chroot.cpp @@ -28,6 +28,7 @@ #include <libdm/dm.h> #include <selinux/android.h> +#include <apex_file_repository.h> #include <apexd.h> #include "installd_constants.h" @@ -64,11 +65,14 @@ static std::vector<apex::ApexFile> ActivateApexPackages() { // system/apex/apexd/apexd.cpp. // // Only scan the APEX directory under /system, /system_ext and /vendor (within the chroot dir). - std::vector<const char*> apex_dirs{apex::kApexPackageSystemDir, apex::kApexPackageSystemExtDir, + std::vector<std::string> apex_dirs{apex::kApexPackageSystemDir, apex::kApexPackageSystemExtDir, apex::kApexPackageVendorDir}; + // Initialize ApexFileRepository used internally in ScanPackagesDirAndActivate. + // This is a quick fix to fix apex activation in otapreopt_chroot. + apex::ApexFileRepository::GetInstance().AddPreInstalledApex(apex_dirs); for (const auto& dir : apex_dirs) { // Cast call to void to suppress warn_unused_result. - static_cast<void>(apex::ScanPackagesDirAndActivate(dir)); + static_cast<void>(apex::ScanPackagesDirAndActivate(dir.c_str())); } return apex::GetActivePackages(); } diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 3b46cb5997..ba9ae204eb 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -33,6 +33,7 @@ #include <unordered_map> #include <android-base/chrono_utils.h> +#include <android-base/unique_fd.h> #include <binder/IBinder.h> #include <binder/Parcelable.h> @@ -44,7 +45,6 @@ #include <utils/RefBase.h> #include <utils/Timers.h> -#include <android-base/unique_fd.h> namespace android { class Parcel; @@ -76,10 +76,15 @@ struct InputMessage { uint32_t seq; } header; - // Body *must* be 8 byte aligned. // For keys and motions, rely on the fact that std::array takes up exactly as much space // as the underlying data. This is not guaranteed by C++, but it simplifies the conversions. static_assert(sizeof(std::array<uint8_t, 32>) == 32); + + // For bool values, rely on the fact that they take up exactly one byte. This is not guaranteed + // by C++ and is implementation-dependent, but it simplifies the conversions. + static_assert(sizeof(bool) == 1); + + // Body *must* be 8 byte aligned. union Body { struct Key { int32_t eventId; @@ -154,8 +159,8 @@ struct InputMessage { } motion; struct Finished { - uint32_t empty1; - uint32_t handled; // actually a bool, but we must maintain 8-byte alignment + bool handled; + uint8_t empty[7]; nsecs_t consumeTime; // The time when the event was consumed by the receiving end inline size_t size() const { return sizeof(Finished); } @@ -163,16 +168,18 @@ struct InputMessage { struct Focus { int32_t eventId; - // The following two fields take up 4 bytes total - uint16_t hasFocus; // actually a bool - uint16_t inTouchMode; // actually a bool, but we must maintain 8-byte alignment + // The following 3 fields take up 4 bytes total + bool hasFocus; + bool inTouchMode; + uint8_t empty[2]; inline size_t size() const { return sizeof(Focus); } } focus; struct Capture { int32_t eventId; - uint32_t pointerCaptureEnabled; // actually a bool, but we maintain 8-byte alignment + bool pointerCaptureEnabled; + uint8_t empty[3]; inline size_t size() const { return sizeof(Capture); } } capture; diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index e9d866b448..6df04f07b6 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -216,6 +216,11 @@ cc_library { "performance*", "portability*", ], + + pgo: { + sampling: true, + profile_file: "libbinder/libbinder.profdata", + }, } // AIDL interface between libbinder and framework.jar diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 1e47a3c3e6..ee2daec5fc 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -577,8 +577,8 @@ status_t InputPublisher::publishFocusEvent(uint32_t seq, int32_t eventId, bool h msg.header.type = InputMessage::Type::FOCUS; msg.header.seq = seq; msg.body.focus.eventId = eventId; - msg.body.focus.hasFocus = hasFocus ? 1 : 0; - msg.body.focus.inTouchMode = inTouchMode ? 1 : 0; + msg.body.focus.hasFocus = hasFocus; + msg.body.focus.inTouchMode = inTouchMode; return mChannel->sendMessage(&msg); } @@ -595,7 +595,7 @@ status_t InputPublisher::publishCaptureEvent(uint32_t seq, int32_t eventId, msg.header.type = InputMessage::Type::CAPTURE; msg.header.seq = seq; msg.body.capture.eventId = eventId; - msg.body.capture.pointerCaptureEnabled = pointerCaptureEnabled ? 1 : 0; + msg.body.capture.pointerCaptureEnabled = pointerCaptureEnabled; return mChannel->sendMessage(&msg); } @@ -615,7 +615,7 @@ status_t InputPublisher::receiveFinishedSignal( mChannel->getName().c_str(), NamedEnum::string(msg.header.type).c_str()); return UNKNOWN_ERROR; } - callback(msg.header.seq, msg.body.finished.handled == 1, msg.body.finished.consumeTime); + callback(msg.header.seq, msg.body.finished.handled, msg.body.finished.consumeTime); return OK; } @@ -1168,7 +1168,7 @@ status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) InputMessage msg; msg.header.type = InputMessage::Type::FINISHED; msg.header.seq = seq; - msg.body.finished.handled = handled ? 1 : 0; + msg.body.finished.handled = handled; msg.body.finished.consumeTime = getConsumeTime(seq); status_t result = mChannel->sendMessage(&msg); if (result == OK) { @@ -1228,12 +1228,12 @@ void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) } void InputConsumer::initializeFocusEvent(FocusEvent* event, const InputMessage* msg) { - event->initialize(msg->body.focus.eventId, msg->body.focus.hasFocus == 1, - msg->body.focus.inTouchMode == 1); + event->initialize(msg->body.focus.eventId, msg->body.focus.hasFocus, + msg->body.focus.inTouchMode); } void InputConsumer::initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg) { - event->initialize(msg->body.capture.eventId, msg->body.capture.pointerCaptureEnabled == 1); + event->initialize(msg->body.capture.eventId, msg->body.capture.pointerCaptureEnabled); } void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) { diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index a8865858d3..8f436085f7 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -49,6 +49,7 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Key, downTime, 88); CHECK_OFFSET(InputMessage::Body::Motion, eventId, 0); + CHECK_OFFSET(InputMessage::Body::Motion, empty1, 4); CHECK_OFFSET(InputMessage::Body::Motion, eventTime, 8); CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16); CHECK_OFFSET(InputMessage::Body::Motion, source, 20); @@ -60,6 +61,7 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Motion, metaState, 72); CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 76); CHECK_OFFSET(InputMessage::Body::Motion, classification, 80); + CHECK_OFFSET(InputMessage::Body::Motion, empty2, 81); CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 84); CHECK_OFFSET(InputMessage::Body::Motion, downTime, 88); CHECK_OFFSET(InputMessage::Body::Motion, dsdx, 96); @@ -73,16 +75,20 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 128); CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 132); CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 136); + CHECK_OFFSET(InputMessage::Body::Motion, empty3, 140); CHECK_OFFSET(InputMessage::Body::Motion, pointers, 144); CHECK_OFFSET(InputMessage::Body::Focus, eventId, 0); CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4); - CHECK_OFFSET(InputMessage::Body::Focus, inTouchMode, 6); + CHECK_OFFSET(InputMessage::Body::Focus, inTouchMode, 5); + CHECK_OFFSET(InputMessage::Body::Focus, empty, 6); CHECK_OFFSET(InputMessage::Body::Capture, eventId, 0); CHECK_OFFSET(InputMessage::Body::Capture, pointerCaptureEnabled, 4); + CHECK_OFFSET(InputMessage::Body::Capture, empty, 5); - CHECK_OFFSET(InputMessage::Body::Finished, handled, 4); + CHECK_OFFSET(InputMessage::Body::Finished, handled, 0); + CHECK_OFFSET(InputMessage::Body::Finished, empty, 1); CHECK_OFFSET(InputMessage::Body::Finished, consumeTime, 8); } diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp index c29181d715..d38f2eff01 100644 --- a/opengl/libs/EGL/egl_angle_platform.cpp +++ b/opengl/libs/EGL/egl_angle_platform.cpp @@ -22,6 +22,8 @@ #pragma GCC diagnostic ignored "-Wunused-parameter" #include <EGL/Platform.h> #pragma GCC diagnostic pop + +#include <android-base/properties.h> #include <android/dlext.h> #include <dlfcn.h> #include <graphicsenv/GraphicsEnv.h> @@ -33,7 +35,6 @@ namespace angle { -constexpr char kAngleEs2Lib[] = "libGLESv2_angle.so"; constexpr int kAngleDlFlags = RTLD_LOCAL | RTLD_NOW; static GetDisplayPlatformFunc angleGetDisplayPlatform = nullptr; @@ -107,18 +108,36 @@ bool initializeAnglePlatform(EGLDisplay dpy) { android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace(); void* so = nullptr; if (ns) { + // Loading from an APK, so hard-code the suffix to "_angle". + constexpr char kAngleEs2Lib[] = "libGLESv2_angle.so"; const android_dlextinfo dlextinfo = { .flags = ANDROID_DLEXT_USE_NAMESPACE, .library_namespace = ns, }; so = android_dlopen_ext(kAngleEs2Lib, kAngleDlFlags, &dlextinfo); + if (so) { + ALOGD("dlopen_ext from APK (%s) success at %p", kAngleEs2Lib, so); + } else { + ALOGE("dlopen_ext(\"%s\") failed: %s", kAngleEs2Lib, dlerror()); + return false; + } } else { // If we are here, ANGLE is loaded as built-in gl driver in the sphal. - so = android_load_sphal_library(kAngleEs2Lib, kAngleDlFlags); - } - if (!so) { - ALOGE("%s failed to dlopen %s!", __FUNCTION__, kAngleEs2Lib); - return false; + // Get the specified ANGLE library filename suffix. + std::string angleEs2LibSuffix = android::base::GetProperty("ro.hardware.egl", ""); + if (angleEs2LibSuffix.empty()) { + ALOGE("%s failed to get valid ANGLE library filename suffix!", __FUNCTION__); + return false; + } + + std::string angleEs2LibName = "libGLESv2_" + angleEs2LibSuffix + ".so"; + so = android_load_sphal_library(angleEs2LibName.c_str(), kAngleDlFlags); + if (so) { + ALOGD("dlopen (%s) success at %p", angleEs2LibName.c_str(), so); + } else { + ALOGE("%s failed to dlopen %s!", __FUNCTION__, angleEs2LibName.c_str()); + return false; + } } angleGetDisplayPlatform = diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp index d5bf569226..325361b45a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp @@ -39,9 +39,6 @@ using ::testing::SaveArg; using ::testing::StrictMock; struct CompositionEngineTest : public testing::Test { - android::mock::HWComposer* mHwc = new StrictMock<android::mock::HWComposer>(); - renderengine::mock::RenderEngine* mRenderEngine = - new StrictMock<renderengine::mock::RenderEngine>(); std::shared_ptr<TimeStats> mTimeStats; impl::CompositionEngine mEngine; @@ -58,15 +55,18 @@ TEST_F(CompositionEngineTest, canInstantiateCompositionEngine) { } TEST_F(CompositionEngineTest, canSetHWComposer) { - mEngine.setHwComposer(std::unique_ptr<android::HWComposer>(mHwc)); + android::mock::HWComposer* hwc = new StrictMock<android::mock::HWComposer>(); + mEngine.setHwComposer(std::unique_ptr<android::HWComposer>(hwc)); - EXPECT_EQ(mHwc, &mEngine.getHwComposer()); + EXPECT_EQ(hwc, &mEngine.getHwComposer()); } TEST_F(CompositionEngineTest, canSetRenderEngine) { - mEngine.setRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine)); + renderengine::mock::RenderEngine* renderEngine = + new StrictMock<renderengine::mock::RenderEngine>(); + mEngine.setRenderEngine(std::unique_ptr<renderengine::RenderEngine>(renderEngine)); - EXPECT_EQ(mRenderEngine, &mEngine.getRenderEngine()); + EXPECT_EQ(renderEngine, &mEngine.getRenderEngine()); } TEST_F(CompositionEngineTest, canSetTimeStats) { @@ -130,10 +130,10 @@ TEST_F(CompositionEnginePresentTest, worksAsExpected) { struct CompositionEngineUpdateCursorAsyncTest : public CompositionEngineTest { public: struct Layer { - Layer() { EXPECT_CALL(outputLayer, getLayerFE()).WillRepeatedly(ReturnRef(layerFE)); } + Layer() { EXPECT_CALL(outputLayer, getLayerFE()).WillRepeatedly(ReturnRef(*layerFE)); } StrictMock<mock::OutputLayer> outputLayer; - StrictMock<mock::LayerFE> layerFE; + sp<StrictMock<mock::LayerFE>> layerFE = sp<StrictMock<mock::LayerFE>>::make(); LayerFECompositionState layerFEState; }; @@ -175,21 +175,21 @@ TEST_F(CompositionEngineUpdateCursorAsyncTest, handlesMultipleLayersBeingCursorL { InSequence seq; EXPECT_CALL(mOutput2Layer1.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true)); - EXPECT_CALL(mOutput2Layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor)); + EXPECT_CALL(*mOutput2Layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor)); EXPECT_CALL(mOutput2Layer1.outputLayer, writeCursorPositionToHWC()); } { InSequence seq; EXPECT_CALL(mOutput3Layer1.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true)); - EXPECT_CALL(mOutput3Layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor)); + EXPECT_CALL(*mOutput3Layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor)); EXPECT_CALL(mOutput3Layer1.outputLayer, writeCursorPositionToHWC()); } { InSequence seq; EXPECT_CALL(mOutput3Layer2.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true)); - EXPECT_CALL(mOutput3Layer2.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor)); + EXPECT_CALL(*mOutput3Layer2.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor)); EXPECT_CALL(mOutput3Layer2.outputLayer, writeCursorPositionToHWC()); } diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 3059beb9e8..5f0b0eea15 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -1697,12 +1697,12 @@ struct OutputUpdateColorProfileTest : public testing::Test { struct Layer { Layer() { - EXPECT_CALL(mOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(mLayerFE)); - EXPECT_CALL(mLayerFE, getCompositionState()).WillRepeatedly(Return(&mLayerFEState)); + EXPECT_CALL(mOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(*mLayerFE)); + EXPECT_CALL(*mLayerFE, getCompositionState()).WillRepeatedly(Return(&mLayerFEState)); } StrictMock<mock::OutputLayer> mOutputLayer; - StrictMock<mock::LayerFE> mLayerFE; + sp<StrictMock<mock::LayerFE>> mLayerFE = sp<StrictMock<mock::LayerFE>>::make(); LayerFECompositionState mLayerFEState; }; @@ -2712,12 +2712,12 @@ struct OutputPostFramebufferTest : public testing::Test { struct Layer { Layer() { - EXPECT_CALL(outputLayer, getLayerFE()).WillRepeatedly(ReturnRef(layerFE)); + EXPECT_CALL(outputLayer, getLayerFE()).WillRepeatedly(ReturnRef(*layerFE)); EXPECT_CALL(outputLayer, getHwcLayer()).WillRepeatedly(Return(&hwc2Layer)); } StrictMock<mock::OutputLayer> outputLayer; - StrictMock<mock::LayerFE> layerFE; + sp<StrictMock<mock::LayerFE>> layerFE = sp<StrictMock<mock::LayerFE>>::make(); StrictMock<HWC2::mock::Layer> hwc2Layer; }; @@ -2793,11 +2793,11 @@ TEST_F(OutputPostFramebufferTest, releaseFencesAreSentToLayerFE) { // are passed. This happens to work with the current implementation, but // would not survive certain calls like Fence::merge() which would return a // new instance. - EXPECT_CALL(mLayer1.layerFE, + EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(Property(&sp<Fence>::get, Eq(layer1Fence.get())))); - EXPECT_CALL(mLayer2.layerFE, + EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(Property(&sp<Fence>::get, Eq(layer2Fence.get())))); - EXPECT_CALL(mLayer3.layerFE, + EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(Property(&sp<Fence>::get, Eq(layer3Fence.get())))); mOutput.postFramebuffer(); @@ -2824,9 +2824,9 @@ TEST_F(OutputPostFramebufferTest, releaseFencesIncludeClientTargetAcquireFence) // Fence::merge is called, and since none of the fences are actually valid, // Fence::NO_FENCE is returned and passed to each onLayerDisplayed() call. // This is the best we can do without creating a real kernel fence object. - EXPECT_CALL(mLayer1.layerFE, onLayerDisplayed(Fence::NO_FENCE)); - EXPECT_CALL(mLayer2.layerFE, onLayerDisplayed(Fence::NO_FENCE)); - EXPECT_CALL(mLayer3.layerFE, onLayerDisplayed(Fence::NO_FENCE)); + EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(Fence::NO_FENCE)); + EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(Fence::NO_FENCE)); + EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(Fence::NO_FENCE)); mOutput.postFramebuffer(); } @@ -3330,12 +3330,12 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, struct OutputComposeSurfacesTest_HandlesProtectedContent : public OutputComposeSurfacesTest { struct Layer { Layer() { - EXPECT_CALL(mLayerFE, getCompositionState()).WillRepeatedly(Return(&mLayerFEState)); - EXPECT_CALL(mOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(mLayerFE)); + EXPECT_CALL(*mLayerFE, getCompositionState()).WillRepeatedly(Return(&mLayerFEState)); + EXPECT_CALL(mOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(*mLayerFE)); } StrictMock<mock::OutputLayer> mOutputLayer; - StrictMock<mock::LayerFE> mLayerFE; + sp<StrictMock<mock::LayerFE>> mLayerFE = sp<StrictMock<mock::LayerFE>>::make(); LayerFECompositionState mLayerFEState; }; @@ -3546,12 +3546,12 @@ struct GenerateClientCompositionRequestsTest : public testing::Test { Layer() { EXPECT_CALL(mOutputLayer, getState()).WillRepeatedly(ReturnRef(mOutputLayerState)); EXPECT_CALL(mOutputLayer, editState()).WillRepeatedly(ReturnRef(mOutputLayerState)); - EXPECT_CALL(mOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(mLayerFE)); - EXPECT_CALL(mLayerFE, getCompositionState()).WillRepeatedly(Return(&mLayerFEState)); + EXPECT_CALL(mOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(*mLayerFE)); + EXPECT_CALL(*mLayerFE, getCompositionState()).WillRepeatedly(Return(&mLayerFEState)); } StrictMock<mock::OutputLayer> mOutputLayer; - StrictMock<mock::LayerFE> mLayerFE; + sp<StrictMock<mock::LayerFE>> mLayerFE = sp<StrictMock<mock::LayerFE>>::make(); LayerFECompositionState mLayerFEState; impl::OutputLayerCompositionState mOutputLayerState; LayerFE::LayerSettings mLayerSettings; @@ -3645,11 +3645,11 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, gathersClientCompositi LayerFE::LayerSettings mShadowSettings; mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f}; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(_)) + EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(_)) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(_)) + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(_)) .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[1].mLayerSettings}))); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_)) + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(_)) .WillOnce(Return(std::vector<LayerFE::LayerSettings>( {mShadowSettings, mLayers[2].mLayerSettings}))); @@ -3683,7 +3683,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, mLayers[1].mLayerFEState.isOpaque = true; mLayers[2].mLayerFEState.isOpaque = true; - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_)) + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(_)) .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings}))); Region accumClearRegion(Rect(10, 11, 12, 13)); @@ -3709,7 +3709,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, mLayers[1].mLayerFEState.isOpaque = false; mLayers[2].mLayerFEState.isOpaque = false; - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_)) + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(_)) .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings}))); Region accumClearRegion(Rect(10, 11, 12, 13)); @@ -3773,9 +3773,9 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqu mBlackoutSettings.alpha = 0.f; mBlackoutSettings.disableBlending = true; - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mBlackoutSettings}))); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings}))); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3835,11 +3835,11 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false /* disabledBlurs */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); static_cast<void>( @@ -3891,11 +3891,11 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false /* disabledBlurs */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); static_cast<void>( @@ -3948,11 +3948,11 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false /* disabledBlurs */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); static_cast<void>( @@ -4003,11 +4003,11 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false /* disabledBlurs */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); static_cast<void>( @@ -4056,11 +4056,11 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false /* disabledBlurs */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + EXPECT_CALL(*mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); static_cast<void>(mOutput.generateClientCompositionRequests(true /* supportsProtectedContent */, @@ -4188,7 +4188,7 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq EXPECT_CALL(leftLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true)); EXPECT_CALL(leftLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false)); - EXPECT_CALL(leftLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(leftLayerSettings)))) + EXPECT_CALL(*leftLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(leftLayerSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>({leftLayer.mLayerSettings}))); compositionengine::LayerFE::ClientCompositionTargetSettings rightLayerSettings{ @@ -4206,7 +4206,7 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq EXPECT_CALL(rightLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true)); EXPECT_CALL(rightLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false)); - EXPECT_CALL(rightLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(rightLayerSettings)))) + EXPECT_CALL(*rightLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(rightLayerSettings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>({rightLayer.mLayerSettings}))); constexpr bool supportsProtectedContent = true; @@ -4246,7 +4246,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings)))) + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mShadowSettings}))); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -4286,7 +4286,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings)))) + EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings)))) .WillOnce(Return(std::vector<LayerFE::LayerSettings>( {mShadowSettings, mLayers[2].mLayerSettings}))); diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 75158729bc..03e38f30de 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -207,6 +207,17 @@ FrameTimelineEvent::PresentType toProto(FramePresentMetadata presentMetadata) { } } +FrameTimelineEvent::PredictionType toProto(PredictionState predictionState) { + switch (predictionState) { + case PredictionState::Valid: + return FrameTimelineEvent::PREDICTION_VALID; + case PredictionState::Expired: + return FrameTimelineEvent::PREDICTION_EXPIRED; + case PredictionState::None: + return FrameTimelineEvent::PREDICTION_UNKNOWN; + } +} + int32_t jankTypeBitmaskToProto(int32_t jankType) { if (jankType == JankType::None) { return FrameTimelineEvent::JANK_NONE; @@ -628,6 +639,7 @@ void SurfaceFrame::traceActuals(int64_t displayFrameToken) const { FrameReadyMetadata::OnTimeFinish); actualSurfaceFrameStartEvent->set_gpu_composition(mGpuComposition); actualSurfaceFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType)); + actualSurfaceFrameStartEvent->set_prediction_type(toProto(mPredictionState)); }); // Actual timeline end @@ -968,6 +980,7 @@ void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid) const { FrameReadyMetadata::OnTimeFinish); actualDisplayFrameStartEvent->set_gpu_composition(mGpuComposition); actualDisplayFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType)); + actualDisplayFrameStartEvent->set_prediction_type(toProto(mPredictionState)); }); // Actual timeline end diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index 6150b22609..f2cb9513f0 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -40,6 +40,7 @@ using ProtoActualSurfaceFrameStart = perfetto::protos::FrameTimelineEvent_Actual using ProtoFrameEnd = perfetto::protos::FrameTimelineEvent_FrameEnd; using ProtoPresentType = perfetto::protos::FrameTimelineEvent_PresentType; using ProtoJankType = perfetto::protos::FrameTimelineEvent_JankType; +using ProtoPredictionType = perfetto::protos::FrameTimelineEvent_PredictionType; namespace android::frametimeline { @@ -717,7 +718,7 @@ ProtoExpectedDisplayFrameStart createProtoExpectedDisplayFrameStart(int64_t cook ProtoActualDisplayFrameStart createProtoActualDisplayFrameStart( int64_t cookie, int64_t token, pid_t pid, ProtoPresentType presentType, bool onTimeFinish, - bool gpuComposition, ProtoJankType jankType) { + bool gpuComposition, ProtoJankType jankType, ProtoPredictionType predictionType) { ProtoActualDisplayFrameStart proto; proto.set_cookie(cookie); proto.set_token(token); @@ -726,6 +727,7 @@ ProtoActualDisplayFrameStart createProtoActualDisplayFrameStart( proto.set_on_time_finish(onTimeFinish); proto.set_gpu_composition(gpuComposition); proto.set_jank_type(jankType); + proto.set_prediction_type(predictionType); return proto; } @@ -745,7 +747,7 @@ ProtoExpectedSurfaceFrameStart createProtoExpectedSurfaceFrameStart(int64_t cook ProtoActualSurfaceFrameStart createProtoActualSurfaceFrameStart( int64_t cookie, int64_t token, int64_t displayFrameToken, pid_t pid, std::string layerName, ProtoPresentType presentType, bool onTimeFinish, bool gpuComposition, - ProtoJankType jankType) { + ProtoJankType jankType, ProtoPredictionType predictionType) { ProtoActualSurfaceFrameStart proto; proto.set_cookie(cookie); proto.set_token(token); @@ -756,6 +758,7 @@ ProtoActualSurfaceFrameStart createProtoActualSurfaceFrameStart( proto.set_on_time_finish(onTimeFinish); proto.set_gpu_composition(gpuComposition); proto.set_jank_type(jankType); + proto.set_prediction_type(predictionType); return proto; } @@ -796,6 +799,8 @@ void validateTraceEvent(const ProtoActualDisplayFrameStart& received, EXPECT_EQ(received.gpu_composition(), source.gpu_composition()); ASSERT_TRUE(received.has_jank_type()); EXPECT_EQ(received.jank_type(), source.jank_type()); + ASSERT_TRUE(received.has_prediction_type()); + EXPECT_EQ(received.prediction_type(), source.prediction_type()); } void validateTraceEvent(const ProtoExpectedSurfaceFrameStart& received, @@ -841,6 +846,8 @@ void validateTraceEvent(const ProtoActualSurfaceFrameStart& received, EXPECT_EQ(received.gpu_composition(), source.gpu_composition()); ASSERT_TRUE(received.has_jank_type()); EXPECT_EQ(received.jank_type(), source.jank_type()); + ASSERT_TRUE(received.has_prediction_type()); + EXPECT_EQ(received.prediction_type(), source.prediction_type()); } void validateTraceEvent(const ProtoFrameEnd& received, const ProtoFrameEnd& source) { @@ -869,7 +876,8 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { createProtoActualDisplayFrameStart(traceCookie + 2, displayFrameToken1, kSurfaceFlingerPid, FrameTimelineEvent::PRESENT_ON_TIME, true, false, - FrameTimelineEvent::JANK_NONE); + FrameTimelineEvent::JANK_NONE, + FrameTimelineEvent::PREDICTION_VALID); auto protoActualDisplayFrameEnd = createProtoFrameEnd(traceCookie + 2); addEmptyDisplayFrame(); @@ -944,7 +952,8 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_predictionExpiredDoesNotTraceExpecte createProtoActualDisplayFrameStart(traceCookie + 1, displayFrameToken1, kSurfaceFlingerPid, FrameTimelineEvent::PRESENT_UNSPECIFIED, false, - false, FrameTimelineEvent::JANK_UNKNOWN); + false, FrameTimelineEvent::JANK_UNKNOWN, + FrameTimelineEvent::PREDICTION_EXPIRED); auto protoActualDisplayFrameEnd = createProtoFrameEnd(traceCookie + 1); addEmptyDisplayFrame(); @@ -1014,7 +1023,8 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { createProtoActualSurfaceFrameStart(traceCookie + 2, surfaceFrameToken, displayFrameToken1, sPidOne, sLayerNameOne, FrameTimelineEvent::PRESENT_DROPPED, false, false, - FrameTimelineEvent::JANK_NONE); + FrameTimelineEvent::JANK_NONE, + FrameTimelineEvent::PREDICTION_VALID); auto protoDroppedSurfaceFrameActualEnd = createProtoFrameEnd(traceCookie + 2); auto protoPresentedSurfaceFrameExpectedStart = @@ -1025,7 +1035,8 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { createProtoActualSurfaceFrameStart(traceCookie + 4, surfaceFrameToken, displayFrameToken1, sPidOne, sLayerNameOne, FrameTimelineEvent::PRESENT_ON_TIME, true, false, - FrameTimelineEvent::JANK_NONE); + FrameTimelineEvent::JANK_NONE, + FrameTimelineEvent::PREDICTION_VALID); auto protoPresentedSurfaceFrameActualEnd = createProtoFrameEnd(traceCookie + 4); // Set up the display frame @@ -1167,7 +1178,8 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpecte createProtoActualSurfaceFrameStart(traceCookie + 1, surfaceFrameToken, displayFrameToken, sPidOne, sLayerNameOne, FrameTimelineEvent::PRESENT_UNSPECIFIED, false, - false, FrameTimelineEvent::JANK_UNKNOWN); + false, FrameTimelineEvent::JANK_UNKNOWN, + FrameTimelineEvent::PREDICTION_EXPIRED); auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1); // Set up the display frame diff --git a/services/vibratorservice/VibratorHalController.cpp b/services/vibratorservice/VibratorHalController.cpp index bcd99575b4..537e49bc0a 100644 --- a/services/vibratorservice/VibratorHalController.cpp +++ b/services/vibratorservice/VibratorHalController.cpp @@ -217,10 +217,10 @@ HalResult<milliseconds> HalController::performEffect( return apply(performEffectFn, "performEffect"); } -HalResult<void> HalController::performComposedEffect( +HalResult<milliseconds> HalController::performComposedEffect( const std::vector<CompositeEffect>& primitiveEffects, const std::function<void()>& completionCallback) { - hal_fn<void> performComposedEffectFn = [&](std::shared_ptr<HalWrapper> hal) { + hal_fn<milliseconds> performComposedEffectFn = [&](std::shared_ptr<HalWrapper> hal) { return hal->performComposedEffect(primitiveEffects, completionCallback); }; return apply(performComposedEffectFn, "performComposedEffect"); diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp index 7fee82fb19..6faab38c51 100644 --- a/services/vibratorservice/VibratorHalWrapper.cpp +++ b/services/vibratorservice/VibratorHalWrapper.cpp @@ -224,12 +224,45 @@ HalResult<milliseconds> AidlHalWrapper::performEffect( return ret; } -HalResult<void> AidlHalWrapper::performComposedEffect( +HalResult<milliseconds> AidlHalWrapper::performComposedEffect( const std::vector<CompositeEffect>& primitiveEffects, const std::function<void()>& completionCallback) { // This method should always support callbacks, so no need to double check. auto cb = new HalCallbackWrapper(completionCallback); - return HalResult<void>::fromStatus(getHal()->compose(primitiveEffects, cb)); + milliseconds duration(0); + for (const auto& effect : primitiveEffects) { + auto durationResult = getPrimitiveDuration(effect.primitive); + if (durationResult.isOk()) { + duration += durationResult.value(); + } + duration += milliseconds(effect.delayMs); + } + return HalResult<milliseconds>::fromStatus(getHal()->compose(primitiveEffects, cb), duration); +} + +HalResult<milliseconds> AidlHalWrapper::getPrimitiveDuration(CompositePrimitive primitive) { + std::lock_guard<std::mutex> lock(mSupportedPrimitivesMutex); + if (mPrimitiveDurations.empty()) { + constexpr auto primitiveRange = enum_range<CompositePrimitive>(); + constexpr auto primitiveCount = std::distance(primitiveRange.begin(), primitiveRange.end()); + mPrimitiveDurations.resize(primitiveCount); + } + auto primitiveIdx = static_cast<size_t>(primitive); + if (primitiveIdx >= mPrimitiveDurations.size()) { + // Safety check, should not happen if enum_range is correct. + return HalResult<milliseconds>::unsupported(); + } + auto& cache = mPrimitiveDurations[primitiveIdx]; + if (cache.has_value()) { + return HalResult<milliseconds>::ok(*cache); + } + int32_t duration; + auto result = getHal()->getPrimitiveDuration(primitive, &duration); + if (result.isOk()) { + // Cache copy of returned value. + cache.emplace(duration); + } + return HalResult<milliseconds>::fromStatus(result, milliseconds(duration)); } HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() { @@ -333,10 +366,10 @@ HalResult<std::vector<CompositePrimitive>> HidlHalWrapper<I>::getSupportedPrimit } template <typename I> -HalResult<void> HidlHalWrapper<I>::performComposedEffect(const std::vector<CompositeEffect>&, - const std::function<void()>&) { +HalResult<std::chrono::milliseconds> HidlHalWrapper<I>::performComposedEffect( + const std::vector<CompositeEffect>&, const std::function<void()>&) { ALOGV("Skipped composed effect because Vibrator HAL AIDL is not available"); - return HalResult<void>::unsupported(); + return HalResult<std::chrono::milliseconds>::unsupported(); } template <typename I> diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h index c405545aab..16d571d2af 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h +++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h @@ -77,7 +77,7 @@ public: hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength, const std::function<void()>& completionCallback) final override; - HalResult<void> performComposedEffect( + HalResult<std::chrono::milliseconds> performComposedEffect( const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects, const std::function<void()>& completionCallback) final override; diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h index 638b48346b..e22ad340a3 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h +++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h @@ -189,7 +189,7 @@ public: hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength, const std::function<void()>& completionCallback) = 0; - virtual HalResult<void> performComposedEffect( + virtual HalResult<std::chrono::milliseconds> performComposedEffect( const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects, const std::function<void()>& completionCallback) = 0; @@ -236,7 +236,7 @@ public: hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength, const std::function<void()>& completionCallback) override final; - HalResult<void> performComposedEffect( + HalResult<std::chrono::milliseconds> performComposedEffect( const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects, const std::function<void()>& completionCallback) override final; @@ -252,6 +252,12 @@ private: GUARDED_BY(mSupportedEffectsMutex); std::optional<std::vector<hardware::vibrator::CompositePrimitive>> mSupportedPrimitives GUARDED_BY(mSupportedPrimitivesMutex); + std::vector<std::optional<std::chrono::milliseconds>> mPrimitiveDurations + GUARDED_BY(mSupportedPrimitivesMutex); + + // Loads and caches from IVibrator. + HalResult<std::chrono::milliseconds> getPrimitiveDuration( + hardware::vibrator::CompositePrimitive primitive); // Loads directly from IVibrator handle, skipping caches. HalResult<Capabilities> getCapabilitiesInternal(); @@ -287,7 +293,7 @@ public: HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitives() override final; - HalResult<void> performComposedEffect( + HalResult<std::chrono::milliseconds> performComposedEffect( const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects, const std::function<void()>& completionCallback) override final; diff --git a/services/vibratorservice/test/VibratorHalControllerTest.cpp b/services/vibratorservice/test/VibratorHalControllerTest.cpp index 2d9d0d6138..c4b39edec4 100644 --- a/services/vibratorservice/test/VibratorHalControllerTest.cpp +++ b/services/vibratorservice/test/VibratorHalControllerTest.cpp @@ -71,7 +71,7 @@ public: (Effect effect, EffectStrength strength, const std::function<void()>& completionCallback), (override)); - MOCK_METHOD(vibrator::HalResult<void>, performComposedEffect, + MOCK_METHOD(vibrator::HalResult<milliseconds>, performComposedEffect, (const std::vector<CompositeEffect>& primitiveEffects, const std::function<void()>& completionCallback), (override)); @@ -143,7 +143,7 @@ protected: .WillRepeatedly(Return(durationResult)); EXPECT_CALL(*mMockHal.get(), performComposedEffect(Eq(compositeEffects), _)) .Times(Exactly(cardinality)) - .WillRepeatedly(Return(voidResult)); + .WillRepeatedly(Return(durationResult)); if (cardinality > 1) { // One reconnection call after each failure. @@ -208,7 +208,10 @@ TEST_F(VibratorHalControllerTest, TestApiCallsAreForwardedToHal) { ASSERT_TRUE(performEffectResult.isOk()); ASSERT_EQ(100ms, performEffectResult.value()); - ASSERT_TRUE(mController->performComposedEffect(compositeEffects, []() {}).isOk()); + auto performComposedEffectResult = + mController->performComposedEffect(compositeEffects, []() {}); + ASSERT_TRUE(performComposedEffectResult.isOk()); + ASSERT_EQ(100ms, performComposedEffectResult.value()); ASSERT_EQ(1, mConnectCounter); } diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp index f85fa10e0d..8b5caa5f82 100644 --- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp +++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp @@ -506,10 +506,21 @@ TEST_F(VibratorHalWrapperAidlTest, TestPerformComposedEffect) { EXPECT_CALL(*mMockHal.get(), compose(Eq(emptyEffects), _)) .Times(Exactly(1)) .WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status()))); + + EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::CLICK), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(1), Return(Status()))); EXPECT_CALL(*mMockHal.get(), compose(Eq(singleEffect), _)) .Times(Exactly(1)) .WillRepeatedly(Return( Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION))); + + EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::SPIN), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(2), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::THUD), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(3), Return(Status()))); EXPECT_CALL(*mMockHal.get(), compose(Eq(multipleEffects), _)) .Times(Exactly(1)) .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))); @@ -520,6 +531,7 @@ TEST_F(VibratorHalWrapperAidlTest, TestPerformComposedEffect) { auto result = mWrapper->performComposedEffect(emptyEffects, callback); ASSERT_TRUE(result.isOk()); + ASSERT_EQ(0ms, result.value()); ASSERT_EQ(1, *callbackCounter.get()); result = mWrapper->performComposedEffect(singleEffect, callback); @@ -532,3 +544,40 @@ TEST_F(VibratorHalWrapperAidlTest, TestPerformComposedEffect) { // Callback not triggered on failure ASSERT_EQ(1, *callbackCounter.get()); } + +TEST_F(VibratorHalWrapperAidlTest, TestPerformComposedCachesPrimitiveDurationsAndIgnoresFailures) { + std::vector<CompositeEffect> multipleEffects; + multipleEffects.push_back( + vibrator::TestFactory::createCompositeEffect(CompositePrimitive::SPIN, 10ms, 0.5f)); + multipleEffects.push_back( + vibrator::TestFactory::createCompositeEffect(CompositePrimitive::THUD, 100ms, 1.0f)); + + EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::SPIN), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(1), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::THUD), _)) + .Times(Exactly(2)) + .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))) + .WillRepeatedly(DoAll(SetArgPointee<1>(2), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), compose(Eq(multipleEffects), _)) + .Times(Exactly(3)) + .WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status()))); + + std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); + auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); + + auto result = mWrapper->performComposedEffect(multipleEffects, callback); + ASSERT_TRUE(result.isOk()); + ASSERT_EQ(111ms, result.value()); // Failed primitive duration counted as 0. + ASSERT_EQ(1, *callbackCounter.get()); + + result = mWrapper->performComposedEffect(multipleEffects, callback); + ASSERT_TRUE(result.isOk()); + ASSERT_EQ(113ms, result.value()); // Second fetch succeeds and returns primitive duration. + ASSERT_EQ(2, *callbackCounter.get()); + + result = mWrapper->performComposedEffect(multipleEffects, callback); + ASSERT_TRUE(result.isOk()); + ASSERT_EQ(113ms, result.value()); // Cached durations not fetched again, same duration returned. + ASSERT_EQ(3, *callbackCounter.get()); +} |