1 /*
2 * Copyright (C) 2011 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 #define LOG_TAG "WindowInfo"
18 #define LOG_NDEBUG 0
19
20 #include <type_traits>
21
22 #include <binder/Parcel.h>
23 #include <gui/WindowInfo.h>
24
25 #include <log/log.h>
26
27 namespace android::gui {
28
29 namespace {
30
operator <<(std::ostream & out,const sp<IBinder> & binder)31 std::ostream& operator<<(std::ostream& out, const sp<IBinder>& binder) {
32 if (binder == nullptr) {
33 out << "<null>";
34 } else {
35 out << binder.get();
36 }
37 return out;
38 }
39
operator <<(std::ostream & out,const Region & region)40 std::ostream& operator<<(std::ostream& out, const Region& region) {
41 if (region.isEmpty()) {
42 out << "<empty>";
43 return out;
44 }
45
46 bool first = true;
47 Region::const_iterator cur = region.begin();
48 Region::const_iterator const tail = region.end();
49 while (cur != tail) {
50 if (first) {
51 first = false;
52 } else {
53 out << "|";
54 }
55 out << "[" << cur->left << "," << cur->top << "][" << cur->right << "," << cur->bottom
56 << "]";
57 cur++;
58 }
59 return out;
60 }
61
writeTransform(android::Parcel * parcel,const ui::Transform & transform)62 status_t writeTransform(android::Parcel* parcel, const ui::Transform& transform) {
63 return parcel->writeFloat(transform.dsdx()) ?:
64 parcel->writeFloat(transform.dtdx()) ?:
65 parcel->writeFloat(transform.tx()) ?:
66 parcel->writeFloat(transform.dtdy()) ?:
67 parcel->writeFloat(transform.dsdy()) ?:
68 parcel->writeFloat(transform.ty());
69 }
70
readTransform(const android::Parcel * parcel,ui::Transform & transform)71 status_t readTransform(const android::Parcel* parcel, ui::Transform& transform) {
72 float dsdx, dtdx, tx, dtdy, dsdy, ty;
73
74 const status_t status = parcel->readFloat(&dsdx) ?:
75 parcel->readFloat(&dtdx) ?:
76 parcel->readFloat(&tx) ?:
77 parcel->readFloat(&dtdy) ?:
78 parcel->readFloat(&dsdy) ?:
79 parcel->readFloat(&ty);
80 if (status != OK) {
81 return status;
82 }
83
84 transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1});
85 return OK;
86 }
87
88 } // namespace
89
setInputConfig(ftl::Flags<InputConfig> config,bool value)90 void WindowInfo::setInputConfig(ftl::Flags<InputConfig> config, bool value) {
91 if (value) {
92 inputConfig |= config;
93 return;
94 }
95 inputConfig &= ~config;
96 }
97
addTouchableRegion(const Rect & region)98 void WindowInfo::addTouchableRegion(const Rect& region) {
99 touchableRegion.orSelf(region);
100 }
101
isSpy() const102 bool WindowInfo::isSpy() const {
103 return inputConfig.test(InputConfig::SPY);
104 }
105
interceptsStylus() const106 bool WindowInfo::interceptsStylus() const {
107 return inputConfig.test(InputConfig::INTERCEPTS_STYLUS);
108 }
109
overlaps(const WindowInfo * other) const110 bool WindowInfo::overlaps(const WindowInfo* other) const {
111 return !frame.isEmpty() && frame.left < other->frame.right && frame.right > other->frame.left &&
112 frame.top < other->frame.bottom && frame.bottom > other->frame.top;
113 }
114
operator ==(const WindowInfo & info) const115 bool WindowInfo::operator==(const WindowInfo& info) const {
116 return info.token == token && info.id == id && info.name == name &&
117 info.dispatchingTimeout == dispatchingTimeout && info.frame == frame &&
118 info.contentSize == contentSize && info.surfaceInset == surfaceInset &&
119 info.globalScaleFactor == globalScaleFactor && info.transform == transform &&
120 info.touchableRegion.hasSameRects(touchableRegion) &&
121 info.touchOcclusionMode == touchOcclusionMode && info.ownerPid == ownerPid &&
122 info.ownerUid == ownerUid && info.packageName == packageName &&
123 info.inputConfig == inputConfig && info.displayId == displayId &&
124 info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
125 info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType &&
126 info.layoutParamsFlags == layoutParamsFlags &&
127 info.canOccludePresentation == canOccludePresentation;
128 }
129
writeToParcel(android::Parcel * parcel) const130 status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
131 if (parcel == nullptr) {
132 ALOGE("%s: Null parcel", __func__);
133 return BAD_VALUE;
134 }
135 if (name.empty()) {
136 parcel->writeInt32(0);
137 return OK;
138 }
139 parcel->writeInt32(1);
140
141 // Ensure that the size of custom types are what we expect for writing into the parcel.
142 static_assert(sizeof(inputConfig) == 4u);
143 static_assert(sizeof(ownerPid.val()) == 4u);
144 static_assert(sizeof(ownerUid.val()) == 4u);
145
146 // clang-format off
147 status_t status = parcel->writeStrongBinder(token) ?:
148 parcel->writeInt64(dispatchingTimeout.count()) ?:
149 parcel->writeInt32(id) ?:
150 parcel->writeUtf8AsUtf16(name) ?:
151 parcel->writeInt32(layoutParamsFlags.get()) ?:
152 parcel->writeInt32(
153 static_cast<std::underlying_type_t<WindowInfo::Type>>(layoutParamsType)) ?:
154 parcel->write(frame) ?:
155 parcel->writeInt32(contentSize.width) ?:
156 parcel->writeInt32(contentSize.height) ?:
157 parcel->writeInt32(surfaceInset) ?:
158 parcel->writeFloat(globalScaleFactor) ?:
159 parcel->writeFloat(alpha) ?:
160 writeTransform(parcel, transform) ?:
161 parcel->writeInt32(static_cast<int32_t>(touchOcclusionMode)) ?:
162 parcel->writeInt32(ownerPid.val()) ?:
163 parcel->writeInt32(ownerUid.val()) ?:
164 parcel->writeUtf8AsUtf16(packageName) ?:
165 parcel->writeInt32(inputConfig.get()) ?:
166 parcel->writeInt32(displayId.val()) ?:
167 applicationInfo.writeToParcel(parcel) ?:
168 parcel->write(touchableRegion) ?:
169 parcel->writeBool(replaceTouchableRegionWithCrop) ?:
170 parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?:
171 parcel->writeStrongBinder(windowToken) ?:
172 parcel->writeStrongBinder(focusTransferTarget) ?:
173 parcel->writeBool(canOccludePresentation) ?:
174 parcel->writeBool(cloneLayerStackTransform.has_value());
175 // clang-format on
176 if (cloneLayerStackTransform) {
177 status = status ?: writeTransform(parcel, *cloneLayerStackTransform);
178 }
179 return status;
180 }
181
readFromParcel(const android::Parcel * parcel)182 status_t WindowInfo::readFromParcel(const android::Parcel* parcel) {
183 if (parcel == nullptr) {
184 ALOGE("%s: Null parcel", __func__);
185 return BAD_VALUE;
186 }
187 if (parcel->readInt32() == 0) {
188 return OK;
189 }
190
191 token = parcel->readStrongBinder();
192 dispatchingTimeout = static_cast<decltype(dispatchingTimeout)>(parcel->readInt64());
193 status_t status = parcel->readInt32(&id) ?: parcel->readUtf8FromUtf16(&name);
194 if (status != OK) {
195 return status;
196 }
197
198 int32_t lpFlags, lpType, touchOcclusionModeInt, inputConfigInt, ownerPidInt, ownerUidInt,
199 displayIdInt;
200 sp<IBinder> touchableRegionCropHandleSp;
201 bool hasCloneLayerStackTransform = false;
202
203 // clang-format off
204 status = parcel->readInt32(&lpFlags) ?:
205 parcel->readInt32(&lpType) ?:
206 parcel->read(frame) ?:
207 parcel->readInt32(&contentSize.width) ?:
208 parcel->readInt32(&contentSize.height) ?:
209 parcel->readInt32(&surfaceInset) ?:
210 parcel->readFloat(&globalScaleFactor) ?:
211 parcel->readFloat(&alpha) ?:
212 readTransform(parcel, /*byRef*/ transform) ?:
213 parcel->readInt32(&touchOcclusionModeInt) ?:
214 parcel->readInt32(&ownerPidInt) ?:
215 parcel->readInt32(&ownerUidInt) ?:
216 parcel->readUtf8FromUtf16(&packageName) ?:
217 parcel->readInt32(&inputConfigInt) ?:
218 parcel->readInt32(&displayIdInt) ?:
219 applicationInfo.readFromParcel(parcel) ?:
220 parcel->read(touchableRegion) ?:
221 parcel->readBool(&replaceTouchableRegionWithCrop) ?:
222 parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?:
223 parcel->readNullableStrongBinder(&windowToken) ?:
224 parcel->readNullableStrongBinder(&focusTransferTarget) ?:
225 parcel->readBool(&canOccludePresentation)?:
226 parcel->readBool(&hasCloneLayerStackTransform);
227 // clang-format on
228
229 if (status != OK) {
230 return status;
231 }
232
233 layoutParamsFlags = ftl::Flags<Flag>(lpFlags);
234 layoutParamsType = static_cast<Type>(lpType);
235 touchOcclusionMode = static_cast<TouchOcclusionMode>(touchOcclusionModeInt);
236 inputConfig = ftl::Flags<InputConfig>(inputConfigInt);
237 ownerPid = Pid{ownerPidInt};
238 ownerUid = Uid{static_cast<uid_t>(ownerUidInt)};
239 touchableRegionCropHandle = touchableRegionCropHandleSp;
240 displayId = ui::LogicalDisplayId{displayIdInt};
241
242 cloneLayerStackTransform =
243 hasCloneLayerStackTransform ? std::make_optional<ui::Transform>() : std::nullopt;
244 if (cloneLayerStackTransform) {
245 status = readTransform(parcel, /*byRef*/ *cloneLayerStackTransform);
246 if (status != OK) {
247 return status;
248 }
249 }
250
251 return OK;
252 }
253
WindowInfoHandle()254 WindowInfoHandle::WindowInfoHandle() {}
255
~WindowInfoHandle()256 WindowInfoHandle::~WindowInfoHandle() {}
257
WindowInfoHandle(const WindowInfoHandle & other)258 WindowInfoHandle::WindowInfoHandle(const WindowInfoHandle& other) : mInfo(other.mInfo) {}
259
WindowInfoHandle(const WindowInfo & other)260 WindowInfoHandle::WindowInfoHandle(const WindowInfo& other) : mInfo(other) {}
261
writeToParcel(android::Parcel * parcel) const262 status_t WindowInfoHandle::writeToParcel(android::Parcel* parcel) const {
263 return mInfo.writeToParcel(parcel);
264 }
265
readFromParcel(const android::Parcel * parcel)266 status_t WindowInfoHandle::readFromParcel(const android::Parcel* parcel) {
267 return mInfo.readFromParcel(parcel);
268 }
269
releaseChannel()270 void WindowInfoHandle::releaseChannel() {
271 mInfo.token.clear();
272 }
273
getToken() const274 sp<IBinder> WindowInfoHandle::getToken() const {
275 return mInfo.token;
276 }
277
updateFrom(sp<WindowInfoHandle> handle)278 void WindowInfoHandle::updateFrom(sp<WindowInfoHandle> handle) {
279 mInfo = handle->mInfo;
280 }
281
operator <<(std::ostream & out,const WindowInfo & info)282 std::ostream& operator<<(std::ostream& out, const WindowInfo& info) {
283 out << "name=" << info.name << ", id=" << info.id << ", displayId=" << info.displayId
284 << ", inputConfig=" << info.inputConfig.string() << ", alpha=" << info.alpha << ", frame=["
285 << info.frame.left << "," << info.frame.top << "][" << info.frame.right << ","
286 << info.frame.bottom << "], globalScale=" << info.globalScaleFactor
287 << ", applicationInfo.name=" << info.applicationInfo.name
288 << ", applicationInfo.token=" << info.applicationInfo.token
289 << ", touchableRegion=" << info.touchableRegion << ", ownerPid=" << info.ownerPid.toString()
290 << ", ownerUid=" << info.ownerUid.toString() << ", dispatchingTimeout="
291 << std::chrono::duration_cast<std::chrono::milliseconds>(info.dispatchingTimeout).count()
292 << "ms, token=" << info.token.get()
293 << ", touchOcclusionMode=" << ftl::enum_string(info.touchOcclusionMode);
294 if (info.canOccludePresentation) out << ", canOccludePresentation";
295 std::string transform;
296 info.transform.dump(transform, "transform", " ");
297 out << "\n" << transform;
298 return out;
299 }
300
operator <<(std::ostream & out,const WindowInfoHandle & window)301 std::ostream& operator<<(std::ostream& out, const WindowInfoHandle& window) {
302 const WindowInfo& info = *window.getInfo();
303 out << info;
304 return out;
305 }
306
307 } // namespace android::gui
308