1 /*
2  * Copyright 2018 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 
17 #pragma once
18 
19 #ifndef LOG_TAG
20 #warning "ComposerClient.h included without LOG_TAG"
21 #endif
22 
23 #include <memory>
24 #include <mutex>
25 #include <vector>
26 
27 #include <android/hardware/graphics/composer/2.1/IComposerClient.h>
28 #include <composer-hal/2.1/ComposerCommandEngine.h>
29 #include <composer-hal/2.1/ComposerHal.h>
30 #include <composer-resources/2.1/ComposerResources.h>
31 #include <log/log.h>
32 
33 namespace android {
34 namespace hardware {
35 namespace graphics {
36 namespace composer {
37 namespace V2_1 {
38 namespace hal {
39 
40 namespace detail {
41 
42 // ComposerClientImpl implements V2_*::IComposerClient on top of V2_*::ComposerHal
43 template <typename Interface, typename Hal>
44 class ComposerClientImpl : public Interface {
45    public:
create(Hal * hal)46     static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
47         auto client = std::make_unique<ComposerClientImpl>(hal);
48         return client->init() ? std::move(client) : nullptr;
49     }
50 
ComposerClientImpl(Hal * hal)51     ComposerClientImpl(Hal* hal) : mHal(hal) {}
52 
~ComposerClientImpl()53     virtual ~ComposerClientImpl() {
54         // not initialized
55         if (!mCommandEngine) {
56             return;
57         }
58 
59         ALOGD("destroying composer client");
60 
61         mHal->unregisterEventCallback();
62         destroyResources();
63         if (mOnClientDestroyed) {
64             mOnClientDestroyed();
65         }
66 
67         ALOGD("removed composer client");
68     }
69 
init()70     bool init() {
71         mResources = createResources();
72         if (!mResources) {
73             ALOGE("failed to create composer resources");
74             return false;
75         }
76 
77         mCommandEngine = createCommandEngine();
78 
79         return true;
80     }
81 
setOnClientDestroyed(std::function<void ()> onClientDestroyed)82     void setOnClientDestroyed(std::function<void()> onClientDestroyed) {
83         mOnClientDestroyed = onClientDestroyed;
84     }
85 
86     // IComposerClient 2.1 interface
87 
88     class HalEventCallback : public Hal::EventCallback {
89        public:
HalEventCallback(Hal * hal,const sp<IComposerCallback> callback,ComposerResources * resources)90          HalEventCallback(Hal* hal, const sp<IComposerCallback> callback,
91                           ComposerResources* resources)
92              : mHal(hal), mCallback(callback), mResources(resources) {}
93 
onHotplug(Display display,IComposerCallback::Connection connected)94          void onHotplug(Display display, IComposerCallback::Connection connected) {
95              if (connected == IComposerCallback::Connection::CONNECTED) {
96                  if (mResources->hasDisplay(display)) {
97                      // This is a subsequent hotplug "connected" for a display. This signals a
98                      // display change and thus the framework may want to reallocate buffers. We
99                      // need to free all cached handles, since they are holding a strong reference
100                      // to the underlying buffers.
101                      cleanDisplayResources(display, mResources, mHal);
102                      mResources->removeDisplay(display);
103                  }
104                  mResources->addPhysicalDisplay(display);
105              } else if (connected == IComposerCallback::Connection::DISCONNECTED) {
106                  mResources->removeDisplay(display);
107              }
108 
109              auto ret = mCallback->onHotplug(display, connected);
110              ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", ret.description().c_str());
111          }
112 
onRefresh(Display display)113         void onRefresh(Display display) {
114             mResources->setDisplayMustValidateState(display, true);
115             auto ret = mCallback->onRefresh(display);
116             ALOGE_IF(!ret.isOk(), "failed to send onRefresh: %s", ret.description().c_str());
117         }
118 
onVsync(Display display,int64_t timestamp)119         void onVsync(Display display, int64_t timestamp) {
120             auto ret = mCallback->onVsync(display, timestamp);
121             ALOGE_IF(!ret.isOk(), "failed to send onVsync: %s", ret.description().c_str());
122         }
123 
124        protected:
125          Hal* const mHal;
126          const sp<IComposerCallback> mCallback;
127          ComposerResources* const mResources;
128     };
129 
registerCallback(const sp<IComposerCallback> & callback)130     Return<void> registerCallback(const sp<IComposerCallback>& callback) override {
131         // no locking as we require this function to be called only once
132         mHalEventCallback = std::make_unique<HalEventCallback>(mHal, callback, mResources.get());
133         mHal->registerEventCallback(mHalEventCallback.get());
134         return Void();
135     }
136 
getMaxVirtualDisplayCount()137     Return<uint32_t> getMaxVirtualDisplayCount() override {
138         return mHal->getMaxVirtualDisplayCount();
139     }
140 
createVirtualDisplay(uint32_t width,uint32_t height,PixelFormat formatHint,uint32_t outputBufferSlotCount,IComposerClient::createVirtualDisplay_cb hidl_cb)141     Return<void> createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat formatHint,
142                                       uint32_t outputBufferSlotCount,
143                                       IComposerClient::createVirtualDisplay_cb hidl_cb) override {
144         Display display = 0;
145         Error err = mHal->createVirtualDisplay(width, height, &formatHint, &display);
146         if (err == Error::NONE) {
147             mResources->addVirtualDisplay(display, outputBufferSlotCount);
148         }
149 
150         hidl_cb(err, display, formatHint);
151         return Void();
152     }
153 
destroyVirtualDisplay(Display display)154     Return<Error> destroyVirtualDisplay(Display display) override {
155         Error err = mHal->destroyVirtualDisplay(display);
156         if (err == Error::NONE) {
157             mResources->removeDisplay(display);
158         }
159 
160         return err;
161     }
162 
createLayer(Display display,uint32_t bufferSlotCount,IComposerClient::createLayer_cb hidl_cb)163     Return<void> createLayer(Display display, uint32_t bufferSlotCount,
164                              IComposerClient::createLayer_cb hidl_cb) override {
165         Layer layer = 0;
166         Error err = mHal->createLayer(display, &layer);
167         if (err == Error::NONE) {
168             err = mResources->addLayer(display, layer, bufferSlotCount);
169             if (err != Error::NONE) {
170                 // The display entry may have already been removed by onHotplug.
171                 // Note: We do not destroy the layer on this error as the hotplug
172                 // disconnect invalidates the display id. The implementation should
173                 // ensure all layers for the display are destroyed.
174                 layer = 0;
175             }
176         }
177 
178         hidl_cb(err, layer);
179         return Void();
180     }
181 
destroyLayer(Display display,Layer layer)182     Return<Error> destroyLayer(Display display, Layer layer) override {
183         Error err = mHal->destroyLayer(display, layer);
184         if (err == Error::NONE) {
185             mResources->removeLayer(display, layer);
186         }
187 
188         return err;
189     }
190 
getActiveConfig(Display display,IComposerClient::getActiveConfig_cb hidl_cb)191     Return<void> getActiveConfig(Display display,
192                                  IComposerClient::getActiveConfig_cb hidl_cb) override {
193         Config config = 0;
194         Error err = mHal->getActiveConfig(display, &config);
195         hidl_cb(err, config);
196         return Void();
197     }
198 
getClientTargetSupport(Display display,uint32_t width,uint32_t height,PixelFormat format,Dataspace dataspace)199     Return<Error> getClientTargetSupport(Display display, uint32_t width, uint32_t height,
200                                          PixelFormat format, Dataspace dataspace) override {
201         Error err = mHal->getClientTargetSupport(display, width, height, format, dataspace);
202         return err;
203     }
204 
getColorModes(Display display,IComposerClient::getColorModes_cb hidl_cb)205     Return<void> getColorModes(Display display,
206                                IComposerClient::getColorModes_cb hidl_cb) override {
207         hidl_vec<ColorMode> modes;
208         Error err = mHal->getColorModes(display, &modes);
209         hidl_cb(err, modes);
210         return Void();
211     }
212 
getDisplayAttribute(Display display,Config config,IComposerClient::Attribute attribute,IComposerClient::getDisplayAttribute_cb hidl_cb)213     Return<void> getDisplayAttribute(Display display, Config config,
214                                      IComposerClient::Attribute attribute,
215                                      IComposerClient::getDisplayAttribute_cb hidl_cb) override {
216         int32_t value = 0;
217         Error err = mHal->getDisplayAttribute(display, config, attribute, &value);
218         hidl_cb(err, value);
219         return Void();
220     }
221 
getDisplayConfigs(Display display,IComposerClient::getDisplayConfigs_cb hidl_cb)222     Return<void> getDisplayConfigs(Display display,
223                                    IComposerClient::getDisplayConfigs_cb hidl_cb) override {
224         hidl_vec<Config> configs;
225         Error err = mHal->getDisplayConfigs(display, &configs);
226         hidl_cb(err, configs);
227         return Void();
228     }
229 
getDisplayName(Display display,IComposerClient::getDisplayName_cb hidl_cb)230     Return<void> getDisplayName(Display display,
231                                 IComposerClient::getDisplayName_cb hidl_cb) override {
232         hidl_string name;
233         Error err = mHal->getDisplayName(display, &name);
234         hidl_cb(err, name);
235         return Void();
236     }
237 
getDisplayType(Display display,IComposerClient::getDisplayType_cb hidl_cb)238     Return<void> getDisplayType(Display display,
239                                 IComposerClient::getDisplayType_cb hidl_cb) override {
240         IComposerClient::DisplayType type = IComposerClient::DisplayType::INVALID;
241         Error err = mHal->getDisplayType(display, &type);
242         hidl_cb(err, type);
243         return Void();
244     }
245 
getDozeSupport(Display display,IComposerClient::getDozeSupport_cb hidl_cb)246     Return<void> getDozeSupport(Display display,
247                                 IComposerClient::getDozeSupport_cb hidl_cb) override {
248         bool support = false;
249         Error err = mHal->getDozeSupport(display, &support);
250         hidl_cb(err, support);
251         return Void();
252     }
253 
getHdrCapabilities(Display display,IComposerClient::getHdrCapabilities_cb hidl_cb)254     Return<void> getHdrCapabilities(Display display,
255                                     IComposerClient::getHdrCapabilities_cb hidl_cb) override {
256         hidl_vec<Hdr> types;
257         float max_lumi = 0.0f;
258         float max_avg_lumi = 0.0f;
259         float min_lumi = 0.0f;
260         Error err = mHal->getHdrCapabilities(display, &types, &max_lumi, &max_avg_lumi, &min_lumi);
261         hidl_cb(err, types, max_lumi, max_avg_lumi, min_lumi);
262         return Void();
263     }
264 
setActiveConfig(Display display,Config config)265     Return<Error> setActiveConfig(Display display, Config config) override {
266         Error err = mHal->setActiveConfig(display, config);
267         return err;
268     }
269 
setColorMode(Display display,ColorMode mode)270     Return<Error> setColorMode(Display display, ColorMode mode) override {
271         Error err = mHal->setColorMode(display, mode);
272         return err;
273     }
274 
setPowerMode(Display display,IComposerClient::PowerMode mode)275     Return<Error> setPowerMode(Display display, IComposerClient::PowerMode mode) override {
276         Error err = mHal->setPowerMode(display, mode);
277         return err;
278     }
279 
setVsyncEnabled(Display display,IComposerClient::Vsync enabled)280     Return<Error> setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override {
281         Error err = mHal->setVsyncEnabled(display, enabled);
282         return err;
283     }
284 
setClientTargetSlotCount(Display display,uint32_t clientTargetSlotCount)285     Return<Error> setClientTargetSlotCount(Display display,
286                                            uint32_t clientTargetSlotCount) override {
287         return mResources->setDisplayClientTargetCacheSize(display, clientTargetSlotCount);
288     }
289 
setInputCommandQueue(const MQDescriptorSync<uint32_t> & descriptor)290     Return<Error> setInputCommandQueue(const MQDescriptorSync<uint32_t>& descriptor) override {
291         std::lock_guard<std::mutex> lock(mCommandEngineMutex);
292         return mCommandEngine->setInputMQDescriptor(descriptor) ? Error::NONE : Error::NO_RESOURCES;
293     }
294 
getOutputCommandQueue(IComposerClient::getOutputCommandQueue_cb hidl_cb)295     Return<void> getOutputCommandQueue(IComposerClient::getOutputCommandQueue_cb hidl_cb) override {
296         // no locking as we require this function to be called inside
297         // executeCommands_cb
298         auto outDescriptor = mCommandEngine->getOutputMQDescriptor();
299         if (outDescriptor) {
300             hidl_cb(Error::NONE, *outDescriptor);
301         } else {
302             hidl_cb(Error::NO_RESOURCES, CommandQueueType::Descriptor());
303         }
304 
305         return Void();
306     }
307 
executeCommands(uint32_t inLength,const hidl_vec<hidl_handle> & inHandles,IComposerClient::executeCommands_cb hidl_cb)308     Return<void> executeCommands(uint32_t inLength, const hidl_vec<hidl_handle>& inHandles,
309                                  IComposerClient::executeCommands_cb hidl_cb) override {
310         std::lock_guard<std::mutex> lock(mCommandEngineMutex);
311         bool outChanged = false;
312         uint32_t outLength = 0;
313         hidl_vec<hidl_handle> outHandles;
314         Error error =
315             mCommandEngine->execute(inLength, inHandles, &outChanged, &outLength, &outHandles);
316 
317         hidl_cb(error, outChanged, outLength, outHandles);
318 
319         mCommandEngine->reset();
320 
321         return Void();
322     }
323 
324    protected:
createResources()325     virtual std::unique_ptr<ComposerResources> createResources() {
326         return ComposerResources::create();
327     }
328 
createCommandEngine()329     virtual std::unique_ptr<ComposerCommandEngine> createCommandEngine() {
330         return std::make_unique<ComposerCommandEngine>(mHal, mResources.get());
331     }
332 
cleanDisplayResources(Display display,ComposerResources * const resources,Hal * const hal)333     static void cleanDisplayResources(Display display, ComposerResources* const resources,
334                                       Hal* const hal) {
335         size_t cacheSize;
336         Error err = resources->getDisplayClientTargetCacheSize(display, &cacheSize);
337         if (err == Error::NONE) {
338             for (int slot = 0; slot < cacheSize; slot++) {
339                 ComposerResources::ReplacedHandle replacedBuffer(/*isBuffer*/ true);
340                 // Replace the buffer slots with NULLs. Keep the old handle until it is
341                 // replaced in ComposerHal, otherwise we risk leaving a dangling pointer.
342                 const native_handle_t* clientTarget = nullptr;
343                 err = resources->getDisplayClientTarget(display, slot, /*useCache*/ true,
344                                                         /*rawHandle*/ nullptr, &clientTarget,
345                                                         &replacedBuffer);
346                 if (err != Error::NONE) {
347                     continue;
348                 }
349                 const std::vector<hwc_rect_t> damage;
350                 err = hal->setClientTarget(display, clientTarget, /*fence*/ -1, 0, damage);
351                 ALOGE_IF(err != Error::NONE,
352                          "Can't clean slot %d of the client target buffer"
353                          "cache for display %" PRIu64,
354                          slot, display);
355             }
356         } else {
357             ALOGE("Can't clean client target cache for display %" PRIu64, display);
358         }
359 
360         err = resources->getDisplayOutputBufferCacheSize(display, &cacheSize);
361         if (err == Error::NONE) {
362             for (int slot = 0; slot < cacheSize; slot++) {
363                 // Replace the buffer slots with NULLs. Keep the old handle until it is
364                 // replaced in ComposerHal, otherwise we risk leaving a dangling pointer.
365                 ComposerResources::ReplacedHandle replacedBuffer(/*isBuffer*/ true);
366                 const native_handle_t* outputBuffer = nullptr;
367                 err = resources->getDisplayOutputBuffer(display, slot, /*useCache*/ true,
368                                                         /*rawHandle*/ nullptr, &outputBuffer,
369                                                         &replacedBuffer);
370                 if (err != Error::NONE) {
371                     continue;
372                 }
373                 err = hal->setOutputBuffer(display, outputBuffer, /*fence*/ -1);
374                 ALOGE_IF(err != Error::NONE,
375                          "Can't clean slot %d of the output buffer cache"
376                          "for display %" PRIu64,
377                          slot, display);
378             }
379         } else {
380             ALOGE("Can't clean output buffer cache for display %" PRIu64, display);
381         }
382     }
383 
destroyResources()384     void destroyResources() {
385         // We want to call hwc2_close here (and move hwc2_open to the
386         // constructor), with the assumption that hwc2_close would
387         //
388         //  - clean up all resources owned by the client
389         //  - make sure all displays are blank (since there is no layer)
390         //
391         // But since SF used to crash at this point, different hwcomposer2
392         // implementations behave differently on hwc2_close.  Our only portable
393         // choice really is to abort().  But that is not an option anymore
394         // because we might also have VTS or VR as clients that can come and go.
395         //
396         // Below we manually clean all resources (layers and virtual
397         // displays), and perform a presentDisplay afterwards.
398         mResources->clear([this](Display display, bool isVirtual, const std::vector<Layer> layers) {
399             ALOGW("destroying client resources for display %" PRIu64, display);
400 
401             for (auto layer : layers) {
402                 mHal->destroyLayer(display, layer);
403             }
404 
405             if (isVirtual) {
406                 mHal->destroyVirtualDisplay(display);
407             } else {
408                 ALOGW("performing a final presentDisplay");
409 
410                 std::vector<Layer> changedLayers;
411                 std::vector<IComposerClient::Composition> compositionTypes;
412                 uint32_t displayRequestMask = 0;
413                 std::vector<Layer> requestedLayers;
414                 std::vector<uint32_t> requestMasks;
415                 mHal->validateDisplay(display, &changedLayers, &compositionTypes,
416                                       &displayRequestMask, &requestedLayers, &requestMasks);
417 
418                 mHal->acceptDisplayChanges(display);
419 
420                 int32_t presentFence = -1;
421                 std::vector<Layer> releasedLayers;
422                 std::vector<int32_t> releaseFences;
423                 mHal->presentDisplay(display, &presentFence, &releasedLayers, &releaseFences);
424                 if (presentFence >= 0) {
425                     close(presentFence);
426                 }
427                 for (auto fence : releaseFences) {
428                     if (fence >= 0) {
429                         close(fence);
430                     }
431                 }
432             }
433         });
434 
435         mResources.reset();
436     }
437 
438     Hal* const mHal;
439 
440     std::unique_ptr<ComposerResources> mResources;
441 
442     std::mutex mCommandEngineMutex;
443     std::unique_ptr<ComposerCommandEngine> mCommandEngine;
444 
445     std::function<void()> mOnClientDestroyed;
446     std::unique_ptr<HalEventCallback> mHalEventCallback;
447 };
448 
449 }  // namespace detail
450 
451 using ComposerClient = detail::ComposerClientImpl<IComposerClient, ComposerHal>;
452 
453 }  // namespace hal
454 }  // namespace V2_1
455 }  // namespace composer
456 }  // namespace graphics
457 }  // namespace hardware
458 }  // namespace android
459