summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2016-12-13 02:15:45 +0100
committerWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2016-12-13 02:15:45 +0100
commitd3ad4f1e64dfe162c03fbbbe79c21c3c20641f18 (patch)
treea21f7d76365795800eebfd006d34803a9304e04c
parentb2381c3e4b90d845d9713b7b29d64317b7f21ce8 (diff)
parentb22bca465e55618a949d9cbdea665a1a3a831241 (diff)
downloadframeworks_native-d3ad4f1e64dfe162c03fbbbe79c21c3c20641f18.zip
frameworks_native-d3ad4f1e64dfe162c03fbbbe79c21c3c20641f18.tar.gz
frameworks_native-d3ad4f1e64dfe162c03fbbbe79c21c3c20641f18.tar.bz2
Merge branch 'cm-13.0' of https://github.com/CyanogenMod/android_frameworks_native into replicant-6.0
-rw-r--r--build/phone-xxhdpi-3072-dalvik-heap.mk25
-rw-r--r--build/phone-xxhdpi-3072-hwui-memory.mk30
-rw-r--r--build/phone-xxxhdpi-3072-dalvik-heap.mk4
-rw-r--r--build/phone-xxxhdpi-4096-dalvik-heap.mk25
-rw-r--r--build/phone-xxxhdpi-4096-hwui-memory.mk30
-rw-r--r--cmds/dumpstate/dumpstate.c5
-rw-r--r--cmds/servicemanager/Android.mk2
-rw-r--r--cmds/servicemanager/service_manager.c11
-rw-r--r--include/input/Input.h13
-rw-r--r--include/ui/FrameStats.h1
-rw-r--r--libs/binder/IMemory.cpp18
-rw-r--r--libs/binder/IPCThreadState.cpp12
-rw-r--r--libs/binder/Parcel.cpp62
-rw-r--r--libs/gui/BufferQueueConsumer.cpp17
-rw-r--r--libs/gui/IGraphicBufferConsumer.cpp2
-rw-r--r--libs/gui/IGraphicBufferProducer.cpp1
-rw-r--r--libs/ui/Region.cpp5
-rw-r--r--opengl/libs/Android.mk4
-rw-r--r--services/inputflinger/InputDispatcher.cpp29
-rw-r--r--services/inputflinger/InputDispatcher.h9
-rw-r--r--services/inputflinger/InputReader.cpp3
-rw-r--r--services/inputflinger/InputWindow.cpp11
-rw-r--r--services/inputflinger/InputWindow.h2
-rw-r--r--services/sensorservice/SensorService.cpp4
-rw-r--r--services/surfaceflinger/Android.mk28
-rw-r--r--services/surfaceflinger/CleanSpec.mk51
-rw-r--r--services/surfaceflinger/DispSync.cpp34
-rw-r--r--services/surfaceflinger/DispSync.h7
-rw-r--r--services/surfaceflinger/DisplayDevice.cpp14
-rw-r--r--services/surfaceflinger/DisplayDevice.h8
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp16
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.h1
-rw-r--r--services/surfaceflinger/DisplayUtils.cpp27
-rw-r--r--services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.cpp30
-rw-r--r--services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.h4
-rw-r--r--services/surfaceflinger/ExSurfaceFlinger/ExLayer.cpp184
-rw-r--r--services/surfaceflinger/ExSurfaceFlinger/ExLayer.h32
-rw-r--r--services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.cpp4
-rw-r--r--services/surfaceflinger/Layer.cpp47
-rw-r--r--services/surfaceflinger/Layer.h16
-rw-r--r--services/surfaceflinger/LayerBlur.cpp103
-rw-r--r--services/surfaceflinger/LayerBlur.h39
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp76
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h6
-rw-r--r--services/surfaceflinger/tests/Transaction_test.cpp46
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);
+ }
+}
}