| Valerie Hau | 9dab973 | 2019-08-20 09:29:25 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2019 The Android Open Source Project | 
 | 3 |  * | 
 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 |  * you may not use this file except in compliance with the License. | 
 | 6 |  * You may obtain a copy of the License at | 
 | 7 |  * | 
 | 8 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 |  * | 
 | 10 |  * Unless required by applicable law or agreed to in writing, software | 
 | 11 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 |  * See the License for the specific language governing permissions and | 
 | 14 |  * limitations under the License. | 
 | 15 |  */ | 
 | 16 |  | 
| Valerie Hau | 9dab973 | 2019-08-20 09:29:25 -0700 | [diff] [blame] | 17 | #include <binder/IInterface.h> | 
 | 18 | #include <binder/IPCThreadState.h> | 
 | 19 | #include <binder/IServiceManager.h> | 
 | 20 | #include <binder/ProcessState.h> | 
| Dominik Laskowski | 3cb3d4e | 2019-11-21 11:14:45 -0800 | [diff] [blame] | 21 | #include <gtest/gtest.h> | 
| Valerie Hau | 9dab973 | 2019-08-20 09:29:25 -0700 | [diff] [blame] | 22 | #include <gui/ISurfaceComposer.h> | 
 | 23 | #include <gui/LayerState.h> | 
 | 24 | #include <gui/Surface.h> | 
 | 25 | #include <gui/SurfaceComposerClient.h> | 
| Marin Shalamanov | a7fe304 | 2021-01-29 21:02:08 +0100 | [diff] [blame] | 26 | #include <ui/DisplayMode.h> | 
| Dominik Laskowski | 3cb3d4e | 2019-11-21 11:14:45 -0800 | [diff] [blame] | 27 | #include <utils/String8.h> | 
| Valerie Hau | 9dab973 | 2019-08-20 09:29:25 -0700 | [diff] [blame] | 28 |  | 
 | 29 | #include <limits> | 
 | 30 |  | 
