aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Coucheron <arco68@gmail.com>2017-04-18 14:44:08 +0200
committerdoc HD <doc.divxm@gmail.com>2017-04-20 07:09:47 +0300
commit0f18353c7114fe7296b0e269df5b74b902a7d10d (patch)
tree163db978256f965885afcb8fd7a950983c53a4b8
parent5f019d534a15b5819d69b29378cd571de395623c (diff)
Add shim for libc to fix camera crash
Change-Id: I607a6016bb3e290713b0faa10c6ee2f875d61158
-rw-r--r--libshims/Android.mk13
-rw-r--r--libshims/bionic/bionic_time_conversions.cpp22
-rw-r--r--libshims/bionic/pthread_cond.cpp220
-rw-r--r--libshims/private/bionic_futex.h45
-rw-r--r--libshims/private/bionic_time_conversions.h14
-rw-r--r--rootdir/init.qcom.rc2
-rw-r--r--serrano-common.mk1
7 files changed, 316 insertions, 1 deletions
diff --git a/libshims/Android.mk b/libshims/Android.mk
index 76fd264..bcc4111 100644
--- a/libshims/Android.mk
+++ b/libshims/Android.mk
@@ -22,3 +22,16 @@ LOCAL_MODULE := libshim_ril
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ bionic/bionic_time_conversions.cpp \
+ bionic/pthread_cond.cpp
+LOCAL_SHARED_LIBRARIES := libc
+LOCAL_MODULE := libshim_c
+LOCAL_CLANG := false
+LOCAL_CXX_STL := none
+LOCAL_SANITIZE := never
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libshims/bionic/bionic_time_conversions.cpp b/libshims/bionic/bionic_time_conversions.cpp
new file mode 100644
index 0000000..67d08dd
--- /dev/null
+++ b/libshims/bionic/bionic_time_conversions.cpp
@@ -0,0 +1,22 @@
+#include "private/bionic_time_conversions.h"
+
+#define NS_PER_S 1000000000
+
+void timespec_from_ms(timespec& ts, const int ms) {
+ ts.tv_sec = ms / 1000;
+ ts.tv_nsec = (ms % 1000) * 1000000;
+}
+
+bool timespec_from_absolute_timespec(timespec& ts, const timespec& abs_ts, clockid_t clock) {
+ clock_gettime(clock, &ts);
+ ts.tv_sec = abs_ts.tv_sec - ts.tv_sec;
+ ts.tv_nsec = abs_ts.tv_nsec - ts.tv_nsec;
+ if (ts.tv_nsec < 0) {
+ ts.tv_sec--;
+ ts.tv_nsec += NS_PER_S;
+ }
+ if (ts.tv_nsec < 0 || ts.tv_sec < 0) {
+ return false;
+ }
+ return true;
+}
diff --git a/libshims/bionic/pthread_cond.cpp b/libshims/bionic/pthread_cond.cpp
new file mode 100644
index 0000000..1e63def
--- /dev/null
+++ b/libshims/bionic/pthread_cond.cpp
@@ -0,0 +1,220 @@
+#include <pthread.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdatomic.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "private/bionic_futex.h"
+#include "private/bionic_time_conversions.h"
+
+// XXX *technically* there is a race condition that could allow
+// XXX a signal to be missed. If thread A is preempted in _wait()
+// XXX after unlocking the mutex and before waiting, and if other
+// XXX threads call signal or broadcast UINT_MAX/2 times (exactly),
+// XXX before thread A is scheduled again and calls futex_wait(),
+// XXX then the signal will be lost.
+
+// We use one bit in pthread_condattr_t (long) values as the 'shared' flag
+// and one bit for the clock type (CLOCK_REALTIME is ((clockid_t) 1), and
+// CLOCK_MONOTONIC is ((clockid_t) 0).). The rest of the bits are a counter.
+//
+// The 'value' field pthread_cond_t has the same layout.
+
+#define COND_SHARED_MASK 0x0001
+#define COND_CLOCK_MASK 0x0002
+#define COND_COUNTER_STEP 0x0004
+#define COND_FLAGS_MASK (COND_SHARED_MASK | COND_CLOCK_MASK)
+#define COND_COUNTER_MASK (~COND_FLAGS_MASK)
+
+#define COND_IS_SHARED(c) (((c) & COND_SHARED_MASK) != 0)
+#define COND_GET_CLOCK(c) (((c) & COND_CLOCK_MASK) >> 1)
+#define COND_SET_CLOCK(attr, c) ((attr) | (c << 1))
+
+int pthread_condattr_init(pthread_condattr_t* attr) {
+ *attr = 0;
+ *attr |= PTHREAD_PROCESS_PRIVATE;
+ *attr |= (CLOCK_REALTIME << 1);
+ return 0;
+}
+
+int pthread_condattr_getpshared(const pthread_condattr_t* attr, int* pshared) {
+ *pshared = static_cast<int>(COND_IS_SHARED(*attr));
+ return 0;
+}
+
+int pthread_condattr_setpshared(pthread_condattr_t* attr, int pshared) {
+ if (pshared != PTHREAD_PROCESS_SHARED && pshared != PTHREAD_PROCESS_PRIVATE) {
+ return EINVAL;
+ }
+
+ *attr |= pshared;
+ return 0;
+}
+
+int pthread_condattr_getclock(const pthread_condattr_t* attr, clockid_t* clock) {
+ *clock = COND_GET_CLOCK(*attr);
+ return 0;
+}
+
+int pthread_condattr_setclock(pthread_condattr_t* attr, clockid_t clock) {
+ if (clock != CLOCK_MONOTONIC && clock != CLOCK_REALTIME) {
+ return EINVAL;
+ }
+
+ *attr = COND_SET_CLOCK(*attr, clock);
+ return 0;
+}
+
+int pthread_condattr_destroy(pthread_condattr_t* attr) {
+ *attr = 0xdeada11d;
+ return 0;
+}
+
+struct pthread_cond_internal_t {
+ atomic_uint state;
+
+ bool process_shared() {
+ return COND_IS_SHARED(atomic_load_explicit(&state, memory_order_relaxed));
+ }
+
+ int get_clock() {
+ return COND_GET_CLOCK(atomic_load_explicit(&state, memory_order_relaxed));
+ }
+
+#if defined(__LP64__)
+ char __reserved[44];
+#endif
+};
+
+static_assert(sizeof(pthread_cond_t) == sizeof(pthread_cond_internal_t),
+ "pthread_cond_t should actually be pthread_cond_internal_t in implementation.");
+
+// For binary compatibility with old version of pthread_cond_t, we can't use more strict alignment
+// than 4-byte alignment.
+static_assert(alignof(pthread_cond_t) == 4,
+ "pthread_cond_t should fulfill the alignment requirement of pthread_cond_internal_t.");
+
+static pthread_cond_internal_t* __get_internal_cond(pthread_cond_t* cond_interface) {
+ return reinterpret_cast<pthread_cond_internal_t*>(cond_interface);
+}
+
+int pthread_cond_init(pthread_cond_t* cond_interface, const pthread_condattr_t* attr) {
+ pthread_cond_internal_t* cond = __get_internal_cond(cond_interface);
+
+ unsigned int init_state = 0;
+ if (attr != NULL) {
+ init_state = (*attr & COND_FLAGS_MASK);
+ }
+ atomic_init(&cond->state, init_state);
+
+ return 0;
+}
+
+int pthread_cond_destroy(pthread_cond_t* cond_interface) {
+ pthread_cond_internal_t* cond = __get_internal_cond(cond_interface);
+ atomic_store_explicit(&cond->state, 0xdeadc04d, memory_order_relaxed);
+ return 0;
+}
+
+// This function is used by pthread_cond_broadcast and
+// pthread_cond_signal to atomically decrement the counter
+// then wake up thread_count threads.
+static int __pthread_cond_pulse(pthread_cond_internal_t* cond, int thread_count) {
+ // We don't use a release/seq_cst fence here. Because pthread_cond_wait/signal can't be
+ // used as a method for memory synchronization by itself. It should always be used with
+ // pthread mutexes. Note that Spurious wakeups from pthread_cond_wait/timedwait may occur,
+ // so when using condition variables there is always a boolean predicate involving shared
+ // variables associated with each condition wait that is true if the thread should proceed.
+ // If the predicate is seen true before a condition wait, pthread_cond_wait/timedwait will
+ // not be called. That's why pthread_wait/signal pair can't be used as a method for memory
+ // synchronization. And it doesn't help even if we use any fence here.
+
+ // The increase of value should leave flags alone, even if the value can overflows.
+ atomic_fetch_add_explicit(&cond->state, COND_COUNTER_STEP, memory_order_relaxed);
+
+ __futex_wake_ex(&cond->state, cond->process_shared(), thread_count);
+ return 0;
+}
+
+static int __pthread_cond_timedwait_relative(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
+ const timespec* rel_timeout_or_null) {
+ unsigned int old_state = atomic_load_explicit(&cond->state, memory_order_relaxed);
+
+ pthread_mutex_unlock(mutex);
+ int status = __futex_wait_ex(&cond->state, cond->process_shared(), old_state, rel_timeout_or_null);
+ pthread_mutex_lock(mutex);
+
+ if (status == -ETIMEDOUT) {
+ return ETIMEDOUT;
+ }
+ return 0;
+}
+
+static int __pthread_cond_timedwait(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
+ const timespec* abs_timeout_or_null, clockid_t clock) {
+ timespec ts;
+ timespec* rel_timeout = NULL;
+
+ if (abs_timeout_or_null != NULL) {
+ rel_timeout = &ts;
+ if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, clock)) {
+ return ETIMEDOUT;
+ }
+ }
+
+ return __pthread_cond_timedwait_relative(cond, mutex, rel_timeout);
+}
+
+int pthread_cond_broadcast(pthread_cond_t* cond_interface) {
+ return __pthread_cond_pulse(__get_internal_cond(cond_interface), INT_MAX);
+}
+
+int pthread_cond_signal(pthread_cond_t* cond_interface) {
+ return __pthread_cond_pulse(__get_internal_cond(cond_interface), 1);
+}
+
+int pthread_cond_wait(pthread_cond_t* cond_interface, pthread_mutex_t* mutex) {
+ pthread_cond_internal_t* cond = __get_internal_cond(cond_interface);
+ return __pthread_cond_timedwait(cond, mutex, NULL, cond->get_clock());
+}
+
+int pthread_cond_timedwait(pthread_cond_t *cond_interface, pthread_mutex_t * mutex,
+ const timespec *abstime) {
+
+ pthread_cond_internal_t* cond = __get_internal_cond(cond_interface);
+ return __pthread_cond_timedwait(cond, mutex, abstime, cond->get_clock());
+}
+
+#if !defined(__LP64__)
+// TODO: this exists only for backward binary compatibility on 32 bit platforms.
+extern "C" int pthread_cond_timedwait_monotonic(pthread_cond_t* cond_interface,
+ pthread_mutex_t* mutex,
+ const timespec* abs_timeout) {
+
+ return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, abs_timeout,
+ CLOCK_MONOTONIC);
+}
+
+extern "C" int pthread_cond_timedwait_monotonic_np(pthread_cond_t* cond_interface,
+ pthread_mutex_t* mutex,
+ const timespec* abs_timeout) {
+ return pthread_cond_timedwait_monotonic(cond_interface, mutex, abs_timeout);
+}
+
+extern "C" int pthread_cond_timedwait_relative_np(pthread_cond_t* cond_interface,
+ pthread_mutex_t* mutex,
+ const timespec* rel_timeout) {
+
+ return __pthread_cond_timedwait_relative(__get_internal_cond(cond_interface), mutex, rel_timeout);
+}
+
+extern "C" int pthread_cond_timeout_np(pthread_cond_t* cond_interface,
+ pthread_mutex_t* mutex, unsigned ms) {
+ timespec ts;
+ timespec_from_ms(ts, ms);
+ return pthread_cond_timedwait_relative_np(cond_interface, mutex, &ts);
+}
+#endif // !defined(__LP64__)
diff --git a/libshims/private/bionic_futex.h b/libshims/private/bionic_futex.h
new file mode 100644
index 0000000..7fe90e3
--- /dev/null
+++ b/libshims/private/bionic_futex.h
@@ -0,0 +1,45 @@
+#ifndef _BIONIC_FUTEX_H
+#define _BIONIC_FUTEX_H
+
+#include <errno.h>
+#include <linux/futex.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <sys/cdefs.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+__BEGIN_DECLS
+
+struct timespec;
+
+static inline __always_inline int __futex(volatile void* ftx, int op, int value, const struct timespec* timeout) {
+ // Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.
+ int saved_errno = errno;
+ int result = syscall(__NR_futex, ftx, op, value, timeout);
+ if (__predict_false(result == -1)) {
+ result = -errno;
+ errno = saved_errno;
+ }
+ return result;
+}
+
+static inline int __futex_wake(volatile void* ftx, int count) {
+ return __futex(ftx, FUTEX_WAKE, count, NULL);
+}
+
+static inline int __futex_wake_ex(volatile void* ftx, bool shared, int count) {
+ return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL);
+}
+
+static inline int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) {
+ return __futex(ftx, FUTEX_WAIT, value, timeout);
+}
+
+static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value, const struct timespec* timeout) {
+ return __futex(ftx, shared ? FUTEX_WAIT : FUTEX_WAIT_PRIVATE, value, timeout);
+}
+
+__END_DECLS
+
+#endif /* _BIONIC_FUTEX_H */
diff --git a/libshims/private/bionic_time_conversions.h b/libshims/private/bionic_time_conversions.h
new file mode 100644
index 0000000..e4dfc0c
--- /dev/null
+++ b/libshims/private/bionic_time_conversions.h
@@ -0,0 +1,14 @@
+#ifndef _BIONIC_TIME_CONVERSIONS_H
+#define _BIONIC_TIME_CONVERSIONS_H
+
+#include <time.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+__LIBC_HIDDEN__ void timespec_from_ms(timespec& ts, const int ms);
+__LIBC_HIDDEN__ bool timespec_from_absolute_timespec(timespec& ts, const timespec& abs_ts, clockid_t clock);
+
+__END_DECLS
+
+#endif
diff --git a/rootdir/init.qcom.rc b/rootdir/init.qcom.rc
index 7bcede0..898cb73 100644
--- a/rootdir/init.qcom.rc
+++ b/rootdir/init.qcom.rc
@@ -31,7 +31,7 @@ import init.target.rc
import init.carrier.rc
on init
- export LD_SHIM_LIBS "/system/lib/libril.so|libshim_ril.so"
+ export LD_SHIM_LIBS "/system/lib/libril.so|libshim_ril.so:/system/bin/mm-qcamera-daemon|libshim_c.so"
# Set permissions for persist partition
mkdir /persist 0771 system system
diff --git a/serrano-common.mk b/serrano-common.mk
index 221779a..277eefe 100644
--- a/serrano-common.mk
+++ b/serrano-common.mk
@@ -125,6 +125,7 @@ PRODUCT_PACKAGES += \
# Shims
PRODUCT_PACKAGES += \
+ libshim_c \
libshim_ril
# Doze