This commit is contained in:
Wolfgang Wiedmeyer 2016-12-13 02:15:45 +01:00
commit d3ad4f1e64
45 changed files with 1007 additions and 91 deletions

View File

@ -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

View File

@ -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

View File

@ -18,8 +18,8 @@
PRODUCT_PROPERTY_OVERRIDES += \ PRODUCT_PROPERTY_OVERRIDES += \
dalvik.vm.heapstartsize=8m \ dalvik.vm.heapstartsize=8m \
dalvik.vm.heapgrowthlimit=256m \ dalvik.vm.heapgrowthlimit=288m \
dalvik.vm.heapsize=512m \ dalvik.vm.heapsize=768m \
dalvik.vm.heaptargetutilization=0.75 \ dalvik.vm.heaptargetutilization=0.75 \
dalvik.vm.heapminfree=2m \ dalvik.vm.heapminfree=2m \
dalvik.vm.heapmaxfree=8m dalvik.vm.heapmaxfree=8m

View File

@ -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

View File

@ -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

View File

@ -272,7 +272,9 @@ static void dumpstate() {
char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX]; char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
char network[PROPERTY_VALUE_MAX], date[80]; char network[PROPERTY_VALUE_MAX], date[80];
char build_type[PROPERTY_VALUE_MAX]; 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.display.id", build, "(unknown)");
property_get("ro.build.fingerprint", fingerprint, "(unknown)"); property_get("ro.build.fingerprint", fingerprint, "(unknown)");
property_get("ro.build.type", build_type, "(unknown)"); property_get("ro.build.type", build_type, "(unknown)");
@ -286,6 +288,7 @@ static void dumpstate() {
printf("========================================================\n"); printf("========================================================\n");
printf("\n"); printf("\n");
printf("CM Version: %s\n", cm_version);
printf("Build: %s\n", build); printf("Build: %s\n", build);
printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */ printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */
printf("Bootloader: %s\n", bootloader); 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_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
dump_file("MEMORY INFO", "/proc/meminfo"); dump_file("MEMORY INFO", "/proc/meminfo");
run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL); 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("VIRTUAL MEMORY STATS", "/proc/vmstat");
dump_file("VMALLOC INFO", "/proc/vmallocinfo"); dump_file("VMALLOC INFO", "/proc/vmallocinfo");
dump_file("SLAB INFO", "/proc/slabinfo"); dump_file("SLAB INFO", "/proc/slabinfo");

View File

@ -18,7 +18,7 @@ LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE) include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := liblog libselinux LOCAL_SHARED_LIBRARIES := liblog libcutils libselinux
LOCAL_SRC_FILES := service_manager.c binder.c LOCAL_SRC_FILES := service_manager.c binder.c
LOCAL_CFLAGS += $(svc_c_flags) LOCAL_CFLAGS += $(svc_c_flags)
LOCAL_MODULE := servicemanager LOCAL_MODULE := servicemanager

View File

@ -8,6 +8,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <cutils/multiuser.h>
#include <private/android_filesystem_config.h> #include <private/android_filesystem_config.h>
#include <selinux/android.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; 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"; 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; 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)) if (!handle || (len == 0) || (len > 127))
return -1; 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", ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
str8(s, len), handle, uid); str8(s, len), handle, uid);
return -1; return -1;

View File

@ -45,6 +45,19 @@ enum {
}; };
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. */ /* Motion event is inconsistent with previously sent motion events. */
AMOTION_EVENT_FLAG_TAINTED = 0x80000000, AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
}; };

View File