| Valerie Hau | 9dab973 | 2019-08-20 09:29:25 -0700 | [diff] [blame] | 31 | #include "BufferGenerator.h" | 
 | 32 | #include "utils/CallbackUtils.h" | 
 | 33 | #include "utils/ColorUtils.h" | 
 | 34 | #include "utils/TransactionUtils.h" | 
 | 35 |  | 
 | 36 | namespace android { | 
 | 37 |  | 
 | 38 | namespace test { | 
 | 39 |  | 
 | 40 | using Transaction = SurfaceComposerClient::Transaction; | 
 | 41 | using CallbackInfo = SurfaceComposerClient::CallbackInfo; | 
 | 42 | using TCLHash = SurfaceComposerClient::TCLHash; | 
 | 43 | using android::hardware::graphics::common::V1_1::BufferUsage; | 
 | 44 |  | 
 | 45 | class TransactionHelper : public Transaction { | 
 | 46 | public: | 
 | 47 |     size_t getNumListeners() { return mListenerCallbacks.size(); } | 
 | 48 |  | 
 | 49 |     std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash> | 
 | 50 |     getListenerCallbacks() { | 
 | 51 |         return mListenerCallbacks; | 
 | 52 |     } | 
 | 53 | }; | 
 | 54 |  | 
 | 55 | class IPCTestUtils { | 
 | 56 | public: | 
 | 57 |     static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult, | 
 | 58 |                                 bool finalState = false); | 
 | 59 |     static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence); | 
 | 60 | }; | 
 | 61 |  | 
 | 62 | class IIPCTest : public IInterface { | 
 | 63 | public: | 
 | 64 |     DECLARE_META_INTERFACE(IPCTest) | 
 | 65 |     enum class Tag : uint32_t { | 
 | 66 |         SetDeathToken = IBinder::FIRST_CALL_TRANSACTION, | 
 | 67 |         InitClient, | 
 | 68 |         CreateTransaction, | 
 | 69 |         MergeAndApply, | 
 | 70 |         VerifyCallbacks, | 
 | 71 |         CleanUp, | 
 | 72 |         Last, | 
 | 73 |     }; | 
 | 74 |  | 
 | 75 |     virtual status_t setDeathToken(sp<IBinder>& token) = 0; | 
 | 76 |  | 
 | 77 |     virtual status_t initClient() = 0; | 
 | 78 |  | 
 | 79 |     virtual status_t createTransaction(TransactionHelper* outTransaction, uint32_t width, | 
 | 80 |                                        uint32_t height) = 0; | 
 | 81 |  | 
 | 82 |     virtual status_t mergeAndApply(TransactionHelper transaction) = 0; | 
 | 83 |  | 
 | 84 |     virtual status_t verifyCallbacks() = 0; | 
 | 85 |  | 
 | 86 |     virtual status_t cleanUp() = 0; | 
 | 87 | }; | 
 | 88 |  | 
 | 89 | class BpIPCTest : public SafeBpInterface<IIPCTest> { | 
 | 90 | public: | 
 | 91 |     explicit BpIPCTest(const sp<IBinder>& impl) : SafeBpInterface<IIPCTest>(impl, "BpIPCTest") {} | 
 | 92 |  | 
 | 93 |     status_t setDeathToken(sp<IBinder>& token) { | 
 | 94 |         return callRemote<decltype(&IIPCTest::setDeathToken)>(Tag::SetDeathToken, token); | 
 | 95 |     } | 
 | 96 |  | 
 | 97 |     status_t initClient() { return callRemote<decltype(&IIPCTest::initClient)>(Tag::InitClient); } | 
 | 98 |  | 
 | 99 |     status_t createTransaction(TransactionHelper* transaction, uint32_t width, uint32_t height) { | 
 | 100 |         return callRemote<decltype(&IIPCTest::createTransaction)>(Tag::CreateTransaction, | 
 | 101 |                                                                   transaction, width, height); | 
 | 102 |     } | 
 | 103 |  | 
 | 104 |     status_t mergeAndApply(TransactionHelper transaction) { | 
 | 105 |         return callRemote<decltype(&IIPCTest::mergeAndApply)>(Tag::MergeAndApply, transaction); | 
 | 106 |     } | 
 | 107 |  | 
 | 108 |     status_t verifyCallbacks() { | 
 | 109 |         return callRemote<decltype(&IIPCTest::verifyCallbacks)>(Tag::VerifyCallbacks); | 
 | 110 |     } | 
 | 111 |  | 
 | 112 |     status_t cleanUp() { return callRemote<decltype(&IIPCTest::cleanUp)>(Tag::CleanUp); } | 
 | 113 | }; | 
 | 114 |  | 
 | 115 | IMPLEMENT_META_INTERFACE(IPCTest, "android.gfx.tests.IIPCTest") | 
 | 116 |  | 
 | 117 | class onTestDeath : public IBinder::DeathRecipient { | 
 | 118 | public: | 
 | 119 |     void binderDied(const wp<IBinder>& /*who*/) override { | 
 | 120 |         ALOGE("onTestDeath::binderDied, exiting"); | 
 | 121 |         exit(0); | 
 | 122 |     } | 
 | 123 | }; | 
 | 124 |  | 
 | 125 | sp<onTestDeath> getDeathToken() { | 
 | 126 |     static sp<onTestDeath> token = new onTestDeath; | 
 | 127 |     return token; | 
 | 128 | } | 
 | 129 |  | 
 | 130 | class BnIPCTest : public SafeBnInterface<IIPCTest> { | 
 | 131 | public: | 
 | 132 |     BnIPCTest() : SafeBnInterface("BnIPCTest") {} | 
 | 133 |  | 
 | 134 |     status_t setDeathToken(sp<IBinder>& token) override { | 
 | 135 |         return token->linkToDeath(getDeathToken()); | 
 | 136 |     } | 
 | 137 |  | 
 | 138 |     status_t initClient() override { | 
 | 139 |         mClient = new SurfaceComposerClient; | 
 | 140 |         auto err = mClient->initCheck(); | 
 | 141 |         return err; | 
 | 142 |     } | 
 | 143 |  | 
 | 144 |     status_t createTransaction(TransactionHelper* transaction, uint32_t width, uint32_t height) { | 
 | 145 |         if (transaction == nullptr) { | 
 | 146 |             ALOGE("Error in createTransaction: transaction is nullptr"); | 
 | 147 |             return BAD_VALUE; | 
 | 148 |         } | 
 | 149 |         mSurfaceControl = mClient->createSurface(String8("parentProcessSurface"), 0, 0, | 
 | 150 |                                                  PIXEL_FORMAT_RGBA_8888, | 
 | 151 |                                                  ISurfaceComposerClient::eFXSurfaceBufferState, | 
 | 152 |                                                  /*parent*/ nullptr); | 
 | 153 |         sp<GraphicBuffer> gb; | 
 | 154 |         sp<Fence> fence; | 
 | 155 |         int err = IPCTestUtils::getBuffer(&gb, &fence); | 
 | 156 |         if (err != NO_ERROR) return err; | 
 | 157 |  | 
 | 158 |         TransactionUtils::fillGraphicBufferColor(gb, | 
 | 159 |                                                  {0, 0, static_cast<int32_t>(width), | 
 | 160 |                                                   static_cast<int32_t>(height)}, | 
 | 161 |                                                  Color::RED); | 
 | 162 |         transaction->setLayerStack(mSurfaceControl, 0) | 
 | 163 |                 .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max()) | 
| Valerie Hau | 9dab973 | 2019-08-20 09:29:25 -0700 | [diff] [blame] | 164 |                 .setBuffer(mSurfaceControl, gb) | 
 | 165 |                 .setAcquireFence(mSurfaceControl, fence) | 
 | 166 |                 .show(mSurfaceControl) | 
 | 167 |                 .addTransactionCompletedCallback(mCallbackHelper.function, | 
 | 168 |                                                  mCallbackHelper.getContext()); | 
 | 169 |         return NO_ERROR; | 
 | 170 |     } | 
 | 171 |  | 
 | 172 |     status_t mergeAndApply(TransactionHelper /*transaction*/) { | 
 | 173 |         // transaction.apply(); | 
 | 174 |         return NO_ERROR; | 
 | 175 |     } | 
 | 176 |  | 
 | 177 |     status_t verifyCallbacks() { | 
 | 178 |         ExpectedResult expected; | 
 | 179 |         expected.addSurface(ExpectedResult::Transaction::PRESENTED, mSurfaceControl); | 
 | 180 |         EXPECT_NO_FATAL_FAILURE(IPCTestUtils::waitForCallback(mCallbackHelper, expected, true)); | 
 | 181 |         return NO_ERROR; | 
 | 182 |     } | 
 | 183 |  | 
 | 184 |     status_t cleanUp() { | 
 | 185 |         if (mClient) mClient->dispose(); | 
 | 186 |         mSurfaceControl = nullptr; | 
 | 187 |         IPCThreadState::self()->stopProcess(); | 
 | 188 |         return NO_ERROR; | 
 | 189 |     } | 
 | 190 |  | 
 | 191 |     status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, | 
 | 192 |                         uint32_t /*flags*/) override { | 
 | 193 |         EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION); | 
 | 194 |         EXPECT_LT(code, static_cast<uint32_t>(IIPCTest::Tag::Last)); | 
 | 195 |         switch (static_cast<IIPCTest::Tag>(code)) { | 
 | 196 |             case IIPCTest::Tag::SetDeathToken: | 
 | 197 |                 return callLocal(data, reply, &IIPCTest::setDeathToken); | 
 | 198 |             case IIPCTest::Tag::InitClient: | 
 | 199 |                 return callLocal(data, reply, &IIPCTest::initClient); | 
 | 200 |             case IIPCTest::Tag::CreateTransaction: | 
 | 201 |                 return callLocal(data, reply, &IIPCTest::createTransaction); | 
 | 202 |             case IIPCTest::Tag::MergeAndApply: | 
 | 203 |                 return callLocal(data, reply, &IIPCTest::mergeAndApply); | 
 | 204 |             case IIPCTest::Tag::VerifyCallbacks: | 
 | 205 |                 return callLocal(data, reply, &IIPCTest::verifyCallbacks); | 
 | 206 |             case IIPCTest::Tag::CleanUp: | 
 | 207 |                 return callLocal(data, reply, &IIPCTest::cleanUp); | 
 | 208 |             default: | 
 | 209 |                 return UNKNOWN_ERROR; | 
 | 210 |         } | 
 | 211 |     } | 
 | 212 |  | 
 | 213 | private: | 
 | 214 |     sp<SurfaceComposerClient> mClient; | 
 | 215 |     sp<SurfaceControl> mSurfaceControl; | 
 | 216 |     CallbackHelper mCallbackHelper; | 
 | 217 | }; | 
 | 218 |  | 
 | 219 | class IPCTest : public ::testing::Test { | 
 | 220 | public: | 
 | 221 |     IPCTest() : mDeathRecipient(new BBinder), mRemote(initRemoteService()) { | 
 | 222 |         ProcessState::self()->startThreadPool(); | 
 | 223 |     } | 
 | 224 |     void SetUp() { | 
 | 225 |         mClient = new SurfaceComposerClient; | 
 | 226 |         ASSERT_EQ(NO_ERROR, mClient->initCheck()); | 
 | 227 |  | 
 | 228 |         mPrimaryDisplay = mClient->getInternalDisplayToken(); | 
| Marin Shalamanov | a7fe304 | 2021-01-29 21:02:08 +0100 | [diff] [blame] | 229 |         ui::DisplayMode mode; | 
 | 230 |         mClient->getActiveDisplayMode(mPrimaryDisplay, &mode); | 
 | 231 |         mDisplayWidth = mode.resolution.getWidth(); | 
 | 232 |         mDisplayHeight = mode.resolution.getHeight(); | 
| Valerie Hau | 9dab973 | 2019-08-20 09:29:25 -0700 | [diff] [blame] | 233 |  | 
 | 234 |         Transaction setupTransaction; | 
 | 235 |         setupTransaction.setDisplayLayerStack(mPrimaryDisplay, 0); | 
 | 236 |         setupTransaction.apply(); | 
 | 237 |     } | 
 | 238 |  | 
 | 239 | protected: | 
 | 240 |     sp<IIPCTest> initRemoteService(); | 
 | 241 |  | 
 | 242 |     sp<IBinder> mDeathRecipient; | 
 | 243 |     sp<IIPCTest> mRemote; | 
 | 244 |     sp<SurfaceComposerClient> mClient; | 
 | 245 |     sp<IBinder> mPrimaryDisplay; | 
 | 246 |     uint32_t mDisplayWidth; | 
 | 247 |     uint32_t mDisplayHeight; | 
 | 248 |     sp<SurfaceControl> sc; | 
 | 249 | }; | 
 | 250 |  | 
 | 251 | status_t IPCTestUtils::getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) { | 
 | 252 |     static BufferGenerator bufferGenerator; | 
 | 253 |     return bufferGenerator.get(outBuffer, outFence); | 
 | 254 | } | 
 | 255 |  | 
 | 256 | void IPCTestUtils::waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult, | 
 | 257 |                                    bool finalState) { | 
 | 258 |     CallbackData callbackData; | 
 | 259 |     ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData)); | 
 | 260 |     EXPECT_NO_FATAL_FAILURE(expectedResult.verifyCallbackData(callbackData)); | 
 | 261 |  | 
 | 262 |     if (finalState) { | 
 | 263 |         ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState()); | 
 | 264 |     } | 
 | 265 | } | 
 | 266 |  | 
 | 267 | sp<IIPCTest> IPCTest::initRemoteService() { | 
 | 268 |     static std::mutex mMutex; | 
 | 269 |     static sp<IIPCTest> remote; | 
 | 270 |     const String16 serviceName("IPCTest"); | 
 | 271 |  | 
 | 272 |     std::unique_lock<decltype(mMutex)> lock; | 
 | 273 |     if (remote == nullptr) { | 
 | 274 |         pid_t forkPid = fork(); | 
 | 275 |         EXPECT_NE(forkPid, -1); | 
 | 276 |  | 
 | 277 |         if (forkPid == 0) { | 
 | 278 |             sp<IIPCTest> nativeService = new BnIPCTest; | 
 | 279 |             if (!nativeService) { | 
 | 280 |                 ALOGE("null service..."); | 
 | 281 |             } | 
 | 282 |             status_t err = defaultServiceManager()->addService(serviceName, | 
 | 283 |                                                                IInterface::asBinder(nativeService)); | 
 | 284 |             if (err != NO_ERROR) { | 
 | 285 |                 ALOGE("failed to add service: %d", err); | 
 | 286 |             } | 
 | 287 |             ProcessState::self()->startThreadPool(); | 
 | 288 |             IPCThreadState::self()->joinThreadPool(); | 
 | 289 |             [&]() { exit(0); }(); | 
 | 290 |         } | 
 | 291 |         sp<IBinder> binder = defaultServiceManager()->getService(serviceName); | 
 | 292 |         remote = interface_cast<IIPCTest>(binder); | 
 | 293 |         remote->setDeathToken(mDeathRecipient); | 
 | 294 |     } | 
 | 295 |     return remote; | 
 | 296 | } | 
 | 297 |  | 
 | 298 | TEST_F(IPCTest, MergeBasic) { | 
 | 299 |     CallbackHelper helper1; | 
 | 300 |     sc = mClient->createSurface(String8("parentProcessSurface"), 0, 0, PIXEL_FORMAT_RGBA_8888, | 
 | 301 |                                 ISurfaceComposerClient::eFXSurfaceBufferState, | 
 | 302 |                                 /*parent*/ nullptr); | 
 | 303 |     sp<GraphicBuffer> gb; | 
 | 304 |     sp<Fence> fence; | 
 | 305 |     int err = IPCTestUtils::getBuffer(&gb, &fence); | 
 | 306 |     ASSERT_EQ(NO_ERROR, err); | 
 | 307 |     TransactionUtils::fillGraphicBufferColor(gb, | 
 | 308 |                                              {0, 0, static_cast<int32_t>(mDisplayWidth), | 
 | 309 |                                               static_cast<int32_t>(mDisplayHeight)}, | 
 | 310 |                                              Color::RED); | 
 | 311 |  | 
 | 312 |     Transaction transaction; | 
 | 313 |     transaction.setLayerStack(sc, 0) | 
 | 314 |             .setLayer(sc, std::numeric_limits<int32_t>::max() - 1) | 
 | 315 |             .setBuffer(sc, gb) | 
 | 316 |             .setAcquireFence(sc, fence) | 
 | 317 |             .show(sc) | 
 | 318 |             .addTransactionCompletedCallback(helper1.function, helper1.getContext()); | 
 | 319 |  | 
 | 320 |     TransactionHelper remote; | 
 | 321 |     mRemote->initClient(); | 
 | 322 |     mRemote->createTransaction(&remote, mDisplayWidth / 2, mDisplayHeight / 2); | 
 | 323 |     ASSERT_EQ(1, remote.getNumListeners()); | 
 | 324 |     auto remoteListenerCallbacks = remote.getListenerCallbacks(); | 
 | 325 |     auto remoteCallback = remoteListenerCallbacks.begin(); | 
 | 326 |     auto remoteCallbackInfo = remoteCallback->second; | 
 | 327 |     auto remoteListenerScs = remoteCallbackInfo.surfaceControls; | 
 | 328 |     ASSERT_EQ(1, remoteCallbackInfo.callbackIds.size()); | 
 | 329 |     ASSERT_EQ(1, remoteListenerScs.size()); | 
 | 330 |  | 
 | 331 |     sp<SurfaceControl> remoteSc = *(remoteListenerScs.begin()); | 
 | 332 |     transaction.merge(std::move(remote)); | 
 | 333 |     transaction.apply(); | 
 | 334 |  | 
 | 335 |     sleep(1); | 
 | 336 |     ExpectedResult expected; | 
 | 337 |     expected.addSurface(ExpectedResult::Transaction::PRESENTED, sc); | 
 | 338 |     expected.addSurface(ExpectedResult::Transaction::PRESENTED, remoteSc); | 
 | 339 |     EXPECT_NO_FATAL_FAILURE(IPCTestUtils::waitForCallback(helper1, expected, true)); | 
 | 340 |  | 
 | 341 |     mRemote->verifyCallbacks(); | 
 | 342 |     mRemote->cleanUp(); | 
 | 343 | } | 
 | 344 |  | 
 | 345 | } // namespace test | 
 | 346 | } // namespace android |