diff options
45 files changed, 1007 insertions, 91 deletions
diff --git a/build/phone-xxhdpi-3072-dalvik-heap.mk b/build/phone-xxhdpi-3072-dalvik-heap.mk new file mode 100644 index 0000000..3598f5a --- /dev/null +++ b/build/phone-xxhdpi-3072-dalvik-heap.mk @@ -0,0 +1,25 @@ +# +# Copyright (C) 2016 The CyanogenMod Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Provides overrides to configure the Dalvik heap for a 3G phone + +PRODUCT_PROPERTY_OVERRIDES += \ + dalvik.vm.heapstartsize=8m \ + dalvik.vm.heapgrowthlimit=288m \ + dalvik.vm.heapsize=768m \ + dalvik.vm.heaptargetutilization=0.75 \ + dalvik.vm.heapminfree=512k \ + dalvik.vm.heapmaxfree=8m diff --git a/build/phone-xxhdpi-3072-hwui-memory.mk b/build/phone-xxhdpi-3072-hwui-memory.mk new file mode 100644 index 0000000..217bfb8 --- /dev/null +++ b/build/phone-xxhdpi-3072-hwui-memory.mk @@ -0,0 +1,30 @@ +# +# Copyright (C) 2016 The CyanogenMod Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Provides overrides to configure the HWUI memory limits + +PRODUCT_PROPERTY_OVERRIDES += \ + ro.hwui.texture_cache_size=72 \ + ro.hwui.layer_cache_size=48 \ + ro.hwui.path_cache_size=32 \ + ro.hwui.gradient_cache_size=1 \ + ro.hwui.drop_shadow_cache_size=6 \ + ro.hwui.r_buffer_cache_size=8 \ + ro.hwui.texture_cache_flushrate=0.4 \ + ro.hwui.text_small_cache_width=1024 \ + ro.hwui.text_small_cache_height=1024 \ + ro.hwui.text_large_cache_width=2048 \ + ro.hwui.text_large_cache_height=1024 diff --git a/build/phone-xxxhdpi-3072-dalvik-heap.mk b/build/phone-xxxhdpi-3072-dalvik-heap.mk index 3bf65a7..56a10dd 100644 --- a/build/phone-xxxhdpi-3072-dalvik-heap.mk +++ b/build/phone-xxxhdpi-3072-dalvik-heap.mk @@ -18,8 +18,8 @@ PRODUCT_PROPERTY_OVERRIDES += \ dalvik.vm.heapstartsize=8m \ - dalvik.vm.heapgrowthlimit=256m \ - dalvik.vm.heapsize=512m \ + dalvik.vm.heapgrowthlimit=288m \ + dalvik.vm.heapsize=768m \ dalvik.vm.heaptargetutilization=0.75 \ dalvik.vm.heapminfree=2m \ dalvik.vm.heapmaxfree=8m diff --git a/build/phone-xxxhdpi-4096-dalvik-heap.mk b/build/phone-xxxhdpi-4096-dalvik-heap.mk new file mode 100644 index 0000000..0e12557 --- /dev/null +++ b/build/phone-xxxhdpi-4096-dalvik-heap.mk @@ -0,0 +1,25 @@ +# +# Copyright (C) 2016 The CyanogenMod Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Provides overrides to configure the Dalvik heap for a 4G phone + +PRODUCT_PROPERTY_OVERRIDES += \ + dalvik.vm.heapstartsize=8m \ + dalvik.vm.heapgrowthlimit=384m \ + dalvik.vm.heapsize=1024m \ + dalvik.vm.heaptargetutilization=0.75 \ + dalvik.vm.heapminfree=4m \ + dalvik.vm.heapmaxfree=16m diff --git a/build/phone-xxxhdpi-4096-hwui-memory.mk b/build/phone-xxxhdpi-4096-hwui-memory.mk new file mode 100644 index 0000000..98cef64 --- /dev/null +++ b/build/phone-xxxhdpi-4096-hwui-memory.mk @@ -0,0 +1,30 @@ +# +# Copyright (C) 2015 The CyanogenMod Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Provides overrides to configure the HWUI memory limits + +PRODUCT_PROPERTY_OVERRIDES += \ + ro.hwui.texture_cache_size=72 \ + ro.hwui.layer_cache_size=48 \ + ro.hwui.r_buffer_cache_size=8 \ + ro.hwui.path_cache_size=32 \ + ro.hwui.gradient_cache_size=1 \ + ro.hwui.drop_shadow_cache_size=6 \ + ro.hwui.texture_cache_flushrate=0.4 \ + ro.hwui.text_small_cache_width=1024 \ + ro.hwui.text_small_cache_height=1024 \ + ro.hwui.text_large_cache_width=2048 \ + ro.hwui.text_large_cache_height=1024 diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index a2e4f4b..475f7e3 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -272,7 +272,9 @@ static void dumpstate() { char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX]; char network[PROPERTY_VALUE_MAX], date[80]; char build_type[PROPERTY_VALUE_MAX]; + char cm_version[PROPERTY_VALUE_MAX]; + property_get("ro.cm.version", cm_version, "(unknown)"); property_get("ro.build.display.id", build, "(unknown)"); property_get("ro.build.fingerprint", fingerprint, "(unknown)"); property_get("ro.build.type", build_type, "(unknown)"); @@ -286,6 +288,7 @@ static void dumpstate() { printf("========================================================\n"); printf("\n"); + printf("CM Version: %s\n", cm_version); printf("Build: %s\n", build); printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */ printf("Bootloader: %s\n", bootloader); @@ -302,7 +305,7 @@ static void dumpstate() { dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd); dump_file("MEMORY INFO", "/proc/meminfo"); run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL); - run_command("PROCRANK", 20, "procrank", NULL); + run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL); dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat"); dump_file("VMALLOC INFO", "/proc/vmallocinfo"); dump_file("SLAB INFO", "/proc/slabinfo"); diff --git a/cmds/servicemanager/Android.mk b/cmds/servicemanager/Android.mk index 155cfc5..5bafd53 100644 --- a/cmds/servicemanager/Android.mk +++ b/cmds/servicemanager/Android.mk @@ -18,7 +18,7 @@ LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) -LOCAL_SHARED_LIBRARIES := liblog libselinux +LOCAL_SHARED_LIBRARIES := liblog libcutils libselinux LOCAL_SRC_FILES := service_manager.c binder.c LOCAL_CFLAGS += $(svc_c_flags) LOCAL_MODULE := servicemanager diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c index 7fa9a39..031f848 100644 --- a/cmds/servicemanager/service_manager.c +++ b/cmds/servicemanager/service_manager.c @@ -8,6 +8,8 @@ #include <stdlib.h> #include <string.h> +#include <cutils/multiuser.h> + #include <private/android_filesystem_config.h> #include <selinux/android.h> @@ -107,9 +109,14 @@ static bool check_mac_perms_from_lookup(pid_t spid, const char *perm, const char return allowed; } -static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid) +static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid) { const char *perm = "add"; + + if (multiuser_get_app_id(uid) >= AID_APP) { + return 0; /* Don't allow apps to register services */ + } + return check_mac_perms_from_lookup(spid, perm, str8(name, name_len)) ? 1 : 0; } @@ -204,7 +211,7 @@ int do_add_service(struct binder_state *bs, if (!handle || (len == 0) || (len > 127)) return -1; - if (!svc_can_register(s, len, spid)) { + if (!svc_can_register(s, len, spid, uid)) { ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", str8(s, len), handle, uid); return -1; diff --git a/include/input/Input.h b/include/input/Input.h index 617175b..82fc659 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -45,6 +45,19 @@ enum { }; enum { + + /** + * This flag indicates that the window that received this motion event is partly + * or wholly obscured by another visible window above it. This flag is set to true + * even if the event did not directly pass through the obscured area. + * A security sensitive application can check this flag to identify situations in which + * a malicious application may have covered up part of its content for the purpose + * of misleading the user or hijacking touches. An appropriate response might be + * to drop the suspect touches or to take additional precautions to confirm the user's + * actual intent. + */ + AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 0x2, + /* Motion event is inconsistent with previously sent motion events. */ AMOTION_EVENT_FLAG_TAINTED = 0x80000000, }; diff --git a/include/ui/FrameStats.h b/include/ui/FrameStats.h index 5fdf94d..6bfe635 100644 --- a/include/ui/FrameStats.h +++ b/include/ui/FrameStats.h @@ -25,6 +25,7 @@ namespace android { class FrameStats : public LightFlattenable<FrameStats> { public: + FrameStats() : refreshPeriodNano(0) {}; /* * Approximate refresh time, in nanoseconds. diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp index 3f2198a..f59867a 100644 --- a/libs/binder/IMemory.cpp +++ b/libs/binder/IMemory.cpp @@ -26,6 +26,7 @@ #include <sys/mman.h> #include <binder/IMemory.h> +#include <cutils/log.h> #include <utils/KeyedVector.h> #include <utils/threads.h> #include <utils/Atomic.h> @@ -191,15 +192,26 @@ sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const if (heap != 0) { mHeap = interface_cast<IMemoryHeap>(heap); if (mHeap != 0) { - mOffset = o; - mSize = s; + size_t heapSize = mHeap->getSize(); + if (s <= heapSize + && o >= 0 + && (static_cast<size_t>(o) <= heapSize - s)) { + mOffset = o; + mSize = s; + } else { + // Hm. + android_errorWriteWithInfoLog(0x534e4554, + "26877992", -1, NULL, 0); + mOffset = 0; + mSize = 0; + } } } } } if (offset) *offset = mOffset; if (size) *size = mSize; - return mHeap; + return (mSize > 0) ? mHeap : 0; } // --------------------------------------------------------------------------- diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index ef88181..af18e11 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -1083,8 +1083,16 @@ status_t IPCThreadState::executeCommand(int32_t cmd) << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl; } if (tr.target.ptr) { - sp<BBinder> b((BBinder*)tr.cookie); - error = b->transact(tr.code, buffer, &reply, tr.flags); + // We only have a weak reference on the target object, so we must first try to + // safely acquire a strong reference before doing anything else with it. + if (reinterpret_cast<RefBase::weakref_type*>( + tr.target.ptr)->attemptIncStrong(this)) { + error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer, + &reply, tr.flags); + reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this); + } else { + error = UNKNOWN_TRANSACTION; + } } else { error = the_context_object->transact(tr.code, buffer, &reply, tr.flags); diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 4f539a8..65e67d6 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -18,6 +18,8 @@ //#define LOG_NDEBUG 0 #include <binder/Parcel.h> +#include <fcntl.h> +#include <pthread.h> #include <binder/IPCThreadState.h> #include <binder/Binder.h> @@ -42,6 +44,9 @@ #include <stdlib.h> #include <stdint.h> #include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> #ifndef INT32_MAX #define INT32_MAX ((int32_t)(2147483647)) @@ -95,6 +100,32 @@ enum { BLOB_ASHMEM_MUTABLE = 2, }; +static dev_t ashmem_rdev() +{ + static dev_t __ashmem_rdev; + static pthread_mutex_t __ashmem_rdev_lock = PTHREAD_MUTEX_INITIALIZER; + + pthread_mutex_lock(&__ashmem_rdev_lock); + + dev_t rdev = __ashmem_rdev; + if (!rdev) { + int fd = TEMP_FAILURE_RETRY(open("/dev/ashmem", O_RDONLY)); + if (fd >= 0) { + struct stat st; + + int ret = TEMP_FAILURE_RETRY(fstat(fd, &st)); + close(fd); + if ((ret >= 0) && S_ISCHR(st.st_mode)) { + rdev = __ashmem_rdev = st.st_rdev; + } + } + } + + pthread_mutex_unlock(&__ashmem_rdev_lock); + + return rdev; +} + void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj, const void* who, size_t* outAshmemSize) { @@ -123,8 +154,10 @@ void acquire_object(const sp<ProcessState>& proc, return; } case BINDER_TYPE_FD: { - if (obj.cookie != 0) { - if (outAshmemSize != NULL) { + if ((obj.cookie != 0) && (outAshmemSize != NULL)) { + struct stat st; + int ret = fstat(obj.handle, &st); + if (!ret && S_ISCHR(st.st_mode) && (st.st_rdev == ashmem_rdev())) { // If we own an ashmem fd, keep track of how much memory it refers to. int size = ashmem_get_size_region(obj.handle); if (size > 0) { @@ -173,15 +206,18 @@ static void release_object(const sp<ProcessState>& proc, return; } case BINDER_TYPE_FD: { - if (outAshmemSize != NULL) { - if (obj.cookie != 0) { - int size = ashmem_get_size_region(obj.handle); - if (size > 0) { - *outAshmemSize -= size; + if (obj.cookie != 0) { // owned + if (outAshmemSize != NULL) { + struct stat st; + int ret = fstat(obj.handle, &st); + if (!ret && S_ISCHR(st.st_mode) && (st.st_rdev == ashmem_rdev())) { + int size = ashmem_get_size_region(obj.handle); + if (size > 0) { + *outAshmemSize -= size; + } } - - close(obj.handle); } + close(obj.handle); #ifdef DISABLE_ASHMEM_TRACKING } else if (obj.cookie != 0) { close(obj.handle); @@ -1389,7 +1425,13 @@ native_handle* Parcel::readNativeHandle() const for (int i=0 ; err==NO_ERROR && i<numFds ; i++) { h->data[i] = dup(readFileDescriptor()); - if (h->data[i] < 0) err = BAD_VALUE; + if (h->data[i] < 0) { + for (int j = 0; j < i; j++) { + close(h->data[j]); + } + native_handle_delete(h); + return 0; + } } err = read(h->data + numFds, sizeof(int)*numInts); if (err != NO_ERROR) { diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index bb3e1b0..7504ed4 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -26,6 +26,10 @@ #include <gui/IConsumerListener.h> #include <gui/IProducerListener.h> +#include <binder/IPCThreadState.h> +#include <binder/PermissionCache.h> +#include <private/android_filesystem_config.h> + namespace android { BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) : @@ -572,7 +576,18 @@ sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const { } void BufferQueueConsumer::dump(String8& result, const char* prefix) const { - mCore->dump(result, prefix); + const IPCThreadState* ipc = IPCThreadState::self(); + const pid_t pid = ipc->getCallingPid(); + const uid_t uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) + && !PermissionCache::checkPermission(String16( + "android.permission.DUMP"), pid, uid)) { + result.appendFormat("Permission Denial: can't dump BufferQueueConsumer " + "from pid=%d, uid=%d\n", pid, uid); + android_errorWriteWithInfoLog(0x534e4554, "27046057", uid, NULL, 0); + } else { + mCore->dump(result, prefix); + } } } // namespace android diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index c4660ba..7ae82e0 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -349,7 +349,7 @@ status_t BnGraphicBufferConsumer::onTransact( } case GET_RELEASED_BUFFERS: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - uint64_t slotMask; + uint64_t slotMask = 0; status_t result = getReleasedBuffers(&slotMask); reply->writeInt64(static_cast<int64_t>(slotMask)); reply->writeInt32(result); diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 1099c84..c3c6235 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -435,6 +435,7 @@ status_t BnGraphicBufferProducer::onTransact( QueueBufferOutput* const output = reinterpret_cast<QueueBufferOutput *>( reply->writeInplace(sizeof(QueueBufferOutput))); + memset(output, 0, sizeof(QueueBufferOutput)); status_t res = connect(listener, api, producerControlledByApp, output); reply->writeInt32(res); return NO_ERROR; diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index 3810da4..cfed7a9 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -795,6 +795,11 @@ status_t Region::unflatten(void const* buffer, size_t size) { return NO_MEMORY; } + if (numRects > (UINT32_MAX / sizeof(Rect))) { + android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, NULL, 0); + return NO_MEMORY; + } + Region result; result.mStorage.clear(); for (size_t r = 0; r < numRects; ++r) { diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk index e952a38..870c2bd 100644 --- a/opengl/libs/Android.mk +++ b/opengl/libs/Android.mk @@ -65,6 +65,10 @@ ifneq ($(MAX_EGL_CACHE_SIZE),) LOCAL_CFLAGS += -DMAX_EGL_CACHE_SIZE=$(MAX_EGL_CACHE_SIZE) endif +ifeq ($(BOARD_USE_BGRA_8888), true) + LOCAL_CFLAGS += -DUSE_BGRA_8888 +endif + LOCAL_REQUIRED_MODULES := $(egl.cfg_config_module) egl.cfg_config_module := diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 0fba1bf..c9e876f 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -1225,6 +1225,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE; if (isWindowObscuredAtPointLocked(windowHandle, x, y)) { outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; + } else if (isWindowObscuredLocked(windowHandle)) { + outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED; } mTempTouchState.addOrUpdateWindow( @@ -1262,6 +1264,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; + } else if (isWindowObscuredLocked(newTouchedWindowHandle)) { + targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED; } // Update hover state. @@ -1437,6 +1441,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, == InputWindowInfo::TYPE_WALLPAPER) { mTempTouchState.addOrUpdateWindow(windowHandle, InputTarget::FLAG_WINDOW_IS_OBSCURED + | InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0)); } @@ -1631,6 +1636,27 @@ bool InputDispatcher::isWindowObscuredAtPointLocked( return false; } + +bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const { + int32_t displayId = windowHandle->getInfo()->displayId; + const InputWindowInfo* windowInfo = windowHandle->getInfo(); + size_t numWindows = mWindowHandles.size(); + for (size_t i = 0; i < numWindows; i++) { + sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i); + if (otherHandle == windowHandle) { + break; + } + + const InputWindowInfo* otherInfo = otherHandle->getInfo(); + if (otherInfo->displayId == displayId + && otherInfo->visible && !otherInfo->isTrustedOverlay() + && otherInfo->overlaps(windowInfo)) { + return true; + } + } + return false; +} + String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime, const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry, const char* targetType) { @@ -1905,6 +1931,9 @@ void InputDispatcher::enqueueDispatchEntryLocked( if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; } + if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) { + dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + } if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 98355c6..1c054f5 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -89,7 +89,7 @@ struct InputTarget { /* This flag indicates that the event is being delivered to a foreground application. */ FLAG_FOREGROUND = 1 << 0, - /* This flag indicates that the target of a MotionEvent is partly or wholly + /* This flag indicates that the MotionEvent falls within the area of the target * obscured by another visible window above it. The motion event should be * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ FLAG_WINDOW_IS_OBSCURED = 1 << 1, @@ -139,6 +139,12 @@ struct InputTarget { | FLAG_DISPATCH_AS_HOVER_EXIT | FLAG_DISPATCH_AS_SLIPPERY_EXIT | FLAG_DISPATCH_AS_SLIPPERY_ENTER, + + /* This flag indicates that the target of a MotionEvent is partly or wholly + * obscured by another visible window above it. The motion event should be + * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */ + FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14, + }; // The input channel to be targeted. @@ -1048,6 +1054,7 @@ private: const InjectionState* injectionState); bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const; + bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const; String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle, const sp<InputWindowHandle>& windowHandle); diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index 53ff155..6cfdceb 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -6167,7 +6167,8 @@ nsecs_t TouchInputMapper::mLastStylusTime = 0; bool TouchInputMapper::rejectPalm(nsecs_t when) { return (when - mLastStylusTime < mConfig.stylusPalmRejectionTime) && - mPointerSimple.currentProperties.toolType != AMOTION_EVENT_TOOL_TYPE_STYLUS; + mPointerSimple.currentProperties.toolType != AMOTION_EVENT_TOOL_TYPE_STYLUS && + mPointerSimple.currentProperties.toolType != AMOTION_EVENT_TOOL_TYPE_ERASER; } void TouchInputMapper::cancelTouch(nsecs_t when) { diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp index fda3ffa..1b913c5 100644 --- a/services/inputflinger/InputWindow.cpp +++ b/services/inputflinger/InputWindow.cpp @@ -36,14 +36,16 @@ bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { } bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { - return x >= frameLeft && x <= frameRight - && y >= frameTop && y <= frameBottom; + return x >= frameLeft && x < frameRight + && y >= frameTop && y < frameBottom; } bool InputWindowInfo::isTrustedOverlay() const { return layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY + || layoutParamsType == TYPE_STATUS_BAR + || layoutParamsType == TYPE_NAVIGATION_BAR || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; } @@ -51,6 +53,11 @@ bool InputWindowInfo::supportsSplitTouch() const { return layoutParamsFlags & FLAG_SPLIT_TOUCH; } +bool InputWindowInfo::overlaps(const InputWindowInfo* other) const { + return frameLeft < other->frameRight && frameRight > other->frameLeft + && frameTop < other->frameBottom && frameBottom > other->frameTop; +} + // --- InputWindowHandle --- diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h index 42457ce..0ac7fce 100644 --- a/services/inputflinger/InputWindow.h +++ b/services/inputflinger/InputWindow.h @@ -146,6 +146,8 @@ struct InputWindowInfo { bool isTrustedOverlay() const; bool supportsSplitTouch() const; + + bool overlaps(const InputWindowInfo* other) const; }; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 28af943..3d9dcd0 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -359,6 +359,8 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) result.appendFormat("non-wakeUp | "); } + result.appendFormat("%.4f mA | ", s.getPowerUsage()); + int bufIndex = mLastEventSeen.indexOfKey(s.getHandle()); if (bufIndex >= 0) { const CircularBuffer* buf = mLastEventSeen.valueAt(bufIndex); @@ -1118,7 +1120,7 @@ bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation, AppOpsManager appOps; if (appOps.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName) != AppOpsManager::MODE_ALLOWED) { - ALOGE("%s a sensor (%s) without enabled required app op: %D", + ALOGE("%s a sensor (%s) without enabled required app op: %d", operation, sensor.getName().string(), opCode); return false; } diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index c1ddba1..25fa503 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -95,6 +95,10 @@ else LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=0 endif +ifeq ($(BOARD_USE_BGRA_8888),true) + LOCAL_CFLAGS += -DUSE_BGRA_8888 +endif + LOCAL_CFLAGS += -fvisibility=hidden -Werror=format LOCAL_CFLAGS += -std=c++11 @@ -116,7 +120,11 @@ ifeq ($(TARGET_USES_QCOM_BSP), true) LOCAL_C_INCLUDES += $(call project-path-for,qcom-display)/libgralloc LOCAL_C_INCLUDES += $(call project-path-for,qcom-display)/libqdutils LOCAL_SHARED_LIBRARIES += libqdutils + LOCAL_SHARED_LIBRARIES += libqdMetaData LOCAL_CFLAGS += -DQTI_BSP + ifeq ($(call is-board-platform-in-list,msm8996),true) + LOCAL_CFLAGS += -DSDM_TARGET + endif LOCAL_SRC_FILES += \ ExSurfaceFlinger/ExLayer.cpp \ ExSurfaceFlinger/ExSurfaceFlinger.cpp \ @@ -124,10 +132,22 @@ ifeq ($(TARGET_USES_QCOM_BSP), true) ExSurfaceFlinger/ExHWComposer.cpp endif -ifeq ($(TARGET_HAVE_UI_BLUR),true) - LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/ui - LOCAL_SHARED_LIBRARIES += libuiblur - LOCAL_CFLAGS += -DUI_BLUR +ifeq ($(BOARD_USES_HWC_SERVICES), true) + LOCAL_CFLAGS += -DUSES_HWC_SERVICES + LOCAL_SHARED_LIBRARIES += libExynosHWCService + LOCAL_C_INCLUDES += \ + $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include \ + $(TOP)/hardware/samsung_slsi-$(TARGET_SLSI_VARIANT)/$(TARGET_BOARD_PLATFORM)/libhwcService \ + $(TOP)/hardware/samsung_slsi-$(TARGET_SLSI_VARIANT)/$(TARGET_BOARD_PLATFORM)/include \ + $(TOP)/hardware/samsung_slsi-$(TARGET_SLSI_VARIANT)/$(TARGET_SOC)/include \ + $(TOP)/hardware/samsung_slsi-$(TARGET_SLSI_VARIANT)/$(TARGET_SOC)/libhwcmodule \ + $(TOP)/hardware/samsung_slsi-$(TARGET_SLSI_VARIANT)/exynos/libhwc \ + $(TOP)/hardware/samsung_slsi-$(TARGET_SLSI_VARIANT)/exynos/include \ + $(TOP)/hardware/samsung_slsi-$(TARGET_SLSI_VARIANT)/exynos/libexynosutils \ + $(TOP)/system/core/libsync/include + +LOCAL_ADDITIONAL_DEPENDENCIES := \ + $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr endif LOCAL_MODULE := libsurfaceflinger diff --git a/services/surfaceflinger/CleanSpec.mk b/services/surfaceflinger/CleanSpec.mk new file mode 100644 index 0000000..c46eaeb --- /dev/null +++ b/services/surfaceflinger/CleanSpec.mk @@ -0,0 +1,51 @@ +# Copyright (C) 2016 The CyanogenMod Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libsurfaceflinger_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libsurfaceflinger_ddmconnection_intermediates) diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp index 73b3897..192d746 100644 --- a/services/surfaceflinger/DispSync.cpp +++ b/services/surfaceflinger/DispSync.cpp @@ -57,15 +57,17 @@ public: mStop(false), mPeriod(0), mPhase(0), + mReferenceTime(0), mWakeupLatency(0) { } virtual ~DispSyncThread() {} - void updateModel(nsecs_t period, nsecs_t phase) { + void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) { Mutex::Autolock lock(mMutex); mPeriod = period; mPhase = phase; + mReferenceTime = referenceTime; mCond.signal(); } @@ -247,7 +249,7 @@ private: ref = lastEventTime; } - nsecs_t phase = mPhase + listener.mPhase; + nsecs_t phase = mReferenceTime + mPhase + listener.mPhase; nsecs_t t = (((ref - phase) / mPeriod) + 1) * mPeriod + phase; if (t - listener.mLastEventTime < mPeriod / 2) { @@ -267,6 +269,7 @@ private: nsecs_t mPeriod; nsecs_t mPhase; + nsecs_t mReferenceTime; nsecs_t mWakeupLatency; Vector<EventListener> mEventListeners; @@ -315,6 +318,9 @@ DispSync::~DispSync() {} void DispSync::reset() { Mutex::Autolock lock(mMutex); + mPhase = 0; + mReferenceTime = 0; + mModelUpdated = false; mNumResyncSamples = 0; mFirstResyncSample = 0; mNumResyncSamplesSincePresent = 0; @@ -342,12 +348,13 @@ bool DispSync::addPresentFence(const sp<Fence>& fence) { updateErrorLocked(); - return mPeriod == 0 || mError > kErrorThreshold; + return !mModelUpdated || mError > kErrorThreshold; } void DispSync::beginResync() { Mutex::Autolock lock(mMutex); + mModelUpdated = false; mNumResyncSamples = 0; } @@ -356,6 +363,10 @@ bool DispSync::addResyncSample(nsecs_t timestamp) { size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES; mResyncSamples[idx] = timestamp; + if (mNumResyncSamples == 0) { + mPhase = 0; + mReferenceTime = timestamp; + } if (mNumResyncSamples < MAX_RESYNC_SAMPLES) { mNumResyncSamples++; @@ -378,7 +389,7 @@ bool DispSync::addResyncSample(nsecs_t timestamp) { return mThread->hasAnyEventListeners(); } - return mPeriod == 0 || mError > kErrorThreshold; + return !mModelUpdated || mError > kErrorThreshold; } void DispSync::endResync() { @@ -407,7 +418,8 @@ void DispSync::setPeriod(nsecs_t period) { Mutex::Autolock lock(mMutex); mPeriod = period; mPhase = 0; - mThread->updateModel(mPeriod, mPhase); + mReferenceTime = 0; + mThread->updateModel(mPeriod, mPhase, mReferenceTime); } nsecs_t DispSync::getPeriod() { @@ -432,7 +444,7 @@ void DispSync::updateModelLocked() { double scale = 2.0 * M_PI / double(mPeriod); for (size_t i = 0; i < mNumResyncSamples; i++) { size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES; - nsecs_t sample = mResyncSamples[idx]; + nsecs_t sample = mResyncSamples[idx] - mReferenceTime; double samplePhase = double(sample % mPeriod) * scale; sampleAvgX += cos(samplePhase); sampleAvgY += sin(samplePhase); @@ -455,12 +467,13 @@ void DispSync::updateModelLocked() { // Artificially inflate the period if requested. mPeriod += mPeriod * mRefreshSkipCount; - mThread->updateModel(mPeriod, mPhase); + mThread->updateModel(mPeriod, mPhase, mReferenceTime); + mModelUpdated = true; } } void DispSync::updateErrorLocked() { - if (mPeriod == 0) { + if (!mModelUpdated) { return; } @@ -472,7 +485,7 @@ void DispSync::updateErrorLocked() { nsecs_t sqErrSum = 0; for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { - nsecs_t sample = mPresentTimes[i]; + nsecs_t sample = mPresentTimes[i] - mReferenceTime; if (sample > mPhase) { nsecs_t sampleErr = (sample - mPhase) % period; if (sampleErr > period / 2) { @@ -506,7 +519,8 @@ void DispSync::resetErrorLocked() { nsecs_t DispSync::computeNextRefresh(int periodOffset) const { Mutex::Autolock lock(mMutex); nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - return (((now - mPhase) / mPeriod) + periodOffset + 1) * mPeriod + mPhase; + nsecs_t phase = mReferenceTime + mPhase; + return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase; } void DispSync::dump(String8& result) const { diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h index ebe19a5..61d891b 100644 --- a/services/surfaceflinger/DispSync.h +++ b/services/surfaceflinger/DispSync.h @@ -146,11 +146,18 @@ private: // number of nanoseconds from time 0 to the first vsync event. nsecs_t mPhase; + // mReferenceTime is the reference time of the modeled vsync events. + // It is the nanosecond timestamp of the first vsync event after a resync. + nsecs_t mReferenceTime; + // mError is the computed model error. It is based on the difference // between the estimated vsync event times and those observed in the // mPresentTimes array. nsecs_t mError; + // Whether we have updated the vsync event model since the last resync. + bool mModelUpdated; + // These member variables are the state used during the resynchronization // process to store information about the hardware vsync event times used // to compute the model. diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index f597b73..b83149b 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -142,10 +142,10 @@ DisplayDevice::DisplayDevice( break; } - mPanelInverseMounted = false; - // Check if panel is inverse mounted (contents show up HV flipped) - property_get("persist.panel.inversemounted", property, "0"); - mPanelInverseMounted = !!atoi(property); + mPanelMountFlip = 0; + // 1: H-Flip, 2: V-Flip, 3: 180 (HV Flip) + property_get("persist.panel.mountflip", property, "0"); + mPanelMountFlip = atoi(property); // initialize the display orientation transform. setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); @@ -401,7 +401,7 @@ status_t DisplayDevice::orientationToTransfrom( property_get("ro.sf.hwrotation", value, "0"); int additionalRot = atoi(value); - if (additionalRot) { + if (additionalRot && mType == DISPLAY_PRIMARY) { additionalRot /= 90; if (orientation == DisplayState::eOrientationUnchanged) { orientation = additionalRot; @@ -428,8 +428,8 @@ status_t DisplayDevice::orientationToTransfrom( return BAD_VALUE; } - if (DISPLAY_PRIMARY == mHwcDisplayId && isPanelInverseMounted()) { - flags = flags ^ Transform::ROT_180; + if (DISPLAY_PRIMARY == mHwcDisplayId) { + flags = flags ^ getPanelMountFlip(); } tr->set(flags, w, h); diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index f492a42..9023ce9 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -126,8 +126,8 @@ public: int32_t getHwcDisplayId() const { return mHwcDisplayId; } const wp<IBinder>& getDisplayToken() const { return mDisplayToken; } - bool isPanelInverseMounted() const { - return mPanelInverseMounted; + uint32_t getPanelMountFlip() const { + return mPanelMountFlip; } // We pass in mustRecompose so we can keep VirtualDisplaySurface's state @@ -230,8 +230,8 @@ private: int mPowerMode; // Current active config int mActiveConfig; - // Panel is inverse mounted - int mPanelInverseMounted; + // Panel's mount flip, H, V or 180 (HV) + uint32_t mPanelMountFlip; }; }; // namespace android diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index a43597a..17e91d9 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -435,7 +435,11 @@ status_t HWComposer::queryDisplayProperties(int disp) { } // FIXME: what should we set the format to? +#ifdef USE_BGRA_8888 + mDisplayData[disp].format = HAL_PIXEL_FORMAT_BGRA_8888; +#else mDisplayData[disp].format = HAL_PIXEL_FORMAT_RGBA_8888; +#endif mDisplayData[disp].connected = true; return NO_ERROR; } @@ -497,7 +501,11 @@ sp<Fence> HWComposer::getDisplayFence(int disp) const { uint32_t HWComposer::getFormat(int disp) const { if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) { +#ifdef USE_BGRA_8888 + return HAL_PIXEL_FORMAT_BGRA_8888; +#else return HAL_PIXEL_FORMAT_RGBA_8888; +#endif } else { return mDisplayData[disp].format; } @@ -879,7 +887,11 @@ int HWComposer::getVisualID() const { // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED // is supported by the implementation. we can only be in this case // if we have HWC 1.1 +#ifdef USE_BGRA_8888 + return HAL_PIXEL_FORMAT_BGRA_8888; +#else return HAL_PIXEL_FORMAT_RGBA_8888; +#endif //return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; } else { return mFbDev->format; @@ -1367,7 +1379,11 @@ bool HWComposer::VSyncThread::threadLoop() { HWComposer::DisplayData::DisplayData() : configs(), currentConfig(0), +#ifdef USE_BGRA_8888 + format(HAL_PIXEL_FORMAT_BGRA_8888), +#else format(HAL_PIXEL_FORMAT_RGBA_8888), +#endif connected(false), hasFbComp(false), hasOvComp(false), capacity(0), list(NULL), diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 9bdb7de..efdcd03 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -306,6 +306,7 @@ public: }; friend class VSyncThread; + friend class ExHWComposer; // for debugging ---------------------------------------------------------- void dump(String8& out) const; diff --git a/services/surfaceflinger/DisplayUtils.cpp b/services/surfaceflinger/DisplayUtils.cpp index a07e69e..e618e89 100644 --- a/services/surfaceflinger/DisplayUtils.cpp +++ b/services/surfaceflinger/DisplayUtils.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015 - 2016, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -45,6 +45,10 @@ #include <ExSurfaceFlinger/ExHWComposer.h> #include <ExSurfaceFlinger/ExVirtualDisplaySurface.h> #include <gralloc_priv.h> +#ifdef SDM_TARGET +#include <qd_utils.h> +#include <display_config.h> +#endif #endif #include <dlfcn.h> #include <cutils/properties.h> @@ -176,8 +180,25 @@ bool DisplayUtils::canAllocateHwcDisplayIdForVDS(int usage) { #ifdef QTI_BSP #ifdef FORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS - // Reserve hardware acceleration for WFD use-case - flag_mask = GRALLOC_USAGE_PRIVATE_WFD; +#ifdef SDM_TARGET + int hdmi_node = qdutils::getHDMINode(); + if(hdmi_node == HWC_DISPLAY_PRIMARY) { + int active_config = qdutils::getActiveConfig(HWC_DISPLAY_PRIMARY); + if(active_config >= 0) { + qdutils::DisplayAttributes attr = qdutils::getDisplayAttributes(active_config, + HWC_DISPLAY_PRIMARY); + if(!attr.is_yuv) { + // Reserve hardware acceleration for WFD use-case + flag_mask = GRALLOC_USAGE_PRIVATE_WFD; + } + } + } else { +#endif + // Reserve hardware acceleration for WFD use-case + flag_mask = GRALLOC_USAGE_PRIVATE_WFD; +#ifdef SDM_TARGET + } +#endif #else // Don't allocate HWC display unless we force HWC copy, otherwise // incompatible buffers are sent to the media stack diff --git a/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.cpp b/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.cpp index 2b41098..92cc1a7 100644 --- a/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.cpp +++ b/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.cpp @@ -31,6 +31,8 @@ #include "ExHWComposer.h" #ifdef QTI_BSP #include <hardware/display_defs.h> +#include <gralloc_priv.h> +#include <qdMetaData.h> #endif namespace android { @@ -74,4 +76,32 @@ bool ExHWComposer::isCompositionTypeBlit(const int32_t compType) const { return false; } +#if defined(QTI_BSP) && defined(SDM_TARGET) +uint32_t ExHWComposer::getS3DFlag(int disp) const { + if (disp < 0) { + return 0; + } + + if (!mHwc || uint32_t(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) + return 0; + + const DisplayData& disp_data(mDisplayData[disp]); + + for (size_t i=0 ; i<disp_data.list->numHwLayers-1; i++) { + const hwc_layer_1_t &l = disp_data.list->hwLayers[i]; + private_handle_t *pvt_handle = static_cast<private_handle_t *> + (const_cast<native_handle_t*>(l.handle)); + + if (pvt_handle != NULL) { + struct S3DSFRender_t s3dRender; + getMetaData(pvt_handle, GET_S3D_RENDER, &s3dRender); + if (s3dRender.DisplayId == static_cast<uint32_t>(disp) && s3dRender.GpuRender) { + return s3dRender.GpuS3dFormat; + } + } + } + return 0; +} +#endif + }; // namespace android diff --git a/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.h b/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.h index 2016ff0..06ee32b 100644 --- a/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.h +++ b/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.h @@ -43,6 +43,10 @@ public: virtual ~ExHWComposer(); +#ifdef QTI_BSP + uint32_t getS3DFlag(int disp) const; +#endif + protected: bool mVDSEnabled; inline bool isVDSEnabled() const { return mVDSEnabled; }; diff --git a/services/surfaceflinger/ExSurfaceFlinger/ExLayer.cpp b/services/surfaceflinger/ExSurfaceFlinger/ExLayer.cpp index fa45579..875d47f 100644 --- a/services/surfaceflinger/ExSurfaceFlinger/ExLayer.cpp +++ b/services/surfaceflinger/ExSurfaceFlinger/ExLayer.cpp @@ -36,10 +36,12 @@ #include <ui/GraphicBuffer.h> #ifdef QTI_BSP #include <gralloc_priv.h> +#include <qdMetaData.h> #include <hardware/display_defs.h> #endif #include "ExLayer.h" +#include "RenderEngine/RenderEngine.h" namespace android { @@ -70,12 +72,18 @@ static Rect getAspectRatio(const sp<const DisplayDevice>& hw, ExLayer::ExLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags) +#ifdef QTI_BSP + : Layer(flinger, client, name, w, h, flags), + mMeshLeftTop(Mesh::TRIANGLE_FAN, 4, 2, 2), + mMeshRightBottom(Mesh::TRIANGLE_FAN, 4, 2, 2) { +#else : Layer(flinger, client, name, w, h, flags) { - +#endif char property[PROPERTY_VALUE_MAX] = {0}; mDebugLogs = false; mIsGPUAllowedForProtected = false; + mIsHDMIPrimary = false; if((property_get("persist.debug.qdframework.logs", property, NULL) > 0) && (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { @@ -88,6 +96,12 @@ ExLayer::ExLayer(SurfaceFlinger* flinger, const sp<Client>& client, (atoi(property) == 1)) { mIsGPUAllowedForProtected = true; } + + if ((property_get("persist.sys.is_hdmi_primary", property, NULL) > 0) && + (atoi(property) == 1)) { + mIsHDMIPrimary = true; + } + } ExLayer::~ExLayer() { @@ -204,4 +218,172 @@ bool ExLayer::canAllowGPUForProtected() const { } } +void ExLayer::drawWithOpenGL(const sp<const DisplayDevice>& hw, + const Region& /* clip */, bool useIdentityTransform) const { + const State& s(getDrawingState()); +#if defined(QTI_BSP) && defined(SDM_TARGET) + uint32_t s3d_fmt = 0; + private_handle_t *pvt_handle = static_cast<private_handle_t *> + (const_cast<native_handle_t*>(mActiveBuffer->handle)); + if (pvt_handle != NULL) { + struct S3DSFRender_t s3dRender; + getMetaData(pvt_handle, GET_S3D_RENDER, &s3dRender); + + if ((s3dRender.DisplayId == static_cast<uint32_t>(hw->getHwcDisplayId()) || + mIsHDMIPrimary) && s3dRender.GpuRender) { + clearMetaData(pvt_handle, SET_S3D_RENDER); + s3d_fmt = s3dRender.GpuS3dFormat; + } + } +#endif + computeGeometry(hw, mMesh, useIdentityTransform); + + /* + * NOTE: the way we compute the texture coordinates here produces + * different results than when we take the HWC path -- in the later case + * the "source crop" is rounded to texel boundaries. + * This can produce significantly different results when the texture + * is scaled by a large amount. + * + * The GL code below is more logical (imho), and the difference with + * HWC is due to a limitation of the HWC API to integers -- a question + * is suspend is whether we should ignore this problem or revert to + * GL composition when a buffer scaling is applied (maybe with some + * minimal value)? Or, we could make GL behave like HWC -- but this feel + * like more of a hack. + */ + Rect win(s.active.w, s.active.h); + if(!s.active.crop.isEmpty()) { + win = s.active.crop; + } +#ifdef QTI_BSP + win = s.transform.transform(win); + win.intersect(hw->getViewport(), &win); + win = s.transform.inverse().transform(win); + win.intersect(Rect(s.active.w, s.active.h), &win); + win = reduce(win, s.activeTransparentRegion); +#else + win = reduce(win, s.activeTransparentRegion); +#endif + float left = float(win.left) / float(s.active.w); + float top = float(win.top) / float(s.active.h); + float right = float(win.right) / float(s.active.w); + float bottom = float(win.bottom) / float(s.active.h); + + // TODO: we probably want to generate the texture coords with the mesh + // here we assume that we only have 4 vertices + Mesh::VertexArray<vec2> texCoords(mMesh.getTexCoordArray<vec2>()); + texCoords[0] = vec2(left, 1.0f - top); + texCoords[1] = vec2(left, 1.0f - bottom); + texCoords[2] = vec2(right, 1.0f - bottom); + texCoords[3] = vec2(right, 1.0f - top); + +#if defined(QTI_BSP) && defined(SDM_TARGET) + computeGeometryS3D(hw, mMesh, mMeshLeftTop, mMeshRightBottom, s3d_fmt); +#endif + + RenderEngine& engine(mFlinger->getRenderEngine()); + engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), s.alpha); + +#if defined(QTI_BSP) && defined(SDM_TARGET) + if (s3d_fmt != HWC_S3DMODE_NONE) { + engine.setScissor(0, 0, hw->getWidth(), hw->getHeight()); + engine.drawMesh(mMeshLeftTop); + engine.drawMesh(mMeshRightBottom); + } else { +#endif + engine.drawMesh(mMesh); +#if defined(QTI_BSP) && defined(SDM_TARGET) + } +#endif + + engine.disableBlending(); +} + +#ifdef QTI_BSP +void ExLayer::computeGeometryS3D(const sp<const DisplayDevice>& hw, Mesh& mesh, + Mesh& meshLeftTop, Mesh &meshRightBottom, uint32_t s3d_fmt) const +{ + Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); + Mesh::VertexArray<vec2> positionLeftTop(meshLeftTop.getPositionArray<vec2>()); + Mesh::VertexArray<vec2> positionRightBottom(meshRightBottom.getPositionArray<vec2>()); + Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>()); + Mesh::VertexArray<vec2> texCoordsLeftTop(meshLeftTop.getTexCoordArray<vec2>()); + Mesh::VertexArray<vec2> texCoordsRightBottom(meshRightBottom.getTexCoordArray<vec2>()); + + Rect scissor = hw->getBounds(); + + if(s3d_fmt == HWC_S3DMODE_NONE) { + return; + } + + uint32_t count = mesh.getVertexCount(); + while(count--) { + positionLeftTop[count] = positionRightBottom[count] = position[count]; + texCoordsLeftTop[count] = texCoordsRightBottom[count] = texCoords[count]; + } + + switch (s3d_fmt) { + case HWC_S3DMODE_LR: + case HWC_S3DMODE_RL: + { + positionLeftTop[0].x = (position[0].x - scissor.left) / 2.0f + scissor.left; + positionLeftTop[1].x = (position[1].x - scissor.left) / 2.0f + scissor.left; + positionLeftTop[2].x = (position[2].x - scissor.left) / 2.0f + scissor.left; + positionLeftTop[3].x = (position[3].x - scissor.left) / 2.0f + scissor.left; + + positionRightBottom[0].x = positionLeftTop[0].x + scissor.getWidth()/2; + positionRightBottom[1].x = positionLeftTop[1].x + scissor.getWidth()/2; + positionRightBottom[2].x = positionLeftTop[2].x + scissor.getWidth()/2; + positionRightBottom[3].x = positionLeftTop[3].x + scissor.getWidth()/2; + + if(isYuvLayer()) { + texCoordsLeftTop[0].x = texCoords[0].x / 2.0f; + texCoordsLeftTop[1].x = texCoords[1].x / 2.0f; + texCoordsLeftTop[2].x = texCoords[2].x / 2.0f; + texCoordsLeftTop[3].x = texCoords[3].x / 2.0f; + + texCoordsRightBottom[0].x = texCoordsLeftTop[0].x + 0.5f; + texCoordsRightBottom[1].x = texCoordsLeftTop[1].x + 0.5f; + texCoordsRightBottom[2].x = texCoordsLeftTop[2].x + 0.5f; + texCoordsRightBottom[3].x = texCoordsLeftTop[3].x + 0.5f; + } + break; + } + case HWC_S3DMODE_TB: + { + positionRightBottom[0].y = (position[0].y - scissor.top) / 2.0f + scissor.top; + positionRightBottom[1].y = (position[1].y - scissor.top) / 2.0f + scissor.top; + positionRightBottom[2].y = (position[2].y - scissor.top) / 2.0f + scissor.top; + positionRightBottom[3].y = (position[3].y - scissor.top) / 2.0f + scissor.top; + + positionLeftTop[0].y = positionRightBottom[0].y + scissor.getHeight() / 2.0f; + positionLeftTop[1].y = positionRightBottom[1].y + scissor.getHeight() / 2.0f; + positionLeftTop[2].y = positionRightBottom[2].y + scissor.getHeight() / 2.0f; + positionLeftTop[3].y = positionRightBottom[3].y + scissor.getHeight() / 2.0f; + + positionLeftTop[0].x = positionRightBottom[0].x = position[0].x; + positionLeftTop[1].x = positionRightBottom[1].x = position[1].x; + positionLeftTop[2].x = positionRightBottom[2].x = position[2].x; + positionLeftTop[3].x = positionRightBottom[3].x = position[3].x; + + if(isYuvLayer()) { + texCoordsRightBottom[0].y = texCoords[0].y / 2.0f; + texCoordsRightBottom[1].y = texCoords[1].y / 2.0f; + texCoordsRightBottom[2].y = texCoords[2].y / 2.0f; + texCoordsRightBottom[3].y = texCoords[3].y / 2.0f; + + texCoordsLeftTop[0].y = texCoordsRightBottom[0].y + 0.5f; + texCoordsLeftTop[1].y = texCoordsRightBottom[1].y + 0.5f; + texCoordsLeftTop[2].y = texCoordsRightBottom[2].y + 0.5f; + texCoordsLeftTop[3].y = texCoordsRightBottom[3].y + 0.5f; + } + break; + } + default: + break; + } +} +#endif + }; // namespace android diff --git a/services/surfaceflinger/ExSurfaceFlinger/ExLayer.h b/services/surfaceflinger/ExSurfaceFlinger/ExLayer.h index 01c74a8..9d22b5f 100644 --- a/services/surfaceflinger/ExSurfaceFlinger/ExLayer.h +++ b/services/surfaceflinger/ExSurfaceFlinger/ExLayer.h @@ -43,6 +43,22 @@ class ExSurfaceFlinger; class ExLayer : public Layer { public: +#ifdef QTI_BSP + enum { + /* + * HWC S3D_MODE is set by HWC driver to indicate that HWC driver can not support + * S3D standalone, need surfaceflinger help to draw layers twice to construct + * S3D framebuffer target. + */ + HWC_S3DMODE_NONE = 0x00000000, + HWC_S3DMODE_LR = 0x00000001, + HWC_S3DMODE_RL = 0x00000002, + HWC_S3DMODE_TB = 0x00000003, + HWC_S3DMODE_FP = 0x00000004, + HWC_S3DMODE_MAX = 0x00000005, + }; +#endif + ExLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags); virtual ~ExLayer(); @@ -57,11 +73,27 @@ public: HWComposer::HWCLayerInterface& layer); virtual bool canAllowGPUForProtected() const; +#ifdef QTI_BSP + virtual void computeGeometryS3D(const sp<const DisplayDevice>& hw, Mesh& mesh, + Mesh& meshLeftTop, Mesh &meshRightBottom, uint32_t s3d_fmt) const; +#endif protected: bool mDebugLogs; bool isDebug() { return mDebugLogs; } bool mIsGPUAllowedForProtected; + bool mIsHDMIPrimary; + +private: +#ifdef QTI_BSP + // The mesh used to draw the layer in GLES composition mode for s3d left/top + mutable Mesh mMeshLeftTop; + // The mesh used to draw the layer in GLES composition mode for s3d right/bottom + mutable Mesh mMeshRightBottom; + + virtual void drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip, + bool useIdentityTransform) const; }; +#endif }; // namespace android diff --git a/services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.cpp b/services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.cpp index 96d4b1d..7be0328 100644 --- a/services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.cpp +++ b/services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.cpp @@ -335,6 +335,10 @@ void ExSurfaceFlinger::dumpDrawCycle(bool prePrepare) { gettimeofday(&tv, NULL); ptm = localtime(&tv.tv_sec); + if (ptm == NULL) { + return; + } + strftime (hms, sizeof (hms), "%H:%M:%S", ptm); millis = tv.tv_usec / 1000; snprintf(timeStamp, sizeof(timeStamp), "Timestamp: %s.%03ld", hms, millis); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 6dd8bad..6a9cdb7 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -104,9 +104,12 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mName = name; + mCurrentState.active.x = 0; + mCurrentState.active.y = 0; mCurrentState.active.w = w; mCurrentState.active.h = h; mCurrentState.active.crop.makeInvalid(); + mCurrentState.active.isPositionPending = false; mCurrentState.z = 0; mCurrentState.alpha = 0xFF; mCurrentState.blur = 0xFF; @@ -464,7 +467,11 @@ void Layer::setGeometry( // this gives us only the "orientation" component of the transform const State& s(getDrawingState()); +#if defined(QTI_BSP) && !defined(QCOM_BSP_LEGACY) + if (!isOpaque(s)) { +#else if (!isOpaque(s) || s.alpha != 0xFF) { +#endif layer.setBlending(mPremultipliedAlpha ? HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE); @@ -1027,6 +1034,17 @@ uint32_t Layer::doTransaction(uint32_t flags) { if (flags & eDontUpdateGeometryState) { } else { Layer::State& editCurrentState(getCurrentState()); + // If a position change was requested, and we have the correct + // buffer size, no need to delay, update state now. + if (editCurrentState.requested.isPositionPending) { + float requestedX = editCurrentState.requested.x; + float requestedY = editCurrentState.requested.y; + if (requestedX != editCurrentState.active.x || + requestedY != editCurrentState.active.y) { + editCurrentState.requested.isPositionPending = false; + editCurrentState.transform.set(requestedX, requestedY); + } + } editCurrentState.active = c.requested; } @@ -1064,10 +1082,15 @@ uint32_t Layer::setTransactionFlags(uint32_t flags) { } bool Layer::setPosition(float x, float y) { - if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y) + if ((mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y + && !mCurrentState.requested.isPositionPending) || + (mCurrentState.requested.isPositionPending && mCurrentState.requested.x == x + && mCurrentState.requested.y == y)) return false; mCurrentState.sequence++; - mCurrentState.transform.set(x, y); + mCurrentState.requested.x = x; + mCurrentState.requested.y = y; + mCurrentState.requested.isPositionPending = true; setTransactionFlags(eTransactionNeeded); return true; } @@ -1290,6 +1313,19 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) (bufWidth == front.requested.w && bufHeight == front.requested.h)) { + + // If a position change was requested along with a resize. + // Now that we have the correct buffer size, update the position as well. + if (current.requested.isPositionPending) { + float requestedX = current.requested.x; + float requestedY = current.requested.y; + if (requestedX != current.active.x || requestedY != current.active.y) { + front.transform.set(requestedX, requestedY); + current.transform.set(requestedX, requestedY); + current.requested.isPositionPending = false; + } + } + // Here we pretend the transaction happened by updating the // current and drawing states. Drawing state is only accessed // in this thread, no need to have it locked @@ -1412,11 +1448,16 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) // Remove any stale buffers that have been dropped during // updateTexImage - while (mQueueItems[0].mFrameNumber != currentFrameNumber) { + while ((mQueuedFrames > 0) && (mQueueItems[0].mFrameNumber != currentFrameNumber)) { mQueueItems.removeAt(0); android_atomic_dec(&mQueuedFrames); } + if (mQueuedFrames == 0) { + ALOGE("[%s] mQueuedFrames is zero !!", mName.string()); + return outDirtyRegion; + } + mQueueItems.removeAt(0); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 196ef3e..0d6ec41 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -95,11 +95,15 @@ public: }; struct Geometry { + float x; + float y; uint32_t w; uint32_t h; + bool isPositionPending; Rect crop; inline bool operator ==(const Geometry& rhs) const { - return (w == rhs.w && h == rhs.h && crop == rhs.crop); + return (w == rhs.w && h == rhs.h && crop == rhs.crop && x == rhs.x && y == rhs.y + && isPositionPending == rhs.isPositionPending); } inline bool operator !=(const Geometry& rhs) const { return !operator ==(rhs); @@ -158,8 +162,13 @@ public: uint32_t getTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); +#ifdef QTI_BSP + virtual void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh, + bool useIdentityTransform) const; +#else void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh, bool useIdentityTransform) const; +#endif Rect computeBounds(const Region& activeTransparentRegion) const; Rect computeBounds() const; @@ -388,9 +397,14 @@ private: // drawing void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip, float r, float g, float b, float alpha) const; +#ifdef QTI_BSP + virtual void drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip, + bool useIdentityTransform) const; +#else void drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip, bool useIdentityTransform) const; +#endif // Temporary - Used only for LEGACY camera mode. uint32_t getProducerStickyTransform() const; diff --git a/services/surfaceflinger/LayerBlur.cpp b/services/surfaceflinger/LayerBlur.cpp index 021978d..93f548f 100644 --- a/services/surfaceflinger/LayerBlur.cpp +++ b/services/surfaceflinger/LayerBlur.cpp @@ -25,6 +25,7 @@ #include <stdint.h> #include <sys/types.h> #include <time.h> +#include <dlfcn.h> #include <utils/Errors.h> #include <utils/Log.h> @@ -90,16 +91,11 @@ static void setupMesh(Mesh& mesh, int width, int height, int viewportHeight) { texCoords[3] = vec2(1.0f, 1.0f); } - LayerBlur::LayerBlur(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags) - : Layer(flinger, client, name, w, h, flags), mBlurMaskSampling(1), mBlurMaskAlphaThreshold(0.0f) - ,mLastFrameSequence(0) + : Layer(flinger, client, name, w, h, flags), mBlurMaskSampling(1), + mBlurMaskAlphaThreshold(0.0f) ,mLastFrameSequence(0) { -#ifdef UI_BLUR - mBlurToken = qtiblur::initBlurToken(); -#endif - GLuint texnames[3]; mFlinger->getRenderEngine().genTextures(3, texnames); mTextureCapture.init(Texture::TEXTURE_2D, texnames[0]); @@ -108,9 +104,6 @@ LayerBlur::LayerBlur(SurfaceFlinger* flinger, const sp<Client>& client, } LayerBlur::~LayerBlur() { -#ifdef UI_BLUR - qtiblur::releaseBlurToken(mBlurToken); -#endif releaseFbo(mFboCapture); releaseFbo(mFboMasking); @@ -168,18 +161,15 @@ void LayerBlur::onDraw(const sp<const DisplayDevice>& hw, const Region& /*clip*/ // blur size_t outTexWidth = mTextureBlur.getWidth(); size_t outTexHeight = mTextureBlur.getHeight(); -#ifdef UI_BLUR - if (!qtiblur::blur(mBlurToken, - s.blur, + if (mBlurImpl.blur(s.blur, mTextureCapture.getTextureName(), mTextureCapture.getWidth(), mTextureCapture.getHeight(), mTextureBlur.getTextureName(), &outTexWidth, - &outTexHeight)) { + &outTexHeight) != OK) { return; } -#endif // mTextureBlur now has "Blurred image" mTextureBlur.setDimensions(outTexWidth, outTexHeight); @@ -238,8 +228,7 @@ bool LayerBlur::captureScreen(const sp<const DisplayDevice>& hw, FBO& fbo, Textu texture.getTextureName(), 0); mFlinger->getRenderEngine().clearWithColor(0.0f, 0.0f, 0.0f, 1.0f); - if (hw->isPanelInverseMounted()) - rotation = Transform::ROT_180; + rotation = (Transform::orientation_flags)(rotation ^ hw->getPanelMountFlip()); mFlinger->renderScreenImplLocked( hw, Rect(0,0,width,height), @@ -412,6 +401,86 @@ void LayerBlur::ensureFbo(FBO& fbo, int width, int height, int textureName) { } } +// --------------------------------------------------------------------------- + +void* LayerBlur::BlurImpl::sLibHandle = NULL; +bool LayerBlur::BlurImpl::sUnsupported = false; + +LayerBlur::BlurImpl::initBlurTokenFn LayerBlur::BlurImpl::initBlurToken = NULL; +LayerBlur::BlurImpl::releaseBlurTokenFn LayerBlur::BlurImpl::releaseBlurToken = NULL; +LayerBlur::BlurImpl::blurFn LayerBlur::BlurImpl::doBlur = NULL; +Mutex LayerBlur::BlurImpl::sLock; + +void LayerBlur::BlurImpl::closeBlurImpl() { + if (sLibHandle != NULL) { + dlclose(sLibHandle); + sLibHandle = NULL; + } +} + +status_t LayerBlur::BlurImpl::initBlurImpl() { + if (sLibHandle != NULL) { + return OK; + } + if (sUnsupported) { + return NO_INIT; + } + + sLibHandle = dlopen("libuiblur.so", RTLD_NOW); + if (sLibHandle == NULL) { + sUnsupported = true; + return NO_INIT; + } + + // happy happy joy joy! + + initBlurToken = (initBlurTokenFn)dlsym(sLibHandle, + "_ZN7qtiblur13initBlurTokenEv"); + releaseBlurToken = (releaseBlurTokenFn)dlsym(sLibHandle, + "_ZN7qtiblur16releaseBlurTokenEPv"); + + if (sizeof(size_t) == 4) { + doBlur = (blurFn)dlsym(sLibHandle, + "_ZN7qtiblur4blurEPvijjjjPjS1_"); + } else if (sizeof(size_t) == 8) { + doBlur = (blurFn)dlsym(sLibHandle, + "_ZN7qtiblur4blurEPvijmmjPmS1_"); + } + + if (!initBlurToken || !releaseBlurToken || !doBlur) { + ALOGE("dlsym failed for blur impl!: %s", dlerror()); + closeBlurImpl(); + sUnsupported = true; + return NO_INIT; + } + + return OK; +} + +LayerBlur::BlurImpl::BlurImpl() : mToken(NULL) { + Mutex::Autolock _l(sLock); + if (initBlurImpl() == OK) { + mToken = initBlurToken(); + } +} + +LayerBlur::BlurImpl::~BlurImpl() { + Mutex::Autolock _l(sLock); + if (mToken != NULL) { + releaseBlurToken(mToken); + } +} + +status_t LayerBlur::BlurImpl::blur(int level, uint32_t inId, size_t inWidth, size_t inHeight, + uint32_t outId, size_t* outWidth, size_t* outHeight) { + Mutex::Autolock _l(sLock); + if (mToken == NULL) { + return NO_INIT; + } + return doBlur(mToken, level, inId, inWidth, inHeight, + outId, outWidth, outHeight) ? OK : NO_INIT; +} + // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/LayerBlur.h b/services/surfaceflinger/LayerBlur.h index 251423e..bd37ad3 100644 --- a/services/surfaceflinger/LayerBlur.h +++ b/services/surfaceflinger/LayerBlur.h @@ -20,15 +20,12 @@ #ifndef ANDROID_LAYER_BLUR_H #define ANDROID_LAYER_BLUR_H +#include <stdlib.h> #include <stdint.h> #include <sys/types.h> #include "Layer.h" -#ifdef UI_BLUR -#include "Blur.h" // libuiblur.so -#endif - // --------------------------------------------------------------------------- namespace android { @@ -58,9 +55,37 @@ public: virtual bool setBlurMaskAlphaThreshold(float alpha) { mBlurMaskAlphaThreshold = alpha; return true; } private: -#ifdef UI_BLUR - qtiblur::BLUR_TOKEN mBlurToken; -#endif + class BlurImpl { + public: + + BlurImpl(); + ~BlurImpl(); + + status_t blur(int level, uint32_t inId, size_t inWidth, size_t inheight, + uint32_t outId, size_t* outWidth, size_t* outHeight); + + protected: + static status_t initBlurImpl(); + static void closeBlurImpl(); + static void* sLibHandle; + static bool sUnsupported; + + typedef void* (*initBlurTokenFn)(); + typedef void* (*releaseBlurTokenFn)(void*); + typedef void* (*blurFn)(void*, int, uint32_t, size_t, size_t, uint32_t, size_t*, size_t*); + + static initBlurTokenFn initBlurToken; + static releaseBlurTokenFn releaseBlurToken; + static blurFn doBlur; + + static Mutex sLock; + + private: + void* mToken; + }; + + BlurImpl mBlurImpl; + wp<Layer> mBlurMaskLayer; int32_t mBlurMaskSampling; float mBlurMaskAlphaThreshold; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a457019..441bad8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -74,6 +74,7 @@ #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" +#include "ExSurfaceFlinger/ExHWComposer.h" #include "DisplayHardware/VirtualDisplaySurface.h" #include "Effects/Daltonizer.h" @@ -82,6 +83,10 @@ #include <cutils/compiler.h> #include "DisplayUtils.h" +#ifdef USES_HWC_SERVICES +#include "ExynosHWCService.h" +#endif + #define DISPLAY_COUNT 1 /* @@ -130,6 +135,10 @@ static sp<Layer> lastSurfaceViewLayer; // --------------------------------------------------------------------------- +#ifdef USES_HWC_SERVICES +static bool notifyPSRExit = true; +#endif + SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), mTransactionFlags(0), @@ -156,6 +165,7 @@ SurfaceFlinger::SurfaceFlinger() mHWVsyncAvailable(false), mDaltonize(false), mHasColorMatrix(false), + mHasSecondaryColorMatrix(false), mHasPoweredOff(false), mFrameBuckets(), mTotalTime(0), @@ -311,6 +321,14 @@ void SurfaceFlinger::bootFinished() // formerly we would just kill the process, but we now ask it to exit so it // can choose where to stop the animation. property_set("service.bootanim.exit", "1"); + +#ifdef USES_HWC_SERVICES + sp<IServiceManager> sm = defaultServiceManager(); + sp<android::IExynosHWCService> hwc = + interface_cast<android::IExynosHWCService>(sm->getService(String16("Exynos.HWCService"))); + ALOGD("boot finished. Inform HWC"); + hwc->setBootFinished(); +#endif } void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { @@ -797,6 +815,19 @@ void SurfaceFlinger::signalTransaction() { } void SurfaceFlinger::signalLayerUpdate() { +#ifdef USES_HWC_SERVICES + if (notifyPSRExit) { + notifyPSRExit = false; + sp<IServiceManager> sm = defaultServiceManager(); + sp<IExynosHWCService> hwcService = + interface_cast<android::IExynosHWCService>( + sm->getService(String16("Exynos.HWCService"))); + if (hwcService != NULL) + hwcService->notifyPSRExit(); + else + ALOGE("HWCService::notifyPSRExit failed"); + } +#endif mEventQueue.invalidate(); } @@ -981,6 +1012,9 @@ void SurfaceFlinger::handleMessageRefresh() { doDebugFlashRegions(); doComposition(); postComposition(); +#ifdef USES_HWC_SERVICES + notifyPSRExit = true; +#endif } previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0); @@ -1193,7 +1227,7 @@ void SurfaceFlinger::setUpHWComposer() { for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { const sp<Layer>& layer(currentLayers[i]); layer->setGeometry(hw, *cur); - if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) { + if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix || mHasSecondaryColorMatrix) { cur->setSkip(true); } } @@ -1958,11 +1992,14 @@ void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw, } } - if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) { + if (CC_LIKELY(!mDaltonize && !mHasColorMatrix && !mHasSecondaryColorMatrix)) { if (!doComposeSurfaces(hw, dirtyRegion)) return; } else { RenderEngine& engine(getRenderEngine()); mat4 colorMatrix = mColorMatrix; + if (mHasSecondaryColorMatrix) { + colorMatrix = mHasColorMatrix ? (colorMatrix * mSecondaryColorMatrix) : mSecondaryColorMatrix; + } if (mDaltonize) { colorMatrix = colorMatrix * mDaltonizer(); } @@ -1999,7 +2036,12 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const } // Never touch the framebuffer if we don't have any framebuffer layers +#if defined(QTI_BSP) && defined(SDM_TARGET) + const bool hasHwcComposition = hwc.hasHwcComposition(id) | + (reinterpret_cast<ExHWComposer*>(&hwc))->getS3DFlag(id); +#else const bool hasHwcComposition = hwc.hasHwcComposition(id); +#endif if (hasHwcComposition) { // when using overlays, we assume a fully transparent framebuffer // NOTE: we could reduce how much we need to clear, for instance @@ -2948,7 +2990,8 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, result.appendFormat(" h/w composer %s and %s\n", hwc.initCheck()==NO_ERROR ? "present" : "not present", (mDebugDisableHWC || mDebugRegion || mDaltonize - || mHasColorMatrix) ? "disabled" : "enabled"); + || mHasColorMatrix + || mHasSecondaryColorMatrix) ? "disabled" : "enabled"); hwc.dump(result); /* @@ -3158,6 +3201,28 @@ status_t SurfaceFlinger::onTransact( mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n)); return NO_ERROR; } + case 1030: { + // apply a secondary color matrix + // this will be combined with any other transformations + n = data.readInt32(); + mHasSecondaryColorMatrix = n ? 1 : 0; + if (n) { + // color matrix is sent as mat3 matrix followed by vec3 + // offset, then packed into a mat4 where the last row is + // the offset and extra values are 0 + for (size_t i = 0 ; i < 4; i++) { + for (size_t j = 0; j < 4; j++) { + mSecondaryColorMatrix[i][j] = data.readFloat(); + } + } + } else { + mSecondaryColorMatrix = mat4(); + } + invalidateHwcGeometry(); + repaintEverything(); + return NO_ERROR; + } + } } return err; @@ -3436,10 +3501,9 @@ void SurfaceFlinger::renderScreenImplLocked( // make sure to clear all GL error flags engine.checkErrors(); - if (DisplayDevice::DISPLAY_PRIMARY == hw->getDisplayType() && - hw->isPanelInverseMounted()) { + if (DisplayDevice::DISPLAY_PRIMARY == hw->getDisplayType()) { rotation = (Transform::orientation_flags) - (rotation ^ Transform::ROT_180); + (rotation ^ hw->getPanelMountFlip()); } // set-up our viewport diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 1f7601a..2003d6e 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -146,6 +146,9 @@ private: friend class DisplayEventConnection; friend class Layer; friend class LayerDim; +#ifdef QTI_BSP + friend class ExLayer; +#endif friend class MonitoredProducer; friend class LayerBlur; @@ -553,6 +556,9 @@ private: mat4 mColorMatrix; bool mHasColorMatrix; + mat4 mSecondaryColorMatrix; + bool mHasSecondaryColorMatrix; + // Static screen stats bool mHasPoweredOff; static const size_t NUM_BUCKETS = 8; // < 1-7, 7+ diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index dcde512..2ef2a50 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -249,4 +249,50 @@ TEST_F(LayerUpdateTest, LayerResizeWorks) { } } +// Ensure that if we move and resize a surface in the same +// transaction, we don't reposition the surface and draw +// using the incorrect buffer size +TEST_F(LayerUpdateTest, LayerMoveAndResizeWorks) { + sp<ScreenCapture> sc; + { + SCOPED_TRACE("before resize and reposition"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 0, 12, 63, 63, 195); + sc->checkPixel( 75, 75, 195, 63, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } + + ALOGD("resizing and repositioning"); + SurfaceComposerClient::openGlobalTransaction(); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 0)); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(64, 128)); + SurfaceComposerClient::closeGlobalTransaction(true); + + ALOGD("resized and repositioned"); + { + // This should not reflect the new size, position or color because SurfaceFlinger + // has not yet received a buffer of the correct size. + SCOPED_TRACE("after resize, before redraw"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 0, 12, 63, 63, 195); + sc->checkPixel( 75, 75, 195, 63, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } + + ALOGD("drawing"); + fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63); + waitForPostedBuffers(); + ALOGD("drawn"); + { + // This should reflect the new size, position and the new color. + SCOPED_TRACE("after redraw"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 64, 0, 63, 195, 63); + // This should pass to imply that we didn't have a frame where the + // surface was moved but not yet resized even though the operations + // were part of the same transaction + sc->checkPixel( 64, 75, 63, 195, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } +} } |