@ -25,6 +25,7 @@ namespace android {
class FrameStats : public LightFlattenable<FrameStats> { class FrameStats : public LightFlattenable<FrameStats> {
public: public:
FrameStats() : refreshPeriodNano(0) {};
/* /*
* Approximate refresh time, in nanoseconds. * Approximate refresh time, in nanoseconds.

View File

@ -26,6 +26,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <binder/IMemory.h> #include <binder/IMemory.h>
#include <cutils/log.h>
#include <utils/KeyedVector.h> #include <utils/KeyedVector.h>
#include <utils/threads.h> #include <utils/threads.h>
#include <utils/Atomic.h> #include <utils/Atomic.h>
@ -191,15 +192,26 @@ sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
if (heap != 0) { if (heap != 0) {
mHeap = interface_cast<IMemoryHeap>(heap); mHeap = interface_cast<IMemoryHeap>(heap);
if (mHeap != 0) { if (mHeap != 0) {
mOffset = o; size_t heapSize = mHeap->getSize();
mSize = s; 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 (offset) *offset = mOffset;
if (size) *size = mSize; if (size) *size = mSize;
return mHeap; return (mSize > 0) ? mHeap : 0;
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -1083,8 +1083,16 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
<< reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl; << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
} }
if (tr.target.ptr) { if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie); // We only have a weak reference on the target object, so we must first try to
error = b->transact(tr.code, buffer, &reply, tr.flags); // 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 { } else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags); error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);

View File

@ -18,6 +18,8 @@
//#define LOG_NDEBUG 0 //#define LOG_NDEBUG 0
#include <binder/Parcel.h> #include <binder/Parcel.h>
#include <fcntl.h>
#include <pthread.h>
#include <binder/IPCThreadState.h> #include <binder/IPCThreadState.h>
#include <binder/Binder.h> #include <binder/Binder.h>
@ -42,6 +44,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef INT32_MAX #ifndef INT32_MAX
#define INT32_MAX ((int32_t)(2147483647)) #define INT32_MAX ((int32_t)(2147483647))
@ -95,6 +100,32 @@ enum {
BLOB_ASHMEM_MUTABLE = 2, 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, void acquire_object(const sp<ProcessState>& proc,
const flat_binder_object& obj, const void* who, size_t* outAshmemSize) const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
{ {
@ -123,8 +154,10 @@ void acquire_object(const sp<ProcessState>& proc,
return; return;
} }
case BINDER_TYPE_FD: { case BINDER_TYPE_FD: {
if (obj.cookie != 0) { if ((obj.cookie != 0) && (outAshmemSize != NULL)) {
if (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. // If we own an ashmem fd, keep track of how much memory it refers to.
int size = ashmem_get_size_region(obj.handle); int size = ashmem_get_size_region(obj.handle);
if (size > 0) { if (size > 0) {
@ -173,15 +206,18 @@ static void release_object(const sp<ProcessState>& proc,
return; return;
} }
case BINDER_TYPE_FD: { case BINDER_TYPE_FD: {
if (outAshmemSize != NULL) { if (obj.cookie != 0) { // owned
if (obj.cookie != 0) { if (outAshmemSize != NULL) {
int size = ashmem_get_size_region(obj.handle); struct stat st;
if (size > 0) { int ret = fstat(obj.handle, &st);
*outAshmemSize -= size; 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 #ifdef DISABLE_ASHMEM_TRACKING
} else if (obj.cookie != 0) { } else if (obj.cookie != 0) {
close(obj.handle); close(obj.handle);
@ -1389,7 +1425,13 @@ native_handle* Parcel::readNativeHandle() const
for (int i=0 ; err==NO_ERROR && i<numFds ; i++) { for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
h->data[i] = dup(readFileDescriptor()); 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); err = read(h->data + numFds, sizeof(int)*numInts);
if (err != NO_ERROR) { if (err != NO_ERROR) {

View File

@ -26,6 +26,10 @@
#include <gui/IConsumerListener.h> #include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h> #include <gui/IProducerListener.h>
#include <binder/IPCThreadState.h>
#include <binder/PermissionCache.h>
#include <private/android_filesystem_config.h>
namespace android { namespace android {
BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) : BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
@ -572,7 +576,18 @@ sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const {
} }
void BufferQueueConsumer::dump(String8& result, const char* prefix) 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 } // namespace android

View File

@ -349,7 +349,7 @@ status_t BnGraphicBufferConsumer::onTransact(
} }
case GET_RELEASED_BUFFERS: { case GET_RELEASED_BUFFERS: {
CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
uint64_t slotMask; uint64_t slotMask = 0;
status_t result = getReleasedBuffers(&slotMask); status_t result = getReleasedBuffers(&slotMask);
reply->writeInt64(static_cast<int64_t>(slotMask)); reply->writeInt64(static_cast<int64_t>(slotMask));
reply->writeInt32(result); reply->writeInt32(result);

View File

@ -435,6 +435,7 @@ status_t BnGraphicBufferProducer::onTransact(
QueueBufferOutput* const output = QueueBufferOutput* const output =
reinterpret_cast<QueueBufferOutput *>( reinterpret_cast<QueueBufferOutput *>(
reply->writeInplace(sizeof(QueueBufferOutput))); reply->writeInplace(sizeof(QueueBufferOutput)));
memset(output, 0, sizeof(QueueBufferOutput));
status_t res = connect(listener, api, producerControlledByApp, output); status_t res = connect(listener, api, producerControlledByApp, output);
reply->writeInt32(res); reply->writeInt32(res);
return NO_ERROR; return NO_ERROR;

View File

@ -795,6 +795,11 @@ status_t Region::unflatten(void const* buffer, size_t size) {
return NO_MEMORY; return NO_MEMORY;
} }
if (numRects > (UINT32_MAX / sizeof(Rect))) {
android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, NULL, 0);
return NO_MEMORY;
}
Region result; Region result;
result.mStorage.clear(); result.mStorage.clear();
for (size_t r = 0; r < numRects; ++r) { for (size_t r = 0; r < numRects; ++r) {

View File

@ -65,6 +65,10 @@ ifneq ($(MAX_EGL_CACHE_SIZE),)
LOCAL_CFLAGS += -DMAX_EGL_CACHE_SIZE=$(MAX_EGL_CACHE_SIZE) LOCAL_CFLAGS += -DMAX_EGL_CACHE_SIZE=$(MAX_EGL_CACHE_SIZE)
endif endif
ifeq ($(BOARD_USE_BGRA_8888), true)
LOCAL_CFLAGS += -DUSE_BGRA_8888
endif
LOCAL_REQUIRED_MODULES := $(egl.cfg_config_module) LOCAL_REQUIRED_MODULES := $(egl.cfg_config_module)
egl.cfg_config_module := egl.cfg_config_module :=

View File

@ -1225,6 +1225,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE; int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
if (isWindowObscuredAtPointLocked(windowHandle, x, y)) { if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
} else if (isWindowObscuredLocked(windowHandle)) {
outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
} }
mTempTouchState.addOrUpdateWindow( mTempTouchState.addOrUpdateWindow(
@ -1262,6 +1264,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
} }
if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
} else if (isWindowObscuredLocked(newTouchedWindowHandle)) {
targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
} }
// Update hover state. // Update hover state.
@ -1437,6 +1441,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
== InputWindowInfo::TYPE_WALLPAPER) { == InputWindowInfo::TYPE_WALLPAPER) {
mTempTouchState.addOrUpdateWindow(windowHandle, mTempTouchState.addOrUpdateWindow(windowHandle,
InputTarget::FLAG_WINDOW_IS_OBSCURED InputTarget::FLAG_WINDOW_IS_OBSCURED
| InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED
| InputTarget::FLAG_DISPATCH_AS_IS, | InputTarget::FLAG_DISPATCH_AS_IS,
BitSet32(0)); BitSet32(0));
} }
@ -1631,6 +1636,27 @@ bool InputDispatcher::isWindowObscuredAtPointLocked(
return false; 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, String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry, const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,
const char* targetType) { const char* targetType) {
@ -1905,6 +1931,9 @@ void InputDispatcher::enqueueDispatchEntryLocked(
if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
dispatchEntry->resolvedFlags |= AMOTION_EVENT_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, if (!connection->inputState.trackMotion(motionEntry,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {

View File

@ -89,7 +89,7 @@ struct InputTarget {
/* This flag indicates that the event is being delivered to a foreground application. */ /* This flag indicates that the event is being delivered to a foreground application. */
FLAG_FOREGROUND = 1 << 0, 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 * obscured by another visible window above it. The motion event should be
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
FLAG_WINDOW_IS_OBSCURED = 1 << 1, FLAG_WINDOW_IS_OBSCURED = 1 << 1,
@ -139,6 +139,12 @@ struct InputTarget {
| FLAG_DISPATCH_AS_HOVER_EXIT | FLAG_DISPATCH_AS_HOVER_EXIT
| FLAG_DISPATCH_AS_SLIPPERY_EXIT | FLAG_DISPATCH_AS_SLIPPERY_EXIT
| FLAG_DISPATCH_AS_SLIPPERY_ENTER, | 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. // The input channel to be targeted.
@ -1048,6 +1054,7 @@ private:
const InjectionState* injectionState); const InjectionState* injectionState);
bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
int32_t x, int32_t y) const; int32_t x, int32_t y) const;
bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const;
String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle, String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle); const sp<InputWindowHandle>& windowHandle);

