• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 #include "CarDisplayProxy.h"
18 
19 #include <aidlcommonsupport/NativeHandle.h>
20 #include <android-base/logging.h>
21 #include <android-base/scopeguard.h>
22 #include <gui/ISurfaceComposer.h>
23 #include <gui/SurfaceComposerClient.h>
24 #include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
25 #include <gui/view/Surface.h>
26 #include <ui/Rotation.h>
27 
28 #include <cinttypes>
29 
30 namespace {
31 
32 using ::aidl::android::frameworks::automotive::display::DisplayDesc;
33 using ::aidl::android::frameworks::automotive::display::Rotation;
34 using ::aidl::android::hardware::common::NativeHandle;
35 using ::android::SurfaceComposerClient;
36 using ::ndk::ScopedAStatus;
37 
38 // We're using the highest Z-order.
39 constexpr int32_t kSurfaceZOrder = 0x7FFFFFFF;
40 
convert(::android::ui::Rotation uiRotation)41 Rotation convert(::android::ui::Rotation uiRotation) {
42     switch (uiRotation) {
43         case ::android::ui::ROTATION_0:
44             return Rotation::ROTATION_0;
45         case ::android::ui::ROTATION_90:
46             return Rotation::ROTATION_90;
47         case ::android::ui::ROTATION_180:
48             return Rotation::ROTATION_180;
49         case ::android::ui::ROTATION_270:
50             return Rotation::ROTATION_270;
51     }
52 }
53 
54 constexpr size_t kMaxWindowSize = 256;
55 
convertHalTokenToNativeHandle(const::android::HalToken & halToken)56 native_handle_t* convertHalTokenToNativeHandle(const ::android::HalToken& halToken) {
57     // Attempts to store halToken in the ints of the native_handle_t after its
58     // size.
59     auto nhDataByteSize = halToken.size();
60     if (nhDataByteSize > kMaxWindowSize) {
61         return nullptr;
62     }
63 
64     auto numInts = ceil(nhDataByteSize / sizeof(int)) + 1;
65     native_handle_t* nh = native_handle_create(/* numFds = */ 0, numInts);
66     if (nh == nullptr) {
67         return nullptr;
68     }
69 
70     // Stores the size of the token in the first int
71     nh->data[0] = nhDataByteSize;
72     memcpy(&(nh->data[1]), halToken.data(), nhDataByteSize);
73     return nh;
74 }
75 
76 }  // namespace
77 
78 namespace aidl::android::frameworks::automotive::display::implementation {
79 
getDisplayIdList(std::vector<int64_t> * _aidl_return)80 ScopedAStatus CarDisplayProxy::getDisplayIdList(std::vector<int64_t>* _aidl_return) {
81     std::vector<::android::PhysicalDisplayId> displayIds =
82             SurfaceComposerClient::getPhysicalDisplayIds();
83     std::for_each(displayIds.begin(), displayIds.end(),
84                   [_aidl_return](const ::android::PhysicalDisplayId& id) {
85                       _aidl_return->push_back(id.value);
86                   });
87 
88     return ScopedAStatus::ok();
89 }
90 
getDisplayInfo(int64_t id,DisplayDesc * _aidl_return)91 ScopedAStatus CarDisplayProxy::getDisplayInfo(int64_t id, DisplayDesc* _aidl_return) {
92     ::android::ui::DisplayMode displayMode;
93     ::android::ui::DisplayState displayState;
94     if (!getDisplayInfoFromSurfaceComposerClient(id, &displayMode, &displayState)) {
95         LOG(ERROR) << "Invalid display id = " << id;
96         return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
97     }
98 
99     DisplayDesc desc = {
100             .width = displayMode.resolution.width,
101             .height = displayMode.resolution.height,
102             .layer = displayState.layerStack.id,
103             .orientation = convert(displayState.orientation),
104     };
105     *_aidl_return = std::move(desc);
106     return ScopedAStatus::ok();
107 }
108 
getDisplayInfoFromSurfaceComposerClient(int64_t id,::android::ui::DisplayMode * displayMode,::android::ui::DisplayState * displayState)109 ::android::sp<::android::IBinder> CarDisplayProxy::getDisplayInfoFromSurfaceComposerClient(
110         int64_t id, ::android::ui::DisplayMode* displayMode,
111         ::android::ui::DisplayState* displayState) {
112     ::android::sp<::android::IBinder> displayToken = SurfaceComposerClient::getPhysicalDisplayToken(
113             ::android::PhysicalDisplayId::fromValue(id));
114     if (!displayToken) {
115         LOG(ERROR) << "Failed to get a valid display token";
116         return nullptr;
117     }
118 
119     ::android::status_t status =
120             SurfaceComposerClient::getActiveDisplayMode(displayToken, displayMode);
121     if (status != ::android::NO_ERROR) {
122         LOG(WARNING) << "Failed to read current mode of the display " << id;
123     }
124 
125     status = SurfaceComposerClient::getDisplayState(displayToken, displayState);
126     if (status != ::android::NO_ERROR) {
127         LOG(WARNING) << "Failed to read current state of the display " << id;
128     }
129 
130     return displayToken;
131 }
132 
getHGraphicBufferProducer(int64_t id,NativeHandle * _aidl_return)133 ScopedAStatus CarDisplayProxy::getHGraphicBufferProducer(int64_t id, NativeHandle* _aidl_return) {
134     ::android::sp<::android::IBinder> displayToken;
135     ::android::sp<::android::SurfaceControl> surfaceControl;
136 
137     if (auto status = getDisplayRecord(id, &displayToken, &surfaceControl); !status.isOk()) {
138         return status;
139     }
140 
141     // SurfaceControl::getSurface() is guaranteed to be non-null.
142     auto targetSurface = surfaceControl->getSurface();
143     auto igbp = targetSurface->getIGraphicBufferProducer();
144     auto hgbp =
145             new ::android::hardware::graphics::bufferqueue::V2_0::utils::B2HGraphicBufferProducer(
146                     igbp);
147 
148     ::android::HalToken halToken;
149     if (!::android::createHalToken(hgbp, &halToken)) {
150         LOG(ERROR) << "Failed to create a hal token";
151         return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
152     }
153 
154     native_handle_t* handle = convertHalTokenToNativeHandle(halToken);
155     auto scope_guard = ::android::base::make_scope_guard([handle]() {
156         native_handle_close(handle);
157         native_handle_delete(handle);
158     });
159     if (handle == nullptr) {
160         LOG(ERROR) << "Failed to create a handle, errno = " << strerror(errno);
161         return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
162     }
163 
164     *_aidl_return = ::android::dupToAidl(handle);
165     return ScopedAStatus::ok();
166 }
167 
getSurface(int64_t id,android::view::Surface * _aidl_return)168 ScopedAStatus CarDisplayProxy::getSurface(int64_t id, android::view::Surface* _aidl_return) {
169     if (_aidl_return == nullptr) {
170         LOG(ERROR) << __FUNCTION__
171                    << " is called with an invalid aidl::android::view::Surface object.";
172         return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
173     }
174 
175     auto it = mSurfaceList.find(id);
176     if (it != mSurfaceList.end() && ::android::Surface::isValid(mSurfaceList[id])) {
177         LOG(DEBUG) << __FUNCTION__ << " reuses an existing surface for a display " << id;
178         _aidl_return->reset(mSurfaceList[id].get());
179         return ScopedAStatus::ok();
180     }
181 
182     ::android::sp<::android::IBinder> displayToken;
183     ::android::sp<::android::SurfaceControl> surfaceControl;
184     if (auto status = getDisplayRecord(id, &displayToken, &surfaceControl); !status.isOk()) {
185         return status;
186     }
187 
188     // Retrieve a Surface associated with a target display.
189     ::android::sp<::android::Surface> targetSurface = surfaceControl->getSurface();
190     if (!targetSurface || !::android::Surface::isValid(targetSurface)) {
191         LOG(ERROR) << "Created Surface is invalid, " << targetSurface.get();
192         return ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION);
193     }
194 
195     // Bookkeep a retrieved Surface object and pass it to the client as a format
196     // of ::aidl::android::view::Surface, which is alias to
197     // ::aidl::android::hardware::NativeWindow.
198     mSurfaceList.insert_or_assign(id, targetSurface);
199     _aidl_return->reset(targetSurface.get());
200     return ScopedAStatus::ok();
201 }
202 
hideWindow(int64_t id)203 ScopedAStatus CarDisplayProxy::hideWindow(int64_t id) {
204     auto it = mDisplays.find(id);
205     if (it == mDisplays.end()) {
206         LOG(DEBUG) << __FUNCTION__ << ": Invalid display id, " << id;
207         return ScopedAStatus::ok();
208     }
209 
210     auto status = SurfaceComposerClient::Transaction{}.hide(it->second.surfaceControl).apply();
211     if (status != ::android::NO_ERROR) {
212         LOG(DEBUG) << __FUNCTION__
213                    << ": Failed to hide a surface, status = " << ::android::statusToString(status);
214     }
215 
216     return ScopedAStatus::ok();
217 }
218 
showWindow(int64_t id)219 ScopedAStatus CarDisplayProxy::showWindow(int64_t id) {
220     auto it = mDisplays.find(id);
221     if (it == mDisplays.end()) {
222         LOG(ERROR) << __FUNCTION__ << ": Invalid display id, " << id;
223         return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
224     }
225 
226     const auto& displayToken = it->second.token;
227     const auto& surfaceControl = it->second.surfaceControl;
228     ::android::ui::DisplayState displayState;
229     ::android::status_t status =
230             SurfaceComposerClient::getDisplayState(displayToken, &displayState);
231     if (status != ::android::NO_ERROR) {
232         LOG(ERROR) << "Failed to read current state of the display " << id
233                    << ", status = " << ::android::statusToString(status);
234         return ScopedAStatus::fromStatus(status);
235     }
236 
237     SurfaceComposerClient::Transaction t;
238     t.setDisplayLayerStack(displayToken, displayState.layerStack);
239     t.setLayerStack(surfaceControl, displayState.layerStack);
240 
241     status = t.setLayer(surfaceControl, kSurfaceZOrder).show(surfaceControl).apply();
242     if (status != ::android::NO_ERROR) {
243         LOG(ERROR) << "Failed to set a layer";
244         return ScopedAStatus::fromStatus(status);
245     }
246 
247     return ScopedAStatus::ok();
248 }
249 
getDisplayRecord(int64_t id,::android::sp<::android::IBinder> * outDisplayToken,::android::sp<::android::SurfaceControl> * outSurfaceControl)250 ScopedAStatus CarDisplayProxy::getDisplayRecord(
251         int64_t id, ::android::sp<::android::IBinder>* outDisplayToken,
252         ::android::sp<::android::SurfaceControl>* outSurfaceControl) {
253     auto it = mDisplays.find(id);
254     if (it != mDisplays.end()) {
255         *outDisplayToken = mDisplays[id].token;
256         *outSurfaceControl = mDisplays[id].surfaceControl;
257         return ScopedAStatus::ok();
258     }
259 
260     ::android::sp<::android::IBinder> displayToken;
261     ::android::sp<::android::SurfaceControl> surfaceControl;
262     ::android::ui::DisplayMode displayMode;
263     ::android::ui::DisplayState displayState;
264     displayToken = getDisplayInfoFromSurfaceComposerClient(id, &displayMode, &displayState);
265     if (!displayToken) {
266         LOG(ERROR) << "Failed to read display information from SurfaceComposerClient.";
267         return ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION);
268     }
269 
270     auto displayWidth = displayMode.resolution.getWidth();
271     auto displayHeight = displayMode.resolution.getHeight();
272     if ((displayState.orientation != ::android::ui::ROTATION_0) &&
273         (displayState.orientation != ::android::ui::ROTATION_180)) {
274         std::swap(displayWidth, displayHeight);
275     }
276 
277     ::android::sp<SurfaceComposerClient> client = new SurfaceComposerClient();
278     ::android::status_t status = client->initCheck();
279     if (status != ::android::NO_ERROR) {
280         LOG(ERROR) << "SurfaceComposerClient::initCheck() fails, error = "
281                    << ::android::statusToString(status);
282         return ScopedAStatus::fromStatus(status);
283     }
284 
285     surfaceControl =
286             client->createSurface(::android::String8::format("CarDisplayProxy::%" PRIx64, id),
287                                   displayWidth, displayHeight, ::android::PIXEL_FORMAT_RGBX_8888,
288                                   ::android::ISurfaceComposerClient::eOpaque);
289     if (!surfaceControl || !surfaceControl->isValid()) {
290         LOG(ERROR) << "Failed to create a SurfaceControl";
291         return ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION);
292     }
293 
294     *outDisplayToken = displayToken;
295     *outSurfaceControl = surfaceControl;
296 
297     DisplayRecord rec = {displayToken, surfaceControl};
298     mDisplays.insert_or_assign(id, std::move(rec));
299 
300     return ScopedAStatus::ok();
301 }
302 
303 }  // namespace aidl::android::frameworks::automotive::display::implementation
304