View File

@ -6167,7 +6167,8 @@ nsecs_t TouchInputMapper::mLastStylusTime = 0;
bool TouchInputMapper::rejectPalm(nsecs_t when) { bool TouchInputMapper::rejectPalm(nsecs_t when) {
return (when - mLastStylusTime < mConfig.stylusPalmRejectionTime) && 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) { void TouchInputMapper::cancelTouch(nsecs_t when) {

View File

@ -36,14 +36,16 @@ bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
} }
bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
return x >= frameLeft && x <= frameRight return x >= frameLeft && x < frameRight
&& y >= frameTop && y <= frameBottom; && y >= frameTop && y < frameBottom;
} }
bool InputWindowInfo::isTrustedOverlay() const { bool InputWindowInfo::isTrustedOverlay() const {
return layoutParamsType == TYPE_INPUT_METHOD return layoutParamsType == TYPE_INPUT_METHOD
|| layoutParamsType == TYPE_INPUT_METHOD_DIALOG || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
|| layoutParamsType == TYPE_MAGNIFICATION_OVERLAY || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
|| layoutParamsType == TYPE_STATUS_BAR
|| layoutParamsType == TYPE_NAVIGATION_BAR
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
} }
@ -51,6 +53,11 @@ bool InputWindowInfo::supportsSplitTouch() const {
return layoutParamsFlags & FLAG_SPLIT_TOUCH; 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 --- // --- InputWindowHandle ---

View File

@ -146,6 +146,8 @@ struct InputWindowInfo {
bool isTrustedOverlay() const; bool isTrustedOverlay() const;
bool supportsSplitTouch() const; bool supportsSplitTouch() const;
bool overlaps(const InputWindowInfo* other) const;
}; };

View File

@ -359,6 +359,8 @@ status_t SensorService::dump(int fd, const Vector<String16>& args)
result.appendFormat("non-wakeUp | "); result.appendFormat("non-wakeUp | ");
} }
result.appendFormat("%.4f mA | ", s.getPowerUsage());
int bufIndex = mLastEventSeen.indexOfKey(s.getHandle()); int bufIndex = mLastEventSeen.indexOfKey(s.getHandle());
if (bufIndex >= 0) { if (bufIndex >= 0) {
const CircularBuffer* buf = mLastEventSeen.valueAt(bufIndex); const CircularBuffer* buf = mLastEventSeen.valueAt(bufIndex);
@ -1118,7 +1120,7 @@ bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation,
AppOpsManager appOps; AppOpsManager appOps;
if (appOps.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName) if (appOps.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName)
!= AppOpsManager::MODE_ALLOWED) { != 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); operation, sensor.getName().string(), opCode);
return false; return false;
} }

View File

@ -95,6 +95,10 @@ else
LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=0 LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=0
endif endif
ifeq ($(BOARD_USE_BGRA_8888),true)
LOCAL_CFLAGS += -DUSE_BGRA_8888
endif
LOCAL_CFLAGS += -fvisibility=hidden -Werror=format LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
LOCAL_CFLAGS += -std=c++11 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)/libgralloc
LOCAL_C_INCLUDES += $(call project-path-for,qcom-display)/libqdutils LOCAL_C_INCLUDES += $(call project-path-for,qcom-display)/libqdutils
LOCAL_SHARED_LIBRARIES += libqdutils LOCAL_SHARED_LIBRARIES += libqdutils
LOCAL_SHARED_LIBRARIES += libqdMetaData
LOCAL_CFLAGS += -DQTI_BSP LOCAL_CFLAGS += -DQTI_BSP
ifeq ($(call is-board-platform-in-list,msm8996),true)
LOCAL_CFLAGS += -DSDM_TARGET
endif
LOCAL_SRC_FILES += \ LOCAL_SRC_FILES += \
ExSurfaceFlinger/ExLayer.cpp \ ExSurfaceFlinger/ExLayer.cpp \
ExSurfaceFlinger/ExSurfaceFlinger.cpp \ ExSurfaceFlinger/ExSurfaceFlinger.cpp \
@ -124,10 +132,22 @@ ifeq ($(TARGET_USES_QCOM_BSP), true)
ExSurfaceFlinger/ExHWComposer.cpp ExSurfaceFlinger/ExHWComposer.cpp
endif endif
ifeq ($(TARGET_HAVE_UI_BLUR),true) ifeq ($(BOARD_USES_HWC_SERVICES), true)
LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/ui LOCAL_CFLAGS += -DUSES_HWC_SERVICES
LOCAL_SHARED_LIBRARIES += libuiblur LOCAL_SHARED_LIBRARIES += libExynosHWCService
LOCAL_CFLAGS += -DUI_BLUR 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 endif
LOCAL_MODULE := libsurfaceflinger LOCAL_MODULE := libsurfaceflinger

View File

@ -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)

View File

@ -57,15 +57,17 @@ public:
mStop(false), mStop(false),
mPeriod(0), mPeriod(0),
mPhase(0), mPhase(0),
mReferenceTime(0),
mWakeupLatency(0) { mWakeupLatency(0) {
} }
virtual ~DispSyncThread() {} 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); Mutex::Autolock lock(mMutex);
mPeriod = period; mPeriod = period;
mPhase = phase; mPhase = phase;
mReferenceTime = referenceTime;
mCond.signal(); mCond.signal();
} }
@ -247,7 +249,7 @@ private:
ref = lastEventTime; ref = lastEventTime;
} }
nsecs_t phase = mPhase + listener.mPhase; nsecs_t phase = mReferenceTime + mPhase + listener.mPhase;
nsecs_t t = (((ref - phase) / mPeriod) + 1) * mPeriod + phase; nsecs_t t = (((ref - phase) / mPeriod) + 1) * mPeriod + phase;
if (t - listener.mLastEventTime < mPeriod / 2) { if (t - listener.mLastEventTime < mPeriod / 2) {
@ -267,6 +269,7 @@ private:
nsecs_t mPeriod; nsecs_t mPeriod;
nsecs_t mPhase; nsecs_t mPhase;
nsecs_t mReferenceTime;
nsecs_t mWakeupLatency; nsecs_t mWakeupLatency;
Vector<EventListener> mEventListeners; Vector<EventListener> mEventListeners;
@ -315,6 +318,9 @@ DispSync::~DispSync() {}
void DispSync::reset() { void DispSync::reset() {
Mutex::Autolock lock(mMutex); Mutex::Autolock lock(mMutex);
mPhase = 0;
mReferenceTime = 0;
mModelUpdated = false;
mNumResyncSamples = 0; mNumResyncSamples = 0;
mFirstResyncSample = 0; mFirstResyncSample = 0;
mNumResyncSamplesSincePresent = 0; mNumResyncSamplesSincePresent = 0;
@ -342,12 +348,13 @@ bool DispSync::addPresentFence(const sp<Fence>& fence) {
updateErrorLocked(); updateErrorLocked();
return mPeriod == 0 || mError > kErrorThreshold; return !mModelUpdated || mError > kErrorThreshold;
} }
void DispSync::beginResync() { void DispSync::beginResync() {
Mutex::Autolock lock(mMutex); Mutex::Autolock lock(mMutex);
mModelUpdated = false;
mNumResyncSamples = 0; mNumResyncSamples = 0;
} }
@ -356,6 +363,10 @@ bool DispSync::addResyncSample(nsecs_t timestamp) {
size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES; size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
mResyncSamples[idx] = timestamp; mResyncSamples[idx] = timestamp;
if (mNumResyncSamples == 0) {
mPhase = 0;
mReferenceTime = timestamp;
}
if (mNumResyncSamples < MAX_RESYNC_SAMPLES) { if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
mNumResyncSamples++; mNumResyncSamples++;
@ -378,7 +389,7 @@ bool DispSync::addResyncSample(nsecs_t timestamp) {
return mThread->hasAnyEventListeners(); return mThread->hasAnyEventListeners();
} }
return mPeriod == 0 || mError > kErrorThreshold; return !mModelUpdated || mError > kErrorThreshold;
} }
void DispSync::endResync() { void DispSync::endResync() {
@ -407,7 +418,8 @@ void DispSync::setPeriod(nsecs_t period) {
Mutex::Autolock lock(mMutex); Mutex::Autolock lock(mMutex);
mPeriod = period; mPeriod = period;
mPhase = 0; mPhase = 0;
mThread->updateModel(mPeriod, mPhase); mReferenceTime = 0;
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
} }
nsecs_t DispSync::getPeriod() { nsecs_t DispSync::getPeriod() {
@ -432,7 +444,7 @@ void DispSync::updateModelLocked() {
double scale = 2.0 * M_PI / double(mPeriod); double scale = 2.0 * M_PI / double(mPeriod);
for (size_t i = 0; i < mNumResyncSamples; i++) { for (size_t i = 0; i < mNumResyncSamples; i++) {
size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES; 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; double samplePhase = double(sample % mPeriod) * scale;
sampleAvgX += cos(samplePhase); sampleAvgX += cos(samplePhase);
sampleAvgY += sin(samplePhase); sampleAvgY += sin(samplePhase);
@ -455,12 +467,13 @@ void DispSync::updateModelLocked() {
// Artificially inflate the period if requested. // Artificially inflate the period if requested.
mPeriod += mPeriod * mRefreshSkipCount; mPeriod += mPeriod * mRefreshSkipCount;
mThread->updateModel(mPeriod, mPhase); mThread->updateModel(mPeriod, mPhase, mReferenceTime);
mModelUpdated = true;
} }
} }
void DispSync::updateErrorLocked() { void DispSync::updateErrorLocked() {
if (mPeriod == 0) { if (!mModelUpdated) {
return; return;
} }
@ -472,7 +485,7 @@ void DispSync::updateErrorLocked() {
nsecs_t sqErrSum = 0; nsecs_t sqErrSum = 0;
for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
nsecs_t sample = mPresentTimes[i]; nsecs_t sample = mPresentTimes[i] - mReferenceTime;
if (sample > mPhase) { if (sample > mPhase) {
nsecs_t sampleErr = (sample - mPhase) % period; nsecs_t sampleErr = (sample - mPhase) % period;
if (sampleErr > period / 2) { if (sampleErr > period / 2) {
@ -506,7 +519,8 @@ void DispSync::resetErrorLocked() {
nsecs_t DispSync::computeNextRefresh(int periodOffset) const { nsecs_t DispSync::computeNextRefresh(int periodOffset) const {
Mutex::Autolock lock(mMutex); Mutex::Autolock lock(mMutex);
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); 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 { void DispSync::dump(String8& result) const {

View File

@ -146,11 +146,18 @@ private:
// number of nanoseconds from time 0 to the first vsync event. // number of nanoseconds from time 0 to the first vsync event.
nsecs_t mPhase; 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 // mError is the computed model error. It is based on the difference
// between the estimated vsync event times and those observed in the // between the estimated vsync event times and those observed in the
// mPresentTimes array. // mPresentTimes array.
nsecs_t mError; 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 // These member variables are the state used during the resynchronization
// process to store information about the hardware vsync event times used // process to store information about the hardware vsync event times used
// to compute the model. // to compute the model.

View File

@ -142,10 +142,10 @@ DisplayDevice::DisplayDevice(
break; break;
} }
mPanelInverseMounted = false; mPanelMountFlip = 0;
// Check if panel is inverse mounted (contents show up HV flipped) // 1: H-Flip, 2: V-Flip, 3: 180 (HV Flip)
property_get("persist.panel.inversemounted", property, "0"); property_get("persist.panel.mountflip", property, "0");
mPanelInverseMounted = !!atoi(property); mPanelMountFlip = atoi(property);
// initialize the display orientation transform. // initialize the display orientation transform.
setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
@ -401,7 +401,7 @@ status_t DisplayDevice::orientationToTransfrom(
property_get("ro.sf.hwrotation", value, "0"); property_get("ro.sf.hwrotation", value, "0");
int additionalRot = atoi(value); int additionalRot = atoi(value);
if (additionalRot) { if (additionalRot && mType == DISPLAY_PRIMARY) {
additionalRot /= 90; additionalRot /= 90;
if (orientation == DisplayState::eOrientationUnchanged) { if (orientation == DisplayState::eOrientationUnchanged) {
orientation = additionalRot; orientation = additionalRot;
@ -428,8 +428,8 @@ status_t DisplayDevice::orientationToTransfrom(
return BAD_VALUE; return BAD_VALUE;
} }
if (DISPLAY_PRIMARY == mHwcDisplayId && isPanelInverseMounted()) { if (DISPLAY_PRIMARY == mHwcDisplayId) {
flags = flags ^ Transform::ROT_180; flags = flags ^ getPanelMountFlip();
} }
tr->set(flags, w, h); tr->set(flags, w, h);

View File

@ -126,8 +126,8 @@ public:
int32_t getHwcDisplayId() const { return mHwcDisplayId; } int32_t getHwcDisplayId() const { return mHwcDisplayId; }
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; } const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
bool isPanelInverseMounted() const { uint32_t getPanelMountFlip() const {
return mPanelInverseMounted; return mPanelMountFlip;
} }
// We pass in mustRecompose so we can keep VirtualDisplaySurface's state // We pass in mustRecompose so we can keep VirtualDisplaySurface's state
@ -230,8 +230,8 @@ private:
int mPowerMode; int mPowerMode;
// Current active config // Current active config
int mActiveConfig; int mActiveConfig;
// Panel is inverse mounted // Panel's mount flip, H, V or 180 (HV)
int mPanelInverseMounted; uint32_t mPanelMountFlip;
}; };
}; // namespace android }; // namespace android

View File

@ -435,7 +435,11 @@ status_t HWComposer::queryDisplayProperties(int disp) {
} }
// FIXME: what should we set the format to? // 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; mDisplayData[disp].format = HAL_PIXEL_FORMAT_RGBA_8888;
#endif
mDisplayData[disp].connected = true; mDisplayData[disp].connected = true;
return NO_ERROR; return NO_ERROR;
} }
@ -497,7 +501,11 @@ sp<Fence> HWComposer::getDisplayFence(int disp) const {
uint32_t HWComposer::getFormat(int disp) const { uint32_t HWComposer::getFormat(int disp) const {
if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) { 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; return HAL_PIXEL_FORMAT_RGBA_8888;
#endif
} else { } else {
return mDisplayData[disp].format; return mDisplayData[disp].format;
} }
@ -879,7 +887,11 @@ int HWComposer::getVisualID() const {
// FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
// is supported by the implementation. we can only be in this case // is supported by the implementation. we can only be in this case
// if we have HWC 1.1 // if we have HWC 1.1
#ifdef USE_BGRA_8888
return HAL_PIXEL_FORMAT_BGRA_8888;
#else
return HAL_PIXEL_FORMAT_RGBA_8888; return HAL_PIXEL_FORMAT_RGBA_8888;
#endif
//return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; //return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
} else { } else {
return mFbDev->format; return mFbDev->format;
@ -1367,7 +1379,11 @@ bool HWComposer::VSyncThread::threadLoop() {
HWComposer::DisplayData::DisplayData() HWComposer::DisplayData::DisplayData()
: configs(), : configs(),
currentConfig(0), currentConfig(0),
#ifdef USE_BGRA_8888
format(HAL_PIXEL_FORMAT_BGRA_8888),
#else
format(HAL_PIXEL_FORMAT_RGBA_8888), format(HAL_PIXEL_FORMAT_RGBA_8888),
#endif
connected(false), connected(false),
hasFbComp(false), hasOvComp(false), hasFbComp(false), hasOvComp(false),
capacity(0), list(NULL), capacity(0), list(NULL),

View File

@ -306,6 +306,7 @@ public:
}; };
friend class VSyncThread; friend class VSyncThread;
friend class ExHWComposer;
// for debugging ---------------------------------------------------------- // for debugging ----------------------------------------------------------
void dump(String8& out) const; void dump(String8& out) const;

View File

@ -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 * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are * modification, are permitted provided that the following conditions are
@ -45,6 +45,10 @@
#include <ExSurfaceFlinger/ExHWComposer.h> #include <ExSurfaceFlinger/ExHWComposer.h>
#include <ExSurfaceFlinger/ExVirtualDisplaySurface.h> #include <ExSurfaceFlinger/ExVirtualDisplaySurface.h>
#include <gralloc_priv.h> #include <gralloc_priv.h>
#ifdef SDM_TARGET
#include <qd_utils.h>
#include <display_config.h>
#endif
#endif #endif
#include <dlfcn.h> #include <dlfcn.h>
#include <cutils/properties.h> #include <cutils/properties.h>
@ -176,8 +180,25 @@ bool DisplayUtils::canAllocateHwcDisplayIdForVDS(int usage) {
#ifdef QTI_BSP #ifdef QTI_BSP
#ifdef FORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS #ifdef FORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS
// Reserve hardware acceleration for WFD use-case #ifdef SDM_TARGET
flag_mask = GRALLOC_USAGE_PRIVATE_WFD; 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 #else
// Don't allocate HWC display unless we force HWC copy, otherwise // Don't allocate HWC display unless we force HWC copy, otherwise
// incompatible buffers are sent to the media stack // incompatible buffers are sent to the media stack

View File

@ -31,6 +31,8 @@
#include "ExHWComposer.h" #include "ExHWComposer.h"
#ifdef QTI_BSP #ifdef QTI_BSP
#include <hardware/display_defs.h> #include <hardware/display_defs.h>
#include <gralloc_priv.h>
#include <qdMetaData.h>
#endif #endif
namespace android { namespace android {
@ -74,4 +76,32 @@ bool ExHWComposer::isCompositionTypeBlit(const int32_t compType) const {
return false; 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 }; // namespace android

View File

@ -43,6 +43,10 @@ public:
virtual ~ExHWComposer(); virtual ~ExHWComposer();
#ifdef QTI_BSP
uint32_t getS3DFlag(int disp) const;
#endif
protected: protected:
bool mVDSEnabled; bool mVDSEnabled;
inline bool isVDSEnabled() const { return mVDSEnabled; }; inline bool isVDSEnabled() const { return mVDSEnabled; };

View File

@ -36,10 +36,12 @@
#include <ui/GraphicBuffer.h> #include <ui/GraphicBuffer.h>
#ifdef QTI_BSP #ifdef QTI_BSP
#include <gralloc_priv.h> #include <gralloc_priv.h>
#include <qdMetaData.h>
#include <hardware/display_defs.h> #include <hardware/display_defs.h>
#endif #endif
#include "ExLayer.h" #include "ExLayer.h"
#include "RenderEngine/RenderEngine.h"
namespace android { namespace android {
@ -70,12 +72,18 @@ static Rect getAspectRatio(const sp<const DisplayDevice>& hw,
ExLayer::ExLayer(SurfaceFlinger* flinger, const sp<Client>& client, ExLayer::ExLayer(SurfaceFlinger* flinger, const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags) 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) { : Layer(flinger, client, name, w, h, flags) {
#endif
char property[PROPERTY_VALUE_MAX] = {0}; char property[PROPERTY_VALUE_MAX] = {0};
mDebugLogs = false; mDebugLogs = false;
mIsGPUAllowedForProtected = false; mIsGPUAllowedForProtected = false;
mIsHDMIPrimary = false;
if((property_get("persist.debug.qdframework.logs", property, NULL) > 0) && if((property_get("persist.debug.qdframework.logs", property, NULL) > 0) &&
(!strncmp(property, "1", PROPERTY_VALUE_MAX ) || (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
(!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
@ -88,6 +96,12 @@ ExLayer::ExLayer(SurfaceFlinger* flinger, const sp<Client>& client,
(atoi(property) == 1)) { (atoi(property) == 1)) {
mIsGPUAllowedForProtected = true; mIsGPUAllowedForProtected = true;
} }
if ((property_get("persist.sys.is_hdmi_primary", property, NULL) > 0) &&
(atoi(property) == 1)) {
mIsHDMIPrimary = true;
}
} }
ExLayer::~ExLayer() { 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 }; // namespace android

View File

@ -43,6 +43,22 @@ class ExSurfaceFlinger;
class ExLayer : public Layer class ExLayer : public Layer
{ {
public: 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, ExLayer(SurfaceFlinger* flinger, const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags); const String8& name, uint32_t w, uint32_t h, uint32_t flags);
virtual ~ExLayer(); virtual ~ExLayer();
@ -57,11 +73,27 @@ public:
HWComposer::HWCLayerInterface& layer); HWComposer::HWCLayerInterface& layer);
virtual bool canAllowGPUForProtected() const; 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: protected:
bool mDebugLogs; bool mDebugLogs;
bool isDebug() { return mDebugLogs; } bool isDebug() { return mDebugLogs; }
bool mIsGPUAllowedForProtected; 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 }; // namespace android

View File

@ -335,6 +335,10 @@ void ExSurfaceFlinger::dumpDrawCycle(bool prePrepare) {
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
ptm = localtime(&tv.tv_sec); ptm = localtime(&tv.tv_sec);
if (ptm == NULL) {
return;
}
strftime (hms, sizeof (hms), "%H:%M:%S", ptm); strftime (hms, sizeof (hms), "%H:%M:%S", ptm);
millis = tv.tv_usec / 1000; millis = tv.tv_usec / 1000;
snprintf(timeStamp, sizeof(timeStamp), "Timestamp: %s.%03ld", hms, millis); snprintf(timeStamp, sizeof(timeStamp), "Timestamp: %s.%03ld", hms, millis);

View File

@ -104,9 +104,12 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
mName = name; mName = name;
mCurrentState.active.x = 0;
mCurrentState.active.y = 0;
mCurrentState.active.w = w; mCurrentState.active.w = w;
mCurrentState.active.h = h; mCurrentState.active.h = h;
mCurrentState.active.crop.makeInvalid(); mCurrentState.active.crop.makeInvalid();
mCurrentState.active.isPositionPending = false;
mCurrentState.z = 0; mCurrentState.z = 0;
mCurrentState.alpha = 0xFF; mCurrentState.alpha = 0xFF;
mCurrentState.blur = 0xFF; mCurrentState.blur = 0xFF;
@ -464,7 +467,11 @@ void Layer::setGeometry(
// this gives us only the "orientation" component of the transform // this gives us only the "orientation" component of the transform
const State& s(getDrawingState()); const State& s(getDrawingState());
#if defined(QTI_BSP) && !defined(QCOM_BSP_LEGACY)
if (!isOpaque(s)) {
#else
if (!isOpaque(s) || s.alpha != 0xFF) { if (!isOpaque(s) || s.alpha != 0xFF) {
#endif
layer.setBlending(mPremultipliedAlpha ? layer.setBlending(mPremultipliedAlpha ?
HWC_BLENDING_PREMULT : HWC_BLENDING_PREMULT :
HWC_BLENDING_COVERAGE); HWC_BLENDING_COVERAGE);
@ -1027,6 +1034,17 @@ uint32_t Layer::doTransaction(uint32_t flags) {
if (flags & eDontUpdateGeometryState) { if (flags & eDontUpdateGeometryState) {
} else { } else {
Layer::State& editCurrentState(getCurrentState()); 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; editCurrentState.active = c.requested;
} }
@ -1064,10 +1082,15 @@ uint32_t Layer::setTransactionFlags(uint32_t flags) {
} }
bool Layer::setPosition(float x, float y) { 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; return false;
mCurrentState.sequence++; mCurrentState.sequence++;
mCurrentState.transform.set(x, y); mCurrentState.requested.x = x;
mCurrentState.requested.y = y;
mCurrentState.requested.isPositionPending = true;
setTransactionFlags(eTransactionNeeded); setTransactionFlags(eTransactionNeeded);
return true; return true;
} }
@ -1290,6 +1313,19 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
(bufWidth == front.requested.w && (bufWidth == front.requested.w &&
bufHeight == front.requested.h)) 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 // Here we pretend the transaction happened by updating the
// current and drawing states. Drawing state is only accessed // current and drawing states. Drawing state is only accessed
// in this thread, no need to have it locked // 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 // Remove any stale buffers that have been dropped during
// updateTexImage // updateTexImage
while (mQueueItems[0].mFrameNumber != currentFrameNumber) { while ((mQueuedFrames > 0) && (mQueueItems[0].mFrameNumber != currentFrameNumber)) {
mQueueItems.removeAt(0); mQueueItems.removeAt(0);
android_atomic_dec(&mQueuedFrames); android_atomic_dec(&mQueuedFrames);
} }
if (mQueuedFrames == 0) {
ALOGE("[%s] mQueuedFrames is zero !!", mName.string());
return outDirtyRegion;
}
mQueueItems.removeAt(0); mQueueItems.removeAt(0);
} }

View File

@ -95,11 +95,15 @@ public:
}; };
struct Geometry { struct Geometry {
float x;
float y;
uint32_t w; uint32_t w;
uint32_t h; uint32_t h;
bool isPositionPending;
Rect crop; Rect crop;
inline bool operator ==(const Geometry& rhs) const { 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 { inline bool operator !=(const Geometry& rhs) const {
return !operator ==(rhs); return !operator ==(rhs);
@ -158,8 +162,13 @@ public:
uint32_t getTransactionFlags(uint32_t flags); uint32_t getTransactionFlags(uint32_t flags);
uint32_t setTransactionFlags(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, void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh,
bool useIdentityTransform) const; bool useIdentityTransform) const;
#endif
Rect computeBounds(const Region& activeTransparentRegion) const; Rect computeBounds(const Region& activeTransparentRegion) const;
Rect computeBounds() const; Rect computeBounds() const;
@ -388,9 +397,14 @@ private:
// drawing // drawing
void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip, void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
float r, float g, float b, float alpha) const; 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, void drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
bool useIdentityTransform) const; bool useIdentityTransform) const;
#endif
// Temporary - Used only for LEGACY camera mode. // Temporary - Used only for LEGACY camera mode.
uint32_t getProducerStickyTransform() const; uint32_t getProducerStickyTransform() const;

View File

@ -25,6 +25,7 @@
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#include <time.h> #include <time.h>
#include <dlfcn.h>
#include <utils/Errors.h> #include <utils/Errors.h>
#include <utils/Log.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); texCoords[3] = vec2(1.0f, 1.0f);
} }
LayerBlur::LayerBlur(SurfaceFlinger* flinger, const sp<Client>& client, LayerBlur::LayerBlur(SurfaceFlinger* flinger, const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags) const String8& name, uint32_t w, uint32_t h, uint32_t flags)
: Layer(flinger, client, name, w, h, flags), mBlurMaskSampling(1), mBlurMaskAlphaThreshold(0.0f) : Layer(flinger, client, name, w, h, flags), mBlurMaskSampling(1),
,mLastFrameSequence(0) mBlurMaskAlphaThreshold(0.0f) ,mLastFrameSequence(0)
{ {
#ifdef UI_BLUR
mBlurToken = qtiblur::initBlurToken();
#endif
GLuint texnames[3]; GLuint texnames[3];
mFlinger->getRenderEngine().genTextures(3, texnames); mFlinger->getRenderEngine().genTextures(3, texnames);
mTextureCapture.init(Texture::TEXTURE_2D, texnames[0]); mTextureCapture.init(Texture::TEXTURE_2D, texnames[0]);
@ -108,9 +104,6 @@ LayerBlur::LayerBlur(SurfaceFlinger* flinger, const sp<Client>& client,
} }
LayerBlur::~LayerBlur() { LayerBlur::~LayerBlur() {
#ifdef UI_BLUR
qtiblur::releaseBlurToken(mBlurToken);
#endif
releaseFbo(mFboCapture); releaseFbo(mFboCapture);
releaseFbo(mFboMasking); releaseFbo(mFboMasking);
@ -168,18 +161,15 @@ void LayerBlur::onDraw(const sp<const DisplayDevice>& hw, const Region& /*clip*/
// blur // blur
size_t outTexWidth = mTextureBlur.getWidth(); size_t outTexWidth = mTextureBlur.getWidth();
size_t outTexHeight = mTextureBlur.getHeight(); size_t outTexHeight = mTextureBlur.getHeight();
#ifdef UI_BLUR if (mBlurImpl.blur(s.blur,
if (!qtiblur::blur(mBlurToken,
s.blur,
mTextureCapture.getTextureName(), mTextureCapture.getTextureName(),
mTextureCapture.getWidth(), mTextureCapture.getWidth(),
mTextureCapture.getHeight(), mTextureCapture.getHeight(),
mTextureBlur.getTextureName(), mTextureBlur.getTextureName(),
&outTexWidth, &outTexWidth,
&outTexHeight)) { &outTexHeight) != OK) {
return; return;
} }
#endif
// mTextureBlur now has "Blurred image" // mTextureBlur now has "Blurred image"
mTextureBlur.setDimensions(outTexWidth, outTexHeight); mTextureBlur.setDimensions(outTexWidth, outTexHeight);
@ -238,8 +228,7 @@ bool LayerBlur::captureScreen(const sp<const DisplayDevice>& hw, FBO& fbo, Textu
texture.getTextureName(), 0); texture.getTextureName(), 0);
mFlinger->getRenderEngine().clearWithColor(0.0f, 0.0f, 0.0f, 1.0f); mFlinger->getRenderEngine().clearWithColor(0.0f, 0.0f, 0.0f, 1.0f);
if (hw->isPanelInverseMounted()) rotation = (Transform::orientation_flags)(rotation ^ hw->getPanelMountFlip());
rotation = Transform::ROT_180;
mFlinger->renderScreenImplLocked( mFlinger->renderScreenImplLocked(
hw, hw,
Rect(0,0,width,height), 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;
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -20,15 +20,12 @@
#ifndef ANDROID_LAYER_BLUR_H #ifndef ANDROID_LAYER_BLUR_H
#define ANDROID_LAYER_BLUR_H #define ANDROID_LAYER_BLUR_H
#include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#include "Layer.h" #include "Layer.h"
#ifdef UI_BLUR
#include "Blur.h" // libuiblur.so
#endif
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
namespace android { namespace android {
@ -58,9 +55,37 @@ public:
virtual bool setBlurMaskAlphaThreshold(float alpha) { mBlurMaskAlphaThreshold = alpha; return true; } virtual bool setBlurMaskAlphaThreshold(float alpha) { mBlurMaskAlphaThreshold = alpha; return true; }
private: private:
#ifdef UI_BLUR class BlurImpl {
qtiblur::BLUR_TOKEN mBlurToken; public:
#endif
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; wp<Layer> mBlurMaskLayer;
int32_t mBlurMaskSampling; int32_t mBlurMaskSampling;
float mBlurMaskAlphaThreshold; float mBlurMaskAlphaThreshold;

View File

@ -74,6 +74,7 @@
#include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h" #include "DisplayHardware/HWComposer.h"
#include "ExSurfaceFlinger/ExHWComposer.h"
#include "DisplayHardware/VirtualDisplaySurface.h" #include "DisplayHardware/VirtualDisplaySurface.h"
#include "Effects/Daltonizer.h" #include "Effects/Daltonizer.h"
@ -82,6 +83,10 @@
#include <cutils/compiler.h> #include <cutils/compiler.h>
#include "DisplayUtils.h" #include "DisplayUtils.h"
#ifdef USES_HWC_SERVICES
#include "ExynosHWCService.h"
#endif
#define DISPLAY_COUNT 1 #define DISPLAY_COUNT 1
/* /*
@ -130,6 +135,10 @@ static sp<Layer> lastSurfaceViewLayer;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
#ifdef USES_HWC_SERVICES
static bool notifyPSRExit = true;
#endif
SurfaceFlinger::SurfaceFlinger() SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(), : BnSurfaceComposer(),
mTransactionFlags(0), mTransactionFlags(0),
@ -156,6 +165,7 @@ SurfaceFlinger::SurfaceFlinger()
mHWVsyncAvailable(false), mHWVsyncAvailable(false),
mDaltonize(false), mDaltonize(false),
mHasColorMatrix(false), mHasColorMatrix(false),
mHasSecondaryColorMatrix(false),
mHasPoweredOff(false), mHasPoweredOff(false),
mFrameBuckets(), mFrameBuckets(),
mTotalTime(0), 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 // formerly we would just kill the process, but we now ask it to exit so it
// can choose where to stop the animation. // can choose where to stop the animation.
property_set("service.bootanim.exit", "1"); 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) { void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
@ -797,6 +815,19 @@ void SurfaceFlinger::signalTransaction() {
} }
void SurfaceFlinger::signalLayerUpdate() { 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(); mEventQueue.invalidate();
} }
@ -981,6 +1012,9 @@ void SurfaceFlinger::handleMessageRefresh() {
doDebugFlashRegions(); doDebugFlashRegions();
doComposition(); doComposition();
postComposition(); postComposition();
#ifdef USES_HWC_SERVICES
notifyPSRExit = true;
#endif
} }
previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0); previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0);
@ -1193,7 +1227,7 @@ void SurfaceFlinger::setUpHWComposer() {
for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
const sp<Layer>& layer(currentLayers[i]); const sp<Layer>& layer(currentLayers[i]);
layer->setGeometry(hw, *cur); layer->setGeometry(hw, *cur);
if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) { if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix || mHasSecondaryColorMatrix) {
cur->setSkip(true); 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; if (!doComposeSurfaces(hw, dirtyRegion)) return;
} else { } else {
RenderEngine& engine(getRenderEngine()); RenderEngine& engine(getRenderEngine());
mat4 colorMatrix = mColorMatrix; mat4 colorMatrix = mColorMatrix;
if (mHasSecondaryColorMatrix) {
colorMatrix = mHasColorMatrix ? (colorMatrix * mSecondaryColorMatrix) : mSecondaryColorMatrix;
}
if (mDaltonize) { if (mDaltonize) {
colorMatrix = colorMatrix * mDaltonizer(); 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 // 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); const bool hasHwcComposition = hwc.hasHwcComposition(id);
#endif
if (hasHwcComposition) { if (hasHwcComposition) {
// when using overlays, we assume a fully transparent framebuffer // when using overlays, we assume a fully transparent framebuffer
// NOTE: we could reduce how much we need to clear, for instance // 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", result.appendFormat(" h/w composer %s and %s\n",
hwc.initCheck()==NO_ERROR ? "present" : "not present", hwc.initCheck()==NO_ERROR ? "present" : "not present",
(mDebugDisableHWC || mDebugRegion || mDaltonize (mDebugDisableHWC || mDebugRegion || mDaltonize
|| mHasColorMatrix) ? "disabled" : "enabled"); || mHasColorMatrix
|| mHasSecondaryColorMatrix) ? "disabled" : "enabled");
hwc.dump(result); hwc.dump(result);
/* /*
@ -3158,6 +3201,28 @@ status_t SurfaceFlinger::onTransact(
mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n)); mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
return NO_ERROR; 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; return err;
@ -3436,10 +3501,9 @@ void SurfaceFlinger::renderScreenImplLocked(
// make sure to clear all GL error flags // make sure to clear all GL error flags
engine.checkErrors(); engine.checkErrors();
if (DisplayDevice::DISPLAY_PRIMARY == hw->getDisplayType() && if (DisplayDevice::DISPLAY_PRIMARY == hw->getDisplayType()) {
hw->isPanelInverseMounted()) {
rotation = (Transform::orientation_flags) rotation = (Transform::orientation_flags)
(rotation ^ Transform::ROT_180); (rotation ^ hw->getPanelMountFlip());
} }
// set-up our viewport // set-up our viewport

View File

@ -146,6 +146,9 @@ private:
friend class DisplayEventConnection; friend class DisplayEventConnection;
friend class Layer; friend class Layer;
friend class LayerDim; friend class LayerDim;
#ifdef QTI_BSP
friend class ExLayer;
#endif
friend class MonitoredProducer; friend class MonitoredProducer;
friend class LayerBlur; friend class LayerBlur;
@ -553,6 +556,9 @@ private:
mat4 mColorMatrix; mat4 mColorMatrix;
bool mHasColorMatrix; bool mHasColorMatrix;
mat4 mSecondaryColorMatrix;
bool mHasSecondaryColorMatrix;
// Static screen stats // Static screen stats
bool mHasPoweredOff; bool mHasPoweredOff;
static const size_t NUM_BUCKETS = 8; // < 1-7, 7+ static const size_t NUM_BUCKETS = 8; // < 1-7, 7+

View File

@ -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);
}
}
} }