Subject: Collected Debian patches for libhybris
Author: Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>

The libhybris package is maintained in Git rather than maintaining
patches as separate files, and separating the patches doesn't seem to
be worth the effort.  They are therefore all included in this single
Debian patch.

For full commit history and separated commits, see the packaging Git
repository.
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/Android.common.mk
@@ -0,0 +1,10 @@
+# define ANDROID_VERSION MAJOR, MINOR and PATCH
+
+ANDROID_VERSION_MAJOR := $(word 1, $(subst ., , $(PLATFORM_VERSION)))
+ANDROID_VERSION_MINOR := $(word 2, $(subst ., , $(PLATFORM_VERSION)))
+ANDROID_VERSION_PATCH := $(word 3, $(subst ., , $(PLATFORM_VERSION)))
+
+LOCAL_CFLAGS += \
+	-DANDROID_VERSION_MAJOR=$(ANDROID_VERSION_MAJOR) \
+	-DANDROID_VERSION_MINOR=$(ANDROID_VERSION_MINOR) \
+	-DANDROID_VERSION_PATCH=$(ANDROID_VERSION_PATCH)
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/camera/Android.mk
+++ libhybris-0.1.0+git20151016+6d424c9/compat/camera/Android.mk
@@ -1,5 +1,6 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
 
 HYBRIS_PATH := $(LOCAL_PATH)/../../hybris
 
@@ -30,6 +31,11 @@ LOCAL_SRC_FILES := direct_camera_test.cp
 
 LOCAL_MODULE := direct_camera_test
 LOCAL_MODULE_TAGS := optional
+ifdef TARGET_2ND_ARCH
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(if $(filter false,$(BOARD_UBUNTU_PREFER_32_BIT)),$(LOCAL_MODULE)$(TARGET_2ND_ARCH_MODULE_SUFFIX),$(LOCAL_MODULE))
+LOCAL_MODULE_STEM_64 := $(if $(filter false,$(BOARD_UBUNTU_PREFER_32_BIT)),$(LOCAL_MODULE),$(LOCAL_MODULE)_64)
+endif
 
 LOCAL_C_INCLUDES := \
 	$(HYBRIS_PATH)/include \
@@ -43,6 +49,7 @@ LOCAL_SHARED_LIBRARIES := \
 	libis_compat_layer \
 	libsf_compat_layer \
 	libcamera_compat_layer \
+	libmedia_compat_layer \
 	libcutils \
 	libcamera_client \
 	libutils \
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/camera/camera_compatibility_layer.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/compat/camera/camera_compatibility_layer.cpp
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2013 Canonical Ltd
+ * Copyright (C) 2013-2014 Canonical Ltd
  *
  * 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
+ *     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,
@@ -14,9 +14,12 @@
  * limitations under the License.
  *
  * Authored by: Thomas Voß <thomas.voss@canonical.com>
- *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ *				Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ *				Jim Hodapp <jim.hodapp@canonical.com>
  */
 
+//#define LOG_NDEBUG 0
+
 #include <hybris/internal/camera_control.h>
 #include <hybris/camera/camera_compatibility_layer.h>
 #include <hybris/camera/camera_compatibility_layer_capabilities.h>
@@ -27,18 +30,41 @@
 #include <binder/ProcessState.h>
 #include <camera/Camera.h>
 #include <camera/CameraParameters.h>
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
 #include <gui/SurfaceTexture.h>
+#else
+#include <gui/GLConsumer.h>
+#endif
+#if ANDROID_VERSION_MAJOR>=5
+#include <gui/IGraphicBufferProducer.h>
+#endif
 #include <ui/GraphicBuffer.h>
 
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
 #undef LOG_TAG
 #define LOG_TAG "CameraCompatibilityLayer"
+#include <utils/Debug.h>
+#include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/Log.h>
+#include <utils/String16.h>
+
+#include <gui/NativeBufferAlloc.h>
+
+#include <cstring>
 
 #define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__)
 
-// From android::SurfaceTexture::FrameAvailableListener
-void CameraControl::onFrameAvailable()
+using android::CompileTimeAssert; // So COMPILE_TIME_ASSERT works
+
+// From android::GLConsumer::FrameAvailableListener
+#if ANDROID_VERSION_MAJOR==5 && ANDROID_VERSION_MINOR>=1 || ANDROID_VERSION_MAJOR>=6
+  void CameraControl::onFrameAvailable(const android::BufferItem& item)
+#else
+  void CameraControl::onFrameAvailable()
+#endif
 {
 	REPORT_FUNCTION();
 	if (listener)
@@ -95,6 +121,9 @@ void CameraControl::postData(
 		if (listener->on_data_compressed_image_cb)
 			listener->on_data_compressed_image_cb(data->pointer(), data->size(), listener->context);
 		break;
+	case CAMERA_MSG_PREVIEW_FRAME:
+		if (listener->on_preview_frame_cb)
+			listener->on_preview_frame_cb(data->pointer(), data->size(), listener->context);
 	default:
 		break;
 	}
@@ -137,54 +166,80 @@ sp<GraphicBuffer> NativeBufferAlloc::cre
 }
 }
 
-namespace
+int android_camera_get_number_of_devices()
 {
-
-android::sp<CameraControl> camera_control_instance;
-
+	REPORT_FUNCTION();
+	return android::Camera::getNumberOfCameras();
 }
 
-int android_camera_get_number_of_devices()
+int android_camera_get_device_info(int32_t camera_id, int* facing, int* orientation)
 {
 	REPORT_FUNCTION();
-	return android::Camera::getNumberOfCameras();
+
+	if (!facing || !orientation)
+		return android::BAD_VALUE;
+
+	COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CAMERA_FACING_BACK == static_cast<int>(BACK_FACING_CAMERA_TYPE));
+	COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CAMERA_FACING_FRONT == static_cast<int>(FRONT_FACING_CAMERA_TYPE));
+
+	android::CameraInfo ci;
+
+	int rv = android::Camera::getCameraInfo(camera_id, &ci);
+	if (rv != android::OK)
+		return rv;
+
+	*facing = ci.facing;
+	*orientation = ci.orientation;
+
+	return android::OK;
 }
 
 CameraControl* android_camera_connect_to(CameraType camera_type, CameraControlListener* listener)
 {
 	REPORT_FUNCTION();
 
-	int32_t camera_id;
-	int32_t camera_count = camera_id = android::Camera::getNumberOfCameras();
+	const int32_t camera_count = android::Camera::getNumberOfCameras();
 
-	for (camera_id = 0; camera_id < camera_count; camera_id++) {
+	for (int32_t camera_id = 0; camera_id < camera_count; camera_id++) {
 		android::CameraInfo ci;
 		android::Camera::getCameraInfo(camera_id, &ci);
 
-		if (ci.facing == camera_type)
-			break;
+		if (ci.facing != camera_type)
+			continue;
+
+		return android_camera_connect_by_id(camera_id, listener);
 	}
 
-	if (camera_id == camera_count)
+	return NULL;
+}
+
+CameraControl* android_camera_connect_by_id(int32_t camera_id, struct CameraControlListener* listener)
+{
+	if (camera_id < 0 || camera_id >= android::Camera::getNumberOfCameras())
 		return NULL;
 
-	CameraControl* cc = new CameraControl();
+	android::sp<CameraControl> cc = new CameraControl();
 	cc->listener = listener;
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR>=3 || ANDROID_VERSION_MAJOR==5 || ANDROID_VERSION_MAJOR>=6
+	cc->camera = android::Camera::connect(camera_id, android::String16("hybris"), android::Camera::USE_CALLING_UID);
+#else
 	cc->camera = android::Camera::connect(camera_id);
+#endif
 
 	if (cc->camera == NULL)
 		return NULL;
 
 	cc->camera_parameters = android::CameraParameters(cc->camera->getParameters());
 
-	camera_control_instance = cc;
-	cc->camera->setListener(camera_control_instance);
+	// android::Camera holds a strong reference to the listener, keeping
+	// |cc| alive
+	cc->camera->setListener(cc);
 	cc->camera->lock();
 
 	// TODO: Move this to a more generic component
 	android::ProcessState::self()->startThreadPool();
 
-	return cc;
+	return cc.get();
 }
 
 void android_camera_disconnect(CameraControl* control)
@@ -215,7 +270,9 @@ int android_camera_unlock(CameraControl*
 
 void android_camera_delete(CameraControl* control)
 {
-	delete control;
+	android::sp<android::Camera> camera = control->camera;
+	control->camera.clear();
+	camera.clear();
 }
 
 void android_camera_dump_parameters(CameraControl* control)
@@ -252,6 +309,35 @@ void android_camera_get_flash_mode(Camer
 		*mode = FLASH_MODE_OFF;
 }
 
+void android_camera_enumerate_supported_flash_modes(CameraControl* control, flash_mode_callback cb, void* ctx)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+	android::String8 raw_modes;
+	raw_modes = android::String8(
+			control->camera_parameters.get(
+				android::CameraParameters::KEY_SUPPORTED_FLASH_MODES));
+
+	const char delimiter[2] = ",";
+	char *token;
+	android::String8 mode;
+	char *raw_modes_mutable = strdup(raw_modes.string());
+
+	token = strtok(raw_modes_mutable, delimiter);
+
+	while (token != NULL) {
+		uint32_t index = flash_modes_lut.indexOfKey(mode);
+
+		mode = android::String8(token);
+		if (flash_modes_lut.indexOfKey(mode) >= 0) {
+			cb(ctx, flash_modes_lut.valueFor(mode));
+		}
+		token = strtok(NULL, delimiter);
+	}
+}
+
 void android_camera_set_white_balance_mode(CameraControl* control, WhiteBalanceMode mode)
 {
 	REPORT_FUNCTION();
@@ -291,6 +377,31 @@ void android_camera_set_scene_mode(Camer
 	control->camera->setParameters(control->camera_parameters.flatten());
 }
 
+void android_camera_enumerate_supported_scene_modes(CameraControl* control, scene_mode_callback cb, void* ctx)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+	android::String8 raw_modes;
+	raw_modes = android::String8(
+					control->camera_parameters.get(
+						android::CameraParameters::KEY_SUPPORTED_SCENE_MODES));
+
+	const char delimiter[2] = ",";
+	char *token;
+	android::String8 mode;
+	char *raw_modes_mutable = strdup(raw_modes.string());
+
+	token = strtok(raw_modes_mutable, delimiter);
+
+	while (token != NULL) {
+		mode = android::String8(token);
+		cb(ctx, scene_modes_lut.valueFor(mode));
+		token = strtok(NULL, delimiter);
+	}
+}
+
 void android_camera_get_scene_mode(CameraControl* control, SceneMode* mode)
 {
 	REPORT_FUNCTION();
@@ -445,6 +556,67 @@ void android_camera_get_picture_size(Cam
 	control->camera_parameters.getPictureSize(width, height);
 }
 
+void android_camera_set_thumbnail_size(struct CameraControl* control, int width, int height)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+
+	control->camera_parameters.set(
+			android::CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH,
+			width);
+	control->camera_parameters.set(
+			android::CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT,
+			height);
+	control->camera->setParameters(control->camera_parameters.flatten());
+}
+
+void android_camera_get_thumbnail_size(struct CameraControl* control, int* width, int* height)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+
+	*width = atoi(control->camera_parameters.get(android::CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH));
+	*height = atoi(control->camera_parameters.get(android::CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT));
+}
+
+void android_camera_enumerate_supported_thumbnail_sizes(struct CameraControl* control, size_callback cb, void* ctx)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+	// e.g. 800x600,320x240
+	android::String8 sizes = android::String8(
+			control->camera_parameters.get(
+				android::CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES));
+
+	const char delimiter[2] = ",";
+	const char size_delimiter[2] = "x";
+	char *token, *save_ptr, *save_ptr1;
+	int height = 0, width = 0;
+	char *sizes_mutable = strdup(sizes.string());
+
+	ALOGD("Supported thumbnail sizes: %s", sizes.string());
+	// Get the first <width>x<height to the left of ','
+	token = strtok_r(sizes_mutable, delimiter, &save_ptr);
+
+	while (token != NULL) {
+		// Parse <width>x<height> token
+		char *w = strtok_r(token, size_delimiter, &save_ptr1);
+		char *h = strtok_r(NULL, size_delimiter, &save_ptr1);
+		width = atoi(w);
+		height = atoi(h);
+		if (width > 0 && height > 0)
+			cb(ctx, width, height);
+		// Get the next <width>x<height> pair
+		token = strtok_r(NULL, delimiter, &save_ptr);
+	}
+}
+
 void android_camera_set_picture_size(CameraControl* control, int width, int height)
 {
 	REPORT_FUNCTION();
@@ -511,30 +683,72 @@ void android_camera_set_preview_texture(
 	assert(control);
 
 	static const bool allow_synchronous_mode = false;
+	static const bool is_controlled_by_app = true;
 
 	android::sp<android::NativeBufferAlloc> native_alloc(
 			new android::NativeBufferAlloc()
 			);
 
+#if ANDROID_VERSION_MAJOR>=5
+	android::sp<android::IGraphicBufferProducer> producer;
+	android::sp<android::IGraphicBufferConsumer> consumer;
+	android::BufferQueue::createBufferQueue(&producer, &consumer);
+#else
 	android::sp<android::BufferQueue> buffer_queue(
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
 			new android::BufferQueue(false, NULL, native_alloc)
+#else
+			new android::BufferQueue(NULL)
+#endif
 			);
+#endif
 
 	if (control->preview_texture == NULL) {
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
 		control->preview_texture = android::sp<android::SurfaceTexture>(
 				new android::SurfaceTexture(
+#else
+		control->preview_texture = android::sp<android::GLConsumer>(
+				new android::GLConsumer(
+#endif
+#if ANDROID_VERSION_MAJOR>=5
+					consumer,
+					texture_id,
+					GL_TEXTURE_EXTERNAL_OES,
+					true,
+					is_controlled_by_app));
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
 					texture_id,
 					allow_synchronous_mode,
 					GL_TEXTURE_EXTERNAL_OES,
 					true,
 					buffer_queue));
+#else
+					buffer_queue,
+					texture_id,
+					GL_TEXTURE_EXTERNAL_OES,
+					true,
+					is_controlled_by_app));
+#endif
 	}
 
 	control->preview_texture->setFrameAvailableListener(
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
 			android::sp<android::SurfaceTexture::FrameAvailableListener>(control));
+#else
+			android::sp<android::GLConsumer::FrameAvailableListener>(control));
+#endif
+
+#if ANDROID_VERSION_MAJOR>=5
+	control->camera->setPreviewTarget(producer);
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
 	control->camera->setPreviewTexture(control->preview_texture->getBufferQueue());
+#else
+	control->camera->setPreviewTarget(buffer_queue);
+#endif
 }
 
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
 void android_camera_set_preview_surface(CameraControl* control, SfSurface* surface)
 {
 	REPORT_FUNCTION();
@@ -544,6 +758,7 @@ void android_camera_set_preview_surface(
 	android::Mutex::Autolock al(control->guard);
 	control->camera->setPreviewDisplay(surface->surface);
 }
+#endif
 
 void android_camera_start_preview(CameraControl* control)
 {
@@ -630,6 +845,22 @@ void android_camera_take_snapshot(Camera
 	control->camera->takePicture(CAMERA_MSG_SHUTTER | CAMERA_MSG_COMPRESSED_IMAGE);
 }
 
+int android_camera_set_preview_callback_mode(CameraControl* control, PreviewCallbackMode mode)
+{
+	REPORT_FUNCTION();
+
+	if (!control)
+		return android::BAD_VALUE;
+
+	android::Mutex::Autolock al(control->guard);
+
+	control->camera->setPreviewCallbackFlags(
+		mode == PREVIEW_CALLBACK_ENABLED ?
+			CAMERA_FRAME_CALLBACK_FLAG_CAMCORDER : CAMERA_FRAME_CALLBACK_FLAG_NOOP);
+
+	return android::OK;
+}
+
 void android_camera_set_preview_format(CameraControl* control, CameraPixelFormat pf)
 {
 	REPORT_FUNCTION();
@@ -690,6 +921,39 @@ void android_camera_reset_focus_region(C
 	android_camera_set_focus_region(control, &region);
 }
 
+void android_camera_set_metering_region(
+                CameraControl* control,
+                MeteringRegion* region)
+{
+        REPORT_FUNCTION();
+        assert(control);
+
+        android::Mutex::Autolock al(control->guard);
+        static const char* metering_region_pattern = "(%d,%d,%d,%d,%d)";
+        static char metering_region[256];
+        snprintf(metering_region,
+                        sizeof(metering_region),
+                        metering_region_pattern,
+                        region->left,
+                        region->top,
+                        region->right,
+                        region->bottom,
+                        region->weight);
+
+        control->camera_parameters.set(
+                        android::CameraParameters::KEY_METERING_AREAS,
+                        metering_region);
+
+        control->camera->setParameters(control->camera_parameters.flatten());
+}
+
+void android_camera_reset_metering_region(CameraControl* control)
+{
+        static FocusRegion region = { 0, 0, 0, 0, 0 };
+
+        android_camera_set_metering_region(control, &region);
+}
+
 void android_camera_set_rotation(CameraControl* control, int rotation)
 {
 	REPORT_FUNCTION();
@@ -702,6 +966,30 @@ void android_camera_set_rotation(CameraC
 	control->camera->setParameters(control->camera_parameters.flatten());
 }
 
+void android_camera_set_location(CameraControl* control, const float* latitude, const float* longitude, const float* altitude, int timestamp, const char* method)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+	control->camera_parameters.setFloat(
+			android::CameraParameters::KEY_GPS_LATITUDE,
+			*latitude);
+	control->camera_parameters.setFloat(
+			android::CameraParameters::KEY_GPS_LONGITUDE,
+			*longitude);
+	control->camera_parameters.setFloat(
+			android::CameraParameters::KEY_GPS_ALTITUDE,
+			*altitude);
+	control->camera_parameters.set(
+			android::CameraParameters::KEY_GPS_TIMESTAMP,
+			timestamp);
+	control->camera_parameters.set(
+			android::CameraParameters::KEY_GPS_PROCESSING_METHOD,
+			method);
+	control->camera->setParameters(control->camera_parameters.flatten());
+}
+
 void android_camera_enumerate_supported_video_sizes(CameraControl* control, size_callback cb, void* ctx)
 {
 	REPORT_FUNCTION();
@@ -737,3 +1025,25 @@ void android_camera_set_video_size(Camer
 	control->camera_parameters.setVideoSize(width, height);
 	control->camera->setParameters(control->camera_parameters.flatten());
 }
+
+void android_camera_set_jpeg_quality(CameraControl* control, int quality)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+	control->camera_parameters.set(
+			android::CameraParameters::KEY_JPEG_QUALITY,
+			quality);
+	control->camera->setParameters(control->camera_parameters.flatten());
+}
+
+void android_camera_get_jpeg_quality(CameraControl* control, int* quality)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+	*quality = atoi(control->camera_parameters.get(
+            android::CameraParameters::KEY_JPEG_QUALITY));
+}
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/camera/direct_camera_test.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/compat/camera/direct_camera_test.cpp
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2013 Canonical Ltd
+ * Copyright (C) 2013-2014 Canonical Ltd
  *
  * 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
+ *		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,
@@ -14,11 +14,13 @@
  * limitations under the License.
  *
  * Authored by: Thomas Voß <thomas.voss@canonical.com>
- *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ *				Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ *				Jim Hodapp <jim.hodapp@canonical.com>
  */
 
 #include <hybris/camera/camera_compatibility_layer.h>
 #include <hybris/camera/camera_compatibility_layer_capabilities.h>
+#include <hybris/media/media_recorder_layer.h>
 
 #include <hybris/input/input_stack_compatibility_layer.h>
 #include <hybris/input/input_stack_compatibility_layer_codes_key.h>
@@ -45,6 +47,11 @@
 int shot_counter = 1;
 int32_t current_zoom_level = 1;
 bool new_camera_frame_available = true;
+static CameraControl* camera_control = NULL;
+int camera_width = 0, camera_height = 0;
+int thumbnail_width = 0, thumbnail_height = 0;
+static MediaRecorderWrapper *recorder = NULL;
+bool recording = false;
 
 EffectMode next_effect()
 {
@@ -122,7 +129,7 @@ void jpeg_data_cb(void* data, uint32_t d
 	printf("%s: %d \n", __PRETTY_FUNCTION__, data_size);
 
 	char fn[256];
-	sprintf(fn, "/data/shot_%d.jpeg", shot_counter);
+	sprintf(fn, "/cache/shot_%d.jpeg", shot_counter);
 	int fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
 	write(fd, data, data_size);
 	close(fd);
@@ -135,131 +142,54 @@ void jpeg_data_cb(void* data, uint32_t d
 void size_cb(void* ctx, int width, int height)
 {
 	printf("Supported size: [%d,%d]\n", width, height);
+	if (width == 1024 && height == 768) {
+		camera_width = 1024;
+		camera_height = 768;
+	}
 }
 
-void preview_texture_needs_update_cb(void* ctx)
-{
-	new_camera_frame_available = true;
-}
-
-void on_new_input_event(Event* event, void* context)
-{
-    assert(context);
-
-    if (event->type == KEY_EVENT_TYPE && event->action == ISCL_KEY_EVENT_ACTION_UP) {
-	    printf("We have got a key event: %d \n", event->details.key.key_code);
-
-	    CameraControl* cc = static_cast<CameraControl*>(context);
-
-	    switch(event->details.key.key_code) {
-	    case ISCL_KEYCODE_VOLUME_UP:
-		    printf("\tZooming in now.\n");
-		    android_camera_start_zoom(cc, current_zoom_level+1);
-		    break;
-	    case ISCL_KEYCODE_VOLUME_DOWN:
-		    printf("\tZooming out now.\n");
-		    android_camera_start_zoom(cc, current_zoom_level-1);
-		    break;
-	    case ISCL_KEYCODE_POWER:
-		    printf("\tTaking a photo now.\n");
-		    android_camera_take_snapshot(cc);
-		    break;
-	    case ISCL_KEYCODE_HEADSETHOOK:
-		    printf("\tSwitching effect.\n");
-		    android_camera_set_effect_mode(cc, next_effect());
-	    }
-    } else if (event->type == MOTION_EVENT_TYPE &&
-		    event->details.motion.pointer_count == 1) {
-	    if ((event->action & ISCL_MOTION_EVENT_ACTION_MASK) == ISCL_MOTION_EVENT_ACTION_UP) {
-		    printf("\tMotion event(Action up): (%f, %f) \n",
-				    event->details.motion.pointer_coordinates[0].x,
-				    event->details.motion.pointer_coordinates[0].y);
-	    }
-
-	    if ((event->action & ISCL_MOTION_EVENT_ACTION_MASK) == ISCL_MOTION_EVENT_ACTION_DOWN) {
-		    printf("\tMotion event(Action down): (%f, %f) \n",
-				    event->details.motion.pointer_coordinates[0].x,
-				    event->details.motion.pointer_coordinates[0].y);
-	    }
-    }
-}
-
-struct ClientWithSurface
-{
-	SfClient* client;
-	SfSurface* surface;
-};
-
-ClientWithSurface client_with_surface(bool setup_surface_with_egl)
+void thumbnail_size_cb(void* ctx, int width, int height)
 {
-	ClientWithSurface cs = ClientWithSurface();
-
-	cs.client = sf_client_create();
-
-	if (!cs.client) {
-		printf("Problem creating client ... aborting now.");
-		return cs;
+	static bool do_once = true;
+	printf("Supported thumbnail size: [%d,%d]\n", width, height);
+	if (do_once) {
+		printf("Selecting thumbnail size: [%dx%d]\n", width, height);
+		thumbnail_width = width;
+		thumbnail_height = height;
 	}
-
-	static const size_t primary_display = 0;
-
-	SfSurfaceCreationParameters params = {
-		0,
-		0,
-		(int) sf_get_display_width(primary_display),
-		(int) sf_get_display_height(primary_display),
-		-1, //PIXEL_FORMAT_RGBA_8888,
-		15000,
-		0.5f,
-		setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL
-		"CameraCompatLayerTestSurface"
-	};
-
-	cs.surface = sf_surface_create(cs.client, &params);
-
-	if (!cs.surface) {
-		printf("Problem creating surface ... aborting now.");
-		return cs;
-	}
-
-	sf_surface_make_current(cs.surface);
-
-	return cs;
 }
 
-#define PRINT_GLERROR() printf("GL error@%d: %x\n", __LINE__, glGetError());
-
 struct RenderData
 {
 	static const char* vertex_shader()
 	{
 		return
-			"#extension GL_OES_EGL_image_external : require              \n"
-			"attribute vec4 a_position;                                  \n"
-			"attribute vec2 a_texCoord;                                  \n"
-			"uniform mat4 m_texMatrix;                                   \n"
-			"varying vec2 v_texCoord;                                    \n"
-			"varying float topDown;                                      \n"
-			"void main()                                                 \n"
-			"{                                                           \n"
-			"   gl_Position = a_position;                                \n"
-			"   v_texCoord = a_texCoord;                                 \n"
-			//                "   v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n"
-			//"   topDown = v_texCoord.y;                                  \n"
-			"}                                                           \n";
+			"#extension GL_OES_EGL_image_external : require				 \n"
+			"attribute vec4 a_position;									 \n"
+			"attribute vec2 a_texCoord;									 \n"
+			"uniform mat4 m_texMatrix;									 \n"
+			"varying vec2 v_texCoord;									 \n"
+			"varying float topDown;										 \n"
+			"void main()												 \n"
+			"{															 \n"
+			"	gl_Position = a_position;								 \n"
+			"	v_texCoord = a_texCoord;								 \n"
+			//				  "   v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n"
+			//"   topDown = v_texCoord.y;								   \n"
+			"}															 \n";
 	}
 
 	static const char* fragment_shader()
 	{
 		return
-			"#extension GL_OES_EGL_image_external : require      \n"
-			"precision mediump float;                            \n"
-			"varying vec2 v_texCoord;                            \n"
-			"uniform samplerExternalOES s_texture;               \n"
-			"void main()                                         \n"
-			"{                                                   \n"
+			"#extension GL_OES_EGL_image_external : require		 \n"
+			"precision mediump float;							 \n"
+			"varying vec2 v_texCoord;							 \n"
+			"uniform samplerExternalOES s_texture;				 \n"
+			"void main()										 \n"
+			"{													 \n"
 			"  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
-			"}                                                   \n";
+			"}													 \n";
 	}
 
 	static GLuint loadShader(GLenum shaderType, const char* pSource)
@@ -354,6 +284,254 @@ struct RenderData
 	GLint matrix_loc;
 };
 
+
+static RenderData render_data;
+static EGLDisplay disp;
+static EGLSurface surface;
+
+void preview_texture_needs_update_cb(void* ctx)
+{
+	ALOGD("Updating preview texture");
+	new_camera_frame_available = true;
+	static GLfloat vVertices[] = { 0.0f, 0.0f, 0.0f, // Position 0
+		0.0f, 0.0f, // TexCoord 0
+		0.0f, 1.0f, 0.0f, // Position 1
+		0.0f, 1.0f, // TexCoord 1
+		1.0f, 1.0f, 0.0f, // Position 2
+		1.0f, 1.0f, // TexCoord 2
+		1.0f, 0.0f, 0.0f, // Position 3
+		1.0f, 0.0f // TexCoord 3
+	};
+
+	GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+	// Set the viewport
+	// Clear the color buffer
+	glClear(GL_COLOR_BUFFER_BIT);
+	// Use the program object
+	glUseProgram(render_data.program_object);
+	// Enable attributes
+	glEnableVertexAttribArray(render_data.position_loc);
+	glEnableVertexAttribArray(render_data.tex_coord_loc);
+	// Load the vertex position
+	glVertexAttribPointer(render_data.position_loc,
+			3,
+			GL_FLOAT,
+			GL_FALSE,
+			5 * sizeof(GLfloat),
+			vVertices);
+	// Load the texture coordinate
+	glVertexAttribPointer(render_data.tex_coord_loc,
+			2,
+			GL_FLOAT,
+			GL_FALSE,
+			5 * sizeof(GLfloat),
+			vVertices+3);
+
+	glActiveTexture(GL_TEXTURE0);
+	// Set the sampler texture unit to 0
+	glUniform1i(render_data.sampler_loc, 0);
+	glUniform1i(render_data.matrix_loc, 0);
+	ALOGD("Updating the preview texture");
+	if (camera_control != NULL)
+		android_camera_update_preview_texture(camera_control);
+	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+	glDisableVertexAttribArray(render_data.position_loc);
+	glDisableVertexAttribArray(render_data.tex_coord_loc);
+
+	eglSwapBuffers(disp, surface);
+}
+
+static void errorCB(void *context)
+{
+	ALOGE("Error while recording.");
+}
+
+static MediaRecorderWrapper *start_video_recording(CameraControl *camera_control)
+{
+	int ret = 0;
+	struct MediaRecorderWrapper *recorder = android_media_new_recorder();
+	android_recorder_set_error_cb(recorder, &errorCB, NULL);
+
+	ALOGD("Unlocking camera");
+	android_camera_unlock(camera_control);
+	if (recorder == NULL)
+		ALOGW("recorder is NULL: %d", __LINE__);
+
+	ret = android_recorder_setCamera(recorder, camera_control);
+	if (ret < 0) {
+		ALOGE("android_recorder_setCamera() failed");
+		return NULL;
+	}
+	ret = android_recorder_setAudioSource(recorder, ANDROID_AUDIO_SOURCE_CAMCORDER);
+	if (ret < 0) {
+		ALOGE("android_recorder_setAudioSource() failed");
+		return NULL;
+	}
+	ret = android_recorder_setVideoSource(recorder, ANDROID_VIDEO_SOURCE_CAMERA);
+	if (ret < 0) {
+		ALOGE("android_recorder_setVideoSource() failed");
+		return NULL;
+	}
+	ret = android_recorder_setOutputFormat(recorder, ANDROID_OUTPUT_FORMAT_MPEG_4);
+	if (ret < 0) {
+		ALOGE("android_recorder_setOutputFormat() failed");
+		return NULL;
+	}
+	ret = android_recorder_setAudioEncoder(recorder, ANDROID_AUDIO_ENCODER_AAC);
+	if (ret < 0) {
+		ALOGE("android_recorder_setAudioEncoder() failed");
+		return NULL;
+	}
+	ret = android_recorder_setVideoEncoder(recorder, ANDROID_VIDEO_ENCODER_H264);
+	if (ret < 0) {
+		ALOGE("android_recorder_setVideoEncoder() failed");
+		return NULL;
+	}
+	int fd = -1;
+	char *out_file = "/cache/test_recording.mp4";
+	fd = open(out_file, O_WRONLY | O_CREAT,
+			  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+	if (fd < 0) {
+		ALOGE("Couldn't open output video file for recording: %s", out_file);
+		return NULL;
+	}
+	ret = android_recorder_setOutputFile(recorder, fd);
+	if (ret < 0) {
+		ALOGE("android_recorder_setOutputFile() failed");
+		return NULL;
+	}
+	ret = android_recorder_setVideoSize(recorder, camera_width, camera_height);
+	if (ret < 0) {
+		ALOGE("android_recorder_setVideoSize() failed");
+		return NULL;
+	}
+	ret = android_recorder_setVideoFrameRate(recorder, 30);
+	if (ret < 0) {
+		ALOGE("android_recorder_setVideoFrameRate() failed");
+		return NULL;
+	}
+	android_recorder_setParameters(recorder, "video-param-encoding-bitrate=5505024"); // 7*1024*768
+	android_recorder_setParameters(recorder, "audio-param-encoding-bitrate=48000");
+	android_recorder_setParameters(recorder, "audio-param-number-of-channels=2");
+	android_recorder_setParameters(recorder, "audio-param-sampling-rate=96000");
+	android_recorder_setParameters(recorder, "video-param-rotation-angle-degrees=90");
+	ALOGD("Preparing video recording");
+	ret = android_recorder_prepare(recorder);
+	if (ret < 0) {
+		ALOGE("android_recorder_prepare() failed");
+		return NULL;
+	}
+	ALOGD("Starting video recording");
+	ret = android_recorder_start(recorder);
+	if (ret < 0) {
+		ALOGE("android_recorder_start() failed");
+		return NULL;
+	}
+
+	return recorder;
+}
+
+static void stop_video_recording(MediaRecorderWrapper *recorder)
+{
+	if (recording) {
+		ALOGD("Stopping video recording");
+		android_recorder_stop(recorder);
+		android_recorder_reset(recorder);
+		android_recorder_release(recorder);
+		ALOGD("Stopped video recording");
+	}
+}
+
+void on_new_input_event(Event* event, void* context)
+{
+	assert(context);
+
+	if (event->type == KEY_EVENT_TYPE && event->action == ISCL_KEY_EVENT_ACTION_UP) {
+		printf("We got a key event: %d \n", event->details.key.key_code);
+
+		CameraControl* cc = static_cast<CameraControl*>(context);
+
+		switch(event->details.key.key_code) {
+		case ISCL_KEYCODE_VOLUME_UP:
+			printf("Starting video recording to /cache/test_recording.mp4\n");
+			start_video_recording(cc);
+			recording = true;
+			break;
+		case ISCL_KEYCODE_VOLUME_DOWN:
+			printf("Stopping video recording\n");
+			stop_video_recording(recorder);
+			recording = false;
+			break;
+		case ISCL_KEYCODE_POWER:
+			printf("\tTaking a photo now.\n");
+			android_camera_take_snapshot(cc);
+			break;
+		case ISCL_KEYCODE_HEADSETHOOK:
+			printf("\tSwitching effect.\n");
+			android_camera_set_effect_mode(cc, next_effect());
+		}
+	} else if (event->type == MOTION_EVENT_TYPE &&
+			event->details.motion.pointer_count == 1) {
+		if ((event->action & ISCL_MOTION_EVENT_ACTION_MASK) == ISCL_MOTION_EVENT_ACTION_UP) {
+			printf("\tMotion event(Action up): (%f, %f) \n",
+					event->details.motion.pointer_coordinates[0].x,
+					event->details.motion.pointer_coordinates[0].y);
+		}
+
+		if ((event->action & ISCL_MOTION_EVENT_ACTION_MASK) == ISCL_MOTION_EVENT_ACTION_DOWN) {
+			printf("\tMotion event(Action down): (%f, %f) \n",
+					event->details.motion.pointer_coordinates[0].x,
+					event->details.motion.pointer_coordinates[0].y);
+		}
+	}
+}
+
+struct ClientWithSurface
+{
+	SfClient* client;
+	SfSurface* surface;
+};
+
+ClientWithSurface client_with_surface(bool setup_surface_with_egl)
+{
+	ClientWithSurface cs = ClientWithSurface();
+
+	cs.client = sf_client_create();
+
+	if (!cs.client) {
+		printf("Problem creating client ... aborting now.");
+		return cs;
+	}
+
+	static const size_t primary_display = 0;
+
+	SfSurfaceCreationParameters params = {
+		0,
+		0,
+		(int) sf_get_display_width(primary_display),
+		(int) sf_get_display_height(primary_display),
+		-1, //PIXEL_FORMAT_RGBA_8888,
+		15000,
+		0.5f,
+		setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL
+		"CameraCompatLayerTestSurface"
+	};
+
+	cs.surface = sf_surface_create(cs.client, &params);
+
+	if (!cs.surface) {
+		printf("Problem creating surface ... aborting now.");
+		return cs;
+	}
+
+	sf_surface_make_current(cs.surface);
+
+	return cs;
+}
+
+#define PRINT_GLERROR() printf("GL error@%d: %x\n", __LINE__, glGetError());
+
 int main(int argc, char** argv)
 {
 	CameraControlListener listener;
@@ -366,80 +544,112 @@ int main(int argc, char** argv)
 	listener.on_data_raw_image_cb = raw_data_cb;
 	listener.on_data_compressed_image_cb = jpeg_data_cb;
 	listener.on_preview_texture_needs_update_cb = preview_texture_needs_update_cb;
-	CameraControl* cc = android_camera_connect_to(FRONT_FACING_CAMERA_TYPE,
+	camera_control = android_camera_connect_to(BACK_FACING_CAMERA_TYPE,
 			&listener);
 
-	if (cc == NULL) {
+	if (camera_control == NULL) {
 		printf("Problem connecting to camera");
 		return 1;
 	}
-
-	listener.context = cc;
+	listener.context = camera_control;
 
 	AndroidEventListener event_listener;
 	event_listener.on_new_event = on_new_input_event;
-	event_listener.context = cc;
+	event_listener.context = camera_control;
 
-	InputStackConfiguration input_configuration = { true, 25000 };
+	InputStackConfiguration input_configuration = {
+		enable_touch_point_visualization : true,
+		default_layer_for_touch_point_visualization : 10000,
+		input_area_width : 1024,
+		input_area_height : 1024
+	};
 
 	android_input_stack_initialize(&event_listener, &input_configuration);
 	android_input_stack_start();
 
-	android_camera_dump_parameters(cc);
-	android_camera_enumerate_supported_picture_sizes(cc, size_cb, NULL);
-	android_camera_enumerate_supported_preview_sizes(cc, size_cb, NULL);
+	// Set the still photo size
+	android_camera_enumerate_supported_picture_sizes(camera_control, size_cb, NULL);
+	if (camera_width == 0 && camera_height == 0) {
+		camera_width = 320;
+		camera_height = 240;
+	}
+	android_camera_set_picture_size(camera_control, camera_width, camera_height);
+
+	// Set the still photo thumbnail size
+	android_camera_enumerate_supported_thumbnail_sizes(camera_control, thumbnail_size_cb, NULL);
+	if (thumbnail_width == 0 && thumbnail_height == 0) {
+		thumbnail_width = 320;
+		thumbnail_height = 240;
+	}
+	android_camera_set_thumbnail_size(camera_control, thumbnail_width, thumbnail_height);
+
+	AutoFocusMode af_mode;
+	android_camera_get_auto_focus_mode(camera_control, &af_mode);
+	printf("Current af mode: %d \n", af_mode);
+
+	int zoom;
+	android_camera_set_zoom(camera_control, 0);
+	android_camera_get_max_zoom(camera_control, &zoom);
+	printf("Max zoom: %d \n", zoom);
+
+	android_camera_enumerate_supported_video_sizes(camera_control, size_cb, NULL);
+	android_camera_enumerate_supported_preview_sizes(camera_control, size_cb, NULL);
+	android_camera_set_preview_size(camera_control, camera_width, camera_height);
 
 	int min_fps, max_fps, current_fps;
-	android_camera_get_preview_fps_range(cc, &min_fps, &max_fps);
+	android_camera_get_preview_fps_range(camera_control, &min_fps, &max_fps);
 	printf("Preview fps range: [%d,%d]\n", min_fps, max_fps);
-	android_camera_get_preview_fps(cc, &current_fps);
+	android_camera_get_preview_fps(camera_control, &current_fps);
 	printf("Current preview fps range: %d\n", current_fps);
 
-	android_camera_set_preview_size(cc, 960, 720);
+#if 0
+	android_camera_dump_parameters(camera_control);
+
+	android_camera_set_display_orientation(camera_control, 90);
 
 	int width, height;
-	android_camera_get_preview_size(cc, &width, &height);
+	android_camera_get_preview_size(camera_control, &width, &height);
 	printf("Current preview size: [%d,%d]\n", width, height);
-	android_camera_get_picture_size(cc, &width, &height);
+	android_camera_get_picture_size(camera_control, &width, &height);
 	printf("Current picture size: [%d,%d]\n", width, height);
-	int zoom;
-	android_camera_get_current_zoom(cc, &zoom);
+	android_camera_get_current_zoom(camera_control, &zoom);
 	printf("Current zoom: %d \n", zoom);
-	android_camera_get_max_zoom(cc, &zoom);
-	printf("Max zoom: %d \n", zoom);
 
 	EffectMode effect_mode;
 	FlashMode flash_mode;
 	WhiteBalanceMode wb_mode;
-	SceneMode scene_mode;
-	AutoFocusMode af_mode;
+	//SceneMode scene_mode;
 	CameraPixelFormat pixel_format;
-	android_camera_get_effect_mode(cc, &effect_mode);
-	android_camera_get_flash_mode(cc, &flash_mode);
-	android_camera_get_white_balance_mode(cc, &wb_mode);
-	android_camera_get_scene_mode(cc, &scene_mode);
-	android_camera_get_auto_focus_mode(cc, &af_mode);
-	android_camera_get_preview_format(cc, &pixel_format);
+	android_camera_get_effect_mode(camera_control, &effect_mode);
 	printf("Current effect mode: %d \n", effect_mode);
+	android_camera_get_flash_mode(camera_control, &flash_mode);
 	printf("Current flash mode: %d \n", flash_mode);
-	printf("Current wb mode: %d \n", wb_mode);
+	android_camera_get_white_balance_mode(camera_control, &wb_mode);
+	ALOGD("Current wb mode: %d \n", wb_mode);
+#if 0
+	// Disabled, causes the test app to crash
+	android_camera_get_scene_mode(camera_control, &scene_mode);
 	printf("Current scene mode: %d \n", scene_mode);
-	printf("Current af mode: %d \n", af_mode);
+#endif
+	android_camera_get_preview_format(camera_control, &pixel_format);
 	printf("Current preview pixel format: %d \n", pixel_format);
-	//android_camera_set_focus_region(cc, -200, -200, 200, 200, 300);
+	//android_camera_set_focus_region(camera_control, -200, -200, 200, 200, 300);
+#endif
 
+	printf("Creating client with surface");
 	ClientWithSurface cs = client_with_surface(true /* Associate surface with egl. */);
 
 	if (!cs.surface) {
 		printf("Problem acquiring surface for preview");
 		return 1;
 	}
+	printf("Finished creating client with surface\n");
 
-	EGLDisplay disp = sf_client_get_egl_display(cs.client);
-	EGLSurface surface = sf_surface_get_egl_surface(cs.surface);
+	disp = sf_client_get_egl_display(cs.client);
+	surface = sf_surface_get_egl_surface(cs.surface);
 
-	RenderData render_data;
 	GLuint preview_texture_id;
+	printf("Getting a texture id\n");
 	glGenTextures(1, &preview_texture_id);
 	glClearColor(1.0, 0., 0.5, 1.);
 	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -448,68 +658,26 @@ int main(int argc, char** argv)
 			GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 	glTexParameteri(
 			GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-	android_camera_set_preview_texture(cc, preview_texture_id);
-	android_camera_set_effect_mode(cc, EFFECT_MODE_SEPIA);
-	android_camera_set_flash_mode(cc, FLASH_MODE_AUTO);
-	android_camera_set_auto_focus_mode(cc, AUTO_FOCUS_MODE_CONTINUOUS_PICTURE);
-	android_camera_start_preview(cc);
+	printf("About to set preview texture\n");
+	android_camera_set_preview_texture(camera_control, preview_texture_id);
+#if 0
+	android_camera_set_effect_mode(camera_control, EFFECT_MODE_SEPIA);
+	android_camera_set_flash_mode(camera_control, FLASH_MODE_AUTO);
+	android_camera_set_auto_focus_mode(camera_control, AUTO_FOCUS_MODE_CONTINUOUS_PICTURE);
+#endif
+	android_camera_start_preview(camera_control);
 
 	GLfloat transformation_matrix[16];
-	android_camera_get_preview_texture_transformation(cc, transformation_matrix);
+	android_camera_get_preview_texture_transformation(camera_control, transformation_matrix);
 	glUniformMatrix4fv(render_data.matrix_loc, 1, GL_FALSE, transformation_matrix);
 
 	printf("Started camera preview.\n");
 
-	while (true) {
-		/*if (new_camera_frame_available)
-		  {
-		  printf("Updating texture");
-		  new_camera_frame_available = false;
-		  }*/
-		static GLfloat vVertices[] = { 0.0f, 0.0f, 0.0f, // Position 0
-			0.0f, 0.0f, // TexCoord 0
-			0.0f, 1.0f, 0.0f, // Position 1
-			0.0f, 1.0f, // TexCoord 1
-			1.0f, 1.0f, 0.0f, // Position 2
-			1.0f, 1.0f, // TexCoord 2
-			1.0f, 0.0f, 0.0f, // Position 3
-			1.0f, 0.0f // TexCoord 3
-		};
-
-		GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
-
-		// Set the viewport
-		// Clear the color buffer
-		glClear(GL_COLOR_BUFFER_BIT);
-		// Use the program object
-		glUseProgram(render_data.program_object);
-		// Enable attributes
-		glEnableVertexAttribArray(render_data.position_loc);
-		glEnableVertexAttribArray(render_data.tex_coord_loc);
-		// Load the vertex position
-		glVertexAttribPointer(render_data.position_loc,
-				3,
-				GL_FLOAT,
-				GL_FALSE,
-				5 * sizeof(GLfloat),
-				vVertices);
-		// Load the texture coordinate
-		glVertexAttribPointer(render_data.tex_coord_loc,
-				2,
-				GL_FLOAT,
-				GL_FALSE,
-				5 * sizeof(GLfloat),
-				vVertices+3);
-
-		glActiveTexture(GL_TEXTURE0);
-		// Set the sampler texture unit to 0
-		glUniform1i(render_data.sampler_loc, 0);
-		glUniform1i(render_data.matrix_loc, 0);
-		android_camera_update_preview_texture(cc);
-		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
-		glDisableVertexAttribArray(render_data.position_loc);
-		glDisableVertexAttribArray(render_data.tex_coord_loc);
-
-		eglSwapBuffers(disp, surface);
+	while (1) {
+		usleep(50);
 	}
+
+	stop_video_recording(recorder);
+	android_camera_stop_preview(camera_control);
+	android_camera_disconnect(camera_control);
 }
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/input/Android.mk
+++ libhybris-0.1.0+git20151016+6d424c9/compat/input/Android.mk
@@ -1,5 +1,6 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
 
 HYBRIS_PATH := $(LOCAL_PATH)/../../hybris
 
@@ -20,8 +21,24 @@ LOCAL_SHARED_LIBRARIES := \
 
 LOCAL_C_INCLUDES := \
 	$(HYBRIS_PATH)/include \
-	external/skia/include/core \
-	frameworks/base/services/input
+	external/skia/include/core
+
+HAS_LIBINPUTSERVICE := $(shell test $(ANDROID_VERSION_MAJOR) -eq 4 -a $(ANDROID_VERSION_MINOR) -gt 2 && echo true)
+ifeq ($(HAS_LIBINPUTSERVICE),true)
+LOCAL_SHARED_LIBRARIES += libinputservice
+LOCAL_C_INCLUDES += frameworks/base/services/input
+endif
+
+HAS_LIBINPUTFLINGER := $(shell test $(ANDROID_VERSION_MAJOR) -ge 5 && echo true)
+ifeq ($(HAS_LIBINPUTFLINGER),true)
+LOCAL_SHARED_LIBRARIES += libinputflinger libinputservice
+LOCAL_C_INCLUDES += \
+	frameworks/base/libs/input \
+	frameworks/native/services
+endif
+
+
+
 
 include $(BUILD_SHARED_LIBRARY)
 
@@ -36,6 +53,11 @@ LOCAL_SRC_FILES:= \
 
 LOCAL_MODULE:= direct_input_test
 LOCAL_MODULE_TAGS := optional
+ifdef TARGET_2ND_ARCH
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(if $(filter false,$(BOARD_UBUNTU_PREFER_32_BIT)),$(LOCAL_MODULE)$(TARGET_2ND_ARCH_MODULE_SUFFIX),$(LOCAL_MODULE))
+LOCAL_MODULE_STEM_64 := $(if $(filter false,$(BOARD_UBUNTU_PREFER_32_BIT)),$(LOCAL_MODULE),$(LOCAL_MODULE)_64)
+endif
 
 LOCAL_C_INCLUDES := \
 	$(HYBRIS_PATH)/include \
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/input/input_compatibility_layer.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/compat/input/input_compatibility_layer.cpp
@@ -19,8 +19,14 @@
 
 #include <hybris/input/input_stack_compatibility_layer.h>
 
-#include "InputListener.h"
-#include "InputReader.h"
+#if ANDROID_VERSION_MAJOR<=4
+  #include "InputListener.h"
+  #include "InputReader.h"
+#elif ANDROID_VERSION_MAJOR>=5
+  #include "inputflinger/InputListener.h"
+  #include "inputflinger/InputReader.h"
+#endif
+
 #include "PointerController.h"
 #include "SpriteController.h"
 #include <gui/ISurfaceComposer.h>
@@ -48,10 +54,28 @@ public:
 
 	DefaultPointerControllerPolicy()
 	{
+#if ANDROID_VERSION_MAJOR<=4
 		bitmap.setConfig(
 				SkBitmap::kARGB_8888_Config,
 				bitmap_width,
 				bitmap_height);
+#elif ANDROID_VERSION_MAJOR==5
+		SkColorType ct = SkBitmapConfigToColorType(SkBitmap::kARGB_8888_Config);
+		bitmap.setInfo(
+				SkImageInfo::Make(bitmap_width,
+					bitmap_height,
+					ct,
+					SkAlphaType::kPremul_SkAlphaType),
+				0);
+#elif ANDROID_VERSION_MAJOR==6
+bitmap.setInfo(
+    SkImageInfo::Make(bitmap_width,
+      bitmap_height,
+      kRGBA_8888_SkColorType,
+      SkAlphaType::kPremul_SkAlphaType),
+    0);
+
+#endif
 		bitmap.allocPixels();
 
 		// Icon for spot touches
@@ -142,7 +166,11 @@ public:
 		mInputDevices = inputDevices;
 	}
 
+#if ANDROID_VERSION_MAJOR<=4
 	virtual android::sp<android::KeyCharacterMap> getKeyboardLayoutOverlay(const android::String8& inputDeviceDescriptor) {
+#elif ANDROID_VERSION_MAJOR>=5
+	virtual android::sp<android::KeyCharacterMap> getKeyboardLayoutOverlay(const android::InputDeviceIdentifier& identifier) {
+#endif
 		return NULL;
 	}
 
@@ -150,6 +178,12 @@ public:
 		return android::String8::empty();
 	}
 
+#if ANDROID_VERSION_MAJOR>=5
+	virtual android::TouchAffineTransformation getTouchAffineTransformation(const android::String8& inputDeviceDescriptor, int32_t surfaceRotation) {
+		return android::TouchAffineTransformation();
+	}
+#endif
+
 private:
 	android::sp<android::Looper> looper;
 	int default_layer_for_touch_point_visualization;
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/Android.mk
@@ -0,0 +1,173 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
+
+LOCAL_SRC_FILES := \
+	camera_service.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcameraservice \
+	libmedialogservice \
+	libcutils \
+	libmedia \
+	libmedia_compat_layer \
+	libmediaplayerservice \
+	libutils \
+	liblog \
+	libbinder
+
+LOCAL_C_INCLUDES := \
+    frameworks/av/media/libmediaplayerservice \
+    frameworks/av/services/medialog \
+    frameworks/av/services/camera/libcameraservice
+
+IS_ANDROID_5 := $(shell test $(ANDROID_VERSION_MAJOR) -ge 5 && echo true)
+
+ifeq ($(IS_ANDROID_5),true)
+LOCAL_C_INCLUDES += system/media/camera/include
+
+# All devices having Android 5.x also have MediaCodecSource
+# available so we don't have to put a switch for this into
+# any BoardConfig.mk
+BOARD_HAS_MEDIA_CODEC_SOURCE := true
+endif
+
+LOCAL_MODULE := camera_service
+
+ifdef TARGET_2ND_ARCH
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(if $(filter false,$(BOARD_UBUNTU_PREFER_32_BIT)),$(LOCAL_MODULE)$(TARGET_2ND_ARCH_MODULE_SUFFIX),$(LOCAL_MODULE))
+LOCAL_MODULE_STEM_64 := $(if $(filter false,$(BOARD_UBUNTU_PREFER_32_BIT)),$(LOCAL_MODULE),$(LOCAL_MODULE)_64)
+endif
+
+include $(BUILD_EXECUTABLE)
+
+# -------------------------------------------------
+
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
+
+HYBRIS_PATH := $(LOCAL_PATH)/../../hybris
+
+LOCAL_CFLAGS += -std=gnu++0x
+
+ifeq ($(BOARD_HAS_MEDIA_RECORDER_PAUSE),true)
+LOCAL_CFLAGS += -DBOARD_HAS_MEDIA_RECORDER_PAUSE
+endif
+ifeq ($(BOARD_HAS_MEDIA_RECORDER_RESUME),true)
+LOCAL_CFLAGS += -DBOARD_HAS_MEDIA_RECORDER_RESUME
+endif
+
+LOCAL_SRC_FILES:= \
+	media_compatibility_layer.cpp \
+	media_codec_layer.cpp \
+	media_codec_list.cpp \
+	media_format_layer.cpp \
+	surface_texture_client_hybris.cpp \
+	decoding_service.cpp \
+	media_recorder_layer.cpp \
+	media_recorder.cpp \
+	media_recorder_client.cpp \
+	media_recorder_factory.cpp \
+	media_recorder_observer.cpp \
+	media_buffer_layer.cpp \
+	media_message_layer.cpp \
+	media_meta_data_layer.cpp
+
+ifeq ($(BOARD_HAS_MEDIA_CODEC_SOURCE),true)
+# MediaCodecSource support is only available starting with
+# Android 5.x so we have to limit support for it.
+LOCAL_SRC_FILES += media_codec_source_layer.cpp
+endif
+
+LOCAL_MODULE:= libmedia_compat_layer
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libcamera_client \
+	libutils \
+	libbinder \
+	libhardware \
+	libui \
+	libgui \
+	libstagefright \
+	libstagefright_foundation \
+	libEGL \
+	libGLESv2 \
+	libmedia \
+	libaudioutils \
+	libmediaplayerservice
+
+LOCAL_C_INCLUDES := \
+	$(HYBRIS_PATH)/include \
+	frameworks/base/media/libstagefright/include \
+	frameworks/base/include/media/stagefright \
+	frameworks/base/include/media \
+	frameworks/av/media \
+	frameworks/av/media/libstagefright/include \
+	frameworks/av/include \
+	frameworks/native/include \
+	system/media/audio_utils/include \
+	frameworks/av/services/camera/libcameraservice
+
+IS_ANDROID_5 := $(shell test $(ANDROID_VERSION_MAJOR) -ge 5 && echo true)
+ifeq ($(IS_ANDROID_5),true)
+LOCAL_C_INCLUDES += frameworks/native/include/media/openmax
+endif
+
+ifeq ($(strip $(MTK_CAMERA_BSP_SUPPORT)),yes)
+LOCAL_C_INCLUDES += $(TOP)/mediatek/kernel/include/linux/vcodec
+LOCAL_SHARED_LIBRARIES += \
+	libvcodecdrv
+
+LOCAL_C_INCLUDES+= \
+	$(TOP)/$(MTK_PATH_SOURCE)/frameworks-ext/av/media/libmediaplayerservice \
+	$(TOP)/$(MTK_PATH_SOURCE)/frameworks-ext/av/include \
+	$(TOP)/$(MTK_PATH_SOURCE)/frameworks-ext/av/media/libstagefright/include \
+	$(TOP)/$(MTK_PATH_PLATFORM)/frameworks/libmtkplayer \
+	$(TOP)/$(MTK_PATH_SOURCE)/frameworks/av/include
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+# -------------------------------------------------
+
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
+
+LOCAL_SRC_FILES:= \
+	direct_media_test.cpp
+
+LOCAL_MODULE:= direct_media_test
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_C_INCLUDES := \
+	$(HYBRIS_PATH)/include \
+	bionic \
+	bionic/libstdc++/include \
+	external/gtest/include \
+	external/stlport/stlport \
+	external/skia/include/core \
+	frameworks/base/include
+
+LOCAL_SHARED_LIBRARIES := \
+	libis_compat_layer \
+	libsf_compat_layer \
+	libmedia_compat_layer \
+	libcutils \
+	libutils \
+	libbinder \
+	libhardware \
+	libui \
+	libgui \
+	libEGL \
+	libGLESv2
+
+ifdef TARGET_2ND_ARCH
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(if $(filter false,$(BOARD_UBUNTU_PREFER_32_BIT)),$(LOCAL_MODULE)$(TARGET_2ND_ARCH_MODULE_SUFFIX),$(LOCAL_MODULE))
+LOCAL_MODULE_STEM_64 := $(if $(filter false,$(BOARD_UBUNTU_PREFER_32_BIT)),$(LOCAL_MODULE),$(LOCAL_MODULE)_64)
+endif
+
+include $(BUILD_EXECUTABLE)
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/SimplePlayer.cpp
@@ -0,0 +1,777 @@
+/*
+ * Copyright (C) 2012 The Android Open Source 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SimplePlayer"
+#include <utils/Log.h>
+
+#include "SimplePlayer.h"
+
+#include <gui/Surface.h>
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+#include <gui/SurfaceTextureClient.h>
+#endif
+#include <media/AudioTrack.h>
+#include <media/ICrypto.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/NativeWindowWrapper.h>
+#include <media/stagefright/NuMediaExtractor.h>
+
+#define USE_MEDIA_CODEC_LAYER
+
+namespace android {
+
+SimplePlayer::SimplePlayer()
+    : mState(UNINITIALIZED),
+      mDoMoreStuffGeneration(0),
+      mStartTimeRealUs(-1ll) {
+}
+
+SimplePlayer::~SimplePlayer() {
+}
+
+// static
+status_t PostAndAwaitResponse(
+        const sp<AMessage> &msg, sp<AMessage> *response) {
+    status_t err = msg->postAndAwaitResponse(response);
+    printf("%s\n", __PRETTY_FUNCTION__);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (!(*response)->findInt32("err", &err)) {
+        err = OK;
+    }
+
+    return err;
+}
+status_t SimplePlayer::setDataSource(const char *path) {
+    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
+    msg->setString("path", path);
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
+status_t SimplePlayer::setSurface(const sp<ISurfaceTexture> &surfaceTexture) {
+    sp<AMessage> msg = new AMessage(kWhatSetSurface, id());
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    sp<SurfaceTextureClient> surfaceTextureClient;
+    if (surfaceTexture != NULL) {
+        surfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
+    }
+#else
+    sp<Surface> surfaceTextureClient;
+    if (surfaceTexture != NULL) {
+        surfaceTextureClient = new Surface(surfaceTexture);
+    }
+#endif
+
+    msg->setObject(
+            "native-window", new NativeWindowWrapper(surfaceTextureClient));
+
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
+status_t SimplePlayer::prepare() {
+    sp<AMessage> msg = new AMessage(kWhatPrepare, id());
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
+status_t SimplePlayer::start() {
+    printf("%s\n", __PRETTY_FUNCTION__);
+    sp<AMessage> msg = new AMessage(kWhatStart, id());
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
+status_t SimplePlayer::stop() {
+    sp<AMessage> msg = new AMessage(kWhatStop, id());
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
+status_t SimplePlayer::reset() {
+    sp<AMessage> msg = new AMessage(kWhatReset, id());
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
+void SimplePlayer::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatSetDataSource:
+        {
+            status_t err;
+            if (mState != UNINITIALIZED) {
+                err = INVALID_OPERATION;
+            } else {
+                CHECK(msg->findString("path", &mPath));
+                mState = UNPREPARED;
+            }
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatSetSurface:
+        {
+            status_t err;
+            if (mState != UNPREPARED) {
+                err = INVALID_OPERATION;
+            } else {
+                sp<RefBase> obj;
+                CHECK(msg->findObject("native-window", &obj));
+
+                mNativeWindow = static_cast<NativeWindowWrapper *>(obj.get());
+
+                err = OK;
+            }
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatPrepare:
+        {
+            status_t err;
+            if (mState != UNPREPARED) {
+                err = INVALID_OPERATION;
+            } else {
+                err = onPrepare();
+
+                if (err == OK) {
+                    mState = STOPPED;
+                }
+            }
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatStart:
+        {
+            status_t err = OK;
+
+            if (mState == UNPREPARED) {
+                err = onPrepare();
+
+                if (err == OK) {
+                    mState = STOPPED;
+                }
+            }
+
+            if (err == OK) {
+                if (mState != STOPPED) {
+                    err = INVALID_OPERATION;
+                } else {
+                    err = onStart();
+
+                    if (err == OK) {
+                        mState = STARTED;
+                    }
+                }
+            }
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatStop:
+        {
+            status_t err;
+
+            if (mState != STARTED) {
+                err = INVALID_OPERATION;
+            } else {
+                err = onStop();
+
+                if (err == OK) {
+                    mState = STOPPED;
+                }
+            }
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatReset:
+        {
+            status_t err = OK;
+
+            if (mState == STARTED) {
+                CHECK_EQ(onStop(), (status_t)OK);
+                mState = STOPPED;
+            }
+
+            if (mState == STOPPED) {
+                err = onReset();
+                mState = UNINITIALIZED;
+            }
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatDoMoreStuff:
+        {
+            int32_t generation;
+            CHECK(msg->findInt32("generation", &generation));
+
+            if (generation != mDoMoreStuffGeneration) {
+                break;
+            }
+
+            status_t err = onDoMoreStuff();
+
+            if (err == OK) {
+                msg->post(10000ll);
+            }
+            break;
+        }
+
+        default:
+            TRESPASS();
+    }
+}
+
+status_t SimplePlayer::onPrepare() {
+    CHECK_EQ(mState, UNPREPARED);
+    printf("%s\n", __PRETTY_FUNCTION__);
+
+    mExtractor = new NuMediaExtractor;
+
+    status_t err = mExtractor->setDataSource(mPath.c_str());
+
+    if (err != OK) {
+        mExtractor.clear();
+        return err;
+    }
+
+    if (mCodecLooper == NULL) {
+        mCodecLooper = new ALooper;
+        mCodecLooper->start();
+    }
+
+    bool haveAudio = false;
+    bool haveVideo = false;
+    for (size_t i = 0; i < mExtractor->countTracks(); ++i) {
+        sp<AMessage> format;
+        status_t err = mExtractor->getTrackFormat(i, &format);
+        CHECK_EQ(err, (status_t)OK);
+
+        AString mime;
+        int32_t width = 0, height = 0, maxInputSize = 0;
+        int64_t durationUs = 0;
+        sp<ABuffer> csd0, csd1;
+#ifdef USE_MEDIA_CODEC_LAYER
+        MediaFormat mformat;
+#endif
+        CHECK(format->findString("mime", &mime));
+
+        if (!haveAudio && !strncasecmp(mime.c_str(), "audio/", 6)) {
+            //haveAudio = true;
+            printf("*** Have audio but skipping it!\n");
+            continue;
+        } else if (!haveVideo && !strncasecmp(mime.c_str(), "video/", 6)) {
+            haveVideo = true;
+            CHECK(format->findInt32("width", &width));
+            CHECK(format->findInt32("height", &height));
+            CHECK(format->findInt64("durationUs", &durationUs));
+            CHECK(format->findInt32("max-input-size", &maxInputSize));
+            CHECK(format->findBuffer("csd-0", &csd0));
+            CHECK(format->findBuffer("csd-1", &csd1));
+#ifdef USE_MEDIA_CODEC_LAYER
+            mformat = media_format_create_video_format(mime.c_str(), width, height, durationUs, maxInputSize);
+            media_format_set_byte_buffer(mformat, "csd-0", csd0->data(), csd0->size());
+            media_format_set_byte_buffer(mformat, "csd-1", csd1->data(), csd1->size());
+#endif
+        } else {
+            continue;
+        }
+
+        err = mExtractor->selectTrack(i);
+        CHECK_EQ(err, (status_t)OK);
+
+        CodecState *state =
+            &mStateByTrackIndex.editValueAt(
+                    mStateByTrackIndex.add(i, CodecState()));
+
+        state->mNumFramesWritten = 0;
+#ifdef USE_MEDIA_CODEC_LAYER
+        state->mCodecDelegate = media_codec_create_by_codec_type(mime.c_str());
+        state->mCodec = media_codec_get(state->mCodecDelegate);
+        CHECK(state->mCodecDelegate != NULL);
+#else
+        state->mCodec = MediaCodec::CreateByType(
+                mCodecLooper, mime.c_str(), false /* encoder */);
+#endif
+
+        CHECK(state->mCodec != NULL);
+
+#ifdef USE_MEDIA_CODEC_LAYER
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+        err = media_codec_configure(state->mCodecDelegate, mformat, mNativeWindow->getSurfaceTextureClient().get(), 0);
+#else
+        err = media_codec_configure(state->mCodecDelegate, mformat, mNativeWindow->getSurface().get(), 0);
+#endif
+#else
+        err = state->mCodec->configure(
+                format,
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+                mNativeWindow->getSurfaceTextureClient(),
+#else
+                mNativeWindow->getSurface(),
+#endif
+                NULL /* crypto */,
+                0 /* flags */);
+#endif
+
+        CHECK_EQ(err, (status_t)OK);
+
+        size_t j = 0;
+        sp<ABuffer> buffer;
+        // Place the CSD data into the source buffer
+        while (format->findBuffer(StringPrintf("csd-%d", j).c_str(), &buffer)) {
+            state->mCSD.push_back(buffer);
+
+            ++j;
+        }
+    }
+
+    for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) {
+        CodecState *state = &mStateByTrackIndex.editValueAt(i);
+
+#ifdef USE_MEDIA_CODEC_LAYER
+        status_t err = media_codec_start(state->mCodecDelegate);
+#else
+        status_t err = state->mCodec->start();
+#endif
+        CHECK_EQ(err, (status_t)OK);
+
+#ifdef USE_MEDIA_CODEC_LAYER
+        size_t nInputBuffers = media_codec_get_input_buffers_size(state->mCodecDelegate);
+        ALOGD("nInputBuffers: %u", nInputBuffers);
+        for (size_t i=0; i<nInputBuffers; i++)
+        {
+            uint8_t *data = media_codec_get_nth_input_buffer(state->mCodecDelegate, i);
+            CHECK(data != NULL);
+            size_t size = media_codec_get_nth_input_buffer_capacity(state->mCodecDelegate, i);
+            ALOGD("input buffer[%d] size: %d", i, size);
+            sp<ABuffer> buf = new ABuffer(data, size);
+            state->mBuffers[0].insertAt(new ABuffer(data, size), i);
+        }
+#else
+        err = state->mCodec->getInputBuffers(&state->mBuffers[0]);
+        CHECK_EQ(err, (status_t)OK);
+#endif
+
+        err = state->mCodec->getOutputBuffers(&state->mBuffers[1]);
+        CHECK_EQ(err, (status_t)OK);
+
+        for (size_t j = 0; j < state->mCSD.size(); ++j) {
+            const sp<ABuffer> &srcBuffer = state->mCSD.itemAt(j);
+
+            size_t index;
+#ifdef USE_MEDIA_CODEC_LAYER
+            err = media_codec_dequeue_input_buffer(state->mCodecDelegate, &index, -1ll);
+#else
+            err = state->mCodec->dequeueInputBuffer(&index, -1ll);
+#endif
+            CHECK_EQ(err, (status_t)OK);
+
+            const sp<ABuffer> &dstBuffer = state->mBuffers[0].itemAt(index);
+
+            CHECK_LE(srcBuffer->size(), dstBuffer->capacity());
+            dstBuffer->setRange(0, srcBuffer->size());
+            memcpy(dstBuffer->data(), srcBuffer->data(), srcBuffer->size());
+
+#ifdef USE_MEDIA_CODEC_LAYER
+            MediaCodecBufferInfo bufInfo;
+            bufInfo.index = index;
+            bufInfo.offset = 0;
+            bufInfo.size = dstBuffer->size();
+            bufInfo.presentation_time_us = 0ll;
+            bufInfo.flags = MediaCodec::BUFFER_FLAG_CODECCONFIG;
+
+            err = media_codec_queue_input_buffer(
+                    state->mCodecDelegate,
+                    &bufInfo);
+
+#else
+            err = state->mCodec->queueInputBuffer(
+                    index,
+                    0,
+                    dstBuffer->size(),
+                    0ll,
+                    MediaCodec::BUFFER_FLAG_CODECCONFIG);
+#endif
+            CHECK_EQ(err, (status_t)OK);
+        }
+    }
+
+    return OK;
+}
+
+status_t SimplePlayer::onStart() {
+    CHECK_EQ(mState, STOPPED);
+
+    mStartTimeRealUs = -1ll;
+
+    sp<AMessage> msg = new AMessage(kWhatDoMoreStuff, id());
+    msg->setInt32("generation", ++mDoMoreStuffGeneration);
+    msg->post();
+
+    return OK;
+}
+
+status_t SimplePlayer::onStop() {
+    CHECK_EQ(mState, STARTED);
+
+    ++mDoMoreStuffGeneration;
+
+    return OK;
+}
+
+status_t SimplePlayer::onReset() {
+    CHECK_EQ(mState, STOPPED);
+
+    for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) {
+        CodecState *state = &mStateByTrackIndex.editValueAt(i);
+
+        CHECK_EQ(state->mCodec->release(), (status_t)OK);
+    }
+
+    mStartTimeRealUs = -1ll;
+
+    mStateByTrackIndex.clear();
+    mCodecLooper.clear();
+    mExtractor.clear();
+    mNativeWindow.clear();
+    mPath.clear();
+
+    return OK;
+}
+
+status_t SimplePlayer::onDoMoreStuff() {
+    ALOGV("onDoMoreStuff");
+    for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) {
+        CodecState *state = &mStateByTrackIndex.editValueAt(i);
+
+        status_t err;
+        do {
+            size_t index;
+#ifdef USE_MEDIA_CODEC_LAYER
+            err = media_codec_dequeue_input_buffer(state->mCodecDelegate, &index, 0ll);
+#else
+            err = state->mCodec->dequeueInputBuffer(&index);
+#endif
+
+            if (err == OK) {
+                ALOGD("dequeued input buffer on track %d",
+                      mStateByTrackIndex.keyAt(i));
+
+                state->mAvailInputBufferIndices.push_back(index);
+            } else {
+                ALOGD("dequeueInputBuffer on track %d returned %d",
+                      mStateByTrackIndex.keyAt(i), err);
+            }
+        } while (err == OK);
+
+        do {
+#ifdef USE_MEDIA_CODEC_LAYER
+            BufferInfo info;
+            MediaCodecBufferInfo bufInfo;
+            err = media_codec_dequeue_output_buffer(
+                    state->mCodecDelegate,
+                    &bufInfo,
+                    0ll);
+
+            info.mIndex = bufInfo.index;
+            info.mOffset = bufInfo.offset;
+            info.mSize = bufInfo.size;
+            info.mPresentationTimeUs = bufInfo.presentation_time_us;
+            info.mFlags = bufInfo.flags;
+
+#else
+            BufferInfo info;
+            err = state->mCodec->dequeueOutputBuffer(
+                    &info.mIndex,
+                    &info.mOffset,
+                    &info.mSize,
+                    &info.mPresentationTimeUs,
+                    &info.mFlags);
+#endif
+
+            if (err == OK) {
+                ALOGV("dequeued output buffer on track %d",
+                      mStateByTrackIndex.keyAt(i));
+
+                state->mAvailOutputBufferInfos.push_back(info);
+            } else if (err == INFO_FORMAT_CHANGED) {
+                err = onOutputFormatChanged(mStateByTrackIndex.keyAt(i), state);
+                CHECK_EQ(err, (status_t)OK);
+            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
+                err = state->mCodec->getOutputBuffers(&state->mBuffers[1]);
+                CHECK_EQ(err, (status_t)OK);
+            } else {
+                ALOGV("dequeueOutputBuffer on track %d returned %d",
+                      mStateByTrackIndex.keyAt(i), err);
+            }
+        } while (err == OK
+                || err == INFO_FORMAT_CHANGED
+                || err == INFO_OUTPUT_BUFFERS_CHANGED);
+    }
+
+    for (;;) {
+        size_t trackIndex;
+        status_t err = mExtractor->getSampleTrackIndex(&trackIndex);
+
+        if (err != OK) {
+            ALOGI("encountered input EOS.");
+            break;
+        } else {
+            CodecState *state = &mStateByTrackIndex.editValueFor(trackIndex);
+
+            if (state->mAvailInputBufferIndices.empty()) {
+                break;
+            }
+
+            size_t index = *state->mAvailInputBufferIndices.begin();
+            state->mAvailInputBufferIndices.erase(
+                    state->mAvailInputBufferIndices.begin());
+
+            const sp<ABuffer> &dstBuffer =
+                state->mBuffers[0].itemAt(index);
+
+            err = mExtractor->readSampleData(dstBuffer);
+            CHECK_EQ(err, (status_t)OK);
+
+            int64_t timeUs;
+            CHECK_EQ(mExtractor->getSampleTime(&timeUs), (status_t)OK);
+
+#ifdef USE_MEDIA_CODEC_LAYER
+            MediaCodecBufferInfo bufInfo;
+            bufInfo.index = index;
+            bufInfo.offset = dstBuffer->offset();
+            bufInfo.size = dstBuffer->size();
+            bufInfo.presentation_time_us = timeUs;
+            bufInfo.flags = 0;
+
+            err = media_codec_queue_input_buffer(
+                    state->mCodecDelegate,
+                    &bufInfo);
+
+#else
+            err = state->mCodec->queueInputBuffer(
+                    index,
+                    dstBuffer->offset(),
+                    dstBuffer->size(),
+                    timeUs,
+                    0);
+#endif
+            CHECK_EQ(err, (status_t)OK);
+
+            ALOGV("enqueued input data on track %d", trackIndex);
+
+            err = mExtractor->advance();
+            CHECK_EQ(err, (status_t)OK);
+        }
+    }
+
+    int64_t nowUs = ALooper::GetNowUs();
+
+    if (mStartTimeRealUs < 0ll) {
+        mStartTimeRealUs = nowUs + 1000000ll;
+    }
+
+    for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) {
+        CodecState *state = &mStateByTrackIndex.editValueAt(i);
+
+        while (!state->mAvailOutputBufferInfos.empty()) {
+            BufferInfo *info = &*state->mAvailOutputBufferInfos.begin();
+
+            int64_t whenRealUs = info->mPresentationTimeUs + mStartTimeRealUs;
+            int64_t lateByUs = nowUs - whenRealUs;
+
+            if (lateByUs > -10000ll) {
+                bool release = true;
+
+                if (lateByUs > 30000ll) {
+                    ALOGI("track %d buffer late by %lld us, dropping.",
+                          mStateByTrackIndex.keyAt(i), lateByUs);
+                    state->mCodec->releaseOutputBuffer(info->mIndex);
+                } else {
+                    if (state->mAudioTrack != NULL) {
+                        const sp<ABuffer> &srcBuffer =
+                            state->mBuffers[1].itemAt(info->mIndex);
+
+                        renderAudio(state, info, srcBuffer);
+
+                        if (info->mSize > 0) {
+                            release = false;
+                        }
+                    }
+
+                    if (release) {
+#ifdef USE_MEDIA_CODEC_LAYER
+                        ALOGD("Rendering output buffer index %d and releasing", info->mIndex);
+                        state->mCodec->renderOutputBufferAndRelease(
+                                info->mIndex);
+#else
+                        ALOGD("Releasing output buffer index %d", info->mIndex);
+                        state->mCodec->releaseOutputBuffer(info->mIndex);
+#endif
+                    }
+                }
+
+                if (release) {
+                    state->mAvailOutputBufferInfos.erase(
+                            state->mAvailOutputBufferInfos.begin());
+
+                    info = NULL;
+                } else {
+                    break;
+                }
+            } else {
+                ALOGV("track %d buffer early by %lld us.",
+                      mStateByTrackIndex.keyAt(i), -lateByUs);
+                break;
+            }
+        }
+    }
+
+    return OK;
+}
+
+status_t SimplePlayer::onOutputFormatChanged(
+        size_t trackIndex, CodecState *state) {
+    sp<AMessage> format;
+    status_t err = state->mCodec->getOutputFormat(&format);
+
+    if (err != OK) {
+        return err;
+    }
+
+    AString mime;
+    CHECK(format->findString("mime", &mime));
+
+    if (!strncasecmp(mime.c_str(), "audio/", 6)) {
+        int32_t channelCount;
+        int32_t sampleRate;
+        CHECK(format->findInt32("channel-count", &channelCount));
+        CHECK(format->findInt32("sample-rate", &sampleRate));
+
+        state->mAudioTrack = new AudioTrack(
+                AUDIO_STREAM_MUSIC,
+                sampleRate,
+                AUDIO_FORMAT_PCM_16_BIT,
+                audio_channel_out_mask_from_count(channelCount),
+                0);
+
+        state->mNumFramesWritten = 0;
+    }
+
+    return OK;
+}
+
+void SimplePlayer::renderAudio(
+        CodecState *state, BufferInfo *info, const sp<ABuffer> &buffer) {
+    CHECK(state->mAudioTrack != NULL);
+
+    if (state->mAudioTrack->stopped()) {
+        state->mAudioTrack->start();
+    }
+
+    uint32_t numFramesPlayed;
+    CHECK_EQ(state->mAudioTrack->getPosition(&numFramesPlayed), (status_t)OK);
+
+    uint32_t numFramesAvailableToWrite =
+        state->mAudioTrack->frameCount()
+            - (state->mNumFramesWritten - numFramesPlayed);
+
+    size_t numBytesAvailableToWrite =
+        numFramesAvailableToWrite * state->mAudioTrack->frameSize();
+
+    size_t copy = info->mSize;
+    if (copy > numBytesAvailableToWrite) {
+        copy = numBytesAvailableToWrite;
+    }
+
+    if (copy == 0) {
+        return;
+    }
+
+    int64_t startTimeUs = ALooper::GetNowUs();
+
+    ssize_t nbytes = state->mAudioTrack->write(
+            buffer->base() + info->mOffset, copy);
+
+    CHECK_EQ(nbytes, (ssize_t)copy);
+
+    int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
+
+    uint32_t numFramesWritten = nbytes / state->mAudioTrack->frameSize();
+
+    if (delayUs > 2000ll) {
+        ALOGW("AudioTrack::write took %lld us, numFramesAvailableToWrite=%u, "
+              "numFramesWritten=%u",
+              delayUs, numFramesAvailableToWrite, numFramesWritten);
+    }
+
+    info->mOffset += nbytes;
+    info->mSize -= nbytes;
+
+    state->mNumFramesWritten += numFramesWritten;
+}
+
+}  // namespace android
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/SimplePlayer.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2012 The Android Open Source 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.
+ */
+
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AString.h>
+#include <utils/KeyedVector.h>
+
+#include <hybris/media/media_codec_layer.h>
+
+namespace android {
+
+struct ABuffer;
+struct ALooper;
+struct AudioTrack;
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+struct ISurfaceTexture;
+#else
+struct IGraphicBufferProducer;
+#endif
+struct MediaCodec;
+struct NativeWindowWrapper;
+struct NuMediaExtractor;
+
+struct SimplePlayer : public AHandler {
+    SimplePlayer();
+
+    status_t setDataSource(const char *path);
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    status_t setSurface(const sp<ISurfaceTexture> &surfaceTexture);
+#else
+    status_t setSurface(const sp<IGraphicBufferProducer> &surfaceTexture);
+#endif
+    status_t prepare();
+    status_t start();
+    status_t stop();
+    status_t reset();
+
+protected:
+    virtual ~SimplePlayer();
+
+    virtual void onMessageReceived(const sp<AMessage> &msg);
+
+private:
+    enum State {
+        UNINITIALIZED,
+        UNPREPARED,
+        STOPPED,
+        STARTED
+    };
+
+    enum {
+        kWhatSetDataSource,
+        kWhatSetSurface,
+        kWhatPrepare,
+        kWhatStart,
+        kWhatStop,
+        kWhatReset,
+        kWhatDoMoreStuff,
+    };
+
+    struct BufferInfo {
+        size_t mIndex;
+        size_t mOffset;
+        size_t mSize;
+        int64_t mPresentationTimeUs;
+        uint32_t mFlags;
+    };
+
+    struct CodecState
+    {
+        sp<MediaCodec> mCodec;
+        MediaCodecDelegate mCodecDelegate;
+        Vector<sp<ABuffer> > mCSD;
+        Vector<sp<ABuffer> > mBuffers[2];
+
+        List<size_t> mAvailInputBufferIndices;
+        List<BufferInfo> mAvailOutputBufferInfos;
+
+        sp<AudioTrack> mAudioTrack;
+        uint32_t mNumFramesWritten;
+    };
+
+    State mState;
+    AString mPath;
+    sp<NativeWindowWrapper> mNativeWindow;
+
+    sp<NuMediaExtractor> mExtractor;
+    sp<ALooper> mCodecLooper;
+    KeyedVector<size_t, CodecState> mStateByTrackIndex;
+    int32_t mDoMoreStuffGeneration;
+
+    int64_t mStartTimeRealUs;
+
+    status_t onPrepare();
+    status_t onStart();
+    status_t onStop();
+    status_t onReset();
+    status_t onDoMoreStuff();
+    status_t onOutputFormatChanged(size_t trackIndex, CodecState *state);
+
+    void renderAudio(
+            CodecState *state, BufferInfo *info, const sp<ABuffer> &buffer);
+
+    DISALLOW_EVIL_CONSTRUCTORS(SimplePlayer);
+};
+
+}  // namespace android
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/camera_service.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "CameraServiceCompatLayer"
+
+#include "media_recorder_factory.h"
+#include "media_recorder.h"
+
+#include <media/camera_record_service.h>
+#include <CameraService.h>
+
+#include <signal.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__)
+
+using namespace android;
+
+/*!
+ * \brief main() instantiates the MediaRecorderFactory Binder server and the CameraService
+ */
+int main(int argc, char** argv)
+{
+    signal(SIGPIPE, SIG_IGN);
+
+    ALOGV("Starting camera services (MediaRecorderFactory, CameraRecordService & CameraService)");
+
+    // Instantiate the in-process MediaRecorderFactory which is responsible
+    // for creating a new IMediaRecorder (MediaRecorder) instance over Binder
+    MediaRecorderFactory::instantiate();
+    // Enable audio recording for camera recording
+    CameraRecordService::instantiate();
+    CameraService::instantiate();
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/codec.cpp
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2012 The Android Open Source 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.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "codec"
+#include <utils/Log.h>
+
+#include "SimplePlayer.h"
+
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <media/ICrypto.h>
+#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/NuMediaExtractor.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayInfo.h>
+
+static void usage(const char *me) {
+    fprintf(stderr, "usage: %s [-a] use audio\n"
+                    "\t\t[-v] use video\n"
+                    "\t\t[-p] playback\n"
+                    "\t\t[-S] allocate buffers from a surface\n",
+                    me);
+
+    exit(1);
+}
+
+namespace android {
+
+struct CodecState {
+    sp<MediaCodec> mCodec;
+    Vector<sp<ABuffer> > mInBuffers;
+    Vector<sp<ABuffer> > mOutBuffers;
+    bool mSignalledInputEOS;
+    bool mSawOutputEOS;
+    int64_t mNumBuffersDecoded;
+    int64_t mNumBytesDecoded;
+    bool mIsAudio;
+};
+
+}  // namespace android
+
+static int decode(
+        const android::sp<android::ALooper> &looper,
+        const char *path,
+        bool useAudio,
+        bool useVideo,
+        const android::sp<android::Surface> &surface) {
+    using namespace android;
+
+    static int64_t kTimeout = 500ll;
+
+    sp<NuMediaExtractor> extractor = new NuMediaExtractor;
+    if (extractor->setDataSource(path) != OK) {
+        fprintf(stderr, "unable to instantiate extractor.\n");
+        return 1;
+    }
+
+    KeyedVector<size_t, CodecState> stateByTrack;
+
+    bool haveAudio = false;
+    bool haveVideo = false;
+    for (size_t i = 0; i < extractor->countTracks(); ++i) {
+        sp<AMessage> format;
+        status_t err = extractor->getTrackFormat(i, &format);
+        CHECK_EQ(err, (status_t)OK);
+
+        AString mime;
+        CHECK(format->findString("mime", &mime));
+
+        bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6);
+        bool isVideo = !strncasecmp(mime.c_str(), "video/", 6);
+
+        if (useAudio && !haveAudio && isAudio) {
+            haveAudio = true;
+        } else if (useVideo && !haveVideo && isVideo) {
+            haveVideo = true;
+        } else {
+            continue;
+        }
+
+        ALOGV("selecting track %d", i);
+
+        err = extractor->selectTrack(i);
+        CHECK_EQ(err, (status_t)OK);
+
+        CodecState *state =
+            &stateByTrack.editValueAt(stateByTrack.add(i, CodecState()));
+
+        state->mNumBytesDecoded = 0;
+        state->mNumBuffersDecoded = 0;
+        state->mIsAudio = isAudio;
+
+        state->mCodec = MediaCodec::CreateByType(
+                looper, mime.c_str(), false /* encoder */);
+
+        CHECK(state->mCodec != NULL);
+
+        err = state->mCodec->configure(
+                format, isVideo ? surface : NULL,
+                NULL /* crypto */,
+                0 /* flags */);
+
+        CHECK_EQ(err, (status_t)OK);
+
+        state->mSignalledInputEOS = false;
+        state->mSawOutputEOS = false;
+    }
+
+    CHECK(!stateByTrack.isEmpty());
+
+    int64_t startTimeUs = ALooper::GetNowUs();
+
+    for (size_t i = 0; i < stateByTrack.size(); ++i) {
+        CodecState *state = &stateByTrack.editValueAt(i);
+
+        sp<MediaCodec> codec = state->mCodec;
+
+        CHECK_EQ((status_t)OK, codec->start());
+
+        CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers));
+        CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers));
+
+        ALOGV("got %d input and %d output buffers",
+              state->mInBuffers.size(), state->mOutBuffers.size());
+    }
+
+    bool sawInputEOS = false;
+
+    for (;;) {
+        if (!sawInputEOS) {
+            size_t trackIndex;
+            status_t err = extractor->getSampleTrackIndex(&trackIndex);
+
+            if (err != OK) {
+                ALOGV("saw input eos");
+                sawInputEOS = true;
+            } else {
+                CodecState *state = &stateByTrack.editValueFor(trackIndex);
+
+                size_t index;
+                err = state->mCodec->dequeueInputBuffer(&index, kTimeout);
+
+                if (err == OK) {
+                    ALOGV("filling input buffer %d", index);
+
+                    const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
+
+                    err = extractor->readSampleData(buffer);
+                    CHECK_EQ(err, (status_t)OK);
+
+                    int64_t timeUs;
+                    err = extractor->getSampleTime(&timeUs);
+                    CHECK_EQ(err, (status_t)OK);
+
+                    uint32_t bufferFlags = 0;
+
+                    err = state->mCodec->queueInputBuffer(
+                            index,
+                            0 /* offset */,
+                            buffer->size(),
+                            timeUs,
+                            bufferFlags);
+
+                    CHECK_EQ(err, (status_t)OK);
+
+                    extractor->advance();
+                } else {
+                    CHECK_EQ(err, -EAGAIN);
+                }
+            }
+        } else {
+            for (size_t i = 0; i < stateByTrack.size(); ++i) {
+                CodecState *state = &stateByTrack.editValueAt(i);
+
+                if (!state->mSignalledInputEOS) {
+                    size_t index;
+                    status_t err =
+                        state->mCodec->dequeueInputBuffer(&index, kTimeout);
+
+                    if (err == OK) {
+                        ALOGV("signalling input EOS on track %d", i);
+
+                        err = state->mCodec->queueInputBuffer(
+                                index,
+                                0 /* offset */,
+                                0 /* size */,
+                                0ll /* timeUs */,
+                                MediaCodec::BUFFER_FLAG_EOS);
+
+                        CHECK_EQ(err, (status_t)OK);
+
+                        state->mSignalledInputEOS = true;
+                    } else {
+                        CHECK_EQ(err, -EAGAIN);
+                    }
+                }
+            }
+        }
+
+        bool sawOutputEOSOnAllTracks = true;
+        for (size_t i = 0; i < stateByTrack.size(); ++i) {
+            CodecState *state = &stateByTrack.editValueAt(i);
+            if (!state->mSawOutputEOS) {
+                sawOutputEOSOnAllTracks = false;
+                break;
+            }
+        }
+
+        if (sawOutputEOSOnAllTracks) {
+            break;
+        }
+
+        for (size_t i = 0; i < stateByTrack.size(); ++i) {
+            CodecState *state = &stateByTrack.editValueAt(i);
+
+            if (state->mSawOutputEOS) {
+                continue;
+            }
+
+            size_t index;
+            size_t offset;
+            size_t size;
+            int64_t presentationTimeUs;
+            uint32_t flags;
+            status_t err = state->mCodec->dequeueOutputBuffer(
+                    &index, &offset, &size, &presentationTimeUs, &flags,
+                    kTimeout);
+
+            if (err == OK) {
+                ALOGV("draining output buffer %d, time = %lld us",
+                      index, presentationTimeUs);
+
+                ++state->mNumBuffersDecoded;
+                state->mNumBytesDecoded += size;
+
+                err = state->mCodec->releaseOutputBuffer(index);
+                CHECK_EQ(err, (status_t)OK);
+
+                if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+                    ALOGV("reached EOS on output.");
+
+                    state->mSawOutputEOS = true;
+                }
+            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
+                ALOGV("INFO_OUTPUT_BUFFERS_CHANGED");
+                CHECK_EQ((status_t)OK,
+                         state->mCodec->getOutputBuffers(&state->mOutBuffers));
+
+                ALOGV("got %d output buffers", state->mOutBuffers.size());
+            } else if (err == INFO_FORMAT_CHANGED) {
+                sp<AMessage> format;
+                CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format));
+
+                ALOGV("INFO_FORMAT_CHANGED: %s", format->debugString().c_str());
+            } else {
+                CHECK_EQ(err, -EAGAIN);
+            }
+        }
+    }
+
+    int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs;
+
+    for (size_t i = 0; i < stateByTrack.size(); ++i) {
+        CodecState *state = &stateByTrack.editValueAt(i);
+
+        CHECK_EQ((status_t)OK, state->mCodec->release());
+
+        if (state->mIsAudio) {
+            ALOGD("track %d: %lld bytes received. %.2f KB/sec\n",
+                   i,
+                   state->mNumBytesDecoded,
+                   state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs);
+        } else {
+            ALOGD("track %d: %lld frames decoded, %.2f fps. %lld bytes "
+                   "received. %.2f KB/sec\n",
+                   i,
+                   state->mNumBuffersDecoded,
+                   state->mNumBuffersDecoded * 1E6 / elapsedTimeUs,
+                   state->mNumBytesDecoded,
+                   state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs);
+        }
+    }
+
+    return 0;
+}
+
+int main(int argc, char **argv) {
+    using namespace android;
+
+    const char *me = argv[0];
+
+    bool useAudio = false;
+    bool useVideo = false;
+    bool playback = false;
+    bool useSurface = false;
+
+    int res;
+    while ((res = getopt(argc, argv, "havpSD")) >= 0) {
+        switch (res) {
+            case 'a':
+            {
+                useAudio = true;
+                break;
+            }
+
+            case 'v':
+            {
+                useVideo = true;
+                break;
+            }
+
+            case 'p':
+            {
+                playback = true;
+                break;
+            }
+
+            case 'S':
+            {
+                useSurface = true;
+                break;
+            }
+
+            case '?':
+            case 'h':
+            default:
+            {
+                usage(me);
+            }
+        }
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    if (argc != 1) {
+        usage(me);
+    }
+
+    if (!useAudio && !useVideo) {
+        useAudio = useVideo = true;
+    }
+
+    ProcessState::self()->startThreadPool();
+
+    DataSource::RegisterDefaultSniffers();
+
+    sp<ALooper> looper = new ALooper;
+    looper->start();
+
+    sp<SurfaceComposerClient> composerClient;
+    sp<SurfaceControl> control;
+    sp<Surface> surface;
+
+    if (playback || (useSurface && useVideo)) {
+        composerClient = new SurfaceComposerClient;
+        CHECK_EQ(composerClient->initCheck(), (status_t)OK);
+
+        sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
+                ISurfaceComposer::eDisplayIdMain));
+        DisplayInfo info;
+        SurfaceComposerClient::getDisplayInfo(display, &info);
+        ssize_t displayWidth = info.w;
+        ssize_t displayHeight = info.h;
+
+        ALOGV("display is %ld x %ld\n", displayWidth, displayHeight);
+
+        control = composerClient->createSurface(
+                String8("A Surface"),
+                displayWidth,
+                displayHeight,
+                PIXEL_FORMAT_RGB_565,
+                0);
+
+        CHECK(control != NULL);
+        CHECK(control->isValid());
+
+        SurfaceComposerClient::openGlobalTransaction();
+        CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
+        CHECK_EQ(control->show(), (status_t)OK);
+        SurfaceComposerClient::closeGlobalTransaction();
+
+        surface = control->getSurface();
+        CHECK(surface != NULL);
+    }
+
+    if (playback) {
+        sp<SimplePlayer> player = new SimplePlayer;
+        looper->registerHandler(player);
+
+        player->setDataSource(argv[0]);
+        player->setSurface(surface->getSurfaceTexture());
+        player->start();
+        ALOGD("Playing for 60 seconds\n");
+        sleep(60);
+        player->stop();
+        player->reset();
+    } else {
+        decode(looper, argv[0], useAudio, useVideo, surface);
+    }
+
+    if (playback || (useSurface && useVideo)) {
+        composerClient->dispose();
+    }
+
+    looper->stop();
+
+    return 0;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/decoding_service.cpp
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+// Uncomment to enable verbose debug output
+#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "DecodingService"
+
+#include "decoding_service_priv.h"
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/BpBinder.h>
+
+typedef void* EGLDisplay;
+typedef void* EGLSyncKHR;
+
+#include <ui/GraphicBuffer.h>
+#include <gui/GraphicBufferAlloc.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/Surface.h>
+#include <gui/NativeBufferAlloc.h>
+
+namespace android {
+
+IMPLEMENT_META_INTERFACE(DecodingService, "android.media.IDecodingService");
+IMPLEMENT_META_INTERFACE(DecodingServiceSession, "android.media.IDecodingServiceSession");
+
+enum {
+    GET_IGRAPHICBUFFERCONSUMER = IBinder::FIRST_CALL_TRANSACTION,
+    GET_IGRAPHICBUFFERPRODUCER,
+    REGISTER_SESSION,
+    UNREGISTER_SESSION,
+};
+
+// ----------------------------------------------------------------------
+
+status_t BnDecodingService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    switch (code) {
+        case GET_IGRAPHICBUFFERCONSUMER: {
+            CHECK_INTERFACE(IDecodingService, data, reply);
+            sp<IGraphicBufferConsumer> gbc;
+            status_t res = getIGraphicBufferConsumer(&gbc);
+#if ANDROID_VERSION_MAJOR>=6
+            reply->writeStrongBinder(IInterface::asBinder(gbc));
+#else
+            reply->writeStrongBinder(gbc->asBinder());
+#endif
+            reply->writeInt32(res);
+
+            return NO_ERROR;
+        } break;
+        case GET_IGRAPHICBUFFERPRODUCER: {
+            CHECK_INTERFACE(IDecodingService, data, reply);
+            sp<IGraphicBufferProducer> gbp;
+            status_t res = getIGraphicBufferProducer(&gbp);
+
+#if ANDROID_VERSION_MAJOR>=6
+            reply->writeStrongBinder(IInterface::asBinder(gbp));
+#else
+            reply->writeStrongBinder(gbp->asBinder());
+#endif
+            reply->writeInt32(res);
+
+            return NO_ERROR;
+        } break;
+        case REGISTER_SESSION: {
+            CHECK_INTERFACE(IDecodingService, data, reply);
+            sp<IBinder> binder = data.readStrongBinder();
+            uint32_t handle = data.readInt32();
+            sp<IDecodingServiceSession> session(new BpDecodingServiceSession(binder));
+            registerSession(session, handle);
+
+            return NO_ERROR;
+        } break;
+        case UNREGISTER_SESSION: {
+            CHECK_INTERFACE(IDecodingService, data, reply);
+            unregisterSession();
+
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+status_t BpDecodingService::getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    Parcel data, reply;
+    data.writeInterfaceToken(IDecodingService::getInterfaceDescriptor());
+    remote()->transact(GET_IGRAPHICBUFFERCONSUMER, data, &reply);
+    *gbc = interface_cast<IGraphicBufferConsumer>(reply.readStrongBinder());
+    return reply.readInt32();
+}
+
+status_t BpDecodingService::getIGraphicBufferProducer(sp<IGraphicBufferProducer>* gbp)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    Parcel data, reply;
+    data.writeInterfaceToken(IDecodingService::getInterfaceDescriptor());
+    remote()->transact(GET_IGRAPHICBUFFERPRODUCER, data, &reply);
+    *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
+    return NO_ERROR;
+}
+
+status_t BpDecodingService::registerSession(const sp<IDecodingServiceSession>& session, uint32_t handle)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    Parcel data, reply;
+    data.writeInterfaceToken(IDecodingService::getInterfaceDescriptor());
+#if ANDROID_VERSION_MAJOR>=6
+    data.writeStrongBinder(IInterface::asBinder(session));
+#else
+    data.writeStrongBinder(session->asBinder());
+#endif
+    data.writeInt32(handle);
+    remote()->transact(REGISTER_SESSION, data, &reply);
+    return NO_ERROR;
+}
+
+status_t BpDecodingService::unregisterSession()
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    Parcel data, reply;
+    data.writeInterfaceToken(IDecodingService::getInterfaceDescriptor());
+    remote()->transact(UNREGISTER_SESSION, data, &reply);
+    return NO_ERROR;
+}
+
+sp<DecodingService> DecodingService::decoding_service = NULL;
+
+DecodingService::DecodingService()
+    : client_death_cb(NULL),
+      client_death_context(NULL)
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+DecodingService::~DecodingService()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+void DecodingService::instantiate()
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    defaultServiceManager()->addService(
+            String16(IDecodingService::exported_service_name()), service_instance());
+    ALOGD("Added Binder service '%s' to ServiceManager", IDecodingService::exported_service_name());
+
+    service_instance()->createBufferQueue();
+}
+
+sp<DecodingService>& DecodingService::service_instance()
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+
+    // TODO Add a mutex here
+    if (decoding_service == NULL)
+    {
+        ALOGD("Creating new static instance of DecodingService");
+        decoding_service = new DecodingService();
+    }
+
+    return decoding_service;
+}
+
+void DecodingService::setDecodingClientDeathCb(DecodingClientDeathCbHybris cb, uint32_t handle, void* context)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+
+    ClientCb *holder = (ClientCb*) malloc(sizeof(ClientCb));
+    holder->cb = cb;
+    holder->context = context;
+
+    clients.add(handle, holder);
+}
+
+status_t DecodingService::getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc)
+{
+    // TODO: Make sure instantiate() has been called first
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    ALOGD("Calling Pid: %d", pid);
+
+#if ANDROID_VERSION_MAJOR>=5
+    *gbc = consumer;
+#else
+    *gbc = buffer_queue;
+#endif
+
+    return OK;
+}
+
+status_t DecodingService::getIGraphicBufferProducer(sp<IGraphicBufferProducer>* gbp)
+{
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    ALOGD("Calling Pid: %d", pid);
+
+#if ANDROID_VERSION_MAJOR>=5
+    *gbp = producer;
+#else
+    *gbp = buffer_queue;
+#endif
+    ALOGD("producer(gbp): %p", (void*)gbp->get());
+    return OK;
+}
+
+status_t DecodingService::registerSession(const sp<IDecodingServiceSession>& session, uint32_t handle)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+
+    // Add session/handle to running clients map and connect death observer
+#if ANDROID_VERSION_MAJOR>=6
+    status_t ret = IInterface::asBinder(session)->linkToDeath(sp<IBinder::DeathRecipient>(this));
+    clientCbs.add(IInterface::asBinder(session), clients.valueFor(handle));
+#else
+    status_t ret = session->asBinder()->linkToDeath(sp<IBinder::DeathRecipient>(this));
+    clientCbs.add(session->asBinder(), clients.valueFor(handle));
+#endif
+    clients.removeItem(handle);
+
+    // Create a new BufferQueue instance so that the next created client plays
+    // video correctly
+    createBufferQueue();
+
+    return ret;
+}
+
+status_t DecodingService::unregisterSession()
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    if (session != NULL)
+    {
+#if ANDROID_VERSION_MAJOR>=6
+        IInterface::asBinder(session)->unlinkToDeath(this);
+#else
+        session->asBinder()->unlinkToDeath(this);
+#endif
+        session.clear();
+        // Reset the BufferQueue instance so that the next created client plays
+        // video correctly
+#if ANDROID_VERSION_MAJOR>=5
+        producer.clear();
+        consumer.clear();
+#else
+        buffer_queue.clear();
+#endif
+    }
+
+    return OK;
+}
+
+void DecodingService::createBufferQueue()
+{
+    // Use a new native buffer allocator vs the default one, which means it'll use the proper one
+    // that will allow rendering to work with Mir
+    sp<IGraphicBufferAlloc> g_buffer_alloc(new GraphicBufferAlloc());
+
+    // This BuferQueue is shared between the client and the service
+#if ANDROID_VERSION_MAJOR>=5
+    BufferQueue::createBufferQueue(&producer, &consumer);
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+    sp<NativeBufferAlloc> native_alloc(new NativeBufferAlloc());
+    buffer_queue = new BufferQueue(false, NULL, native_alloc);
+#else
+    buffer_queue = new BufferQueue(NULL);
+    ALOGD("buffer_queue: %p", (void*)buffer_queue.get());
+#endif
+#if ANDROID_VERSION_MAJOR>=5
+    producer->setBufferCount(5);
+#else
+    buffer_queue->setBufferCount(5);
+#endif
+}
+
+void DecodingService::binderDied(const wp<IBinder>& who)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+
+    sp<IBinder> sp = who.promote();
+    ClientCb *cb = clientCbs.valueFor(sp);
+
+    if (cb && cb->cb != NULL) {
+        cb->cb(cb->context);
+        free(cb);
+        clientCbs.removeItem(sp);
+    }
+
+    unregisterSession();
+}
+
+sp<BpDecodingService> DecodingClient::decoding_service = NULL;
+
+DecodingClient::DecodingClient()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+
+    ProcessState::self()->startThreadPool();
+}
+
+DecodingClient::~DecodingClient()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+sp<BpDecodingService>& DecodingClient::service_instance()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+    // TODO: Add a mutex here
+    if (decoding_service == NULL)
+    {
+        ALOGD("Creating a new static BpDecodingService instance");
+        sp<IServiceManager> service_manager = defaultServiceManager();
+        sp<IBinder> service = service_manager->getService(
+                String16(IDecodingService::exported_service_name()));
+        decoding_service = new BpDecodingService(service);
+    }
+
+    return decoding_service;
+}
+
+status_t DecodingClient::getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    return service_instance()->getIGraphicBufferConsumer(gbc);
+}
+
+// IDecodingServiceSession
+
+BpDecodingServiceSession::BpDecodingServiceSession(const sp<IBinder>& impl)
+    : BpInterface<IDecodingServiceSession>(impl)
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+BpDecodingServiceSession::~BpDecodingServiceSession()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+BnDecodingServiceSession::BnDecodingServiceSession()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+BnDecodingServiceSession::~BnDecodingServiceSession()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+status_t BnDecodingServiceSession::onTransact(uint32_t code, const Parcel& data,
+            Parcel* reply, uint32_t flags)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+
+    return NO_ERROR;
+}
+
+// ----- C API ----- //
+
+
+}; // namespace android
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/decoding_service_priv.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef DECODING_SERVICE_PRIV_H_
+#define DECODING_SERVICE_PRIV_H_
+
+#include "surface_texture_client_hybris_priv.h"
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+typedef struct {
+    DecodingClientDeathCbHybris cb;
+    void *context;
+} ClientCb;
+
+class IGraphicBufferConsumer;
+class IGraphicBufferProducer;
+class BufferQueue;
+class GLConsumer;
+
+class IDecodingServiceSession : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(DecodingServiceSession);
+
+    static const char* exported_service_name() { return "android.media.IDecodingServiceSession"; }
+
+};
+
+class BnDecodingServiceSession : public BnInterface<IDecodingServiceSession>
+{
+public:
+    BnDecodingServiceSession();
+    virtual ~BnDecodingServiceSession();
+
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+                                Parcel* reply, uint32_t flags = 0);
+};
+
+enum {
+    SET_DECODING_CLIENT_DEATH_CB = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpDecodingServiceSession : public BpInterface<IDecodingServiceSession>
+{
+public:
+    BpDecodingServiceSession(const sp<IBinder>& impl);
+    ~BpDecodingServiceSession();
+};
+
+class IDecodingService: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(DecodingService);
+
+    static const char* exported_service_name() { return "android.media.IDecodingService"; }
+
+    virtual status_t getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc) = 0;
+    virtual status_t getIGraphicBufferProducer(sp<IGraphicBufferProducer>* gbp) = 0;
+    virtual status_t registerSession(const sp<IDecodingServiceSession>& session, uint32_t handle) = 0;
+    virtual status_t unregisterSession() = 0;
+};
+
+class BnDecodingService: public BnInterface<IDecodingService>
+{
+public:
+    virtual status_t onTransact( uint32_t code,
+                                 const Parcel& data,
+                                 Parcel* reply,
+                                 uint32_t flags = 0);
+};
+
+class BpDecodingService: public BpInterface<IDecodingService>
+{
+public:
+    BpDecodingService(const sp<IBinder>& impl)
+        : BpInterface<IDecodingService>(impl)
+    {
+        ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    }
+
+    virtual status_t getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc);
+    virtual status_t getIGraphicBufferProducer(sp<IGraphicBufferProducer>* gbp);
+    virtual status_t registerSession(const sp<IDecodingServiceSession>& session, uint32_t handle);
+    virtual status_t unregisterSession();
+};
+
+class DecodingService : public BnDecodingService,
+                        public IBinder::DeathRecipient
+{
+public:
+    DecodingService();
+    virtual ~DecodingService();
+    /** Adds the decoding service to the default service manager in Binder **/
+    static void instantiate();
+    static sp<DecodingService>& service_instance();
+
+    virtual void setDecodingClientDeathCb(DecodingClientDeathCbHybris cb, uint32_t handle, void* context);
+
+    // IDecodingService interface:
+    virtual status_t getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc);
+    virtual status_t getIGraphicBufferProducer(sp<IGraphicBufferProducer>* gbp);
+
+    virtual status_t registerSession(const sp<IDecodingServiceSession>& session, uint32_t handle);
+    virtual status_t unregisterSession();
+
+    /** Get notified when the Binder connection to the client dies **/
+    virtual void binderDied(const wp<IBinder>& who);
+
+protected:
+    virtual void createBufferQueue();
+
+private:
+    static sp<DecodingService> decoding_service;
+#if ANDROID_VERSION_MAJOR>=5
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+#else
+    sp<BufferQueue> buffer_queue;
+#endif
+    sp<IDecodingServiceSession> session;
+    DecodingClientDeathCbHybris client_death_cb;
+    void *client_death_context;
+    KeyedVector< uint32_t, ClientCb* > clients;
+    KeyedVector< sp<IBinder>, ClientCb* > clientCbs;
+};
+
+class DecodingClient
+{
+public:
+    DecodingClient();
+    virtual ~DecodingClient();
+
+    static sp<BpDecodingService>& service_instance();
+
+    virtual status_t getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc);
+
+private:
+    static sp<BpDecodingService> decoding_service;
+};
+
+struct IGBCWrapper
+{
+    IGBCWrapper(const sp<IGraphicBufferConsumer>& igbc)
+    {
+        consumer = igbc;
+    }
+
+    sp<IGraphicBufferConsumer> consumer;
+};
+
+struct IGBPWrapper
+{
+    IGBPWrapper(const sp<IGraphicBufferProducer>& igbp)
+    {
+        producer = igbp;
+    }
+
+    sp<IGraphicBufferProducer> producer;
+};
+
+struct GLConsumerWrapper
+{
+    GLConsumerWrapper(const sp<_GLConsumerHybris>& gl_consumer)
+    {
+        consumer = gl_consumer;
+    }
+
+    sp<_GLConsumerHybris> consumer;
+};
+
+struct DSSessionWrapper
+{
+    DSSessionWrapper(const sp<IDecodingServiceSession>& session)
+    {
+        ALOGD("Entering %s", __PRETTY_FUNCTION__);
+        this->session = session;
+    }
+
+    ~DSSessionWrapper()
+    {
+        ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    }
+
+    sp<IDecodingServiceSession> session;
+};
+
+}; // namespace android
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/direct_media_test.cpp
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ */
+
+#include <hybris/media/media_compatibility_layer.h>
+#include "direct_media_test.h"
+
+#include <utils/Errors.h>
+
+#include <hybris/surface_flinger/surface_flinger_compatibility_layer.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+using namespace android;
+
+static float DestWidth = 0.0, DestHeight = 0.0;
+// Actual video dimmensions
+static int Width = 0, Height = 0;
+
+static GLfloat positionCoordinates[8];
+
+MediaPlayerWrapper *player = NULL;
+
+void calculate_position_coordinates()
+{
+	// Assuming cropping output for now
+	float x = 1, y = 1;
+
+	// Black borders
+	x = float(Width / DestWidth);
+	y = float(Height / DestHeight);
+
+	// Make the larger side be 1
+	if (x > y) {
+		y /= x;
+		x = 1;
+	} else {
+		x /= y;
+		y = 1;
+	}
+
+	positionCoordinates[0] = -x;
+	positionCoordinates[1] = y;
+	positionCoordinates[2] = -x;
+	positionCoordinates[3] = -y;
+	positionCoordinates[4] = x;
+	positionCoordinates[5] = -y;
+	positionCoordinates[6] = x;
+	positionCoordinates[7] = y;
+}
+
+WindowRenderer::WindowRenderer(int width, int height)
+	: mThreadCmd(CMD_IDLE)
+{
+	createThread(threadStart, this);
+}
+
+WindowRenderer::~WindowRenderer()
+{
+}
+
+int WindowRenderer::threadStart(void* self)
+{
+	((WindowRenderer *)self)->glThread();
+	return 0;
+}
+
+void WindowRenderer::glThread()
+{
+	printf("%s\n", __PRETTY_FUNCTION__);
+
+	Mutex::Autolock autoLock(mLock);
+}
+
+struct ClientWithSurface
+{
+	SfClient* client;
+	SfSurface* surface;
+};
+
+ClientWithSurface client_with_surface(bool setup_surface_with_egl)
+{
+	ClientWithSurface cs = ClientWithSurface();
+
+	cs.client = sf_client_create();
+
+	if (!cs.client) {
+		printf("Problem creating client ... aborting now.");
+		return cs;
+	}
+
+	static const size_t primary_display = 0;
+
+	DestWidth = sf_get_display_width(primary_display);
+	DestHeight = sf_get_display_height(primary_display);
+	printf("Primary display width: %f, height: %f\n", DestWidth, DestHeight);
+
+	SfSurfaceCreationParameters params = {
+		0,
+		0,
+		(int) DestWidth,
+		(int) DestHeight,
+		-1, //PIXEL_FORMAT_RGBA_8888,
+		15000,
+		0.5f,
+		setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL
+		"MediaCompatLayerTestSurface"
+	};
+
+	cs.surface = sf_surface_create(cs.client, &params);
+
+	if (!cs.surface) {
+		printf("Problem creating surface ... aborting now.");
+		return cs;
+	}
+
+	sf_surface_make_current(cs.surface);
+
+	return cs;
+}
+
+struct RenderData
+{
+	static const char *vertex_shader()
+	{
+		return
+			"attribute vec4 a_position;                                  \n"
+			"attribute vec2 a_texCoord;                                  \n"
+			"uniform mat4 m_texMatrix;                                   \n"
+			"varying vec2 v_texCoord;                                    \n"
+			"varying float topDown;                                      \n"
+			"void main()                                                 \n"
+			"{                                                           \n"
+			"   gl_Position = a_position;                                \n"
+			"   v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n"
+			"}                                                           \n";
+	}
+
+	static const char *fragment_shader()
+	{
+		return
+			"#extension GL_OES_EGL_image_external : require      \n"
+			"precision mediump float;                            \n"
+			"varying vec2 v_texCoord;                            \n"
+			"uniform samplerExternalOES s_texture;               \n"
+			"void main()                                         \n"
+			"{                                                   \n"
+			"  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
+			"}                                                   \n";
+	}
+
+	static GLuint loadShader(GLenum shaderType, const char* pSource)
+	{
+		GLuint shader = glCreateShader(shaderType);
+
+		if (shader) {
+			glShaderSource(shader, 1, &pSource, NULL);
+			glCompileShader(shader);
+			GLint compiled = 0;
+			glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+
+			if (!compiled) {
+				GLint infoLen = 0;
+				glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+				if (infoLen) {
+					char* buf = (char*) malloc(infoLen);
+					if (buf) {
+						glGetShaderInfoLog(shader, infoLen, NULL, buf);
+						fprintf(stderr, "Could not compile shader %d:\n%s\n",
+								shaderType, buf);
+						free(buf);
+					}
+					glDeleteShader(shader);
+					shader = 0;
+				}
+			}
+		} else {
+			printf("Error, during shader creation: %i\n", glGetError());
+		}
+
+		return shader;
+	}
+
+	static GLuint create_program(const char* pVertexSource, const char* pFragmentSource)
+	{
+		GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+		if (!vertexShader) {
+			printf("vertex shader not compiled\n");
+			return 0;
+		}
+
+		GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+		if (!pixelShader) {
+			printf("frag shader not compiled\n");
+			return 0;
+		}
+
+		GLuint program = glCreateProgram();
+		if (program) {
+			glAttachShader(program, vertexShader);
+			glAttachShader(program, pixelShader);
+			glLinkProgram(program);
+			GLint linkStatus = GL_FALSE;
+			glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+
+			if (linkStatus != GL_TRUE) {
+				GLint bufLength = 0;
+				glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+				if (bufLength) {
+					char* buf = (char*) malloc(bufLength);
+					if (buf) {
+						glGetProgramInfoLog(program, bufLength, NULL, buf);
+						fprintf(stderr, "Could not link program:\n%s\n", buf);
+						free(buf);
+					}
+				}
+				glDeleteProgram(program);
+				program = 0;
+			}
+		}
+
+		return program;
+	}
+
+	RenderData() : program_object(create_program(vertex_shader(), fragment_shader()))
+	{
+		position_loc = glGetAttribLocation(program_object, "a_position");
+		tex_coord_loc = glGetAttribLocation(program_object, "a_texCoord");
+		sampler_loc = glGetUniformLocation(program_object, "s_texture");
+		matrix_loc = glGetUniformLocation(program_object, "m_texMatrix");
+	}
+
+	// Handle to a program object
+	GLuint program_object;
+	// Attribute locations
+	GLint position_loc;
+	GLint tex_coord_loc;
+	// Sampler location
+	GLint sampler_loc;
+	// Matrix location
+	GLint matrix_loc;
+};
+
+static int setup_video_texture(ClientWithSurface *cs, GLuint *preview_texture_id)
+{
+	assert(cs != NULL);
+	assert(preview_texture_id != NULL);
+
+	sf_surface_make_current(cs->surface);
+
+	glGenTextures(1, preview_texture_id);
+	glClearColor(0, 0, 0, 0);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+	android_media_set_preview_texture(player, *preview_texture_id);
+
+	return 0;
+}
+
+static void print_gl_error(unsigned int line)
+{
+	GLint error = glGetError();
+	printf("GL error: %#04x (line: %d)\n", error, line);
+}
+
+static int update_gl_buffer(RenderData *render_data, EGLDisplay *disp, EGLSurface *surface)
+{
+	assert(disp != NULL);
+	assert(surface != NULL);
+
+	GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+	const GLfloat textureCoordinates[] = {
+		1.0f,  1.0f,
+		0.0f,  1.0f,
+		0.0f,  0.0f,
+		1.0f,  0.0f
+	};
+
+	calculate_position_coordinates();
+
+	glClear(GL_COLOR_BUFFER_BIT);
+	// Use the program object
+	glUseProgram(render_data->program_object);
+	// Enable attributes
+	glEnableVertexAttribArray(render_data->position_loc);
+	glEnableVertexAttribArray(render_data->tex_coord_loc);
+	// Load the vertex position
+	glVertexAttribPointer(render_data->position_loc,
+			2,
+			GL_FLOAT,
+			GL_FALSE,
+			0,
+			positionCoordinates);
+	// Load the texture coordinate
+	glVertexAttribPointer(render_data->tex_coord_loc,
+			2,
+			GL_FLOAT,
+			GL_FALSE,
+			0,
+			textureCoordinates);
+
+	GLfloat matrix[16];
+	android_media_surface_texture_get_transformation_matrix(player, matrix);
+
+	glUniformMatrix4fv(render_data->matrix_loc, 1, GL_FALSE, matrix);
+
+	glActiveTexture(GL_TEXTURE0);
+	// Set the sampler texture unit to 0
+	glUniform1i(render_data->sampler_loc, 0);
+	glUniform1i(render_data->matrix_loc, 0);
+	android_media_update_surface_texture(player);
+	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+	//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+	glDisableVertexAttribArray(render_data->position_loc);
+	glDisableVertexAttribArray(render_data->tex_coord_loc);
+
+	eglSwapBuffers(*disp, *surface);
+
+	return 0;
+}
+
+void set_video_size_cb(int height, int width, void *context)
+{
+	printf("Video height: %d, width: %d\n", height, width);
+	printf("Video dest height: %f, width: %f\n", DestHeight, DestWidth);
+
+	Height = height;
+	Width = width;
+}
+
+int main(int argc, char **argv)
+{
+	if (argc < 2) {
+		printf("Usage: direct_media_test <video_to_play>\n");
+		return EXIT_FAILURE;
+	}
+
+	player = android_media_new_player();
+	if (player == NULL) {
+		printf("Problem creating new media player.\n");
+		return EXIT_FAILURE;
+	}
+
+	// Set player event cb for when the video size is known:
+	android_media_set_video_size_cb(player, set_video_size_cb, NULL);
+
+	printf("Setting data source to: %s.\n", argv[1]);
+
+	if (android_media_set_data_source(player, argv[1]) != OK) {
+		printf("Failed to set data source: %s\n", argv[1]);
+		return EXIT_FAILURE;
+	}
+
+	WindowRenderer renderer(DestWidth, DestHeight);
+
+	printf("Creating EGL surface.\n");
+	ClientWithSurface cs = client_with_surface(true /* Associate surface with egl. */);
+	if (!cs.surface) {
+		printf("Problem acquiring surface for preview");
+		return EXIT_FAILURE;
+	}
+
+	printf("Creating GL texture.\n");
+	GLuint preview_texture_id;
+	EGLDisplay disp = sf_client_get_egl_display(cs.client);
+	EGLSurface surface = sf_surface_get_egl_surface(cs.surface);
+
+	sf_surface_make_current(cs.surface);
+	if (setup_video_texture(&cs, &preview_texture_id) != OK) {
+		printf("Problem setting up GL texture for video surface.\n");
+		return EXIT_FAILURE;
+	}
+
+	RenderData render_data;
+
+	printf("Starting video playback.\n");
+	android_media_play(player);
+
+	printf("Updating gl buffer continuously...\n");
+	while (android_media_is_playing(player)) {
+		update_gl_buffer(&render_data, &disp, &surface);
+	}
+
+	android_media_stop(player);
+
+	return EXIT_SUCCESS;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/direct_media_test.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef DIRECT_MEDIA_TEST_H_
+#define DIRECT_MEDIA_TEST_H_
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class RenderInput;
+
+class WindowRenderer
+{
+public:
+    WindowRenderer(int width, int height);
+    ~WindowRenderer();
+
+private:
+    // The GL thread functions
+    static int threadStart(void* self);
+    void glThread();
+
+    // These variables are used to communicate between the GL thread and
+    // other threads.
+    Mutex mLock;
+    Condition mCond;
+    enum {
+        CMD_IDLE,
+        CMD_RENDER_INPUT,
+        CMD_RESERVE_TEXTURE,
+        CMD_DELETE_TEXTURE,
+        CMD_QUIT,
+    };
+    int mThreadCmd;
+    RenderInput* mThreadRenderInput;
+    GLuint mThreadTextureId;
+};
+} // android
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_buffer_layer.cpp
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Simon Fels <simon.fels@canonical.com>
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "MediaCompatibilityLayer"
+
+#include <hybris/media/media_buffer_layer.h>
+
+#include "media_buffer_priv.h"
+#include "media_meta_data_priv.h"
+#include "media_message_priv.h"
+
+MediaBufferPrivate* MediaBufferPrivate::toPrivate(MediaBufferWrapper *buffer)
+{
+    if (!buffer)
+        return NULL;
+
+    return static_cast<MediaBufferPrivate*>(buffer);
+}
+
+MediaBufferPrivate::MediaBufferPrivate(android::MediaBuffer *buffer) :
+    buffer(buffer),
+    return_callback(NULL),
+    return_callback_data(NULL)
+{
+}
+
+MediaBufferPrivate::MediaBufferPrivate() :
+    buffer(NULL)
+{
+}
+
+MediaBufferPrivate::~MediaBufferPrivate()
+{
+    if (buffer)
+        buffer->release();
+}
+
+void MediaBufferPrivate::signalBufferReturned(android::MediaBuffer *buffer)
+{
+    if (buffer != this->buffer) {
+        ALOGE("Got called for unknown buffer %p", buffer);
+        return;
+    }
+
+    if (!return_callback)
+        return;
+
+    return_callback(this, return_callback_data);
+}
+
+MediaBufferWrapper* media_buffer_create(size_t size)
+{
+    android::MediaBuffer *mbuf = new android::MediaBuffer(size);
+    if (!mbuf)
+        return NULL;
+
+    MediaBufferPrivate *d = new MediaBufferPrivate(mbuf);
+    if (!d) {
+        mbuf->release();
+        return NULL;
+    }
+
+    return d;
+}
+
+void media_buffer_destroy(MediaBufferWrapper *buffer)
+{
+    MediaBufferPrivate *d = MediaBufferPrivate::toPrivate(buffer);
+    if (!d)
+        return;
+
+    delete d;
+}
+
+
+void media_buffer_release(MediaBufferWrapper *buffer)
+{
+    MediaBufferPrivate *d = MediaBufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer)
+        return;
+
+    d->buffer->release();
+}
+
+void media_buffer_ref(MediaBufferWrapper *buffer)
+{
+    MediaBufferPrivate *d = MediaBufferPrivate::toPrivate(buffer);
+    if (!d)
+        return;
+
+    d->buffer->add_ref();
+}
+
+int media_buffer_get_refcount(MediaBufferWrapper *buffer)
+{
+    MediaBufferPrivate *d = MediaBufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer)
+        return 0;
+
+    return d->buffer->refcount();
+}
+
+void* media_buffer_get_data(MediaBufferWrapper *buffer)
+{
+    MediaBufferPrivate *d = MediaBufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer)
+        return NULL;
+
+    return d->buffer->data();
+}
+
+size_t media_buffer_get_size(MediaBufferWrapper *buffer)
+{
+    MediaBufferPrivate *d = MediaBufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer)
+        return 0;
+
+    return d->buffer->size();
+}
+
+size_t media_buffer_get_range_offset(MediaBufferWrapper *buffer)
+{
+    MediaBufferPrivate *d = MediaBufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer)
+        return 0;
+
+    return d->buffer->range_offset();
+}
+
+size_t media_buffer_get_range_length(MediaBufferWrapper *buffer)
+{
+    MediaBufferPrivate *d = MediaBufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer)
+        return 0;
+
+    return d->buffer->range_length();
+}
+
+MediaMetaDataWrapper* media_buffer_get_meta_data(MediaBufferWrapper *buffer)
+{
+    MediaBufferPrivate *d = MediaBufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer)
+        return NULL;
+
+    return new MediaMetaDataPrivate(d->buffer->meta_data());
+}
+
+void media_buffer_set_return_callback(MediaBufferWrapper *buffer,
+    MediaBufferReturnCallback callback, void *user_data)
+{
+    MediaBufferPrivate *d = MediaBufferPrivate::toPrivate(buffer);
+    if (!d)
+        return;
+
+    d->return_callback = callback;
+    d->return_callback_data = user_data;
+
+    if (d->return_callback)
+        d->buffer->setObserver(d);
+    else
+        d->buffer->setObserver(NULL);
+}
+
+MediaABufferPrivate* MediaABufferPrivate::toPrivate(MediaABufferWrapper *buffer)
+{
+    if (!buffer)
+        return NULL;
+
+    return static_cast<MediaABufferPrivate*>(buffer);
+}
+
+MediaABufferPrivate::MediaABufferPrivate()
+{
+}
+
+MediaABufferPrivate::MediaABufferPrivate(android::sp<android::ABuffer> buffer) :
+    buffer(buffer)
+{
+}
+
+MediaABufferWrapper* media_abuffer_create(size_t capacity)
+{
+    MediaABufferPrivate *d = new MediaABufferPrivate;
+    if (!d)
+        return NULL;
+
+    d->buffer = new android::ABuffer(capacity);
+    if (!d->buffer.get()) {
+        delete d;
+        return NULL;
+    }
+
+    return d;
+}
+
+MediaABufferWrapper* media_abuffer_create_with_data(uint8_t *data, size_t size)
+{
+    MediaABufferPrivate *d = new MediaABufferPrivate;
+    if (!d)
+        return NULL;
+
+    d->buffer = new android::ABuffer(data, size);
+    if (!d->buffer.get()) {
+        delete d;
+        return NULL;
+    }
+
+    return d;
+}
+
+void media_abuffer_set_range(MediaABufferWrapper *buffer, size_t offset, size_t size)
+{
+    MediaABufferPrivate *d = MediaABufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer.get())
+        return;
+
+    d->buffer->setRange(offset, size);
+}
+
+void media_abuffer_set_media_buffer_base(MediaABufferWrapper *buffer, MediaBufferWrapper *mbuf)
+{
+    MediaABufferPrivate *d = MediaABufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer.get())
+        return;
+
+#if ANDROID_VERSION_MAJOR>=5
+    android::MediaBuffer *media_buffer = NULL;
+
+    if (mbuf != NULL)
+        media_buffer = MediaBufferPrivate::toPrivate(mbuf)->buffer;
+
+    d->buffer->setMediaBufferBase(media_buffer);
+#else
+    return;
+#endif
+}
+
+MediaBufferWrapper* media_abuffer_get_media_buffer_base(MediaABufferWrapper *buffer)
+{
+    MediaABufferPrivate *d = MediaABufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer.get())
+        return NULL;
+
+#if ANDROID_VERSION_MAJOR>= 5
+
+    android::MediaBufferBase *mbufb = d->buffer->getMediaBufferBase();
+    if (mbufb == NULL)
+        return NULL;
+
+    MediaBufferPrivate *mbuf = new MediaBufferPrivate;
+    mbuf->buffer = (android::MediaBuffer*) mbufb;
+
+    return mbuf;
+#else
+    return NULL;
+#endif
+}
+
+void* media_abuffer_get_data(MediaABufferWrapper *buffer)
+{
+    MediaABufferPrivate *d = MediaABufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer.get())
+        return NULL;
+
+    return d->buffer->data();
+}
+
+size_t media_abuffer_get_size(MediaABufferWrapper *buffer)
+{
+    MediaABufferPrivate *d = MediaABufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer.get())
+        return 0;
+
+    return d->buffer->size();
+}
+
+size_t media_abuffer_get_range_offset(MediaABufferWrapper *buffer)
+{
+    MediaABufferPrivate *d = MediaABufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer.get())
+        return 0;
+
+    return d->buffer->offset();
+}
+
+size_t media_abuffer_get_capacity(MediaABufferWrapper *buffer)
+{
+    MediaABufferPrivate *d = MediaABufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer.get())
+        return 0;
+
+    return d->buffer->capacity();
+}
+
+MediaMessageWrapper* media_abuffer_get_meta(MediaABufferWrapper *buffer)
+{
+    MediaABufferPrivate *d = MediaABufferPrivate::toPrivate(buffer);
+    if (!d || !d->buffer.get())
+        return NULL;
+
+    MediaMessagePrivate *msg = new MediaMessagePrivate;
+    if (!msg)
+        return NULL;
+
+    msg->msg = d->buffer->meta();
+
+    return msg;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_buffer_priv.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Simon Fels <simon.fels@canonical.com>
+ */
+
+#ifndef MEDIA_BUFFER_PRIV_H_
+#define MEDIA_BUFFER_PRIV_H_
+
+#include <hybris/media/media_buffer_layer.h>
+
+#include <media/stagefright/foundation/ABuffer.h>
+
+#include <media/stagefright/MediaBuffer.h>
+
+struct MediaBufferPrivate : public android::MediaBufferObserver
+{
+public:
+    static MediaBufferPrivate* toPrivate(MediaBufferWrapper *source);
+
+    MediaBufferPrivate(android::MediaBuffer *data);
+    MediaBufferPrivate();
+    ~MediaBufferPrivate();
+
+    void signalBufferReturned(android::MediaBuffer *buffer);
+
+    android::MediaBuffer *buffer;
+    MediaBufferReturnCallback return_callback;
+    void *return_callback_data;
+};
+
+struct MediaABufferPrivate
+{
+public:
+    static MediaABufferPrivate* toPrivate(MediaABufferWrapper *source);
+
+    MediaABufferPrivate();
+    MediaABufferPrivate(android::sp<android::ABuffer> buffer);
+
+public:
+    android::sp<android::ABuffer> buffer;
+};
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_codec_layer.cpp
@@ -0,0 +1,937 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+// Uncomment to enable verbose debug output
+#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "MediaCodecLayer"
+
+#include <hybris/media/media_codec_layer.h>
+#include <hybris/media/media_compatibility_layer.h>
+#include <hybris/media/media_format_layer.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <binder/ProcessState.h>
+
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/ICrypto.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaErrors.h>
+#if ANDROID_VERSION_MAJOR<=5
+#include <media/stagefright/NativeWindowWrapper.h>
+#endif
+
+#include <gui/IGraphicBufferProducer.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/Vector.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <utils/Mutex.h>
+
+#include "media_format_layer_priv.h"
+#include "surface_texture_client_hybris_priv.h"
+#include "decoding_service_priv.h"
+#include "media_message_priv.h"
+#include "media_buffer_priv.h"
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__);
+
+using namespace android;
+
+struct _MediaCodecDelegate : public AHandler
+{
+public:
+    typedef sp<_MediaCodecDelegate> Ptr;
+
+    explicit _MediaCodecDelegate(void *context);
+    virtual ~_MediaCodecDelegate();
+
+protected:
+    virtual void onMessageReceived(const sp<AMessage> &msg) { }
+
+public:
+    sp<MediaCodec> media_codec;
+    sp<ALooper> looper;
+
+    Vector<sp<ABuffer> > input_buffers;
+    Vector<sp<ABuffer> > output_buffers;
+    List<MediaCodecBufferInfo> available_output_buffer_infos;
+    Mutex mtx_output_buffer_infos;
+    List<size_t> available_input_buffer_indices;
+    bool output_format_changed;
+    bool hardware_rendering;
+
+    void *context;
+    unsigned int refcount;
+};
+
+_MediaCodecDelegate::_MediaCodecDelegate(void *context)
+    : output_format_changed(false),
+      hardware_rendering(false),
+      context(context),
+      refcount(1)
+{
+    REPORT_FUNCTION()
+}
+
+_MediaCodecDelegate::~_MediaCodecDelegate()
+{
+    REPORT_FUNCTION()
+}
+
+static inline _MediaCodecDelegate *get_internal_delegate(MediaCodecDelegate delegate)
+{
+    if (delegate == NULL)
+    {
+        ALOGE("delegate must not be NULL");
+        return NULL;
+    }
+
+    _MediaCodecDelegate *d = static_cast<_MediaCodecDelegate*>(delegate);
+    // Some simple sanity checks that must be true for a valid MediaCodecDelegate instance
+    if (d->media_codec == NULL || d->refcount < 1)
+        return NULL;
+
+    return d;
+}
+
+// ----- DecodingService C API ----- //
+//
+// FIXME: These functions really need to be moved into decoding_service.cpp, but for some
+// reason were segfaulting when I tried them in there last
+
+namespace {
+
+    DecodingClient& decoding_client_instance()
+    {
+        static DecodingClient instance;
+        return instance;
+    }
+}
+
+void decoding_service_init()
+{
+    REPORT_FUNCTION();
+
+    // Register the service with Binder ServiceManager
+    DecodingService::instantiate();
+
+    ProcessState::self()->startThreadPool();
+}
+
+IGBCWrapperHybris decoding_service_get_igraphicbufferconsumer()
+{
+    REPORT_FUNCTION();
+
+    sp<IGraphicBufferConsumer> consumer;
+    decoding_client_instance().getIGraphicBufferConsumer(&consumer);
+    IGBCWrapper *wrapper = new IGBCWrapper(consumer);
+    return wrapper;
+}
+
+IGBPWrapperHybris decoding_service_get_igraphicbufferproducer()
+{
+    REPORT_FUNCTION();
+
+    sp<IServiceManager> service_manager = defaultServiceManager();
+    sp<IBinder> service = service_manager->getService(
+            String16(IDecodingService::exported_service_name()));
+
+    sp<IGraphicBufferProducer> producer;
+    DecodingClient::service_instance()->getIGraphicBufferProducer(&producer);
+    IGBPWrapper *wrapper = new IGBPWrapper(producer);
+
+    return wrapper;
+}
+
+DSSessionWrapperHybris decoding_service_create_session(uint32_t handle)
+{
+    REPORT_FUNCTION();
+
+    sp<IServiceManager> service_manager = defaultServiceManager();
+    sp<IBinder> service = service_manager->getService(
+            String16(IDecodingService::exported_service_name()));
+
+    // Create a new decoding service session
+    sp<BnDecodingServiceSession> session(new BnDecodingServiceSession());
+    // This new session will destroy and replace any existing session
+    DecodingClient::service_instance()->registerSession(session, handle);
+    DSSessionWrapper *wrapper(new DSSessionWrapper(session));
+
+    return wrapper;
+}
+
+void decoding_service_set_client_death_cb(DecodingClientDeathCbHybris cb, uint32_t handle, void *context)
+{
+    REPORT_FUNCTION();
+
+    if (cb == NULL)
+    {
+        ALOGE("cb must not be NULL");
+        return;
+    }
+
+    DecodingService::service_instance()->setDecodingClientDeathCb(cb, handle, context);
+}
+
+// ----- End of DecodingService C API ----- //
+
+MediaCodecDelegate media_codec_create_by_codec_name(const char *name)
+{
+    REPORT_FUNCTION()
+
+    if (name == NULL)
+    {
+        ALOGE("name must not be NULL");
+        return NULL;
+    }
+
+    ALOGD("Creating codec '%s'", name);
+
+    ProcessState::self()->startThreadPool();
+
+    _MediaCodecDelegate *d(new _MediaCodecDelegate(NULL));
+    d->looper = new ALooper;
+    d->looper->start();
+
+    d->media_codec = android::MediaCodec::CreateByComponentName(d->looper, name);
+
+    return d;
+}
+
+#ifdef SIMPLE_PLAYER
+MediaCodec* media_codec_get(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return NULL;
+
+    return d->media_codec.get();
+}
+#endif
+
+MediaCodecDelegate media_codec_create_by_codec_type(const char *type)
+{
+    REPORT_FUNCTION()
+
+    if (type == NULL)
+    {
+        ALOGE("type must not be NULL");
+        return NULL;
+    }
+
+    ALOGD("Creating codec by type '%s'", type);
+
+    ProcessState::self()->startThreadPool();
+
+    _MediaCodecDelegate *d(new _MediaCodecDelegate(NULL));
+    d->looper = new ALooper;
+    d->looper->start();
+
+    d->media_codec = android::MediaCodec::CreateByType(d->looper, type, false);
+
+    return d;
+}
+
+void media_codec_delegate_destroy(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+    {
+        ALOGE("d == NULL, cannot destroy MediaCodecDelegate instance");
+        return;
+    }
+
+    ALOGI("Releasing media_codec");
+    d->media_codec->release();
+    ALOGI("Stopping looper");
+    d->looper->stop();
+
+    ALOGI("Setting refcount = 0");
+    d->refcount = 0;
+
+    ALOGI("Deleting the MediaCodecDelegate instance");
+    delete d;
+}
+
+void media_codec_delegate_ref(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return;
+
+    d->refcount++;
+}
+
+void media_codec_delegate_unref(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+    {
+        ALOGE("d == NULL, cannot unref MediaCodecDelegate instance");
+        return;
+    }
+
+    if (d->refcount > 1)
+        d->refcount--;
+    else
+        media_codec_delegate_destroy (delegate);
+}
+
+#ifdef SIMPLE_PLAYER
+int media_codec_configure(MediaCodecDelegate delegate, MediaFormat format, void *nativeWindow, uint32_t flags)
+#else
+int media_codec_configure(MediaCodecDelegate delegate, MediaFormat format, SurfaceTextureClientHybris stc, uint32_t flags)
+#endif
+{
+    REPORT_FUNCTION()
+
+    if (format == NULL)
+    {
+        ALOGE("format must not be NULL");
+        return BAD_VALUE;
+    }
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    _MediaFormat *format_priv = static_cast<_MediaFormat*>(format);
+#ifndef SIMPLE_PLAYER
+    _SurfaceTextureClientHybris *stch = static_cast<_SurfaceTextureClientHybris*>(stc);
+#endif
+
+    sp<AMessage> aformat = new AMessage;
+    aformat->setString("mime", format_priv->mime.c_str());
+    if (format_priv->duration_us > 0)
+        aformat->setInt64("durationUs", format_priv->duration_us);
+    aformat->setInt32("width", format_priv->width);
+    aformat->setInt32("height", format_priv->height);
+    if (format_priv->max_input_size > 0)
+        aformat->setInt32("max-input-size", format_priv->max_input_size);
+
+    if (format_priv->csd.get() != NULL) {
+        const size_t csd_size = format_priv->csd->size();
+
+        ALOGD("Adding csd (%zu bytes)", csd_size);
+
+        sp<ABuffer> buffer = new ABuffer(csd_size);
+        memcpy(buffer->data(), format_priv->csd->data(), csd_size);
+
+        buffer->meta()->setInt32("csd", true);
+        buffer->meta()->setInt64("timeUs", 0);
+        aformat->setBuffer("csd-0", buffer);
+    }
+
+    ALOGD("Format: %s", aformat->debugString().c_str());
+
+#ifdef SIMPLE_PLAYER
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    sp<SurfaceTextureClient> surfaceTextureClient = static_cast<SurfaceTextureClient*>(nativeWindow);
+#else
+    sp<Surface> surfaceTextureClient = static_cast<Surface*>(nativeWindow);
+#endif
+    // TODO: Don't just pass NULL for the security when DRM is needed
+    d->media_codec->configure(aformat, surfaceTextureClient, NULL, flags);
+#else
+    ALOGD("SurfaceTextureClientHybris: %p", stch);
+
+    // Make sure we're ready to configure the codec and the Surface/SurfaceTextureClient together
+    if (stch != NULL && stch->hardwareRendering() && stch->isReady())
+    {
+        ALOGD("Doing hardware decoding with hardware rendering");
+        // TODO: Don't just pass NULL for the security when DRM is needed
+        d->media_codec->configure(aformat, stch, NULL, flags);
+    }
+    else
+    {
+        ALOGD("Doing hardware decoding path with software rendering");
+        // This scenario is for hardware video decoding, but software rendering, therefore there's
+        // no need to pass a valid Surface/SurfaceTextureClient instance to configure()
+        d->media_codec->configure(aformat, NULL, NULL, flags);
+    }
+#endif
+
+    return OK;
+}
+
+int media_codec_set_surface_texture_client(MediaCodecDelegate delegate, SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+    if (stc == NULL)
+    {
+        ALOGE("stc must not be NULL");
+        return BAD_VALUE;
+    }
+
+    _SurfaceTextureClientHybris *stcu = static_cast<_SurfaceTextureClientHybris*>(stc);
+    status_t err = native_window_api_connect(stcu, NATIVE_WINDOW_API_MEDIA);
+    if (err != OK)
+    {
+        ALOGE("native_window_api_connect returned an error: %s (%d)", strerror(-err), err);
+        return err;
+    }
+
+    return OK;
+}
+
+int media_codec_queue_csd(MediaCodecDelegate delegate, MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    if (format == NULL)
+    {
+        ALOGE("format must not be NULL");
+        return BAD_VALUE;
+    }
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    _MediaFormat *format_priv = static_cast<_MediaFormat*>(format);
+    assert(format_priv->csd != NULL);
+
+    status_t err = OK;
+
+    Vector<sp<ABuffer> > input_bufs[1];
+    err = d->media_codec->getInputBuffers(&input_bufs[0]);
+    CHECK_EQ(err, static_cast<status_t>(OK));
+
+    for (size_t i=0; i<2; ++i)
+    {
+        const sp<ABuffer> &srcBuffer = format_priv->csd;
+
+        size_t index = 0;
+        err = d->media_codec->dequeueInputBuffer(&index, -1ll);
+        CHECK_EQ(err, static_cast<status_t>(OK));
+
+        const sp<ABuffer> &dstBuffer = input_bufs[0].itemAt(index);
+
+        CHECK_LE(srcBuffer->size(), dstBuffer->capacity());
+        dstBuffer->setRange(0, srcBuffer->size());
+        memcpy(dstBuffer->data(), srcBuffer->data(), srcBuffer->size());
+
+        dstBuffer->meta()->setInt32("csd", true);
+        dstBuffer->meta()->setInt64("timeUs", 0);
+
+        AString err_msg;
+        err = d->media_codec->queueInputBuffer(
+                index,
+                0,
+                dstBuffer->size(),
+                0ll,
+                MediaCodec::BUFFER_FLAG_CODECCONFIG);
+        CHECK_EQ(err, static_cast<status_t>(OK));
+    }
+
+    return err;
+}
+
+int media_codec_start(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    return d->media_codec->start();
+}
+
+int media_codec_stop(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    return d->media_codec->stop();
+}
+
+int media_codec_release(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    return d->media_codec->release();
+}
+
+int media_codec_flush(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    d->mtx_output_buffer_infos.lock();
+
+    d->available_output_buffer_infos.clear();
+
+    d->mtx_output_buffer_infos.unlock();
+
+    return d->media_codec->flush();
+}
+
+size_t media_codec_get_input_buffers_size(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    status_t ret = d->media_codec->getInputBuffers(&d->input_buffers);
+    if (ret != OK)
+    {
+        ALOGE("Failed to get input buffers size");
+        return 0;
+    }
+    ALOGD("Got %d input buffers", d->input_buffers.size());
+
+    return d->input_buffers.size();
+}
+
+uint8_t *media_codec_get_nth_input_buffer(MediaCodecDelegate delegate, size_t n)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return NULL;
+
+    if (d->input_buffers.size() == 0)
+    {
+        status_t ret = d->media_codec->getInputBuffers(&d->input_buffers);
+        if (ret != OK)
+        {
+            ALOGE("Failed to get input buffers");
+            return NULL;
+        }
+    }
+
+    if (n > d->input_buffers.size())
+    {
+      ALOGE("Failed to get %uth input buffer, n > total buffer size", n);
+      return NULL;
+    }
+
+    return d->input_buffers.itemAt(n).get()->data();
+}
+
+MediaABufferWrapper* media_codec_get_nth_input_buffer_as_abuffer(MediaCodecDelegate delegate, size_t n)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return NULL;
+
+    if (d->input_buffers.size() == 0)
+    {
+        status_t ret = d->media_codec->getInputBuffers(&d->input_buffers);
+        if (ret != OK)
+        {
+            ALOGE("Failed to get input buffers");
+            return NULL;
+        }
+    }
+
+    if (n > d->input_buffers.size())
+    {
+      ALOGE("Failed to get %uth input buffer, n > total buffer size", n);
+      return NULL;
+    }
+
+    return new MediaABufferPrivate(d->input_buffers.itemAt(n).get());
+}
+
+size_t media_codec_get_nth_input_buffer_capacity(MediaCodecDelegate delegate, size_t n)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    Vector<sp<ABuffer> > input_buffers;
+    status_t ret = d->media_codec->getInputBuffers(&input_buffers);
+    if (ret != OK)
+    {
+        ALOGE("Failed to get input buffers");
+        return 0;
+    }
+
+    if (n > input_buffers.size())
+    {
+      ALOGE("Failed to get %uth input buffer capacity, n > total buffer size", n);
+      return 0;
+    }
+
+    return input_buffers[n].get()->capacity();
+}
+
+size_t media_codec_get_output_buffers_size(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    status_t ret = d->media_codec->getOutputBuffers(&d->output_buffers);
+    if (ret != OK)
+    {
+        ALOGE("Failed to get output buffers size");
+        return 0;
+    }
+    ALOGD("Got %d output buffers", d->output_buffers.size());
+
+    return d->output_buffers.size();
+}
+
+uint8_t *media_codec_get_nth_output_buffer(MediaCodecDelegate delegate, size_t n)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return NULL;
+
+    status_t ret = d->media_codec->getOutputBuffers(&d->output_buffers);
+    if (ret != OK)
+    {
+        ALOGE("Failed to get output buffers");
+        return NULL;
+    }
+
+    if (n > d->output_buffers.size())
+    {
+      ALOGE("Failed to get %uth output buffer, n > total buffer size", n);
+      return NULL;
+    }
+
+    return d->output_buffers.itemAt(n).get()->data();
+}
+
+MediaABufferWrapper* media_codec_get_nth_output_buffer_as_abuffer(MediaCodecDelegate delegate, size_t n)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return NULL;
+
+    if (d->output_buffers.size() == 0)
+    {
+        status_t ret = d->media_codec->getOutputBuffers(&d->output_buffers);
+        if (ret != OK)
+        {
+            ALOGE("Failed to get output buffers");
+            return NULL;
+        }
+    }
+
+    if (n > d->output_buffers.size())
+    {
+      ALOGE("Failed to get %uth output buffer, n > total buffer size", n);
+      return NULL;
+    }
+
+    return new MediaABufferPrivate(d->output_buffers.itemAt(n).get());
+}
+
+size_t media_codec_get_nth_output_buffer_capacity(MediaCodecDelegate delegate, size_t n)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    status_t ret = d->media_codec->getOutputBuffers(&d->output_buffers);
+    if (ret != OK)
+    {
+        ALOGE("Failed to get output buffers");
+        return 0;
+    }
+
+    if (n > d->output_buffers.size())
+    {
+      ALOGE("Failed to get %uth output buffer capacity, n > total buffer size", n);
+      return 0;
+    }
+
+    return d->output_buffers[n].get()->capacity();
+}
+
+#define INFO_TRY_AGAIN_LATER        -1
+#define INFO_OUTPUT_FORMAT_CHANGED  -2
+#define INFO_OUTPUT_BUFFERS_CHANGED -4
+
+int media_codec_dequeue_output_buffer(MediaCodecDelegate delegate, MediaCodecBufferInfo *info, int64_t timeout_us)
+{
+    REPORT_FUNCTION()
+
+    if (info == NULL)
+    {
+        ALOGE("info must not be NULL");
+        return BAD_VALUE;
+    }
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    int ret = d->media_codec->dequeueOutputBuffer(&info->index, &info->offset, &info->size, &info->presentation_time_us, &info->flags, timeout_us);
+    ALOGD("dequeueOutputBuffer() ret: %d", ret);
+    info->render_retries = 0;
+
+    if (ret == -EAGAIN)
+    {
+        ALOGD("dequeueOutputBuffer returned %d", ret);
+        return INFO_TRY_AGAIN_LATER;
+    }
+    else if (ret & ~INFO_OUTPUT_BUFFERS_CHANGED)
+    {
+        ALOGD("Output buffers changed (ret: %d)", ret);
+        return INFO_OUTPUT_BUFFERS_CHANGED + 1;
+    }
+    // FIXME: Get rid of the hardcoded -10 and replace with more elegant solution
+    else if (ret & ~(INFO_FORMAT_CHANGED - 10))
+    {
+        ALOGD("Output buffer format changed (ret: %d)", ret);
+        d->output_format_changed = true;
+        return -2;
+    }
+
+    ALOGD("Dequeued output buffer:\n-----------------------");
+    ALOGD("index: %u", info->index);
+    ALOGD("offset: %d", info->offset);
+    ALOGD("size: %d", info->size);
+    ALOGD("presentation_time_us: %lld", info->presentation_time_us);
+    ALOGD("flags: %d", info->flags);
+
+    d->mtx_output_buffer_infos.lock();
+
+    // Keep track of the used output buffer info
+    d->available_output_buffer_infos.push_back(*info);
+
+    d->mtx_output_buffer_infos.unlock();
+
+    return OK;
+}
+
+int media_codec_queue_input_buffer(MediaCodecDelegate delegate, const MediaCodecBufferInfo *info)
+{
+    REPORT_FUNCTION()
+
+    if (info == NULL)
+    {
+        ALOGE("info must not be NULL");
+        return BAD_VALUE;
+    }
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    // Make sure that there is at least one dequeued input buffer available
+    if (d->available_input_buffer_indices.empty())
+    {
+        ALOGE("Input buffer index %d has not been dequeued, cannot queue input buffer", info->index);
+        return BAD_VALUE;
+    }
+
+    const size_t index = *d->available_input_buffer_indices.begin();
+    d->available_input_buffer_indices.erase(d->available_input_buffer_indices.begin());
+
+    ALOGD("info->index: %d", index);
+    ALOGD("info->offset: %d", info->offset);
+    ALOGD("info->size: %d", info->size);
+    ALOGD("info->presentation_time_us: %lld", info->presentation_time_us);
+    ALOGD("info->flags: %d", info->flags);
+
+    AString err_msg;
+    status_t ret = d->media_codec->queueInputBuffer(index, info->offset, info->size,
+            info->presentation_time_us, info->flags, &err_msg);
+    if (ret != OK)
+    {
+        ALOGE("Failed to queue input buffer (err: %d, index: %d)", ret, index);
+        ALOGE("Detailed error message: %s", err_msg.c_str());
+    }
+
+    return ret;
+}
+
+int media_codec_dequeue_input_buffer(MediaCodecDelegate delegate, size_t *index, int64_t timeout_us)
+{
+    REPORT_FUNCTION()
+
+    if (index == NULL)
+    {
+        ALOGE("index must not be NULL");
+        return BAD_VALUE;
+    }
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    status_t ret = d->media_codec->dequeueInputBuffer(index, timeout_us);
+    if (ret == -EAGAIN)
+    {
+        ALOGD("dequeueInputBuffer returned %d, tried timeout: %lld", ret, timeout_us);
+        return INFO_TRY_AGAIN_LATER;
+    }
+    else if (ret == OK)
+    {
+        ALOGD("Dequeued input buffer (index: %d)", *index);
+        d->available_input_buffer_indices.push_back(*index);
+    }
+    else
+        ALOGE("Failed to dequeue input buffer (err: %d, index: %d)", ret, *index);
+
+    return ret;
+}
+
+int media_codec_release_output_buffer(MediaCodecDelegate delegate, size_t index, uint8_t render)
+{
+    REPORT_FUNCTION()
+    ALOGV("Requesting to release output buffer index: %d, render: %d", index, render);
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    status_t ret = OK;
+
+    /* This function can be called from multiple threads from gstreamer */
+    Mutex::Autolock autoLock(d->mtx_output_buffer_infos);
+
+    auto it = d->available_output_buffer_infos.begin();
+    while (it != d->available_output_buffer_infos.end())
+    {
+        MediaCodecBufferInfo *info = &*it;
+        ALOGD("info index: %d", info->index);
+        ALOGD("info render_retries: %u", info->render_retries);
+        if (info->render_retries == 1)
+        {
+            ALOGV("Rendering and releasing output buffer %d from the available indices list", info->index);
+            ret = d->media_codec->renderOutputBufferAndRelease(info->index);
+            if (ret != OK)
+            {
+                ALOGE("Failed to release output buffer (ret: %d, index: %d)", ret, info->index);
+                ++info->render_retries;
+            }
+            else
+            {
+                ALOGV("Successfully rendered output buffer %d on a second try.", info->index);
+                d->available_output_buffer_infos.erase(it);
+            }
+        }
+        else if (info->render_retries > 1)
+        {
+            ALOGV("Tried to render output buffer %d twice, dropping.", info->index);
+            ret = d->media_codec->releaseOutputBuffer(info->index);
+            d->available_output_buffer_infos.erase(d->available_output_buffer_infos.begin());
+        }
+
+        ++it;
+    }
+
+    MediaCodecBufferInfo *info = &*d->available_output_buffer_infos.begin();
+    // Either render and release the output buffer, or just release.
+    if (render)
+    {
+        ALOGV("Rendering and releasing output buffer %d from the available indices list", info->index);
+        ret = d->media_codec->renderOutputBufferAndRelease(info->index);
+    }
+    else
+    {
+        ALOGV("Releasing output buffer %d from the available indices list", info->index);
+        ret = d->media_codec->releaseOutputBuffer(info->index);
+    }
+    if (ret != OK)
+    {
+        ALOGE("Failed to release output buffer (ret: %d, index: %d)", ret, info->index);
+        ++info->render_retries;
+    } else {
+        ALOGV("Released output buffer %d from the available buffer infos list", info->index);
+        d->available_output_buffer_infos.erase(d->available_output_buffer_infos.begin());
+    }
+
+    return ret;
+}
+
+MediaFormat media_codec_get_output_format(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return NULL;
+
+    _MediaFormat *f = new _MediaFormat();
+
+    sp<AMessage> msg_format;
+    status_t ret = d->media_codec->getOutputFormat(&msg_format);
+    if (ret != OK)
+    {
+        ALOGE("Failed to get the output format");
+        return NULL;
+    }
+
+    ALOGD("Output format: %s", msg_format->debugString().c_str());
+
+    CHECK(msg_format->findString("mime", &f->mime));
+    CHECK(msg_format->findInt32("width", &f->width));
+    CHECK(msg_format->findInt32("height", &f->height));
+    CHECK(msg_format->findInt32("stride", &f->stride));
+    CHECK(msg_format->findInt32("slice-height", &f->slice_height));
+    CHECK(msg_format->findInt32("color-format", &f->color_format));
+    Rect crop;
+    CHECK(msg_format->findRect("crop", &crop.left, &crop.top, &crop.right, &crop.bottom));
+
+    return f;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_codec_list.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+// Uncomment to enable verbose debug output
+#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "MediaCodecList"
+
+#include <hybris/media/media_codec_list.h>
+
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/MediaCodecList.h>
+
+#include <utils/Log.h>
+#include <utils/Vector.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__);
+
+using namespace android;
+
+ssize_t media_codec_list_find_codec_by_type(const char *type, bool encoder, size_t startIndex)
+{
+    REPORT_FUNCTION()
+    return MediaCodecList::getInstance()->findCodecByType(type, encoder, startIndex);
+}
+
+ssize_t media_codec_list_find_codec_by_name(const char *name)
+{
+    REPORT_FUNCTION()
+    return MediaCodecList::getInstance()->findCodecByName(name);
+}
+
+size_t media_codec_list_count_codecs()
+{
+    REPORT_FUNCTION()
+    return MediaCodecList::getInstance()->countCodecs();
+}
+
+void media_codec_list_get_codec_info_at_id(size_t index)
+{
+    REPORT_FUNCTION()
+}
+
+const char *media_codec_list_get_codec_name(size_t index)
+{
+    REPORT_FUNCTION()
+#if ANDROID_VERSION_MAJOR>=5
+    return MediaCodecList::getInstance()->getCodecInfo(index)->getCodecName();
+#else
+    return MediaCodecList::getInstance()->getCodecName(index);
+#endif
+}
+
+bool media_codec_list_is_encoder(size_t index)
+{
+    REPORT_FUNCTION()
+#if ANDROID_VERSION_MAJOR>=5
+    return MediaCodecList::getInstance()->getCodecInfo(index)->isEncoder();
+#else
+    return MediaCodecList::getInstance()->isEncoder(index);
+#endif
+}
+
+size_t media_codec_list_get_num_supported_types(size_t index)
+{
+    REPORT_FUNCTION()
+
+    Vector<AString> types;
+#if ANDROID_VERSION_MAJOR>=5
+    MediaCodecList::getInstance()->getCodecInfo(index)->getSupportedMimes(&types);
+#else
+    status_t err = MediaCodecList::getInstance()->getSupportedTypes(index, &types);
+    if (err != OK)
+    {
+        ALOGE("Failed to get the number of supported codec types (err: %d)", err);
+        return 0;
+    }
+#endif
+    ALOGD("Number of supported codec types: %d", types.size());
+
+    return types.size();
+}
+
+size_t media_codec_list_get_nth_supported_type_len(size_t index, size_t n)
+{
+    REPORT_FUNCTION()
+
+    Vector<AString> types;
+#if ANDROID_VERSION_MAJOR>=5
+    MediaCodecList::getInstance()->getCodecInfo(index)->getSupportedMimes(&types);
+#else
+    status_t err = MediaCodecList::getInstance()->getSupportedTypes(index, &types);
+#endif
+
+    return types[n].size();
+}
+
+int media_codec_list_get_nth_supported_type(size_t index, char *type, size_t n)
+{
+    REPORT_FUNCTION()
+
+    if (type == NULL)
+    {
+        ALOGE("types must not be NULL");
+        return BAD_VALUE;
+    }
+
+    Vector<AString> types;
+#if ANDROID_VERSION_MAJOR>=5
+    MediaCodecList::getInstance()->getCodecInfo(index)->getSupportedMimes(&types);
+#else
+    status_t err = MediaCodecList::getInstance()->getSupportedTypes(index, &types);
+#endif
+    for (size_t i=0; i<types[n].size(); ++i)
+        type[i] = types.itemAt(n).c_str()[i];
+
+#if ANDROID_VERSION_MAJOR>=5
+    return OK;
+#else
+    return err;
+#endif
+}
+
+static void media_codec_list_get_num_codec_capabilities(size_t index, const char *type, size_t *num_profile_levels, size_t *num_color_formats)
+{
+    REPORT_FUNCTION()
+
+#if ANDROID_VERSION_MAJOR>=5
+    Vector<MediaCodecInfo::ProfileLevel> profile_levels;
+#else
+    Vector<MediaCodecList::ProfileLevel> profile_levels;
+#endif
+    Vector<uint32_t> color_formats;
+    ALOGD("index: %d, type: '%s'", index, type);
+#if ANDROID_VERSION_MAJOR>=5
+    MediaCodecList::getInstance()->getCodecInfo(index)->getCapabilitiesFor(type)->getSupportedProfileLevels(&profile_levels);
+    MediaCodecList::getInstance()->getCodecInfo(index)->getCapabilitiesFor(type)->getSupportedColorFormats(&color_formats);
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+    status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &color_formats);
+#else
+    uint32_t flags;
+    status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &color_formats, &flags);
+#endif
+#if ANDROID_VERSION_MAJOR<5
+    if (err != OK)
+    {
+        ALOGE("Failed to get the number of supported codec capabilities (err: %d)", err);
+        return;
+    }
+#endif
+
+    if (num_profile_levels != NULL)
+    {
+        ALOGD("Number of codec profile levels: %d", profile_levels.size());
+        *num_profile_levels = profile_levels.size();
+    }
+    if (num_color_formats != NULL)
+    {
+        ALOGD("Number of codec color formats: %d", color_formats.size());
+        *num_color_formats = color_formats.size();
+    }
+}
+
+size_t media_codec_list_get_num_profile_levels(size_t index, const char *type)
+{
+    REPORT_FUNCTION()
+
+    size_t num = 0;
+    media_codec_list_get_num_codec_capabilities(index, type, &num, NULL);
+
+    return num;
+}
+
+size_t media_codec_list_get_num_color_formats(size_t index, const char *type)
+{
+    REPORT_FUNCTION()
+
+    size_t num = 0;
+    media_codec_list_get_num_codec_capabilities(index, type, NULL, &num);
+
+    return num;
+}
+
+int media_codec_list_get_nth_codec_profile_level(size_t index, const char *type, profile_level *pro_level, size_t n)
+{
+    REPORT_FUNCTION()
+
+    if (type == NULL)
+    {
+        ALOGE("types must not be NULL");
+        return BAD_VALUE;
+    }
+
+    if (pro_level == NULL)
+    {
+        ALOGE("pro_level must not be NULL");
+        return BAD_VALUE;
+    }
+
+#if ANDROID_VERSION_MAJOR>=5
+    Vector<MediaCodecInfo::ProfileLevel> profile_levels;
+#else
+    Vector<MediaCodecList::ProfileLevel> profile_levels;
+#endif
+    Vector<uint32_t> formats;
+#if ANDROID_VERSION_MAJOR>=5
+    MediaCodecList::getInstance()->getCodecInfo(index)->getCapabilitiesFor(type)->getSupportedProfileLevels(&profile_levels);
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+    status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &formats);
+#else
+    uint32_t flags;
+    status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &formats, &flags);
+#endif
+#if ANDROID_VERSION_MAJOR<5
+    if (err != OK)
+    {
+        ALOGE("Failed to get the nth codec profile level (err: %d)", err);
+        return 0;
+    }
+#endif
+
+    pro_level->profile = profile_levels[n].mProfile;
+    pro_level->level = profile_levels[n].mLevel;
+
+#if ANDROID_VERSION_MAJOR>=5
+    return OK;
+#else
+    return err;
+#endif
+}
+
+int media_codec_list_get_codec_color_formats(size_t index, const char *type, uint32_t *color_formats)
+{
+    REPORT_FUNCTION()
+
+#if ANDROID_VERSION_MAJOR>=5
+    Vector<MediaCodecInfo::ProfileLevel> profile_levels;
+#else
+    Vector<MediaCodecList::ProfileLevel> profile_levels;
+#endif
+    Vector<uint32_t> formats;
+#if ANDROID_VERSION_MAJOR>=5
+    MediaCodecList::getInstance()->getCodecInfo(index)->getCapabilitiesFor(type)->getSupportedColorFormats(&formats);
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+    status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &formats);
+#else
+    uint32_t flags;
+    status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &formats, &flags);
+#endif
+#if ANDROID_VERSION_MAJOR<5
+    if (err != OK)
+    {
+        ALOGE("Failed to get the number of supported codec types (err: %d)", err);
+        return 0;
+    }
+#endif
+
+    for (size_t i=0; i<formats.size(); ++i)
+    {
+        color_formats[i] = formats[i];
+        ALOGD("Color format [%d]: %d", i, formats[i]);
+    }
+
+    return OK;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_codec_source_layer.cpp
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Simon Fels <simon.fels@canonical.com>
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "MediaCompatibilityLayer"
+
+#include <gui/Surface.h>
+
+#include <media/ICrypto.h>
+
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaCodecSource.h>
+#include <media/stagefright/MediaErrors.h>
+
+#include <hybris/media/media_codec_source_layer.h>
+
+#include "media_message_priv.h"
+#include "media_buffer_priv.h"
+#include "media_meta_data_priv.h"
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__);
+
+struct MediaSourcePrivate : public android::MediaSource
+{
+public:
+    static MediaSourcePrivate* toPrivate(MediaSourceWrapper *source);
+
+    android::status_t start(android::MetaData *params = NULL);
+    android::status_t stop();
+    android::sp<android::MetaData> getFormat();
+    android::status_t read(android::MediaBuffer **buffer, const android::MediaSource::ReadOptions *options = NULL);
+    android::status_t pause();
+
+    android::sp<android::MetaData> format;
+
+    MediaSourceStartCallback start_callback;
+    void *start_callback_data;
+    MediaSourceStopCallback stop_callback;
+    void *stop_callback_data;
+    MediaSourceReadCallback read_callback;
+    void *read_callback_data;
+    MediaSourcePauseCallback pause_callback;
+    void *pause_callback_data;
+};
+
+MediaSourcePrivate* MediaSourcePrivate::toPrivate(MediaSourceWrapper *source)
+{
+    if (!source)
+        return NULL;
+
+    return static_cast<MediaSourcePrivate*>(source);
+}
+
+android::status_t MediaSourcePrivate::start(android::MetaData *params)
+{
+    if(!start_callback)
+        return android::ERROR_UNSUPPORTED;
+
+    return start_callback(nullptr, start_callback_data);
+}
+
+android::status_t MediaSourcePrivate::stop()
+{
+    if (!stop_callback)
+        return android::ERROR_UNSUPPORTED;
+
+    return stop_callback(stop_callback_data);
+}
+
+android::sp<android::MetaData> MediaSourcePrivate::getFormat()
+{
+    return format;
+}
+
+android::status_t MediaSourcePrivate::read(android::MediaBuffer **buffer, const android::MediaSource::ReadOptions *options)
+{
+    (void) options;
+
+    if (!read_callback)
+        return android::ERROR_UNSUPPORTED;
+
+    MediaBufferPrivate *buf = NULL;
+
+    int err = read_callback(reinterpret_cast<MediaBufferWrapper**>(&buf), read_callback_data);
+    if (!buf)
+        return err;
+
+    *buffer = buf->buffer;
+
+    return err;
+}
+
+android::status_t MediaSourcePrivate::pause()
+{
+    if (!pause_callback)
+        return android::ERROR_UNSUPPORTED;
+
+    return pause_callback(pause_callback_data);
+}
+
+MediaSourceWrapper* media_source_create(void)
+{
+    MediaSourcePrivate *d  = new MediaSourcePrivate;
+    if (!d)
+        return NULL;
+
+    return d;
+}
+
+void media_source_release(MediaSourceWrapper *source)
+{
+    MediaSourcePrivate *d = MediaSourcePrivate::toPrivate(source);
+    if (!d)
+        return;
+
+    delete d;
+}
+
+void media_source_set_format(MediaSourceWrapper *source, MediaMetaDataWrapper *meta)
+{
+    MediaSourcePrivate *d = MediaSourcePrivate::toPrivate(source);
+    if (!d)
+        return;
+
+    auto dm = MediaMetaDataPrivate::toPrivate(meta);
+    if (!dm)
+        return;
+
+    d->format = dm->data;
+}
+
+void media_source_set_start_callback(MediaSourceWrapper *source, MediaSourceStartCallback callback, void *user_data)
+{
+    MediaSourcePrivate *d = MediaSourcePrivate::toPrivate(source);
+    if (!d)
+        return;
+
+    d->start_callback = callback;
+    d->start_callback_data = user_data;
+}
+
+void media_source_set_stop_callback(MediaSourceWrapper *source, MediaSourceStopCallback callback, void *user_data)
+{
+    MediaSourcePrivate *d = MediaSourcePrivate::toPrivate(source);
+    if (!d)
+        return;
+
+    d->stop_callback = callback;
+    d->stop_callback_data = user_data;
+}
+
+void media_source_set_read_callback(MediaSourceWrapper *source, MediaSourceReadCallback callback, void *user_data)
+{
+    MediaSourcePrivate *d = MediaSourcePrivate::toPrivate(source);
+    if (!d)
+        return;
+
+    d->read_callback = callback;
+    d->read_callback_data = user_data;
+}
+
+void media_source_set_pause_callback(MediaSourceWrapper *source, MediaSourcePauseCallback callback, void *user_data)
+{
+    MediaSourcePrivate *d = MediaSourcePrivate::toPrivate(source);
+    if (!d)
+        return;
+
+    d->pause_callback = callback;
+    d->pause_callback_data = user_data;
+}
+
+struct MediaCodecSourcePrivate : public android::AHandler
+{
+public:
+    static MediaCodecSourcePrivate* toPrivate(MediaCodecSourceWrapper *source);
+
+    explicit MediaCodecSourcePrivate(void *context);
+    virtual ~MediaCodecSourcePrivate();
+
+protected:
+    virtual void onMessageReceived(const android::sp<android::AMessage> &msg);
+
+public:
+    void *context;
+    unsigned int refcount;
+    android::sp<android::ALooper> looper;
+    android::sp<android::MediaCodecSource> codec;
+    android::sp<android::Surface> input_surface;
+    android::sp<android::MediaSource> source;
+};
+
+MediaCodecSourcePrivate* MediaCodecSourcePrivate::toPrivate(MediaCodecSourceWrapper *source)
+{
+    if (!source)
+        return NULL;
+
+    return static_cast<MediaCodecSourcePrivate*>(source);
+}
+
+MediaCodecSourcePrivate::MediaCodecSourcePrivate(void *context) :
+    context(context),
+    refcount(1)
+{
+    REPORT_FUNCTION();
+}
+
+MediaCodecSourcePrivate::~MediaCodecSourcePrivate()
+{
+    REPORT_FUNCTION();
+}
+
+void MediaCodecSourcePrivate::onMessageReceived(const android::sp<android::AMessage> &msg)
+{
+    (void) msg;
+}
+
+MediaCodecSourceWrapper* media_codec_source_create(MediaMessageWrapper *format, MediaSourceWrapper *source, int flags)
+{
+    if (!format)
+        return NULL;
+
+    MediaCodecSourcePrivate *d = new MediaCodecSourcePrivate(NULL);
+    if (!d)
+        return NULL;
+
+    d->looper = new android::ALooper();
+    d->looper->start();
+
+    d->source = MediaSourcePrivate::toPrivate(source);
+
+    MediaMessagePrivate *dm = MediaMessagePrivate::toPrivate(format);
+
+    ALOGV("Creating media codec source");
+#if ANDROID_VERSION_MAJOR>=6
+    // We don't use persistent input surface
+    d->codec = android::MediaCodecSource::Create(d->looper, dm->msg, d->source, NULL, flags);
+#else
+    d->codec = android::MediaCodecSource::Create(d->looper, dm->msg, d->source, flags);
+#endif
+
+    return d;
+}
+
+void media_codec_source_release(MediaCodecSourceWrapper *source)
+{
+    MediaCodecSourcePrivate *d = MediaCodecSourcePrivate::toPrivate(source);
+    if (!d)
+        return;
+
+    delete d;
+}
+
+MediaNativeWindowHandle* media_codec_source_get_native_window_handle(MediaCodecSourceWrapper *source)
+{
+    MediaCodecSourcePrivate *d = MediaCodecSourcePrivate::toPrivate(source);
+    if (!d)
+        return NULL;
+
+    if (!d->input_surface.get())
+        d->input_surface = new android::Surface(d->codec->getGraphicBufferProducer());
+
+    return static_cast<ANativeWindow*>(d->input_surface.get());
+}
+
+MediaMetaDataWrapper* media_codec_source_get_format(MediaCodecSourceWrapper *source)
+{
+    MediaCodecSourcePrivate *d = MediaCodecSourcePrivate::toPrivate(source);
+    if (!d)
+        return NULL;
+
+    return new MediaMetaDataPrivate(d->codec->getFormat());
+}
+
+bool media_codec_source_start(MediaCodecSourceWrapper *source)
+{
+    MediaCodecSourcePrivate *d = MediaCodecSourcePrivate::toPrivate(source);
+    if (!d)
+        return false;
+
+    android::status_t err = d->codec->start(NULL);
+    if (err != android::OK)
+        return false;
+
+    return true;
+}
+
+bool media_codec_source_stop(MediaCodecSourceWrapper *source)
+{
+    MediaCodecSourcePrivate *d = MediaCodecSourcePrivate::toPrivate(source);
+    if (!d)
+        return false;
+
+    android::status_t err = d->codec->stop();
+    if (err != android::OK)
+        return false;
+
+    return true;
+}
+
+bool media_codec_source_pause(MediaCodecSourceWrapper *source)
+{
+    MediaCodecSourcePrivate *d = MediaCodecSourcePrivate::toPrivate(source);
+    if (!d)
+        return false;
+
+    android::status_t err = d->codec->pause();
+    if (err != android::OK)
+        return false;
+
+    return true;
+}
+
+bool media_codec_source_read(MediaCodecSourceWrapper *source, MediaBufferWrapper **buffer)
+{
+    MediaCodecSourcePrivate *d = MediaCodecSourcePrivate::toPrivate(source);
+    if (!d)
+        return false;
+
+    android::MediaBuffer *buff = NULL;
+    android::status_t err = d->codec->read(&buff);
+    if (err != android::OK)
+        return false;
+
+    *buffer = new MediaBufferPrivate(buff);
+
+    return true;
+}
+
+bool media_codec_source_request_idr_frame(MediaCodecSourceWrapper *source)
+{
+    MediaCodecSourcePrivate *d = MediaCodecSourcePrivate::toPrivate(source);
+    if (!d || !d->codec.get())
+        return false;
+
+    android::status_t err = d->codec->requestIDRFrame();
+    if (err != android::OK)
+        return false;
+
+    return true;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_compatibility_layer.cpp
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ */
+
+// Uncomment to enable verbose debug output
+#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "MediaCompatibilityLayer"
+
+#include <hybris/media/media_compatibility_layer.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <media/mediaplayer.h>
+
+#include <binder/ProcessState.h>
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+#include <gui/SurfaceTexture.h>
+#else
+#include <gui/GLConsumer.h>
+#endif
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <utils/Log.h>
+
+#include <gui/NativeBufferAlloc.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__)
+
+namespace android
+{
+NativeBufferAlloc::NativeBufferAlloc() {
+}
+
+NativeBufferAlloc::~NativeBufferAlloc() {
+}
+
+sp<GraphicBuffer> NativeBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h,
+			PixelFormat format, uint32_t usage, status_t* error) {
+	sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
+	status_t err = graphicBuffer->initCheck();
+	*error = err;
+	if (err != 0 || graphicBuffer->handle == 0) {
+		if (err == NO_MEMORY) {
+			GraphicBuffer::dumpAllocationsToSystemLog();
+		}
+		ALOGI("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
+				"failed (%s), handle=%p",
+				w, h, strerror(-err), graphicBuffer->handle);
+		return 0;
+	}
+	return graphicBuffer;
+}
+}
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+struct FrameAvailableListener : public android::SurfaceTexture::FrameAvailableListener
+#else
+struct FrameAvailableListener : public android::GLConsumer::FrameAvailableListener
+#endif
+{
+	public:
+		FrameAvailableListener()
+			: set_video_texture_needs_update_cb(NULL),
+			video_texture_needs_update_context(NULL)
+		{
+		}
+
+		// From android::GLConsumer/SurfaceTexture::FrameAvailableListener
+#if ANDROID_VERSION_MAJOR==5 && ANDROID_VERSION_MINOR>=1 || ANDROID_VERSION_MAJOR>=6
+		virtual void onFrameAvailable(const android::BufferItem& item)
+#else
+		virtual void onFrameAvailable()
+#endif
+		{
+			if (set_video_texture_needs_update_cb != NULL)
+				set_video_texture_needs_update_cb(video_texture_needs_update_context);
+		}
+
+		void setVideoTextureNeedsUpdateCb(on_video_texture_needs_update cb, void *context)
+		{
+			set_video_texture_needs_update_cb = cb;
+			video_texture_needs_update_context = context;
+		}
+
+	private:
+		on_video_texture_needs_update set_video_texture_needs_update_cb;
+		void *video_texture_needs_update_context;
+};
+
+class MediaPlayerListenerWrapper : public android::MediaPlayerListener
+{
+	public:
+		MediaPlayerListenerWrapper()
+			: set_video_size_cb(NULL),
+			video_size_context(NULL),
+			error_cb(NULL),
+			error_context(NULL),
+			playback_complete_cb(NULL),
+			playback_complete_context(NULL),
+			media_prepared_cb(NULL),
+			media_prepared_context(NULL)
+		{
+		}
+
+		void notify(int msg, int ext1, int ext2, const android::Parcel *obj)
+		{
+			ALOGV("\tmsg: %d, ext1: %d, ext2: %d \n", msg, ext1, ext2);
+
+			switch (msg) {
+			case android::MEDIA_PREPARED:
+				ALOGV("\tMEDIA_PREPARED msg\n");
+				if (media_prepared_cb != NULL)
+					media_prepared_cb(media_prepared_context);
+				else
+					ALOGW("Failed to signal media prepared, callback not set.");
+				break;
+			case android::MEDIA_PLAYBACK_COMPLETE:
+				ALOGV("\tMEDIA_PLAYBACK_COMPLETE msg\n");
+				if (playback_complete_cb != NULL)
+					playback_complete_cb(playback_complete_context);
+				else
+					ALOGW("Failed to signal end of playback, callback not set.");
+				break;
+			case android::MEDIA_BUFFERING_UPDATE:
+				ALOGV("\tMEDIA_BUFFERING_UPDATE msg\n");
+				break;
+			case android::MEDIA_SEEK_COMPLETE:
+				ALOGV("\tMEDIA_SEEK_COMPLETE msg\n");
+				break;
+			case android::MEDIA_SET_VIDEO_SIZE:
+				ALOGV("\tMEDIA_SET_VIDEO_SIZE msg\n");
+				if (set_video_size_cb != NULL)
+					set_video_size_cb(ext2, ext1, video_size_context);
+				else
+					ALOGE("Failed to set video size. set_video_size_cb is NULL.");
+				break;
+			case android::MEDIA_TIMED_TEXT:
+				ALOGV("\tMEDIA_TIMED_TEXT msg\n");
+				break;
+			case android::MEDIA_ERROR:
+				ALOGV("\tMEDIA_ERROR msg\n");
+				// TODO: Extend this cb to include the error message
+				if (error_cb != NULL)
+					error_cb(error_context);
+				else
+					ALOGE("Failed to signal error to app layer, callback not set.");
+				break;
+			case android::MEDIA_INFO:
+				ALOGV("\tMEDIA_INFO msg\n");
+				break;
+			default:
+				ALOGV("\tUnknown media msg\n");
+			}
+		}
+
+		void setVideoSizeCb(on_msg_set_video_size cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			set_video_size_cb = cb;
+			video_size_context = context;
+		}
+
+		void setErrorCb(on_msg_error cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			error_cb = cb;
+			error_context = context;
+		}
+
+		void setPlaybackCompleteCb(on_playback_complete cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			playback_complete_cb = cb;
+			playback_complete_context = context;
+		}
+
+		void setMediaPreparedCb(on_media_prepared cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			media_prepared_cb = cb;
+			media_prepared_context = context;
+		}
+
+	private:
+		on_msg_set_video_size set_video_size_cb;
+		void *video_size_context;
+		on_msg_error error_cb;
+		void *error_context;
+		on_playback_complete playback_complete_cb;
+		void *playback_complete_context;
+		on_media_prepared media_prepared_cb;
+		void *media_prepared_context;
+};
+
+// ----- MediaPlayer Wrapper ----- //
+
+struct MediaPlayerWrapper : public android::MediaPlayer
+{
+	public:
+		MediaPlayerWrapper()
+			: MediaPlayer(),
+			texture(NULL),
+			media_player_listener(new MediaPlayerListenerWrapper()),
+			frame_listener(new FrameAvailableListener),
+			left_volume(1), // Set vol to 100% for this track by default
+			right_volume(1),
+			source_fd(-1)
+		{
+			setListener(media_player_listener);
+			// Update the live volume with the cached values
+			MediaPlayer::setVolume(left_volume, right_volume);
+		}
+
+		~MediaPlayerWrapper()
+		{
+			reset();
+			source_fd = -1;
+		}
+
+#if  ANDROID_VERSION_MAJOR>=5
+		android::status_t setVideoSurfaceTexture(android::sp<android::IGraphicBufferProducer> bq, const android::sp<android::GLConsumer> &surfaceTexture)
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+		android::status_t setVideoSurfaceTexture(const android::sp<android::SurfaceTexture> &surfaceTexture)
+#else
+		android::status_t setVideoSurfaceTexture(android::sp<android::BufferQueue> bq, const android::sp<android::GLConsumer> &surfaceTexture)
+#endif
+		{
+			REPORT_FUNCTION();
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+			surfaceTexture->getBufferQueue()->setBufferCount(5);
+#else
+			bq->setBufferCount(5);
+#endif
+			texture = surfaceTexture;
+			texture->setFrameAvailableListener(frame_listener);
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+			return MediaPlayer::setVideoSurfaceTexture(surfaceTexture->getBufferQueue());
+#else
+			return MediaPlayer::setVideoSurfaceTexture(bq);
+#endif
+		}
+
+		void updateGLConsumer()
+		{
+			assert(texture != NULL);
+			texture->updateTexImage();
+		}
+
+		void get_transformation_matrix_for_surface_texture(GLfloat* matrix)
+		{
+			assert(texture != NULL);
+			texture->getTransformMatrix(matrix);
+		}
+
+		void setVideoSizeCb(on_msg_set_video_size cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			assert(media_player_listener != NULL);
+			media_player_listener->setVideoSizeCb(cb, context);
+		}
+
+		void setVideoTextureNeedsUpdateCb(on_video_texture_needs_update cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			assert(frame_listener != NULL);
+			frame_listener->setVideoTextureNeedsUpdateCb(cb, context);
+		}
+
+		void setErrorCb(on_msg_error cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			assert(media_player_listener != NULL);
+			media_player_listener->setErrorCb(cb, context);
+		}
+
+		void setPlaybackCompleteCb(on_playback_complete cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			assert(media_player_listener != NULL);
+			media_player_listener->setPlaybackCompleteCb(cb, context);
+		}
+
+		void setMediaPreparedCb(on_media_prepared cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			assert(media_player_listener != NULL);
+			media_player_listener->setMediaPreparedCb(cb, context);
+		}
+
+		void getVolume(float *leftVolume, float *rightVolume)
+		{
+			*leftVolume = left_volume;
+			*rightVolume = right_volume;
+		}
+
+		android::status_t setVolume(float leftVolume, float rightVolume)
+		{
+			REPORT_FUNCTION();
+
+			left_volume = leftVolume;
+			right_volume = rightVolume;
+			return MediaPlayer::setVolume(leftVolume, rightVolume);
+		}
+
+		int getSourceFd() const { return source_fd; }
+		void setSourceFd(int fd) { source_fd = fd; }
+
+	private:
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+		android::sp<android::SurfaceTexture> texture;
+#else
+		android::sp<android::GLConsumer> texture;
+#endif
+		android::sp<MediaPlayerListenerWrapper> media_player_listener;
+		android::sp<FrameAvailableListener> frame_listener;
+		float left_volume;
+		float right_volume;
+		int source_fd;
+}; // MediaPlayerWrapper
+
+using namespace android;
+
+// ----- Media Player C API Implementation ----- //
+
+void android_media_set_video_size_cb(MediaPlayerWrapper *mp, on_msg_set_video_size cb, void *context)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->setVideoSizeCb(cb, context);
+}
+
+void android_media_set_video_texture_needs_update_cb(MediaPlayerWrapper *mp, on_video_texture_needs_update cb, void *context)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->setVideoTextureNeedsUpdateCb(cb, context);
+}
+
+void android_media_set_error_cb(MediaPlayerWrapper *mp, on_msg_error cb, void *context)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->setErrorCb(cb, context);
+}
+
+void android_media_set_playback_complete_cb(MediaPlayerWrapper *mp, on_playback_complete cb, void *context)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->setPlaybackCompleteCb(cb, context);
+}
+
+void android_media_set_media_prepared_cb(MediaPlayerWrapper *mp, on_media_prepared cb, void *context)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->setMediaPreparedCb(cb, context);
+}
+
+MediaPlayerWrapper *android_media_new_player()
+{
+	REPORT_FUNCTION();
+
+	MediaPlayerWrapper *mp = new MediaPlayerWrapper();
+	if (mp == NULL) {
+		ALOGE("Failed to create new MediaPlayerWrapper instance.");
+		return NULL;
+	}
+
+	// Required for internal player state processing. Without this, prepare() and start() hang.
+	ProcessState::self()->startThreadPool();
+
+	return mp;
+}
+
+int android_media_set_data_source(MediaPlayerWrapper *mp, const char* url)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	if (url == NULL) {
+		ALOGE("url must not be NULL");
+		return BAD_VALUE;
+	}
+
+	ALOGD("url: %s", url);
+
+	String16 src(url);
+	if (src.startsWith(String16("http://")) == true) {
+		ALOGD("HTTP source URL detected");
+#if 0 // remarked for future debugging - chunsang
+#if ANDROID_VERSION_MAJOR==5
+		mp->setDataSource(NULL,url, NULL);
+#else
+		mp->setDataSource(url, NULL);
+#endif
+#endif
+	} else {
+		ALOGD("File source URL detected");
+		int fd = open(url, O_RDONLY);
+		if (fd < 0)
+		{
+			ALOGE("Failed to open source data at: %s\n", url);
+			return BAD_VALUE;
+		}
+
+		mp->setSourceFd(fd);
+
+		struct stat st;
+		stat(url, &st);
+
+		ALOGD("source file length: %lld\n", st.st_size);
+
+		mp->setDataSource(fd, 0, st.st_size);
+	}
+	mp->prepare();
+
+	return OK;
+}
+
+int android_media_set_preview_texture(MediaPlayerWrapper *mp, int texture_id)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	android::sp<android::NativeBufferAlloc> native_alloc(
+			new android::NativeBufferAlloc()
+			);
+
+#if ANDROID_VERSION_MAJOR>=5
+	android::sp<IGraphicBufferProducer> producer;
+	android::sp<IGraphicBufferConsumer> consumer;
+	BufferQueue::createBufferQueue(&producer, &consumer);
+#else
+	android::sp<android::BufferQueue> buffer_queue(
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+			new android::BufferQueue(false, NULL, native_alloc)
+#else
+			new android::BufferQueue(NULL)
+#endif
+			);
+#endif
+
+	static const bool allow_synchronous_mode = true;
+	// Create a new GLConsumer/SurfaceTexture from the texture_id in synchronous mode (don't wait on all data in the buffer)
+#if ANDROID_VERSION_MAJOR>=5
+	mp->setVideoSurfaceTexture(producer, android::sp<android::GLConsumer>(
+				new android::GLConsumer(
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+	mp->setVideoSurfaceTexture(android::sp<android::SurfaceTexture>(
+				new android::SurfaceTexture(
+#else
+	mp->setVideoSurfaceTexture(buffer_queue, android::sp<android::GLConsumer>(
+				new android::GLConsumer(
+#endif
+#if ANDROID_VERSION_MAJOR>=5
+					consumer,
+					texture_id,
+					GL_TEXTURE_EXTERNAL_OES,
+					true,
+					false)));
+
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+					texture_id,
+					allow_synchronous_mode,
+					GL_TEXTURE_EXTERNAL_OES,
+					true,
+					buffer_queue)));
+#else
+					buffer_queue,
+					texture_id,
+					GL_TEXTURE_EXTERNAL_OES,
+					true,
+					false)));
+#endif
+
+	return OK;
+}
+
+void android_media_update_surface_texture(MediaPlayerWrapper *mp)
+{
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->updateGLConsumer();
+}
+
+void android_media_surface_texture_get_transformation_matrix(MediaPlayerWrapper *mp, GLfloat* matrix)
+{
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->get_transformation_matrix_for_surface_texture(matrix);
+}
+
+int android_media_play(MediaPlayerWrapper *mp)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	mp->start();
+	const char *tmp = mp->isPlaying() ? "yes" : "no";
+	ALOGV("Is playing?: %s\n", tmp);
+
+	return OK;
+}
+
+int android_media_pause(MediaPlayerWrapper *mp)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	mp->pause();
+
+	return OK;
+}
+
+int android_media_stop(MediaPlayerWrapper *mp)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	mp->stop();
+
+	int fd = mp->getSourceFd();
+	if (fd > -1)
+		close(fd);
+
+	return OK;
+}
+
+bool android_media_is_playing(MediaPlayerWrapper *mp)
+{
+	if (mp != NULL) {
+		if (mp->isPlaying())
+			return true;
+	}
+
+	return false;
+}
+
+int android_media_seek_to(MediaPlayerWrapper *mp, int msec)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	return mp->seekTo(msec);
+}
+
+int android_media_get_current_position(MediaPlayerWrapper *mp, int *msec)
+{
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	return mp->getCurrentPosition(msec);
+}
+
+int android_media_get_duration(MediaPlayerWrapper *mp, int *msec)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	return mp->getDuration(msec);
+}
+
+int android_media_get_volume(MediaPlayerWrapper *mp, int *volume)
+{
+	REPORT_FUNCTION();
+
+	if (volume == NULL) {
+		ALOGE("volume must not be NULL");
+		return BAD_VALUE;
+	}
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	float left_volume = 0, right_volume = 0;
+	mp->getVolume(&left_volume, &right_volume);
+	*volume = left_volume * 100;
+
+	return OK;
+}
+
+int android_media_set_volume(MediaPlayerWrapper *mp, int volume)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	float left_volume = float(volume / 100);
+	float right_volume = float(volume / 100);
+	return mp->setVolume(left_volume, right_volume);
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_core.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Simon Fels <simon.fels@canonical.com>
+ */
+
+unsigned int hybris_media_get_version(void)
+{
+	/* The version number here will be bumped when the ABI of the
+	 * media compatibility layer changes. This version number will
+	 * be used by clients to track newly added functionality.
+	 *
+	 * If new functionality is added the client side is responsible
+	 * to continue working on platforms where the new functionality
+	 * is not yet available.
+	 *
+	 * Changelog:
+	 * 1:
+	 *  - Introduction of the new versioning approach
+	 *  - MediaCodecSource support for Android 5.x based platforms
+	 *  - Wrappers for AMessage, MediaBuffer, MediaMetaData etc. to
+	 *    support MediaCodecSource implementation
+	 */
+	return 1;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_format_layer.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+// Uncomment to enable verbose debug output
+#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "MediaFormatLayer"
+
+#include <hybris/media/media_format_layer.h>
+#include "media_format_layer_priv.h"
+
+#include <assert.h>
+
+#include <utils/Log.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__);
+
+using namespace android;
+
+static inline _MediaFormat *get_internal_format(MediaFormat format)
+{
+    if (format == NULL)
+    {
+        ALOGE("format must not be NULL");
+        return NULL;
+    }
+
+    _MediaFormat *mf = static_cast<_MediaFormat*>(format);
+    assert(mf->refcount >= 1);
+
+    return mf;
+}
+
+MediaFormat media_format_create_video_format(const char *mime, int32_t width, int32_t height, int64_t duration_us, int32_t max_input_size)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *format = new _MediaFormat();
+    format->mime = AString(mime);
+    format->width = width;
+    format->height = height;
+    format->duration_us = duration_us;
+    format->max_input_size = max_input_size;
+
+    return format;
+}
+
+void media_format_destroy(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return;
+
+    if (mf->refcount)
+        return;
+
+    delete mf;
+}
+
+void media_format_ref(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return;
+
+    mf->refcount++;
+}
+
+void media_format_unref(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return;
+
+    if (mf->refcount)
+        mf->refcount--;
+}
+
+void media_format_set_byte_buffer(MediaFormat format, const char *key, uint8_t *data, size_t size)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return;
+    if (key == NULL || data == NULL || size == 0)
+        return;
+
+    mf->csd_key_name = AString(key);
+    mf->csd = sp<ABuffer>(new ABuffer(data, size));
+}
+
+const char* media_format_get_mime(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return NULL;
+
+    return mf->mime.c_str();
+}
+
+int64_t media_format_get_duration_us(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->duration_us;
+}
+
+int32_t media_format_get_width(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->width;
+}
+
+int32_t media_format_get_height(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->height;
+}
+
+int32_t media_format_get_max_input_size(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->max_input_size;
+}
+
+int32_t media_format_get_stride(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->stride;
+}
+
+int32_t media_format_get_slice_height(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->slice_height;
+}
+
+int32_t media_format_get_color_format(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->color_format;
+}
+
+int32_t media_format_get_crop_left(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->crop_left;
+}
+
+int32_t media_format_get_crop_right(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->crop_right;
+}
+
+int32_t media_format_get_crop_top(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->crop_top;
+}
+
+int32_t media_format_get_crop_bottom(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->crop_bottom;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_format_layer_priv.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#include <stddef.h>
+#include <unistd.h>
+
+#include <media/stagefright/foundation/AString.h>
+
+#include <utils/RefBase.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _MediaFormat : public RefBase
+{
+    _MediaFormat()
+      : refcount(1)
+    {
+    }
+
+    AString mime;
+    int64_t duration_us;
+    int32_t width;
+    int32_t height;
+    int32_t max_input_size;
+
+    unsigned int refcount;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_format_layer_priv.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_FORMAT_LAYER_PRIV_H_
+#define MEDIA_FORMAT_LAYER_PRIV_H_
+
+#include <stddef.h>
+#include <unistd.h>
+
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/ABuffer.h>
+
+#include <utils/RefBase.h>
+
+struct _MediaFormat : public android::RefBase
+{
+    _MediaFormat()
+      : duration_us(0),
+        width(0),
+        height(0),
+        max_input_size(0),
+        csd(NULL),
+        stride(0),
+        slice_height(0),
+        color_format(0),
+        crop_left(0),
+        crop_right(0),
+        crop_top(0),
+        crop_bottom(0),
+        refcount(1)
+    {
+    }
+
+    android::AString mime;
+    int64_t duration_us;
+    int32_t width;
+    int32_t height;
+    int32_t max_input_size;
+    android::AString csd_key_name;
+    android::sp<android::ABuffer> csd;
+
+    int32_t stride;
+    int32_t slice_height;
+    int32_t color_format;
+    int32_t crop_left;
+    int32_t crop_right;
+    int32_t crop_top;
+    int32_t crop_bottom;
+
+    unsigned int refcount;
+};
+
+#endif // MEDIA_FORMAT_LAYER_PRIV_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_message_layer.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Simon Fels <simon.fels@canonical.com>
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "MediaCompatibilityLayer"
+
+#include <hybris/media/media_message_layer.h>
+
+#include "media_message_priv.h"
+
+MediaMessagePrivate* MediaMessagePrivate::toPrivate(MediaMessageWrapper *msg)
+{
+    if (!msg)
+        return NULL;
+
+    return static_cast<MediaMessagePrivate*>(msg);
+}
+
+MediaMessagePrivate::MediaMessagePrivate() :
+    msg(new android::AMessage)
+{
+}
+
+MediaMessagePrivate::~MediaMessagePrivate()
+{
+}
+
+MediaMessageWrapper* media_message_create()
+{
+    MediaMessagePrivate *d = new MediaMessagePrivate;
+    if (!d)
+        return NULL;
+
+    return d;
+}
+
+void media_message_release(MediaMessageWrapper *msg)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return;
+
+    delete d;
+}
+
+void media_message_clear(MediaMessageWrapper *msg)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return;
+
+    d->msg->clear();
+}
+
+const char* media_message_dump(MediaMessageWrapper *msg)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return NULL;
+
+    return d->msg->debugString().c_str();
+}
+
+void media_message_set_int32(MediaMessageWrapper *msg, const char *name, int32_t value)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return;
+
+    d->msg->setInt32(name, value);
+}
+
+void media_message_set_int64(MediaMessageWrapper *msg, const char *name, int64_t value)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return;
+
+    d->msg->setInt64(name, value);
+}
+
+void media_message_set_size(MediaMessageWrapper *msg, const char *name, ssize_t value)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return;
+
+    d->msg->setSize(name, value);
+}
+
+void media_message_set_float(MediaMessageWrapper *msg, const char *name, float value)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return;
+
+    d->msg->setFloat(name, value);
+}
+
+void media_message_set_double(MediaMessageWrapper *msg, const char *name, double value)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return;
+
+    d->msg->setDouble(name, value);
+}
+
+void media_message_set_string(MediaMessageWrapper *msg, const char *name, const char *value, ssize_t len)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return;
+
+
+    d->msg->setString(name, value);
+}
+
+bool media_message_find_int32(MediaMessageWrapper *msg, const char *name, int32_t *value)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return false;
+
+    return d->msg->findInt32(name, value);
+}
+
+bool media_message_find_int64(MediaMessageWrapper *msg, const char *name, int64_t *value)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return false;
+
+    int64_t v;
+    if (!d->msg->findInt64(name, &v))
+        return false;
+
+    if (value)
+        *value = v;
+    return true;
+}
+
+bool media_message_find_size(MediaMessageWrapper *msg, const char *name, size_t *value)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return false;
+
+    size_t v;
+    if (d->msg->findSize(name, &v))
+        return false;
+
+    if (value)
+        *value = v;
+
+    return true;
+}
+
+bool media_message_find_float(MediaMessageWrapper *msg, const char *name, float *value)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return false;
+
+    float v;
+    if (!d->msg->findFloat(name, &v))
+        return false;
+
+    if (value)
+        *value = v;
+
+    return true;
+}
+
+bool media_message_find_double(MediaMessageWrapper *msg, const char *name, double *value)
+{
+    MediaMessagePrivate *d = MediaMessagePrivate::toPrivate(msg);
+    if (!d)
+        return false;
+
+    double v;
+    if (!d->msg->findDouble(name, &v))
+        return false;
+
+    if (value)
+        *value = v;
+
+    return true;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_message_priv.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Simon Fels <simon.fels@canonical.com>
+ */
+
+#ifndef MEDIA_MESSAGE_PRIV_H_
+#define MEDIA_MESSAGE_PRIV_H_
+
+#include <hybris/media/media_message_layer.h>
+
+#include <media/stagefright/foundation/AMessage.h>
+
+struct MediaMessagePrivate
+{
+public:
+    static MediaMessagePrivate* toPrivate(MediaMessageWrapper *msg);
+
+    explicit MediaMessagePrivate();
+    virtual ~MediaMessagePrivate();
+
+    android::sp<android::AMessage> msg;
+};
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_meta_data_layer.cpp
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Simon Fels <simon.fels@canonical.com>
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "MediaCompatibilityLayer"
+
+#include <hybris/media/media_meta_data_layer.h>
+
+#include "media_meta_data_priv.h"
+
+MediaMetaDataPrivate* MediaMetaDataPrivate::toPrivate(MediaMetaDataWrapper *md)
+{
+    if (!md)
+        return NULL;
+
+    return static_cast<MediaMetaDataPrivate*>(md);
+}
+
+MediaMetaDataPrivate::MediaMetaDataPrivate() :
+    data(new android::MetaData)
+{
+}
+
+MediaMetaDataPrivate::MediaMetaDataPrivate(const android::sp<android::MetaData> &md) :
+    data(md)
+{
+}
+
+MediaMetaDataPrivate::~MediaMetaDataPrivate()
+{
+}
+
+uint32_t media_meta_data_get_key_id(int key)
+{
+    switch (key)
+    {
+    case MEDIA_META_DATA_KEY_TIME:
+        return android::kKeyTime;
+    case MEDIA_META_DATA_KEY_IS_CODEC_CONFIG:
+        return android::kKeyIsCodecConfig;
+    case MEDIA_META_DATA_KEY_MIME:
+        return android::kKeyMIMEType;
+    case MEDIA_META_DATA_KEY_NUM_BUFFERS:
+        return android::kKeyNumBuffers;
+    case MEDIA_META_DATA_KEY_WIDTH:
+        return android::kKeyWidth;
+    case MEDIA_META_DATA_KEY_HEIGHT:
+        return android::kKeyHeight;
+    case MEDIA_META_DATA_KEY_STRIDE:
+        return android::kKeyStride;
+    case MEDIA_META_DATA_KEY_COLOR_FORMAT:
+        return android::kKeyColorFormat;
+    case MEDIA_META_DATA_KEY_SLICE_HEIGHT:
+        return android::kKeySliceHeight;
+    case MEDIA_META_DATA_KEY_FRAMERATE:
+        return android::kKeyFrameRate;
+    case MEDIA_META_DATA_KEY_MEDIA_BUFFER:
+        return 'mediaBuffer';
+    default:
+        break;
+    }
+
+    return 0;
+}
+
+MediaMetaDataWrapper* media_meta_data_create()
+{
+    MediaMetaDataPrivate *d = new MediaMetaDataPrivate;
+    if (!d)
+        return NULL;
+
+    return d;
+}
+
+void media_meta_data_release(MediaMetaDataWrapper *meta_data)
+{
+    MediaMetaDataPrivate *d = MediaMetaDataPrivate::toPrivate(meta_data);
+    if (!d)
+        return;
+
+    delete d;
+}
+
+void media_meta_data_clear(MediaMetaDataWrapper *meta_data)
+{
+    MediaMetaDataPrivate *d = MediaMetaDataPrivate::toPrivate(meta_data);
+    if (!d || !d->data.get())
+        return;
+
+    d->data->clear();
+}
+
+bool media_meta_data_remove(MediaMetaDataWrapper *meta_data, uint32_t key)
+{
+    MediaMetaDataPrivate *d = MediaMetaDataPrivate::toPrivate(meta_data);
+    if (!d || !d->data.get())
+        return false;
+
+    return d->data->remove(key);
+}
+
+bool media_meta_data_set_cstring(MediaMetaDataWrapper *meta_data, uint32_t key, const char *value)
+{
+    MediaMetaDataPrivate *d = MediaMetaDataPrivate::toPrivate(meta_data);
+    if (!d || !d->data.get())
+        return false;
+
+    android::status_t err = d->data->setCString(key, value);
+    return err == android::OK;
+}
+
+bool media_meta_data_set_int32(MediaMetaDataWrapper *meta_data, uint32_t key, int32_t value)
+{
+    MediaMetaDataPrivate *d = MediaMetaDataPrivate::toPrivate(meta_data);
+    if (!d || !d->data.get())
+        return false;
+
+    android::status_t err = d->data->setInt32(key, value);
+    return err == android::OK;
+}
+
+bool media_meta_data_set_int64(MediaMetaDataWrapper *meta_data, uint32_t key, int64_t value)
+{
+    MediaMetaDataPrivate *d = MediaMetaDataPrivate::toPrivate(meta_data);
+    if (!d || !d->data.get())
+        return false;
+
+    android::status_t err = d->data->setInt64(key, value);
+    return err == android::OK;
+}
+
+bool media_meta_data_set_float(MediaMetaDataWrapper *meta_data, uint32_t key, float value)
+{
+    MediaMetaDataPrivate *d = MediaMetaDataPrivate::toPrivate(meta_data);
+    if (!d || !d->data.get())
+        return false;
+
+    android::status_t err = d->data->setFloat(key, value);
+    return err == android::OK;
+}
+
+bool media_meta_data_set_pointer(MediaMetaDataWrapper *meta_data, uint32_t key, void *value)
+{
+    MediaMetaDataPrivate *d = MediaMetaDataPrivate::toPrivate(meta_data);
+    if (!d || !d->data.get())
+        return false;
+
+    android::status_t err = d->data->setPointer(key, value);
+    return err == android::OK;
+}
+
+bool media_meta_data_find_cstring(MediaMetaDataWrapper *meta_data, uint32_t key, const char **value)
+{
+    MediaMetaDataPrivate *d = MediaMetaDataPrivate::toPrivate(meta_data);
+    if (!d || !d->data.get())
+        return false;
+
+    const char *v = NULL;
+    if (!d->data->findCString(key, &v))
+        return false;
+
+    if (value)
+        *value = v;
+
+    return true;
+}
+
+bool media_meta_data_find_int32(MediaMetaDataWrapper *meta_data, uint32_t key, int32_t *value)
+{
+    MediaMetaDataPrivate *d = MediaMetaDataPrivate::toPrivate(meta_data);
+    if (!d || !d->data.get())
+        return false;
+
+    int32_t v;
+    if (!d->data->findInt32(key, &v))
+        return false;
+
+    if (value)
+        *value = v;
+
+    return true;
+}
+
+bool media_meta_data_find_int64(MediaMetaDataWrapper *meta_data, uint32_t key, int64_t *value)
+{
+    MediaMetaDataPrivate *d = MediaMetaDataPrivate::toPrivate(meta_data);
+    if (!d || !d->data.get())
+        return false;
+
+    int64_t v;
+    if (!d->data->findInt64(key, &v))
+        return false;
+
+    if (value)
+        *value = v;
+
+    return true;
+}
+
+bool media_meta_data_find_float(MediaMetaDataWrapper *meta_data, uint32_t key, float *value)
+{
+    MediaMetaDataPrivate *d = MediaMetaDataPrivate::toPrivate(meta_data);
+    if (!d || !d->data.get())
+        return false;
+
+    float v;
+    if (!d->data->findFloat(key, &v))
+        return false;
+
+    if (value)
+        *value = v;
+
+    return true;
+}
+
+bool media_meta_data_find_pointer(MediaMetaDataWrapper *meta_data, uint32_t key, void **value)
+{
+    MediaMetaDataPrivate *d = MediaMetaDataPrivate::toPrivate(meta_data);
+    if (!d || !d->data.get())
+        return false;
+
+    void *v = NULL;
+    if (!d->data->findPointer(key, &v))
+        return false;
+
+    if (value)
+        *value = v;
+
+    return true;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_meta_data_priv.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Simon Fels <simon.fels@canonical.com>
+ */
+
+#ifndef MEDIA_META_DATA_PRIV_H_
+#define MEDIA_META_DATA_PRIV_H_
+
+#include <media/stagefright/MetaData.h>
+
+struct MediaMetaDataPrivate
+{
+public:
+    static MediaMetaDataPrivate* toPrivate(MediaMetaDataWrapper *md);
+
+    MediaMetaDataPrivate();
+    MediaMetaDataPrivate(const android::sp<android::MetaData> &md);
+    ~MediaMetaDataPrivate();
+
+    android::sp<android::MetaData> data;
+};
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder.cpp
@@ -0,0 +1,748 @@
+/*
+ ** Copyright (c) 2008 The Android Open Source Project
+ ** Copyright (C) 2014 Canonical Ltd
+ **
+ ** Adapted from the Android equivalent code for use in Ubuntu.
+ **
+ ** 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.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "MediaRecorder"
+
+#include "media_recorder.h"
+#include "media_recorder_factory.h"
+
+#include <utils/Log.h>
+#include <binder/IServiceManager.h>
+#include <utils/String8.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaRecorder.h>
+#include <media/mediaplayer.h>  // for MEDIA_ERROR_SERVER_DIED
+#include <gui/IGraphicBufferProducer.h>
+
+namespace android {
+
+status_t MediaRecorder::setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy)
+{
+    ALOGV("setCamera(%p,%p)", camera.get(), proxy.get());
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_IDLE)) {
+        ALOGE("setCamera called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setCamera(camera, proxy);
+    if (OK != ret) {
+        ALOGV("setCamera failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::setPreviewSurface(const sp<IGraphicBufferProducer>& surface)
+{
+    ALOGV("setPreviewSurface(%p)", surface.get());
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setPreviewSurface called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (!mIsVideoSourceSet) {
+        ALOGE("try to set preview surface without setting the video source first");
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setPreviewSurface(surface);
+    if (OK != ret) {
+        ALOGV("setPreviewSurface failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::init()
+{
+    ALOGV("init");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_IDLE)) {
+        ALOGE("init called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->init();
+    if (OK != ret) {
+        ALOGV("init failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+
+    ret = mMediaRecorder->setListener(this);
+    if (OK != ret) {
+        ALOGV("setListener failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+
+    mCurrentState = MEDIA_RECORDER_INITIALIZED;
+    return ret;
+}
+
+status_t MediaRecorder::setVideoSource(int vs)
+{
+    ALOGV("setVideoSource(%d)", vs);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsVideoSourceSet) {
+        ALOGE("video source has already been set");
+        return INVALID_OPERATION;
+    }
+    if (mCurrentState & MEDIA_RECORDER_IDLE) {
+        ALOGV("Call init() since the media recorder is not initialized yet");
+        status_t ret = init();
+        if (OK != ret) {
+            return ret;
+        }
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        ALOGE("setVideoSource called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    // following call is made over the Binder Interface
+    status_t ret = mMediaRecorder->setVideoSource(vs);
+
+    if (OK != ret) {
+        ALOGV("setVideoSource failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mIsVideoSourceSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setAudioSource(int as)
+{
+    ALOGV("setAudioSource(%d)", as);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mCurrentState & MEDIA_RECORDER_IDLE) {
+        ALOGV("Call init() since the media recorder is not initialized yet");
+        status_t ret = init();
+        if (OK != ret) {
+            return ret;
+        }
+    }
+    if (mIsAudioSourceSet) {
+        ALOGE("audio source has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        ALOGE("setAudioSource called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setAudioSource(as);
+    if (OK != ret) {
+        ALOGV("setAudioSource failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mIsAudioSourceSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setOutputFormat(int of)
+{
+    ALOGV("setOutputFormat(%d)", of);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        ALOGE("setOutputFormat called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (mIsVideoSourceSet && of >= OUTPUT_FORMAT_AUDIO_ONLY_START && of != OUTPUT_FORMAT_RTP_AVP && of != OUTPUT_FORMAT_MPEG2TS) { //first non-video output format
+        ALOGE("output format (%d) is meant for audio recording only and incompatible with video recording", of);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setOutputFormat(of);
+    if (OK != ret) {
+        ALOGE("setOutputFormat failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mCurrentState = MEDIA_RECORDER_DATASOURCE_CONFIGURED;
+    return ret;
+}
+
+status_t MediaRecorder::setVideoEncoder(int ve)
+{
+    ALOGV("setVideoEncoder(%d)", ve);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!mIsVideoSourceSet) {
+        ALOGE("try to set the video encoder without setting the video source first");
+        return INVALID_OPERATION;
+    }
+    if (mIsVideoEncoderSet) {
+        ALOGE("video encoder has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setVideoEncoder called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setVideoEncoder(ve);
+    if (OK != ret) {
+        ALOGV("setVideoEncoder failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mIsVideoEncoderSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setAudioEncoder(int ae)
+{
+    ALOGV("setAudioEncoder(%d)", ae);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!mIsAudioSourceSet) {
+        ALOGE("try to set the audio encoder without setting the audio source first");
+        return INVALID_OPERATION;
+    }
+    if (mIsAudioEncoderSet) {
+        ALOGE("audio encoder has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setAudioEncoder called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setAudioEncoder(ae);
+    if (OK != ret) {
+        ALOGV("setAudioEncoder failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mIsAudioEncoderSet = true;
+    return ret;
+}
+#if ANDROID_VERSION_MAJOR<=5
+status_t MediaRecorder::setOutputFile(const char* path)
+{
+    ALOGV("setOutputFile(%s)", path);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsOutputFileSet) {
+        ALOGE("output file has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setOutputFile called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setOutputFile(path);
+    if (OK != ret) {
+        ALOGV("setOutputFile failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mIsOutputFileSet = true;
+    return ret;
+}
+#endif
+
+status_t MediaRecorder::setOutputFile(int fd, int64_t offset, int64_t length)
+{
+    ALOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsOutputFileSet) {
+        ALOGE("output file has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setOutputFile called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    // It appears that if an invalid file descriptor is passed through
+    // binder calls, the server-side of the inter-process function call
+    // is skipped. As a result, the check at the server-side to catch
+    // the invalid file descritpor never gets invoked. This is to workaround
+    // this issue by checking the file descriptor first before passing
+    // it through binder call.
+    if (fd < 0) {
+        ALOGE("Invalid file descriptor: %d", fd);
+        return BAD_VALUE;
+    }
+
+    status_t ret = mMediaRecorder->setOutputFile(fd, offset, length);
+    if (OK != ret) {
+        ALOGV("setOutputFile failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mIsOutputFileSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setVideoSize(int width, int height)
+{
+    ALOGV("setVideoSize(%d, %d)", width, height);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setVideoSize called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (!mIsVideoSourceSet) {
+        ALOGE("Cannot set video size without setting video source first");
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setVideoSize(width, height);
+    if (OK != ret) {
+        ALOGE("setVideoSize failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+
+    return ret;
+}
+
+// Query a SurfaceMediaSurface through the Mediaserver, over the
+// binder interface. This is used by the Filter Framework (MediaEncoder)
+// to get an <IGraphicBufferProducer> object to hook up to ANativeWindow.
+sp<IGraphicBufferProducer> MediaRecorder::
+        querySurfaceMediaSourceFromMediaServer()
+{
+    Mutex::Autolock _l(mLock);
+    mSurfaceMediaSource =
+            mMediaRecorder->querySurfaceMediaSource();
+    if (mSurfaceMediaSource == NULL) {
+        ALOGE("SurfaceMediaSource could not be initialized!");
+    }
+    return mSurfaceMediaSource;
+}
+
+status_t MediaRecorder::setVideoFrameRate(int frames_per_second)
+{
+    ALOGV("setVideoFrameRate(%d)", frames_per_second);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (!mIsVideoSourceSet) {
+        ALOGE("Cannot set video frame rate without setting video source first");
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setVideoFrameRate(frames_per_second);
+    if (OK != ret) {
+        ALOGE("setVideoFrameRate failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::setParameters(const String8& params) {
+    ALOGV("setParameters(%s)", params.string());
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+
+    bool isInvalidState = (mCurrentState &
+                           (MEDIA_RECORDER_PREPARED |
+                            MEDIA_RECORDER_RECORDING |
+                            MEDIA_RECORDER_ERROR));
+    if (isInvalidState) {
+        ALOGE("setParameters is called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setParameters(params);
+    if (OK != ret) {
+        ALOGE("setParameters(%s) failed: %d", params.string(), ret);
+        // Do not change our current state to MEDIA_RECORDER_ERROR, failures
+        // of the only currently supported parameters, "max-duration" and
+        // "max-filesize" are _not_ fatal.
+    }
+
+    return ret;
+}
+
+status_t MediaRecorder::prepare()
+{
+    ALOGV("prepare");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("prepare called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (mIsAudioSourceSet != mIsAudioEncoderSet) {
+        if (mIsAudioSourceSet) {
+            ALOGE("audio source is set, but audio encoder is not set");
+        } else {  // must not happen, since setAudioEncoder checks this already
+            ALOGE("audio encoder is set, but audio source is not set");
+        }
+        return INVALID_OPERATION;
+    }
+
+    if (mIsVideoSourceSet != mIsVideoEncoderSet) {
+        if (mIsVideoSourceSet) {
+            ALOGE("video source is set, but video encoder is not set");
+        } else {  // must not happen, since setVideoEncoder checks this already
+            ALOGE("video encoder is set, but video source is not set");
+        }
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->prepare();
+    if (OK != ret) {
+        ALOGE("prepare failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mCurrentState = MEDIA_RECORDER_PREPARED;
+    return ret;
+}
+
+status_t MediaRecorder::getMaxAmplitude(int* max)
+{
+    ALOGV("getMaxAmplitude");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mCurrentState & MEDIA_RECORDER_ERROR) {
+        ALOGE("getMaxAmplitude called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->getMaxAmplitude(max);
+    if (OK != ret) {
+        ALOGE("getMaxAmplitude failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::start()
+{
+    ALOGV("start");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_PREPARED)) {
+        ALOGE("start called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->start();
+    if (OK != ret) {
+        ALOGE("start failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mCurrentState = MEDIA_RECORDER_RECORDING;
+    return ret;
+}
+
+status_t MediaRecorder::stop()
+{
+    ALOGV("stop");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_RECORDING)) {
+        ALOGE("stop called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->stop();
+    if (OK != ret) {
+        ALOGE("stop failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+
+    // FIXME:
+    // stop and reset are semantically different.
+    // We treat them the same for now, and will change this in the future.
+    doCleanUp();
+    mCurrentState = MEDIA_RECORDER_IDLE;
+    return ret;
+}
+
+// Reset should be OK in any state
+status_t MediaRecorder::reset()
+{
+    ALOGV("reset");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+
+    doCleanUp();
+    status_t ret = UNKNOWN_ERROR;
+    switch (mCurrentState) {
+        case MEDIA_RECORDER_IDLE:
+            ret = OK;
+            break;
+
+        case MEDIA_RECORDER_RECORDING:
+        case MEDIA_RECORDER_DATASOURCE_CONFIGURED:
+        case MEDIA_RECORDER_PREPARED:
+        case MEDIA_RECORDER_ERROR: {
+            ret = doReset();
+            if (OK != ret) {
+                return ret;  // No need to continue
+            }
+        }  // Intentional fall through
+        case MEDIA_RECORDER_INITIALIZED:
+            ret = close();
+            break;
+
+        default: {
+            ALOGE("Unexpected non-existing state: %d", mCurrentState);
+            break;
+        }
+    }
+    return ret;
+}
+
+status_t MediaRecorder::close()
+{
+    ALOGV("close");
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        ALOGE("close called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    status_t ret = mMediaRecorder->close();
+    if (OK != ret) {
+        ALOGE("close failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    } else {
+        mCurrentState = MEDIA_RECORDER_IDLE;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::doReset()
+{
+    ALOGV("doReset");
+    status_t ret = mMediaRecorder->reset();
+    if (OK != ret) {
+        ALOGE("doReset failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    } else {
+        mCurrentState = MEDIA_RECORDER_INITIALIZED;
+    }
+    return ret;
+}
+
+void MediaRecorder::doCleanUp()
+{
+    ALOGV("doCleanUp");
+    mIsAudioSourceSet  = false;
+    mIsVideoSourceSet  = false;
+    mIsAudioEncoderSet = false;
+    mIsVideoEncoderSet = false;
+    mIsOutputFileSet   = false;
+}
+
+// Release should be OK in any state
+status_t MediaRecorder::release()
+{
+    ALOGV("release");
+    if (mMediaRecorder != NULL) {
+        return mMediaRecorder->release();
+    }
+    return INVALID_OPERATION;
+}
+
+
+MediaRecorder::MediaRecorder()
+    : mMediaRecorderFactory(NULL),
+    mSurfaceMediaSource(NULL)
+{
+    ALOGV("constructor (custom)");
+
+    if (mMediaRecorderFactory == NULL) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16(IMediaRecorderFactory::exported_service_name()));
+            if (binder != 0) {
+                break;
+            }
+            ALOGW("MediaRecorderFactory service not published, waiting...");
+            usleep(500000); // 0.5 s
+        } while (true);
+
+        mMediaRecorderFactory = interface_cast<IMediaRecorderFactory>(binder);
+    }
+
+    ALOGE_IF(mMediaRecorderFactory == NULL, "no MediaRecorderFactory!?");
+
+    mMediaRecorder = mMediaRecorderFactory->createMediaRecorder();
+    if (mMediaRecorder != NULL) {
+        mCurrentState = MEDIA_RECORDER_IDLE;
+    }
+
+    doCleanUp();
+}
+
+status_t MediaRecorder::initCheck()
+{
+    return mMediaRecorder != 0 ? NO_ERROR : NO_INIT;
+}
+
+MediaRecorder::~MediaRecorder()
+{
+    ALOGV("destructor");
+    if (mMediaRecorder != NULL) {
+        mMediaRecorder.clear();
+    }
+
+    if (mSurfaceMediaSource != NULL) {
+        mSurfaceMediaSource.clear();
+    }
+}
+
+status_t MediaRecorder::setListener(const sp<MediaRecorderListener>& listener)
+{
+    ALOGV("setListener");
+    Mutex::Autolock _l(mLock);
+    mListener = listener;
+
+    if (mMediaRecorder != NULL) {
+        // Sets a listener so that when the named pipe reader in RecordThread is ready,
+        // we can bubble up to media_recorder_layer to signal the app that it's ready
+        // to do audio recording
+        mMediaRecorder->setListener(this);
+    }
+
+    return NO_ERROR;
+}
+
+status_t MediaRecorder::setClientName(const String16& clientName)
+{
+    ALOGV("setClientName");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    bool isInvalidState = (mCurrentState &
+                           (MEDIA_RECORDER_PREPARED |
+                            MEDIA_RECORDER_RECORDING |
+                            MEDIA_RECORDER_ERROR));
+    if (isInvalidState) {
+        ALOGE("setClientName is called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    mMediaRecorder->setClientName(clientName);
+
+    return NO_ERROR;
+}
+
+void MediaRecorder::notify(int msg, int ext1, int ext2)
+{
+    ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
+
+    sp<MediaRecorderListener> listener;
+    mLock.lock();
+    listener = mListener;
+    mLock.unlock();
+
+    if (listener != NULL) {
+        Mutex::Autolock _l(mNotifyLock);
+        ALOGV("callback application");
+        listener->notify(msg, ext1, ext2);
+        ALOGV("back from callback");
+    }
+}
+
+void MediaRecorder::readAudio()
+{
+    ALOGV("%s", __PRETTY_FUNCTION__);
+
+    sp<MediaRecorderListener> listener;
+    status_t ret = NO_ERROR;
+    mLock.lock();
+    listener = mListener;
+    mLock.unlock();
+
+    if (listener != NULL) {
+        Mutex::Autolock _l(mReadAudioLock);
+        ALOGV("callback application");
+        listener->readAudio();
+        ALOGV("back from callback");
+    }
+}
+
+void MediaRecorder::died()
+{
+    ALOGV("died");
+    notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
+}
+
+} // namespace android
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder.h
@@ -0,0 +1,271 @@
+/*
+ ** Copyright (C) 2008 The Android Open Source Project
+ ** Copyright (C) 2014 Canonical Ltd
+ **
+ ** Adapted from the Android equivalent code for use in Ubuntu.
+ **
+ ** 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.
+ */
+
+#ifndef ANDROID_MEDIARECORDER_H
+#define ANDROID_MEDIARECORDER_H
+
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
+#include <media/IMediaRecorderClient.h>
+#include <media/IMediaDeathNotifier.h>
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+class Surface;
+class IMediaRecorder;
+class IMediaRecorderFactory;
+class ICamera;
+class ICameraRecordingProxy;
+class IGraphicBufferProducer;
+class Surface;
+
+typedef void (*media_completion_f)(status_t status, void *cookie);
+
+enum video_source {
+    VIDEO_SOURCE_DEFAULT = 0,
+    VIDEO_SOURCE_CAMERA = 1,
+    VIDEO_SOURCE_GRALLOC_BUFFER = 2,
+
+    VIDEO_SOURCE_LIST_END  // must be last - used to validate audio source type
+};
+
+// Please update media/java/android/media/MediaRecorder.java if the following is updated.
+enum output_format {
+    OUTPUT_FORMAT_DEFAULT = 0,
+    OUTPUT_FORMAT_THREE_GPP = 1,
+    OUTPUT_FORMAT_MPEG_4 = 2,
+
+
+    OUTPUT_FORMAT_AUDIO_ONLY_START = 3, // Used in validating the output format.  Should be the
+                                        //  at the start of the audio only output formats.
+
+    /* These are audio only file formats */
+    OUTPUT_FORMAT_RAW_AMR = 3, //to be backward compatible
+    OUTPUT_FORMAT_AMR_NB = 3,
+    OUTPUT_FORMAT_AMR_WB = 4,
+    OUTPUT_FORMAT_AAC_ADIF = 5,
+    OUTPUT_FORMAT_AAC_ADTS = 6,
+
+    /* Stream over a socket, limited to a single stream */
+    OUTPUT_FORMAT_RTP_AVP = 7,
+
+    /* H.264/AAC data encapsulated in MPEG2/TS */
+    OUTPUT_FORMAT_MPEG2TS = 8,
+
+    OUTPUT_FORMAT_LIST_END // must be last - used to validate format type
+};
+
+enum audio_encoder {
+    AUDIO_ENCODER_DEFAULT = 0,
+    AUDIO_ENCODER_AMR_NB = 1,
+    AUDIO_ENCODER_AMR_WB = 2,
+    AUDIO_ENCODER_AAC = 3,
+    AUDIO_ENCODER_HE_AAC = 4,
+    AUDIO_ENCODER_AAC_ELD = 5,
+
+    AUDIO_ENCODER_LIST_END // must be the last - used to validate the audio encoder type
+};
+
+enum video_encoder {
+    VIDEO_ENCODER_DEFAULT = 0,
+    VIDEO_ENCODER_H263 = 1,
+    VIDEO_ENCODER_H264 = 2,
+    VIDEO_ENCODER_MPEG_4_SP = 3,
+
+    VIDEO_ENCODER_LIST_END // must be the last - used to validate the video encoder type
+};
+
+/*
+ * The state machine of the media_recorder.
+ */
+enum media_recorder_states {
+    // Error state.
+    MEDIA_RECORDER_ERROR                 =      0,
+
+    // Recorder was just created.
+    MEDIA_RECORDER_IDLE                  = 1 << 0,
+
+    // Recorder has been initialized.
+    MEDIA_RECORDER_INITIALIZED           = 1 << 1,
+
+    // Configuration of the recorder has been completed.
+    MEDIA_RECORDER_DATASOURCE_CONFIGURED = 1 << 2,
+
+    // Recorder is ready to start.
+    MEDIA_RECORDER_PREPARED              = 1 << 3,
+
+    // Recording is in progress.
+    MEDIA_RECORDER_RECORDING             = 1 << 4,
+};
+
+// The "msg" code passed to the listener in notify.
+enum media_recorder_event_type {
+    MEDIA_RECORDER_EVENT_LIST_START               = 1,
+    MEDIA_RECORDER_EVENT_ERROR                    = 1,
+    MEDIA_RECORDER_EVENT_INFO                     = 2,
+    MEDIA_RECORDER_EVENT_LIST_END                 = 99,
+
+    // Track related event types
+    MEDIA_RECORDER_TRACK_EVENT_LIST_START         = 100,
+    MEDIA_RECORDER_TRACK_EVENT_ERROR              = 100,
+    MEDIA_RECORDER_TRACK_EVENT_INFO               = 101,
+    MEDIA_RECORDER_TRACK_EVENT_LIST_END           = 1000,
+};
+
+/*
+ * The (part of) "what" code passed to the listener in notify.
+ * When the error or info type is track specific, the what has
+ * the following layout:
+ * the left-most 16-bit is meant for error or info type.
+ * the right-most 4-bit is meant for track id.
+ * the rest is reserved.
+ *
+ * | track id | reserved |     error or info type     |
+ * 31         28         16                           0
+ *
+ */
+enum media_recorder_error_type {
+    MEDIA_RECORDER_ERROR_UNKNOWN                   = 1,
+
+    // Track related error type
+    MEDIA_RECORDER_TRACK_ERROR_LIST_START          = 100,
+    MEDIA_RECORDER_TRACK_ERROR_GENERAL             = 100,
+    MEDIA_RECORDER_ERROR_VIDEO_NO_SYNC_FRAME       = 200,
+    MEDIA_RECORDER_TRACK_ERROR_LIST_END            = 1000,
+};
+
+// The codes are distributed as follow:
+//   0xx: Reserved
+//   8xx: General info/warning
+//
+enum media_recorder_info_type {
+    MEDIA_RECORDER_INFO_UNKNOWN                   = 1,
+
+    MEDIA_RECORDER_INFO_MAX_DURATION_REACHED      = 800,
+    MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED      = 801,
+
+    // All track related informtional events start here
+    MEDIA_RECORDER_TRACK_INFO_LIST_START           = 1000,
+    MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS    = 1000,
+    MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME     = 1001,
+    MEDIA_RECORDER_TRACK_INFO_TYPE                 = 1002,
+    MEDIA_RECORDER_TRACK_INFO_DURATION_MS          = 1003,
+
+    // The time to measure the max chunk duration
+    MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS     = 1004,
+
+    MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES       = 1005,
+
+    // The time to measure how well the audio and video
+    // track data is interleaved.
+    MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS       = 1006,
+
+    // The time to measure system response. Note that
+    // the delay does not include the intentional delay
+    // we use to eliminate the recording sound.
+    MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS     = 1007,
+
+    // The time used to compensate for initial A/V sync.
+    MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS      = 1008,
+
+    // Total number of bytes of the media data.
+    MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES          = 1009,
+
+    MEDIA_RECORDER_TRACK_INFO_LIST_END             = 2000,
+};
+
+class MediaPlayerService;
+
+// ----------------------------------------------------------------------------
+// ref-counted object for callbacks
+class MediaRecorderListener: virtual public RefBase
+{
+public:
+    virtual void notify(int msg, int ext1, int ext2) = 0;
+    virtual void readAudio() = 0;
+};
+
+class MediaRecorder : public BnMediaRecorderClient,
+                      public virtual IMediaDeathNotifier
+{
+public:
+    MediaRecorder();
+    ~MediaRecorder();
+
+    void        died();
+    status_t    initCheck();
+    status_t    setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy);
+    status_t    setPreviewSurface(const sp<IGraphicBufferProducer>& surface);
+    status_t    setVideoSource(int vs);
+    status_t    setAudioSource(int as);
+    status_t    setOutputFormat(int of);
+    status_t    setVideoEncoder(int ve);
+    status_t    setAudioEncoder(int ae);
+#if ANDROID_VERSION_MAJOR<=5
+    status_t    setOutputFile(const char* path);
+#endif
+    status_t    setOutputFile(int fd, int64_t offset, int64_t length);
+    status_t    setVideoSize(int width, int height);
+    status_t    setVideoFrameRate(int frames_per_second);
+    status_t    setParameters(const String8& params);
+    status_t    setListener(const sp<MediaRecorderListener>& listener);
+    status_t    setClientName(const String16& clientName);
+    status_t    prepare();
+    status_t    getMaxAmplitude(int* max);
+    status_t    start();
+    status_t    stop();
+    status_t    reset();
+    status_t    init();
+    status_t    close();
+    status_t    release();
+    void        notify(int msg, int ext1, int ext2);
+    void        readAudio();
+    sp<IGraphicBufferProducer>     querySurfaceMediaSourceFromMediaServer();
+
+private:
+    void                    doCleanUp();
+    status_t                doReset();
+
+    sp<IMediaRecorder>          mMediaRecorder;
+    sp<MediaRecorderListener>   mListener;
+    sp<IMediaRecorderFactory>   mMediaRecorderFactory;
+
+    // Reference to IGraphicBufferProducer
+    // for encoding GL Frames. That is useful only when the
+    // video source is set to VIDEO_SOURCE_GRALLOC_BUFFER
+    sp<IGraphicBufferProducer>  mSurfaceMediaSource;
+
+    media_recorder_states       mCurrentState;
+    bool                        mIsAudioSourceSet;
+    bool                        mIsVideoSourceSet;
+    bool                        mIsAudioEncoderSet;
+    bool                        mIsVideoEncoderSet;
+    bool                        mIsOutputFileSet;
+    Mutex                       mLock;
+    Mutex                       mNotifyLock;
+    Mutex                       mReadAudioLock;
+};
+
+};  // namespace android
+
+#endif // ANDROID_MEDIARECORDER_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_client.cpp
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2013-2014 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#include "media_recorder_client.h"
+
+#include <libmediaplayerservice/StagefrightRecorder.h>
+#include <binder/IServiceManager.h>
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "MediaRecorderClient"
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__)
+
+using namespace android;
+
+MediaRecorderClient::MediaRecorderClient()
+{
+    REPORT_FUNCTION();
+
+    sp<IServiceManager> service_manager = defaultServiceManager();
+    sp<IBinder> service = service_manager->getService(
+        String16(IMediaRecorderObserver::exported_service_name()));
+
+    media_recorder_observer = new BpMediaRecorderObserver(service);
+
+#if ANDROID_VERSION_MAJOR>=6
+    // TODO: do we need to get valid package here?
+    const String16 opPackageName("ubuntu");
+    recorder = new android::StagefrightRecorder(opPackageName);
+#else
+    recorder = new android::StagefrightRecorder;
+#endif
+}
+
+MediaRecorderClient::~MediaRecorderClient()
+{
+    REPORT_FUNCTION();
+    release();
+}
+
+status_t MediaRecorderClient::setCamera(const sp<android::ICamera>& camera,
+        const sp<ICameraRecordingProxy>& proxy)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setCamera(camera, proxy);
+}
+
+status_t MediaRecorderClient::setPreviewSurface(const android::sp<android::IGraphicBufferProducer>& surface)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setPreviewSurface(surface);
+}
+
+status_t MediaRecorderClient::setVideoSource(int vs)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL)     {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setVideoSource((android::video_source)vs);
+}
+
+status_t MediaRecorderClient::setAudioSource(int as)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL)  {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setAudioSource((audio_source_t)as);
+}
+
+status_t MediaRecorderClient::setOutputFormat(int of)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setOutputFormat((android::output_format)of);
+}
+
+status_t MediaRecorderClient::setVideoEncoder(int ve)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setVideoEncoder((android::video_encoder)ve);
+}
+
+status_t MediaRecorderClient::setAudioEncoder(int ae)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setAudioEncoder((android::audio_encoder)ae);
+}
+
+#if ANDROID_VERSION_MAJOR<=5
+status_t MediaRecorderClient::setOutputFile(const char* path)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setOutputFile(path);
+}
+#else
+status_t MediaRecorderClient::setInputSurface(const sp<IGraphicBufferConsumer>& surface)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setInputSurface(surface);
+}
+#endif
+
+status_t MediaRecorderClient::setOutputFile(int fd, int64_t offset, int64_t length)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setOutputFile(fd, offset, length);
+}
+
+status_t MediaRecorderClient::setVideoSize(int width, int height)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setVideoSize(width, height);
+}
+
+status_t MediaRecorderClient::setVideoFrameRate(int frames_per_second)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setVideoFrameRate(frames_per_second);
+}
+
+status_t MediaRecorderClient::setParameters(const android::String8& params)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setParameters(params);
+}
+
+status_t MediaRecorderClient::setListener(const android::sp<android::IMediaRecorderClient>& listener)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setListener(listener);
+}
+
+status_t MediaRecorderClient::setClientName(const android::String16& clientName)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setClientName(clientName);
+}
+
+status_t MediaRecorderClient::prepare()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->prepare();
+}
+
+status_t MediaRecorderClient::getMaxAmplitude(int* max)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->getMaxAmplitude(max);
+}
+
+status_t MediaRecorderClient::start()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+
+    if (media_recorder_observer != NULL)
+        media_recorder_observer->recordingStarted();
+
+    return recorder->start();
+}
+
+status_t MediaRecorderClient::stop()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+
+    if (media_recorder_observer != NULL)
+        media_recorder_observer->recordingStopped();
+
+    return recorder->stop();
+}
+
+#ifdef BOARD_HAS_MEDIA_RECORDER_PAUSE
+status_t MediaRecorderClient::pause()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->pause();
+
+}
+#endif
+
+#ifdef BOARD_HAS_MEDIA_RECORDER_RESUME
+status_t MediaRecorderClient::resume()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->resume();
+}
+#endif
+
+status_t MediaRecorderClient::reset()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->reset();
+}
+
+status_t MediaRecorderClient::init()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->init();
+}
+
+status_t MediaRecorderClient::close()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->close();
+}
+
+status_t MediaRecorderClient::release()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder != NULL) {
+        delete recorder;
+        recorder = NULL;
+    }
+    return NO_ERROR;
+}
+
+status_t MediaRecorderClient::dump(int fd, const Vector<String16>& args) const
+{
+    REPORT_FUNCTION();
+    if (recorder != NULL) {
+        return recorder->dump(fd, args);
+    }
+    return android::OK;
+}
+
+sp<IGraphicBufferProducer> MediaRecorderClient::querySurfaceMediaSource()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder is not initialized");
+        return NULL;
+    }
+    return recorder->querySurfaceMediaSource();
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_client.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2013-2014 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_RECORDER_CLIENT_H_
+#define MEDIA_RECORDER_CLIENT_H_
+
+#include <hybris/internal/camera_control.h>
+#include <hybris/media/media_recorder_layer.h>
+
+#include "media_recorder_observer.h"
+
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+class MediaRecorderBase;
+class Mutex;
+class BpMediaRecorderObserver;
+
+/*!
+ * \brief The MediaRecorderClient struct wraps the service side of the MediaRecorder class
+ */
+struct MediaRecorderClient : public BnMediaRecorder
+{
+public:
+    MediaRecorderClient();
+    virtual ~MediaRecorderClient();
+
+    virtual status_t setCamera(const sp<ICamera>& camera,
+            const sp<ICameraRecordingProxy>& proxy);
+    virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface);
+    virtual status_t setVideoSource(int vs);
+    virtual status_t setAudioSource(int as);
+    virtual status_t setOutputFormat(int of);
+    virtual status_t setVideoEncoder(int ve);
+    virtual status_t setAudioEncoder(int ae);
+#if ANDROID_VERSION_MAJOR<=5
+    virtual status_t setOutputFile(const char* path);
+#else
+    virtual status_t setInputSurface(const sp<IGraphicBufferConsumer>& surface);
+#endif
+    virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
+    virtual status_t setVideoSize(int width, int height);
+    virtual status_t setVideoFrameRate(int frames_per_second);
+    virtual status_t setParameters(const String8& params);
+    virtual status_t setListener(const sp<IMediaRecorderClient>& listener);
+    virtual status_t setClientName(const String16& clientName);
+    virtual status_t prepare();
+    virtual status_t getMaxAmplitude(int* max);
+    virtual status_t start();
+    virtual status_t stop();
+#ifdef BOARD_HAS_MEDIA_RECORDER_PAUSE
+    virtual status_t pause();
+#endif
+#ifdef BOARD_HAS_MEDIA_RECORDER_RESUME
+    virtual status_t resume();
+#endif
+    virtual status_t reset();
+    virtual status_t init();
+    virtual status_t close();
+    virtual status_t release();
+    virtual status_t dump(int fd, const Vector<String16>& args) const;
+    virtual sp<IGraphicBufferProducer> querySurfaceMediaSource();
+
+private:
+    sp<BpMediaRecorderObserver> media_recorder_observer;
+    MediaRecorderBase *recorder;
+    Mutex recorder_lock;
+};
+
+}
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_factory.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "MediaRecorderFactory"
+
+#include "media_recorder_factory.h"
+#include "media_recorder_client.h"
+#include <hybris/media/media_recorder_layer.h>
+
+#include <gui/IGraphicBufferProducer.h>
+#include <media/IMediaRecorder.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__)
+
+namespace android {
+
+enum {
+    CREATE_MEDIA_RECORDER = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpMediaRecorderFactory: public BpInterface<IMediaRecorderFactory>
+{
+public:
+    BpMediaRecorderFactory(const sp<IBinder>& impl)
+        : BpInterface<IMediaRecorderFactory>(impl)
+    {
+    }
+
+    virtual sp<IMediaRecorder> createMediaRecorder()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorderFactory::getInterfaceDescriptor());
+        remote()->transact(CREATE_MEDIA_RECORDER, data, &reply);
+        return interface_cast<IMediaRecorder>(reply.readStrongBinder());
+    }
+};
+
+// ----------------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(MediaRecorderFactory, "android.media.IMediaRecorderFactory");
+
+// ----------------------------------------------------------------------
+
+status_t BnMediaRecorderFactory::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case CREATE_MEDIA_RECORDER: {
+            CHECK_INTERFACE(IMediaRecorderFactory, data, reply);
+            sp<IMediaRecorder> recorder = createMediaRecorder();
+#if ANDROID_VERSION_MAJOR>=6
+            reply->writeStrongBinder(IInterface::asBinder(recorder));
+#else
+            reply->writeStrongBinder(recorder->asBinder());
+#endif
+
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+sp<MediaRecorderFactory> MediaRecorderFactory::media_recorder_factory;
+Mutex MediaRecorderFactory::s_lock;
+
+MediaRecorderFactory::MediaRecorderFactory()
+{
+    REPORT_FUNCTION();
+}
+
+MediaRecorderFactory::~MediaRecorderFactory()
+{
+    REPORT_FUNCTION();
+}
+
+/*!
+ * \brief Creates and adds the MediaRecorderFactory service to the default Binder ServiceManager
+ */
+void MediaRecorderFactory::instantiate()
+{
+    defaultServiceManager()->addService(
+            String16(IMediaRecorderFactory::exported_service_name()), factory_instance());
+    ALOGV("Added Binder service '%s' to ServiceManager", IMediaRecorderFactory::exported_service_name());
+}
+
+/*!
+ * \brief Creates a new MediaRecorderClient instance over Binder
+ * \return A new MediaRecorderClient instance
+ */
+sp<IMediaRecorder> MediaRecorderFactory::createMediaRecorder()
+{
+    REPORT_FUNCTION();
+    sp<MediaRecorderClient> recorder = new MediaRecorderClient();
+    return recorder;
+}
+
+/*!
+ * \brief Get a reference to the MediaRecorderFactory singleton instance
+ * \return The MediaRecorderFactory singleton instance
+ */
+sp<MediaRecorderFactory>& MediaRecorderFactory::factory_instance()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock _l(s_lock);
+    if (media_recorder_factory == NULL)
+    {
+        ALOGD("Creating new static instance of MediaRecorderFactory");
+        media_recorder_factory = new MediaRecorderFactory();
+    }
+
+    return media_recorder_factory;
+}
+
+} // namespace android
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_factory.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_RECORDER_FACTORY_H_
+#define MEDIA_RECORDER_FACTORY_H_
+
+#include <media/IMediaRecorder.h>
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class Mutex;
+
+class IMediaRecorderFactory: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MediaRecorderFactory);
+
+    static const char* exported_service_name() { return "android.media.IMediaRecorderFactory"; }
+
+    virtual sp<IMediaRecorder> createMediaRecorder() = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaRecorderFactory: public BnInterface<IMediaRecorderFactory>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+class MediaRecorderFactory : public BnMediaRecorderFactory
+{
+public:
+    MediaRecorderFactory();
+    virtual ~MediaRecorderFactory();
+
+    static void instantiate();
+
+    virtual sp<IMediaRecorder> createMediaRecorder();
+private:
+    static sp<MediaRecorderFactory>& factory_instance();
+
+    static sp<MediaRecorderFactory> media_recorder_factory;
+    static Mutex s_lock;
+};
+
+}
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_layer.cpp
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2013-2014 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ *              Guenter Schwann <guenter.schwann@canonical.com>
+ *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "MediaRecorderCompatibilityLayer"
+
+#include "media_recorder.h"
+
+#include <hybris/internal/camera_control.h>
+#include <hybris/media/media_recorder_layer.h>
+
+#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__)
+
+using namespace android;
+
+/*!
+ * \brief The MediaRecorderListenerWrapper class is used to listen to camera events
+ * from the MediaRecorder instance
+ */
+class MediaRecorderListenerWrapper : public android::MediaRecorderListener
+{
+public:
+    MediaRecorderListenerWrapper()
+        : error_cb(NULL),
+          error_context(NULL),
+          read_audio_cb(NULL),
+          read_audio_context(NULL)
+{
+}
+
+    void notify(int msg, int ext1, int ext2)
+    {
+        ALOGV("\tmsg: %d, ext1: %d, ext2: %d \n", msg, ext1, ext2);
+
+        switch (msg) {
+            case android::MEDIA_RECORDER_EVENT_ERROR:
+                ALOGV("\tMEDIA_RECORDER_EVENT_ERROR msg\n");
+                // TODO: Extend this cb to include the error message
+                if (error_cb != NULL)
+                    error_cb(error_context);
+                else
+                    ALOGE("Failed to signal error to app layer, callback not set.");
+                break;
+            default:
+                ALOGV("\tUnknown notification\n");
+        }
+    }
+
+    void readAudio()
+    {
+        REPORT_FUNCTION();
+        if (read_audio_cb != NULL) {
+            read_audio_cb(read_audio_context);
+        }
+        else
+            ALOGW("Failed to call read_audio_cb since it's NULL");
+    }
+
+    void setErrorCb(on_recorder_msg_error cb, void *context)
+    {
+        REPORT_FUNCTION();
+        error_cb = cb;
+        error_context = context;
+    }
+
+    void setReadAudioCb(on_recorder_read_audio cb, void *context)
+    {
+        REPORT_FUNCTION();
+        read_audio_cb = cb;
+        read_audio_context = context;
+    }
+
+private:
+    on_recorder_msg_error error_cb;
+    void *error_context;
+    on_recorder_read_audio read_audio_cb;
+    void *read_audio_context;
+};
+
+/*!
+ * \brief The MediaRecorderWrapper struct wraps the MediaRecorder class
+ */
+struct MediaRecorderWrapper : public android::MediaRecorder
+{
+public:
+    MediaRecorderWrapper()
+        : MediaRecorder(),
+          media_recorder_listener(new MediaRecorderListenerWrapper())
+{
+}
+
+    ~MediaRecorderWrapper()
+    {
+        reset();
+    }
+
+    void init()
+    {
+        setListener(media_recorder_listener);
+    }
+
+    void setErrorCb(on_recorder_msg_error cb, void *context)
+    {
+        REPORT_FUNCTION();
+
+        assert(media_recorder_listener != NULL);
+        media_recorder_listener->setErrorCb(cb, context);
+    }
+
+    void setAudioReadCb(on_recorder_read_audio cb, void *context)
+    {
+        REPORT_FUNCTION();
+
+        assert(media_recorder_listener != NULL);
+        media_recorder_listener->setReadAudioCb(cb, context);
+    }
+
+private:
+    android::sp<MediaRecorderListenerWrapper> media_recorder_listener;
+};
+
+/*!
+ * \brief android_recorder_set_error_cb
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param cb The callback function to be called when a recording error occurs
+ * \param user context to pass through to the error handler
+ */
+void android_recorder_set_error_cb(MediaRecorderWrapper *mr, on_recorder_msg_error cb,
+        void *context)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return;
+    }
+
+    mr->setErrorCb(cb, context);
+}
+
+void android_recorder_set_audio_read_cb(MediaRecorderWrapper *mr, on_recorder_read_audio cb,
+        void *context)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return;
+    }
+
+    mr->setAudioReadCb(cb, context);
+}
+
+/*!
+ * \brief android_media_new_recorder creates a new MediaRecorder
+ * \return New MediaRecorder object, or NULL if the object could not be created.
+ */
+MediaRecorderWrapper *android_media_new_recorder()
+{
+    REPORT_FUNCTION();
+
+    MediaRecorderWrapper *mr = new MediaRecorderWrapper;
+    if (mr == NULL) {
+        ALOGE("Failed to create new MediaRecorder instance.");
+        return NULL;
+    }
+
+    return mr;
+}
+
+/*!
+ * \brief android_recorder_initCheck
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_initCheck(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->initCheck();
+}
+
+/*!
+ * \brief android_recorder_setCamera sets the camera object for recording videos from the camera
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param control Wrapper for the camera (see camera in hybris)
+ * \return negative value if an error occured
+ */
+int android_recorder_setCamera(MediaRecorderWrapper *mr, CameraControl* control)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+    if (control == NULL) {
+        ALOGE("control must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    mr->init();
+
+    return mr->setCamera(control->camera->remote(), control->camera->getRecordingProxy());
+}
+
+/*!
+ * \brief android_recorder_setVideoSource sets the video source.
+ * If no video source is set, only audio is recorded.
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param vs The video source. It's either a camera or a gralloc buffer
+ * \return negative value if an error occured
+ */
+int android_recorder_setVideoSource(MediaRecorderWrapper *mr, VideoSource vs)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setVideoSource(static_cast<int>(vs));
+}
+
+/*!
+ * \brief android_recorder_setAudioSource
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param as The audio source.
+ * \return negative value if an error occured
+ */
+int android_recorder_setAudioSource(MediaRecorderWrapper *mr, AudioSource as)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setAudioSource(static_cast<int>(as));
+}
+
+/*!
+ * \brief android_recorder_setOutputFormat
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param of The output file container format
+ * \return negative value if an error occured
+ */
+int android_recorder_setOutputFormat(MediaRecorderWrapper *mr, OutputFormat of)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setOutputFormat(static_cast<int>(of));
+}
+
+/*!
+ * \brief android_recorder_setVideoEncoder
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param ve The video encoder sets the codec type for encoding/recording video
+ * \return negative value if an error occured
+ */
+int android_recorder_setVideoEncoder(MediaRecorderWrapper *mr, VideoEncoder ve)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setVideoEncoder(static_cast<int>(ve));
+}
+
+/*!
+ * \brief android_recorder_setAudioEncoder
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param ae The audio encoder sets the codec type for encoding/recording audio
+ * \return negative value if an error occured
+ */
+int android_recorder_setAudioEncoder(MediaRecorderWrapper *mr, AudioEncoder ae)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setAudioEncoder(static_cast<int>(ae));
+}
+
+/*!
+ * \brief android_recorder_setOutputFile sets the output file to the given file descriptor
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param fd File descriptor of an open file, that the stream can be written to
+ * \return negative value if an error occured
+ */
+int android_recorder_setOutputFile(MediaRecorderWrapper *mr, int fd)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setOutputFile(fd, 0, 0);
+}
+
+/*!
+ * \brief android_recorder_setVideoSize
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param width output width for the video to record
+ * \param height output height for the video to record
+ * \return negative value if an error occured
+ */
+int android_recorder_setVideoSize(MediaRecorderWrapper *mr, int width, int height)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setVideoSize(width, height);
+}
+
+/*!
+ * \brief android_recorder_setVideoFrameRate
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param frames_per_second How many frames per second to record at (e.g. 720p is typically 30)
+ * \return negative value if an error occured
+ */
+int android_recorder_setVideoFrameRate(MediaRecorderWrapper *mr, int frames_per_second)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setVideoFrameRate(frames_per_second);
+}
+
+/*!
+ * \brief android_recorder_setParameters sets a parameter. Even those without
+ * explicit function.
+ * For possible parameter pairs look for examples in StagefrightRecorder::setParameter()
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param parameters list of parameters. format is "parameter1=value;parameter2=value"
+ * \return negative value if an error occured
+ */
+int android_recorder_setParameters(MediaRecorderWrapper *mr, const char *parameters)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    android::String8 params(parameters);
+    return mr->setParameters(params);
+}
+
+/*!
+ * \brief android_recorder_start starts the recording.
+ * The MediaRecorder has to be in state "prepared" (call android_recorder_prepare() first)
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_start(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->start();
+}
+
+/*!
+ * \brief android_recorder_stop Stops a running recording.
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_stop(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->stop();
+}
+
+/*!
+ * \brief android_recorder_prepare put the MediaRecorder into state "prepare"
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_prepare(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->prepare();
+}
+
+/*!
+ * \brief android_recorder_reset resets the MediaRecorder
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_reset(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->reset();
+}
+
+/*!
+ * \brief android_recorder_close closes the MediaRecorder
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_close(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->close();
+}
+
+/*!
+ * \brief android_recorder_release releases the MediaRecorder resources
+ * This deletes the MediaRecorder instance. So don't use the instance after calling this function.
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_release(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->release();
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_observer.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Ricardo Mendoza <ricardo.mendoza@canonical.com>
+ */
+
+// Uncomment to enabe verbose debug output
+//#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "MediaRecorderObserver"
+
+#include "media_recorder_observer.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <binder/ProcessState.h>
+
+#include <binder/IServiceManager.h>
+
+#include <utils/Vector.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+IMPLEMENT_META_INTERFACE(MediaRecorderObserver, "android.media.IMediaRecorderObserver");
+
+status_t BnMediaRecorderObserver::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case RECORDING_STARTED: {
+            CHECK_INTERFACE(IMediaRecorderObserver, data, reply);
+            recordingStarted();
+
+            return NO_ERROR;
+        } break;
+        case RECORDING_STOPPED: {
+            CHECK_INTERFACE(IMediaRecorderObserver, data, reply);
+            recordingStopped();
+
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+MediaRecorderObserver::MediaRecorderObserver()
+{
+    defaultServiceManager()->addService(
+        String16(IMediaRecorderObserver::exported_service_name()), this);
+
+    ProcessState::self()->startThreadPool();
+}
+
+void MediaRecorderObserver::recordingStarted()
+{
+    if (media_recording_started != nullptr)
+        media_recording_started(true, cb_context);
+}
+
+void MediaRecorderObserver::recordingStopped()
+{
+    if (media_recording_started != nullptr)
+        media_recording_started(false, cb_context);
+}
+
+void MediaRecorderObserver::setRecordingSignalCb(media_recording_started_cb cb, void *context)
+{
+    if (cb != NULL) {
+        cb_context = context;
+        media_recording_started = cb;
+    }
+}
+
+};
+
+// C API
+
+struct MediaRecorderObserver {
+    MediaRecorderObserver(android::MediaRecorderObserver *observer)
+        : impl(observer)
+    {
+    }
+
+    android::MediaRecorderObserver* impl;
+};
+
+MediaRecorderObserver* android_media_recorder_observer_new()
+{
+    MediaRecorderObserver *p = new MediaRecorderObserver(new android::MediaRecorderObserver);
+
+    if (p == NULL) {
+        ALOGE("Failed to create new MediaRecorderObserver instance.");
+        return NULL;
+    }
+
+    return p;
+}
+
+void android_media_recorder_observer_set_cb(MediaRecorderObserver *observer, media_recording_started_cb cb, void *context)
+{
+    if (observer == NULL)
+        return;
+
+    auto p = observer->impl;
+
+    p->setRecordingSignalCb(cb, context);
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_observer.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Ricardo Mendoza <ricardo.mendoza@canonical.com>
+ */
+
+#ifndef MEDIA_RECORDER_OBSERVER_H_
+#define MEDIA_RECORDER_OBSERVER_H_
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+#include <hybris/media/media_recorder_layer.h>
+
+namespace android {
+
+enum {
+    RECORDING_STARTED = IBinder::FIRST_CALL_TRANSACTION,
+    RECORDING_STOPPED,
+};
+
+class IMediaRecorderObserver: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MediaRecorderObserver);
+
+    static const char* exported_service_name() { return "android.media.IMediaRecorderObserver"; }
+
+    virtual void recordingStarted(void) = 0;
+    virtual void recordingStopped(void) = 0;
+};
+
+class BnMediaRecorderObserver: public BnInterface<IMediaRecorderObserver>
+{
+public:
+    virtual status_t onTransact( uint32_t code,
+                                 const Parcel& data,
+                                 Parcel* reply,
+                                 uint32_t flags = 0);
+};
+
+class BpMediaRecorderObserver: public BpInterface<IMediaRecorderObserver>
+{
+public:
+    BpMediaRecorderObserver(const sp<IBinder>& impl)
+        : BpInterface<IMediaRecorderObserver>(impl)
+    {
+    }
+
+    virtual void recordingStarted()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorderObserver::getInterfaceDescriptor());
+        remote()->transact(RECORDING_STARTED, data, &reply);
+        return;
+    }
+
+    virtual void recordingStopped()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorderObserver::getInterfaceDescriptor());
+        remote()->transact(RECORDING_STOPPED, data, &reply);
+        return;
+    }
+};
+
+class MediaRecorderObserver : public BnMediaRecorderObserver
+{
+public:
+    MediaRecorderObserver();
+    ~MediaRecorderObserver() = default;
+
+    virtual void recordingStarted(void);
+    virtual void recordingStopped(void);
+
+    virtual void setRecordingSignalCb(media_recording_started_cb cb, void *context);
+
+private:
+    media_recording_started_cb media_recording_started;
+    void *cb_context;
+};
+
+}; // namespace android
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/surface_texture_client_hybris.cpp
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+// Uncomment to enable verbose debug output
+#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "SurfaceTextureClientHybris"
+
+#include <hybris/media/surface_texture_client_hybris.h>
+#include "surface_texture_client_hybris_priv.h"
+#include "decoding_service_priv.h"
+
+#include <ui/GraphicBuffer.h>
+#include <utils/Log.h>
+#include <ui/Region.h>
+#include <gui/Surface.h>
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+#include <gui/SurfaceTextureClient.h>
+#endif
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/GLConsumer.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__);
+
+using namespace android;
+
+// ----- Begin _SurfaceTextureClientHybris API ----- //
+
+static inline _SurfaceTextureClientHybris *get_internal_stch(SurfaceTextureClientHybris stc, const char * func)
+{
+    if (stc == NULL)
+    {
+        ALOGE("stc must not be NULL (%s)", func);
+        return NULL;
+    }
+
+    _SurfaceTextureClientHybris *s = static_cast<_SurfaceTextureClientHybris*>(stc);
+    assert(s->refcount >= 1);
+
+    return s;
+}
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris()
+    : refcount(1),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+#endif
+
+#if ANDROID_VERSION_MAJOR>=5
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp<IGraphicBufferProducer> &st)
+    : Surface::Surface(st, true),
+      refcount(1),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR>=4
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp<BufferQueue> &bq)
+    : Surface::Surface(bq, true),
+      refcount(1),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp<IGraphicBufferProducer> &st)
+    : Surface::Surface(st, true),
+      refcount(1),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+#endif
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const _SurfaceTextureClientHybris &stch)
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    : SurfaceTextureClient::SurfaceTextureClient(),
+#else
+    : Surface::Surface(new BufferQueue(), true),
+#endif
+      refcount(stch.refcount),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp<ISurfaceTexture> &st)
+    : SurfaceTextureClient::SurfaceTextureClient(st),
+#else
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp<IGraphicBufferProducer> &st)
+    : Surface::Surface(st, false),
+#endif
+      refcount(1),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+#endif
+
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const android::sp<android::IGraphicBufferProducer> &st,
+        bool producerIsControlledByApp)
+    : Surface::Surface(st, producerIsControlledByApp),
+      refcount(1),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+
+_SurfaceTextureClientHybris::~_SurfaceTextureClientHybris()
+{
+    REPORT_FUNCTION()
+
+    ready = false;
+}
+
+bool _SurfaceTextureClientHybris::isReady() const
+{
+    return ready;
+}
+
+void _SurfaceTextureClientHybris::setReady(bool ready)
+{
+    this->ready = ready;
+}
+
+int _SurfaceTextureClientHybris::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd)
+{
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    return SurfaceTextureClient::dequeueBuffer(buffer, fenceFd);
+#else
+    return Surface::dequeueBuffer(buffer, fenceFd);
+#endif
+}
+
+int _SurfaceTextureClientHybris::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd)
+{
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    return SurfaceTextureClient::queueBuffer(buffer, fenceFd);
+#else
+    return Surface::queueBuffer(buffer, fenceFd);
+#endif
+}
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+void _SurfaceTextureClientHybris::setISurfaceTexture(const sp<ISurfaceTexture>& surface_texture)
+{
+    SurfaceTextureClient::setISurfaceTexture(surface_texture);
+#else
+void _SurfaceTextureClientHybris::setISurfaceTexture(const sp<IGraphicBufferProducer>& surface_texture)
+{
+    // We don't need to set up the IGraphicBufferProducer as stc needs it when created
+#endif
+
+    // Ready for rendering
+    ready = true;
+}
+
+void _SurfaceTextureClientHybris::setHardwareRendering(bool do_hardware_rendering)
+{
+    hardware_rendering = do_hardware_rendering;
+}
+
+bool _SurfaceTextureClientHybris::hardwareRendering()
+{
+  return hardware_rendering;
+}
+
+// ----- End _SurfaceTextureClientHybris API ----- //
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+static inline void set_surface(_SurfaceTextureClientHybris *stch, const sp<SurfaceTexture> &surface_texture)
+#else
+static inline void set_surface(_SurfaceTextureClientHybris *stch, const sp<GLConsumer> &surface_texture)
+#endif
+{
+    REPORT_FUNCTION()
+
+    if (stch == NULL)
+        return;
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    stch->setISurfaceTexture(surface_texture->getBufferQueue());
+#else
+    stch->setISurfaceTexture(stch->getIGraphicBufferProducer());
+#endif
+}
+
+SurfaceTextureClientHybris surface_texture_client_create_by_id(unsigned int texture_id)
+{
+    REPORT_FUNCTION()
+
+    if (texture_id == 0)
+    {
+        ALOGE("Cannot create new SurfaceTextureClientHybris, texture id must be > 0.");
+        return NULL;
+    }
+#if ANDROID_VERSION_MAJOR>=5
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    _SurfaceTextureClientHybris *stch(new _SurfaceTextureClientHybris(producer));
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+    // Use a new native buffer allocator vs the default one, which means it'll use the proper one
+    // that will allow rendering to work with Mir
+    sp<NativeBufferAlloc> native_alloc(new NativeBufferAlloc());
+
+    sp<BufferQueue> buffer_queue(new BufferQueue(false, NULL, native_alloc));
+    _SurfaceTextureClientHybris *stch(new _SurfaceTextureClientHybris);
+#else
+    sp<BufferQueue> buffer_queue(new BufferQueue(NULL));
+    _SurfaceTextureClientHybris *stch(new _SurfaceTextureClientHybris(buffer_queue));
+#endif
+
+    ALOGD("stch: %p (%s)", stch, __PRETTY_FUNCTION__);
+
+    if (stch->surface_texture != NULL)
+      stch->surface_texture.clear();
+
+    const bool allow_synchronous_mode = true;
+#if ANDROID_VERSION_MAJOR>=5
+    stch->surface_texture = new GLConsumer(consumer, texture_id, GL_TEXTURE_EXTERNAL_OES, true, true);
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    stch->surface_texture = new SurfaceTexture(texture_id, allow_synchronous_mode, GL_TEXTURE_EXTERNAL_OES, true, buffer_queue);
+    set_surface(stch, stch->surface_texture);
+#else
+    stch->surface_texture = new GLConsumer(buffer_queue, texture_id, GL_TEXTURE_EXTERNAL_OES, true, true);
+#endif
+    set_surface(stch, stch->surface_texture);
+
+    return stch;
+}
+
+SurfaceTextureClientHybris surface_texture_client_create_by_igbp(IGBPWrapperHybris wrapper)
+{
+    if (wrapper == NULL)
+    {
+        ALOGE("Cannot create new SurfaceTextureClientHybris, wrapper must not be NULL.");
+        return NULL;
+    }
+
+    IGBPWrapper *igbp = static_cast<IGBPWrapper*>(wrapper);
+    // The producer should be the same BufferQueue as what the client is using but over Binder
+    // Allow the app to control the producer side BufferQueue
+    _SurfaceTextureClientHybris *stch(new _SurfaceTextureClientHybris(igbp->producer, true));
+    // Ready for rendering
+    stch->setReady();
+    return stch;
+}
+
+GLConsumerWrapperHybris gl_consumer_create_by_id_with_igbc(unsigned int texture_id, IGBCWrapperHybris wrapper)
+{
+    REPORT_FUNCTION()
+
+    if (texture_id == 0)
+    {
+        ALOGE("Cannot create new SurfaceTextureClientHybris, texture id must be > 0.");
+        return NULL;
+    }
+
+    if (wrapper == NULL)
+    {
+        ALOGE("Cannot create new GLConsumerHybris, wrapper must not be NULL.");
+        return NULL;
+    }
+
+    IGBCWrapper *igbc = static_cast<IGBCWrapper*>(wrapper);
+    // Use a fence guard and consumer is controlled by app:
+    sp<_GLConsumerHybris> gl_consumer = new _GLConsumerHybris(igbc->consumer, texture_id, GL_TEXTURE_EXTERNAL_OES, true, true);
+    GLConsumerWrapper *glc_wrapper = new GLConsumerWrapper(gl_consumer);
+
+    return glc_wrapper;
+}
+
+int gl_consumer_set_frame_available_cb(GLConsumerWrapperHybris wrapper, FrameAvailableCbHybris cb, void *context)
+{
+    REPORT_FUNCTION()
+
+    if (wrapper == NULL)
+    {
+        ALOGE("Cannot set GLConsumerWrapperHybris, wrapper must not be NULL");
+        return BAD_VALUE;
+    }
+    if (cb == NULL)
+    {
+        ALOGE("Cannot set FrameAvailableCbHybris, cb must not be NULL");
+        return BAD_VALUE;
+    }
+
+    GLConsumerWrapper *glc_wrapper = static_cast<GLConsumerWrapper*>(wrapper);
+    sp<_GLConsumerHybris> glc_hybris = static_cast<_GLConsumerHybris*>(glc_wrapper->consumer.get());
+    glc_hybris->createFrameAvailableListener(cb, wrapper, context);
+
+    return OK;
+}
+
+void gl_consumer_get_transformation_matrix(GLConsumerWrapperHybris wrapper, float *matrix)
+{
+    REPORT_FUNCTION()
+
+    if (wrapper == NULL)
+    {
+        ALOGE("Cannot set GLConsumerWrapperHybris, wrapper must not be NULL");
+        return;
+    }
+
+    GLConsumerWrapper *glc_wrapper = static_cast<GLConsumerWrapper*>(wrapper);
+    sp<_GLConsumerHybris> glc_hybris = static_cast<_GLConsumerHybris*>(glc_wrapper->consumer.get());
+    glc_hybris->getTransformMatrix(static_cast<GLfloat*>(matrix));
+}
+
+void gl_consumer_update_texture(GLConsumerWrapperHybris wrapper)
+{
+    REPORT_FUNCTION()
+
+    if (wrapper == NULL)
+    {
+        ALOGE("Cannot set GLConsumerWrapperHybris, wrapper must not be NULL");
+        return;
+    }
+
+    GLConsumerWrapper *glc_wrapper = static_cast<GLConsumerWrapper*>(wrapper);
+    sp<_GLConsumerHybris> glc_hybris = static_cast<_GLConsumerHybris*>(glc_wrapper->consumer.get());
+    glc_hybris->updateTexImage();
+}
+
+uint8_t surface_texture_client_is_ready_for_rendering(SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return false;
+
+    return static_cast<uint8_t>(s->isReady());
+}
+
+uint8_t surface_texture_client_hardware_rendering(SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return false;
+
+    return s->hardwareRendering();
+}
+
+void surface_texture_client_set_hardware_rendering(SurfaceTextureClientHybris stc, uint8_t hardware_rendering)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return;
+
+    s->setHardwareRendering(static_cast<bool>(hardware_rendering));
+}
+
+void surface_texture_client_get_transformation_matrix(SurfaceTextureClientHybris stc, float *matrix)
+{
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return;
+
+    s->surface_texture->getTransformMatrix(static_cast<GLfloat*>(matrix));
+}
+
+void surface_texture_client_update_texture(SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return;
+
+    s->surface_texture->updateTexImage();
+}
+
+void surface_texture_client_destroy(SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+    {
+        ALOGE("s == NULL, cannot destroy SurfaceTextureClientHybris instance");
+        return;
+    }
+
+    s->refcount = 0;
+
+    delete s;
+}
+
+void surface_texture_client_ref(SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return;
+
+    s->refcount++;
+}
+
+void surface_texture_client_unref(SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+    {
+        ALOGE("s == NULL, cannot unref SurfaceTextureClientHybris instance");
+        return;
+    }
+
+    if (s->refcount > 1)
+        s->refcount--;
+    else
+        surface_texture_client_destroy (stc);
+}
+
+void surface_texture_client_set_surface_texture(SurfaceTextureClientHybris stc, EGLNativeWindowType native_window)
+{
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return;
+
+    if (native_window == NULL)
+    {
+        ALOGE("native_window must not be NULL");
+        return;
+    }
+
+    sp<Surface> surface = static_cast<Surface*>(native_window);
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    s->setISurfaceTexture(surface->getSurfaceTexture());
+#else
+    s->setISurfaceTexture(surface->getIGraphicBufferProducer());
+#endif
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/surface_texture_client_hybris_priv.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef SURFACE_TEXTURE_CLIENT_HYBRIS_PRIV_H
+#define SURFACE_TEXTURE_CLIENT_HYBRIS_PRIV_H
+
+#include "hybris/media/surface_texture_client_hybris.h"
+
+#include <gui/Surface.h>
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+#include <gui/SurfaceTextureClient.h>
+#else
+#include <gui/GLConsumer.h>
+#endif
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+struct _SurfaceTextureClientHybris : public android::SurfaceTextureClient
+#else
+struct _SurfaceTextureClientHybris : public android::Surface
+#endif
+{
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    _SurfaceTextureClientHybris();
+#endif
+    _SurfaceTextureClientHybris(const _SurfaceTextureClientHybris &stch);
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    _SurfaceTextureClientHybris(const android::sp<android::ISurfaceTexture> &st);
+#else
+    _SurfaceTextureClientHybris(const android::sp<android::IGraphicBufferProducer> &st);
+    _SurfaceTextureClientHybris(const android::sp<android::IGraphicBufferProducer> &st,
+            bool producerIsControlledByApp);
+    _SurfaceTextureClientHybris(const android::sp<android::BufferQueue> &bq);
+#endif
+    ~_SurfaceTextureClientHybris();
+
+    /** Has a texture id or EGLNativeWindowType been passed in, meaning rendering will function? **/
+    bool isReady() const;
+    void setReady(bool ready = true);
+
+public:
+    int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
+    int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    void setISurfaceTexture(const android::sp<android::ISurfaceTexture>& surface_texture);
+#else
+    void setISurfaceTexture(const android::sp<android::IGraphicBufferProducer>& surface_texture);
+#endif
+    void setHardwareRendering(bool do_hardware_rendering);
+    bool hardwareRendering();
+
+    unsigned int refcount;
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    android::sp<android::SurfaceTexture> surface_texture;
+#else
+    android::sp<android::GLConsumer> surface_texture;
+#endif
+
+private:
+    bool ready;
+    bool hardware_rendering;
+};
+
+namespace android {
+
+class _GLConsumerHybris : public GLConsumer
+{
+    class FrameAvailableListener : public GLConsumer::FrameAvailableListener
+    {
+    public:
+        FrameAvailableListener()
+            : frame_available_cb(NULL),
+              glc_wrapper(NULL),
+              context(NULL)
+        {
+        }
+
+#if ANDROID_VERSION_MAJOR==5 && ANDROID_VERSION_MINOR>=1 || ANDROID_VERSION_MAJOR>=6
+		virtual void onFrameAvailable(const android::BufferItem& item)
+#else
+        virtual void onFrameAvailable()
+#endif
+        {
+            if (frame_available_cb != NULL)
+                frame_available_cb(glc_wrapper, context);
+            else
+                ALOGE("Failed to call, frame_available_cb is NULL");
+        }
+
+        void setFrameAvailableCbHybris(FrameAvailableCbHybris cb, GLConsumerWrapperHybris wrapper, void *context)
+        {
+            frame_available_cb = cb;
+            glc_wrapper = wrapper;
+            this->context = context;
+        }
+
+    private:
+        FrameAvailableCbHybris frame_available_cb;
+        GLConsumerWrapperHybris glc_wrapper;
+        void *context;
+    };
+
+public:
+    _GLConsumerHybris(const sp<IGraphicBufferConsumer>& bq,
+            uint32_t tex, uint32_t textureTarget = TEXTURE_EXTERNAL,
+            bool useFenceSync = true, bool isControlledByApp = false)
+        : GLConsumer(bq, tex, textureTarget, useFenceSync, isControlledByApp)
+    {
+    }
+
+    void createFrameAvailableListener(FrameAvailableCbHybris cb, GLConsumerWrapperHybris wrapper, void *context)
+    {
+        frame_available_listener = new _GLConsumerHybris::FrameAvailableListener();
+        frame_available_listener->setFrameAvailableCbHybris(cb, wrapper, context);
+        setFrameAvailableListener(frame_available_listener);
+    }
+
+private:
+    sp<_GLConsumerHybris::FrameAvailableListener> frame_available_listener;
+};
+
+}; // namespace android
+
+#endif
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/surface_flinger/Android.mk
+++ libhybris-0.1.0+git20151016+6d424c9/compat/surface_flinger/Android.mk
@@ -1,5 +1,6 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
 
 HYBRIS_PATH := $(LOCAL_PATH)/../../hybris
 
@@ -30,6 +31,11 @@ LOCAL_SRC_FILES:= \
 
 LOCAL_MODULE:= direct_sf_test
 LOCAL_MODULE_TAGS := optional
+ifdef TARGET_2ND_ARCH
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(if $(filter false,$(BOARD_UBUNTU_PREFER_32_BIT)),$(LOCAL_MODULE)$(TARGET_2ND_ARCH_MODULE_SUFFIX),$(LOCAL_MODULE))
+LOCAL_MODULE_STEM_64 := $(if $(filter false,$(BOARD_UBUNTU_PREFER_32_BIT)),$(LOCAL_MODULE),$(LOCAL_MODULE)_64)
+endif
 
 LOCAL_C_INCLUDES := \
 	$(HYBRIS_PATH)/include
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/surface_flinger/surface_flinger_compatibility_layer.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/compat/surface_flinger/surface_flinger_compatibility_layer.cpp
@@ -28,6 +28,9 @@
 #include <ui/PixelFormat.h>
 #include <ui/Region.h>
 #include <ui/Rect.h>
+#if ANDROID_VERSION_MAJOR>=5
+  #include <hardware/hwcomposer_defs.h>
+#endif
 
 #include <cassert>
 #include <cstdio>
@@ -80,7 +83,11 @@ void sf_blank(size_t display_id)
 		return;
 	}
 
+#if ANDROID_VERSION_MAJOR<=4
 	android::SurfaceComposerClient::blankDisplay(display);
+#elif ANDROID_VERSION_MAJOR>=5
+	android::SurfaceComposerClient::setDisplayPowerMode(display, HWC_POWER_MODE_OFF);
+#endif
 }
 
 void sf_unblank(size_t display_id)
@@ -98,7 +105,11 @@ void sf_unblank(size_t display_id)
 		return;
 	}
 
+#if ANDROID_VERSION_MAJOR<=4
 	android::SurfaceComposerClient::unblankDisplay(display);
+#elif ANDROID_VERSION_MAJOR>=5
+	android::SurfaceComposerClient::setDisplayPowerMode(display, HWC_POWER_MODE_NORMAL);
+#endif
 }
 
 size_t sf_get_display_width(size_t display_id)
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/ui/Android.mk
+++ libhybris-0.1.0+git20151016+6d424c9/compat/ui/Android.mk
@@ -1,5 +1,6 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
 
 HYBRIS_PATH := $(LOCAL_PATH)/../../hybris
 
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/ui/ui_compatibility_layer.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/compat/ui/ui_compatibility_layer.cpp
@@ -126,6 +126,7 @@ void* graphic_buffer_get_native_buffer(s
     return buffer->self->getNativeBuffer();
 }
 
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
 void graphic_buffer_set_index(struct graphic_buffer *buffer, int index)
 {
     return buffer->self->setIndex(index);
@@ -135,6 +136,7 @@ int graphic_buffer_get_index(struct grap
 {
     return buffer->self->getIndex();
 }
+#endif
 
 int graphic_buffer_init_check(struct graphic_buffer *buffer)
 {
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/Makefile.am
@@ -6,7 +6,7 @@ endif
 if HAS_ANDROID_5_0_0
 SUBDIRS += libsync
 endif
-SUBDIRS += egl glesv1 glesv2 ui sf input camera vibrator
+SUBDIRS += egl glesv1 glesv2 ui sf input camera vibrator media wifi
 
 if HAS_LIBNFC_NXP_HEADERS
 SUBDIRS += libnfc_nxp libnfc_ndef_nxp
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/README
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/README
@@ -0,0 +1,12 @@
+libhybris
+=========
+
+Hybris is a solution that commits hybris, by allowing us to use bionic
+-based HW adaptations in glibc systems.
+
+
+Supported Architectures
+-----------------------
+
+Libhybris currently only supports 32 bit ARM and x86 systems. 64 bit
+system are not yet supported.
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/camera/camera.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/camera/camera.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Canonical Ltd
+ * Copyright (C) 2013 - 2014 Canonical Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,13 +26,16 @@
 #include <hybris/camera/camera_compatibility_layer_capabilities.h>
 #include <hybris/surface_flinger/surface_flinger_compatibility_layer.h>
 
-#define COMPAT_LIBRARY_PATH "/system/lib/libcamera_compat_layer.so"
+#define COMPAT_LIBRARY_PATH "libcamera_compat_layer.so"
 
 HYBRIS_LIBRARY_INITIALIZE(camera, COMPAT_LIBRARY_PATH);
 
 HYBRIS_IMPLEMENT_FUNCTION0(camera, int, android_camera_get_number_of_devices);
+HYBRIS_IMPLEMENT_FUNCTION3(camera, int, android_camera_get_device_info, int32_t, int*, int*);
 HYBRIS_IMPLEMENT_FUNCTION2(camera, struct CameraControl*, android_camera_connect_to,
 	CameraType, struct CameraControlListener*);
+HYBRIS_IMPLEMENT_FUNCTION2(camera, struct CameraControl*, android_camera_connect_by_id,
+	int32_t, struct CameraControlListener*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_disconnect,
 	struct CameraControl*);
 HYBRIS_IMPLEMENT_FUNCTION1(camera, int, android_camera_lock, struct CameraControl*);
@@ -52,8 +55,12 @@ HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera,
 	struct CameraControl*, SceneMode);
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_auto_focus_mode,
 	struct CameraControl*, AutoFocusMode);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_preview_format,
+	struct CameraControl*, CameraPixelFormat);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_set_picture_size,
 	struct CameraControl*, int, int);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_set_thumbnail_size,
+	struct CameraControl*, int, int);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_set_preview_size,
 	struct CameraControl*, int, int);
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_display_orientation,
@@ -66,12 +73,20 @@ HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera,
 	struct CameraControl*, FocusRegion*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_reset_focus_region,
 	struct CameraControl*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_metering_region,
+        struct CameraControl*, MeteringRegion*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_reset_metering_region,
+        struct CameraControl*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_preview_fps,
 	struct CameraControl*, int);
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_rotation,
 	struct CameraControl*, int);
+HYBRIS_IMPLEMENT_VOID_FUNCTION6(camera, android_camera_set_location,
+	struct CameraControl*, const float*, const float*, const float*, int, const char*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_set_video_size,
 	struct CameraControl*, int, int);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_jpeg_quality,
+	struct CameraControl*, int);
 
 // Getters
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_get_effect_mode,
@@ -88,6 +103,8 @@ HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera,
 	struct CameraControl*, int*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_get_picture_size,
 	struct CameraControl*, int*, int*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_get_thumbnail_size,
+	struct CameraControl*, int*, int*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_get_preview_size,
 	struct CameraControl*, int*, int*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_get_preview_fps_range,
@@ -98,14 +115,22 @@ HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera,
 	struct CameraControl*, float*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_get_video_size,
 	struct CameraControl*, int*, int*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_get_jpeg_quality,
+	struct CameraControl*, int*);
 
 // Enumerators
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_enumerate_supported_picture_sizes,
 	struct CameraControl*, size_callback, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_enumerate_supported_thumbnail_sizes,
+	struct CameraControl*, size_callback, void*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_enumerate_supported_preview_sizes,
 	struct CameraControl*, size_callback, void*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_enumerate_supported_video_sizes,
 	struct CameraControl*, size_callback, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_enumerate_supported_scene_modes,
+	struct CameraControl*, scene_mode_callback, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_enumerate_supported_flash_modes,
+	struct CameraControl*, flash_mode_callback, void*);
 
 HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_update_preview_texture, struct CameraControl*);
 
@@ -118,3 +143,6 @@ HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera,
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_zoom, struct CameraControl*, int32_t);
 HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_stop_zoom, struct CameraControl*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_take_snapshot, struct CameraControl*);
+
+HYBRIS_IMPLEMENT_FUNCTION2(camera, int, android_camera_set_preview_callback_mode,
+	struct CameraControl*, PreviewCallbackMode);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/Makefile.am
@@ -1,44 +1,51 @@
 lib_LTLIBRARIES = \
 	libhybris-common.la
 
-# JB linker works fine for ICS
-if HAS_ANDROID_4_0_0
-SUBDIRS = jb
-libhybris_common_la_LIBADD= jb/libandroid-linker.la
-else
-if HAS_ANDROID_5_0_0
-SUBDIRS = jb
-libhybris_common_la_LIBADD= jb/libandroid-linker.la
-else
-if HAS_ANDROID_2_3_0
-SUBDIRS = gingerbread
-libhybris_common_la_LIBADD= gingerbread/libandroid-linker.la
-else
-$(error No Android Version is defined)
-endif
+SUBDIRS =
+
+if !WANT_ARCH_ARM64
+SUBDIRS += jb
 endif
+
+if WANT_EXPERIMENTAL
+SUBDIRS += mm
 endif
 
 libhybris_common_la_SOURCES = \
 	hooks.c \
 	hooks_shm.c \
 	strlcpy.c \
-	dlfcn.c \
+	strlcat.c \
 	logging.c \
 	sysconf.c
-libhybris_common_la_CFLAGS = \
+libhybris_common_la_CPPFLAGS = \
 	-I$(top_srcdir)/include \
 	$(ANDROID_HEADERS_CFLAGS) \
-	-I$(top_srcdir)/common
+	-I$(top_srcdir)/common \
+	-DLINKER_PLUGIN_DIR=\"$(libdir)/libhybris/linker\"
 if WANT_TRACE
-libhybris_common_la_CFLAGS += -DDEBUG
+libhybris_common_la_CPPFLAGS += -DDEBUG
 endif
 if WANT_DEBUG
-libhybris_common_la_CFLAGS += -ggdb -O0
+libhybris_common_la_CPPFLAGS += -ggdb -O0
+endif
+if WANT_MALI_QUIRKS
+libhybris_common_la_CPPFLAGS += -DMALI_QUIRKS
+endif
+if WANT_UBUNTU_LINKER_OVERRIDES
+libhybris_common_la_CPPFLAGS += -DUBUNTU_LINKER_OVERRIDES
+endif
+if !WANT_ARCH_ARM64
+libhybris_common_la_CPPFLAGS += -DWANT_LINKER_JB
+endif
+if WANT_EXPERIMENTAL
+libhybris_common_la_CPPFLAGS += -DWANT_LINKER_MM
 endif
 libhybris_common_la_LDFLAGS = \
 	-ldl \
 	-lrt \
 	-pthread \
+	-lc \
+	-lstdc++ \
 	$(top_builddir)/properties/libandroid-properties.la \
 	-version-info "$(LT_CURRENT)":"$(LT_REVISION)":"$(LT_AGE)"
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/hooks.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/hooks.c
@@ -17,18 +17,21 @@
  *
  */
 
+#include "config.h"
+
 #include <hybris/common/binding.h>
 
 #include "hooks_shm.h"
 
-#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdarg.h>
 #include <stdio_ext.h>
 #include <stddef.h>
 #include <stdlib.h>
+#include <limits.h>
 #include <malloc.h>
 #include <string.h>
+#include <inttypes.h>
 #include <strings.h>
 #include <dlfcn.h>
 #include <pthread.h>
@@ -39,22 +42,47 @@
 #include <dirent.h>
 #include <sys/types.h>
 #include <stdarg.h>
+#include <wchar.h>
+#include <sched.h>
+#include <pwd.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/signalfd.h>
 
 #include <sys/ipc.h>
 #include <sys/shm.h>
 #include <fcntl.h>
 
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+
 #include <netdb.h>
 #include <unistd.h>
 #include <syslog.h>
 #include <locale.h>
 #include <sys/syscall.h>
 #include <sys/auxv.h>
+#include <sys/prctl.h>
+
+#include <sys/mman.h>
+#include <libgen.h>
+#include <mntent.h>
 
 #include <hybris/properties/properties.h>
+#include <hybris/common/hooks.h>
 
 static locale_t hybris_locale;
 static int locale_inited = 0;
+static hybris_hook_cb hook_callback = NULL;
+
+static void (*_android_linker_init)(int sdk_version, void* (*get_hooked_symbol)(const char*, const char*)) = NULL;
+static void* (*_android_dlopen)(const char *filename, int flags) = NULL;
+static void* (*_android_dlsym)(void *handle, const char *symbol) = NULL;
+static void* (*_android_dladdr)(void *addr, Dl_info *info) = NULL;
+static int (*_android_dlclose)(void *handle) = NULL;
+static const char* (*_android_dlerror)(void) = NULL;
+
 /* TODO:
 *  - Check if the int arguments at attr_set/get match the ones at Android
 *  - Check how to deal with memory leaks (specially with static initializers)
@@ -68,8 +96,12 @@ static int locale_inited = 0;
 
 #define ANDROID_MUTEX_SHARED_MASK      0x2000
 #define ANDROID_COND_SHARED_MASK       0x0001
+#define ANDROID_COND_COUNTER_INCREMENT 0x0002
+#define ANDROID_COND_COUNTER_MASK      (~ANDROID_COND_SHARED_MASK)
 #define ANDROID_RWLOCKATTR_SHARED_MASK 0x0010
 
+#define ANDROID_COND_IS_SHARED(c)  (((c)->value & ANDROID_COND_SHARED_MASK) != 0)
+
 /* For the static initializer types */
 #define ANDROID_PTHREAD_MUTEX_INITIALIZER            0
 #define ANDROID_PTHREAD_RECURSIVE_MUTEX_INITIALIZER  0x4000
@@ -77,10 +109,21 @@ static int locale_inited = 0;
 #define ANDROID_PTHREAD_COND_INITIALIZER             0
 #define ANDROID_PTHREAD_RWLOCK_INITIALIZER           0
 
+#define MALI_HIST_DUMP_THREAD_NAME "mali-hist-dump"
+
 /* Debug */
 #include "logging.h"
 #define LOGD(message, ...) HYBRIS_DEBUG_LOG(HOOKS, message, ##__VA_ARGS__)
 
+#ifdef DEBUG
+#define TRACE_HOOK(message, ...) \
+    if (hybris_should_trace(NULL, NULL)) { \
+        HYBRIS_DEBUG_LOG(HOOKS, message, ##__VA_ARGS__); \
+    }
+#else
+#define TRACE_HOOK(message, ...)
+#endif
+
 /* we have a value p:
  *  - if p <= ANDROID_TOP_ADDR_VALUE_MUTEX then it is an android mutex, not one we processed
  *  - if p > VMALLOC_END, then the pointer is not a result of malloc ==> it is an shm offset
@@ -91,8 +134,13 @@ struct _hook {
     void *func;
 };
 
+/* pthread cond struct as done in Android */
+typedef struct {
+    int volatile value;
+} android_cond_t;
+
 /* Helpers */
-static int hybris_check_android_shared_mutex(unsigned int mutex_addr)
+static int hybris_check_android_shared_mutex(uintptr_t mutex_addr)
 {
     /* If not initialized or initialized by Android, it should contain a low
      * address, which is basically just the int values for Android's own
@@ -104,7 +152,7 @@ static int hybris_check_android_shared_m
     return 0;
 }
 
-static int hybris_check_android_shared_cond(unsigned int cond_addr)
+static int hybris_check_android_shared_cond(uintptr_t cond_addr)
 {
     /* If not initialized or initialized by Android, it should contain a low
      * address, which is basically just the int values for Android's own
@@ -113,9 +161,59 @@ static int hybris_check_android_shared_c
                     (cond_addr & ANDROID_COND_SHARED_MASK))
         return 1;
 
+    /* In case android is setting up cond_addr with a negative value,
+     * used for error control */
+    if (cond_addr > HYBRIS_SHM_MASK_TOP)
+        return 1;
+
+    return 0;
+}
+
+/* Based on Android's Bionic pthread implementation.
+ * This is just needed when we have a shared cond with Android */
+static int __android_pthread_cond_pulse(android_cond_t *cond, int counter)
+{
+    long flags;
+    int fret;
+
+    if (cond == NULL)
+        return EINVAL;
+
+    flags = (cond->value & ~ANDROID_COND_COUNTER_MASK);
+    for (;;) {
+        long oldval = cond->value;
+        long newval = 0;
+        /* In our case all we need to do is make sure the negative value
+         * is under our range, which is the last 0xF from SHM_MASK */
+        if (oldval < -12)
+            newval = ((oldval + ANDROID_COND_COUNTER_INCREMENT) &
+                            ANDROID_COND_COUNTER_MASK) | flags;
+        else
+            newval = ((oldval - ANDROID_COND_COUNTER_INCREMENT) &
+                            ANDROID_COND_COUNTER_MASK) | flags;
+        if (__sync_bool_compare_and_swap(&cond->value, oldval, newval))
+            break;
+    }
+
+    int pshared = cond->value & ANDROID_COND_SHARED_MASK;
+    fret = syscall(SYS_futex , &cond->value,
+                   pshared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, counter,
+                   NULL, NULL, NULL);
+    LOGD("futex based pthread_cond_*, value %d, counter %d, ret %d",
+                                            cond->value, counter, fret);
     return 0;
 }
 
+int android_pthread_cond_broadcast(android_cond_t *cond)
+{
+    return __android_pthread_cond_pulse(cond, INT_MAX);
+}
+
+int android_pthread_cond_signal(android_cond_t *cond)
+{
+    return __android_pthread_cond_pulse(cond, 1);
+}
+
 static void hybris_set_mutex_attr(unsigned int android_value, pthread_mutexattr_t *attr)
 {
     /* Init already sets as PTHREAD_MUTEX_NORMAL */
@@ -159,25 +257,49 @@ static pthread_rwlock_t* hybris_alloc_in
  * utils, such as malloc, memcpy
  *
  * Useful to handle hacks such as the one applied for Nvidia, and to
- * avoid crashes.
+ * avoid crashes. Also we need to hook all memory allocation related
+ * ones to make sure all are using the same allocator implementation.
  *
  * */
 
-static void *my_malloc(size_t size)
+static void *_hybris_hook_malloc(size_t size)
 {
-    return malloc(size);
+    TRACE_HOOK("size %zu", size);
+
+    void *res = malloc(size);
+
+    TRACE_HOOK("res %p", res);
+
+    return res;
 }
 
-static void *my_memcpy(void *dst, const void *src, size_t len)
+static size_t _hybris_hook_malloc_usable_size (void *ptr)
 {
+    TRACE_HOOK("ptr %p", ptr);
+
+    return malloc_usable_size(ptr);
+}
+
+static void *_hybris_hook_memcpy(void *dst, const void *src, size_t len)
+{
+    TRACE_HOOK("dst %p src %p len %zu", dst, src, len);
+
     if (src == NULL || dst == NULL)
         return NULL;
 
     return memcpy(dst, src, len);
 }
 
-static size_t my_strlen(const char *s)
+static int _hybris_hook_memcmp(const void *s1, const void *s2, size_t n)
+{
+    TRACE_HOOK("s1 %p '%s' s2 %p '%s' n %zu", s1, (char*) s1, s2, (char*) s2, n);
+
+    return memcmp(s1, s2, n);
+}
+
+static size_t _hybris_hook_strlen(const char *s)
 {
+    TRACE_HOOK("s '%s'", s);
 
     if (s == NULL)
         return -1;
@@ -185,9 +307,11 @@ static size_t my_strlen(const char *s)
     return strlen(s);
 }
 
-static pid_t my_gettid( void )
+static pid_t _hybris_hook_gettid(void)
 {
-        return syscall( __NR_gettid );
+    TRACE_HOOK("");
+
+    return syscall(__NR_gettid);
 }
 
 /*
@@ -198,17 +322,43 @@ static pid_t my_gettid( void )
  *
  * */
 
-static int my_pthread_create(pthread_t *thread, const pthread_attr_t *__attr,
+static int _hybris_hook_pthread_create(pthread_t *thread, const pthread_attr_t *__attr,
                              void *(*start_routine)(void*), void *arg)
 {
     pthread_attr_t *realattr = NULL;
 
+    TRACE_HOOK("thread %p attr %p", thread, __attr);
+
     if (__attr != NULL)
-        realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+        realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
 
     return pthread_create(thread, realattr, start_routine, arg);
 }
 
+static int _hybris_hook_pthread_kill(pthread_t thread, int sig)
+{
+    TRACE_HOOK("thread %llu sig %d", (unsigned long long) thread, sig);
+
+    if (thread == 0)
+        return ESRCH;
+
+    return pthread_kill(thread, sig);
+}
+
+static int _hybris_hook_pthread_setspecific(pthread_key_t key, const void *ptr)
+{
+    TRACE_HOOK("key %d ptr %" PRIdPTR, key, (intptr_t) ptr);
+
+    return pthread_setspecific(key, ptr);
+}
+
+static void* _hybris_hook_pthread_getspecific(pthread_key_t key)
+{
+    TRACE_HOOK("key %d", key);
+
+    return pthread_getspecific(key);
+}
+
 /*
  * pthread_attr_* functions
  *
@@ -217,123 +367,176 @@ static int my_pthread_create(pthread_t *
  *
  * */
 
-static int my_pthread_attr_init(pthread_attr_t *__attr)
+static int _hybris_hook_pthread_attr_init(pthread_attr_t *__attr)
 {
     pthread_attr_t *realattr;
 
+    TRACE_HOOK("attr %p", __attr);
+
     realattr = malloc(sizeof(pthread_attr_t));
-    *((unsigned int *)__attr) = (unsigned int) realattr;
+    *((uintptr_t *)__attr) = (uintptr_t) realattr;
 
     return pthread_attr_init(realattr);
 }
 
-static int my_pthread_attr_destroy(pthread_attr_t *__attr)
+static int _hybris_hook_pthread_attr_destroy(pthread_attr_t *__attr)
 {
     int ret;
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p", __attr);
 
     ret = pthread_attr_destroy(realattr);
-    /* We need to release the memory allocated at my_pthread_attr_init
+    /* We need to release the memory allocated at _hybris_hook_pthread_attr_init
      * Possible side effects if destroy is called without our init */
     free(realattr);
 
     return ret;
 }
 
-static int my_pthread_attr_setdetachstate(pthread_attr_t *__attr, int state)
+static int _hybris_hook_pthread_attr_setdetachstate(pthread_attr_t *__attr, int state)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p state %d", __attr, state);
+
     return pthread_attr_setdetachstate(realattr, state);
 }
 
-static int my_pthread_attr_getdetachstate(pthread_attr_t const *__attr, int *state)
+static int _hybris_hook_pthread_attr_getdetachstate(pthread_attr_t const *__attr, int *state)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p state %p", __attr, state);
+
     return pthread_attr_getdetachstate(realattr, state);
 }
 
-static int my_pthread_attr_setschedpolicy(pthread_attr_t *__attr, int policy)
+static int _hybris_hook_pthread_attr_setschedpolicy(pthread_attr_t *__attr, int policy)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p policy %d", __attr, policy);
+
     return pthread_attr_setschedpolicy(realattr, policy);
 }
 
-static int my_pthread_attr_getschedpolicy(pthread_attr_t const *__attr, int *policy)
+static int _hybris_hook_pthread_attr_getschedpolicy(pthread_attr_t const *__attr, int *policy)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p policy %p", __attr, policy);
+
     return pthread_attr_getschedpolicy(realattr, policy);
 }
 
-static int my_pthread_attr_setschedparam(pthread_attr_t *__attr, struct sched_param const *param)
+static int _hybris_hook_pthread_attr_setschedparam(pthread_attr_t *__attr, struct sched_param const *param)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p param %p", __attr, param);
+
     return pthread_attr_setschedparam(realattr, param);
 }
 
-static int my_pthread_attr_getschedparam(pthread_attr_t const *__attr, struct sched_param *param)
+static int _hybris_hook_pthread_attr_getschedparam(pthread_attr_t const *__attr, struct sched_param *param)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p param %p", __attr, param);
+
     return pthread_attr_getschedparam(realattr, param);
 }
 
-static int my_pthread_attr_setstacksize(pthread_attr_t *__attr, size_t stack_size)
+static int _hybris_hook_pthread_attr_setstacksize(pthread_attr_t *__attr, size_t stack_size)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p stack size %zu", __attr, stack_size);
+
     return pthread_attr_setstacksize(realattr, stack_size);
 }
 
-static int my_pthread_attr_getstacksize(pthread_attr_t const *__attr, size_t *stack_size)
+static int _hybris_hook_pthread_attr_getstacksize(pthread_attr_t const *__attr, size_t *stack_size)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p stack size %p", __attr, stack_size);
+
     return pthread_attr_getstacksize(realattr, stack_size);
 }
 
-static int my_pthread_attr_setstackaddr(pthread_attr_t *__attr, void *stack_addr)
+static int _hybris_hook_pthread_attr_setstackaddr(pthread_attr_t *__attr, void *stack_addr)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p stack addr %p", __attr, stack_addr);
+
     return pthread_attr_setstackaddr(realattr, stack_addr);
 }
 
-static int my_pthread_attr_getstackaddr(pthread_attr_t const *__attr, void **stack_addr)
+static int _hybris_hook_pthread_attr_getstackaddr(pthread_attr_t const *__attr, void **stack_addr)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p stack addr %p", __attr, stack_addr);
+
     return pthread_attr_getstackaddr(realattr, stack_addr);
 }
 
-static int my_pthread_attr_setstack(pthread_attr_t *__attr, void *stack_base, size_t stack_size)
+static int _hybris_hook_pthread_attr_setstack(pthread_attr_t *__attr, void *stack_base, size_t stack_size)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p stack base %p stack size %zu", __attr,
+               stack_base, stack_size);
+
     return pthread_attr_setstack(realattr, stack_base, stack_size);
 }
 
-static int my_pthread_attr_getstack(pthread_attr_t const *__attr, void **stack_base, size_t *stack_size)
+static int _hybris_hook_pthread_attr_getstack(pthread_attr_t const *__attr, void **stack_base, size_t *stack_size)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p stack base %p stack size %p", __attr,
+               stack_base, stack_size);
+
     return pthread_attr_getstack(realattr, stack_base, stack_size);
 }
 
-static int my_pthread_attr_setguardsize(pthread_attr_t *__attr, size_t guard_size)
+static int _hybris_hook_pthread_attr_setguardsize(pthread_attr_t *__attr, size_t guard_size)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p guard size %zu", __attr, guard_size);
+
     return pthread_attr_setguardsize(realattr, guard_size);
 }
 
-static int my_pthread_attr_getguardsize(pthread_attr_t const *__attr, size_t *guard_size)
+static int _hybris_hook_pthread_attr_getguardsize(pthread_attr_t const *__attr, size_t *guard_size)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p guard size %p", __attr, guard_size);
+
     return pthread_attr_getguardsize(realattr, guard_size);
 }
 
-static int my_pthread_attr_setscope(pthread_attr_t *__attr, int scope)
+static int _hybris_hook_pthread_attr_setscope(pthread_attr_t *__attr, int scope)
 {
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p scope %d", __attr, scope);
+
     return pthread_attr_setscope(realattr, scope);
 }
 
-static int my_pthread_attr_getscope(pthread_attr_t const *__attr)
+static int _hybris_hook_pthread_attr_getscope(pthread_attr_t const *__attr)
 {
     int scope;
-    pthread_attr_t *realattr = (pthread_attr_t *) *(unsigned int *) __attr;
+    pthread_attr_t *realattr = (pthread_attr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p", __attr);
 
     /* Android doesn't have the scope attribute because it always
      * returns PTHREAD_SCOPE_SYSTEM */
@@ -342,12 +545,14 @@ static int my_pthread_attr_getscope(pthr
     return scope;
 }
 
-static int my_pthread_getattr_np(pthread_t thid, pthread_attr_t *__attr)
+static int _hybris_hook_pthread_getattr_np(pthread_t thid, pthread_attr_t *__attr)
 {
     pthread_attr_t *realattr;
 
+    TRACE_HOOK("attr %p", __attr);
+
     realattr = malloc(sizeof(pthread_attr_t));
-    *((unsigned int *)__attr) = (unsigned int) realattr;
+    *((uintptr_t *)__attr) = (uintptr_t) realattr;
 
     return pthread_getattr_np(thid, realattr);
 }
@@ -360,11 +565,13 @@ static int my_pthread_getattr_np(pthread
  *
  * */
 
-static int my_pthread_mutex_init(pthread_mutex_t *__mutex,
+static int _hybris_hook_pthread_mutex_init(pthread_mutex_t *__mutex,
                           __const pthread_mutexattr_t *__mutexattr)
 {
     pthread_mutex_t *realmutex = NULL;
 
+    TRACE_HOOK("mutex %p attr %p", __mutex, __mutexattr);
+
     int pshared = 0;
     if (__mutexattr)
         pthread_mutexattr_getpshared(__mutexattr, &pshared);
@@ -373,7 +580,7 @@ static int my_pthread_mutex_init(pthread
         /* non shared, standard mutex: use malloc */
         realmutex = malloc(sizeof(pthread_mutex_t));
 
-        *((unsigned int *)__mutex) = (unsigned int) realmutex;
+        *((uintptr_t *)__mutex) = (uintptr_t) realmutex;
     }
     else {
         /* process-shared mutex: use the shared memory segment */
@@ -388,14 +595,16 @@ static int my_pthread_mutex_init(pthread
     return pthread_mutex_init(realmutex, __mutexattr);
 }
 
-static int my_pthread_mutex_destroy(pthread_mutex_t *__mutex)
+static int _hybris_hook_pthread_mutex_destroy(pthread_mutex_t *__mutex)
 {
     int ret;
 
+    TRACE_HOOK("mutex %p", __mutex);
+
     if (!__mutex)
         return EINVAL;
 
-    pthread_mutex_t *realmutex = (pthread_mutex_t *) *(unsigned int *) __mutex;
+    pthread_mutex_t *realmutex = (pthread_mutex_t *) *(uintptr_t *) __mutex;
 
     if (!realmutex)
         return EINVAL;
@@ -409,19 +618,21 @@ static int my_pthread_mutex_destroy(pthr
         ret = pthread_mutex_destroy(realmutex);
     }
 
-    *((unsigned int *)__mutex) = 0;
+    *((uintptr_t *)__mutex) = 0;
 
     return ret;
 }
 
-static int my_pthread_mutex_lock(pthread_mutex_t *__mutex)
+static int _hybris_hook_pthread_mutex_lock(pthread_mutex_t *__mutex)
 {
+    TRACE_HOOK("mutex %p", __mutex);
+
     if (!__mutex) {
         LOGD("Null mutex lock, not locking.");
         return 0;
     }
 
-    unsigned int value = (*(unsigned int *) __mutex);
+    uintptr_t value = (*(uintptr_t *) __mutex);
     if (hybris_check_android_shared_mutex(value)) {
         LOGD("Shared mutex with Android, not locking.");
         return 0;
@@ -432,16 +643,20 @@ static int my_pthread_mutex_lock(pthread
         realmutex = (pthread_mutex_t *)hybris_get_shmpointer((hybris_shm_pointer_t)value);
 
     if (value <= ANDROID_TOP_ADDR_VALUE_MUTEX) {
+        TRACE("value %p <= ANDROID_TOP_ADDR_VALUE_MUTEX 0x%x",
+              (void*) value, ANDROID_TOP_ADDR_VALUE_MUTEX);
         realmutex = hybris_alloc_init_mutex(value);
-        *((unsigned int *)__mutex) = (unsigned int) realmutex;
+        *((uintptr_t *)__mutex) = (uintptr_t) realmutex;
     }
 
     return pthread_mutex_lock(realmutex);
 }
 
-static int my_pthread_mutex_trylock(pthread_mutex_t *__mutex)
+static int _hybris_hook_pthread_mutex_trylock(pthread_mutex_t *__mutex)
 {
-    unsigned int value = (*(unsigned int *) __mutex);
+    uintptr_t value = (*(uintptr_t *) __mutex);
+
+    TRACE_HOOK("mutex %p", __mutex);
 
     if (hybris_check_android_shared_mutex(value)) {
         LOGD("Shared mutex with Android, not try locking.");
@@ -454,20 +669,22 @@ static int my_pthread_mutex_trylock(pthr
 
     if (value <= ANDROID_TOP_ADDR_VALUE_MUTEX) {
         realmutex = hybris_alloc_init_mutex(value);
-        *((unsigned int *)__mutex) = (unsigned int) realmutex;
+        *((uintptr_t *)__mutex) = (uintptr_t) realmutex;
     }
 
     return pthread_mutex_trylock(realmutex);
 }
 
-static int my_pthread_mutex_unlock(pthread_mutex_t *__mutex)
+static int _hybris_hook_pthread_mutex_unlock(pthread_mutex_t *__mutex)
 {
+    TRACE_HOOK("mutex %p", __mutex);
+
     if (!__mutex) {
         LOGD("Null mutex lock, not unlocking.");
         return 0;
     }
 
-    unsigned int value = (*(unsigned int *) __mutex);
+    uintptr_t value = (*(uintptr_t *) __mutex);
     if (hybris_check_android_shared_mutex(value)) {
         LOGD("Shared mutex with Android, not unlocking.");
         return 0;
@@ -486,11 +703,13 @@ static int my_pthread_mutex_unlock(pthre
     return pthread_mutex_unlock(realmutex);
 }
 
-static int my_pthread_mutex_lock_timeout_np(pthread_mutex_t *__mutex, unsigned __msecs)
+static int _hybris_hook_pthread_mutex_lock_timeout_np(pthread_mutex_t *__mutex, unsigned __msecs)
 {
     struct timespec tv;
     pthread_mutex_t *realmutex;
-    unsigned int value = (*(unsigned int *) __mutex);
+    uintptr_t value = (*(uintptr_t *) __mutex);
+
+    TRACE_HOOK("mutex %p msecs %u", __mutex, __msecs);
 
     if (hybris_check_android_shared_mutex(value)) {
         LOGD("Shared mutex with Android, not lock timeout np.");
@@ -501,7 +720,7 @@ static int my_pthread_mutex_lock_timeout
 
     if (value <= ANDROID_TOP_ADDR_VALUE_MUTEX) {
         realmutex = hybris_alloc_init_mutex(value);
-        *((int *)__mutex) = (int) realmutex;
+        *((uintptr_t *)__mutex) = (uintptr_t) realmutex;
     }
 
     clock_gettime(CLOCK_REALTIME, &tv);
@@ -515,9 +734,36 @@ static int my_pthread_mutex_lock_timeout
     return pthread_mutex_timedlock(realmutex, &tv);
 }
 
-static int my_pthread_mutexattr_setpshared(pthread_mutexattr_t *__attr,
+static int _hybris_hook_pthread_mutex_timedlock(pthread_mutex_t *__mutex,
+                                      const struct timespec *__abs_timeout)
+{
+    TRACE_HOOK("mutex %p abs timeout %p", __mutex, __abs_timeout);
+
+    if (!__mutex) {
+        LOGD("Null mutex lock, not unlocking.");
+        return 0;
+    }
+
+    uintptr_t value = (*(uintptr_t *) __mutex);
+    if (hybris_check_android_shared_mutex(value)) {
+        LOGD("Shared mutex with Android, not lock timeout np.");
+        return 0;
+    }
+
+    pthread_mutex_t *realmutex = (pthread_mutex_t *) value;
+    if (value <= ANDROID_TOP_ADDR_VALUE_MUTEX) {
+        realmutex = hybris_alloc_init_mutex(value);
+        *((uintptr_t *)__mutex) = (uintptr_t) realmutex;
+    }
+
+    return pthread_mutex_timedlock(realmutex, __abs_timeout);
+}
+
+static int _hybris_hook_pthread_mutexattr_setpshared(pthread_mutexattr_t *__attr,
                                            int pshared)
 {
+    TRACE_HOOK("attr %p pshared %d", __attr, pshared);
+
     return pthread_mutexattr_setpshared(__attr, pshared);
 }
 
@@ -529,11 +775,13 @@ static int my_pthread_mutexattr_setpshar
  *
  * */
 
-static int my_pthread_cond_init(pthread_cond_t *cond,
+static int _hybris_hook_pthread_cond_init(pthread_cond_t *cond,
                                 const pthread_condattr_t *attr)
 {
     pthread_cond_t *realcond = NULL;
 
+    TRACE_HOOK("cond %p attr %p", cond, attr);
+
     int pshared = 0;
 
     if (attr)
@@ -543,13 +791,13 @@ static int my_pthread_cond_init(pthread_
         /* non shared, standard cond: use malloc */
         realcond = malloc(sizeof(pthread_cond_t));
 
-        *((unsigned int *) cond) = (unsigned int) realcond;
+        *((uintptr_t *) cond) = (uintptr_t) realcond;
     }
     else {
         /* process-shared condition: use the shared memory segment */
         hybris_shm_pointer_t handle = hybris_shm_alloc(sizeof(pthread_cond_t));
 
-        *((unsigned int *)cond) = (unsigned int) handle;
+        *((uintptr_t *)cond) = (uintptr_t) handle;
 
         if (handle)
             realcond = (pthread_cond_t *)hybris_get_shmpointer(handle);
@@ -558,10 +806,12 @@ static int my_pthread_cond_init(pthread_
     return pthread_cond_init(realcond, attr);
 }
 
-static int my_pthread_cond_destroy(pthread_cond_t *cond)
+static int _hybris_hook_pthread_cond_destroy(pthread_cond_t *cond)
 {
     int ret;
-    pthread_cond_t *realcond = (pthread_cond_t *) *(unsigned int *) cond;
+    pthread_cond_t *realcond = (pthread_cond_t *) *(uintptr_t *) cond;
+
+    TRACE_HOOK("cond %p", cond);
 
     if (!realcond) {
       return EINVAL;
@@ -576,17 +826,20 @@ static int my_pthread_cond_destroy(pthre
         ret = pthread_cond_destroy(realcond);
     }
 
-    *((unsigned int *)cond) = 0;
+    *((uintptr_t *)cond) = 0;
 
     return ret;
 }
 
-static int my_pthread_cond_broadcast(pthread_cond_t *cond)
+static int _hybris_hook_pthread_cond_broadcast(pthread_cond_t *cond)
 {
-    unsigned int value = (*(unsigned int *) cond);
+    uintptr_t value = (*(uintptr_t *) cond);
+
+    TRACE_HOOK("cond %p", cond);
+
     if (hybris_check_android_shared_cond(value)) {
-        LOGD("shared condition with Android, not broadcasting.");
-        return 0;
+        LOGD("Shared condition with Android, broadcasting with futex.");
+        return android_pthread_cond_broadcast((android_cond_t *) cond);
     }
 
     pthread_cond_t *realcond = (pthread_cond_t *) value;
@@ -595,19 +848,21 @@ static int my_pthread_cond_broadcast(pth
 
     if (value <= ANDROID_TOP_ADDR_VALUE_COND) {
         realcond = hybris_alloc_init_cond();
-        *((unsigned int *) cond) = (unsigned int) realcond;
+        *((uintptr_t *) cond) = (uintptr_t) realcond;
     }
 
     return pthread_cond_broadcast(realcond);
 }
 
-static int my_pthread_cond_signal(pthread_cond_t *cond)
+static int _hybris_hook_pthread_cond_signal(pthread_cond_t *cond)
 {
-    unsigned int value = (*(unsigned int *) cond);
+    uintptr_t value = (*(uintptr_t *) cond);
+
+    TRACE_HOOK("cond %p", cond);
 
     if (hybris_check_android_shared_cond(value)) {
-        LOGD("Shared condition with Android, not signaling.");
-        return 0;
+        LOGD("Shared condition with Android, broadcasting with futex.");
+        return android_pthread_cond_signal((android_cond_t *) cond);
     }
 
     pthread_cond_t *realcond = (pthread_cond_t *) value;
@@ -616,17 +871,19 @@ static int my_pthread_cond_signal(pthrea
 
     if (value <= ANDROID_TOP_ADDR_VALUE_COND) {
         realcond = hybris_alloc_init_cond();
-        *((unsigned int *) cond) = (unsigned int) realcond;
+        *((uintptr_t *) cond) = (uintptr_t) realcond;
     }
 
     return pthread_cond_signal(realcond);
 }
 
-static int my_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+static int _hybris_hook_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
 {
     /* Both cond and mutex can be statically initialized, check for both */
-    unsigned int cvalue = (*(unsigned int *) cond);
-    unsigned int mvalue = (*(unsigned int *) mutex);
+    uintptr_t cvalue = (*(uintptr_t *) cond);
+    uintptr_t mvalue = (*(uintptr_t *) mutex);
+
+    TRACE_HOOK("cond %p mutex %p", cond, mutex);
 
     if (hybris_check_android_shared_cond(cvalue) ||
         hybris_check_android_shared_mutex(mvalue)) {
@@ -640,7 +897,7 @@ static int my_pthread_cond_wait(pthread_
 
     if (cvalue <= ANDROID_TOP_ADDR_VALUE_COND) {
         realcond = hybris_alloc_init_cond();
-        *((unsigned int *) cond) = (unsigned int) realcond;
+        *((uintptr_t *) cond) = (uintptr_t) realcond;
     }
 
     pthread_mutex_t *realmutex = (pthread_mutex_t *) mvalue;
@@ -649,18 +906,20 @@ static int my_pthread_cond_wait(pthread_
 
     if (mvalue <= ANDROID_TOP_ADDR_VALUE_MUTEX) {
         realmutex = hybris_alloc_init_mutex(mvalue);
-        *((unsigned int *) mutex) = (unsigned int) realmutex;
+        *((uintptr_t *) mutex) = (uintptr_t) realmutex;
     }
 
     return pthread_cond_wait(realcond, realmutex);
 }
 
-static int my_pthread_cond_timedwait(pthread_cond_t *cond,
+static int _hybris_hook_pthread_cond_timedwait(pthread_cond_t *cond,
                 pthread_mutex_t *mutex, const struct timespec *abstime)
 {
     /* Both cond and mutex can be statically initialized, check for both */
-    unsigned int cvalue = (*(unsigned int *) cond);
-    unsigned int mvalue = (*(unsigned int *) mutex);
+    uintptr_t cvalue = (*(uintptr_t *) cond);
+    uintptr_t mvalue = (*(uintptr_t *) mutex);
+
+    TRACE_HOOK("cond %p mutex %p abstime %p", cond, mutex, abstime);
 
     if (hybris_check_android_shared_cond(cvalue) ||
          hybris_check_android_shared_mutex(mvalue)) {
@@ -674,7 +933,7 @@ static int my_pthread_cond_timedwait(pth
 
     if (cvalue <= ANDROID_TOP_ADDR_VALUE_COND) {
         realcond = hybris_alloc_init_cond();
-        *((unsigned int *) cond) = (unsigned int) realcond;
+        *((uintptr_t *) cond) = (uintptr_t) realcond;
     }
 
     pthread_mutex_t *realmutex = (pthread_mutex_t *) mvalue;
@@ -683,18 +942,20 @@ static int my_pthread_cond_timedwait(pth
 
     if (mvalue <= ANDROID_TOP_ADDR_VALUE_MUTEX) {
         realmutex = hybris_alloc_init_mutex(mvalue);
-        *((unsigned int *) mutex) = (unsigned int) realmutex;
+        *((uintptr_t *) mutex) = (uintptr_t) realmutex;
     }
 
     return pthread_cond_timedwait(realcond, realmutex, abstime);
 }
 
-static int my_pthread_cond_timedwait_relative_np(pthread_cond_t *cond,
+static int _hybris_hook_pthread_cond_timedwait_relative_np(pthread_cond_t *cond,
                 pthread_mutex_t *mutex, const struct timespec *reltime)
 {
     /* Both cond and mutex can be statically initialized, check for both */
-    unsigned int cvalue = (*(unsigned int *) cond);
-    unsigned int mvalue = (*(unsigned int *) mutex);
+    uintptr_t cvalue = (*(uintptr_t *) cond);
+    uintptr_t mvalue = (*(uintptr_t *) mutex);
+
+    TRACE_HOOK("cond %p mutex %p reltime %p", cond, mutex, reltime);
 
     if (hybris_check_android_shared_cond(cvalue) ||
          hybris_check_android_shared_mutex(mvalue)) {
@@ -708,7 +969,7 @@ static int my_pthread_cond_timedwait_rel
 
     if (cvalue <= ANDROID_TOP_ADDR_VALUE_COND) {
         realcond = hybris_alloc_init_cond();
-        *((unsigned int *) cond) = (unsigned int) realcond;
+        *((uintptr_t *) cond) = (uintptr_t) realcond;
     }
 
     pthread_mutex_t *realmutex = (pthread_mutex_t *) mvalue;
@@ -717,7 +978,7 @@ static int my_pthread_cond_timedwait_rel
 
     if (mvalue <= ANDROID_TOP_ADDR_VALUE_MUTEX) {
         realmutex = hybris_alloc_init_mutex(mvalue);
-        *((unsigned int *) mutex) = (unsigned int) realmutex;
+        *((uintptr_t *) mutex) = (uintptr_t) realmutex;
     }
 
     struct timespec tv;
@@ -731,6 +992,30 @@ static int my_pthread_cond_timedwait_rel
     return pthread_cond_timedwait(realcond, realmutex, &tv);
 }
 
+int _hybris_hook_pthread_setname_np(pthread_t thread, const char *name)
+{
+    TRACE_HOOK("thread %llu name %s", (unsigned long long) thread, name);
+
+#ifdef MALI_QUIRKS
+    if (strcmp(name, MALI_HIST_DUMP_THREAD_NAME) == 0) {
+        HYBRIS_DEBUG_LOG(HOOKS, "%s: Found mali-hist-dump thread, killing it ...",
+                         __FUNCTION__);
+
+        if (thread != pthread_self()) {
+            HYBRIS_DEBUG_LOG(HOOKS, "%s: -> Failed, as calling thread is not mali-hist-dump itself",
+                             __FUNCTION__);
+            return 0;
+        }
+
+        pthread_exit((void*) thread);
+
+        return 0;
+    }
+#endif
+
+    return pthread_setname_np(thread, name);
+}
+
 /*
  * pthread_rwlockattr_* functions
  *
@@ -739,20 +1024,24 @@ static int my_pthread_cond_timedwait_rel
  *
  * */
 
-static int my_pthread_rwlockattr_init(pthread_rwlockattr_t *__attr)
+static int _hybris_hook_pthread_rwlockattr_init(pthread_rwlockattr_t *__attr)
 {
     pthread_rwlockattr_t *realattr;
 
+    TRACE_HOOK("attr %p", __attr);
+
     realattr = malloc(sizeof(pthread_rwlockattr_t));
-    *((unsigned int *)__attr) = (unsigned int) realattr;
+    *((uintptr_t *)__attr) = (uintptr_t) realattr;
 
     return pthread_rwlockattr_init(realattr);
 }
 
-static int my_pthread_rwlockattr_destroy(pthread_rwlockattr_t *__attr)
+static int _hybris_hook_pthread_rwlockattr_destroy(pthread_rwlockattr_t *__attr)
 {
     int ret;
-    pthread_rwlockattr_t *realattr = (pthread_rwlockattr_t *) *(unsigned int *) __attr;
+    pthread_rwlockattr_t *realattr = (pthread_rwlockattr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p", __attr);
 
     ret = pthread_rwlockattr_destroy(realattr);
     free(realattr);
@@ -760,20 +1049,44 @@ static int my_pthread_rwlockattr_destroy
     return ret;
 }
 
-static int my_pthread_rwlockattr_setpshared(pthread_rwlockattr_t *__attr,
+static int _hybris_hook_pthread_rwlockattr_setpshared(pthread_rwlockattr_t *__attr,
                                             int pshared)
 {
-    pthread_rwlockattr_t *realattr = (pthread_rwlockattr_t *) *(unsigned int *) __attr;
+    pthread_rwlockattr_t *realattr = (pthread_rwlockattr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p pshared %d", __attr, pshared);
+
     return pthread_rwlockattr_setpshared(realattr, pshared);
 }
 
-static int my_pthread_rwlockattr_getpshared(pthread_rwlockattr_t *__attr,
+static int _hybris_hook_pthread_rwlockattr_getpshared(pthread_rwlockattr_t *__attr,
                                             int *pshared)
 {
-    pthread_rwlockattr_t *realattr = (pthread_rwlockattr_t *) *(unsigned int *) __attr;
+    pthread_rwlockattr_t *realattr = (pthread_rwlockattr_t *) *(uintptr_t *) __attr;
+
+    TRACE_HOOK("attr %p pshared %p", __attr, pshared);
+
     return pthread_rwlockattr_getpshared(realattr, pshared);
 }
 
+int _hybris_hook_pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref)
+{
+    pthread_rwlockattr_t *realattr = (pthread_rwlockattr_t *) *(uintptr_t *) attr;
+
+    TRACE_HOOK("attr %p pref %i", attr, pref);
+
+    return pthread_rwlockattr_setkind_np(realattr, pref);
+}
+
+int _hybris_hook_pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t *attr, int *pref)
+{
+    pthread_rwlockattr_t *realattr = (pthread_rwlockattr_t *) *(uintptr_t *) attr;
+
+    TRACE_HOOK("attr %p pref %p", attr, pref);
+
+    return pthread_rwlockattr_getkind_np(realattr, pref);
+}
+
 /*
  * pthread_rwlock_* functions
  *
@@ -782,15 +1095,17 @@ static int my_pthread_rwlockattr_getpsha
  *
  * */
 
-static int my_pthread_rwlock_init(pthread_rwlock_t *__rwlock,
+static int _hybris_hook_pthread_rwlock_init(pthread_rwlock_t *__rwlock,
                                   __const pthread_rwlockattr_t *__attr)
 {
     pthread_rwlock_t *realrwlock = NULL;
     pthread_rwlockattr_t *realattr = NULL;
     int pshared = 0;
 
+    TRACE_HOOK("rwlock %p attr %p", __rwlock, __attr);
+
     if (__attr != NULL)
-        realattr = (pthread_rwlockattr_t *) *(unsigned int *) __attr;
+        realattr = (pthread_rwlockattr_t *) *(uintptr_t *) __attr;
 
     if (realattr)
         pthread_rwlockattr_getpshared(realattr, &pshared);
@@ -799,13 +1114,13 @@ static int my_pthread_rwlock_init(pthrea
         /* non shared, standard rwlock: use malloc */
         realrwlock = malloc(sizeof(pthread_rwlock_t));
 
-        *((unsigned int *) __rwlock) = (unsigned int) realrwlock;
+        *((uintptr_t *) __rwlock) = (uintptr_t) realrwlock;
     }
     else {
         /* process-shared condition: use the shared memory segment */
         hybris_shm_pointer_t handle = hybris_shm_alloc(sizeof(pthread_rwlock_t));
 
-        *((unsigned int *)__rwlock) = (unsigned int) handle;
+        *((uintptr_t *)__rwlock) = (uintptr_t) handle;
 
         if (handle)
             realrwlock = (pthread_rwlock_t *)hybris_get_shmpointer(handle);
@@ -814,10 +1129,12 @@ static int my_pthread_rwlock_init(pthrea
     return pthread_rwlock_init(realrwlock, realattr);
 }
 
-static int my_pthread_rwlock_destroy(pthread_rwlock_t *__rwlock)
+static int _hybris_hook_pthread_rwlock_destroy(pthread_rwlock_t *__rwlock)
 {
     int ret;
-    pthread_rwlock_t *realrwlock = (pthread_rwlock_t *) *(unsigned int *) __rwlock;
+    pthread_rwlock_t *realrwlock = (pthread_rwlock_t *) *(uintptr_t *) __rwlock;
+
+    TRACE_HOOK("rwlock %p", __rwlock);
 
     if (!hybris_is_pointer_in_shm((void*)realrwlock)) {
         ret = pthread_rwlock_destroy(realrwlock);
@@ -833,64 +1150,87 @@ static int my_pthread_rwlock_destroy(pth
 
 static pthread_rwlock_t* hybris_set_realrwlock(pthread_rwlock_t *rwlock)
 {
-    unsigned int value = (*(unsigned int *) rwlock);
+    uintptr_t value = (*(uintptr_t *) rwlock);
     pthread_rwlock_t *realrwlock = (pthread_rwlock_t *) value;
+
     if (hybris_is_pointer_in_shm((void*)value))
         realrwlock = (pthread_rwlock_t *)hybris_get_shmpointer((hybris_shm_pointer_t)value);
 
-    if (realrwlock <= ANDROID_TOP_ADDR_VALUE_RWLOCK) {
+    if ((uintptr_t)realrwlock <= ANDROID_TOP_ADDR_VALUE_RWLOCK) {
         realrwlock = hybris_alloc_init_rwlock();
-        *((unsigned int *)rwlock) = (unsigned int) realrwlock;
+        *((uintptr_t *)rwlock) = (uintptr_t) realrwlock;
     }
     return realrwlock;
 }
 
-static int my_pthread_rwlock_rdlock(pthread_rwlock_t *__rwlock)
+static int _hybris_hook_pthread_rwlock_rdlock(pthread_rwlock_t *__rwlock)
 {
+    TRACE_HOOK("rwlock %p", __rwlock);
+
     pthread_rwlock_t *realrwlock = hybris_set_realrwlock(__rwlock);
+
     return pthread_rwlock_rdlock(realrwlock);
 }
 
-static int my_pthread_rwlock_tryrdlock(pthread_rwlock_t *__rwlock)
+static int _hybris_hook_pthread_rwlock_tryrdlock(pthread_rwlock_t *__rwlock)
 {
+    TRACE_HOOK("rwlock %p", __rwlock);
+
     pthread_rwlock_t *realrwlock = hybris_set_realrwlock(__rwlock);
+
     return pthread_rwlock_tryrdlock(realrwlock);
 }
 
-static int my_pthread_rwlock_timedrdlock(pthread_rwlock_t *__rwlock,
+static int _hybris_hook_pthread_rwlock_timedrdlock(pthread_rwlock_t *__rwlock,
                                          __const struct timespec *abs_timeout)
 {
+    TRACE_HOOK("rwlock %p abs timeout %p", __rwlock, abs_timeout);
+
     pthread_rwlock_t *realrwlock = hybris_set_realrwlock(__rwlock);
+
     return pthread_rwlock_timedrdlock(realrwlock, abs_timeout);
 }
 
-static int my_pthread_rwlock_wrlock(pthread_rwlock_t *__rwlock)
+static int _hybris_hook_pthread_rwlock_wrlock(pthread_rwlock_t *__rwlock)
 {
+    TRACE_HOOK("rwlock %p", __rwlock);
+
     pthread_rwlock_t *realrwlock = hybris_set_realrwlock(__rwlock);
+
     return pthread_rwlock_wrlock(realrwlock);
 }
 
-static int my_pthread_rwlock_trywrlock(pthread_rwlock_t *__rwlock)
+static int _hybris_hook_pthread_rwlock_trywrlock(pthread_rwlock_t *__rwlock)
 {
+    TRACE_HOOK("rwlock %p", __rwlock);
+
     pthread_rwlock_t *realrwlock = hybris_set_realrwlock(__rwlock);
+
     return pthread_rwlock_trywrlock(realrwlock);
 }
 
-static int my_pthread_rwlock_timedwrlock(pthread_rwlock_t *__rwlock,
+static int _hybris_hook_pthread_rwlock_timedwrlock(pthread_rwlock_t *__rwlock,
                                          __const struct timespec *abs_timeout)
 {
+    TRACE_HOOK("rwlock %p abs timeout %p", __rwlock, abs_timeout);
+
     pthread_rwlock_t *realrwlock = hybris_set_realrwlock(__rwlock);
+
     return pthread_rwlock_timedwrlock(realrwlock, abs_timeout);
 }
 
-static int my_pthread_rwlock_unlock(pthread_rwlock_t *__rwlock)
+static int _hybris_hook_pthread_rwlock_unlock(pthread_rwlock_t *__rwlock)
 {
-    unsigned int value = (*(unsigned int *) __rwlock);
+    uintptr_t value = (*(uintptr_t *) __rwlock);
+
+    TRACE_HOOK("rwlock %p", __rwlock);
+
     if (value <= ANDROID_TOP_ADDR_VALUE_RWLOCK) {
         LOGD("Trying to unlock a rwlock that's not locked/initialized"
                " by Hybris, not unlocking.");
         return 0;
     }
+
     pthread_rwlock_t *realrwlock = (pthread_rwlock_t *) value;
     if (hybris_is_pointer_in_shm((void*)value))
         realrwlock = (pthread_rwlock_t *)hybris_get_shmpointer((hybris_shm_pointer_t)value);
@@ -898,10 +1238,27 @@ static int my_pthread_rwlock_unlock(pthr
     return pthread_rwlock_unlock(realrwlock);
 }
 
+#define min(X,Y) (((X) < (Y)) ? (X) : (Y))
+
+static pid_t _hybris_hook_pthread_gettid(pthread_t t)
+{
+    TRACE_HOOK("thread %lu", (unsigned long) t);
+
+    // glibc doesn't offer us a way to retrieve the thread id for a
+    // specific thread. However pthread_t is defined as unsigned
+    // long int and is the thread id so we can just copy it over
+    // into a pid_t.
+    pid_t tid;
+    memcpy(&tid, &t, min(sizeof(tid), sizeof(t)));
+    return tid;
+}
 
-static int my_set_errno(int oi_errno)
+static int _hybris_hook_set_errno(int oi_errno)
 {
+    TRACE_HOOK("errno %d", oi_errno);
+
     errno = oi_errno;
+
     return -1;
 }
 
@@ -916,7 +1273,60 @@ static int my_set_errno(int oi_errno)
  * instead of calling one of the hooked methods.
  * Therefore we need to set __isthreaded to true, even if we are not in a multi-threaded context.
  */
-static int __my_isthreaded = 1;
+static int ___hybris_hook_isthreaded = 1;
+
+/* "struct __sbuf" from bionic/libc/include/stdio.h */
+#if defined(__LP64__)
+struct bionic_sbuf {
+    unsigned char* _base;
+    size_t _size;
+};
+#else
+struct bionic_sbuf {
+    unsigned char *_base;
+    int _size;
+};
+#endif
+
+/* "struct __sFILE" from bionic/libc/include/stdio.h */
+struct __attribute__((packed)) bionic_file {
+    unsigned char *_p;      /* current position in (some) buffer */
+    int _r;                 /* read space left for getc() */
+    int _w;                 /* write space left for putc() */
+#if defined(__LP64__)
+    int _flags;             /* flags, below; this FILE is free if 0 */
+    int _file;              /* fileno, if Unix descriptor, else -1 */
+#else
+    short _flags;           /* flags, below; this FILE is free if 0 */
+    short _file;            /* fileno, if Unix descriptor, else -1 */
+#endif
+    struct bionic_sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */
+    int _lbfsize;           /* 0 or -_bf._size, for inline putc */
+
+    /* operations */
+    void *_cookie;          /* cookie passed to io functions */
+    int (*_close)(void *);
+    int (*_read)(void *, char *, int);
+    fpos_t (*_seek)(void *, fpos_t, int);
+    int (*_write)(void *, const char *, int);
+
+    /* extension data, to avoid further ABI breakage */
+    struct bionic_sbuf _ext;
+    /* data for long sequences of ungetc() */
+    unsigned char *_up;     /* saved _p when _p is doing ungetc data */
+    int _ur;                /* saved _r when _r is counting ungetc data */
+
+    /* tricks to meet minimum requirements even when malloc() fails */
+    unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */
+    unsigned char _nbuf[1]; /* guarantee a getc() buffer */
+
+    /* separate buffer for fgetln() when line crosses buffer boundary */
+    struct bionic_sbuf _lb; /* buffer for fgetln() */
+
+    /* Unix stdio files get aligned to block boundaries on fseek() */
+    int _blksize;           /* stat.st_blksize (may be != _bf._size) */
+    fpos_t _offset;         /* current lseek offset */
+};
 
 /*
  * redirection for bionic's __sF, which is defined as:
@@ -929,65 +1339,82 @@ static int __my_isthreaded = 1;
  *   pointer.
  *   Currently, only fputs is managed.
  */
-#define BIONIC_SIZEOF_FILE 84
-static char my_sF[3*BIONIC_SIZEOF_FILE] = {0};
+static char _hybris_hook_sF[3 * sizeof(struct bionic_file)] = {0};
 static FILE *_get_actual_fp(FILE *fp)
 {
     char *c_fp = (char*)fp;
-    if (c_fp == &my_sF[0])
+    if (c_fp == &_hybris_hook_sF[0])
         return stdin;
-    else if (c_fp == &my_sF[BIONIC_SIZEOF_FILE])
+    else if (c_fp == &_hybris_hook_sF[sizeof(struct bionic_file)])
         return stdout;
-    else if (c_fp == &my_sF[BIONIC_SIZEOF_FILE*2])
+    else if (c_fp == &_hybris_hook_sF[sizeof(struct bionic_file) * 2])
         return stderr;
 
     return fp;
 }
 
-static void my_clearerr(FILE *fp)
+static void _hybris_hook_clearerr(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     clearerr(_get_actual_fp(fp));
 }
 
-static int my_fclose(FILE *fp)
+static int _hybris_hook_fclose(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return fclose(_get_actual_fp(fp));
 }
 
-static int my_feof(FILE *fp)
+static int _hybris_hook_feof(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return feof(_get_actual_fp(fp));
 }
 
-static int my_ferror(FILE *fp)
+static int _hybris_hook_ferror(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return ferror(_get_actual_fp(fp));
 }
 
-static int my_fflush(FILE *fp)
+static int _hybris_hook_fflush(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return fflush(_get_actual_fp(fp));
 }
 
-static int my_fgetc(FILE *fp)
+static int _hybris_hook_fgetc(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return fgetc(_get_actual_fp(fp));
 }
 
-static int my_fgetpos(FILE *fp, fpos_t *pos)
+static int _hybris_hook_fgetpos(FILE *fp, fpos_t *pos)
 {
+    TRACE_HOOK("fp %p pos %p", fp, pos);
+
     return fgetpos(_get_actual_fp(fp), pos);
 }
 
-static char* my_fgets(char *s, int n, FILE *fp)
+static char* _hybris_hook_fgets(char *s, int n, FILE *fp)
 {
+    TRACE_HOOK("s %s n %d fp %p", s, n, fp);
+
     return fgets(s, n, _get_actual_fp(fp));
 }
 
-FP_ATTRIB static int my_fprintf(FILE *fp, const char *fmt, ...)
+FP_ATTRIB static int _hybris_hook_fprintf(FILE *fp, const char *fmt, ...)
 {
     int ret = 0;
 
+    TRACE_HOOK("fp %p fmt '%s'", fp, fmt);
+
     va_list args;
     va_start(args,fmt);
     ret = vfprintf(_get_actual_fp(fp), fmt, args);
@@ -996,30 +1423,40 @@ FP_ATTRIB static int my_fprintf(FILE *fp
     return ret;
 }
 
-static int my_fputc(int c, FILE *fp)
+static int _hybris_hook_fputc(int c, FILE *fp)
 {
+    TRACE_HOOK("c %d fp %p", c, fp);
+
     return fputc(c, _get_actual_fp(fp));
 }
 
-static int my_fputs(const char *s, FILE *fp)
+static int _hybris_hook_fputs(const char *s, FILE *fp)
 {
+    TRACE_HOOK("s '%s' fp %p", s, fp);
+
     return fputs(s, _get_actual_fp(fp));
 }
 
-static size_t my_fread(void *ptr, size_t size, size_t nmemb, FILE *fp)
+static size_t _hybris_hook_fread(void *ptr, size_t size, size_t nmemb, FILE *fp)
 {
+    TRACE_HOOK("ptr %p size %zu nmemb %zu fp %p", ptr, size, nmemb, fp);
+
     return fread(ptr, size, nmemb, _get_actual_fp(fp));
 }
 
-static FILE* my_freopen(const char *filename, const char *mode, FILE *fp)
+static FILE* _hybris_hook_freopen(const char *filename, const char *mode, FILE *fp)
 {
+    TRACE_HOOK("filename '%s' mode '%s' fp %p", filename, mode, fp);
+
     return freopen(filename, mode, _get_actual_fp(fp));
 }
 
-FP_ATTRIB static int my_fscanf(FILE *fp, const char *fmt, ...)
+FP_ATTRIB static int _hybris_hook_fscanf(FILE *fp, const char *fmt, ...)
 {
     int ret = 0;
 
+    TRACE_HOOK("fp %p fmt '%s'", fp, fmt);
+
     va_list args;
     va_start(args,fmt);
     ret = vfscanf(_get_actual_fp(fp), fmt, args);
@@ -1028,155 +1465,208 @@ FP_ATTRIB static int my_fscanf(FILE *fp,
     return ret;
 }
 
-static int my_fseek(FILE *fp, long offset, int whence)
+static int _hybris_hook_fseek(FILE *fp, long offset, int whence)
 {
+    TRACE_HOOK("fp %p offset %jd whence %d", fp, offset, whence);
+
     return fseek(_get_actual_fp(fp), offset, whence);
 }
 
-static int my_fseeko(FILE *fp, off_t offset, int whence)
+static int _hybris_hook_fseeko(FILE *fp, off_t offset, int whence)
 {
+    TRACE_HOOK("fp %p offset %jd whence %d", fp, offset, whence);
+
     return fseeko(_get_actual_fp(fp), offset, whence);
 }
 
-static int my_fsetpos(FILE *fp, const fpos_t *pos)
+static int _hybris_hook_fsetpos(FILE *fp, const fpos_t *pos)
 {
+    TRACE_HOOK("fp %p pos %p", fp, pos);
+
     return fsetpos(_get_actual_fp(fp), pos);
 }
 
-static long my_ftell(FILE *fp)
+static long _hybris_hook_ftell(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return ftell(_get_actual_fp(fp));
 }
 
-static off_t my_ftello(FILE *fp)
+static off_t _hybris_hook_ftello(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return ftello(_get_actual_fp(fp));
 }
 
-static size_t my_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp)
+static size_t _hybris_hook_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp)
 {
+    TRACE_HOOK("ptr %p size %zu nmemb %zu fp %p", ptr, size, nmemb, fp);
+
     return fwrite(ptr, size, nmemb, _get_actual_fp(fp));
 }
 
-static int my_getc(FILE *fp)
+static int _hybris_hook_getc(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return getc(_get_actual_fp(fp));
 }
 
-static ssize_t my_getdelim(char ** lineptr, size_t *n, int delimiter, FILE * fp)
+static ssize_t _hybris_hook_getdelim(char ** lineptr, size_t *n, int delimiter, FILE * fp)
 {
+    TRACE_HOOK("lineptr %p n %p delimiter %d fp %p", lineptr, n, delimiter, fp);
+
     return getdelim(lineptr, n, delimiter, _get_actual_fp(fp));
 }
 
-static ssize_t my_getline(char **lineptr, size_t *n, FILE *fp)
+static ssize_t _hybris_hook_getline(char **lineptr, size_t *n, FILE *fp)
 {
+    TRACE_HOOK("lineptr %p n %p fp %p", lineptr, n, fp);
+
     return getline(lineptr, n, _get_actual_fp(fp));
 }
 
-
-static int my_putc(int c, FILE *fp)
+static int _hybris_hook_putc(int c, FILE *fp)
 {
+    TRACE_HOOK("c %d fp %p", c, fp);
+
     return putc(c, _get_actual_fp(fp));
 }
 
-static void my_rewind(FILE *fp)
+static void _hybris_hook_rewind(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     rewind(_get_actual_fp(fp));
 }
 
-static void my_setbuf(FILE *fp, char *buf)
+static void _hybris_hook_setbuf(FILE *fp, char *buf)
 {
+    TRACE_HOOK("fp %p buf '%s'", fp, buf);
+
     setbuf(_get_actual_fp(fp), buf);
 }
 
-static int my_setvbuf(FILE *fp, char *buf, int mode, size_t size)
+static int _hybris_hook_setvbuf(FILE *fp, char *buf, int mode, size_t size)
 {
+    TRACE_HOOK("fp %p buf '%s' mode %d size %zu", fp, buf, mode, size);
+
     return setvbuf(_get_actual_fp(fp), buf, mode, size);
 }
 
-static int my_ungetc(int c, FILE *fp)
+static int _hybris_hook_ungetc(int c, FILE *fp)
 {
+    TRACE_HOOK("c %d fp %p", c, fp);
+
     return ungetc(c, _get_actual_fp(fp));
 }
 
-static int my_vfprintf(FILE *fp, const char *fmt, va_list arg)
+static int _hybris_hook_vfprintf(FILE *fp, const char *fmt, va_list arg)
 {
+    TRACE_HOOK("fp %p fmt '%s'", fp, fmt);
+
     return vfprintf(_get_actual_fp(fp), fmt, arg);
 }
 
-
-static int my_vfscanf(FILE *fp, const char *fmt, va_list arg)
+static int _hybris_hook_vfscanf(FILE *fp, const char *fmt, va_list arg)
 {
+    TRACE_HOOK("fp %p fmt '%s'", fp, fmt);
+
     return vfscanf(_get_actual_fp(fp), fmt, arg);
 }
 
-static int my_fileno(FILE *fp)
+static int _hybris_hook_fileno(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return fileno(_get_actual_fp(fp));
 }
 
-
-static int my_pclose(FILE *fp)
+static int _hybris_hook_pclose(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return pclose(_get_actual_fp(fp));
 }
 
-static void my_flockfile(FILE *fp)
+static void _hybris_hook_flockfile(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return flockfile(_get_actual_fp(fp));
 }
 
-static int my_ftrylockfile(FILE *fp)
+static int _hybris_hook_ftrylockfile(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return ftrylockfile(_get_actual_fp(fp));
 }
 
-static void my_funlockfile(FILE *fp)
+static void _hybris_hook_funlockfile(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return funlockfile(_get_actual_fp(fp));
 }
 
-
-static int my_getc_unlocked(FILE *fp)
+static int _hybris_hook_getc_unlocked(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return getc_unlocked(_get_actual_fp(fp));
 }
 
-static int my_putc_unlocked(int c, FILE *fp)
+static int _hybris_hook_putc_unlocked(int c, FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return putc_unlocked(c, _get_actual_fp(fp));
 }
 
 /* exists only on the BSD platform
-static char* my_fgetln(FILE *fp, size_t *len)
+static char* _hybris_hook_fgetln(FILE *fp, size_t *len)
 {
     return fgetln(_get_actual_fp(fp), len);
 }
 */
-static int my_fpurge(FILE *fp)
+
+static int _hybris_hook_fpurge(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     __fpurge(_get_actual_fp(fp));
 
     return 0;
 }
 
-static int my_getw(FILE *fp)
+static int _hybris_hook_getw(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     return getw(_get_actual_fp(fp));
 }
 
-static int my_putw(int w, FILE *fp)
+static int _hybris_hook_putw(int w, FILE *fp)
 {
+    TRACE_HOOK("w %d fp %p", w, fp);
+
     return putw(w, _get_actual_fp(fp));
 }
 
-static void my_setbuffer(FILE *fp, char *buf, int size)
+static void _hybris_hook_setbuffer(FILE *fp, char *buf, int size)
 {
+    TRACE_HOOK("fp %p buf '%s' size %d", fp, buf, size);
+
     setbuffer(_get_actual_fp(fp), buf, size);
 }
 
-static int my_setlinebuf(FILE *fp)
+static int _hybris_hook_setlinebuf(FILE *fp)
 {
+    TRACE_HOOK("fp %p", fp);
+
     setlinebuf(_get_actual_fp(fp));
 
     return 0;
@@ -1191,7 +1681,7 @@ struct bionic_dirent {
     char             d_name[256];
 };
 
-static struct bionic_dirent *my_readdir(DIR *dirp)
+static struct bionic_dirent *_hybris_hook_readdir(DIR *dirp)
 {
     /**
      * readdir(3) manpage says:
@@ -1207,6 +1697,8 @@ static struct bionic_dirent *my_readdir(
 
     static struct bionic_dirent result;
 
+    TRACE_HOOK("dirp %p", dirp);
+
     struct dirent *real_result = readdir(dirp);
     if (!real_result) {
         return NULL;
@@ -1225,12 +1717,14 @@ static struct bionic_dirent *my_readdir(
     return &result;
 }
 
-static int my_readdir_r(DIR *dir, struct bionic_dirent *entry,
+static int _hybris_hook_readdir_r(DIR *dir, struct bionic_dirent *entry,
         struct bionic_dirent **result)
 {
     struct dirent entry_r;
     struct dirent *result_r;
 
+    TRACE_HOOK("dir %p entry %p result %p", dir, entry, result);
+
     int res = readdir_r(dir, &entry_r, &result_r);
 
     if (res == 0) {
@@ -1255,58 +1749,222 @@ static int my_readdir_r(DIR *dir, struct
     return res;
 }
 
-extern long my_sysconf(int name);
+static int _hybris_hook_alphasort(struct bionic_dirent **a,
+                        struct bionic_dirent **b)
+{
+    return strcoll((*a)->d_name, (*b)->d_name);
+}
+
+static int _hybris_hook_versionsort(struct bionic_dirent **a,
+                          struct bionic_dirent **b)
+{
+    return strverscmp((*a)->d_name, (*b)->d_name);
+}
+
+static int _hybris_hook_scandirat(int parent_fd, const char* dir_name,
+                struct bionic_dirent ***namelist,
+		int (*filter)(const struct bionic_dirent *),
+		int (*compar)(const struct bionic_dirent **, const struct bionic_dirent **))
+{
+    struct dirent **namelist_r;
+    static struct bionic_dirent **result;
+    struct bionic_dirent *filter_r;
+
+    int i = 0;
+    size_t nItems = 0;
+
+    TRACE_HOOK("parent_fd %d, dir_name %s, namelist %p, filter %p, compar %p",
+               parent_fd, dir_name, namelist, filter, compar);
+
+    int res = scandirat(parent_fd, dir_name, &namelist_r, NULL, NULL);
+
+    if (res != 0 && namelist_r != NULL) {
+
+        result = malloc(res * sizeof(struct bionic_dirent));
+        if (!result)
+            return -1;
+
+        for (i = 0; i < res; i++) {
+            filter_r = malloc(sizeof(struct bionic_dirent));
+            if (!filter_r) {
+                while (i-- > 0)
+                        free(result[i]);
+                    free(result);
+                    return -1;
+            }
+            filter_r->d_ino = namelist_r[i]->d_ino;
+            filter_r->d_off = namelist_r[i]->d_off;
+            filter_r->d_reclen = namelist_r[i]->d_reclen;
+            filter_r->d_type = namelist_r[i]->d_type;
+
+            strcpy(filter_r->d_name, namelist_r[i]->d_name);
+            filter_r->d_name[sizeof(namelist_r[i]->d_name) - 1] = '\0';
+
+            if (filter != NULL && !(*filter)(filter_r)) {//apply filter
+                free(filter_r);
+                continue;
+            }
+
+            result[nItems++] = filter_r;
+        }
+        if (nItems && compar != NULL)
+            qsort(result, nItems, sizeof(struct bionic_dirent *), (__compar_fn_t) compar);
+
+        *namelist = result;
+    }
+
+    return res;
+}
+
+static int _hybris_hook_scandir(const char* dir_path, struct bionic_dirent ***namelist,
+		int (*filter)(const struct bionic_dirent *),
+		int (*compar)(const struct bionic_dirent **, const struct bionic_dirent **))
+{
+    return _hybris_hook_scandirat(AT_FDCWD, dir_path, namelist, filter, compar);
+}
 
-FP_ATTRIB static double my_strtod(const char *nptr, char **endptr)
+static inline void swap(void **a, void **b)
 {
-	if (locale_inited == 0)
-	{
-		hybris_locale = newlocale(LC_ALL_MASK, "C", 0);
-		locale_inited = 1;
-	}
-	return strtod_l(nptr, endptr, hybris_locale);
+    void *tmp = *a;
+    *a = *b;
+    *b = tmp;
 }
 
-extern int __cxa_atexit(void (*)(void*), void*, void*);
-extern void __cxa_finalize(void * d);
+static int _hybris_hook_getaddrinfo(const char *hostname, const char *servname,
+    const struct addrinfo *hints, struct addrinfo **res)
+{
+    struct addrinfo *fixed_hints = NULL;
 
-struct open_redirect {
-	const char *from;
-	const char *to;
-};
+    TRACE_HOOK("hostname '%s' servname '%s' hints %p res %p",
+               hostname, servname, hints, res);
 
-struct open_redirect open_redirects[] = {
-	{ "/dev/log/main", "/dev/log_main" },
-	{ "/dev/log/radio", "/dev/log_radio" },
-	{ "/dev/log/system", "/dev/log_system" },
-	{ "/dev/log/events", "/dev/log_events" },
-	{ NULL, NULL }
-};
+    if (hints) {
+        fixed_hints = (struct addrinfo*) malloc(sizeof(struct addrinfo));
+        memcpy(fixed_hints, hints, sizeof(struct addrinfo));
+        // fix bionic -> glibc missmatch
+        swap((void**)&(fixed_hints->ai_canonname), (void**)&(fixed_hints->ai_addr));
+    }
+
+    int result = getaddrinfo(hostname, servname, fixed_hints, res);
+
+    if (fixed_hints)
+        free(fixed_hints);
+
+    // fix bionic <- glibc missmatch
+    struct addrinfo *it = *res;
+    while (it) {
+        swap((void**) &(it->ai_canonname), (void**) &(it->ai_addr));
+        it = it->ai_next;
+    }
+
+    return result;
+}
+
+static void _hybris_hook_freeaddrinfo(struct addrinfo *__ai)
+{
+    TRACE_HOOK("ai %p", __ai);
+
+    if (__ai == NULL)
+        return;
+
+    struct addrinfo *it = __ai;
+    while (it) {
+        swap((void**) &(it->ai_canonname), (void**) &(it->ai_addr));
+        it = it->ai_next;
+    }
+
+    freeaddrinfo(__ai);
+}
+
+extern long _hybris_map_sysconf(int name);
+
+long _hybris_hook_sysconf(int name)
+{
+    TRACE_HOOK("name %d", name);
+
+    return _hybris_map_sysconf(name);
+}
+
+FP_ATTRIB static double _hybris_hook_strtod(const char *nptr, char **endptr)
+{
+    TRACE_HOOK("nptr '%s' endptr %p", nptr, endptr);
+
+    if (locale_inited == 0) {
+            hybris_locale = newlocale(LC_ALL_MASK, "C", 0);
+            locale_inited = 1;
+    }
+
+    return strtod_l(nptr, endptr, hybris_locale);
+}
+
+static long int _hybris_hook_strtol(const char* str, char** endptr, int base)
+{
+    TRACE_HOOK("str '%s' endptr %p base %i", str, endptr, base);
+
+    return strtol(str, endptr, base);
+}
+
+static int ___hybris_hook_system_property_read(const void *pi, char *name, char *value)
+{
+    TRACE_HOOK("pi %p name '%s' value '%s'", pi, name, value);
+
+    return property_get(name, value, NULL);
+}
+
+static int ___hybris_hook_system_property_foreach(void (*propfn)(const void *pi, void *cookie), void *cookie)
+{
+    TRACE_HOOK("propfn %p cookie %p", propfn, cookie);
+
+    return 0;
+}
+
+static const void *___hybris_hook_system_property_find(const char *name)
+{
+    TRACE_HOOK("name '%s'", name);
+
+    return NULL;
+}
+
+static unsigned int ___hybris_hook_system_property_serial(const void *pi)
+{
+    TRACE_HOOK("pi %p", pi);
 
-int my_open(const char *pathname, int flags, ...)
+    return 0;
+}
+
+static int ___hybris_hook_system_property_wait(const void *pi)
+{
+    TRACE_HOOK("pi %p", pi);
+
+    return 0;
+}
+
+static int ___hybris_hook_system_property_update(void *pi, const char *value, unsigned int len)
+{
+    TRACE_HOOK("pi %p value '%s' len %d", pi, value, len);
+
+    return 0;
+}
+
+static int ___hybris_hook_system_property_add(const char *name, unsigned int namelen, const char *value, unsigned int valuelen)
+{
+    TRACE_HOOK("name '%s' namelen %d value '%s' valuelen %d",
+               name, namelen, value, valuelen);
+    return 0;
+}
+
+static unsigned int ___hybris_hook_system_property_wait_any(unsigned int serial)
 {
-	va_list ap;
-	mode_t mode = 0;
-	const char *target_path = pathname;
-
-	if (pathname != NULL) {
-		struct open_redirect *entry = &open_redirects[0];
-		while (entry->from != NULL) {
-			if (strcmp(pathname, entry->from) == 0) {
-				target_path = entry->to;
-				break;
-			}
-			entry++;
-		}
-	}
-
-	if (flags & O_CREAT) {
-		va_start(ap, flags);
-		mode = va_arg(ap, mode_t);
-		va_end(ap);
-	}
+    TRACE_HOOK("serial %d", serial);
 
-	return open(target_path, flags, mode);
+    return 0;
+}
+
+static const void *___hybris_hook_system_property_find_nth(unsigned n)
+{
+    TRACE_HOOK("n %d", n);
+
+    return NULL;
 }
 
 /**
@@ -1317,25 +1975,394 @@ int my_open(const char *pathname, int fl
  * implementation of our internal property handling
  */
 
-int my_system_property_get(const char *name, const char *value)
+int _hybris_hook_system_property_get(const char *name, const char *value)
+{
+    TRACE_HOOK("name '%s' value '%s'", name, value);
+
+    return property_get(name, (char*) value, NULL);
+}
+
+int _hybris_hook_property_get(const char *key, char *value, const char *default_value)
 {
-	return property_get(name, value, NULL);
+    TRACE_HOOK("key '%s' value '%s' default value '%s'",
+               key, value, default_value);
+
+    return property_get(key, value, default_value);
+}
+
+int _hybris_hook_property_set(const char *key, const char *value)
+{
+    TRACE_HOOK("key '%s' value '%s'", key, value);
+
+    return property_set(key, value);
+}
+
+char *_hybris_hook_getenv(const char *name)
+{
+    TRACE_HOOK("name '%s'", name);
+
+    return getenv(name);
+}
+
+int _hybris_hook_setenv(const char *name, const char *value, int overwrite)
+{
+    TRACE_HOOK("name '%s' value '%s' overwrite %d", name, value, overwrite);
+
+    return setenv(name, value, overwrite);
+}
+
+int _hybris_hook_putenv(char *string)
+{
+    TRACE_HOOK("string '%s'", string);
+
+    return putenv(string);
+}
+
+int _hybris_hook_clearenv(void)
+{
+    TRACE_HOOK("");
+
+    return clearenv();
+}
+
+extern int __cxa_atexit(void (*)(void*), void*, void*);
+extern void __cxa_finalize(void * d);
+
+struct open_redirect {
+    const char *from;
+    const char *to;
+};
+
+struct open_redirect open_redirects[] = {
+    { "/dev/log/main", "/dev/alog/main" },
+    { "/dev/log/radio", "/dev/alog/radio" },
+    { "/dev/log/system", "/dev/alog/system" },
+    { "/dev/log/events", "/dev/alog/events" },
+    { NULL, NULL }
+};
+
+int _hybris_hook_open(const char *pathname, int flags, ...)
+{
+    va_list ap;
+    mode_t mode = 0;
+    const char *target_path = pathname;
+
+    TRACE_HOOK("pathname '%s' flags %d", pathname, flags);
+
+    if (pathname != NULL) {
+            struct open_redirect *entry = &open_redirects[0];
+            while (entry->from != NULL) {
+                    if (strcmp(pathname, entry->from) == 0) {
+                            target_path = entry->to;
+                            break;
+                    }
+                    entry++;
+            }
+    }
+
+    if (flags & O_CREAT) {
+            va_start(ap, flags);
+            mode = va_arg(ap, mode_t);
+            va_end(ap);
+    }
+
+    return open(target_path, flags, mode);
 }
 
 static __thread void *tls_hooks[16];
 
-void *__get_tls_hooks()
+static void *_hybris_hook_get_tls_hooks()
 {
-  return tls_hooks;
+    TRACE_HOOK("");
+    return tls_hooks;
+}
+
+int _hybris_hook_prctl(int option, unsigned long arg2, unsigned long arg3,
+             unsigned long arg4, unsigned long arg5)
+{
+    TRACE_HOOK("option %d arg2 %lu arg3 %lu arg4 %lu arg5 %lu",
+               option, arg2, arg3, arg4, arg5);
+
+#ifdef MALI_QUIRKS
+    if (option == PR_SET_NAME) {
+        char *name = (char*) arg2;
+
+        if (strcmp(name, MALI_HIST_DUMP_THREAD_NAME) == 0) {
+
+            // This can only work because prctl with PR_SET_NAME
+            // can be only called for the current thread and not
+            // for another thread so we can safely pause things.
+
+            HYBRIS_DEBUG_LOG(HOOKS, "%s: Found mali-hist-dump, killing thread ...",
+                             __FUNCTION__);
+
+            pthread_exit(NULL);
+        }
+    }
+#endif
+
+    return prctl(option, arg2, arg3, arg4, arg5);
 }
 
-static struct _hook hooks[] = {
-    {"property_get", property_get },
-    {"property_set", property_set },
-    {"__system_property_get", my_system_property_get },
-    {"getenv", getenv },
+static char* _hybris_hook_basename(const char *path)
+{
+    static __thread char buf[PATH_MAX];
+
+    TRACE_HOOK("path '%s'", path);
+
+    memset(buf, 0, sizeof(buf));
+
+    if (path)
+        strncpy(buf, path, sizeof(buf));
+
+    buf[sizeof buf - 1] = '\0';
+
+    return basename(buf);
+}
+
+static char* _hybris_hook_dirname(char *path)
+{
+    static __thread char buf[PATH_MAX];
+
+    TRACE_HOOK("path '%s'", path);
+
+    memset(buf, 0, sizeof(buf));
+
+    if (path)
+        strncpy(buf, path, sizeof(buf));
+
+    buf[sizeof buf - 1] = '\0';
+
+    return dirname(path);
+}
+
+static char* _hybris_hook_strerror(int errnum)
+{
+    TRACE_HOOK("errnum %d", errnum);
+
+    return strerror(errnum);
+}
+
+static char* _hybris_hook__gnu_strerror_r(int errnum, char *buf, size_t buf_len)
+{
+    TRACE_HOOK("errnum %d buf '%s' buf len %zu", errnum, buf, buf_len);
+
+    return strerror_r(errnum, buf, buf_len);
+}
+
+static int _hybris_hook_mprotect(void *addr, size_t len, int prot)
+{
+    TRACE_HOOK("addr %p len %zu prot %d", addr, len, prot);
+
+    return mprotect(addr, len, prot);
+}
+
+static int _hybris_hook_posix_memalign(void **memptr, size_t alignment, size_t size)
+{
+    TRACE_HOOK("memptr %p alignment %zu size %zu", memptr, alignment, size);
+
+    return posix_memalign(memptr, alignment, size);
+}
+
+static pid_t _hybris_hook_fork(void)
+{
+    TRACE_HOOK("");
+
+    return fork();
+}
+
+static locale_t _hybris_hook_newlocale(int category_mask, const char *locale, locale_t base)
+{
+    TRACE_HOOK("category mask %i locale '%s'", category_mask, locale);
+
+    return newlocale(category_mask, locale, base);
+}
+
+static void _hybris_hook_freelocale(locale_t locobj)
+{
+    TRACE_HOOK("");
+
+    return freelocale(locobj);
+}
+
+static locale_t _hybris_hook_duplocale(locale_t locobj)
+{
+    TRACE_HOOK("");
+
+    return duplocale(locobj);
+}
+
+static locale_t _hybris_hook_uselocale(locale_t newloc)
+{
+    TRACE_HOOK("");
+
+    return uselocale(newloc);
+}
+
+static struct lconv* _hybris_hook_localeconv(void)
+{
+    TRACE_HOOK("");
+
+    return localeconv();
+}
+
+static char* _hybris_hook_setlocale(int category, const char *locale)
+{
+    TRACE_HOOK("category %i locale '%s'", category, locale);
+
+    return setlocale(category, locale);
+}
+
+static void* _hybris_hook_mmap(void *addr, size_t len, int prot,
+                  int flags, int fd, off_t offset)
+{
+    TRACE_HOOK("addr %p len %zu prot %i flags %i fd %i offset %jd",
+               addr, len, prot, flags, fd, offset);
+
+    return mmap(addr, len, prot, flags, fd, offset);
+}
+
+static int _hybris_hook_munmap(void *addr, size_t length)
+{
+    TRACE_HOOK("addr %p length %zu", addr, length);
+
+    return munmap(addr, length);
+}
+
+extern size_t strlcat(char *dst, const char *src, size_t siz);
+extern size_t strlcpy(char *dst, const char *src, size_t siz);
+
+static int _hybris_hook_strcmp(const char *s1, const char *s2)
+{
+    TRACE_HOOK("s1 '%s' s2 '%s'", s1, s2);
+
+    if ( s1 == NULL || s2 == NULL)
+        return -1;
+
+    return strcmp(s1, s2);
+}
+
+static FILE* _hybris_hook_setmntent(const char *filename, const char *type)
+{
+    TRACE_HOOK("filename %s type %s", filename, type);
+
+    return setmntent(filename, type);
+}
+
+static struct mntent* _hybris_hook_getmntent(FILE *fp)
+{
+    TRACE_HOOK("fp %p", fp);
+
+    /* glibc doesn't allow NULL fp here, but bionic does. */
+    if (fp == NULL)
+        return NULL;
+
+    return getmntent(_get_actual_fp(fp));
+}
+
+static struct mntent* _hybris_hook_getmntent_r(FILE *fp, struct mntent *e, char *buf, int buf_len)
+{
+    TRACE_HOOK("fp %p e %p buf '%s' buf len %i",
+               fp, e, buf, buf_len);
+
+    /* glibc doesn't allow NULL fp here, but bionic does. */
+    if (fp == NULL)
+        return NULL;
+
+    return getmntent_r(_get_actual_fp(fp), e, buf, buf_len);
+}
+
+int _hybris_hook_endmntent(FILE *fp)
+{
+    TRACE_HOOK("fp %p", fp);
+
+    return endmntent(_get_actual_fp(fp));
+}
+
+static int _hybris_hook_fputws(const wchar_t *ws, FILE *stream)
+{
+    TRACE_HOOK("stream %p", stream);
+
+    return fputws(ws, _get_actual_fp(stream));
+}
+
+static int _hybris_hook_vfwprintf(FILE *stream, const wchar_t *format, va_list args)
+{
+    TRACE_HOOK("stream %p", stream);
+
+    return vfwprintf(_get_actual_fp(stream), format, args);
+}
+
+static wint_t _hybris_hook_fputwc(wchar_t wc, FILE *stream)
+{
+    TRACE_HOOK("stream %p", stream);
+
+    return fputwc(wc, _get_actual_fp(stream));
+}
+
+static wint_t _hybris_hook_putwc(wchar_t wc, FILE *stream)
+{
+    TRACE_HOOK("stream %p", stream);
+
+    return putwc(wc, _get_actual_fp(stream));
+}
+
+static wint_t _hybris_hook_fgetwc(FILE *stream)
+{
+    TRACE_HOOK("stream %p", stream);
+
+    return fgetwc(_get_actual_fp(stream));
+}
+
+static wint_t _hybris_hook_getwc(FILE *stream)
+{
+    TRACE_HOOK("stream %p", stream);
+
+    return getwc(_get_actual_fp(stream));
+}
+
+static void *_hybris_hook_android_dlopen(const char *filename, int flag)
+{
+    TRACE("filename %s flag %i", filename, flag);
+
+    return _android_dlopen(filename,flag);
+}
+
+static void *_hybris_hook_android_dlsym(void *handle, const char *symbol)
+{
+    TRACE("handle %p symbol %s", handle, symbol);
+
+    return _android_dlsym(handle,symbol);
+}
+
+static void* _hybris_hook_android_dladdr(void *addr, Dl_info *info)
+{
+    TRACE("addr %p info %p", addr, info);
+
+    return _android_dladdr(addr, info);
+}
+
+static int _hybris_hook_android_dlclose(void *handle)
+{
+    TRACE("handle %p", handle);
+
+    return _android_dlclose(handle);
+}
+
+static const char *_hybris_hook_android_dlerror(void)
+{
+    TRACE("");
+
+    return android_dlerror();
+}
+
+static struct _hook hooks_common[] = {
+    {"property_get", _hybris_hook_property_get },
+    {"property_set", _hybris_hook_property_set },
+    {"__system_property_get", _hybris_hook_system_property_get },
+    {"getenv", _hybris_hook_getenv},
     {"printf", printf },
-    {"malloc", my_malloc },
+    {"malloc", _hybris_hook_malloc },
     {"free", free },
     {"calloc", calloc },
     {"cfree", cfree },
@@ -1345,22 +2372,24 @@ static struct _hook hooks[] = {
     {"pvalloc", pvalloc },
     {"fread", fread },
     {"getxattr", getxattr},
+    {"mprotect", _hybris_hook_mprotect},
     /* string.h */
     {"memccpy",memccpy},
     {"memchr",memchr},
     {"memrchr",memrchr},
-    {"memcmp",memcmp},
-    {"memcpy",my_memcpy},
+    {"memcmp",_hybris_hook_memcmp},
+    {"memcpy",_hybris_hook_memcpy},
     {"memmove",memmove},
     {"memset",memset},
     {"memmem",memmem},
-    //  {"memswap",memswap},
+    {"getlogin", getlogin},
+    // {"memswap",memswap},
     {"index",index},
     {"rindex",rindex},
     {"strchr",strchr},
     {"strrchr",strrchr},
-    {"strlen",my_strlen},
-    {"strcmp",strcmp},
+    {"strlen",_hybris_hook_strlen},
+    {"strcmp",_hybris_hook_strcmp},
     {"strcpy",strcpy},
     {"strcat",strcat},
     {"strcasecmp",strcasecmp},
@@ -1369,16 +2398,14 @@ static struct _hook hooks[] = {
     {"strstr",strstr},
     {"strtok",strtok},
     {"strtok_r",strtok_r},
-    {"strerror",strerror},
+    {"strerror",_hybris_hook_strerror},
     {"strerror_r",strerror_r},
     {"strnlen",strnlen},
     {"strncat",strncat},
     {"strndup",strndup},
     {"strncmp",strncmp},
     {"strncpy",strncpy},
-    {"strtod", my_strtod},
-    //{"strlcat",strlcat},
-    //{"strlcpy",strlcpy},
+    {"strtod", _hybris_hook_strtod},
     {"strcspn",strcspn},
     {"strpbrk",strpbrk},
     {"strsep",strsep},
@@ -1395,17 +2422,19 @@ static struct _hook hooks[] = {
     {"index",index},
     {"rindex",rindex},
     {"strcasecmp",strcasecmp},
+    {"__sprintf_chk", __sprintf_chk},
+    {"__snprintf_chk", __snprintf_chk},
     {"strncasecmp",strncasecmp},
     /* dirent.h */
     {"opendir", opendir},
     {"closedir", closedir},
     /* pthread.h */
     {"getauxval", getauxval},
-    {"gettid", my_gettid},
+    {"gettid", _hybris_hook_gettid},
     {"getpid", getpid},
     {"pthread_atfork", pthread_atfork},
-    {"pthread_create", my_pthread_create},
-    {"pthread_kill", pthread_kill},
+    {"pthread_create", _hybris_hook_pthread_create},
+    {"pthread_kill", _hybris_hook_pthread_kill},
     {"pthread_exit", pthread_exit},
     {"pthread_join", pthread_join},
     {"pthread_detach", pthread_detach},
@@ -1413,72 +2442,78 @@ static struct _hook hooks[] = {
     {"pthread_equal", pthread_equal},
     {"pthread_getschedparam", pthread_getschedparam},
     {"pthread_setschedparam", pthread_setschedparam},
-    {"pthread_mutex_init", my_pthread_mutex_init},
-    {"pthread_mutex_destroy", my_pthread_mutex_destroy},
-    {"pthread_mutex_lock", my_pthread_mutex_lock},
-    {"pthread_mutex_unlock", my_pthread_mutex_unlock},
-    {"pthread_mutex_trylock", my_pthread_mutex_trylock},
-    {"pthread_mutex_lock_timeout_np", my_pthread_mutex_lock_timeout_np},
+    {"pthread_mutex_init", _hybris_hook_pthread_mutex_init},
+    {"pthread_mutex_destroy", _hybris_hook_pthread_mutex_destroy},
+    {"pthread_mutex_lock", _hybris_hook_pthread_mutex_lock},
+    {"pthread_mutex_unlock", _hybris_hook_pthread_mutex_unlock},
+    {"pthread_mutex_trylock", _hybris_hook_pthread_mutex_trylock},
+    {"pthread_mutex_lock_timeout_np", _hybris_hook_pthread_mutex_lock_timeout_np},
+    {"pthread_mutex_timedlock", _hybris_hook_pthread_mutex_timedlock},
     {"pthread_mutexattr_init", pthread_mutexattr_init},
     {"pthread_mutexattr_destroy", pthread_mutexattr_destroy},
     {"pthread_mutexattr_gettype", pthread_mutexattr_gettype},
     {"pthread_mutexattr_settype", pthread_mutexattr_settype},
     {"pthread_mutexattr_getpshared", pthread_mutexattr_getpshared},
-    {"pthread_mutexattr_setpshared", my_pthread_mutexattr_setpshared},
+    {"pthread_mutexattr_setpshared", _hybris_hook_pthread_mutexattr_setpshared},
     {"pthread_condattr_init", pthread_condattr_init},
     {"pthread_condattr_getpshared", pthread_condattr_getpshared},
     {"pthread_condattr_setpshared", pthread_condattr_setpshared},
     {"pthread_condattr_destroy", pthread_condattr_destroy},
-    {"pthread_cond_init", my_pthread_cond_init},
-    {"pthread_cond_destroy", my_pthread_cond_destroy},
-    {"pthread_cond_broadcast", my_pthread_cond_broadcast},
-    {"pthread_cond_signal", my_pthread_cond_signal},
-    {"pthread_cond_wait", my_pthread_cond_wait},
-    {"pthread_cond_timedwait", my_pthread_cond_timedwait},
-    {"pthread_cond_timedwait_monotonic", my_pthread_cond_timedwait},
-    {"pthread_cond_timedwait_monotonic_np", my_pthread_cond_timedwait},
-    {"pthread_cond_timedwait_relative_np", my_pthread_cond_timedwait_relative_np},
+    {"pthread_condattr_getclock", pthread_condattr_getclock},
+    {"pthread_condattr_setclock", pthread_condattr_setclock},
+    {"pthread_cond_init", _hybris_hook_pthread_cond_init},
+    {"pthread_cond_destroy", _hybris_hook_pthread_cond_destroy},
+    {"pthread_cond_broadcast", _hybris_hook_pthread_cond_broadcast},
+    {"pthread_cond_signal", _hybris_hook_pthread_cond_signal},
+    {"pthread_cond_wait", _hybris_hook_pthread_cond_wait},
+    {"pthread_cond_timedwait", _hybris_hook_pthread_cond_timedwait},
+    {"pthread_cond_timedwait_monotonic", _hybris_hook_pthread_cond_timedwait},
+    {"pthread_cond_timedwait_monotonic_np", _hybris_hook_pthread_cond_timedwait},
+    {"pthread_cond_timedwait_relative_np", _hybris_hook_pthread_cond_timedwait_relative_np},
     {"pthread_key_delete", pthread_key_delete},
-    {"pthread_setname_np", pthread_setname_np},
+    {"pthread_setname_np", _hybris_hook_pthread_setname_np},
     {"pthread_once", pthread_once},
     {"pthread_key_create", pthread_key_create},
-    {"pthread_setspecific", pthread_setspecific},
-    {"pthread_getspecific", pthread_getspecific},
-    {"pthread_attr_init", my_pthread_attr_init},
-    {"pthread_attr_destroy", my_pthread_attr_destroy},
-    {"pthread_attr_setdetachstate", my_pthread_attr_setdetachstate},
-    {"pthread_attr_getdetachstate", my_pthread_attr_getdetachstate},
-    {"pthread_attr_setschedpolicy", my_pthread_attr_setschedpolicy},
-    {"pthread_attr_getschedpolicy", my_pthread_attr_getschedpolicy},
-    {"pthread_attr_setschedparam", my_pthread_attr_setschedparam},
-    {"pthread_attr_getschedparam", my_pthread_attr_getschedparam},
-    {"pthread_attr_setstacksize", my_pthread_attr_setstacksize},
-    {"pthread_attr_getstacksize", my_pthread_attr_getstacksize},
-    {"pthread_attr_setstackaddr", my_pthread_attr_setstackaddr},
-    {"pthread_attr_getstackaddr", my_pthread_attr_getstackaddr},
-    {"pthread_attr_setstack", my_pthread_attr_setstack},
-    {"pthread_attr_getstack", my_pthread_attr_getstack},
-    {"pthread_attr_setguardsize", my_pthread_attr_setguardsize},
-    {"pthread_attr_getguardsize", my_pthread_attr_getguardsize},
-    {"pthread_attr_setscope", my_pthread_attr_setscope},
-    {"pthread_attr_setscope", my_pthread_attr_getscope},
-    {"pthread_getattr_np", my_pthread_getattr_np},
-    {"pthread_rwlockattr_init", my_pthread_rwlockattr_init},
-    {"pthread_rwlockattr_destroy", my_pthread_rwlockattr_destroy},
-    {"pthread_rwlockattr_setpshared", my_pthread_rwlockattr_setpshared},
-    {"pthread_rwlockattr_getpshared", my_pthread_rwlockattr_getpshared},
-    {"pthread_rwlock_init", my_pthread_rwlock_init},
-    {"pthread_rwlock_destroy", my_pthread_rwlock_destroy},
-    {"pthread_rwlock_unlock", my_pthread_rwlock_unlock},
-    {"pthread_rwlock_wrlock", my_pthread_rwlock_wrlock},
-    {"pthread_rwlock_rdlock", my_pthread_rwlock_rdlock},
-    {"pthread_rwlock_tryrdlock", my_pthread_rwlock_tryrdlock},
-    {"pthread_rwlock_trywrlock", my_pthread_rwlock_trywrlock},
-    {"pthread_rwlock_timedrdlock", my_pthread_rwlock_timedrdlock},
-    {"pthread_rwlock_timedwrlock", my_pthread_rwlock_timedwrlock},
+    {"pthread_setspecific", _hybris_hook_pthread_setspecific},
+    {"pthread_getspecific", _hybris_hook_pthread_getspecific},
+    {"pthread_attr_init", _hybris_hook_pthread_attr_init},
+    {"pthread_attr_destroy", _hybris_hook_pthread_attr_destroy},
+    {"pthread_attr_setdetachstate", _hybris_hook_pthread_attr_setdetachstate},
+    {"pthread_attr_getdetachstate", _hybris_hook_pthread_attr_getdetachstate},
+    {"pthread_attr_setschedpolicy", _hybris_hook_pthread_attr_setschedpolicy},
+    {"pthread_attr_getschedpolicy", _hybris_hook_pthread_attr_getschedpolicy},
+    {"pthread_attr_setschedparam", _hybris_hook_pthread_attr_setschedparam},
+    {"pthread_attr_getschedparam", _hybris_hook_pthread_attr_getschedparam},
+    {"pthread_attr_setstacksize", _hybris_hook_pthread_attr_setstacksize},
+    {"pthread_attr_getstacksize", _hybris_hook_pthread_attr_getstacksize},
+    {"pthread_attr_setstackaddr", _hybris_hook_pthread_attr_setstackaddr},
+    {"pthread_attr_getstackaddr", _hybris_hook_pthread_attr_getstackaddr},
+    {"pthread_attr_setstack", _hybris_hook_pthread_attr_setstack},
+    {"pthread_attr_getstack", _hybris_hook_pthread_attr_getstack},
+    {"pthread_attr_setguardsize", _hybris_hook_pthread_attr_setguardsize},
+    {"pthread_attr_getguardsize", _hybris_hook_pthread_attr_getguardsize},
+    {"pthread_attr_setscope", _hybris_hook_pthread_attr_setscope},
+    {"pthread_attr_getscope", _hybris_hook_pthread_attr_getscope},
+    {"pthread_getattr_np", _hybris_hook_pthread_getattr_np},
+    {"pthread_rwlockattr_init", _hybris_hook_pthread_rwlockattr_init},
+    {"pthread_rwlockattr_destroy", _hybris_hook_pthread_rwlockattr_destroy},
+    {"pthread_rwlockattr_setpshared", _hybris_hook_pthread_rwlockattr_setpshared},
+    {"pthread_rwlockattr_getpshared", _hybris_hook_pthread_rwlockattr_getpshared},
+    {"pthread_rwlock_init", _hybris_hook_pthread_rwlock_init},
+    {"pthread_rwlock_destroy", _hybris_hook_pthread_rwlock_destroy},
+    {"pthread_rwlock_unlock", _hybris_hook_pthread_rwlock_unlock},
+    {"pthread_rwlock_wrlock", _hybris_hook_pthread_rwlock_wrlock},
+    {"pthread_rwlock_rdlock", _hybris_hook_pthread_rwlock_rdlock},
+    {"pthread_rwlock_tryrdlock", _hybris_hook_pthread_rwlock_tryrdlock},
+    {"pthread_rwlock_trywrlock", _hybris_hook_pthread_rwlock_trywrlock},
+    {"pthread_rwlock_timedrdlock", _hybris_hook_pthread_rwlock_timedrdlock},
+    {"pthread_rwlock_timedwrlock", _hybris_hook_pthread_rwlock_timedwrlock},
+    /* bionic-only pthread */
+    {"__pthread_gettid", _hybris_hook_pthread_gettid},
+    {"pthread_gettid_np", _hybris_hook_pthread_gettid},
     /* stdio.h */
-    {"__isthreaded", &__my_isthreaded},
-    {"__sF", &my_sF},
+    {"__isthreaded", &___hybris_hook_isthreaded},
+    {"__sF", &_hybris_hook_sF},
     {"fopen", fopen},
     {"fdopen", fdopen},
     {"popen", popen},
@@ -1489,79 +2524,80 @@ static struct _hook hooks[] = {
     {"snprintf", snprintf},
     {"vsprintf", vsprintf},
     {"vsnprintf", vsnprintf},
-    {"clearerr", my_clearerr},
-    {"fclose", my_fclose},
-    {"feof", my_feof},
-    {"ferror", my_ferror},
-    {"fflush", my_fflush},
-    {"fgetc", my_fgetc},
-    {"fgetpos", my_fgetpos},
-    {"fgets", my_fgets},
-    {"fprintf", my_fprintf},
-    {"fputc", my_fputc},
-    {"fputs", my_fputs},
-    {"fread", my_fread},
-    {"freopen", my_freopen},
-    {"fscanf", my_fscanf},
-    {"fseek", my_fseek},
-    {"fseeko", my_fseeko},
-    {"fsetpos", my_fsetpos},
-    {"ftell", my_ftell},
-    {"ftello", my_ftello},
-    {"fwrite", my_fwrite},
-    {"getc", my_getc},
-    {"getdelim", my_getdelim},
-    {"getline", my_getline},
-    {"putc", my_putc},
-    {"rewind", my_rewind},
-    {"setbuf", my_setbuf},
-    {"setvbuf", my_setvbuf},
-    {"ungetc", my_ungetc},
+    {"clearerr", _hybris_hook_clearerr},
+    {"fclose", _hybris_hook_fclose},
+    {"feof", _hybris_hook_feof},
+    {"ferror", _hybris_hook_ferror},
+    {"fflush", _hybris_hook_fflush},
+    {"fgetc", _hybris_hook_fgetc},
+    {"fgetpos", _hybris_hook_fgetpos},
+    {"fgets", _hybris_hook_fgets},
+    {"fprintf", _hybris_hook_fprintf},
+    {"fputc", _hybris_hook_fputc},
+    {"fputs", _hybris_hook_fputs},
+    {"fread", _hybris_hook_fread},
+    {"freopen", _hybris_hook_freopen},
+    {"fscanf", _hybris_hook_fscanf},
+    {"fseek", _hybris_hook_fseek},
+    {"fseeko", _hybris_hook_fseeko},
+    {"fsetpos", _hybris_hook_fsetpos},
+    {"ftell", _hybris_hook_ftell},
+    {"ftello", _hybris_hook_ftello},
+    {"fwrite", _hybris_hook_fwrite},
+    {"getc", _hybris_hook_getc},
+    {"getdelim", _hybris_hook_getdelim},
+    {"getline", _hybris_hook_getline},
+    {"putc", _hybris_hook_putc},
+    {"rewind", _hybris_hook_rewind},
+    {"setbuf", _hybris_hook_setbuf},
+    {"setvbuf", _hybris_hook_setvbuf},
+    {"ungetc", _hybris_hook_ungetc},
     {"vasprintf", vasprintf},
-    {"vfprintf", my_vfprintf},
-    {"vfscanf", my_vfscanf},
-    {"fileno", my_fileno},
-    {"pclose", my_pclose},
-    {"flockfile", my_flockfile},
-    {"ftrylockfile", my_ftrylockfile},
-    {"funlockfile", my_funlockfile},
-    {"getc_unlocked", my_getc_unlocked},
-    {"putc_unlocked", my_putc_unlocked},
-    //{"fgetln", my_fgetln},
-    {"fpurge", my_fpurge},
-    {"getw", my_getw},
-    {"putw", my_putw},
-    {"setbuffer", my_setbuffer},
-    {"setlinebuf", my_setlinebuf},
+    {"vfprintf", _hybris_hook_vfprintf},
+    {"vfscanf", _hybris_hook_vfscanf},
+    {"fileno", _hybris_hook_fileno},
+    {"pclose", _hybris_hook_pclose},
+    {"flockfile", _hybris_hook_flockfile},
+    {"ftrylockfile", _hybris_hook_ftrylockfile},
+    {"funlockfile", _hybris_hook_funlockfile},
+    {"getc_unlocked", _hybris_hook_getc_unlocked},
+    {"putc_unlocked", _hybris_hook_putc_unlocked},
+    //{"fgetln", _hybris_hook_fgetln},
+    {"fpurge", _hybris_hook_fpurge},
+    {"getw", _hybris_hook_getw},
+    {"putw", _hybris_hook_putw},
+    {"setbuffer", _hybris_hook_setbuffer},
+    {"setlinebuf", _hybris_hook_setlinebuf},
     {"__errno", __errno_location},
-    {"__set_errno", my_set_errno},
+    {"__set_errno", _hybris_hook_set_errno},
     /* net specifics, to avoid __res_get_state */
-    {"getaddrinfo", getaddrinfo},
+    {"getaddrinfo", _hybris_hook_getaddrinfo},
+    {"freeaddrinfo", _hybris_hook_freeaddrinfo},
     {"gethostbyaddr", gethostbyaddr},
     {"gethostbyname", gethostbyname},
     {"gethostbyname2", gethostbyname2},
     {"gethostent", gethostent},
     {"strftime", strftime},
-    {"sysconf", my_sysconf},
-    {"dlopen", android_dlopen},
-    {"dlerror", android_dlerror},
-    {"dlsym", android_dlsym},
-    {"dladdr", android_dladdr},
-    {"dlclose", android_dlclose},
+    {"sysconf", _hybris_hook_sysconf},
+    {"dlopen", _hybris_hook_android_dlopen},
+    {"dlerror", _hybris_hook_android_dlerror},
+    {"dlsym", _hybris_hook_android_dlsym},
+    {"dladdr", _hybris_hook_android_dladdr},
+    {"dlclose", _hybris_hook_android_dlclose},
     /* dirent.h */
     {"opendir", opendir},
     {"fdopendir", fdopendir},
     {"closedir", closedir},
-    {"readdir", my_readdir},
-    {"readdir_r", my_readdir_r},
+    {"readdir", _hybris_hook_readdir},
+    {"readdir_r", _hybris_hook_readdir_r},
     {"rewinddir", rewinddir},
     {"seekdir", seekdir},
     {"telldir", telldir},
     {"dirfd", dirfd},
     /* fcntl.h */
-    {"open", my_open},
+    {"open", _hybris_hook_open},
     // TODO: scandir, scandirat, alphasort, versionsort
-    {"__get_tls_hooks", __get_tls_hooks},
+    {"__get_tls_hooks", _hybris_hook_get_tls_hooks},
     {"sscanf", sscanf},
     {"scanf", scanf},
     {"vscanf", vscanf},
@@ -1575,6 +2611,9 @@ static struct _hook hooks[] = {
     {"timer_gettime", timer_gettime},
     {"timer_delete", timer_delete},
     {"timer_getoverrun", timer_getoverrun},
+    {"localtime", localtime},
+    {"localtime_r", localtime_r},
+    {"gmtime", gmtime},
     {"abort", abort},
     {"writev", writev},
     /* unistd.h */
@@ -1583,34 +2622,369 @@ static struct _hook hooks[] = {
     {"getgrgid", getgrgid},
     {"__cxa_atexit", __cxa_atexit},
     {"__cxa_finalize", __cxa_finalize},
-    {NULL, NULL},
+    {"__system_property_read", ___hybris_hook_system_property_read},
+    {"__system_property_set", property_set},
+    {"__system_property_foreach", ___hybris_hook_system_property_foreach},
+    {"__system_property_find", ___hybris_hook_system_property_find},
+    {"__system_property_serial", ___hybris_hook_system_property_serial},
+    {"__system_property_wait", ___hybris_hook_system_property_wait},
+    {"__system_property_update", ___hybris_hook_system_property_update},
+    {"__system_property_add", ___hybris_hook_system_property_add},
+    {"__system_property_wait_any", ___hybris_hook_system_property_wait_any},
+    {"__system_property_find_nth", ___hybris_hook_system_property_find_nth},
+    /* sys/prctl.h */
+    {"prctl", _hybris_hook_prctl},
 };
 
-void *get_hooked_symbol(char *sym)
+static struct _hook hooks_mm[] = {
+    {"strtol", _hybris_hook_strtol},
+    {"strlcat",strlcat},
+    {"strlcpy",strlcpy},
+    {"setenv", _hybris_hook_setenv},
+    {"putenv", _hybris_hook_putenv},
+    {"clearenv", _hybris_hook_clearenv},
+    {"dprintf", dprintf},
+    {"mallinfo", mallinfo},
+    {"malloc_usable_size", _hybris_hook_malloc_usable_size},
+    {"posix_memalign", _hybris_hook_posix_memalign},
+    {"mprotect", _hybris_hook_mprotect},
+    {"__gnu_strerror_r",_hybris_hook__gnu_strerror_r},
+    {"pthread_rwlockattr_getkind_np", _hybris_hook_pthread_rwlockattr_getkind_np},
+    {"pthread_rwlockattr_setkind_np", _hybris_hook_pthread_rwlockattr_setkind_np},
+    /* unistd.h */
+    {"fork", _hybris_hook_fork},
+    {"ttyname", ttyname},
+    {"swprintf", swprintf},
+    {"fmemopen", fmemopen},
+    {"open_memstream", open_memstream},
+    {"open_wmemstream", open_wmemstream},
+    {"ptsname", ptsname},
+    {"__hybris_set_errno_internal", _hybris_hook_set_errno},
+    {"getservbyname", getservbyname},
+    /* libgen.h */
+    {"basename", _hybris_hook_basename},
+    {"dirname", _hybris_hook_dirname},
+    /* locale.h */
+    {"newlocale", _hybris_hook_newlocale},
+    {"freelocale", _hybris_hook_freelocale},
+    {"duplocale", _hybris_hook_duplocale},
+    {"uselocale", _hybris_hook_uselocale},
+    {"localeconv", _hybris_hook_localeconv},
+    {"setlocale", _hybris_hook_setlocale},
+    /* sys/mman.h */
+    {"mmap", _hybris_hook_mmap},
+    {"munmap", _hybris_hook_munmap},
+    /* wchar.h */
+    {"wmemchr", wmemchr},
+    {"wmemcmp", wmemcmp},
+    {"wmemcpy", wmemcpy},
+    {"wmemmove", wmemmove},
+    {"wmemset", wmemset},
+    {"wmempcpy", wmempcpy},
+    {"fputws", _hybris_hook_fputws},
+    // It's enough to hook vfwprintf here as fwprintf will call it with a
+    // proper va_list in place so we don't have to handle this here.
+    {"vfwprintf", _hybris_hook_vfwprintf},
+    {"fputwc", _hybris_hook_fputwc},
+    {"putwc", _hybris_hook_putwc},
+    {"fgetwc", _hybris_hook_fgetwc},
+    {"getwc", _hybris_hook_getwc},
+    /* sched.h */
+    {"clone", clone},
+    /* mntent.h */
+    {"setmntent", _hybris_hook_setmntent},
+    {"getmntent", _hybris_hook_getmntent},
+    {"getmntent_r", _hybris_hook_getmntent_r},
+    {"endmntent", _hybris_hook_endmntent},
+    /* stdlib.h */
+    {"system", system},
+    /* pwd.h */
+    {"getgrnam", getgrnam},
+    {"getpwuid", getpwuid},
+    {"getpwnam", getpwnam},
+    /* signal.h */
+    /* Hooks commented out for the moment as we need proper translations between
+     * bionic and glibc types for them to work (for instance, sigset_t has
+     * different definitions in each library).
+     */
+#if 0
+    {"sigaction", sigaction},
+    {"sigaddset", sigaddset},
+    {"sigaltstack", sigaltstack},
+    {"sigblock", sigblock},
+    {"sigdelset", sigdelset},
+    {"sigemptyset", sigemptyset},
+    {"sigfillset", sigfillset},
+    {"siginterrupt", siginterrupt},
+    {"sigismember", sigismember},
+    {"siglongjmp", siglongjmp},
+    {"signal", signal},
+    {"signalfd", signalfd},
+    {"sigpending", sigpending},
+    {"sigprocmask", sigprocmask},
+    {"sigqueue", sigqueue},
+    // setjmp.h defines segsetjmp via a #define and the real symbol
+    // we have to forward to is __sigsetjmp
+    {"sigsetjmp", __sigsetjmp},
+    {"sigsetmask", sigsetmask},
+    {"sigsuspend", sigsuspend},
+    {"sigtimedwait", sigtimedwait},
+    {"sigwait", sigwait},
+    {"sigwaitinfo", sigwaitinfo},
+#endif
+    /* dirent.h */
+    {"readdir64", _hybris_hook_readdir},
+    {"readdir64_r", _hybris_hook_readdir_r},
+    {"scandir", _hybris_hook_scandir},
+    {"scandirat", _hybris_hook_scandirat},
+    {"alphasort,", _hybris_hook_alphasort},
+    {"versionsort,", _hybris_hook_versionsort},
+    {"scandir64", _hybris_hook_scandir},
+};
+
+
+static int hook_cmp(const void *a, const void *b)
+{
+    return strcmp(((struct _hook*)a)->name, ((struct _hook*)b)->name);
+}
+
+void hybris_set_hook_callback(hybris_hook_cb callback)
+{
+    hook_callback = callback;
+}
+
+static int get_android_sdk_version()
+{
+    static int sdk_version = -1;
+
+    if (sdk_version > 0)
+        return sdk_version;
+
+    char value[PROP_VALUE_MAX];
+    property_get("ro.build.version.sdk", value, "19");
+
+    sdk_version = 19;
+    if (strlen(value) > 0)
+        sdk_version = atoi(value);
+
+#ifdef UBUNTU_LINKER_OVERRIDES
+    /* We override both frieza and turbo here until they are ready to be
+     * upgraded to the newer linker. */
+    char device_name[PROP_VALUE_MAX];
+    memset(device_name, 0, sizeof(device_name));
+    property_get("ro.build.product", device_name, "");
+    if (strlen(device_name) > 0) {
+        /* Force SDK version for both frieza/cooler and turbo for the time being */
+        if (strcmp(device_name, "frieza") == 0 ||
+            strcmp(device_name, "cooler") == 0 ||
+            strcmp(device_name, "turbo") == 0)
+            sdk_version = 19;
+    }
+#endif
+
+    char *version_override = getenv("HYBRIS_ANDROID_SDK_VERSION");
+    if (version_override)
+        sdk_version = atoi(version_override);
+
+    LOGD("Using SDK API version %i\n", sdk_version);
+
+    return sdk_version;
+}
+
+#define HOOKS_SIZE(hooks) \
+    (sizeof(hooks) / sizeof(hooks[0]))
+
+
+static void* __hybris_get_hooked_symbol(const char *sym, const char *requester)
 {
-    struct _hook *ptr = &hooks[0];
-    static int counter = -1;
+    static int sorted = 0;
+    static intptr_t counter = -1;
+    void *found = NULL;
+    struct _hook key;
 
-    while (ptr->name != NULL)
+    /* First check if we have a callback registered which could
+     * give us a context specific hook implementation */
+    if (hook_callback)
     {
-        if (strcmp(sym, ptr->name) == 0){
-            return ptr->func;
-        }
-        ptr++;
+        found = hook_callback(sym, requester);
+        if (found)
+            return (void*) found;
     }
-    if (strstr(sym, "pthread") != NULL)
+
+    if (!sorted)
+    {
+        qsort(hooks_common, HOOKS_SIZE(hooks_common), sizeof(hooks_common[0]), hook_cmp);
+        qsort(hooks_mm, HOOKS_SIZE(hooks_mm), sizeof(hooks_mm[0]), hook_cmp);
+        sorted = 1;
+    }
+
+    /* Allow newer hooks to override those which are available for all versions */
+    key.name = sym;
+    if (get_android_sdk_version() > 21)
+        found = bsearch(&key, hooks_mm, HOOKS_SIZE(hooks_mm), sizeof(hooks_mm[0]), hook_cmp);
+    if (!found)
+        found = bsearch(&key, hooks_common, HOOKS_SIZE(hooks_common), sizeof(hooks_common[0]), hook_cmp);
+
+    if (found)
+        return ((struct _hook*) found)->func;
+
+    if (strncmp(sym, "pthread", 7) == 0 ||
+        strncmp(sym, "__pthread", 9) == 0)
     {
         /* safe */
         if (strcmp(sym, "pthread_sigmask") == 0)
            return NULL;
         /* not safe */
         counter--;
-        LOGD("%s %i\n", sym, counter);
+        // If you're experiencing a crash later on check the address of the
+        // function pointer being call. If it matches the printed counter
+        // value here then you can easily find out which symbol is missing.
+        LOGD("Missing hook for pthread symbol %s (counter %" PRIiPTR ")\n", sym, counter);
         return (void *) counter;
     }
+
+    if (!getenv("HYBRIS_DONT_PRINT_SYMBOLS_WITHOUT_HOOK"))
+        LOGD("Could not find a hook for symbol %s", sym);
+
     return NULL;
 }
 
-void android_linker_init()
+static void *linker_handle = NULL;
+
+static void* __hybris_load_linker(const char *path)
+{
+    void *handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
+    if (!handle) {
+        fprintf(stderr, "ERROR: Failed to load hybris linker for Android SDK version %d\n",
+                get_android_sdk_version());
+        return NULL;
+    }
+    return handle;
+}
+
+#define LINKER_NAME_JB "jb"
+#define LINKER_NAME_MM "mm"
+
+#if defined(WANT_LINKER_JB)
+#define LINKER_NAME_DEFAULT LINKER_NAME_JB
+#elif defined(WANT_LINKER_MM)
+#define LINKER_NAME_DEFAULT LINKER_NAME_MM
+#endif
+
+static int linker_initialized = 0;
+
+static void __hybris_linker_init()
+{
+    LOGD("Linker initialization");
+
+    int sdk_version = get_android_sdk_version();
+
+    char path[PATH_MAX];
+    const char *name = LINKER_NAME_DEFAULT;
+
+    /* See https://source.android.com/source/build-numbers.html for
+     * an overview over available SDK version numbers and which
+     * Android version they relate to. */
+#if defined(WANT_LINKER_MM)
+    if (sdk_version <= 23)
+        name = LINKER_NAME_MM;
+#endif
+#if defined(WANT_LINKER_JB)
+    if (sdk_version < 21)
+        name = LINKER_NAME_JB;
+#endif
+
+    const char *linker_dir = LINKER_PLUGIN_DIR;
+    const char *user_linker_dir = getenv("HYBRIS_LINKER_DIR");
+    if (user_linker_dir)
+        linker_dir = user_linker_dir;
+
+    snprintf(path, PATH_MAX, "%s/%s.so", linker_dir, name);
+
+    LOGD("Loading linker from %s..", path);
+
+    linker_handle = __hybris_load_linker(path);
+    if (!linker_handle)
+        exit(1);
+
+    /* Load all necessary symbols we need from the linker */
+    _android_linker_init = dlsym(linker_handle, "android_linker_init");
+    _android_dlopen = dlsym(linker_handle, "android_dlopen");
+    _android_dlsym = dlsym(linker_handle, "android_dlsym");
+    _android_dladdr = dlsym(linker_handle, "android_dladdr");
+    _android_dlclose = dlsym(linker_handle, "android_dlclose");
+    _android_dlerror = dlsym(linker_handle, "android_dlerror");
+
+    /* Now its time to setup the linker itself */
+    _android_linker_init(sdk_version, __hybris_get_hooked_symbol);
+
+    linker_initialized = 1;
+}
+
+#define ENSURE_LINKER_IS_LOADED() \
+    if (!linker_initialized) \
+        __hybris_linker_init();
+
+/* NOTE: As we're not linking directly with the linker anymore
+ * but several users are using android_* functions directly we
+ * have to export them here. */
+
+void *android_dlopen(const char *filename, int flag)
+{
+    ENSURE_LINKER_IS_LOADED();
+
+    if (!_android_dlopen)
+        return NULL;
+
+    return _android_dlopen(filename,flag);
+}
+
+void *android_dlsym(void *handle, const char *symbol)
+{
+    ENSURE_LINKER_IS_LOADED();
+
+    if (!_android_dlsym)
+        return NULL;
+
+    return _android_dlsym(handle,symbol);
+}
+
+int android_dlclose(void *handle)
+{
+    ENSURE_LINKER_IS_LOADED();
+
+    if (!_android_dlclose)
+        return -1;
+
+    return _android_dlclose(handle);
+}
+
+const char *android_dlerror(void)
+{
+    ENSURE_LINKER_IS_LOADED();
+
+    if (!_android_dlerror)
+        return NULL;
+
+    return _android_dlerror();
+}
+
+void *hybris_dlopen(const char *filename, int flag)
+{
+    return android_dlopen(filename,flag);
+}
+
+void *hybris_dlsym(void *handle, const char *symbol)
+{
+    return android_dlsym(handle,symbol);
+}
+
+int hybris_dlclose(void *handle)
+{
+    return android_dlclose(handle);
+}
+
+const char *hybris_dlerror(void)
 {
+    return android_dlerror();
 }
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/hooks_shm.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/hooks_shm.c
@@ -16,13 +16,15 @@
  *
  */
 
-#include "hooks_shm.h"
+#include "config.h"
 
-#define _GNU_SOURCE
+#include "hooks_shm.h"
 
 #include <stddef.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <stdio.h>
+#include <string.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <pthread.h>
@@ -36,7 +38,11 @@
 #define LOGD(message, ...) HYBRIS_DEBUG_LOG(HOOKS, message, ##__VA_ARGS__)
 
 #define HYBRIS_DATA_SIZE    4000
-#define HYBRIS_SHM_MASK     0xFF000000UL
+#if defined(__LP64__)
+# define HYBRIS_SHM_MASK    0xFFFFFFFFFF000000ULL
+#else
+# define HYBRIS_SHM_MASK    0xFF000000UL
+#endif
 #define HYBRIS_SHM_PATH     "/hybris_shm_data"
 
 /* Structure of a shared memory region */
@@ -123,9 +129,11 @@ static void _hybris_shm_init()
         else {
             LOGD("Creating a new shared memory segment.");
 
-            _hybris_shm_fd = shm_open(HYBRIS_SHM_PATH, O_RDWR | O_CREAT, 0660);
+            mode_t pumask = umask(0);
+            _hybris_shm_fd = shm_open(HYBRIS_SHM_PATH, O_RDWR | O_CREAT, 0666);
+            umask(pumask);
             if (_hybris_shm_fd >= 0) {
-                ftruncate( _hybris_shm_fd, size_to_map );
+                TEMP_FAILURE_RETRY(ftruncate( _hybris_shm_fd, size_to_map ));
                 /* Map the memory object */
                 _hybris_shm_data = (hybris_shm_data_t *)mmap( NULL, size_to_map,
                                              PROT_READ | PROT_WRITE, MAP_SHARED,
@@ -161,7 +169,7 @@ static void _hybris_shm_init()
  */
 static void _hybris_shm_extend_region()
 {
-    ftruncate( _hybris_shm_fd, _current_mapped_size + HYBRIS_DATA_SIZE );
+    TEMP_FAILURE_RETRY(ftruncate( _hybris_shm_fd, _current_mapped_size + HYBRIS_DATA_SIZE ));
     _hybris_shm_data->max_offset += HYBRIS_DATA_SIZE;
 
     _sync_mmap_with_shm();
@@ -171,11 +179,12 @@ static void _hybris_shm_extend_region()
 
  /*
   * Determine if the pointer that has been extracted by hybris is
-  * pointing to an address in the shared memory
+  * pointing to an address in the shared memory.
   */
 int hybris_is_pointer_in_shm(void *ptr)
 {
-    if ((unsigned int)ptr >= HYBRIS_SHM_MASK)
+    if (((uintptr_t) ptr >= HYBRIS_SHM_MASK) &&
+                    ((uintptr_t) ptr <= HYBRIS_SHM_MASK_TOP))
         return 1;
 
     return 0;
@@ -199,7 +208,7 @@ void *hybris_get_shmpointer(hybris_shm_p
         _sync_mmap_with_shm();  /* make sure our mmap is sync'ed */
 
         if (_hybris_shm_data != NULL) {
-            unsigned int offset = handle & (~HYBRIS_SHM_MASK);
+            uintptr_t offset = handle & (~HYBRIS_SHM_MASK);
             realpointer = &(_hybris_shm_data->data) + offset;
 
             /* Be careful when activating this trace: this method is called *a lot* !
@@ -241,7 +250,7 @@ hybris_shm_pointer_t hybris_shm_alloc(si
 
     /* there is now enough place in this pool */
     location = _hybris_shm_data->current_offset | HYBRIS_SHM_MASK;
-    LOGD("Allocated a shared object (size = %d, at offset %d)", size, _hybris_shm_data->current_offset);
+    LOGD("Allocated a shared object (size = %zu, at offset %d)", size, _hybris_shm_data->current_offset);
 
     _hybris_shm_data->current_offset += size;
 
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/hooks_shm.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/hooks_shm.h
@@ -19,8 +19,12 @@
 #define HOOKS_SHM_H_
 
 #include <stddef.h>
+#include <stdint.h>
 
-typedef unsigned int hybris_shm_pointer_t;
+/* Leave space to workaround the issue that Android might pass negative int values */
+#define HYBRIS_SHM_MASK_TOP (UINTPTR_MAX - 15)
+
+typedef uintptr_t hybris_shm_pointer_t;
 
 /* 
  * Allocate a space in the shared memory region of hybris
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/jb/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/jb/Makefile.am
@@ -6,26 +6,27 @@ if  WANT_ARCH_X86
 ARCHFLAGS = -DANDROID_X86_LINKER
 endif
 
-noinst_LTLIBRARIES = \
-	libandroid-linker.la
-libandroid_linker_la_SOURCES = \
+modlibexecdir = $(libdir)/libhybris/linker
+modlibexec_LTLIBRARIES = jb.la
+jb_la_SOURCES = \
 	dlfcn.c \
 	linker.c \
 	linker_environ.c \
 	linker_format.c \
-	rt.c
-libandroid_linker_la_CFLAGS = \
+	rt.c \
+	../strlcpy.c
+jb_la_CFLAGS = \
 	-I$(top_srcdir)/include \
 	$(ANDROID_HEADERS_CFLAGS) \
 	-I$(top_srcdir)/common \
-	-D_GNU_SOURCE \
-	-DLINKER_TEXT_BASE=0xB0000100 \
-	-DLINKER_AREA_SIZE=0x01000000 \
 	-DDEFAULT_HYBRIS_LD_LIBRARY_PATH="\"@DEFAULT_HYBRIS_LD_LIBRARY_PATH@\"" \
 	$(ARCHFLAGS)
+jb_la_LDFLAGS = \
+	-module \
+	-avoid-version
 
 if WANT_DEBUG
-libandroid_linker_la_CFLAGS += -DLINKER_DEBUG=1
+jb_la_CFLAGS += -DLINKER_DEBUG=1
 else
-libandroid_linker_la_CFLAGS += -DLINKER_DEBUG=0
+jb_la_CFLAGS += -DLINKER_DEBUG=0
 endif
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/jb/debugger.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/jb/debugger.c
@@ -26,6 +26,8 @@
  * SUCH DAMAGE.
  */
 
+#include "config.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/jb/dlfcn.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/jb/dlfcn.c
@@ -13,7 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define _GNU_SOURCE
+
+#include "config.h"
+
 #include <dlfcn.h>
 #include <pthread.h>
 #include <stdio.h>
@@ -78,7 +80,7 @@ const char *android_dlerror(void)
 void *android_dlsym(void *handle, const char *symbol)
 {
     soinfo *found;
-    Elf32_Sym *sym;
+    Elf_Sym *sym;
     unsigned bind;
 
     pthread_mutex_lock(&dl_lock);
@@ -142,7 +144,7 @@ int android_dladdr(const void *addr, Dl_
         info->dli_fbase = (void*)si->base;
 
         /* Determine if any symbol in the library contains the specified address */
-        Elf32_Sym *sym = find_containing_symbol(addr, si);
+        Elf_Sym *sym = find_containing_symbol(addr, si);
 
         if(sym != NULL) {
             info->dli_sname = si->strtab + sym->st_name;
@@ -171,7 +173,7 @@ int android_dl_iterate_phdr(int (*cb)(st
 //                     0000000 00011111 111112 22222222 2333333 333344444444445555555
 //                     0123456 78901234 567890 12345678 9012345 678901234567890123456
 #define ANDROID_LIBDL_STRTAB \
-                      "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0dl_iterate_phdr\0"
+                      "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0dl_unwind_find_exidx\0"
 
 _Unwind_Ptr android_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount);
 
@@ -191,7 +193,7 @@ _Unwind_Ptr android_dl_unwind_find_exidx
 #endif
 
 
-static Elf32_Sym libdl_symtab[] = {
+static Elf_Sym libdl_symtab[] = {
       // total length of libdl_info.strtab, including trailing 0
       // This is actually the the STH_UNDEF entry. Technically, it's
       // supposed to have st_name == 0, but instead, it points to an index
@@ -199,44 +201,42 @@ static Elf32_Sym libdl_symtab[] = {
     { st_name: sizeof(ANDROID_LIBDL_STRTAB) - 1,
     },
     { st_name: 0,   // starting index of the name in libdl_info.strtab
-      st_value: (Elf32_Addr) &android_dlopen,
+      st_value: (Elf_Addr) &android_dlopen,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
     { st_name: 7,
-      st_value: (Elf32_Addr) &android_dlclose,
+      st_value: (Elf_Addr) &android_dlclose,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
     { st_name: 15,
-      st_value: (Elf32_Addr) &android_dlsym,
+      st_value: (Elf_Addr) &android_dlsym,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
     { st_name: 21,
-      st_value: (Elf32_Addr) &android_dlerror,
+      st_value: (Elf_Addr) &android_dlerror,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
     { st_name: 29,
-      st_value: (Elf32_Addr) &android_dladdr,
+      st_value: (Elf_Addr) &android_dladdr,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
-#ifdef ANDROID_ARM_LINKER
     { st_name: 36,
-      st_value: (Elf32_Addr) &android_dl_unwind_find_exidx,
+      st_value: (Elf_Addr) &android_dl_iterate_phdr,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
-    { st_name: 57,
-#else
-    { st_name: 36,
-#endif
-      st_value: (Elf32_Addr) &android_dl_iterate_phdr,
+#ifdef ANDROID_ARM_LINKER
+    { st_name: 52,
+      st_value: (Elf_Addr) &android_dl_unwind_find_exidx,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
+#endif
 };
 
 /* Fake out a hash table with a single bucket.
@@ -273,12 +273,8 @@ soinfo libdl_info = {
     symtab: libdl_symtab,
 
     refcount: 1,
-    nbucket: 1,
-#if defined(ANDROID_ARM_LINKER)
-    nchain: 8,
-#else
-    nchain: 7,
-#endif
+    nbucket: sizeof(libdl_buckets)/sizeof(unsigned),
+    nchain: sizeof(libdl_chains)/sizeof(unsigned),
     bucket: libdl_buckets,
     chain: libdl_chains,
 };
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/jb/linker.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/jb/linker.c
@@ -26,6 +26,8 @@
  * SUCH DAMAGE.
  */
 
+#include "config.h"
+
 #include <linux/auxvec.h>
 
 #include <stdio.h>
@@ -79,6 +81,7 @@
  *   having a hard limit (64)
 */
 
+static void* (*_get_hooked_symbol)(const char *symbol, const char *requester);
 
 static int link_image(soinfo *si, unsigned wr_offset);
 
@@ -380,10 +383,10 @@ android_dl_iterate_phdr(int (*cb)(struct
     return rv;
 }
 
-static Elf32_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name)
+static Elf_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name)
 {
-    Elf32_Sym *s;
-    Elf32_Sym *symtab = si->symtab;
+    Elf_Sym *s;
+    Elf_Sym *symtab = si->symtab;
     const char *strtab = si->strtab;
     unsigned n;
 
@@ -425,11 +428,11 @@ static unsigned elfhash(const char *_nam
     return h;
 }
 
-static Elf32_Sym *
+static Elf_Sym *
 _do_lookup(soinfo *si, const char *name, unsigned *base)
 {
     unsigned elf_hash = elfhash(name);
-    Elf32_Sym *s;
+    Elf_Sym *s;
     unsigned *d;
     soinfo *lsi = si;
     int i;
@@ -501,17 +504,17 @@ done:
 /* This is used by dl_sym().  It performs symbol lookup only within the
    specified soinfo object and not in any of its dependencies.
  */
-Elf32_Sym *lookup_in_library(soinfo *si, const char *name)
+Elf_Sym *lookup_in_library(soinfo *si, const char *name)
 {
     return _elf_lookup(si, elfhash(name), name);
 }
 
 /* This is used by dl_sym().  It performs a global symbol lookup.
  */
-Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start)
+Elf_Sym *lookup(const char *name, soinfo **found, soinfo *start)
 {
     unsigned elf_hash = elfhash(name);
-    Elf32_Sym *s = NULL;
+    Elf_Sym *s = NULL;
     soinfo *si;
 
     if(start == NULL) {
@@ -552,7 +555,7 @@ soinfo *find_containing_library(const vo
     return NULL;
 }
 
-Elf32_Sym *find_containing_symbol(const void *addr, soinfo *si)
+Elf_Sym *find_containing_symbol(const void *addr, soinfo *si)
 {
     unsigned int i;
     unsigned soaddr = (unsigned)addr - si->base;
@@ -560,7 +563,7 @@ Elf32_Sym *find_containing_symbol(const
     /* Search the library's symbol table for any defined symbol which
      * contains this address */
     for(i=0; i<si->nchain; i++) {
-        Elf32_Sym *sym = &si->symtab[i];
+        Elf_Sym *sym = &si->symtab[i];
 
         if(sym->st_shndx != SHN_UNDEF &&
            soaddr >= sym->st_value &&
@@ -575,7 +578,7 @@ Elf32_Sym *find_containing_symbol(const
 #if 0
 static void dump(soinfo *si)
 {
-    Elf32_Sym *s = si->symtab;
+    Elf_Sym *s = si->symtab;
     unsigned n;
 
     for(n = 0; n < si->nchain; n++) {
@@ -704,7 +707,7 @@ is_prelinked(int fd, const char *name)
 static int
 verify_elf_object(void *base, const char *name)
 {
-    Elf32_Ehdr *hdr = (Elf32_Ehdr *) base;
+    Elf_Ehdr *hdr = (Elf_Ehdr *) base;
 
     if (hdr->e_ident[EI_MAG0] != ELFMAG0) return -1;
     if (hdr->e_ident[EI_MAG1] != ELFMAG1) return -1;
@@ -749,8 +752,8 @@ get_lib_extents(int fd, const char *name
     unsigned min_vaddr = 0xffffffff;
     unsigned max_vaddr = 0;
     unsigned char *_hdr = (unsigned char *)__hdr;
-    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)_hdr;
-    Elf32_Phdr *phdr;
+    Elf_Ehdr *ehdr = (Elf_Ehdr *)_hdr;
+    Elf_Phdr *phdr;
     int cnt;
 
     TRACE("[ %5d Computing extents for '%s'. ]\n", pid, name);
@@ -769,7 +772,7 @@ get_lib_extents(int fd, const char *name
         TRACE("[ %5d - Non-prelinked library '%s' found. ]\n", pid, name);
     }
 
-    phdr = (Elf32_Phdr *)(_hdr + ehdr->e_phoff);
+    phdr = (Elf_Phdr *)(_hdr + ehdr->e_phoff);
 
     /* find the min/max p_vaddrs from all the PT_LOAD segments so we can
      * get the range. */
@@ -884,12 +887,12 @@ err:
 static int
 load_segments(int fd, void *header, soinfo *si)
 {
-    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header;
-    Elf32_Phdr *phdr = (Elf32_Phdr *)((unsigned char *)header + ehdr->e_phoff);
-    Elf32_Addr base = (Elf32_Addr) si->base;
+    Elf_Ehdr *ehdr = (Elf_Ehdr *)header;
+    Elf_Phdr *phdr = (Elf_Phdr *)((unsigned char *)header + ehdr->e_phoff);
+    Elf_Addr base = (Elf_Addr) si->base;
     int cnt;
     unsigned len;
-    Elf32_Addr tmp;
+    Elf_Addr tmp;
     unsigned char *pbase;
     unsigned char *extra_base;
     unsigned extra_len;
@@ -955,7 +958,7 @@ load_segments(int fd, void *header, soin
              *                  |                     |
              *                 _+---------------------+  page boundary
              */
-            tmp = (Elf32_Addr)(((unsigned)pbase + len + PAGE_SIZE - 1) &
+            tmp = (Elf_Addr)(((unsigned)pbase + len + PAGE_SIZE - 1) &
                                     (~PAGE_MASK));
             if (tmp < (base + phdr->p_vaddr + phdr->p_memsz)) {
                 extra_len = base + phdr->p_vaddr + phdr->p_memsz - tmp;
@@ -1019,7 +1022,7 @@ load_segments(int fd, void *header, soin
                        phdr->p_vaddr, phdr->p_memsz);
                 goto fail;
             }
-            si->gnu_relro_start = (Elf32_Addr) (base + phdr->p_vaddr);
+            si->gnu_relro_start = (Elf_Addr) (base + phdr->p_vaddr);
             si->gnu_relro_len = (unsigned) phdr->p_memsz;
         } else {
 #ifdef ANDROID_ARM_LINKER
@@ -1066,11 +1069,11 @@ fail:
  */
 #if 0
 static unsigned
-get_wr_offset(int fd, const char *name, Elf32_Ehdr *ehdr)
+get_wr_offset(int fd, const char *name, Elf_Ehdr *ehdr)
 {
-    Elf32_Shdr *shdr_start;
-    Elf32_Shdr *shdr;
-    int shdr_sz = ehdr->e_shnum * sizeof(Elf32_Shdr);
+    Elf_Shdr *shdr_start;
+    Elf_Shdr *shdr;
+    int shdr_sz = ehdr->e_shnum * sizeof(Elf_Shdr);
     int cnt;
     unsigned wr_offset = 0xffffffff;
 
@@ -1103,7 +1106,7 @@ load_library(const char *name)
     unsigned req_base;
     const char *bname;
     soinfo *si = NULL;
-    Elf32_Ehdr *hdr;
+    Elf_Ehdr *hdr;
 
     if(fd == -1) {
         DL_ERR("Library '%s' not found", name);
@@ -1160,8 +1163,8 @@ load_library(const char *name)
 
     /* this might not be right. Technically, we don't even need this info
      * once we go through 'load_segments'. */
-    hdr = (Elf32_Ehdr *)si->base;
-    si->phdr = (Elf32_Phdr *)((unsigned char *)si->base + hdr->e_phoff);
+    hdr = (Elf_Ehdr *)si->base;
+    si->phdr = (Elf_Phdr *)((unsigned char *)si->base + hdr->e_phoff);
     si->phnum = hdr->e_phnum;
     /**/
 
@@ -1260,7 +1263,7 @@ unsigned unload_library(soinfo *si)
          * in link_image. This is needed to undo the DT_NEEDED hack below.
          */
         if ((si->gnu_relro_start != 0) && (si->gnu_relro_len != 0)) {
-            Elf32_Addr start = (si->gnu_relro_start & ~PAGE_MASK);
+            Elf_Addr start = (si->gnu_relro_start & ~PAGE_MASK);
             unsigned len = (si->gnu_relro_start - start) + si->gnu_relro_len;
             if (mprotect((void *) start, len, PROT_READ | PROT_WRITE) < 0)
                 DL_ERR("%5d %s: could not undo GNU_RELRO protections. "
@@ -1303,16 +1306,16 @@ unsigned unload_library(soinfo *si)
 }
 
 /* TODO: don't use unsigned for addrs below. It works, but is not
- * ideal. They should probably be either uint32_t, Elf32_Addr, or unsigned
+ * ideal. They should probably be either uint32_t, Elf_Addr, or unsigned
  * long.
  */
-static int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count)
+static int reloc_library(soinfo *si, Elf_Rel *rel, unsigned count)
 {
-    Elf32_Sym *symtab = si->symtab;
+    Elf_Sym *symtab = si->symtab;
     const char *strtab = si->strtab;
-    Elf32_Sym *s;
+    Elf_Sym *s;
     unsigned base;
-    Elf32_Rel *start = rel;
+    Elf_Rel *start = rel;
     unsigned idx;
 
     for (idx = 0; idx < count; ++idx) {
@@ -1327,7 +1330,7 @@ static int reloc_library(soinfo *si, Elf
         if(sym != 0) {
             sym_name = (char *)(strtab + symtab[sym].st_name);
             INFO("HYBRIS: '%s' checking hooks for sym '%s'\n", si->name, sym_name);
-            sym_addr = get_hooked_symbol(sym_name);
+            sym_addr = _get_hooked_symbol(sym_name, si->name);
             if (sym_addr != NULL) {
                 INFO("HYBRIS: '%s' hooked symbol %s to %x\n", si->name,
                                                   sym_name, sym_addr);
@@ -1711,7 +1714,7 @@ static int nullify_closed_stdio (void)
 static int link_image(soinfo *si, unsigned wr_offset)
 {
     unsigned *d;
-    Elf32_Phdr *phdr = si->phdr;
+    Elf_Phdr *phdr = si->phdr;
     int phnum = si->phnum;
 
     INFO("[ %5d linking %s ]\n", pid, si->name);
@@ -1794,7 +1797,7 @@ static int link_image(soinfo *si, unsign
                            phdr->p_vaddr, phdr->p_memsz);
                     goto fail;
                 }
-                si->gnu_relro_start = (Elf32_Addr) (si->base + phdr->p_vaddr);
+                si->gnu_relro_start = (Elf_Addr) (si->base + phdr->p_vaddr);
                 si->gnu_relro_len = (unsigned) phdr->p_memsz;
             }
         }
@@ -1821,7 +1824,7 @@ static int link_image(soinfo *si, unsign
             si->strtab = (const char *) (si->base + *d);
             break;
         case DT_SYMTAB:
-            si->symtab = (Elf32_Sym *) (si->base + *d);
+            si->symtab = (Elf_Sym *) (si->base + *d);
             break;
         case DT_PLTREL:
             if(*d != DT_REL) {
@@ -1830,13 +1833,13 @@ static int link_image(soinfo *si, unsign
             }
             break;
         case DT_JMPREL:
-            si->plt_rel = (Elf32_Rel*) (si->base + *d);
+            si->plt_rel = (Elf_Rel*) (si->base + *d);
             break;
         case DT_PLTRELSZ:
             si->plt_rel_count = *d / 8;
             break;
         case DT_REL:
-            si->rel = (Elf32_Rel*) (si->base + *d);
+            si->rel = (Elf_Rel*) (si->base + *d);
             break;
         case DT_RELSZ:
             si->rel_count = *d / 8;
@@ -1868,7 +1871,7 @@ static int link_image(soinfo *si, unsign
                   pid, si->name, si->init_array);
             break;
         case DT_INIT_ARRAYSZ:
-            si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
+            si->init_array_count = ((unsigned)*d) / sizeof(Elf_Addr);
             break;
         case DT_FINI_ARRAY:
             si->fini_array = (unsigned *)(si->base + *d);
@@ -1876,7 +1879,7 @@ static int link_image(soinfo *si, unsign
                   pid, si->name, si->fini_array);
             break;
         case DT_FINI_ARRAYSZ:
-            si->fini_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
+            si->fini_array_count = ((unsigned)*d) / sizeof(Elf_Addr);
             break;
         case DT_PREINIT_ARRAY:
             si->preinit_array = (unsigned *)(si->base + *d);
@@ -1884,7 +1887,7 @@ static int link_image(soinfo *si, unsign
                   pid, si->name, si->preinit_array);
             break;
         case DT_PREINIT_ARRAYSZ:
-            si->preinit_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
+            si->preinit_array_count = ((unsigned)*d) / sizeof(Elf_Addr);
             break;
         case DT_TEXTREL:
             /* TODO: make use of this. */
@@ -1986,7 +1989,7 @@ static int link_image(soinfo *si, unsign
 #endif
 
     if (si->gnu_relro_start != 0 && si->gnu_relro_len != 0) {
-        Elf32_Addr start = (si->gnu_relro_start & ~PAGE_MASK);
+        Elf_Addr start = (si->gnu_relro_start & ~PAGE_MASK);
         unsigned len = (si->gnu_relro_start - start) + si->gnu_relro_len;
         if (mprotect((void *) start, len, PROT_READ) < 0) {
             DL_ERR("%5d GNU_RELRO mprotect of library '%s' failed: %d (%s)\n",
@@ -2169,7 +2172,7 @@ sanitize:
     while(vecs[0] != 0){
         switch(vecs[0]){
         case AT_PHDR:
-            si->phdr = (Elf32_Phdr*) vecs[1];
+            si->phdr = (Elf_Phdr*) vecs[1];
             break;
         case AT_PHNUM:
             si->phnum = (int) vecs[1];
@@ -2189,7 +2192,7 @@ sanitize:
     si->base = 0;
     for ( nn = 0; nn < si->phnum; nn++ ) {
         if (si->phdr[nn].p_type == PT_PHDR) {
-            si->base = (Elf32_Addr) si->phdr - si->phdr[nn].p_vaddr;
+            si->base = (Elf_Addr) si->phdr - si->phdr[nn].p_vaddr;
             break;
         }
     }
@@ -2302,9 +2305,9 @@ static unsigned find_linker_base(unsigne
  */
 unsigned __linker_init(unsigned **elfdata) {
     unsigned linker_addr = find_linker_base(elfdata);
-    Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_addr;
-    Elf32_Phdr *phdr =
-        (Elf32_Phdr *)((unsigned char *) linker_addr + elf_hdr->e_phoff);
+    Elf_Ehdr *elf_hdr = (Elf_Ehdr *) linker_addr;
+    Elf_Phdr *phdr =
+        (Elf_Phdr *)((unsigned char *) linker_addr + elf_hdr->e_phoff);
 
     soinfo linker_so;
     memset(&linker_so, 0, sizeof(soinfo));
@@ -2333,3 +2336,8 @@ unsigned __linker_init(unsigned **elfdat
     // the main part of the linker now.
     return __linker_init_post_relocation(elfdata);
 }
+
+void android_linker_init(int sdk_version, void *(get_hooked_symbol)(const char*, const char*)) {
+   (void) sdk_version;
+   _get_hooked_symbol = get_hooked_symbol;
+}
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/jb/linker.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/jb/linker.h
@@ -38,6 +38,26 @@
 #define PAGE_SIZE 4096
 #define PAGE_MASK 4095
 
+#if defined(__x86_64__)
+typedef Elf64_Ehdr Elf_Ehdr;
+typedef Elf64_Shdr Elf_Shdr;
+typedef Elf64_Sym  Elf_Sym;
+typedef Elf64_Addr Elf_Addr;
+typedef Elf64_Phdr Elf_Phdr;
+typedef Elf64_Half Elf_Half;
+typedef Elf64_Rel  Elf_Rel;
+typedef Elf64_Rela Elf_Rela;
+#else
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Shdr Elf_Shdr;
+typedef Elf32_Sym  Elf_Sym;
+typedef Elf32_Addr Elf_Addr;
+typedef Elf32_Phdr Elf_Phdr;
+typedef Elf32_Half Elf_Half;
+typedef Elf32_Rel  Elf_Rel;
+typedef Elf32_Rela Elf_Rela;
+#endif
+
 void debugger_init();
 const char *addr_to_name(unsigned addr);
 
@@ -55,10 +75,10 @@ struct link_map
 /* needed for dl_iterate_phdr to be passed to the callbacks provided */
 struct dl_phdr_info
 {
-    Elf32_Addr dlpi_addr;
+    Elf_Addr dlpi_addr;
     const char *dlpi_name;
-    const Elf32_Phdr *dlpi_phdr;
-    Elf32_Half dlpi_phnum;
+    const Elf_Phdr *dlpi_phdr;
+    Elf_Half dlpi_phnum;
 };
 
 
@@ -90,7 +110,7 @@ typedef struct soinfo soinfo;
 struct soinfo
 {
     const char name[SOINFO_NAME_LEN];
-    Elf32_Phdr *phdr;
+    Elf_Phdr *phdr;
     int phnum;
     unsigned entry;
     unsigned base;
@@ -107,7 +127,7 @@ struct soinfo
     unsigned flags;
 
     const char *strtab;
-    Elf32_Sym *symtab;
+    Elf_Sym *symtab;
 
     unsigned nbucket;
     unsigned nchain;
@@ -116,10 +136,10 @@ struct soinfo
 
     unsigned *plt_got;
 
-    Elf32_Rel *plt_rel;
+    Elf_Rel *plt_rel;
     unsigned plt_rel_count;
 
-    Elf32_Rel *rel;
+    Elf_Rel *rel;
     unsigned rel_count;
 
     unsigned *preinit_array;
@@ -144,7 +164,7 @@ struct soinfo
 
     int constructors_called;
 
-    Elf32_Addr gnu_relro_start;
+    Elf_Addr gnu_relro_start;
     unsigned gnu_relro_len;
 
 };
@@ -202,18 +222,17 @@ extern soinfo libdl_info;
 
 soinfo *find_library(const char *name);
 unsigned unload_library(soinfo *si);
-Elf32_Sym *lookup_in_library(soinfo *si, const char *name);
-Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start);
+Elf_Sym *lookup_in_library(soinfo *si, const char *name);
+Elf_Sym *lookup(const char *name, soinfo **found, soinfo *start);
 soinfo *find_containing_library(const void *addr);
-Elf32_Sym *find_containing_symbol(const void *addr, soinfo *si);
+Elf_Sym *find_containing_symbol(const void *addr, soinfo *si);
 const char *linker_get_error(void);
 void call_constructors_recursive(soinfo *si);
 
+int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *), void *);
 #ifdef ANDROID_ARM_LINKER 
 typedef long unsigned int *_Unwind_Ptr;
 _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount);
-#elif defined(ANDROID_X86_LINKER)
-int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *), void *);
 #endif
 
 #endif
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/jb/linker_environ.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/jb/linker_environ.c
@@ -25,6 +25,9 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
+#include "config.h"
+
 #include "linker_environ.h"
 #include <stddef.h>
 
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/jb/linker_format.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/jb/linker_format.c
@@ -26,6 +26,8 @@
  * SUCH DAMAGE.
  */
 
+#include "config.h"
+
 #include <stdarg.h>
 #include <string.h>
 #include <errno.h>
@@ -268,7 +270,7 @@ static int log_vprint(int prio, const ch
     result = vformat_buffer(buf, sizeof buf, fmt, args);
 
     if (log_fd < 0) {
-        log_fd = open("/dev/log/main", O_WRONLY);
+        log_fd = open("/dev/alog/main", O_WRONLY);
         if (log_fd < 0) {
             log_fd = fileno(stdout); // kernel doesn't have android log
             return result;
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/Makefile.am
@@ -0,0 +1,52 @@
+bionic = $(top_srcdir)/common/mm/bionic
+bionic_libc = $(bionic)/libc
+
+modlibexecdir = $(libdir)/libhybris/linker
+modlibexec_LTLIBRARIES = mm.la
+
+ARCH_FLAGS =
+
+AM_CFLAGS = \
+	-std=gnu99
+
+AM_CPPFLAGS = \
+	-fno-stack-protector \
+	-Wstrict-overflow=5
+
+AM_CXXFLAGS = \
+	-std=gnu++11 \
+	-Wold-style-cast
+
+mm_la_SOURCES = \
+	hybris_compat.cpp \
+	dlfcn.cpp \
+	linker_allocator.cpp \
+	linker_block_allocator.cpp \
+	linker.cpp \
+	linker_memory.cpp \
+	linker_phdr.cpp \
+	linker_sdk_versions.cpp \
+	rt.cpp \
+	../strlcpy.c \
+	../strlcat.c
+mm_la_CPPFLAGS = \
+	$(AM_CPPFLAGS) \
+	-I$(top_srcdir)/include \
+	-I$(top_srcdir)/common \
+	-I$(bionic_libc)/ \
+	-I$(bionic_libc)/include \
+	-DDEFAULT_HYBRIS_LD_LIBRARY_PATH="\"@DEFAULT_HYBRIS_LD_LIBRARY_PATH@\"" \
+	$(ARCH_FLAGS) \
+	$(ANDROID_HEADERS_CFLAGS)
+mm_la_LDFLAGS = \
+	-lsupc++ \
+	-module \
+	-avoid-version
+
+if WANT_DEBUG
+mm_la_CPPFLAGS += \
+	-DTRACE_DEBUG=1
+else
+mm_la_CPPFLAGS += \
+	-DTRACE_DEBUG=1
+endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/NOTICE
@@ -0,0 +1,204 @@
+Copyright (C) 2007 The Android Open Source 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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2008 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2010 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2012 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2013 The Android Open Source 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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2013 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2014 The Android Open Source 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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2015 The Android Open Source 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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2015 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/bionic/pthread_internal.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef _PTHREAD_INTERNAL_H_
+#define _PTHREAD_INTERNAL_H_
+
+#include <pthread.h>
+#include <atomic>
+
+#include "private/bionic_tls.h"
+
+/* Has the thread been detached by a pthread_join or pthread_detach call? */
+#define PTHREAD_ATTR_FLAG_DETACHED 0x00000001
+
+/* Has the thread been joined by another thread? */
+#define PTHREAD_ATTR_FLAG_JOINED 0x00000002
+
+struct pthread_key_data_t {
+  uintptr_t seq; // Use uintptr_t just for alignment, as we use pointer below.
+  void* data;
+};
+
+enum ThreadJoinState {
+  THREAD_NOT_JOINED,
+  THREAD_EXITED_NOT_JOINED,
+  THREAD_JOINED,
+  THREAD_DETACHED
+};
+
+struct pthread_internal_t {
+  struct pthread_internal_t* next;
+  struct pthread_internal_t* prev;
+
+  pid_t tid;
+
+ private:
+  pid_t cached_pid_;
+
+ public:
+  pid_t invalidate_cached_pid() {
+    pid_t old_value;
+    get_cached_pid(&old_value);
+    set_cached_pid(0);
+    return old_value;
+  }
+
+  void set_cached_pid(pid_t value) {
+    cached_pid_ = value;
+  }
+
+  bool get_cached_pid(pid_t* cached_pid) {
+    *cached_pid = cached_pid_;
+    return (*cached_pid != 0);
+  }
+
+  pthread_attr_t attr;
+
+  ThreadJoinState join_state;
+
+  //__pthread_cleanup_t* cleanup_stack;
+
+  void* (*start_routine)(void*);
+  void* start_routine_arg;
+  void* return_value;
+
+  void* alternate_signal_stack;
+
+  pthread_mutex_t startup_handshake_mutex;
+
+  size_t mmap_size;
+
+  void* tls[BIONIC_TLS_SLOTS];
+
+  pthread_key_data_t key_data[BIONIC_PTHREAD_KEY_COUNT];
+
+  /*
+   * The dynamic linker implements dlerror(3), which makes it hard for us to implement this
+   * per-thread buffer by simply using malloc(3) and free(3).
+   */
+#define __BIONIC_DLERROR_BUFFER_SIZE 512
+  char dlerror_buffer[__BIONIC_DLERROR_BUFFER_SIZE];
+};
+
+ int __init_thread(pthread_internal_t* thread);
+ void __init_tls(pthread_internal_t* thread);
+ void __init_alternate_signal_stack(pthread_internal_t*);
+
+ pthread_t           __pthread_internal_add(pthread_internal_t* thread);
+ pthread_internal_t* __pthread_internal_find(pthread_t pthread_id);
+ void                __pthread_internal_remove(pthread_internal_t* thread);
+ void                __pthread_internal_remove_and_free(pthread_internal_t* thread);
+
+// Make __get_thread() inlined for performance reason. See http://b/19825434.
+static inline pthread_internal_t* __get_thread() {
+  return reinterpret_cast<pthread_internal_t*>(__get_tls()[TLS_SLOT_THREAD_ID]);
+}
+
+ void pthread_key_clean_all(void);
+
+/*
+ * Traditionally we gave threads a 1MiB stack. When we started
+ * allocating per-thread alternate signal stacks to ease debugging of
+ * stack overflows, we subtracted the same amount we were using there
+ * from the default thread stack size. This should keep memory usage
+ * roughly constant.
+ */
+#define PTHREAD_STACK_SIZE_DEFAULT ((1 * 1024 * 1024) - SIGSTKSZ)
+
+/* Leave room for a guard page in the internally created signal stacks. */
+#define SIGNAL_STACK_SIZE (SIGSTKSZ + PAGE_SIZE)
+
+/* Needed by fork. */
+ extern void __bionic_atfork_run_prepare();
+ extern void __bionic_atfork_run_child();
+ extern void __bionic_atfork_run_parent();
+
+#endif /* _PTHREAD_INTERNAL_H_ */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/include/android/api-level.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_API_LEVEL_H
+#define ANDROID_API_LEVEL_H
+
+/*
+ * Magic version number for a current development build, which has
+ * not yet turned into an official release.
+ */
+#define __ANDROID_API__ 10000
+
+#endif /* ANDROID_API_LEVEL_H */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/include/android/dlext.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 The Android Open Source 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.
+ */
+
+#ifndef __ANDROID_DLEXT_H__
+#define __ANDROID_DLEXT_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>  /* for off64_t */
+
+__BEGIN_DECLS
+
+/* bitfield definitions for android_dlextinfo.flags */
+enum {
+  /* When set, the reserved_addr and reserved_size fields must point to an
+   * already-reserved region of address space which will be used to load the
+   * library if it fits. If the reserved region is not large enough, the load
+   * will fail.
+   */
+  ANDROID_DLEXT_RESERVED_ADDRESS      = 0x1,
+
+  /* As DLEXT_RESERVED_ADDRESS, but if the reserved region is not large enough,
+   * the linker will choose an available address instead.
+   */
+  ANDROID_DLEXT_RESERVED_ADDRESS_HINT = 0x2,
+
+  /* When set, write the GNU RELRO section of the mapped library to relro_fd
+   * after relocation has been performed, to allow it to be reused by another
+   * process loading the same library at the same address. This implies
+   * ANDROID_DLEXT_USE_RELRO.
+   */
+  ANDROID_DLEXT_WRITE_RELRO           = 0x4,
+
+  /* When set, compare the GNU RELRO section of the mapped library to relro_fd
+   * after relocation has been performed, and replace any relocated pages that
+   * are identical with a version mapped from the file.
+   */
+  ANDROID_DLEXT_USE_RELRO             = 0x8,
+
+  /* Instruct dlopen to use library_fd instead of opening file by name.
+   * The filename parameter is still used to identify the library.
+   */
+  ANDROID_DLEXT_USE_LIBRARY_FD        = 0x10,
+
+  /* If opening a library using library_fd read it starting at library_fd_offset.
+   * This flag is only valid when ANDROID_DLEXT_USE_LIBRARY_FD is set.
+   */
+  ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET    = 0x20,
+
+  /* When set, do not check if the library has already been loaded by file stat(2)s.
+   *
+   * This flag allows forced loading of the library in the case when for some
+   * reason multiple ELF files share the same filename (because the already-loaded
+   * library has been removed and overwritten, for example).
+   *
+   * Note that if the library has the same dt_soname as an old one and some other
+   * library has the soname in DT_NEEDED list, the first one will be used to resolve any
+   * dependencies.
+   */
+  ANDROID_DLEXT_FORCE_LOAD = 0x40,
+
+  /* When set, if the minimum p_vaddr of the ELF file's PT_LOAD segments is non-zero,
+   * the dynamic linker will load it at that address.
+   *
+   * This flag is for ART internal use only.
+   */
+  ANDROID_DLEXT_FORCE_FIXED_VADDR = 0x80,
+
+  /* Mask of valid bits */
+  ANDROID_DLEXT_VALID_FLAG_BITS       = ANDROID_DLEXT_RESERVED_ADDRESS |
+                                        ANDROID_DLEXT_RESERVED_ADDRESS_HINT |
+                                        ANDROID_DLEXT_WRITE_RELRO |
+                                        ANDROID_DLEXT_USE_RELRO |
+                                        ANDROID_DLEXT_USE_LIBRARY_FD |
+                                        ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET |
+                                        ANDROID_DLEXT_FORCE_LOAD |
+                                        ANDROID_DLEXT_FORCE_FIXED_VADDR,
+};
+
+typedef struct {
+  uint64_t flags;
+  void*   reserved_addr;
+  size_t  reserved_size;
+  int     relro_fd;
+  int     library_fd;
+  off64_t library_fd_offset;
+} android_dlextinfo;
+
+extern void* android_dlopen_ext(const char* filename, int flag, const android_dlextinfo* extinfo);
+
+__END_DECLS
+
+#endif /* __ANDROID_DLEXT_H__ */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/include/link.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef _LINK_H_
+#define _LINK_H_
+
+#include <sys/types.h>
+#include <elf.h>
+
+__BEGIN_DECLS
+
+#if __LP64__
+#define ElfW(type) Elf64_ ## type
+#else
+#define ElfW(type) Elf32_ ## type
+#endif
+
+struct dl_phdr_info {
+  ElfW(Addr) dlpi_addr;
+  const char* dlpi_name;
+  const ElfW(Phdr)* dlpi_phdr;
+  ElfW(Half) dlpi_phnum;
+};
+
+int dl_iterate_phdr(int (*)(struct dl_phdr_info*, size_t, void*), void*);
+
+#ifdef __arm__
+typedef long unsigned int* _Unwind_Ptr;
+_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr, int*);
+#endif
+
+/* Used by the dynamic linker to communicate with the debugger. */
+struct link_map {
+  ElfW(Addr) l_addr;
+  char* l_name;
+  ElfW(Dyn)* l_ld;
+  struct link_map* l_next;
+  struct link_map* l_prev;
+};
+
+/* Used by the dynamic linker to communicate with the debugger. */
+struct r_debug {
+  int32_t r_version;
+  struct link_map* r_map;
+  ElfW(Addr) r_brk;
+  enum {
+    RT_CONSISTENT,
+    RT_ADD,
+    RT_DELETE
+  } r_state;
+  ElfW(Addr) r_ldbase;
+};
+
+__END_DECLS
+
+#endif /* _LINK_H_ */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/ErrnoRestorer.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 The Android Open Source 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.
+ */
+
+#ifndef ERRNO_RESTORER_H
+#define ERRNO_RESTORER_H
+
+#include <errno.h>
+
+#include "bionic_macros.h"
+
+class ErrnoRestorer {
+ public:
+  explicit ErrnoRestorer() : saved_errno_(errno) {
+  }
+
+  ~ErrnoRestorer() {
+    errno = saved_errno_;
+  }
+
+  void override(int new_errno) {
+    saved_errno_ = new_errno;
+  }
+
+ private:
+  int saved_errno_;
+
+  DISALLOW_COPY_AND_ASSIGN(ErrnoRestorer);
+};
+
+#endif // ERRNO_RESTORER_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/KernelArgumentBlock.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 The Android Open Source 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.
+ */
+
+#ifndef KERNEL_ARGUMENT_BLOCK_H
+#define KERNEL_ARGUMENT_BLOCK_H
+
+#include <elf.h>
+#include <link.h>
+#include <stdint.h>
+#include <sys/auxv.h>
+
+#include "private/bionic_macros.h"
+
+struct abort_msg_t;
+
+// When the kernel starts the dynamic linker, it passes a pointer to a block
+// of memory containing argc, the argv array, the environment variable array,
+// and the array of ELF aux vectors. This class breaks that block up into its
+// constituents for easy access.
+class KernelArgumentBlock {
+ public:
+  KernelArgumentBlock(void* raw_args) {
+    uintptr_t* args = reinterpret_cast<uintptr_t*>(raw_args);
+    argc = static_cast<int>(*args);
+    argv = reinterpret_cast<char**>(args + 1);
+    envp = argv + argc + 1;
+
+    // Skip over all environment variable definitions to find aux vector.
+    // The end of the environment block is marked by two NULL pointers.
+    char** p = envp;
+    while (*p != NULL) {
+      ++p;
+    }
+    ++p; // Skip second NULL;
+
+    auxv = reinterpret_cast<ElfW(auxv_t)*>(p);
+  }
+
+  // Similar to ::getauxval but doesn't require the libc global variables to be set up,
+  // so it's safe to call this really early on. This function also lets you distinguish
+  // between the inability to find the given type and its value just happening to be 0.
+  unsigned long getauxval(unsigned long type, bool* found_match = NULL) {
+    for (ElfW(auxv_t)* v = auxv; v->a_type != AT_NULL; ++v) {
+      if (v->a_type == type) {
+        if (found_match != NULL) {
+            *found_match = true;
+        }
+        return v->a_un.a_val;
+      }
+    }
+    if (found_match != NULL) {
+      *found_match = false;
+    }
+    return 0;
+  }
+
+  int argc;
+  char** argv;
+  char** envp;
+  ElfW(auxv_t)* auxv;
+
+  abort_msg_t** abort_message_ptr;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(KernelArgumentBlock);
+};
+
+#endif // KERNEL_ARGUMENT_BLOCK_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/NetdClientDispatch.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2014 The Android Open Source 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.
+ */
+
+#ifndef PRIVATE_NETD_CLIENT_DISPATCH_H
+#define PRIVATE_NETD_CLIENT_DISPATCH_H
+
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+
+__BEGIN_DECLS
+
+struct NetdClientDispatch {
+    int (*accept4)(int, struct sockaddr*, socklen_t*, int);
+    int (*connect)(int, const struct sockaddr*, socklen_t);
+    int (*socket)(int, int, int);
+    unsigned (*netIdForResolv)(unsigned);
+};
+
+extern  struct NetdClientDispatch __netdClientDispatch;
+
+__END_DECLS
+
+#endif  // PRIVATE_NETD_CLIENT_DISPATCH_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/ScopeGuard.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 The Android Open Source 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.
+ */
+
+#ifndef _SCOPE_GUARD_H
+#define _SCOPE_GUARD_H
+
+#include "private/bionic_macros.h"
+
+// TODO: include explicit std::move when it becomes available
+template<typename F>
+class ScopeGuard {
+ public:
+  ScopeGuard(F f) : f_(f), active_(true) {}
+
+  ScopeGuard(ScopeGuard&& that) : f_(that.f_), active_(that.active_) {
+    that.active_ = false;
+  }
+
+  ~ScopeGuard() {
+    if (active_) {
+      f_();
+    }
+  }
+
+  void disable() {
+    active_ = false;
+  }
+ private:
+  F f_;
+  bool active_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeGuard);
+};
+
+template<typename T>
+ScopeGuard<T> make_scope_guard(T f) {
+  return ScopeGuard<T>(f);
+}
+
+#endif  // _SCOPE_GUARD_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/ScopedPthreadMutexLocker.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 The Android Open Source 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.
+ */
+
+#ifndef SCOPED_PTHREAD_MUTEX_LOCKER_H
+#define SCOPED_PTHREAD_MUTEX_LOCKER_H
+
+#include <pthread.h>
+
+#include "bionic_macros.h"
+
+class ScopedPthreadMutexLocker {
+ public:
+  explicit ScopedPthreadMutexLocker(pthread_mutex_t* mu) : mu_(mu) {
+    pthread_mutex_lock(mu_);
+  }
+
+  ~ScopedPthreadMutexLocker() {
+    pthread_mutex_unlock(mu_);
+  }
+
+ private:
+  pthread_mutex_t* mu_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPthreadMutexLocker);
+};
+
+#endif // SCOPED_PTHREAD_MUTEX_LOCKER_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/ScopedReaddir.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2013 The Android Open Source 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.
+ */
+
+#ifndef SCOPED_READDIR_H
+#define SCOPED_READDIR_H
+
+#include <dirent.h>
+
+#include "private/bionic_macros.h"
+
+class ScopedReaddir {
+ public:
+  ScopedReaddir(const char* path) {
+    dir_ = opendir(path);
+  }
+
+  ~ScopedReaddir() {
+    if (dir_ != NULL) {
+      closedir(dir_);
+    }
+  }
+
+  bool IsBad() {
+    return dir_ == NULL;
+  }
+
+  dirent* ReadEntry() {
+    return readdir(dir_);
+  }
+
+ private:
+  DIR* dir_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedReaddir);
+};
+
+#endif // SCOPED_READDIR_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/ThreadLocalBuffer.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BIONIC_THREAD_LOCAL_BUFFER_H_included
+#define _BIONIC_THREAD_LOCAL_BUFFER_H_included
+
+#include <malloc.h>
+#include <pthread.h>
+
+// TODO: use __thread instead?
+
+template <typename T, size_t Size = sizeof(T)>
+class ThreadLocalBuffer {
+ public:
+  ThreadLocalBuffer() {
+    // We used to use pthread_once to initialize the keys, but life is more predictable
+    // if we allocate them all up front when the C library starts up, via __constructor__.
+    pthread_key_create(&key_, free);
+  }
+
+  T* get() {
+    T* result = reinterpret_cast<T*>(pthread_getspecific(key_));
+    if (result == nullptr) {
+      result = reinterpret_cast<T*>(calloc(1, Size));
+      pthread_setspecific(key_, result);
+    }
+    return result;
+  }
+
+  size_t size() { return Size; }
+
+ private:
+  pthread_key_t key_;
+};
+
+#endif // _BIONIC_THREAD_LOCAL_BUFFER_H_included
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/UniquePtr.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2010 The Android Open Source 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.
+ */
+
+#ifndef UNIQUE_PTR_H_included
+#define UNIQUE_PTR_H_included
+
+// Default deleter for pointer types.
+template <typename T>
+struct DefaultDelete {
+    enum { type_must_be_complete = sizeof(T) };
+    DefaultDelete() {}
+    void operator()(T* p) const {
+        delete p;
+    }
+};
+
+// Default deleter for array types.
+template <typename T>
+struct DefaultDelete<T[]> {
+    enum { type_must_be_complete = sizeof(T) };
+    void operator()(T* p) const {
+        delete[] p;
+    }
+};
+
+// A smart pointer that deletes the given pointer on destruction.
+// Equivalent to C++0x's std::unique_ptr (a combination of boost::scoped_ptr
+// and boost::scoped_array).
+// Named to be in keeping with Android style but also to avoid
+// collision with any other implementation, until we can switch over
+// to unique_ptr.
+// Use thus:
+//   UniquePtr<C> c(new C);
+template <typename T, typename D = DefaultDelete<T> >
+class UniquePtr {
+public:
+    // Construct a new UniquePtr, taking ownership of the given raw pointer.
+    explicit UniquePtr(T* ptr = nullptr) : mPtr(ptr) { }
+
+    UniquePtr(UniquePtr<T, D>&& that) {
+      mPtr = that.mPtr;
+      that.mPtr = nullptr;
+    }
+
+    ~UniquePtr() {
+        reset();
+    }
+
+    // Accessors.
+    T& operator*() const { return *mPtr; }
+    T* operator->() const { return mPtr; }
+    T* get() const { return mPtr; }
+
+    // Returns the raw pointer and hands over ownership to the caller.
+    // The pointer will not be deleted by UniquePtr.
+    T* release() __attribute__((warn_unused_result)) {
+        T* result = mPtr;
+        mPtr = nullptr;
+        return result;
+    }
+
+    // Takes ownership of the given raw pointer.
+    // If this smart pointer previously owned a different raw pointer, that
+    // raw pointer will be freed.
+    void reset(T* ptr = nullptr) {
+        if (ptr != mPtr) {
+            D()(mPtr);
+            mPtr = ptr;
+        }
+    }
+
+private:
+    // The raw pointer.
+    T* mPtr;
+
+    // Comparing unique pointers is probably a mistake, since they're unique.
+    template <typename T2> bool operator==(const UniquePtr<T2>& p) const = delete;
+    template <typename T2> bool operator!=(const UniquePtr<T2>& p) const = delete;
+
+    // Disallow copy and assignment.
+    UniquePtr(const UniquePtr&) = delete;
+    void operator=(const UniquePtr&) = delete;
+};
+
+// Partial specialization for array types. Like std::unique_ptr, this removes
+// operator* and operator-> but adds operator[].
+template <typename T, typename D>
+class UniquePtr<T[], D> {
+public:
+    explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) {
+    }
+    UniquePtr(UniquePtr<T, D>&& that) {
+      mPtr = that.mPtr;
+      that.mPtr = nullptr;
+    }
+
+    ~UniquePtr() {
+        reset();
+    }
+
+    T& operator[](size_t i) const {
+        return mPtr[i];
+    }
+    T* get() const { return mPtr; }
+
+    T* release() __attribute__((warn_unused_result)) {
+        T* result = mPtr;
+        mPtr = NULL;
+        return result;
+    }
+
+    void reset(T* ptr = NULL) {
+        if (ptr != mPtr) {
+            D()(mPtr);
+            mPtr = ptr;
+        }
+    }
+
+private:
+    T* mPtr;
+
+    // Disallow copy and assignment.
+    UniquePtr(const UniquePtr&) = delete;
+    void operator=(const UniquePtr&) = delete;
+};
+
+#endif  // UNIQUE_PTR_H_included
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/__get_tls.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __BIONIC_PRIVATE_GET_TLS_H_
+#define __BIONIC_PRIVATE_GET_TLS_H_
+
+#if defined(__aarch64__)
+# define __get_tls() ({ void** __val; __asm__("mrs %0, tpidr_el0" : "=r"(__val)); __val; })
+#elif defined(__arm__)
+# define __get_tls() ({ void** __val; __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__val)); __val; })
+#elif defined(__mips__)
+# define __get_tls() \
+    /* On mips32r1, this goes via a kernel illegal instruction trap that's optimized for v1. */ \
+    ({ register void** __val asm("v1"); \
+       __asm__(".set    push\n" \
+               ".set    mips32r2\n" \
+               "rdhwr   %0,$29\n" \
+               ".set    pop\n" : "=r"(__val)); \
+       __val; })
+#elif defined(__i386__)
+# define __get_tls() ({ void** __val; __asm__("movl %%gs:0, %0" : "=r"(__val)); __val; })
+#elif defined(__x86_64__)
+# define __get_tls() ({ void** __val; __asm__("mov %%fs:0, %0" : "=r"(__val)); __val; })
+#else
+#error unsupported architecture
+#endif
+
+#endif /* __BIONIC_PRIVATE_GET_TLS_H_ */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_asm.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _PRIVATE_BIONIC_ASM_H_
+#define _PRIVATE_BIONIC_ASM_H_
+
+#include <asm/unistd.h> /* For system call numbers. */
+#define MAX_ERRNO 4095  /* For recognizing system call error returns. */
+
+#define __bionic_asm_custom_entry(f)
+#define __bionic_asm_custom_end(f)
+#define __bionic_asm_function_type @function
+
+#include <machine/asm.h>
+
+#define ENTRY(f) \
+    .text; \
+    .globl f; \
+    .align __bionic_asm_align; \
+    .type f, __bionic_asm_function_type; \
+    f: \
+    __bionic_asm_custom_entry(f); \
+    .cfi_startproc \
+
+#define END(f) \
+    .cfi_endproc; \
+    .size f, .-f; \
+    __bionic_asm_custom_end(f) \
+
+/* Like ENTRY, but with hidden visibility. */
+#define ENTRY_PRIVATE(f) \
+    ENTRY(f); \
+    .hidden f \
+
+#define ALIAS_SYMBOL(alias, original) \
+    .globl alias; \
+    .equ alias, original
+
+#endif /* _PRIVATE_BIONIC_ASM_H_ */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_auxv.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef _PRIVATE_BIONIC_AUXV_H_
+#define _PRIVATE_BIONIC_AUXV_H_
+
+#include <elf.h>
+#include <link.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern ElfW(auxv_t)* __libc_auxv;
+
+__END_DECLS
+
+#endif /* _PRIVATE_BIONIC_AUXV_H_ */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_config.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 The Android Open Source 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.
+ */
+
+#ifndef _BIONIC_CONFIG_H_
+#define _BIONIC_CONFIG_H_
+
+// valloc(3) and pvalloc(3) were removed from POSIX 2004. We do not include them
+// for LP64, but the symbols remain in LP32 for binary compatibility.
+#if !defined(__LP64__)
+#define HAVE_DEPRECATED_MALLOC_FUNCS 1
+#endif
+
+#endif // _BIONIC_CONFIG_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_constants.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 The Android Open Source 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.
+ */
+
+#ifndef _BIONIC_CONSTANTS_H_
+#define _BIONIC_CONSTANTS_H_
+
+#define NS_PER_S 1000000000
+
+#endif // _BIONIC_CONSTANTS_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_futex.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#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 */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_lock.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef _BIONIC_LOCK_H
+#define _BIONIC_LOCK_H
+
+#include <stdatomic.h>
+#include "private/bionic_futex.h"
+
+class Lock {
+ private:
+  enum LockState {
+    Unlocked = 0,
+    LockedWithoutWaiter,
+    LockedWithWaiter,
+  };
+  _Atomic(LockState) state;
+  bool process_shared;
+
+ public:
+  Lock(bool process_shared = false) {
+    init(process_shared);
+  }
+
+  void init(bool process_shared) {
+    atomic_init(&state, Unlocked);
+    this->process_shared = process_shared;
+  }
+
+  void lock() {
+    LockState old_state = Unlocked;
+    if (__predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
+                         LockedWithoutWaiter, memory_order_acquire, memory_order_relaxed))) {
+      return;
+    }
+    while (atomic_exchange_explicit(&state, LockedWithWaiter, memory_order_acquire) != Unlocked) {
+      // TODO: As the critical section is brief, it is a better choice to spin a few times befor sleeping.
+      __futex_wait_ex(&state, process_shared, LockedWithWaiter, NULL);
+    }
+    return;
+  }
+
+  void unlock() {
+    if (atomic_exchange_explicit(&state, Unlocked, memory_order_release) == LockedWithWaiter) {
+      __futex_wake_ex(&state, process_shared, 1);
+    }
+  }
+};
+
+#endif  // _BIONIC_LOCK_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_macros.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 The Android Open Source 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.
+ */
+
+#ifndef _BIONIC_MACROS_H_
+#define _BIONIC_MACROS_H_
+
+// Frameworks OpenGL code currently leaks this header and allows
+// collisions with other declarations, e.g., from libnativehelper.
+// TODO: Remove once cleaned up. b/18334516
+#if !defined(DISALLOW_COPY_AND_ASSIGN)
+// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions.
+// It goes in the private: declarations in a class.
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&) = delete;      \
+  void operator=(const TypeName&) = delete
+#endif  // !defined(DISALLOW_COPY_AND_ASSIGN)
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName() = delete;                           \
+  DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+#define BIONIC_ALIGN(value, alignment) \
+  (((value) + (alignment) - 1) & ~((alignment) - 1))
+
+#define BIONIC_ROUND_UP_POWER_OF_2(value) \
+  (sizeof(value) == 8) \
+    ? (1UL << (64 - __builtin_clzl(static_cast<unsigned long>(value)))) \
+    : (1UL << (32 - __builtin_clz(static_cast<unsigned int>(value))))
+
+#endif // _BIONIC_MACROS_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_mbstate.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BIONIC_MBSTATE_H
+#define _BIONIC_MBSTATE_H
+
+#include <wchar.h>
+
+__BEGIN_DECLS
+
+/*
+ * These return values are specified by POSIX for multibyte conversion
+ * functions.
+ */
+#define __MB_ERR_ILLEGAL_SEQUENCE static_cast<size_t>(-1)
+#define __MB_ERR_INCOMPLETE_SEQUENCE static_cast<size_t>(-2)
+
+#define __MB_IS_ERR(rv) (rv == __MB_ERR_ILLEGAL_SEQUENCE || \
+                         rv == __MB_ERR_INCOMPLETE_SEQUENCE)
+
+size_t mbstate_bytes_so_far(const mbstate_t* ps);
+void mbstate_set_byte(mbstate_t* ps, int i, char byte);
+uint8_t mbstate_get_byte(const mbstate_t* ps, int n);
+size_t reset_and_return_illegal(int _errno, mbstate_t* ps);
+size_t reset_and_return(int _return, mbstate_t* ps);
+
+__END_DECLS
+
+#endif // _BIONIC_MBSTATE_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_prctl.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 The Android Open Source 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.
+ */
+
+#ifndef BIONIC_PRCTL_H
+#define BIONIC_PRCTL_H
+
+#include <sys/prctl.h>
+
+// This is only supported by Android kernels, so it's not in the uapi headers.
+#define PR_SET_VMA   0x53564d41
+#define PR_SET_VMA_ANON_NAME    0
+
+#endif // BIONIC_PRCTL_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_ssp.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _PRIVATE_SSP_H
+#define _PRIVATE_SSP_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* GCC uses this on ARM and MIPS; we use it on x86 to set the guard in TLS. */
+extern uintptr_t __stack_chk_guard;
+
+/* GCC calls this if a stack guard check fails. */
+extern void __stack_chk_fail();
+
+__END_DECLS
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_string_utils.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source 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.
+ */
+
+#ifndef _BIONIC_STRING_UTILS_H_
+#define _BIONIC_STRING_UTILS_H_
+
+#include <string.h>
+
+static inline bool ends_with(const char* s1, const char* s2) {
+  size_t s1_length = strlen(s1);
+  size_t s2_length = strlen(s2);
+  if (s2_length > s1_length) {
+    return false;
+  }
+  return memcmp(s1 + (s1_length - s2_length), s2, s2_length) == 0;
+}
+
+#endif // _BIONIC_STRING_UTILS_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_systrace.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source 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.
+ */
+
+#ifndef BIONIC_SYSTRACE_H
+#define BIONIC_SYSTRACE_H
+
+#include "bionic_macros.h"
+
+// Tracing class for bionic. To begin a trace at a specified point:
+//   ScopedTrace("Trace message");
+// The trace will end when the contructor goes out of scope.
+
+class  ScopedTrace {
+ public:
+  explicit ScopedTrace(const char* message);
+  ~ScopedTrace();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedTrace);
+};
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_time.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef _BIONIC_TIME_H
+#define _BIONIC_TIME_H
+
+#include <time.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+// We can't remove this (and this file) until we fix MtpUtils.cpp.
+time_t mktime_tz(struct tm* const, char const*);
+
+__END_DECLS
+
+#endif /* _BIONIC_TIME_H */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_time_conversions.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BIONIC_TIME_CONVERSIONS_H
+#define _BIONIC_TIME_CONVERSIONS_H
+
+#include <time.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+ bool timespec_from_timeval(timespec& ts, const timeval& tv);
+ void timespec_from_ms(timespec& ts, const int ms);
+
+ void timeval_from_timespec(timeval& tv, const timespec& ts);
+
+ bool timespec_from_absolute_timespec(timespec& ts, const timespec& abs_ts, clockid_t clock);
+
+__END_DECLS
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/bionic_tls.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __BIONIC_PRIVATE_BIONIC_TLS_H_
+#define __BIONIC_PRIVATE_BIONIC_TLS_H_
+
+#include <sys/cdefs.h>
+#include <limits.h>
+#include "bionic_macros.h"
+#include "__get_tls.h"
+
+__BEGIN_DECLS
+
+/** WARNING WARNING WARNING
+ **
+ ** This header file is *NOT* part of the public Bionic ABI/API
+ ** and should not be used/included by user-serviceable parts of
+ ** the system (e.g. applications).
+ **
+ ** It is only provided here for the benefit of the system dynamic
+ ** linker and the OpenGL sub-system (which needs to access the
+ ** pre-allocated slot directly for performance reason).
+ **/
+
+// Well-known TLS slots. What data goes in which slot is arbitrary unless otherwise noted.
+enum {
+  TLS_SLOT_SELF = 0, // The kernel requires this specific slot for x86.
+  TLS_SLOT_THREAD_ID,
+  TLS_SLOT_ERRNO = 5,
+
+  // These two aren't used by bionic itself, but allow the graphics code to
+  // access TLS directly rather than using the pthread API.
+  TLS_SLOT_OPENGL_API = 6,
+  TLS_SLOT_OPENGL = 7,
+
+  // This slot is only used to pass information from the dynamic linker to
+  // libc.so when the C library is loaded in to memory. The C runtime init
+  // function will then clear it. Since its use is extremely temporary,
+  // we reuse an existing location that isn't needed during libc startup.
+  TLS_SLOT_BIONIC_PREINIT = TLS_SLOT_OPENGL_API,
+
+  TLS_SLOT_STACK_GUARD = 8, // GCC requires this specific slot for x86.
+  TLS_SLOT_DLERROR,
+
+  BIONIC_TLS_SLOTS // Must come last!
+};
+
+/*
+ * Bionic uses some pthread keys internally. All pthread keys used internally
+ * should be created in constructors, except for keys that may be used in or
+ * before constructors.
+ *
+ * We need to manually maintain the count of pthread keys used internally, but
+ * pthread_test should fail if we forget.
+ *
+ * These are the pthread keys currently used internally by libc:
+ *
+ *  basename               libc (ThreadLocalBuffer)
+ *  dirname                libc (ThreadLocalBuffer)
+ *  uselocale              libc (can be used in constructors)
+ *  getmntent_mntent       libc (ThreadLocalBuffer)
+ *  getmntent_strings      libc (ThreadLocalBuffer)
+ *  ptsname                libc (ThreadLocalBuffer)
+ *  ttyname                libc (ThreadLocalBuffer)
+ *  strerror               libc (ThreadLocalBuffer)
+ *  strsignal              libc (ThreadLocalBuffer)
+ *  passwd                 libc (ThreadLocalBuffer)
+ *  group                  libc (ThreadLocalBuffer)
+ *  _res_key               libc (constructor in BSD code)
+ */
+
+#define LIBC_PTHREAD_KEY_RESERVED_COUNT 12
+
+#if defined(USE_JEMALLOC)
+/* Internally, jemalloc uses a single key for per thread data. */
+#define JEMALLOC_PTHREAD_KEY_RESERVED_COUNT 1
+#define BIONIC_PTHREAD_KEY_RESERVED_COUNT (LIBC_PTHREAD_KEY_RESERVED_COUNT + JEMALLOC_PTHREAD_KEY_RESERVED_COUNT)
+#else
+#define BIONIC_PTHREAD_KEY_RESERVED_COUNT LIBC_PTHREAD_KEY_RESERVED_COUNT
+#endif
+
+/*
+ * Maximum number of pthread keys allocated.
+ * This includes pthread keys used internally and externally.
+ */
+#define BIONIC_PTHREAD_KEY_COUNT (BIONIC_PTHREAD_KEY_RESERVED_COUNT + PTHREAD_KEYS_MAX)
+
+__END_DECLS
+
+#if defined(__cplusplus)
+class KernelArgumentBlock;
+extern void __libc_init_tls(KernelArgumentBlock& args);
+#endif
+
+#endif /* __BIONIC_PRIVATE_BIONIC_TLS_H_ */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/kernel_sigset_t.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 The Android Open Source 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.
+ */
+
+#ifndef LIBC_PRIVATE_KERNEL_SIGSET_T_H_
+#define LIBC_PRIVATE_KERNEL_SIGSET_T_H_
+
+#include <signal.h>
+
+// Our sigset_t is wrong for ARM and x86. It's 32-bit but the kernel expects 64 bits.
+// This means we can't support real-time signals correctly until we can change the ABI.
+// In the meantime, we can use this union to pass an appropriately-sized block of memory
+// to the kernel, at the cost of not being able to refer to real-time signals.
+union kernel_sigset_t {
+  kernel_sigset_t() {
+    clear();
+  }
+
+  kernel_sigset_t(const sigset_t* value) {
+    clear();
+    set(value);
+  }
+
+  void clear() {
+    __builtin_memset(this, 0, sizeof(*this));
+  }
+
+  void set(const sigset_t* value) {
+    bionic = *value;
+  }
+
+  sigset_t* get() {
+    return &bionic;
+  }
+
+  sigset_t bionic;
+#ifndef __mips__
+  uint32_t kernel[2];
+#endif
+};
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/libc_events.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBC_EVENTS_H
+#define _LIBC_EVENTS_H
+
+
+// This is going to be included in assembler code so only allow #define
+// values instead of defining an enum.
+
+#define BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW   80100
+#define BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW   80105
+#define BIONIC_EVENT_MEMMOVE_BUFFER_OVERFLOW  80110
+#define BIONIC_EVENT_STRNCAT_BUFFER_OVERFLOW  80115
+#define BIONIC_EVENT_STRNCPY_BUFFER_OVERFLOW  80120
+#define BIONIC_EVENT_MEMSET_BUFFER_OVERFLOW   80125
+#define BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW   80130
+#define BIONIC_EVENT_STPCPY_BUFFER_OVERFLOW   80135
+#define BIONIC_EVENT_STPNCPY_BUFFER_OVERFLOW  80140
+
+#define BIONIC_EVENT_RESOLVER_OLD_RESPONSE    80300
+#define BIONIC_EVENT_RESOLVER_WRONG_SERVER    80305
+#define BIONIC_EVENT_RESOLVER_WRONG_QUERY     80310
+
+#endif // _LIBC_EVENTS_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/libc_logging.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBC_LOGGING_H
+#define _LIBC_LOGGING_H
+
+#include <sys/cdefs.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+#include "libc_events.h"
+
+enum {
+  ANDROID_LOG_UNKNOWN = 0,
+  ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
+
+  ANDROID_LOG_VERBOSE,
+  ANDROID_LOG_DEBUG,
+  ANDROID_LOG_INFO,
+  ANDROID_LOG_WARN,
+  ANDROID_LOG_ERROR,
+  ANDROID_LOG_FATAL,
+
+  ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
+};
+
+enum {
+  LOG_ID_MIN = 0,
+
+  LOG_ID_MAIN = 0,
+  LOG_ID_RADIO = 1,
+  LOG_ID_EVENTS = 2,
+  LOG_ID_SYSTEM = 3,
+  LOG_ID_CRASH = 4,
+
+  LOG_ID_MAX
+};
+
+struct abort_msg_t {
+  size_t size;
+  char msg[0];
+};
+
+//
+// Formats a message to the log (priority 'fatal'), then aborts.
+//
+
+ void __libc_fatal(const char* format, ...);
+
+//
+// Formats a message to the log (priority 'fatal'), but doesn't abort.
+// Used by the malloc implementation to ensure that debuggerd dumps memory
+// around the bad address.
+//
+
+ void __libc_fatal_no_abort(const char* format, ...);
+
+//
+// Formatting routines for the C library's internal debugging.
+// Unlike the usual alternatives, these don't allocate, and they don't drag in all of stdio.
+//
+
+ int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...);
+
+ int __libc_format_fd(int fd, const char* format, ...);
+
+ int __libc_format_log(int priority, const char* tag, const char* format, ...);
+
+ int __libc_format_log_va_list(int priority, const char* tag, const char* format,
+                                              va_list ap);
+
+//
+// Event logging.
+//
+
+ void __libc_android_log_event_int(int32_t tag, int value);
+ void __libc_android_log_event_uid(int32_t tag);
+
+ void __fortify_chk_fail(const char* msg, uint32_t event_tag);
+
+__END_DECLS
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/bionic/libc/private/thread_private.h
@@ -0,0 +1,55 @@
+/* $OpenBSD: thread_private.h,v 1.18 2006/02/22 07:16:31 otto Exp $ */
+
+/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */
+
+#ifndef _THREAD_PRIVATE_H_
+#define _THREAD_PRIVATE_H_
+
+#include <pthread.h>
+
+__BEGIN_DECLS
+
+/*
+ * This file defines the thread library interface to libc.  Thread
+ * libraries must implement the functions described here for proper
+ * inter-operation with libc.   libc contains weak versions of the
+ * described functions for operation in a non-threaded environment.
+ */
+
+/*
+ * helper macro to make unique names in the thread namespace
+ */
+#define __THREAD_NAME(name)	__CONCAT(_thread_tagname_,name)
+
+struct __thread_private_tag_t {
+    pthread_mutex_t    _private_lock;
+    pthread_key_t      _private_key;
+};
+
+#define _THREAD_PRIVATE_MUTEX(name)  \
+	static struct __thread_private_tag_t  __THREAD_NAME(name) = { PTHREAD_MUTEX_INITIALIZER, -1 }
+#define _THREAD_PRIVATE_MUTEX_LOCK(name)  \
+	pthread_mutex_lock( &__THREAD_NAME(name)._private_lock )
+#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \
+	pthread_mutex_unlock( &__THREAD_NAME(name)._private_lock )
+
+/* Note that these aren't compatible with the usual OpenBSD ones which lazy-initialize! */
+#define _MUTEX_LOCK(l) pthread_mutex_lock((pthread_mutex_t*) l)
+#define _MUTEX_UNLOCK(l) pthread_mutex_unlock((pthread_mutex_t*) l)
+
+ void  _thread_atexit_lock(void);
+ void  _thread_atexit_unlock(void);
+
+#define _ATEXIT_LOCK() _thread_atexit_lock()
+#define _ATEXIT_UNLOCK() _thread_atexit_unlock()
+
+ void    _thread_arc4_lock(void);
+ void    _thread_arc4_unlock(void);
+
+#define _ARC4_LOCK() _thread_arc4_lock()
+#define _ARC4_UNLOCK() _thread_arc4_unlock()
+#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f))
+
+__END_DECLS
+
+#endif /* _THREAD_PRIVATE_H_ */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/dlfcn.cpp
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2007 The Android Open Source 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.
+ */
+
+#include "linker.h"
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <android/dlext.h>
+#include <android/api-level.h>
+
+#include <bionic/pthread_internal.h>
+#include "private/bionic_tls.h"
+#include "private/ScopedPthreadMutexLocker.h"
+#include "private/ThreadLocalBuffer.h"
+
+#include "hybris_compat.h"
+
+/* This file hijacks the symbols stubbed out in libdl.so. */
+
+static pthread_mutex_t g_dl_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
+static char dl_err_buf[1024];
+static const char *dl_err_str;
+
+static const char* __bionic_set_dlerror(char* new_value) {
+#ifdef DISABLED_FOR_HYBRIS_SUPPORT
+  char** dlerror_slot = &reinterpret_cast<char**>(__get_tls())[TLS_SLOT_DLERROR];
+
+  const char* old_value = *dlerror_slot;
+  *dlerror_slot = new_value;
+  return old_value;
+#else
+  char *dlerror_slot = dl_err_buf;
+  const char *old_value = dlerror_slot;
+  dlerror_slot = new_value;
+  return old_value;
+#endif
+}
+
+static void __bionic_format_dlerror(const char* msg, const char* detail) {
+#ifdef DISABLED_FOR_HYBRIS_SUPPORT
+  char* buffer = __get_thread()->dlerror_buffer;
+#else
+  char* buffer = dl_err_buf;
+#endif
+  strlcpy(buffer, msg, __BIONIC_DLERROR_BUFFER_SIZE);
+  if (detail != nullptr) {
+    strlcat(buffer, ": ", __BIONIC_DLERROR_BUFFER_SIZE);
+    strlcat(buffer, detail, __BIONIC_DLERROR_BUFFER_SIZE);
+  }
+
+  __bionic_set_dlerror(buffer);
+}
+
+extern "C" const char* android_dlerror() {
+  const char* old_value = __bionic_set_dlerror(nullptr);
+  return old_value;
+}
+
+void android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+  do_android_get_LD_LIBRARY_PATH(buffer, buffer_size);
+}
+
+void android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+  do_android_update_LD_LIBRARY_PATH(ld_library_path);
+}
+
+static void* dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+  soinfo* result = do_dlopen(filename, flags, extinfo);
+  if (result == nullptr) {
+    __bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
+    return nullptr;
+  }
+  return result;
+}
+
+extern "C" void* android_dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) {
+  return dlopen_ext(filename, flags, extinfo);
+}
+
+extern "C" void* android_dlopen(const char* filename, int flags) {
+  return dlopen_ext(filename, flags, nullptr);
+}
+
+extern "C" void* android_dlsym(void* handle, const char* symbol) {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+
+#if !defined(__LP64__)
+  if (handle == nullptr) {
+    __bionic_format_dlerror("dlsym library handle is null", nullptr);
+    return nullptr;
+  }
+#endif
+
+  if (symbol == nullptr) {
+    __bionic_format_dlerror("dlsym symbol name is null", nullptr);
+    return nullptr;
+  }
+
+  soinfo* found = nullptr;
+  const ElfW(Sym)* sym = nullptr;
+  void* caller_addr = __builtin_return_address(0);
+  soinfo* caller = find_containing_library(caller_addr);
+
+  if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
+    sym = dlsym_linear_lookup(symbol, &found, caller, handle);
+  } else {
+    sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
+  }
+
+  if (sym != nullptr) {
+    unsigned bind = ELF_ST_BIND(sym->st_info);
+
+    if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
+      return reinterpret_cast<void*>(found->resolve_symbol_address(sym));
+    }
+
+    __bionic_format_dlerror("symbol found but not global", symbol);
+    return nullptr;
+  } else {
+    __bionic_format_dlerror("undefined symbol", symbol);
+    return nullptr;
+  }
+}
+
+extern "C" int android_dladdr(const void* addr, Dl_info* info) {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+
+  // Determine if this address can be found in any library currently mapped.
+  soinfo* si = find_containing_library(addr);
+  if (si == nullptr) {
+    return 0;
+  }
+
+  memset(info, 0, sizeof(Dl_info));
+
+  info->dli_fname = si->get_realpath();
+  // Address at which the shared object is loaded.
+  info->dli_fbase = reinterpret_cast<void*>(si->base);
+
+  // Determine if any symbol in the library contains the specified address.
+  ElfW(Sym)* sym = si->find_symbol_by_address(addr);
+  if (sym != nullptr) {
+    info->dli_sname = si->get_string(sym->st_name);
+    info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
+  }
+
+  return 1;
+}
+
+extern "C" int android_dlclose(void* handle) {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+  do_dlclose(reinterpret_cast<soinfo*>(handle));
+  // dlclose has no defined errors.
+  return 0;
+}
+
+int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+  return do_dl_iterate_phdr(cb, data);
+}
+
+void android_set_application_target_sdk_version(uint32_t target) {
+  // lock to avoid modification in the middle of dlopen.
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+  set_application_target_sdk_version(target);
+}
+
+uint32_t android_get_application_target_sdk_version() {
+  return get_application_target_sdk_version();
+}
+
+// name_offset: starting index of the name in libdl_info.strtab
+#define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \
+    { name_offset, \
+      reinterpret_cast<Elf32_Addr>(value), \
+      /* st_size */ 0, \
+      (shndx == 0) ? 0 : (STB_GLOBAL << 4), \
+      /* st_other */ 0, \
+      shndx, \
+    }
+
+#define ELF64_SYM_INITIALIZER(name_offset, value, shndx) \
+    { name_offset, \
+      (shndx == 0) ? 0 : (STB_GLOBAL << 4), \
+      /* st_other */ 0, \
+      shndx, \
+      reinterpret_cast<Elf64_Addr>(value), \
+      /* st_size */ 0, \
+    }
+
+#if defined(__arm__)
+_Unwind_Ptr android_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount);
+#endif
+
+static const char ANDROID_LIBDL_STRTAB[] =
+  // 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667777777777888888888899999 99999
+  // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890123456789012345678901234 56789
+    "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0android_get_LD_LIBRARY_PATH\0dl_it"
+  // 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
+  // 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
+    "erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
+  // 0000000000111111
+  // 0123456789012345
+    "get_sdk_version\0"
+#if defined(__arm__)
+  // 216
+    "dl_unwind_find_exidx\0"
+#endif
+    ;
+
+static ElfW(Sym) g_libdl_symtab[] = {
+  // Total length of libdl_info.strtab, including trailing 0.
+  // This is actually the STH_UNDEF entry. Technically, it's
+  // supposed to have st_name == 0, but instead, it points to an index
+  // in the strtab with a \0 to make iterating through the symtab easier.
+  ELFW(SYM_INITIALIZER)(sizeof(ANDROID_LIBDL_STRTAB) - 1, nullptr, 0),
+  ELFW(SYM_INITIALIZER)(  0, &android_dlopen, 1),
+  ELFW(SYM_INITIALIZER)(  7, &android_dlclose, 1),
+  ELFW(SYM_INITIALIZER)( 15, &android_dlsym, 1),
+  ELFW(SYM_INITIALIZER)( 21, &android_dlerror, 1),
+  ELFW(SYM_INITIALIZER)( 29, &android_dladdr, 1),
+  ELFW(SYM_INITIALIZER)( 36, &android_update_LD_LIBRARY_PATH, 1),
+  ELFW(SYM_INITIALIZER)( 67, &android_get_LD_LIBRARY_PATH, 1),
+  ELFW(SYM_INITIALIZER)( 95, &dl_iterate_phdr, 1),
+  ELFW(SYM_INITIALIZER)(111, &android_dlopen_ext, 1),
+  ELFW(SYM_INITIALIZER)(130, &android_set_application_target_sdk_version, 1),
+  ELFW(SYM_INITIALIZER)(173, &android_get_application_target_sdk_version, 1),
+#if defined(__arm__)
+  ELFW(SYM_INITIALIZER)(216, &dl_unwind_find_exidx, 1),
+#endif
+};
+
+// Fake out a hash table with a single bucket.
+//
+// A search of the hash table will look through g_libdl_symtab starting with index 1, then
+// use g_libdl_chains to find the next index to look at. g_libdl_chains should be set up to
+// walk through every element in g_libdl_symtab, and then end with 0 (sentinel value).
+//
+// That is, g_libdl_chains should look like { 0, 2, 3, ... N, 0 } where N is the number
+// of actual symbols, or nelems(g_libdl_symtab)-1 (since the first element of g_libdl_symtab is not
+// a real symbol). (See soinfo_elf_lookup().)
+//
+// Note that adding any new symbols here requires stubbing them out in libdl.
+static unsigned g_libdl_buckets[1] = { 1 };
+#if defined(__arm__)
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0 };
+#else
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0 };
+#endif
+
+static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
+static soinfo* __libdl_info = nullptr;
+
+// This is used by the dynamic linker. Every process gets these symbols for free.
+soinfo* get_libdl_info() {
+  if (__libdl_info == nullptr) {
+    __libdl_info = new (__libdl_info_buf) soinfo("libdl.so", nullptr, 0, RTLD_GLOBAL);
+    __libdl_info->flags_ |= FLAG_LINKED;
+    __libdl_info->strtab_ = ANDROID_LIBDL_STRTAB;
+    __libdl_info->symtab_ = g_libdl_symtab;
+    __libdl_info->nbucket_ = sizeof(g_libdl_buckets)/sizeof(unsigned);
+    __libdl_info->nchain_ = sizeof(g_libdl_chains)/sizeof(unsigned);
+    __libdl_info->bucket_ = g_libdl_buckets;
+    __libdl_info->chain_ = g_libdl_chains;
+    __libdl_info->ref_count_ = 1;
+    __libdl_info->strtab_size_ = sizeof(ANDROID_LIBDL_STRTAB);
+    __libdl_info->local_group_root_ = __libdl_info;
+    __libdl_info->soname_ = "libdl.so";
+    __libdl_info->target_sdk_version_ = __ANDROID_API__;
+#if DISABLED_FOR_HYBRIS_SUPPORT
+#if defined(__arm__)
+    strlcpy(__libdl_info->old_name_, __libdl_info->soname_, sizeof(__libdl_info->old_name_));
+#endif
+#endif
+  }
+
+  return __libdl_info;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/hybris_compat.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hybris_compat.h"
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/hybris_compat.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef HYBRIS_ANDROID_MM_COMPAT_H_
+#define HYBRIS_ANDROID_MM_COMPAT_H_
+
+#include <string.h>
+#include <memory.h>
+
+extern "C" size_t strlcpy(char *dest, const char *src, size_t size);
+extern "C" size_t strlcat(char *dst, const char *src, size_t size);
+
+#define ELF_ST_BIND(x)          ((x) >> 4)
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
+/*
+ * From bionic/libc/include/elf.h
+ *
+ * Android compressed rel/rela sections
+ */
+#define DT_ANDROID_REL (DT_LOOS + 2)
+#define DT_ANDROID_RELSZ (DT_LOOS + 3)
+
+#define DT_ANDROID_RELA (DT_LOOS + 4)
+#define DT_ANDROID_RELASZ (DT_LOOS + 5)
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linked_list.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2014 The Android Open Source 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.
+ */
+
+#ifndef __LINKED_LIST_H
+#define __LINKED_LIST_H
+
+#include "private/bionic_macros.h"
+
+template<typename T>
+struct LinkedListEntry {
+  LinkedListEntry<T>* next;
+  T* element;
+};
+
+/*
+ * Represents linked list of objects of type T
+ */
+template<typename T, typename Allocator>
+class LinkedList {
+ public:
+  LinkedList() : head_(nullptr), tail_(nullptr) {}
+  ~LinkedList() {
+    clear();
+  }
+
+  LinkedList(LinkedList&& that) {
+    this->head_ = that.head_;
+    this->tail_ = that.tail_;
+    that.head_ = that.tail_ = nullptr;
+  }
+
+  void push_front(T* const element) {
+    LinkedListEntry<T>* new_entry = Allocator::alloc();
+    new_entry->next = head_;
+    new_entry->element = element;
+    head_ = new_entry;
+    if (tail_ == nullptr) {
+      tail_ = new_entry;
+    }
+  }
+
+  void push_back(T* const element) {
+    LinkedListEntry<T>* new_entry = Allocator::alloc();
+    new_entry->next = nullptr;
+    new_entry->element = element;
+    if (tail_ == nullptr) {
+      tail_ = head_ = new_entry;
+    } else {
+      tail_->next = new_entry;
+      tail_ = new_entry;
+    }
+  }
+
+  T* pop_front() {
+    if (head_ == nullptr) {
+      return nullptr;
+    }
+
+    LinkedListEntry<T>* entry = head_;
+    T* element = entry->element;
+    head_ = entry->next;
+    Allocator::free(entry);
+
+    if (head_ == nullptr) {
+      tail_ = nullptr;
+    }
+
+    return element;
+  }
+
+  T* front() const {
+    if (head_ == nullptr) {
+      return nullptr;
+    }
+
+    return head_->element;
+  }
+
+  void clear() {
+    while (head_ != nullptr) {
+      LinkedListEntry<T>* p = head_;
+      head_ = head_->next;
+      Allocator::free(p);
+    }
+
+    tail_ = nullptr;
+  }
+
+  template<typename F>
+  void for_each(F action) const {
+    visit([&] (T* si) {
+      action(si);
+      return true;
+    });
+  }
+
+  template<typename F>
+  bool visit(F action) const {
+    for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
+      if (!action(e->element)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  template<typename F>
+  void remove_if(F predicate) {
+    for (LinkedListEntry<T>* e = head_, *p = nullptr; e != nullptr;) {
+      if (predicate(e->element)) {
+        LinkedListEntry<T>* next = e->next;
+        if (p == nullptr) {
+          head_ = next;
+        } else {
+          p->next = next;
+        }
+        Allocator::free(e);
+        e = next;
+      } else {
+        p = e;
+        e = e->next;
+      }
+    }
+  }
+
+  template<typename F>
+  T* find_if(F predicate) const {
+    for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
+      if (predicate(e->element)) {
+        return e->element;
+      }
+    }
+
+    return nullptr;
+  }
+
+  size_t copy_to_array(T* array[], size_t array_length) const {
+    size_t sz = 0;
+    for (LinkedListEntry<T>* e = head_; sz < array_length && e != nullptr; e = e->next) {
+      array[sz++] = e->element;
+    }
+
+    return sz;
+  }
+
+  bool contains(const T* el) const {
+    for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
+      if (e->element == el) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  static LinkedList make_list(T* const element) {
+    LinkedList<T, Allocator> one_element_list;
+    one_element_list.push_back(element);
+    return one_element_list;
+  }
+
+ private:
+  LinkedListEntry<T>* head_;
+  LinkedListEntry<T>* tail_;
+  DISALLOW_COPY_AND_ASSIGN(LinkedList);
+};
+
+#endif // __LINKED_LIST_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker.cpp
@@ -0,0 +1,3391 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <android/api-level.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+#include <new>
+#include <string>
+#include <vector>
+
+// Private C library headers.
+#include "private/bionic_tls.h"
+#include "private/KernelArgumentBlock.h"
+#include "private/ScopedPthreadMutexLocker.h"
+#include "private/ScopeGuard.h"
+#include "private/UniquePtr.h"
+
+#include "linker.h"
+#include "linker_block_allocator.h"
+#include "linker_debug.h"
+#include "linker_sleb128.h"
+#include "linker_phdr.h"
+#include "linker_relocs.h"
+#include "linker_reloc_iterators.h"
+
+#include "hybris_compat.h"
+
+#ifdef DISABLED_FOR_HYBRIS_SUPPORT
+extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
+#endif
+
+// Override macros to use C++ style casts.
+#undef ELF_ST_TYPE
+#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
+
+static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
+
+static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
+static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
+
+static soinfo* solist = get_libdl_info();
+static soinfo* sonext = get_libdl_info();
+static soinfo* somain; // main process, always the one after libdl_info
+
+static const char* const kDefaultLdPaths[] = {
+#if defined(__LP64__)
+  "/vendor/lib64",
+  "/system/lib64",
+#else
+  "/vendor/lib",
+  "/system/lib",
+#endif
+  nullptr
+};
+
+static const ElfW(Versym) kVersymNotNeeded = 0;
+static const ElfW(Versym) kVersymGlobal = 1;
+
+static std::vector<std::string> g_ld_library_paths;
+static std::vector<std::string> g_ld_preload_names;
+
+static std::vector<soinfo*> g_ld_preloads;
+
+int g_ld_debug_verbosity = 0;
+
+abort_msg_t* g_abort_message = nullptr; // For debuggerd.
+
+#if STATS
+struct linker_stats_t {
+  int count[kRelocMax];
+};
+
+static linker_stats_t linker_stats;
+
+void count_relocation(RelocationKind kind) {
+  ++linker_stats.count[kind];
+}
+#else
+void count_relocation(RelocationKind) {
+}
+#endif
+
+#if COUNT_PAGES
+uint32_t bitmask[4096];
+#endif
+
+static char __linker_dl_err_buf[768];
+
+char* linker_get_error_buffer() {
+  return &__linker_dl_err_buf[0];
+}
+
+size_t linker_get_error_buffer_size() {
+  return sizeof(__linker_dl_err_buf);
+}
+
+// This function is an empty stub where GDB locates a breakpoint to get notified
+// about linker activity.
+extern "C"
+void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
+
+static pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER;
+static r_debug _r_debug =
+    {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
+
+static link_map* r_debug_tail = 0;
+
+static void* (*_get_hooked_symbol)(const char *sym, const char *requester);
+
+static void insert_soinfo_into_debug_map(soinfo* info) {
+  // Copy the necessary fields into the debug structure.
+  link_map* map = &(info->link_map_head);
+  map->l_addr = info->load_bias;
+  // link_map l_name field is not const.
+  map->l_name = const_cast<char*>(info->get_realpath());
+  map->l_ld = info->dynamic;
+
+  // Stick the new library at the end of the list.
+  // gdb tends to care more about libc than it does
+  // about leaf libraries, and ordering it this way
+  // reduces the back-and-forth over the wire.
+  if (r_debug_tail) {
+    r_debug_tail->l_next = map;
+    map->l_prev = r_debug_tail;
+    map->l_next = 0;
+  } else {
+    _r_debug.r_map = map;
+    map->l_prev = 0;
+    map->l_next = 0;
+  }
+  r_debug_tail = map;
+}
+
+static void remove_soinfo_from_debug_map(soinfo* info) {
+  link_map* map = &(info->link_map_head);
+
+  if (r_debug_tail == map) {
+    r_debug_tail = map->l_prev;
+  }
+
+  if (map->l_prev) {
+    map->l_prev->l_next = map->l_next;
+  }
+  if (map->l_next) {
+    map->l_next->l_prev = map->l_prev;
+  }
+}
+
+static void notify_gdb_of_load(soinfo* info) {
+  if (info->is_main_executable()) {
+    // GDB already knows about the main executable
+    return;
+  }
+
+  ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
+
+  _r_debug.r_state = r_debug::RT_ADD;
+  rtld_db_dlactivity();
+
+  insert_soinfo_into_debug_map(info);
+
+  _r_debug.r_state = r_debug::RT_CONSISTENT;
+  rtld_db_dlactivity();
+}
+
+static void notify_gdb_of_unload(soinfo* info) {
+  if (info->is_main_executable()) {
+    // GDB already knows about the main executable
+    return;
+  }
+
+  ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
+
+  _r_debug.r_state = r_debug::RT_DELETE;
+  rtld_db_dlactivity();
+
+  remove_soinfo_from_debug_map(info);
+
+  _r_debug.r_state = r_debug::RT_CONSISTENT;
+  rtld_db_dlactivity();
+}
+
+void notify_gdb_of_libraries() {
+  _r_debug.r_state = r_debug::RT_ADD;
+  rtld_db_dlactivity();
+  _r_debug.r_state = r_debug::RT_CONSISTENT;
+  rtld_db_dlactivity();
+}
+
+LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
+  return g_soinfo_links_allocator.alloc();
+}
+
+void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
+  g_soinfo_links_allocator.free(entry);
+}
+
+static soinfo* soinfo_alloc(const char* name, struct stat* file_stat,
+                            off64_t file_offset, uint32_t rtld_flags) {
+  if (strlen(name) >= PATH_MAX) {
+    DL_ERR("library name \"%s\" too long", name);
+    return nullptr;
+  }
+
+  soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags);
+
+  sonext->next = si;
+  sonext = si;
+
+  TRACE("name %s: allocated soinfo @ %p", name, si);
+  return si;
+}
+
+static void soinfo_free(soinfo* si) {
+  if (si == nullptr) {
+    return;
+  }
+
+  if (si->base != 0 && si->size != 0) {
+    munmap(reinterpret_cast<void*>(si->base), si->size);
+  }
+
+  soinfo *prev = nullptr, *trav;
+
+  TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
+
+  for (trav = solist; trav != nullptr; trav = trav->next) {
+    if (trav == si) {
+      break;
+    }
+    prev = trav;
+  }
+
+  if (trav == nullptr) {
+    // si was not in solist
+    DL_ERR("name \"%s\"@%p is not in solist!", si->get_realpath(), si);
+    return;
+  }
+
+  // clear links to/from si
+  si->remove_all_links();
+
+  // prev will never be null, because the first entry in solist is
+  // always the static libdl_info.
+  prev->next = si->next;
+  if (si == sonext) {
+    sonext = prev;
+  }
+
+  si->~soinfo();
+  g_soinfo_allocator.free(si);
+}
+
+static void parse_path(const char* path, const char* delimiters,
+                       std::vector<std::string>* paths) {
+  if (path == nullptr) {
+    return;
+  }
+
+  paths->clear();
+
+  for (const char *p = path; ; ++p) {
+    size_t len = strcspn(p, delimiters);
+    // skip empty tokens
+    if (len == 0) {
+      continue;
+    }
+
+    paths->push_back(std::string(p, len));
+    p += len;
+
+    if (*p == '\0') {
+      break;
+    }
+  }
+}
+
+static void parse_LD_LIBRARY_PATH(const char* path) {
+  parse_path(path, ":", &g_ld_library_paths);
+}
+
+static void parse_LD_PRELOAD(const char* path) {
+  // We have historically supported ':' as well as ' ' in LD_PRELOAD.
+  parse_path(path, " :", &g_ld_preload_names);
+}
+
+static bool realpath_fd(int fd, std::string* realpath) {
+  std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
+  snprintf(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
+  if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
+    PRINT("readlink('%s') failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
+    return false;
+  }
+
+  *realpath = std::string(&buf[0]);
+  return true;
+}
+
+#if defined(__arm__)
+
+// For a given PC, find the .so that it belongs to.
+// Returns the base address of the .ARM.exidx section
+// for that .so, and the number of 8-byte entries
+// in that section (via *pcount).
+//
+// Intended to be called by libc's __gnu_Unwind_Find_exidx().
+//
+// This function is exposed via dlfcn.cpp and libdl.so.
+_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
+  uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
+
+  for (soinfo* si = solist; si != 0; si = si->next) {
+    if ((addr >= si->base) && (addr < (si->base + si->size))) {
+        *pcount = si->ARM_exidx_count;
+        return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
+    }
+  }
+  *pcount = 0;
+  return nullptr;
+}
+
+#endif
+
+// Here, we only have to provide a callback to iterate across all the
+// loaded libraries. gcc_eh does the rest.
+int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
+  int rv = 0;
+  for (soinfo* si = solist; si != nullptr; si = si->next) {
+    dl_phdr_info dl_info;
+    dl_info.dlpi_addr = si->link_map_head.l_addr;
+    dl_info.dlpi_name = si->link_map_head.l_name;
+    dl_info.dlpi_phdr = si->phdr;
+    dl_info.dlpi_phnum = si->phnum;
+    rv = cb(&dl_info, sizeof(dl_phdr_info), data);
+    if (rv != 0) {
+      break;
+    }
+  }
+  return rv;
+}
+
+const ElfW(Versym)* soinfo::get_versym(size_t n) const {
+  if (has_min_version(2) && versym_ != nullptr) {
+    return versym_ + n;
+  }
+
+  return nullptr;
+}
+
+ElfW(Addr) soinfo::get_verneed_ptr() const {
+  if (has_min_version(2)) {
+    return verneed_ptr_;
+  }
+
+  return 0;
+}
+
+size_t soinfo::get_verneed_cnt() const {
+  if (has_min_version(2)) {
+    return verneed_cnt_;
+  }
+
+  return 0;
+}
+
+ElfW(Addr) soinfo::get_verdef_ptr() const {
+  if (has_min_version(2)) {
+    return verdef_ptr_;
+  }
+
+  return 0;
+}
+
+size_t soinfo::get_verdef_cnt() const {
+  if (has_min_version(2)) {
+    return verdef_cnt_;
+  }
+
+  return 0;
+}
+
+template<typename F>
+static bool for_each_verdef(const soinfo* si, F functor) {
+  if (!si->has_min_version(2)) {
+    return true;
+  }
+
+  uintptr_t verdef_ptr = si->get_verdef_ptr();
+  if (verdef_ptr == 0) {
+    return true;
+  }
+
+  size_t offset = 0;
+
+  size_t verdef_cnt = si->get_verdef_cnt();
+  for (size_t i = 0; i<verdef_cnt; ++i) {
+    const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
+    size_t verdaux_offset = offset + verdef->vd_aux;
+    offset += verdef->vd_next;
+
+    if (verdef->vd_version != 1) {
+      DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
+          i, verdef->vd_version, si->get_realpath());
+      return false;
+    }
+
+    if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
+      // "this is the version of the file itself.  It must not be used for
+      //  matching a symbol. It can be used to match references."
+      //
+      // http://www.akkadia.org/drepper/symbol-versioning
+      continue;
+    }
+
+    if (verdef->vd_cnt == 0) {
+      DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
+      return false;
+    }
+
+    const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
+
+    if (functor(i, verdef, verdaux) == true) {
+      break;
+    }
+  }
+
+  return true;
+}
+
+bool soinfo::find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const {
+  if (vi == nullptr) {
+    *versym = kVersymNotNeeded;
+    return true;
+  }
+
+  *versym = kVersymGlobal;
+
+  return for_each_verdef(this,
+    [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
+      if (verdef->vd_hash == vi->elf_hash &&
+          strcmp(vi->name, get_string(verdaux->vda_name)) == 0) {
+        *versym = verdef->vd_ndx;
+        return true;
+      }
+
+      return false;
+    }
+  );
+}
+
+bool soinfo::find_symbol_by_name(SymbolName& symbol_name,
+                                 const version_info* vi,
+                                 const ElfW(Sym)** symbol) const {
+  uint32_t symbol_index;
+  bool success =
+      is_gnu_hash() ?
+      gnu_lookup(symbol_name, vi, &symbol_index) :
+      elf_lookup(symbol_name, vi, &symbol_index);
+
+  if (success) {
+    *symbol = symbol_index == 0 ? nullptr : symtab_ + symbol_index;
+  }
+
+  return success;
+}
+
+static bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) {
+  if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
+      ELF_ST_BIND(s->st_info) == STB_WEAK) {
+    return s->st_shndx != SHN_UNDEF;
+  } else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) {
+    DL_WARN("unexpected ST_BIND value: %d for '%s' in '%s'",
+        ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath());
+  }
+
+  return false;
+}
+
+static const ElfW(Versym) kVersymHiddenBit = 0x8000;
+
+static inline bool is_versym_hidden(const ElfW(Versym)* versym) {
+  // the symbol is hidden if bit 15 of versym is set.
+  return versym != nullptr && (*versym & kVersymHiddenBit) != 0;
+}
+
+static inline bool check_symbol_version(const ElfW(Versym) verneed,
+                                        const ElfW(Versym)* verdef) {
+  return verneed == kVersymNotNeeded ||
+      verdef == nullptr ||
+      verneed == (*verdef & ~kVersymHiddenBit);
+}
+
+bool soinfo::gnu_lookup(SymbolName& symbol_name,
+                        const version_info* vi,
+                        uint32_t* symbol_index) const {
+  uint32_t hash = symbol_name.gnu_hash();
+  uint32_t h2 = hash >> gnu_shift2_;
+
+  uint32_t bloom_mask_bits = sizeof(ElfW(Addr))*8;
+  uint32_t word_num = (hash / bloom_mask_bits) & gnu_maskwords_;
+  ElfW(Addr) bloom_word = gnu_bloom_filter_[word_num];
+
+  *symbol_index = 0;
+
+  TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p (gnu)",
+      symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
+
+  // test against bloom filter
+  if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) {
+    TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
+        symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
+
+    return true;
+  }
+
+  // bloom test says "probably yes"...
+  uint32_t n = gnu_bucket_[hash % gnu_nbucket_];
+
+  if (n == 0) {
+    TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
+        symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
+
+    return true;
+  }
+
+  // lookup versym for the version definition in this library
+  // note the difference between "version is not requested" (vi == nullptr)
+  // and "version not found". In the first case verneed is kVersymNotNeeded
+  // which implies that the default version can be accepted; the second case results in
+  // verneed = 1 (kVersymGlobal) and implies that we should ignore versioned symbols
+  // for this library and consider only *global* ones.
+  ElfW(Versym) verneed = 0;
+  if (!find_verdef_version_index(vi, &verneed)) {
+    return false;
+  }
+
+  do {
+    ElfW(Sym)* s = symtab_ + n;
+    const ElfW(Versym)* verdef = get_versym(n);
+    // skip hidden versions when verneed == kVersymNotNeeded (0)
+    if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
+        continue;
+    }
+    if (((gnu_chain_[n] ^ hash) >> 1) == 0 &&
+        check_symbol_version(verneed, verdef) &&
+        strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
+        is_symbol_global_and_defined(this, s)) {
+      TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
+          symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(s->st_value),
+          static_cast<size_t>(s->st_size));
+      *symbol_index = n;
+      return true;
+    }
+  } while ((gnu_chain_[n++] & 1) == 0);
+
+  TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
+             symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
+
+  return true;
+}
+
+bool soinfo::elf_lookup(SymbolName& symbol_name,
+                        const version_info* vi,
+                        uint32_t* symbol_index) const {
+  uint32_t hash = symbol_name.elf_hash();
+
+  TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd",
+             symbol_name.get_name(), get_realpath(),
+             reinterpret_cast<void*>(base), hash, hash % nbucket_);
+
+  ElfW(Versym) verneed = 0;
+  if (!find_verdef_version_index(vi, &verneed)) {
+    return false;
+  }
+
+  for (uint32_t n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) {
+    ElfW(Sym)* s = symtab_ + n;
+    const ElfW(Versym)* verdef = get_versym(n);
+
+    // skip hidden versions when verneed == 0
+    if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
+        continue;
+    }
+
+    if (check_symbol_version(verneed, verdef) &&
+        strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
+        is_symbol_global_and_defined(this, s)) {
+      TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
+                 symbol_name.get_name(), get_realpath(),
+                 reinterpret_cast<void*>(s->st_value),
+                 static_cast<size_t>(s->st_size));
+      *symbol_index = n;
+      return true;
+    }
+  }
+
+  TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd",
+             symbol_name.get_name(), get_realpath(),
+             reinterpret_cast<void*>(base), hash, hash % nbucket_);
+
+  *symbol_index = 0;
+  return true;
+}
+
+soinfo::soinfo(const char* realpath, const struct stat* file_stat,
+               off64_t file_offset, int rtld_flags) {
+
+  if (realpath != nullptr) {
+    realpath_ = realpath;
+  }
+
+  flags_ = FLAG_NEW_SOINFO;
+  version_ = SOINFO_VERSION;
+
+  if (file_stat != nullptr) {
+    this->st_dev_ = file_stat->st_dev;
+    this->st_ino_ = file_stat->st_ino;
+    this->file_offset_ = file_offset;
+  }
+
+  this->rtld_flags_ = rtld_flags;
+}
+
+
+uint32_t SymbolName::elf_hash() {
+  if (!has_elf_hash_) {
+    const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);
+    uint32_t h = 0, g;
+
+    while (*name) {
+      h = (h << 4) + *name++;
+      g = h & 0xf0000000;
+      h ^= g;
+      h ^= g >> 24;
+    }
+
+    elf_hash_ = h;
+    has_elf_hash_ = true;
+  }
+
+  return elf_hash_;
+}
+
+uint32_t SymbolName::gnu_hash() {
+  if (!has_gnu_hash_) {
+    uint32_t h = 5381;
+    const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);
+    while (*name != 0) {
+      h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c
+    }
+
+    gnu_hash_ =  h;
+    has_gnu_hash_ = true;
+  }
+
+  return gnu_hash_;
+}
+
+bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
+                      soinfo** si_found_in, const soinfo::soinfo_list_t& global_group,
+                      const soinfo::soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
+  SymbolName symbol_name(name);
+  const ElfW(Sym)* s = nullptr;
+
+  /* "This element's presence in a shared object library alters the dynamic linker's
+   * symbol resolution algorithm for references within the library. Instead of starting
+   * a symbol search with the executable file, the dynamic linker starts from the shared
+   * object itself. If the shared object fails to supply the referenced symbol, the
+   * dynamic linker then searches the executable file and other shared objects as usual."
+   *
+   * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
+   *
+   * Note that this is unlikely since static linker avoids generating
+   * relocations for -Bsymbolic linked dynamic executables.
+   */
+  if (si_from->has_DT_SYMBOLIC) {
+    DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
+    if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
+      return false;
+    }
+
+    if (s != nullptr) {
+      *si_found_in = si_from;
+    }
+  }
+
+  // 1. Look for it in global_group
+  if (s == nullptr) {
+    bool error = false;
+    global_group.visit([&](soinfo* global_si) {
+      DEBUG("%s: looking up %s in %s (from global group)",
+          si_from->get_realpath(), name, global_si->get_realpath());
+      if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
+        error = true;
+        return false;
+      }
+
+      if (s != nullptr) {
+        *si_found_in = global_si;
+        return false;
+      }
+
+      return true;
+    });
+
+    if (error) {
+      return false;
+    }
+  }
+
+  // 2. Look for it in the local group
+  if (s == nullptr) {
+    bool error = false;
+    local_group.visit([&](soinfo* local_si) {
+      if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
+        // we already did this - skip
+        return true;
+      }
+
+      DEBUG("%s: looking up %s in %s (from local group)",
+          si_from->get_realpath(), name, local_si->get_realpath());
+      if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
+        error = true;
+        return false;
+      }
+
+      if (s != nullptr) {
+        *si_found_in = local_si;
+        return false;
+      }
+
+      return true;
+    });
+
+    if (error) {
+      return false;
+    }
+  }
+
+  if (s != nullptr) {
+    TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
+               "found in %s, base = %p, load bias = %p",
+               si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
+               (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
+               reinterpret_cast<void*>((*si_found_in)->load_bias));
+  }
+
+  *symbol = s;
+  return true;
+}
+
+class ProtectedDataGuard {
+ public:
+  ProtectedDataGuard() {
+    if (ref_count_++ == 0) {
+      protect_data(PROT_READ | PROT_WRITE);
+    }
+  }
+
+  ~ProtectedDataGuard() {
+    if (ref_count_ == 0) { // overflow
+      __libc_fatal("Too many nested calls to dlopen()");
+    }
+
+    if (--ref_count_ == 0) {
+      protect_data(PROT_READ);
+    }
+  }
+ private:
+  void protect_data(int protection) {
+    g_soinfo_allocator.protect_all(protection);
+    g_soinfo_links_allocator.protect_all(protection);
+  }
+
+  static size_t ref_count_;
+};
+
+size_t ProtectedDataGuard::ref_count_ = 0;
+
+// Each size has it's own allocator.
+template<size_t size>
+class SizeBasedAllocator {
+ public:
+  static void* alloc() {
+    return allocator_.alloc();
+  }
+
+  static void free(void* ptr) {
+    allocator_.free(ptr);
+  }
+
+ private:
+  static LinkerBlockAllocator allocator_;
+};
+
+template<size_t size>
+LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
+
+template<typename T>
+class TypeBasedAllocator {
+ public:
+  static T* alloc() {
+    return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
+  }
+
+  static void free(T* ptr) {
+    SizeBasedAllocator<sizeof(T)>::free(ptr);
+  }
+};
+
+class LoadTask {
+ public:
+  struct deleter_t {
+    void operator()(LoadTask* t) {
+      TypeBasedAllocator<LoadTask>::free(t);
+    }
+  };
+
+  typedef UniquePtr<LoadTask, deleter_t> unique_ptr;
+
+  static deleter_t deleter;
+
+  static LoadTask* create(const char* name, soinfo* needed_by) {
+    LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
+    return new (ptr) LoadTask(name, needed_by);
+  }
+
+  const char* get_name() const {
+    return name_;
+  }
+
+  soinfo* get_needed_by() const {
+    return needed_by_;
+  }
+ private:
+  LoadTask(const char* name, soinfo* needed_by)
+    : name_(name), needed_by_(needed_by) {}
+
+  const char* name_;
+  soinfo* needed_by_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
+};
+
+LoadTask::deleter_t LoadTask::deleter;
+
+template <typename T>
+using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
+
+typedef linked_list_t<soinfo> SoinfoLinkedList;
+typedef linked_list_t<const char> StringLinkedList;
+typedef linked_list_t<LoadTask> LoadTaskList;
+
+
+// This function walks down the tree of soinfo dependencies
+// in breadth-first order and
+//   * calls action(soinfo* si) for each node, and
+//   * terminates walk if action returns false.
+//
+// walk_dependencies_tree returns false if walk was terminated
+// by the action and true otherwise.
+template<typename F>
+static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
+  SoinfoLinkedList visit_list;
+  SoinfoLinkedList visited;
+
+  for (size_t i = 0; i < root_soinfos_size; ++i) {
+    visit_list.push_back(root_soinfos[i]);
+  }
+
+  soinfo* si;
+  while ((si = visit_list.pop_front()) != nullptr) {
+    if (visited.contains(si)) {
+      continue;
+    }
+
+    if (!action(si)) {
+      return false;
+    }
+
+    visited.push_back(si);
+
+    si->get_children().for_each([&](soinfo* child) {
+      visit_list.push_back(child);
+    });
+  }
+
+  return true;
+}
+
+
+static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
+                                            soinfo** found, SymbolName& symbol_name) {
+  const ElfW(Sym)* result = nullptr;
+  bool skip_lookup = skip_until != nullptr;
+
+  walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
+    if (skip_lookup) {
+      skip_lookup = current_soinfo != skip_until;
+      return true;
+    }
+
+    if (!current_soinfo->find_symbol_by_name(symbol_name, nullptr, &result)) {
+      result = nullptr;
+      return false;
+    }
+
+    if (result != nullptr) {
+      *found = current_soinfo;
+      return false;
+    }
+
+    return true;
+  });
+
+  return result;
+}
+
+// This is used by dlsym(3).  It performs symbol lookup only within the
+// specified soinfo object and its dependencies in breadth first order.
+const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
+  // According to man dlopen(3) and posix docs in the case when si is handle
+  // of the main executable we need to search not only in the executable and its
+  // dependencies but also in all libraries loaded with RTLD_GLOBAL.
+  //
+  // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
+  // libraries and they are loaded in breath-first (correct) order we can just execute
+  // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
+  if (si == somain) {
+    return dlsym_linear_lookup(name, found, nullptr, RTLD_DEFAULT);
+  }
+
+  SymbolName symbol_name(name);
+  return dlsym_handle_lookup(si, nullptr, found, symbol_name);
+}
+
+/* This is used by dlsym(3) to performs a global symbol lookup. If the
+   start value is null (for RTLD_DEFAULT), the search starts at the
+   beginning of the global solist. Otherwise the search starts at the
+   specified soinfo (for RTLD_NEXT).
+ */
+const ElfW(Sym)* dlsym_linear_lookup(const char* name,
+                                     soinfo** found,
+                                     soinfo* caller,
+                                     void* handle) {
+  SymbolName symbol_name(name);
+
+  soinfo* start = solist;
+
+  if (handle == RTLD_NEXT) {
+    if (caller == nullptr) {
+      return nullptr;
+    } else {
+      start = caller->next;
+    }
+  }
+
+  const ElfW(Sym)* s = nullptr;
+  for (soinfo* si = start; si != nullptr; si = si->next) {
+    // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
+    // if the library is opened by application with target api level <= 22
+    // See http://b/21565766
+    if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 && si->get_target_sdk_version() > 22) {
+      continue;
+    }
+
+    if (!si->find_symbol_by_name(symbol_name, nullptr, &s)) {
+      return nullptr;
+    }
+
+    if (s != nullptr) {
+      *found = si;
+      break;
+    }
+  }
+
+  // If not found - use dlsym_handle_lookup for caller's
+  // local_group unless it is part of the global group in which
+  // case we already did it.
+  if (s == nullptr && caller != nullptr &&
+      (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
+    return dlsym_handle_lookup(caller->get_local_group_root(),
+        (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name);
+  }
+
+  if (s != nullptr) {
+    TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
+               name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
+  }
+
+  return s;
+}
+
+soinfo* find_containing_library(const void* p) {
+  ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
+  for (soinfo* si = solist; si != nullptr; si = si->next) {
+    if (address >= si->base && address - si->base < si->size) {
+      return si;
+    }
+  }
+  return nullptr;
+}
+
+ElfW(Sym)* soinfo::find_symbol_by_address(const void* addr) {
+  return is_gnu_hash() ? gnu_addr_lookup(addr) : elf_addr_lookup(addr);
+}
+
+static bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) {
+  return sym->st_shndx != SHN_UNDEF &&
+      soaddr >= sym->st_value &&
+      soaddr < sym->st_value + sym->st_size;
+}
+
+ElfW(Sym)* soinfo::gnu_addr_lookup(const void* addr) {
+  ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
+
+  for (size_t i = 0; i < gnu_nbucket_; ++i) {
+    uint32_t n = gnu_bucket_[i];
+
+    if (n == 0) {
+      continue;
+    }
+
+    do {
+      ElfW(Sym)* sym = symtab_ + n;
+      if (symbol_matches_soaddr(sym, soaddr)) {
+        return sym;
+      }
+    } while ((gnu_chain_[n++] & 1) == 0);
+  }
+
+  return nullptr;
+}
+
+ElfW(Sym)* soinfo::elf_addr_lookup(const void* addr) {
+  ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
+
+  // Search the library's symbol table for any defined symbol which
+  // contains this address.
+  for (size_t i = 0; i < nchain_; ++i) {
+    ElfW(Sym)* sym = symtab_ + i;
+    if (symbol_matches_soaddr(sym, soaddr)) {
+      return sym;
+    }
+  }
+
+  return nullptr;
+}
+
+static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
+  int n = snprintf(buf, buf_size, "%s/%s", path, name);
+  if (n < 0 || n >= static_cast<int>(buf_size)) {
+    PRINT("Warning: ignoring very long library path: %s/%s", path, name);
+    return false;
+  }
+
+  return true;
+}
+
+static int open_library_on_default_path(const char* name, off64_t* file_offset) {
+  for (size_t i = 0; kDefaultLdPaths[i] != nullptr; ++i) {
+    char buf[512];
+    if (!format_path(buf, sizeof(buf), kDefaultLdPaths[i], name)) {
+      continue;
+    }
+
+    int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
+    if (fd != -1) {
+      *file_offset = 0;
+      return fd;
+    }
+  }
+
+  return -1;
+}
+
+static int open_library_on_ld_library_path(const char* name, off64_t* file_offset) {
+  for (const auto& path_str : g_ld_library_paths) {
+    char buf[512];
+    const char* const path = path_str.c_str();
+    if (!format_path(buf, sizeof(buf), path, name)) {
+      continue;
+    }
+
+    int fd = -1;
+    if (fd == -1) {
+      fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
+      if (fd != -1) {
+        *file_offset = 0;
+      }
+    }
+
+    if (fd != -1) {
+      return fd;
+    }
+  }
+
+  return -1;
+}
+
+static int open_library(const char* name, off64_t* file_offset) {
+  TRACE("[ opening %s ]", name);
+
+  // If the name contains a slash, we should attempt to open it directly and not search the paths.
+  if (strchr(name, '/') != nullptr) {
+    int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
+    if (fd != -1) {
+      *file_offset = 0;
+    }
+    return fd;
+  }
+
+  // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
+  int fd = open_library_on_ld_library_path(name, file_offset);
+  if (fd == -1) {
+    fd = open_library_on_default_path(name, file_offset);
+  }
+  return fd;
+}
+
+static const char* fix_dt_needed(const char* dt_needed, const char* sopath) {
+  (void) sopath;
+#if !defined(__LP64__)
+  // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
+  if (get_application_target_sdk_version() <= 22) {
+    const char* bname = basename(dt_needed);
+    if (bname != dt_needed) {
+      DL_WARN("'%s' library has invalid DT_NEEDED entry '%s'", sopath, dt_needed);
+    }
+
+    return bname;
+  }
+#endif
+  return dt_needed;
+}
+
+template<typename F>
+static void for_each_dt_needed(const soinfo* si, F action) {
+  for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
+    if (d->d_tag == DT_NEEDED) {
+      action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
+    }
+  }
+}
+
+static soinfo* load_library(int fd, off64_t file_offset,
+                            LoadTaskList& load_tasks,
+                            const char* name, int rtld_flags,
+                            const android_dlextinfo* extinfo) {
+  if ((file_offset % PAGE_SIZE) != 0) {
+    DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
+    return nullptr;
+  }
+  if (file_offset < 0) {
+    DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
+    return nullptr;
+  }
+
+  struct stat file_stat;
+  if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
+    DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
+    return nullptr;
+  }
+  if (file_offset >= file_stat.st_size) {
+    DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
+        name, file_offset, file_stat.st_size);
+    return nullptr;
+  }
+
+  // Check for symlink and other situations where
+  // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
+  if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
+    for (soinfo* si = solist; si != nullptr; si = si->next) {
+      if (si->get_st_dev() != 0 &&
+          si->get_st_ino() != 0 &&
+          si->get_st_dev() == file_stat.st_dev &&
+          si->get_st_ino() == file_stat.st_ino &&
+          si->get_file_offset() == file_offset) {
+        TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
+            "will return existing soinfo", name, si->get_realpath());
+        return si;
+      }
+    }
+  }
+
+  if ((rtld_flags & RTLD_NOLOAD) != 0) {
+    DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
+    return nullptr;
+  }
+
+  std::string realpath = name;
+  if (!realpath_fd(fd, &realpath)) {
+    PRINT("warning: unable to get realpath for the library \"%s\". Will use given name.", name);
+    realpath = name;
+  }
+
+  // Read the ELF header and load the segments.
+  ElfReader elf_reader(realpath.c_str(), fd, file_offset, file_stat.st_size);
+  if (!elf_reader.Load(extinfo)) {
+    return nullptr;
+  }
+
+  soinfo* si = soinfo_alloc(realpath.c_str(), &file_stat, file_offset, rtld_flags);
+  if (si == nullptr) {
+    return nullptr;
+  }
+  si->base = elf_reader.load_start();
+  si->size = elf_reader.load_size();
+  si->load_bias = elf_reader.load_bias();
+  si->phnum = elf_reader.phdr_count();
+  si->phdr = elf_reader.loaded_phdr();
+
+  if (!si->prelink_image()) {
+    soinfo_free(si);
+    return nullptr;
+  }
+
+  for_each_dt_needed(si, [&] (const char* name) {
+    load_tasks.push_back(LoadTask::create(name, si));
+  });
+
+  return si;
+}
+
+static soinfo* load_library(LoadTaskList& load_tasks,
+                            const char* name, int rtld_flags,
+                            const android_dlextinfo* extinfo) {
+  if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
+    off64_t file_offset = 0;
+    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
+      file_offset = extinfo->library_fd_offset;
+    }
+    return load_library(extinfo->library_fd, file_offset, load_tasks, name, rtld_flags, extinfo);
+  }
+
+  // Open the file.
+  off64_t file_offset;
+  int fd = open_library(name, &file_offset);
+  if (fd == -1) {
+    DL_ERR("library \"%s\" not found", name);
+    return nullptr;
+  }
+  soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo);
+  close(fd);
+  return result;
+}
+
+// Returns true if library was found and false in 2 cases
+// 1. The library was found but loaded under different target_sdk_version
+//    (*candidate != nullptr)
+// 2. The library was not found by soname (*candidate is nullptr)
+static bool find_loaded_library_by_soname(const char* name, soinfo** candidate) {
+  *candidate = nullptr;
+
+  // Ignore filename with path.
+  if (strchr(name, '/') != nullptr) {
+    return false;
+  }
+
+  uint32_t target_sdk_version = get_application_target_sdk_version();
+
+  for (soinfo* si = solist; si != nullptr; si = si->next) {
+    const char* soname = si->get_soname();
+    if (soname != nullptr && (strcmp(name, soname) == 0)) {
+      // If the library was opened under different target sdk version
+      // skip this step and try to reopen it. The exceptions are
+      // "libdl.so" and global group. There is no point in skipping
+      // them because relocation process is going to use them
+      // in any case.
+      bool is_libdl = si == solist;
+      if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 ||
+          !si->is_linked() || si->get_target_sdk_version() == target_sdk_version) {
+        *candidate = si;
+        return true;
+      } else if (*candidate == nullptr) {
+        // for the different sdk version - remember the first library.
+        *candidate = si;
+      }
+    }
+  }
+
+  return false;
+}
+
+static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name,
+                                     int rtld_flags, const android_dlextinfo* extinfo) {
+  soinfo* candidate;
+
+  if (find_loaded_library_by_soname(name, &candidate)) {
+    return candidate;
+  }
+
+  // Library might still be loaded, the accurate detection
+  // of this fact is done by load_library.
+  TRACE("[ '%s' find_loaded_library_by_soname returned false (*candidate=%s@%p). Trying harder...]",
+      name, candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
+
+  soinfo* si = load_library(load_tasks, name, rtld_flags, extinfo);
+
+  // In case we were unable to load the library but there
+  // is a candidate loaded under the same soname but different
+  // sdk level - return it anyways.
+  if (si == nullptr && candidate != nullptr) {
+    si = candidate;
+  }
+
+  return si;
+}
+
+static void soinfo_unload(soinfo* si);
+
+// TODO: this is slightly unusual way to construct
+// the global group for relocation. Not every RTLD_GLOBAL
+// library is included in this group for backwards-compatibility
+// reasons.
+//
+// This group consists of the main executable, LD_PRELOADs
+// and libraries with the DF_1_GLOBAL flag set.
+static soinfo::soinfo_list_t make_global_group() {
+  soinfo::soinfo_list_t global_group;
+  for (soinfo* si = somain; si != nullptr; si = si->next) {
+    if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
+      global_group.push_back(si);
+    }
+  }
+
+  return global_group;
+}
+
+static bool find_libraries(soinfo* start_with, const char* const library_names[],
+      size_t library_names_count, soinfo* soinfos[], std::vector<soinfo*>* ld_preloads,
+      size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) {
+  // Step 0: prepare.
+  LoadTaskList load_tasks;
+  for (size_t i = 0; i < library_names_count; ++i) {
+    const char* name = library_names[i];
+    load_tasks.push_back(LoadTask::create(name, start_with));
+  }
+
+  // Construct global_group.
+  soinfo::soinfo_list_t global_group = make_global_group();
+
+  // If soinfos array is null allocate one on stack.
+  // The array is needed in case of failure; for example
+  // when library_names[] = {libone.so, libtwo.so} and libone.so
+  // is loaded correctly but libtwo.so failed for some reason.
+  // In this case libone.so should be unloaded on return.
+  // See also implementation of failure_guard below.
+
+  if (soinfos == nullptr) {
+    size_t soinfos_size = sizeof(soinfo*)*library_names_count;
+    soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
+    memset(soinfos, 0, soinfos_size);
+  }
+
+  // list of libraries to link - see step 2.
+  size_t soinfos_count = 0;
+
+  auto failure_guard = make_scope_guard([&]() {
+    // Housekeeping
+    load_tasks.for_each([] (LoadTask* t) {
+      LoadTask::deleter(t);
+    });
+
+    for (size_t i = 0; i<soinfos_count; ++i) {
+      soinfo_unload(soinfos[i]);
+    }
+  });
+
+  // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order.
+  for (LoadTask::unique_ptr task(load_tasks.pop_front());
+      task.get() != nullptr; task.reset(load_tasks.pop_front())) {
+    soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo);
+    if (si == nullptr) {
+      return false;
+    }
+
+    soinfo* needed_by = task->get_needed_by();
+
+    if (needed_by != nullptr) {
+      needed_by->add_child(si);
+    }
+
+    if (si->is_linked()) {
+      si->increment_ref_count();
+    }
+
+    // When ld_preloads is not null, the first
+    // ld_preloads_count libs are in fact ld_preloads.
+    if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
+      // Add LD_PRELOADed libraries to the global group for future runs.
+      // There is no need to explicitly add them to the global group
+      // for this run because they are going to appear in the local
+      // group in the correct order.
+      si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
+      ld_preloads->push_back(si);
+    }
+
+    if (soinfos_count < library_names_count) {
+      soinfos[soinfos_count++] = si;
+    }
+  }
+
+  // Step 2: link libraries.
+  soinfo::soinfo_list_t local_group;
+  walk_dependencies_tree(
+      start_with == nullptr ? soinfos : &start_with,
+      start_with == nullptr ? soinfos_count : 1,
+      [&] (soinfo* si) {
+    local_group.push_back(si);
+    return true;
+  });
+
+  // We need to increment ref_count in case
+  // the root of the local group was not linked.
+  bool was_local_group_root_linked = local_group.front()->is_linked();
+
+  bool linked = local_group.visit([&](soinfo* si) {
+    if (!si->is_linked()) {
+      if (!si->link_image(global_group, local_group, extinfo)) {
+        return false;
+      }
+      si->set_linked();
+    }
+
+    return true;
+  });
+
+  if (linked) {
+    failure_guard.disable();
+  }
+
+  if (!was_local_group_root_linked) {
+    local_group.front()->increment_ref_count();
+  }
+
+  return linked;
+}
+
+static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
+  soinfo* si;
+
+  if (name == nullptr) {
+    si = somain;
+  } else if (!find_libraries(nullptr, &name, 1, &si, nullptr, 0, rtld_flags, extinfo)) {
+    return nullptr;
+  }
+
+  return si;
+}
+
+static void soinfo_unload(soinfo* root) {
+  // Note that the library can be loaded but not linked;
+  // in which case there is no root but we still need
+  // to walk the tree and unload soinfos involved.
+  //
+  // This happens on unsuccessful dlopen, when one of
+  // the DT_NEEDED libraries could not be linked/found.
+  if (root->is_linked()) {
+    root = root->get_local_group_root();
+  }
+
+  if (!root->can_unload()) {
+    TRACE("not unloading '%s' - the binary is flagged with NODELETE", root->get_realpath());
+    return;
+  }
+
+  size_t ref_count = root->is_linked() ? root->decrement_ref_count() : 0;
+
+  if (ref_count == 0) {
+    soinfo::soinfo_list_t local_unload_list;
+    soinfo::soinfo_list_t external_unload_list;
+    soinfo::soinfo_list_t depth_first_list;
+    depth_first_list.push_back(root);
+    soinfo* si = nullptr;
+
+    while ((si = depth_first_list.pop_front()) != nullptr) {
+      if (local_unload_list.contains(si)) {
+        continue;
+      }
+
+      local_unload_list.push_back(si);
+
+      if (si->has_min_version(0)) {
+        soinfo* child = nullptr;
+        while ((child = si->get_children().pop_front()) != nullptr) {
+          TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
+              child->get_realpath(), child);
+
+          if (local_unload_list.contains(child)) {
+            continue;
+          } else if (child->is_linked() && child->get_local_group_root() != root) {
+            external_unload_list.push_back(child);
+          } else {
+            depth_first_list.push_front(child);
+          }
+        }
+      } else {
+#if !defined(__work_around_b_19059885__)
+        __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
+#else
+        PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
+        for_each_dt_needed(si, [&] (const char* library_name) {
+          TRACE("deprecated (old format of soinfo): %s needs to unload %s",
+              si->get_realpath(), library_name);
+
+          soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr);
+          if (needed != nullptr) {
+            // Not found: for example if symlink was deleted between dlopen and dlclose
+            // Since we cannot really handle errors at this point - print and continue.
+            PRINT("warning: couldn't find %s needed by %s on unload.",
+                library_name, si->get_realpath());
+            return;
+          } else if (local_unload_list.contains(needed)) {
+            // already visited
+            return;
+          } else if (needed->is_linked() && needed->get_local_group_root() != root) {
+            // external group
+            external_unload_list.push_back(needed);
+          } else {
+            // local group
+            depth_first_list.push_front(needed);
+          }
+        });
+#endif
+      }
+    }
+
+    local_unload_list.for_each([](soinfo* si) {
+      si->call_destructors();
+    });
+
+    while ((si = local_unload_list.pop_front()) != nullptr) {
+      notify_gdb_of_unload(si);
+      soinfo_free(si);
+    }
+
+    while ((si = external_unload_list.pop_front()) != nullptr) {
+      soinfo_unload(si);
+    }
+  } else {
+    TRACE("not unloading '%s' group, decrementing ref_count to %zd",
+        root->get_realpath(), ref_count);
+  }
+}
+
+void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
+  // Use basic string manipulation calls to avoid snprintf.
+  // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
+  // When debug malloc is enabled, this call returns 0. This in turn causes
+  // snprintf to do nothing, which causes libraries to fail to load.
+  // See b/17302493 for further details.
+  // Once the above bug is fixed, this code can be modified to use
+  // snprintf again.
+  size_t required_len = strlen(kDefaultLdPaths[0]) + strlen(kDefaultLdPaths[1]) + 2;
+  if (buffer_size < required_len) {
+    __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
+                 "buffer len %zu, required len %zu", buffer_size, required_len);
+  }
+  char* end = stpcpy(buffer, kDefaultLdPaths[0]);
+  *end = ':';
+  strcpy(end + 1, kDefaultLdPaths[1]);
+}
+
+void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
+  parse_LD_LIBRARY_PATH(ld_library_path);
+}
+
+soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) {
+  if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
+    DL_ERR("invalid flags to dlopen: %x", flags);
+    return nullptr;
+  }
+  if (extinfo != nullptr) {
+    if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
+      DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
+      return nullptr;
+    }
+    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
+        (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
+      DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
+          "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
+      return nullptr;
+    }
+  }
+
+  ProtectedDataGuard guard;
+  soinfo* si = find_library(name, flags, extinfo);
+  if (si != nullptr) {
+    si->call_constructors();
+  }
+  return si;
+}
+
+void do_dlclose(soinfo* si) {
+  ProtectedDataGuard guard;
+  soinfo_unload(si);
+}
+
+static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
+  typedef ElfW(Addr) (*ifunc_resolver_t)(void);
+  ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
+  ElfW(Addr) ifunc_addr = ifunc_resolver();
+  TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
+      ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
+
+  return ifunc_addr;
+}
+
+const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
+  if (source_symver < 2 ||
+      source_symver >= version_infos.size() ||
+      version_infos[source_symver].name == nullptr) {
+    return nullptr;
+  }
+
+  return &version_infos[source_symver];
+}
+
+void VersionTracker::add_version_info(size_t source_index,
+                                      ElfW(Word) elf_hash,
+                                      const char* ver_name,
+                                      const soinfo* target_si) {
+  if (source_index >= version_infos.size()) {
+    version_infos.resize(source_index+1);
+  }
+
+  version_infos[source_index].elf_hash = elf_hash;
+  version_infos[source_index].name = ver_name;
+  version_infos[source_index].target_si = target_si;
+}
+
+bool VersionTracker::init_verneed(const soinfo* si_from) {
+  uintptr_t verneed_ptr = si_from->get_verneed_ptr();
+
+  if (verneed_ptr == 0) {
+    return true;
+  }
+
+  size_t verneed_cnt = si_from->get_verneed_cnt();
+
+  for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
+    const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
+    size_t vernaux_offset = offset + verneed->vn_aux;
+    offset += verneed->vn_next;
+
+    if (verneed->vn_version != 1) {
+      DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
+      return false;
+    }
+
+    const char* target_soname = si_from->get_string(verneed->vn_file);
+    // find it in dependencies
+    soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
+      return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
+    });
+
+    if (target_si == nullptr) {
+      DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
+          target_soname, i, si_from->get_realpath());
+      return false;
+    }
+
+    for (size_t j = 0; j<verneed->vn_cnt; ++j) {
+      const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
+      vernaux_offset += vernaux->vna_next;
+
+      const ElfW(Word) elf_hash = vernaux->vna_hash;
+      const char* ver_name = si_from->get_string(vernaux->vna_name);
+      ElfW(Half) source_index = vernaux->vna_other;
+
+      add_version_info(source_index, elf_hash, ver_name, target_si);
+    }
+  }
+
+  return true;
+}
+
+bool VersionTracker::init_verdef(const soinfo* si_from) {
+  return for_each_verdef(si_from,
+    [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
+      add_version_info(verdef->vd_ndx, verdef->vd_hash,
+          si_from->get_string(verdaux->vda_name), si_from);
+      return false;
+    }
+  );
+}
+
+bool VersionTracker::init(const soinfo* si_from) {
+  if (!si_from->has_min_version(2)) {
+    return true;
+  }
+
+  return init_verneed(si_from) && init_verdef(si_from);
+}
+
+bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
+                                 const char* sym_name, const version_info** vi) {
+  const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
+  ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
+
+  if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
+    *vi = version_tracker.get_version_info(sym_ver);
+
+    if (*vi == nullptr) {
+      DL_ERR("cannot find verneed/verdef for version index=%d "
+          "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
+      return false;
+    }
+  } else {
+    // there is no version info
+    *vi = nullptr;
+  }
+
+  return true;
+}
+
+#if !defined(__mips__)
+#if defined(USE_RELA)
+static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr ) {
+  return rela->r_addend;
+}
+#else
+static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
+  if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
+      ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
+    return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
+  }
+  return 0;
+}
+#endif
+
+template<typename ElfRelIteratorT>
+bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
+                      const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
+  for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
+    const auto rel = rel_iterator.next();
+    if (rel == nullptr) {
+      return false;
+    }
+
+    ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
+    ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
+
+    ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
+    ElfW(Addr) sym_addr = 0;
+    const char* sym_name = nullptr;
+    ElfW(Addr) addend = get_addend(rel, reloc);
+
+    DEBUG("Processing '%s' relocation at index %zd", get_realpath(), idx);
+    if (type == R_GENERIC_NONE) {
+      continue;
+    }
+
+    const ElfW(Sym)* s = nullptr;
+    soinfo* lsi = nullptr;
+
+    if (sym != 0) {
+      sym_name = get_string(symtab_[sym].st_name);
+      const version_info* vi = nullptr;
+
+      sym_addr = reinterpret_cast<ElfW(Addr)>(_get_hooked_symbol(sym_name, get_realpath()));
+      if (!sym_addr) {
+        if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
+          return false;
+        }
+
+        if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
+          return false;
+        }
+      }
+
+      if (sym_addr == 0 && s == nullptr) {
+        // We only allow an undefined symbol if this is a weak reference...
+        s = &symtab_[sym];
+        if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
+          DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
+          return false;
+        }
+
+        /* IHI0044C AAELF 4.5.1.1:
+
+           Libraries are not searched to resolve weak references.
+           It is not an error for a weak reference to remain unsatisfied.
+
+           During linking, the value of an undefined weak reference is:
+           - Zero if the relocation type is absolute
+           - The address of the place if the relocation is pc-relative
+           - The address of nominal base address if the relocation
+             type is base-relative.
+         */
+
+        switch (type) {
+          case R_GENERIC_JUMP_SLOT:
+          case R_GENERIC_GLOB_DAT:
+          case R_GENERIC_RELATIVE:
+          case R_GENERIC_IRELATIVE:
+#if defined(__aarch64__)
+          case R_AARCH64_ABS64:
+          case R_AARCH64_ABS32:
+          case R_AARCH64_ABS16:
+#elif defined(__x86_64__)
+          case R_X86_64_32:
+          case R_X86_64_64:
+#elif defined(__arm__)
+          case R_ARM_ABS32:
+#elif defined(__i386__)
+          case R_386_32:
+#endif
+            /*
+             * The sym_addr was initialized to be zero above, or the relocation
+             * code below does not care about value of sym_addr.
+             * No need to do anything.
+             */
+            break;
+#if defined(__x86_64__)
+          case R_X86_64_PC32:
+            sym_addr = reloc;
+            break;
+#elif defined(__i386__)
+          case R_386_PC32:
+            sym_addr = reloc;
+            break;
+#endif
+          default:
+            DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
+            return false;
+        }
+      } else if (sym_addr == 0) { // We got a definition.
+#if !defined(__LP64__)
+        // When relocating dso with text_relocation .text segment is
+        // not executable. We need to restore elf flags before resolving
+        // STT_GNU_IFUNC symbol.
+        bool protect_segments = has_text_relocations &&
+                                lsi == this &&
+                                ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
+        if (protect_segments) {
+          if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
+            DL_ERR("can't protect segments for \"%s\": %s",
+                   get_realpath(), strerror(errno));
+            return false;
+          }
+        }
+#endif
+        sym_addr = lsi->resolve_symbol_address(s);
+#if !defined(__LP64__)
+        if (protect_segments) {
+          if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
+            DL_ERR("can't unprotect loadable segments for \"%s\": %s",
+                   get_realpath(), strerror(errno));
+            return false;
+          }
+        }
+#endif
+      }
+      count_relocation(kRelocSymbol);
+    }
+
+    switch (type) {
+      case R_GENERIC_JUMP_SLOT:
+        count_relocation(kRelocAbsolute);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
+                   reinterpret_cast<void*>(reloc),
+                   reinterpret_cast<void*>(sym_addr + addend), sym_name);
+
+        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
+        break;
+      case R_GENERIC_GLOB_DAT:
+        count_relocation(kRelocAbsolute);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
+                   reinterpret_cast<void*>(reloc),
+                   reinterpret_cast<void*>(sym_addr + addend), sym_name);
+        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
+        break;
+      case R_GENERIC_RELATIVE:
+        count_relocation(kRelocRelative);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
+                   reinterpret_cast<void*>(reloc),
+                   reinterpret_cast<void*>(load_bias + addend));
+        *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
+        break;
+      case R_GENERIC_IRELATIVE:
+        count_relocation(kRelocRelative);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
+                    reinterpret_cast<void*>(reloc),
+                    reinterpret_cast<void*>(load_bias + addend));
+        {
+#if !defined(__LP64__)
+          // When relocating dso with text_relocation .text segment is
+          // not executable. We need to restore elf flags for this
+          // particular call.
+          if (has_text_relocations) {
+            if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
+              DL_ERR("can't protect segments for \"%s\": %s",
+                     get_realpath(), strerror(errno));
+              return false;
+            }
+          }
+#endif
+          ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
+#if !defined(__LP64__)
+          // Unprotect it afterwards...
+          if (has_text_relocations) {
+            if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
+              DL_ERR("can't unprotect loadable segments for \"%s\": %s",
+                     get_realpath(), strerror(errno));
+              return false;
+            }
+          }
+#endif
+          *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
+        }
+        break;
+
+#if defined(__aarch64__)
+      case R_AARCH64_ABS64:
+        count_relocation(kRelocAbsolute);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO ABS64 %16" PRIx64 " <- %16" PRIx64 " %s\n",
+                   reloc, (sym_addr + addend), sym_name);
+        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
+        break;
+      case R_AARCH64_ABS32:
+        count_relocation(kRelocAbsolute);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO ABS32 %16" PRIx64 " <- %16" PRIx64 " %s\n",
+                   reloc, (sym_addr + addend), sym_name);
+        {
+          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
+          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
+          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
+          if ((min_value <= (reloc_value + (sym_addr + addend))) &&
+              ((reloc_value + (sym_addr + addend)) <= max_value)) {
+            *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
+          } else {
+            DL_ERR("0x%016" PRIx64 " out of range 0x%016" PRIx64 " to 0x%016" PRIx64,
+                   (reloc_value + (sym_addr + addend)), min_value, max_value);
+            return false;
+          }
+        }
+        break;
+      case R_AARCH64_ABS16:
+        count_relocation(kRelocAbsolute);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO ABS16 %16" PRIx64 " <- %16" PRIx64 " %s\n",
+                   reloc, (sym_addr + addend), sym_name);
+        {
+          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
+          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
+          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
+          if ((min_value <= (reloc_value + (sym_addr + addend))) &&
+              ((reloc_value + (sym_addr + addend)) <= max_value)) {
+            *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
+          } else {
+            DL_ERR("0x%016" PRIx64 " out of range 0x%016" PRIx64 " to 0x%016" PRIx64,
+                   reloc_value + (sym_addr + addend), min_value, max_value);
+            return false;
+          }
+        }
+        break;
+      case R_AARCH64_PREL64:
+        count_relocation(kRelocRelative);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO REL64 %16" PRIx64 " <- %16" PRIx64 " - %16" PRIx64 " %s\n",
+                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
+        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend) - rel->r_offset;
+        break;
+      case R_AARCH64_PREL32:
+        count_relocation(kRelocRelative);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO REL32 %16" PRIx64 " <- %16" PRIx64 " - %16" PRIx64 " %s\n",
+                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
+        {
+          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
+          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
+          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
+          if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) &&
+              ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) {
+            *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
+          } else {
+            DL_ERR("0x%016" PRIx64 " out of range 0x%016" PRIx64 " to 0x%016" PRIx64,
+                   reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value);
+            return false;
+          }
+        }
+        break;
+      case R_AARCH64_PREL16:
+        count_relocation(kRelocRelative);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO REL16 %16" PRIx64 " <- %16" PRIx64 " - %16" PRIx64 " %s\n",
+                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
+        {
+          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
+          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
+          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
+          if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) &&
+              ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) {
+            *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
+          } else {
+            DL_ERR("0x%016" PRIx64 " out of range 0x%016" PRIx64 " to 0x%016" PRIx64,
+                   reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value);
+            return false;
+          }
+        }
+        break;
+
+      case R_AARCH64_COPY:
+        /*
+         * ET_EXEC is not supported so this should not happen.
+         *
+         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
+         *
+         * Section 4.6.11 "Dynamic relocations"
+         * R_AARCH64_COPY may only appear in executable objects where e_type is
+         * set to ET_EXEC.
+         */
+        DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
+        return false;
+      case R_AARCH64_TLS_TPREL:
+        TRACE_TYPE(RELO, "RELO TLS_TPREL *** %16" PRIx64 " <- %16" PRIx64 " - %16" PRIx64 "\n",
+                   reloc, (sym_addr + addend), rel->r_offset);
+        break;
+      case R_AARCH64_TLS_DTPREL:
+        TRACE_TYPE(RELO, "RELO TLS_DTPREL *** %16" PRIx64 " <- %16" PRIx64 " - %16" PRIx64 "\n",
+                   reloc, (sym_addr + addend), rel->r_offset);
+        break;
+#elif defined(__x86_64__)
+      case R_X86_64_32:
+        count_relocation(kRelocRelative);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
+                   static_cast<size_t>(sym_addr), sym_name);
+        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
+        break;
+      case R_X86_64_64:
+        count_relocation(kRelocRelative);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
+                   static_cast<size_t>(sym_addr), sym_name);
+        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
+        break;
+      case R_X86_64_PC32:
+        count_relocation(kRelocRelative);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
+                   static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
+                   static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
+        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - reloc;
+        break;
+#elif defined(__arm__)
+      case R_ARM_ABS32:
+        count_relocation(kRelocAbsolute);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
+        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
+        break;
+      case R_ARM_REL32:
+        count_relocation(kRelocRelative);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
+                   reloc, sym_addr, rel->r_offset, sym_name);
+        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
+        break;
+      case R_ARM_COPY:
+        /*
+         * ET_EXEC is not supported so this should not happen.
+         *
+         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
+         *
+         * Section 4.6.1.10 "Dynamic relocations"
+         * R_ARM_COPY may only appear in executable objects where e_type is
+         * set to ET_EXEC.
+         */
+        DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
+        return false;
+#elif defined(__i386__)
+      case R_386_32:
+        count_relocation(kRelocRelative);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
+        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
+        break;
+      case R_386_PC32:
+        count_relocation(kRelocRelative);
+        MARK(rel->r_offset);
+        TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
+                   reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
+        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
+        break;
+#endif
+      default:
+        DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
+        return false;
+    }
+  }
+  return true;
+}
+#endif  // !defined(__mips__)
+
+void soinfo::call_array(const char* array_name , linker_function_t* functions,
+                        size_t count, bool reverse) {
+  if (functions == nullptr) {
+    return;
+  }
+
+  TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, get_realpath());
+
+  int begin = reverse ? (count - 1) : 0;
+  int end = reverse ? -1 : count;
+  int step = reverse ? -1 : 1;
+
+  for (int i = begin; i != end; i += step) {
+    TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]);
+    call_function("function", functions[i]);
+  }
+
+  TRACE("[ Done calling %s for '%s' ]", array_name, get_realpath());
+}
+
+void soinfo::call_function(const char* function_name , linker_function_t function) {
+  if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
+    return;
+  }
+
+  TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, get_realpath());
+  function();
+  TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, get_realpath());
+}
+
+void soinfo::call_pre_init_constructors() {
+  // DT_PREINIT_ARRAY functions are called before any other constructors for executables,
+  // but ignored in a shared library.
+  call_array("DT_PREINIT_ARRAY", preinit_array_, preinit_array_count_, false);
+}
+
+void soinfo::call_constructors() {
+  if (constructors_called) {
+    return;
+  }
+
+  if (strcmp(soname_, "libc.so") == 0) {
+    DEBUG("HYBRIS: =============> Skipping libc.so\n");
+    return;
+  }
+
+  // We set constructors_called before actually calling the constructors, otherwise it doesn't
+  // protect against recursive constructor calls. One simple example of constructor recursion
+  // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
+  // 1. The program depends on libc, so libc's constructor is called here.
+  // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
+  // 3. dlopen() calls the constructors on the newly created
+  //    soinfo for libc_malloc_debug_leak.so.
+  // 4. The debug .so depends on libc, so CallConstructors is
+  //    called again with the libc soinfo. If it doesn't trigger the early-
+  //    out above, the libc constructor will be called again (recursively!).
+  constructors_called = true;
+
+  if (!is_main_executable() && preinit_array_ != nullptr) {
+    // The GNU dynamic linker silently ignores these, but we warn the developer.
+    PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!",
+          get_realpath(), preinit_array_count_);
+  }
+
+  get_children().for_each([] (soinfo* si) {
+    si->call_constructors();
+  });
+
+  TRACE("\"%s\": calling constructors", get_realpath());
+
+  // DT_INIT should be called before DT_INIT_ARRAY if both are present.
+  call_function("DT_INIT", init_func_);
+  call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false);
+}
+
+void soinfo::call_destructors() {
+  if (!constructors_called) {
+    return;
+  }
+  TRACE("\"%s\": calling destructors", get_realpath());
+
+  // DT_FINI_ARRAY must be parsed in reverse order.
+  call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true);
+
+  // DT_FINI should be called after DT_FINI_ARRAY if both are present.
+  call_function("DT_FINI", fini_func_);
+
+  // This is needed on second call to dlopen
+  // after library has been unloaded with RTLD_NODELETE
+  constructors_called = false;
+}
+
+void soinfo::add_child(soinfo* child) {
+  if (has_min_version(0)) {
+    child->parents_.push_back(this);
+    this->children_.push_back(child);
+  }
+}
+
+void soinfo::remove_all_links() {
+  if (!has_min_version(0)) {
+    return;
+  }
+
+  // 1. Untie connected soinfos from 'this'.
+  children_.for_each([&] (soinfo* child) {
+    child->parents_.remove_if([&] (const soinfo* parent) {
+      return parent == this;
+    });
+  });
+
+  parents_.for_each([&] (soinfo* parent) {
+    parent->children_.remove_if([&] (const soinfo* child) {
+      return child == this;
+    });
+  });
+
+  // 2. Once everything untied - clear local lists.
+  parents_.clear();
+  children_.clear();
+}
+
+dev_t soinfo::get_st_dev() const {
+  if (has_min_version(0)) {
+    return st_dev_;
+  }
+
+  return 0;
+};
+
+ino_t soinfo::get_st_ino() const {
+  if (has_min_version(0)) {
+    return st_ino_;
+  }
+
+  return 0;
+}
+
+off64_t soinfo::get_file_offset() const {
+  if (has_min_version(1)) {
+    return file_offset_;
+  }
+
+  return 0;
+}
+
+uint32_t soinfo::get_rtld_flags() const {
+  if (has_min_version(1)) {
+    return rtld_flags_;
+  }
+
+  return 0;
+}
+
+uint32_t soinfo::get_dt_flags_1() const {
+  if (has_min_version(1)) {
+    return dt_flags_1_;
+  }
+
+  return 0;
+}
+
+void soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
+  if (has_min_version(1)) {
+    if ((dt_flags_1 & DF_1_GLOBAL) != 0) {
+      rtld_flags_ |= RTLD_GLOBAL;
+    }
+
+    if ((dt_flags_1 & DF_1_NODELETE) != 0) {
+      rtld_flags_ |= RTLD_NODELETE;
+    }
+
+    dt_flags_1_ = dt_flags_1;
+  }
+}
+
+const char* soinfo::get_realpath() const {
+#if defined(__work_around_b_19059885__)
+  if (has_min_version(2)) {
+    return realpath_.c_str();
+  } else {
+    return old_name_;
+  }
+#else
+  return realpath_.c_str();
+#endif
+}
+
+const char* soinfo::get_soname() const {
+#if defined(__work_around_b_19059885__)
+  if (has_min_version(2)) {
+    return soname_;
+  } else {
+    return old_name_;
+  }
+#else
+  return soname_;
+#endif
+}
+
+// This is a return on get_children()/get_parents() if
+// 'this->flags' does not have FLAG_NEW_SOINFO set.
+static soinfo::soinfo_list_t g_empty_list;
+
+soinfo::soinfo_list_t& soinfo::get_children() {
+  if (has_min_version(0)) {
+    return children_;
+  }
+
+  return g_empty_list;
+}
+
+const soinfo::soinfo_list_t& soinfo::get_children() const {
+  if (has_min_version(0)) {
+    return children_;
+  }
+
+  return g_empty_list;
+}
+
+soinfo::soinfo_list_t& soinfo::get_parents() {
+  if (has_min_version(0)) {
+    return parents_;
+  }
+
+  return g_empty_list;
+}
+
+ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
+  if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
+    return call_ifunc_resolver(s->st_value + load_bias);
+  }
+
+  return static_cast<ElfW(Addr)>(s->st_value + load_bias);
+}
+
+const char* soinfo::get_string(ElfW(Word) index) const {
+  if (has_min_version(1) && (index >= strtab_size_)) {
+    __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
+        get_realpath(), strtab_size_, index);
+  }
+
+  return strtab_ + index;
+}
+
+bool soinfo::is_gnu_hash() const {
+  return (flags_ & FLAG_GNU_HASH) != 0;
+}
+
+bool soinfo::can_unload() const {
+  return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0;
+}
+
+bool soinfo::is_linked() const {
+  return (flags_ & FLAG_LINKED) != 0;
+}
+
+bool soinfo::is_main_executable() const {
+  return (flags_ & FLAG_EXE) != 0;
+}
+
+void soinfo::set_linked() {
+  flags_ |= FLAG_LINKED;
+}
+
+void soinfo::set_linker_flag() {
+  flags_ |= FLAG_LINKER;
+}
+
+void soinfo::set_main_executable() {
+  flags_ |= FLAG_EXE;
+}
+
+void soinfo::increment_ref_count() {
+  local_group_root_->ref_count_++;
+}
+
+size_t soinfo::decrement_ref_count() {
+  return --local_group_root_->ref_count_;
+}
+
+soinfo* soinfo::get_local_group_root() const {
+  return local_group_root_;
+}
+
+// This function returns api-level at the time of
+// dlopen/load. Note that libraries opened by system
+// will always have 'current' api level.
+uint32_t soinfo::get_target_sdk_version() const {
+  if (!has_min_version(2)) {
+    return __ANDROID_API__;
+  }
+
+  return local_group_root_->target_sdk_version_;
+}
+
+bool soinfo::prelink_image() {
+  /* Extract dynamic section */
+  ElfW(Word) dynamic_flags = 0;
+  phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
+
+  /* We can't log anything until the linker is relocated */
+  bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
+  if (!relocating_linker) {
+    INFO("[ linking %s ]", get_realpath());
+    DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
+  }
+
+  if (dynamic == nullptr) {
+    if (!relocating_linker) {
+      DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
+    }
+    return false;
+  } else {
+    if (!relocating_linker) {
+      DEBUG("dynamic = %p", dynamic);
+    }
+  }
+
+#if defined(__arm__)
+  (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
+                                  &ARM_exidx, &ARM_exidx_count);
+#endif
+
+  // Extract useful information from dynamic section.
+  // Note that: "Except for the DT_NULL element at the end of the array,
+  // and the relative order of DT_NEEDED elements, entries may appear in any order."
+  //
+  // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
+  uint32_t needed_count = 0;
+  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
+    DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
+          d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
+    switch (d->d_tag) {
+      case DT_SONAME:
+        // this is parsed after we have strtab initialized (see below).
+        break;
+
+      case DT_HASH:
+        nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
+        nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
+        bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
+        chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
+        break;
+
+      case DT_GNU_HASH:
+        gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
+        // skip symndx
+        gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
+        gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
+
+        gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
+        gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
+        // amend chain for symndx = header[1]
+        gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
+            reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
+
+        if (!powerof2(gnu_maskwords_)) {
+          DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
+              gnu_maskwords_, get_realpath());
+          return false;
+        }
+        --gnu_maskwords_;
+
+        flags_ |= FLAG_GNU_HASH;
+        break;
+
+      case DT_STRTAB:
+        strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
+        break;
+
+      case DT_STRSZ:
+        strtab_size_ = d->d_un.d_val;
+        break;
+
+      case DT_SYMTAB:
+        symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
+        break;
+
+      case DT_SYMENT:
+        if (d->d_un.d_val != sizeof(ElfW(Sym))) {
+          DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
+              static_cast<size_t>(d->d_un.d_val), get_realpath());
+          return false;
+        }
+        break;
+
+      case DT_PLTREL:
+#if defined(USE_RELA)
+        if (d->d_un.d_val != DT_RELA) {
+          DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
+          return false;
+        }
+#else
+        if (d->d_un.d_val != DT_REL) {
+          DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
+          return false;
+        }
+#endif
+        break;
+
+      case DT_JMPREL:
+#if defined(USE_RELA)
+        plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
+#else
+        plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
+#endif
+        break;
+
+      case DT_PLTRELSZ:
+#if defined(USE_RELA)
+        plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
+#else
+        plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
+#endif
+        break;
+
+      case DT_PLTGOT:
+#if defined(__mips__)
+        // Used by mips and mips64.
+        plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
+#endif
+        // Ignore for other platforms... (because RTLD_LAZY is not supported)
+        break;
+
+      case DT_DEBUG:
+        // Set the DT_DEBUG entry to the address of _r_debug for GDB
+        // if the dynamic table is writable
+// FIXME: not working currently for N64
+// The flags for the LOAD and DYNAMIC program headers do not agree.
+// The LOAD section containing the dynamic table has been mapped as
+// read-only, but the DYNAMIC header claims it is writable.
+#if !(defined(__mips__) && defined(__LP64__))
+        if ((dynamic_flags & PF_W) != 0) {
+          d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
+        }
+#endif
+        break;
+#if defined(USE_RELA)
+      case DT_RELA:
+        rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
+        break;
+
+      case DT_RELASZ:
+        rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
+        break;
+
+      case DT_ANDROID_RELA:
+        android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
+        break;
+
+      case DT_ANDROID_RELASZ:
+        android_relocs_size_ = d->d_un.d_val;
+        break;
+
+      case DT_ANDROID_REL:
+        DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
+        return false;
+
+      case DT_ANDROID_RELSZ:
+        DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
+        return false;
+
+      case DT_RELAENT:
+        if (d->d_un.d_val != sizeof(ElfW(Rela))) {
+          DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
+          return false;
+        }
+        break;
+
+      // ignored (see DT_RELCOUNT comments for details)
+      case DT_RELACOUNT:
+        break;
+
+      case DT_REL:
+        DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
+        return false;
+
+      case DT_RELSZ:
+        DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
+        return false;
+
+#else
+      case DT_REL:
+        rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
+        break;
+
+      case DT_RELSZ:
+        rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
+        break;
+
+      case DT_RELENT:
+        if (d->d_un.d_val != sizeof(ElfW(Rel))) {
+          DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
+          return false;
+        }
+        break;
+
+      case DT_ANDROID_REL:
+        android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
+        break;
+
+      case DT_ANDROID_RELSZ:
+        android_relocs_size_ = d->d_un.d_val;
+        break;
+
+      case DT_ANDROID_RELA:
+        DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
+        return false;
+
+      case DT_ANDROID_RELASZ:
+        DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
+        return false;
+
+      // "Indicates that all RELATIVE relocations have been concatenated together,
+      // and specifies the RELATIVE relocation count."
+      //
+      // TODO: Spec also mentions that this can be used to optimize relocation process;
+      // Not currently used by bionic linker - ignored.
+      case DT_RELCOUNT:
+        break;
+
+      case DT_RELA:
+        DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
+        return false;
+
+      case DT_RELASZ:
+        DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
+        return false;
+
+#endif
+      case DT_INIT:
+        init_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
+        DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
+        break;
+
+      case DT_FINI:
+        fini_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
+        DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
+        break;
+
+      case DT_INIT_ARRAY:
+        init_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
+        DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
+        break;
+
+      case DT_INIT_ARRAYSZ:
+        init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
+        break;
+
+      case DT_FINI_ARRAY:
+        fini_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
+        DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
+        break;
+
+      case DT_FINI_ARRAYSZ:
+        fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
+        break;
+
+      case DT_PREINIT_ARRAY:
+        preinit_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
+        DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
+        break;
+
+      case DT_PREINIT_ARRAYSZ:
+        preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
+        break;
+
+      case DT_TEXTREL:
+#if defined(__LP64__)
+        DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
+        return false;
+#else
+        has_text_relocations = true;
+        break;
+#endif
+
+      case DT_SYMBOLIC:
+        has_DT_SYMBOLIC = true;
+        break;
+
+      case DT_NEEDED:
+        ++needed_count;
+        break;
+
+      case DT_FLAGS:
+        if (d->d_un.d_val & DF_TEXTREL) {
+#if defined(__LP64__)
+          DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
+          return false;
+#else
+          has_text_relocations = true;
+#endif
+        }
+        if (d->d_un.d_val & DF_SYMBOLIC) {
+          has_DT_SYMBOLIC = true;
+        }
+        break;
+
+      case DT_FLAGS_1:
+        set_dt_flags_1(d->d_un.d_val);
+
+        if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
+          DL_WARN("%s: unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
+        }
+        break;
+#if defined(__mips__)
+      case DT_MIPS_RLD_MAP:
+        // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
+        {
+          r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
+          *dp = &_r_debug;
+        }
+        break;
+      case DT_MIPS_RLD_MAP2:
+        // Set the DT_MIPS_RLD_MAP2 entry to the address of _r_debug for GDB.
+        {
+          r_debug** dp = reinterpret_cast<r_debug**>(
+              reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
+          *dp = &_r_debug;
+        }
+        break;
+
+      case DT_MIPS_RLD_VERSION:
+      case DT_MIPS_FLAGS:
+      case DT_MIPS_BASE_ADDRESS:
+      case DT_MIPS_UNREFEXTNO:
+        break;
+
+      case DT_MIPS_SYMTABNO:
+        mips_symtabno_ = d->d_un.d_val;
+        break;
+
+      case DT_MIPS_LOCAL_GOTNO:
+        mips_local_gotno_ = d->d_un.d_val;
+        break;
+
+      case DT_MIPS_GOTSYM:
+        mips_gotsym_ = d->d_un.d_val;
+        break;
+#endif
+      // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
+      case DT_BIND_NOW:
+        break;
+
+      case DT_VERSYM:
+        versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
+        break;
+
+      case DT_VERDEF:
+        verdef_ptr_ = load_bias + d->d_un.d_ptr;
+        break;
+      case DT_VERDEFNUM:
+        verdef_cnt_ = d->d_un.d_val;
+        break;
+
+      case DT_VERNEED:
+        verneed_ptr_ = load_bias + d->d_un.d_ptr;
+        break;
+
+      case DT_VERNEEDNUM:
+        verneed_cnt_ = d->d_un.d_val;
+        break;
+
+      default:
+        if (!relocating_linker) {
+          DL_WARN("%s: unused DT entry: type %p arg %p", get_realpath(),
+              reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
+        }
+        break;
+    }
+  }
+
+  DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
+        reinterpret_cast<void*>(base), strtab_, symtab_);
+
+  // Sanity checks.
+  if (relocating_linker && needed_count != 0) {
+    DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
+    return false;
+  }
+  if (nbucket_ == 0 && gnu_nbucket_ == 0) {
+    DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
+        "(new hash type from the future?)", get_realpath());
+    return false;
+  }
+  if (strtab_ == 0) {
+    DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
+    return false;
+  }
+  if (symtab_ == 0) {
+    DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
+    return false;
+  }
+
+  // second pass - parse entries relying on strtab
+  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
+    if (d->d_tag == DT_SONAME) {
+      soname_ = get_string(d->d_un.d_val);
+#if defined(__work_around_b_19059885__)
+      strlcpy(old_name_, soname_, sizeof(old_name_));
+#endif
+      break;
+    }
+  }
+
+  // Before M release linker was using basename in place of soname.
+  // In the case when dt_soname is absent some apps stop working
+  // because they can't find dt_needed library by soname.
+  // This workaround should keep them working. (applies only
+  // for apps targeting sdk version <=22). Make an exception for
+  // the main executable and linker; they do not need to have dt_soname
+  if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 &&
+      get_application_target_sdk_version() <= 22) {
+    soname_ = basename(realpath_.c_str());
+    DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
+        get_realpath(), soname_);
+  }
+  return true;
+}
+
+bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
+                        const android_dlextinfo* extinfo) {
+
+  local_group_root_ = local_group.front();
+  if (local_group_root_ == nullptr) {
+    local_group_root_ = this;
+  }
+
+  if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
+    target_sdk_version_ = get_application_target_sdk_version();
+  }
+
+  VersionTracker version_tracker;
+
+  if (!version_tracker.init(this)) {
+    return false;
+  }
+
+#if !defined(__LP64__)
+  if (has_text_relocations) {
+    // Fail if app is targeting sdk version > 22
+    // TODO (dimitry): remove != __ANDROID_API__ check once http://b/20020312 is fixed
+    if (get_application_target_sdk_version() != __ANDROID_API__
+        && get_application_target_sdk_version() > 22) {
+      DL_ERR("%s: has text relocations", get_realpath());
+      return false;
+    }
+    // Make segments writable to allow text relocations to work properly. We will later call
+    // phdr_table_protect_segments() after all of them are applied and all constructors are run.
+    DL_WARN("%s has text relocations. This is wasting memory and prevents "
+            "security hardening. Please fix.", get_realpath());
+    if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
+      DL_ERR("can't unprotect loadable segments for \"%s\": %s",
+             get_realpath(), strerror(errno));
+      return false;
+    }
+  }
+#endif
+
+  if (android_relocs_ != nullptr) {
+    // check signature
+    if (android_relocs_size_ > 3 &&
+        android_relocs_[0] == 'A' &&
+        android_relocs_[1] == 'P' &&
+        android_relocs_[2] == 'S' &&
+        android_relocs_[3] == '2') {
+      DEBUG("[ android relocating %s ]", get_realpath());
+
+      bool relocated = false;
+      const uint8_t* packed_relocs = android_relocs_ + 4;
+      const size_t packed_relocs_size = android_relocs_size_ - 4;
+
+      relocated = relocate(
+          version_tracker,
+          packed_reloc_iterator<sleb128_decoder>(
+            sleb128_decoder(packed_relocs, packed_relocs_size)),
+          global_group, local_group);
+
+      if (!relocated) {
+        return false;
+      }
+    } else {
+      DL_ERR("bad android relocation header.");
+      return false;
+    }
+  }
+
+#if defined(USE_RELA)
+  if (rela_ != nullptr) {
+    DEBUG("[ relocating %s ]", get_realpath());
+    if (!relocate(version_tracker,
+            plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
+      return false;
+    }
+  }
+  if (plt_rela_ != nullptr) {
+    DEBUG("[ relocating %s plt ]", get_realpath());
+    if (!relocate(version_tracker,
+            plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
+      return false;
+    }
+  }
+#else
+  if (rel_ != nullptr) {
+    DEBUG("[ relocating %s ]", get_realpath());
+    if (!relocate(version_tracker,
+            plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
+      return false;
+    }
+  }
+  if (plt_rel_ != nullptr) {
+    DEBUG("[ relocating %s plt ]", get_realpath());
+    if (!relocate(version_tracker,
+            plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
+      return false;
+    }
+  }
+#endif
+
+#if defined(__mips__)
+  if (!mips_relocate_got(version_tracker, global_group, local_group)) {
+    return false;
+  }
+#endif
+
+  DEBUG("[ finished linking %s ]", get_realpath());
+
+#if !defined(__LP64__)
+  if (has_text_relocations) {
+    // All relocations are done, we can protect our segments back to read-only.
+    if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
+      DL_ERR("can't protect segments for \"%s\": %s",
+             get_realpath(), strerror(errno));
+      return false;
+    }
+  }
+#endif
+
+  /* We can also turn on GNU RELRO protection */
+  if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
+    DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
+           get_realpath(), strerror(errno));
+    return false;
+  }
+
+  /* Handle serializing/sharing the RELRO segment */
+  if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
+    if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
+                                       extinfo->relro_fd) < 0) {
+      DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
+             get_realpath(), strerror(errno));
+      return false;
+    }
+  } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
+    if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
+                                 extinfo->relro_fd) < 0) {
+      DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
+             get_realpath(), strerror(errno));
+      return false;
+    }
+  }
+
+  notify_gdb_of_load(this);
+  return true;
+}
+
+/*
+ * This function add vdso to internal dso list.
+ * It helps to stack unwinding through signal handlers.
+ * Also, it makes bionic more like glibc.
+ */
+static void add_vdso(KernelArgumentBlock& args) {
+#if defined(AT_SYSINFO_EHDR)
+  ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR));
+  if (ehdr_vdso == nullptr) {
+    return;
+  }
+
+  soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0);
+
+  si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
+  si->phnum = ehdr_vdso->e_phnum;
+  si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso);
+  si->size = phdr_table_get_load_size(si->phdr, si->phnum);
+  si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
+
+  si->prelink_image();
+  si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr);
+#endif
+}
+
+/*
+ * This is linker soinfo for GDB. See details below.
+ */
+#if defined(__LP64__)
+#define LINKER_PATH "/system/bin/linker64"
+#else
+#define LINKER_PATH "/system/bin/linker"
+#endif
+
+// This is done to avoid calling c-tor prematurely
+// because soinfo c-tor needs memory allocator
+// which might be initialized after global variables.
+static uint8_t linker_soinfo_for_gdb_buf[sizeof(soinfo)] __attribute__((aligned(8)));
+static soinfo* linker_soinfo_for_gdb = nullptr;
+
+/* gdb expects the linker to be in the debug shared object list.
+ * Without this, gdb has trouble locating the linker's ".text"
+ * and ".plt" sections. Gdb could also potentially use this to
+ * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
+ * Don't use soinfo_alloc(), because the linker shouldn't
+ * be on the soinfo list.
+ */
+static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
+  linker_soinfo_for_gdb = new (linker_soinfo_for_gdb_buf) soinfo(LINKER_PATH, nullptr, 0, 0);
+
+  linker_soinfo_for_gdb->load_bias = linker_base;
+
+  /*
+   * Set the dynamic field in the link map otherwise gdb will complain with
+   * the following:
+   *   warning: .dynamic section for "/system/bin/linker" is not at the
+   *   expected address (wrong library or version mismatch?)
+   */
+  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base);
+  ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff);
+  phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
+                                 &linker_soinfo_for_gdb->dynamic, nullptr);
+  insert_soinfo_into_debug_map(linker_soinfo_for_gdb);
+}
+
+extern "C" int __system_properties_init(void);
+
+/*
+ * This code is called after the linker has linked itself and
+ * fixed it's own GOT. It is safe to make references to externs
+ * and other non-local data at this point.
+ */
+static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
+#if TIMING
+  struct timeval t0, t1;
+  gettimeofday(&t0, 0);
+#endif
+
+#ifdef DISABLED_FOR_HYBRIS_SUPPORT
+  // Sanitize the environment.
+  __libc_init_AT_SECURE(args);
+
+  // Initialize system properties
+  __system_properties_init(); // may use 'environ'
+#endif
+
+#ifdef DISABLED_FOR_HYBRIS_SUPPORT
+  debuggerd_init();
+#endif
+
+  // Get a few environment variables.
+  const char* LD_DEBUG = getenv("HYBRIS_LD_DEBUG");
+  if (LD_DEBUG != nullptr) {
+    g_ld_debug_verbosity = atoi(LD_DEBUG);
+  }
+
+  // These should have been sanitized by __libc_init_AT_SECURE, but the test
+  // doesn't cost us anything.
+  const char* ldpath_env = nullptr;
+  const char* ldpreload_env = nullptr;
+  if (!getauxval(AT_SECURE)) {
+    ldpath_env = getenv("HYBRIS_LD_LIBRARY_PATH");
+    ldpreload_env = getenv("HYBRIS_LD_PRELOAD");
+  }
+
+  INFO("[ android linker & debugger ]");
+
+  soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL);
+  if (si == nullptr) {
+    exit(EXIT_FAILURE);
+  }
+
+  /* bootstrap the link map, the main exe always needs to be first */
+  si->set_main_executable();
+  link_map* map = &(si->link_map_head);
+
+  map->l_addr = 0;
+  map->l_name = args.argv[0];
+  map->l_prev = nullptr;
+  map->l_next = nullptr;
+
+  _r_debug.r_map = map;
+  r_debug_tail = map;
+
+  init_linker_info_for_gdb(linker_base);
+
+  // Extract information passed from the kernel.
+  si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR));
+  si->phnum = args.getauxval(AT_PHNUM);
+  si->entry = args.getauxval(AT_ENTRY);
+
+  /* Compute the value of si->base. We can't rely on the fact that
+   * the first entry is the PHDR because this will not be true
+   * for certain executables (e.g. some in the NDK unit test suite)
+   */
+  si->base = 0;
+  si->size = phdr_table_get_load_size(si->phdr, si->phnum);
+  si->load_bias = 0;
+  for (size_t i = 0; i < si->phnum; ++i) {
+    if (si->phdr[i].p_type == PT_PHDR) {
+      si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr;
+      si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset;
+      break;
+    }
+  }
+  si->dynamic = nullptr;
+
+  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
+  if (elf_hdr->e_type != ET_DYN) {
+    fprintf(stderr, "error: only position independent executables (PIE) are supported.\n");
+    exit(EXIT_FAILURE);
+  }
+
+  // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
+  if (DEFAULT_HYBRIS_LD_LIBRARY_PATH)
+    parse_LD_LIBRARY_PATH(DEFAULT_HYBRIS_LD_LIBRARY_PATH);
+  else
+    parse_LD_LIBRARY_PATH(ldpath_env);
+  parse_LD_PRELOAD(ldpreload_env);
+
+  somain = si;
+
+  if (!si->prelink_image()) {
+    fprintf(stderr, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
+    exit(EXIT_FAILURE);
+  }
+
+  // add somain to global group
+  si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
+
+  // Load ld_preloads and dependencies.
+  StringLinkedList needed_library_name_list;
+  size_t needed_libraries_count = 0;
+  size_t ld_preloads_count = 0;
+
+  for (const auto& ld_preload_name : g_ld_preload_names) {
+    needed_library_name_list.push_back(ld_preload_name.c_str());
+    ++needed_libraries_count;
+    ++ld_preloads_count;
+  }
+
+  for_each_dt_needed(si, [&](const char* name) {
+    needed_library_name_list.push_back(name);
+    ++needed_libraries_count;
+  });
+
+  const char* needed_library_names[needed_libraries_count];
+
+  memset(needed_library_names, 0, sizeof(needed_library_names));
+  needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
+
+  if (needed_libraries_count > 0 &&
+      !find_libraries(si, needed_library_names, needed_libraries_count, nullptr,
+          &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) {
+    fprintf(stderr, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
+    exit(EXIT_FAILURE);
+  } else if (needed_libraries_count == 0) {
+    if (!si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr)) {
+      fprintf(stderr, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
+      exit(EXIT_FAILURE);
+    }
+    si->increment_ref_count();
+  }
+
+  add_vdso(args);
+
+  {
+    ProtectedDataGuard guard;
+
+    si->call_pre_init_constructors();
+
+    /* After the prelink_image, the si->load_bias is initialized.
+     * For so lib, the map->l_addr will be updated in notify_gdb_of_load.
+     * We need to update this value for so exe here. So Unwind_Backtrace
+     * for some arch like x86 could work correctly within so exe.
+     */
+    map->l_addr = si->load_bias;
+    si->call_constructors();
+  }
+
+#if TIMING
+  gettimeofday(&t1, nullptr);
+  PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) (
+           (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
+           (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)));
+#endif
+#if STATS
+  PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0],
+         linker_stats.count[kRelocAbsolute],
+         linker_stats.count[kRelocRelative],
+         linker_stats.count[kRelocCopy],
+         linker_stats.count[kRelocSymbol]);
+#endif
+#if COUNT_PAGES
+  {
+    unsigned n;
+    unsigned i;
+    unsigned count = 0;
+    for (n = 0; n < 4096; n++) {
+      if (bitmask[n]) {
+        unsigned x = bitmask[n];
+#if defined(__LP64__)
+        for (i = 0; i < 32; i++) {
+#else
+        for (i = 0; i < 8; i++) {
+#endif
+          if (x & 1) {
+            count++;
+          }
+          x >>= 1;
+        }
+      }
+    }
+    PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4);
+  }
+#endif
+
+#if TIMING || STATS || COUNT_PAGES
+  fflush(stdout);
+#endif
+
+  TRACE("[ Ready to execute '%s' @ %p ]", si->get_realpath(), reinterpret_cast<void*>(si->entry));
+  return si->entry;
+}
+
+/* Compute the load-bias of an existing executable. This shall only
+ * be used to compute the load bias of an executable or shared library
+ * that was loaded by the kernel itself.
+ *
+ * Input:
+ *    elf    -> address of ELF header, assumed to be at the start of the file.
+ * Return:
+ *    load bias, i.e. add the value of any p_vaddr in the file to get
+ *    the corresponding address in memory.
+ */
+static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) {
+  ElfW(Addr) offset = elf->e_phoff;
+  const ElfW(Phdr)* phdr_table =
+      reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
+  const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
+
+  for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
+    if (phdr->p_type == PT_LOAD) {
+      return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr;
+    }
+  }
+  return 0;
+}
+
+extern "C" void android_linker_init(int sdk_version, void* (*get_hooked_symbol)(const char*, const char*)) {
+  // Get a few environment variables.
+  const char* LD_DEBUG = getenv("HYBRIS_LD_DEBUG");
+  if (LD_DEBUG != nullptr) {
+    g_ld_debug_verbosity = atoi(LD_DEBUG);
+  }
+
+  if (sdk_version > 0)
+    set_application_target_sdk_version(sdk_version);
+
+  _get_hooked_symbol = get_hooked_symbol;
+}
+
+#ifdef DISABLED_FOR_HYBRIS_SUPPORT
+extern "C" void _start();
+
+/*
+ * This is the entry point for the linker, called from begin.S. This
+ * method is responsible for fixing the linker's own relocations, and
+ * then calling __linker_init_post_relocation().
+ *
+ * Because this method is called before the linker has fixed it's own
+ * relocations, any attempt to reference an extern variable, extern
+ * function, or other GOT reference will generate a segfault.
+ */
+extern "C" ElfW(Addr) __linker_init(void* raw_args) {
+  KernelArgumentBlock args(raw_args);
+
+  ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
+  ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
+  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
+  ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
+
+  soinfo linker_so(nullptr, nullptr, 0, 0);
+
+  // If the linker is not acting as PT_INTERP entry_point is equal to
+  // _start. Which means that the linker is running as an executable and
+  // already linked by PT_INTERP.
+  //
+  // This happens when user tries to run 'adb shell /system/bin/linker'
+  // see also https://code.google.com/p/android/issues/detail?id=63174
+  if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
+    __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]);
+  }
+
+  linker_so.base = linker_addr;
+  linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
+  linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
+  linker_so.dynamic = nullptr;
+  linker_so.phdr = phdr;
+  linker_so.phnum = elf_hdr->e_phnum;
+  linker_so.set_linker_flag();
+
+  // This might not be obvious... The reasons why we pass g_empty_list
+  // in place of local_group here are (1) we do not really need it, because
+  // linker is built with DT_SYMBOLIC and therefore relocates its symbols against
+  // itself without having to look into local_group and (2) allocators
+  // are not yet initialized, and therefore we cannot use linked_list.push_*
+  // functions at this point.
+  if (!(linker_so.prelink_image() && linker_so.link_image(g_empty_list, g_empty_list, nullptr))) {
+    // It would be nice to print an error message, but if the linker
+    // can't link itself, there's no guarantee that we'll be able to
+    // call write() (because it involves a GOT reference). We may as
+    // well try though...
+    const char* msg = "CANNOT LINK EXECUTABLE: ";
+    int unused __attribute__((unused));
+    unused = write(2, msg, strlen(msg));
+    unused = write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));
+    unused = write(2, "\n", 1);
+    _exit(EXIT_FAILURE);
+  }
+
+#ifdef DISABLED_FOR_HYBRIS_SUPPORT
+  __libc_init_tls(args);
+#endif
+
+  // Initialize the linker's own global variables
+  linker_so.call_constructors();
+
+  // Initialize static variables. Note that in order to
+  // get correct libdl_info we need to call constructors
+  // before get_libdl_info().
+  solist = get_libdl_info();
+  sonext = get_libdl_info();
+
+  // We have successfully fixed our own relocations. It's safe to run
+  // the main part of the linker now.
+  args.abort_message_ptr = &g_abort_message;
+  ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
+
+  INFO("[ jumping to _start ]");
+
+  // Return the address that the calling assembly stub should jump to.
+  return start_address;
+}
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker.h
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINKER_H_
+#define _LINKER_H_
+
+#include <elf.h>
+#include <inttypes.h>
+#include <link.h>
+#include <unistd.h>
+#include <android/dlext.h>
+#include <sys/stat.h>
+
+#include "private/libc_logging.h"
+#include "linked_list.h"
+
+#include <string>
+#include <vector>
+
+#define DL_ERR(fmt, x...) \
+    do { \
+      fprintf(stderr, fmt, ##x); \
+      fprintf(stderr, "\n"); \
+      /* If LD_DEBUG is set high enough, log every dlerror(3) message. */ \
+      DEBUG("%s\n", linker_get_error_buffer()); \
+    } while (false)
+
+#define DL_WARN(fmt, x...) \
+    do { \
+      fprintf(stderr, "WARNING: linker " fmt, ##x); \
+      fprintf(stderr, "\n"); \
+    } while (false)
+
+#if defined(__LP64__)
+#define ELFW(what) ELF64_ ## what
+#else
+#define ELFW(what) ELF32_ ## what
+#endif
+
+// mips64 interprets Elf64_Rel structures' r_info field differently.
+// bionic (like other C libraries) has macros that assume regular ELF files,
+// but the dynamic linker needs to be able to load mips64 ELF files.
+#if defined(__mips__) && defined(__LP64__)
+#undef ELF64_R_SYM
+#undef ELF64_R_TYPE
+#undef ELF64_R_INFO
+#define ELF64_R_SYM(info)   (((info) >> 0) & 0xffffffff)
+#define ELF64_R_SSYM(info)  (((info) >> 32) & 0xff)
+#define ELF64_R_TYPE3(info) (((info) >> 40) & 0xff)
+#define ELF64_R_TYPE2(info) (((info) >> 48) & 0xff)
+#define ELF64_R_TYPE(info)  (((info) >> 56) & 0xff)
+#endif
+
+// Returns the address of the page containing address 'x'.
+#define PAGE_START(x)  ((x) & PAGE_MASK)
+
+// Returns the offset of address 'x' in its page.
+#define PAGE_OFFSET(x) ((x) & ~PAGE_MASK)
+
+// Returns the address of the next page after address 'x', unless 'x' is
+// itself at the start of a page.
+#define PAGE_END(x)    PAGE_START((x) + (PAGE_SIZE-1))
+
+#define FLAG_LINKED     0x00000001
+#define FLAG_EXE        0x00000004 // The main executable
+#define FLAG_LINKER     0x00000010 // The linker itself
+#define FLAG_GNU_HASH   0x00000040 // uses gnu hash
+#define FLAG_NEW_SOINFO 0x40000000 // new soinfo format
+
+#define SUPPORTED_DT_FLAGS_1 (DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)
+
+#define SOINFO_VERSION 2
+
+#if defined(__work_around_b_19059885__)
+#define SOINFO_NAME_LEN 128
+#endif
+
+typedef void (*linker_function_t)();
+
+// Android uses RELA for aarch64 and x86_64. mips64 still uses REL.
+#if defined(__aarch64__) || defined(__x86_64__)
+#define USE_RELA 1
+#endif
+
+struct soinfo;
+
+class SoinfoListAllocator {
+ public:
+  static LinkedListEntry<soinfo>* alloc();
+  static void free(LinkedListEntry<soinfo>* entry);
+
+ private:
+  // unconstructable
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SoinfoListAllocator);
+};
+
+class SymbolName {
+ public:
+  explicit SymbolName(const char* name)
+      : name_(name), has_elf_hash_(false), has_gnu_hash_(false),
+        elf_hash_(0), gnu_hash_(0) { }
+
+  const char* get_name() {
+    return name_;
+  }
+
+  uint32_t elf_hash();
+  uint32_t gnu_hash();
+
+ private:
+  const char* name_;
+  bool has_elf_hash_;
+  bool has_gnu_hash_;
+  uint32_t elf_hash_;
+  uint32_t gnu_hash_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SymbolName);
+};
+
+struct version_info {
+  version_info() : elf_hash(0), name(nullptr), target_si(nullptr) {}
+
+  uint32_t elf_hash;
+  const char* name;
+  const soinfo* target_si;
+};
+
+// Class used construct version dependency graph.
+class VersionTracker {
+ public:
+  VersionTracker() = default;
+  bool init(const soinfo* si_from);
+
+  const version_info* get_version_info(ElfW(Versym) source_symver) const;
+ private:
+  bool init_verneed(const soinfo* si_from);
+  bool init_verdef(const soinfo* si_from);
+  void add_version_info(size_t source_index, ElfW(Word) elf_hash,
+      const char* ver_name, const soinfo* target_si);
+
+  std::vector<version_info> version_infos;
+
+  DISALLOW_COPY_AND_ASSIGN(VersionTracker);
+};
+
+struct soinfo {
+ public:
+  typedef LinkedList<soinfo, SoinfoListAllocator> soinfo_list_t;
+#if defined(__work_around_b_19059885__)
+ private:
+  char old_name_[SOINFO_NAME_LEN];
+#endif
+ public:
+  const ElfW(Phdr)* phdr;
+  size_t phnum;
+  ElfW(Addr) entry;
+  ElfW(Addr) base;
+  size_t size;
+
+#if defined(__work_around_b_19059885__)
+  uint32_t unused1;  // DO NOT USE, maintained for compatibility.
+#endif
+
+  ElfW(Dyn)* dynamic;
+
+#if defined(__work_around_b_19059885__)
+  uint32_t unused2; // DO NOT USE, maintained for compatibility
+  uint32_t unused3; // DO NOT USE, maintained for compatibility
+#endif
+
+  soinfo* next;
+ private:
+  uint32_t flags_;
+
+  const char* strtab_;
+  ElfW(Sym)* symtab_;
+
+  size_t nbucket_;
+  size_t nchain_;
+  uint32_t* bucket_;
+  uint32_t* chain_;
+
+#if defined(__mips__) || !defined(__LP64__)
+  // This is only used by mips and mips64, but needs to be here for
+  // all 32-bit architectures to preserve binary compatibility.
+  ElfW(Addr)** plt_got_;
+#endif
+
+#if defined(USE_RELA)
+  ElfW(Rela)* plt_rela_;
+  size_t plt_rela_count_;
+
+  ElfW(Rela)* rela_;
+  size_t rela_count_;
+#else
+  ElfW(Rel)* plt_rel_;
+  size_t plt_rel_count_;
+
+  ElfW(Rel)* rel_;
+  size_t rel_count_;
+#endif
+
+  linker_function_t* preinit_array_;
+  size_t preinit_array_count_;
+
+  linker_function_t* init_array_;
+  size_t init_array_count_;
+  linker_function_t* fini_array_;
+  size_t fini_array_count_;
+
+  linker_function_t init_func_;
+  linker_function_t fini_func_;
+
+#if defined(__arm__)
+ public:
+  // ARM EABI section used for stack unwinding.
+  uint32_t* ARM_exidx;
+  size_t ARM_exidx_count;
+ private:
+#elif defined(__mips__)
+  uint32_t mips_symtabno_;
+  uint32_t mips_local_gotno_;
+  uint32_t mips_gotsym_;
+  bool mips_relocate_got(const VersionTracker& version_tracker,
+                         const soinfo_list_t& global_group,
+                         const soinfo_list_t& local_group);
+
+#endif
+  size_t ref_count_;
+ public:
+  link_map link_map_head;
+
+  bool constructors_called;
+
+  // When you read a virtual address from the ELF file, add this
+  // value to get the corresponding address in the process' address space.
+  ElfW(Addr) load_bias;
+
+#if !defined(__LP64__)
+  bool has_text_relocations;
+#endif
+  bool has_DT_SYMBOLIC;
+
+ public:
+  soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags);
+
+  void call_constructors();
+  void call_destructors();
+  void call_pre_init_constructors();
+  bool prelink_image();
+  bool link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
+                  const android_dlextinfo* extinfo);
+
+  void add_child(soinfo* child);
+  void remove_all_links();
+
+  ino_t get_st_ino() const;
+  dev_t get_st_dev() const;
+  off64_t get_file_offset() const;
+
+  uint32_t get_rtld_flags() const;
+  uint32_t get_dt_flags_1() const;
+  void set_dt_flags_1(uint32_t dt_flags_1);
+
+  soinfo_list_t& get_children();
+  const soinfo_list_t& get_children() const;
+
+  soinfo_list_t& get_parents();
+
+  bool find_symbol_by_name(SymbolName& symbol_name,
+                           const version_info* vi,
+                           const ElfW(Sym)** symbol) const;
+
+  ElfW(Sym)* find_symbol_by_address(const void* addr);
+  ElfW(Addr) resolve_symbol_address(const ElfW(Sym)* s) const;
+
+  const char* get_string(ElfW(Word) index) const;
+  bool can_unload() const;
+  bool is_gnu_hash() const;
+
+  bool inline has_min_version(uint32_t min_version) const {
+#if defined(__work_around_b_19059885__)
+    (void) min_version;
+    return (flags_ & FLAG_NEW_SOINFO) != 0 && version_ >= min_version;
+#else
+    return true;
+#endif
+  }
+
+  bool is_linked() const;
+  bool is_main_executable() const;
+
+  void set_linked();
+  void set_linker_flag();
+  void set_main_executable();
+
+  void increment_ref_count();
+  size_t decrement_ref_count();
+
+  soinfo* get_local_group_root() const;
+
+  const char* get_soname() const;
+  const char* get_realpath() const;
+  const ElfW(Versym)* get_versym(size_t n) const;
+  ElfW(Addr) get_verneed_ptr() const;
+  size_t get_verneed_cnt() const;
+  ElfW(Addr) get_verdef_ptr() const;
+  size_t get_verdef_cnt() const;
+
+  bool find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const;
+
+  uint32_t get_target_sdk_version() const;
+
+ private:
+  bool elf_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
+  ElfW(Sym)* elf_addr_lookup(const void* addr);
+  bool gnu_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
+  ElfW(Sym)* gnu_addr_lookup(const void* addr);
+
+  bool lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
+                           const char* sym_name, const version_info** vi);
+
+  void call_array(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
+  void call_function(const char* function_name, linker_function_t function);
+  template<typename ElfRelIteratorT>
+  bool relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
+                const soinfo_list_t& global_group, const soinfo_list_t& local_group);
+
+ private:
+  // This part of the structure is only available
+  // when FLAG_NEW_SOINFO is set in this->flags.
+  uint32_t version_;
+
+  // version >= 0
+  dev_t st_dev_;
+  ino_t st_ino_;
+
+  // dependency graph
+  soinfo_list_t children_;
+  soinfo_list_t parents_;
+
+  // version >= 1
+  off64_t file_offset_;
+  uint32_t rtld_flags_;
+  uint32_t dt_flags_1_;
+  size_t strtab_size_;
+
+  // version >= 2
+
+  size_t gnu_nbucket_;
+  uint32_t* gnu_bucket_;
+  uint32_t* gnu_chain_;
+  uint32_t gnu_maskwords_;
+  uint32_t gnu_shift2_;
+  ElfW(Addr)* gnu_bloom_filter_;
+
+  soinfo* local_group_root_;
+
+  uint8_t* android_relocs_;
+  size_t android_relocs_size_;
+
+  const char* soname_;
+  std::string realpath_;
+
+  const ElfW(Versym)* versym_;
+
+  ElfW(Addr) verdef_ptr_;
+  size_t verdef_cnt_;
+
+  ElfW(Addr) verneed_ptr_;
+  size_t verneed_cnt_;
+
+  uint32_t target_sdk_version_;
+
+  friend soinfo* get_libdl_info();
+};
+
+bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
+                      soinfo** si_found_in, const soinfo::soinfo_list_t& global_group,
+                      const soinfo::soinfo_list_t& local_group, const ElfW(Sym)** symbol);
+
+enum RelocationKind {
+  kRelocAbsolute = 0,
+  kRelocRelative,
+  kRelocCopy,
+  kRelocSymbol,
+  kRelocMax
+};
+
+void count_relocation(RelocationKind kind);
+
+soinfo* get_libdl_info();
+
+void do_android_get_LD_LIBRARY_PATH(char*, size_t);
+void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
+soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo);
+void do_dlclose(soinfo* si);
+
+int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data);
+
+const ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller, void* handle);
+soinfo* find_containing_library(const void* addr);
+
+const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name);
+
+void debuggerd_init();
+extern "C" abort_msg_t* g_abort_message;
+extern "C" void notify_gdb_of_libraries();
+
+char* linker_get_error_buffer();
+size_t linker_get_error_buffer_size();
+
+void set_application_target_sdk_version(uint32_t target);
+uint32_t get_application_target_sdk_version();
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker_allocator.cpp
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.
+ */
+
+#include "linker_allocator.h"
+#include "linker.h"
+
+#include <algorithm>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <memory.h>
+
+#include "private/bionic_prctl.h"
+
+#include "hybris_compat.h"
+
+//
+// LinkerMemeoryAllocator is general purpose allocator
+// designed to provide the same functionality as the malloc/free/realloc
+// libc functions.
+//
+// On alloc:
+// If size is >= 1k allocator proxies malloc call directly to mmap
+// If size < 1k allocator uses SmallObjectAllocator for the size
+// rounded up to the nearest power of two.
+//
+// On free:
+//
+// For a pointer allocated using proxy-to-mmap allocator unmaps
+// the memory.
+//
+// For a pointer allocated using SmallObjectAllocator it adds
+// the block to free_blocks_list_. If the number of free pages reaches 2,
+// SmallObjectAllocator munmaps one of the pages keeping the other one
+// in reserve.
+
+static const char kSignature[4] = {'L', 'M', 'A', 1};
+
+static const size_t kSmallObjectMaxSize = 1 << kSmallObjectMaxSizeLog2;
+
+// This type is used for large allocations (with size >1k)
+static const uint32_t kLargeObject = 111;
+
+bool operator<(const small_object_page_record& one, const small_object_page_record& two) {
+  return one.page_addr < two.page_addr;
+}
+
+static inline uint16_t log2(size_t number) {
+  uint16_t result = 0;
+  number--;
+
+  while (number != 0) {
+    result++;
+    number >>= 1;
+  }
+
+  return result;
+}
+
+LinkerSmallObjectAllocator::LinkerSmallObjectAllocator()
+    : type_(0), name_(nullptr), block_size_(0), free_pages_cnt_(0), free_blocks_list_(nullptr) {}
+
+void* LinkerSmallObjectAllocator::alloc() {
+  if (free_blocks_list_ == nullptr) {
+    alloc_page();
+  }
+
+  small_object_block_record* block_record = free_blocks_list_;
+  if (block_record->free_blocks_cnt > 1) {
+    small_object_block_record* next_free = reinterpret_cast<small_object_block_record*>(
+        reinterpret_cast<uint8_t*>(block_record) + block_size_);
+    next_free->next = block_record->next;
+    next_free->free_blocks_cnt = block_record->free_blocks_cnt - 1;
+    free_blocks_list_ = next_free;
+  } else {
+    free_blocks_list_ = block_record->next;
+  }
+
+  // bookkeeping...
+  auto page_record = find_page_record(block_record);
+
+  if (page_record->allocated_blocks_cnt == 0) {
+    free_pages_cnt_--;
+  }
+
+  page_record->free_blocks_cnt--;
+  page_record->allocated_blocks_cnt++;
+
+  memset(block_record, 0, block_size_);
+
+  return block_record;
+}
+
+void LinkerSmallObjectAllocator::free_page(linker_vector_t::iterator page_record) {
+  void* page_start = reinterpret_cast<void*>(page_record->page_addr);
+  void* page_end = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(page_start) + PAGE_SIZE);
+
+  while (free_blocks_list_ != nullptr &&
+      free_blocks_list_ > page_start &&
+      free_blocks_list_ < page_end) {
+    free_blocks_list_ = free_blocks_list_->next;
+  }
+
+  small_object_block_record* current = free_blocks_list_;
+
+  while (current != nullptr) {
+    while (current->next > page_start && current->next < page_end) {
+      current->next = current->next->next;
+    }
+
+    current = current->next;
+  }
+
+  munmap(page_start, PAGE_SIZE);
+  page_records_.erase(page_record);
+  free_pages_cnt_--;
+}
+
+void LinkerSmallObjectAllocator::free(void* ptr) {
+  auto page_record = find_page_record(ptr);
+
+  ssize_t offset = reinterpret_cast<uintptr_t>(ptr) - sizeof(page_info);
+
+  if (offset % block_size_ != 0) {
+    __libc_fatal("invalid pointer: %p (block_size=%zd)", ptr, block_size_);
+  }
+
+  memset(ptr, 0, block_size_);
+  small_object_block_record* block_record = reinterpret_cast<small_object_block_record*>(ptr);
+
+  block_record->next = free_blocks_list_;
+  block_record->free_blocks_cnt = 1;
+
+  free_blocks_list_ = block_record;
+
+  page_record->free_blocks_cnt++;
+  page_record->allocated_blocks_cnt--;
+
+  if (page_record->allocated_blocks_cnt == 0) {
+    if (free_pages_cnt_++ > 1) {
+      // if we already have a free page - unmap this one.
+      free_page(page_record);
+    }
+  }
+}
+
+void LinkerSmallObjectAllocator::init(uint32_t type, size_t block_size, const char* name) {
+  type_ = type;
+  block_size_ = block_size;
+  name_ = name;
+}
+
+linker_vector_t::iterator LinkerSmallObjectAllocator::find_page_record(void* ptr) {
+  void* addr = reinterpret_cast<void*>(PAGE_START(reinterpret_cast<uintptr_t>(ptr)));
+  small_object_page_record boundary;
+  boundary.page_addr = addr;
+  linker_vector_t::iterator it = std::lower_bound(
+      page_records_.begin(), page_records_.end(), boundary);
+
+  if (it == page_records_.end() || it->page_addr != addr) {
+    // not found...
+    __libc_fatal("page record for %p was not found (block_size=%zd)", ptr, block_size_);
+  }
+
+  return it;
+}
+
+void LinkerSmallObjectAllocator::create_page_record(void* page_addr, size_t free_blocks_cnt) {
+  small_object_page_record record;
+  record.page_addr = page_addr;
+  record.free_blocks_cnt = free_blocks_cnt;
+  record.allocated_blocks_cnt = 0;
+
+  linker_vector_t::iterator it = std::lower_bound(
+      page_records_.begin(), page_records_.end(), record);
+  page_records_.insert(it, record);
+}
+
+void LinkerSmallObjectAllocator::alloc_page() {
+  void* map_ptr = mmap(nullptr, PAGE_SIZE,
+      PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
+  if (map_ptr == MAP_FAILED) {
+    __libc_fatal("mmap failed");
+  }
+
+  prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_ptr, PAGE_SIZE, name_);
+
+  memset(map_ptr, 0, PAGE_SIZE);
+
+  page_info* info = reinterpret_cast<page_info*>(map_ptr);
+  memcpy(info->signature, kSignature, sizeof(kSignature));
+  info->type = type_;
+  info->allocator_addr = this;
+
+  size_t free_blocks_cnt = (PAGE_SIZE - sizeof(page_info))/block_size_;
+
+  create_page_record(map_ptr, free_blocks_cnt);
+
+  small_object_block_record* first_block = reinterpret_cast<small_object_block_record*>(info + 1);
+
+  first_block->next = free_blocks_list_;
+  first_block->free_blocks_cnt = free_blocks_cnt;
+
+  free_blocks_list_ = first_block;
+}
+
+
+LinkerMemoryAllocator::LinkerMemoryAllocator() {
+  static const char* allocator_names[kSmallObjectAllocatorsCount] = {
+    "linker_alloc_16", // 2^4
+    "linker_alloc_32", // 2^5
+    "linker_alloc_64", // and so on...
+    "linker_alloc_128",
+    "linker_alloc_256",
+    "linker_alloc_512",
+    "linker_alloc_1024", // 2^10
+  };
+
+  for (size_t i = 0; i < kSmallObjectAllocatorsCount; ++i) {
+    uint32_t type = i + kSmallObjectMinSizeLog2;
+    allocators_[i].init(type, 1 << type, allocator_names[i]);
+  }
+}
+
+void* LinkerMemoryAllocator::alloc_mmap(size_t size) {
+  size_t allocated_size = PAGE_END(size + sizeof(page_info));
+  void* map_ptr = mmap(nullptr, allocated_size,
+      PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
+
+  if (map_ptr == MAP_FAILED) {
+    __libc_fatal("mmap failed");
+  }
+
+  prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_ptr, allocated_size, "linker_alloc_lob");
+
+  memset(map_ptr, 0, allocated_size);
+
+  page_info* info = reinterpret_cast<page_info*>(map_ptr);
+  memcpy(info->signature, kSignature, sizeof(kSignature));
+  info->type = kLargeObject;
+  info->allocated_size = allocated_size;
+
+  return info + 1;
+}
+
+void* LinkerMemoryAllocator::alloc(size_t size) {
+  // treat alloc(0) as alloc(1)
+  if (size == 0) {
+    size = 1;
+  }
+
+  if (size > kSmallObjectMaxSize) {
+    return alloc_mmap(size);
+  }
+
+  uint16_t log2_size = log2(size);
+
+  if (log2_size < kSmallObjectMinSizeLog2) {
+    log2_size = kSmallObjectMinSizeLog2;
+  }
+
+  return get_small_object_allocator(log2_size)->alloc();
+}
+
+page_info* LinkerMemoryAllocator::get_page_info(void* ptr) {
+  page_info* info = reinterpret_cast<page_info*>(PAGE_START(reinterpret_cast<size_t>(ptr)));
+  if (memcmp(info->signature, kSignature, sizeof(kSignature)) != 0) {
+    __libc_fatal("invalid pointer %p (page signature mismatch)", ptr);
+  }
+
+  return info;
+}
+
+void* LinkerMemoryAllocator::realloc(void* ptr, size_t size) {
+  if (ptr == nullptr) {
+    return alloc(size);
+  }
+
+  if (size == 0) {
+    free(ptr);
+    return nullptr;
+  }
+
+  page_info* info = get_page_info(ptr);
+
+  size_t old_size = 0;
+
+  if (info->type == kLargeObject) {
+    old_size = info->allocated_size - sizeof(page_info);
+  } else {
+    LinkerSmallObjectAllocator* allocator = get_small_object_allocator(info->type);
+    if (allocator != info->allocator_addr) {
+      __libc_fatal("invalid pointer %p (page signature mismatch)", ptr);
+    }
+
+    old_size = allocator->get_block_size();
+  }
+
+  if (old_size < size) {
+    void *result = alloc(size);
+    memcpy(result, ptr, old_size);
+    free(ptr);
+    return result;
+  }
+
+  return ptr;
+}
+
+void LinkerMemoryAllocator::free(void* ptr) {
+  if (ptr == nullptr) {
+    return;
+  }
+
+  page_info* info = get_page_info(ptr);
+
+  if (info->type == kLargeObject) {
+    munmap(info, info->allocated_size);
+  } else {
+    LinkerSmallObjectAllocator* allocator = get_small_object_allocator(info->type);
+    if (allocator != info->allocator_addr) {
+      __libc_fatal("invalid pointer %p (invalid allocator address for the page)", ptr);
+    }
+
+    allocator->free(ptr);
+  }
+}
+
+LinkerSmallObjectAllocator* LinkerMemoryAllocator::get_small_object_allocator(uint32_t type) {
+  if (type < kSmallObjectMinSizeLog2 || type > kSmallObjectMaxSizeLog2) {
+    __libc_fatal("invalid type: %u", type);
+  }
+
+  return &allocators_[type - kSmallObjectMinSizeLog2];
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker_allocator.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.
+ */
+
+#ifndef __LINKER_ALLOCATOR_H
+#define __LINKER_ALLOCATOR_H
+
+#include <stdlib.h>
+#include <sys/cdefs.h>
+#include <sys/mman.h>
+#include <stddef.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "private/bionic_prctl.h"
+#include "private/libc_logging.h"
+
+const uint32_t kSmallObjectMaxSizeLog2 = 10;
+const uint32_t kSmallObjectMinSizeLog2 = 4;
+const uint32_t kSmallObjectAllocatorsCount = kSmallObjectMaxSizeLog2 - kSmallObjectMinSizeLog2 + 1;
+
+class LinkerSmallObjectAllocator;
+
+// This structure is placed at the beginning of each addressable page
+// and has all information we need to find the corresponding memory allocator.
+struct page_info {
+  char signature[4];
+  uint32_t type;
+  union {
+    // we use allocated_size for large objects allocator
+    size_t allocated_size;
+    // and allocator_addr for small ones.
+    LinkerSmallObjectAllocator* allocator_addr;
+  };
+};
+
+struct small_object_page_record {
+  void* page_addr;
+  size_t free_blocks_cnt;
+  size_t allocated_blocks_cnt;
+};
+
+// for lower_bound...
+bool operator<(const small_object_page_record& one, const small_object_page_record& two);
+
+struct small_object_block_record {
+  small_object_block_record* next;
+  size_t free_blocks_cnt;
+};
+
+// This is implementation for std::vector allocator
+template <typename T>
+class linker_vector_allocator {
+ public:
+  typedef T value_type;
+  typedef T* pointer;
+  typedef const T* const_pointer;
+  typedef T& reference;
+  typedef const T& const_reference;
+  typedef size_t size_type;
+  typedef ptrdiff_t difference_type;
+
+  T* allocate(size_t n, const T* hint = nullptr) {
+    size_t size = n * sizeof(T);
+    void* ptr = mmap(const_cast<T*>(hint), size,
+        PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
+    if (ptr == MAP_FAILED) {
+      // Spec says we need to throw std::bad_alloc here but because our
+      // code does not support exception handling anyways - we are going to abort.
+      __libc_fatal("mmap failed");
+    }
+
+    prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, size, "linker_alloc_vector");
+
+    return reinterpret_cast<T*>(ptr);
+  }
+
+  void deallocate(T* ptr, size_t n) {
+    munmap(ptr, n * sizeof(T));
+  }
+};
+
+typedef
+    std::vector<small_object_page_record, linker_vector_allocator<small_object_page_record>>
+    linker_vector_t;
+
+
+class LinkerSmallObjectAllocator {
+ public:
+  LinkerSmallObjectAllocator();
+  void init(uint32_t type, size_t block_size, const char* name);
+  void* alloc();
+  void free(void* ptr);
+
+  size_t get_block_size() const { return block_size_; }
+ private:
+  void alloc_page();
+  void free_page(linker_vector_t::iterator page_record);
+  linker_vector_t::iterator find_page_record(void* ptr);
+  void create_page_record(void* page_addr, size_t free_blocks_cnt);
+
+  uint32_t type_;
+  const char* name_;
+  size_t block_size_;
+
+  size_t free_pages_cnt_;
+  small_object_block_record* free_blocks_list_;
+
+  // sorted vector of page records
+  linker_vector_t page_records_;
+};
+
+class LinkerMemoryAllocator {
+ public:
+  LinkerMemoryAllocator();
+  void* alloc(size_t size);
+
+  // Note that this implementation of realloc never shrinks allocation
+  void* realloc(void* ptr, size_t size);
+  void free(void* ptr);
+ private:
+  void* alloc_mmap(size_t size);
+  page_info* get_page_info(void* ptr);
+  LinkerSmallObjectAllocator* get_small_object_allocator(uint32_t type);
+
+  LinkerSmallObjectAllocator allocators_[kSmallObjectAllocatorsCount];
+};
+
+
+#endif  /* __LINKER_ALLOCATOR_H */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker_block_allocator.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2014 The Android Open Source 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.
+ */
+
+#include "linker_block_allocator.h"
+#include <inttypes.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "private/bionic_prctl.h"
+
+#include "hybris_compat.h"
+
+struct LinkerBlockAllocatorPage {
+  LinkerBlockAllocatorPage* next;
+  uint8_t bytes[PAGE_SIZE-sizeof(LinkerBlockAllocatorPage*)];
+};
+
+struct FreeBlockInfo {
+  void* next_block;
+  size_t num_free_blocks;
+};
+
+LinkerBlockAllocator::LinkerBlockAllocator(size_t block_size)
+  : block_size_(block_size < sizeof(FreeBlockInfo) ? sizeof(FreeBlockInfo) : block_size),
+    page_list_(nullptr),
+    free_block_list_(nullptr)
+{}
+
+void* LinkerBlockAllocator::alloc() {
+  if (free_block_list_ == nullptr) {
+    create_new_page();
+  }
+
+  FreeBlockInfo* block_info = reinterpret_cast<FreeBlockInfo*>(free_block_list_);
+  if (block_info->num_free_blocks > 1) {
+    FreeBlockInfo* next_block_info = reinterpret_cast<FreeBlockInfo*>(
+      reinterpret_cast<char*>(free_block_list_) + block_size_);
+    next_block_info->next_block = block_info->next_block;
+    next_block_info->num_free_blocks = block_info->num_free_blocks - 1;
+    free_block_list_ = next_block_info;
+  } else {
+    free_block_list_ = block_info->next_block;
+  }
+
+  memset(block_info, 0, block_size_);
+
+  return block_info;
+}
+
+void LinkerBlockAllocator::free(void* block) {
+  if (block == nullptr) {
+    return;
+  }
+
+  LinkerBlockAllocatorPage* page = find_page(block);
+
+  if (page == nullptr) {
+    abort();
+  }
+
+  ssize_t offset = reinterpret_cast<uint8_t*>(block) - page->bytes;
+
+  if (offset % block_size_ != 0) {
+    abort();
+  }
+
+  memset(block, 0, block_size_);
+
+  FreeBlockInfo* block_info = reinterpret_cast<FreeBlockInfo*>(block);
+
+  block_info->next_block = free_block_list_;
+  block_info->num_free_blocks = 1;
+
+  free_block_list_ = block_info;
+}
+
+void LinkerBlockAllocator::protect_all(int prot) {
+  for (LinkerBlockAllocatorPage* page = page_list_; page != nullptr; page = page->next) {
+    if (mprotect(page, PAGE_SIZE, prot) == -1) {
+      abort();
+    }
+  }
+}
+
+void LinkerBlockAllocator::create_new_page() {
+  LinkerBlockAllocatorPage* page = reinterpret_cast<LinkerBlockAllocatorPage*>(
+      mmap(nullptr, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0));
+
+  if (page == MAP_FAILED) {
+    abort(); // oom
+  }
+
+  prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, page, PAGE_SIZE, "linker_alloc");
+
+  memset(page, 0, PAGE_SIZE);
+
+  FreeBlockInfo* first_block = reinterpret_cast<FreeBlockInfo*>(page->bytes);
+  first_block->next_block = free_block_list_;
+  first_block->num_free_blocks = (PAGE_SIZE - sizeof(LinkerBlockAllocatorPage*))/block_size_;
+
+  free_block_list_ = first_block;
+
+  page->next = page_list_;
+  page_list_ = page;
+}
+
+LinkerBlockAllocatorPage* LinkerBlockAllocator::find_page(void* block) {
+  if (block == nullptr) {
+    abort();
+  }
+
+  LinkerBlockAllocatorPage* page = page_list_;
+  while (page != nullptr) {
+    const uint8_t* page_ptr = reinterpret_cast<const uint8_t*>(page);
+    if (block >= (page_ptr + sizeof(page->next)) && block < (page_ptr + PAGE_SIZE)) {
+      return page;
+    }
+
+    page = page->next;
+  }
+
+  abort();
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker_block_allocator.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 The Android Open Source 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.
+ */
+
+#ifndef __LINKER_BLOCK_ALLOCATOR_H
+#define __LINKER_BLOCK_ALLOCATOR_H
+
+#include <stdlib.h>
+#include <limits.h>
+#include "private/bionic_macros.h"
+
+struct LinkerBlockAllocatorPage;
+
+/*
+ * This class is a non-template version of the LinkerTypeAllocator
+ * It keeps code inside .cpp file by keeping the interface
+ * template-free.
+ *
+ * Please use LinkerTypeAllocator<type> where possible (everywhere).
+ */
+class LinkerBlockAllocator {
+ public:
+  explicit LinkerBlockAllocator(size_t block_size);
+
+  void* alloc();
+  void free(void* block);
+  void protect_all(int prot);
+
+ private:
+  void create_new_page();
+  LinkerBlockAllocatorPage* find_page(void* block);
+
+  size_t block_size_;
+  LinkerBlockAllocatorPage* page_list_;
+  void* free_block_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(LinkerBlockAllocator);
+};
+
+/*
+ * A simple allocator for the dynamic linker. An allocator allocates instances
+ * of a single fixed-size type. Allocations are backed by page-sized private
+ * anonymous mmaps.
+ *
+ * The differences between this allocator and LinkerMemoryAllocator are:
+ * 1. This allocator manages space more efficiently. LinkerMemoryAllocator
+ *    operates in power-of-two sized blocks up to 1k, when this implementation
+ *    splits the page to aligned size of structure; For example for structures
+ *    with size 513 this allocator will use 516 (520 for lp64) bytes of data
+ *    where generalized implementation is going to use 1024 sized blocks.
+ *
+ * 2. This allocator does not munmap allocated memory, where LinkerMemoryAllocator does.
+ *
+ * 3. This allocator provides mprotect services to the user, where LinkerMemoryAllocator
+ *    always treats it's memory as READ|WRITE.
+ */
+template<typename T>
+class LinkerTypeAllocator {
+ public:
+  LinkerTypeAllocator() : block_allocator_(sizeof(T)) {}
+  T* alloc() { return reinterpret_cast<T*>(block_allocator_.alloc()); }
+  void free(T* t) { block_allocator_.free(t); }
+  void protect_all(int prot) { block_allocator_.protect_all(prot); }
+ private:
+  LinkerBlockAllocator block_allocator_;
+  DISALLOW_COPY_AND_ASSIGN(LinkerTypeAllocator);
+};
+
+#endif // __LINKER_BLOCK_ALLOCATOR_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker_debug.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINKER_DEBUG_H_
+#define _LINKER_DEBUG_H_
+
+// You can increase the verbosity of debug traces by defining the LD_DEBUG
+// environment variable to a numeric value from 0 to 2 (corresponding to
+// INFO, TRACE, and DEBUG calls in the source). This will only
+// affect new processes being launched.
+
+// By default, traces are sent to logcat, with the "linker" tag. You can
+// change this to go to stdout instead by setting the definition of
+// LINKER_DEBUG_TO_LOG to 0.
+#define LINKER_DEBUG_TO_LOG  0
+
+#define TRACE_DEBUG          1
+#define DO_TRACE_LOOKUP      1
+#define DO_TRACE_RELO        1
+#define DO_TRACE_IFUNC       1
+#define TIMING               0
+#define STATS                0
+#define COUNT_PAGES          0
+
+/*********************************************************************
+ * You shouldn't need to modify anything below unless you are adding
+ * more debugging information.
+ *
+ * To enable/disable specific debug options, change the defines above
+ *********************************************************************/
+
+#include "private/libc_logging.h"
+
+extern int g_ld_debug_verbosity;
+
+#define _PRINTVF(v, x...) \
+    do { \
+      if (g_ld_debug_verbosity > (v)) { fprintf(stderr, x); fprintf(stderr, "\n"); } \
+    } while (0)
+
+#define PRINT(x...)          _PRINTVF(-1, x)
+#define INFO(x...)           _PRINTVF(0, x)
+#define TRACE(x...)          _PRINTVF(1, x)
+
+#if TRACE_DEBUG
+#define DEBUG(x...)          _PRINTVF(2, "DEBUG: " x)
+#else /* !TRACE_DEBUG */
+#define DEBUG(x...)          do {} while (0)
+#endif /* TRACE_DEBUG */
+
+#define TRACE_TYPE(t, x...)   do { if (DO_TRACE_##t) { TRACE(x); } } while (0)
+
+#if COUNT_PAGES
+extern uint32_t bitmask[];
+#if defined(__LP64__)
+#define MARK(offset) \
+    do { \
+      if ((((offset) >> 12) >> 5) < 4096) \
+          bitmask[((offset) >> 12) >> 5] |= (1 << (((offset) >> 12) & 31)); \
+    } while (0)
+#else
+#define MARK(offset) \
+    do { \
+      bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \
+    } while (0)
+#endif
+#else
+#define MARK(x) do {} while (0)
+
+#endif
+
+#endif /* _LINKER_DEBUG_H_ */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker_libc_support.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 The Android Open Source 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.
+ */
+
+#include "../libc/arch-common/bionic/__dso_handle.h"
+
+int atexit(void (*function)(void) __attribute__((__unused__))) {
+  return -1;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker_memory.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.
+ */
+
+#include "linker_allocator.h"
+
+#include <stdlib.h>
+
+#if DISABLED_FOR_HYBRIS_SUPPORT
+static LinkerMemoryAllocator g_linker_allocator;
+
+void* malloc(size_t byte_count) {
+  return g_linker_allocator.alloc(byte_count);
+}
+
+void* calloc(size_t item_count, size_t item_size) {
+  return g_linker_allocator.alloc(item_count*item_size);
+}
+
+void* realloc(void* p, size_t byte_count) {
+  return g_linker_allocator.realloc(p, byte_count);
+}
+
+void free(void* ptr) {
+  g_linker_allocator.free(ptr);
+}
+#endif
+
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker_phdr.cpp
@@ -0,0 +1,827 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "linker_phdr.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "linker.h"
+#include "linker_debug.h"
+
+#include "hybris_compat.h"
+
+static int GetTargetElfMachine() {
+#if defined(__arm__)
+  return EM_ARM;
+#elif defined(__aarch64__)
+  return EM_AARCH64;
+#elif defined(__i386__)
+  return EM_386;
+#elif defined(__mips__)
+  return EM_MIPS;
+#elif defined(__x86_64__)
+  return EM_X86_64;
+#endif
+}
+
+/**
+  TECHNICAL NOTE ON ELF LOADING.
+
+  An ELF file's program header table contains one or more PT_LOAD
+  segments, which corresponds to portions of the file that need to
+  be mapped into the process' address space.
+
+  Each loadable segment has the following important properties:
+
+    p_offset  -> segment file offset
+    p_filesz  -> segment file size
+    p_memsz   -> segment memory size (always >= p_filesz)
+    p_vaddr   -> segment's virtual address
+    p_flags   -> segment flags (e.g. readable, writable, executable)
+
+  We will ignore the p_paddr and p_align fields of ElfW(Phdr) for now.
+
+  The loadable segments can be seen as a list of [p_vaddr ... p_vaddr+p_memsz)
+  ranges of virtual addresses. A few rules apply:
+
+  - the virtual address ranges should not overlap.
+
+  - if a segment's p_filesz is smaller than its p_memsz, the extra bytes
+    between them should always be initialized to 0.
+
+  - ranges do not necessarily start or end at page boundaries. Two distinct
+    segments can have their start and end on the same page. In this case, the
+    page inherits the mapping flags of the latter segment.
+
+  Finally, the real load addrs of each segment is not p_vaddr. Instead the
+  loader decides where to load the first segment, then will load all others
+  relative to the first one to respect the initial range layout.
+
+  For example, consider the following list:
+
+    [ offset:0,      filesz:0x4000, memsz:0x4000, vaddr:0x30000 ],
+    [ offset:0x4000, filesz:0x2000, memsz:0x8000, vaddr:0x40000 ],
+
+  This corresponds to two segments that cover these virtual address ranges:
+
+       0x30000...0x34000
+       0x40000...0x48000
+
+  If the loader decides to load the first segment at address 0xa0000000
+  then the segments' load address ranges will be:
+
+       0xa0030000...0xa0034000
+       0xa0040000...0xa0048000
+
+  In other words, all segments must be loaded at an address that has the same
+  constant offset from their p_vaddr value. This offset is computed as the
+  difference between the first segment's load address, and its p_vaddr value.
+
+  However, in practice, segments do _not_ start at page boundaries. Since we
+  can only memory-map at page boundaries, this means that the bias is
+  computed as:
+
+       load_bias = phdr0_load_address - PAGE_START(phdr0->p_vaddr)
+
+  (NOTE: The value must be used as a 32-bit unsigned integer, to deal with
+          possible wrap around UINT32_MAX for possible large p_vaddr values).
+
+  And that the phdr0_load_address must start at a page boundary, with
+  the segment's real content starting at:
+
+       phdr0_load_address + PAGE_OFFSET(phdr0->p_vaddr)
+
+  Note that ELF requires the following condition to make the mmap()-ing work:
+
+      PAGE_OFFSET(phdr0->p_vaddr) == PAGE_OFFSET(phdr0->p_offset)
+
+  The load_bias must be added to any p_vaddr value read from the ELF file to
+  determine the corresponding memory address.
+
+ **/
+
+#define MAYBE_MAP_FLAG(x, from, to)  (((x) & (from)) ? (to) : 0)
+#define PFLAGS_TO_PROT(x)            (MAYBE_MAP_FLAG((x), PF_X, PROT_EXEC) | \
+                                      MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
+                                      MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
+
+ElfReader::ElfReader(const char* name, int fd, off64_t file_offset, off64_t file_size)
+    : name_(name), fd_(fd), file_offset_(file_offset), file_size_(file_size),
+      phdr_num_(0), phdr_mmap_(nullptr), phdr_table_(nullptr), phdr_size_(0),
+      load_start_(nullptr), load_size_(0), load_bias_(0),
+      loaded_phdr_(nullptr) {
+}
+
+ElfReader::~ElfReader() {
+  if (phdr_mmap_ != nullptr) {
+    munmap(phdr_mmap_, phdr_size_);
+  }
+}
+
+bool ElfReader::Load(const android_dlextinfo* extinfo) {
+  return ReadElfHeader() &&
+         VerifyElfHeader() &&
+         ReadProgramHeader() &&
+         ReserveAddressSpace(extinfo) &&
+         LoadSegments() &&
+         FindPhdr();
+}
+
+bool ElfReader::ReadElfHeader() {
+  ssize_t rc = TEMP_FAILURE_RETRY(pread64(fd_, &header_, sizeof(header_), file_offset_));
+  if (rc < 0) {
+    DL_ERR("can't read file \"%s\": %s", name_, strerror(errno));
+    return false;
+  }
+
+  if (rc != sizeof(header_)) {
+    DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_,
+           static_cast<size_t>(rc));
+    return false;
+  }
+  return true;
+}
+
+bool ElfReader::VerifyElfHeader() {
+  if (memcmp(header_.e_ident, ELFMAG, SELFMAG) != 0) {
+    DL_ERR("\"%s\" has bad ELF magic", name_);
+    return false;
+  }
+
+  // Try to give a clear diagnostic for ELF class mismatches, since they're
+  // an easy mistake to make during the 32-bit/64-bit transition period.
+  int elf_class = header_.e_ident[EI_CLASS];
+#if defined(__LP64__)
+  if (elf_class != ELFCLASS64) {
+    if (elf_class == ELFCLASS32) {
+      DL_ERR("\"%s\" is 32-bit instead of 64-bit", name_);
+    } else {
+      DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
+    }
+    return false;
+  }
+#else
+  if (elf_class != ELFCLASS32) {
+    if (elf_class == ELFCLASS64) {
+      DL_ERR("\"%s\" is 64-bit instead of 32-bit", name_);
+    } else {
+      DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
+    }
+    return false;
+  }
+#endif
+
+  if (header_.e_ident[EI_DATA] != ELFDATA2LSB) {
+    DL_ERR("\"%s\" not little-endian: %d", name_, header_.e_ident[EI_DATA]);
+    return false;
+  }
+
+  if (header_.e_type != ET_DYN) {
+    DL_ERR("\"%s\" has unexpected e_type: %d", name_, header_.e_type);
+    return false;
+  }
+
+  if (header_.e_version != EV_CURRENT) {
+    DL_ERR("\"%s\" has unexpected e_version: %d", name_, header_.e_version);
+    return false;
+  }
+
+  if (header_.e_machine != GetTargetElfMachine()) {
+    DL_ERR("\"%s\" has unexpected e_machine: %d", name_, header_.e_machine);
+    return false;
+  }
+
+  return true;
+}
+
+// Loads the program header table from an ELF file into a read-only private
+// anonymous mmap-ed block.
+bool ElfReader::ReadProgramHeader() {
+  phdr_num_ = header_.e_phnum;
+
+  // Like the kernel, we only accept program header tables that
+  // are smaller than 64KiB.
+  if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(ElfW(Phdr))) {
+    DL_ERR("\"%s\" has invalid e_phnum: %zd", name_, phdr_num_);
+    return false;
+  }
+
+  ElfW(Addr) page_min = PAGE_START(header_.e_phoff);
+  ElfW(Addr) page_max = PAGE_END(header_.e_phoff + (phdr_num_ * sizeof(ElfW(Phdr))));
+  ElfW(Addr) page_offset = PAGE_OFFSET(header_.e_phoff);
+
+  phdr_size_ = page_max - page_min;
+
+  void* mmap_result =
+      mmap64(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, file_offset_ + page_min);
+  if (mmap_result == MAP_FAILED) {
+    DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
+    return false;
+  }
+
+  phdr_mmap_ = mmap_result;
+  phdr_table_ = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(mmap_result) + page_offset);
+  return true;
+}
+
+/* Returns the size of the extent of all the possibly non-contiguous
+ * loadable segments in an ELF program header table. This corresponds
+ * to the page-aligned size in bytes that needs to be reserved in the
+ * process' address space. If there are no loadable segments, 0 is
+ * returned.
+ *
+ * If out_min_vaddr or out_max_vaddr are not null, they will be
+ * set to the minimum and maximum addresses of pages to be reserved,
+ * or 0 if there is nothing to load.
+ */
+size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                ElfW(Addr)* out_min_vaddr,
+                                ElfW(Addr)* out_max_vaddr) {
+  ElfW(Addr) min_vaddr = UINTPTR_MAX;
+  ElfW(Addr) max_vaddr = 0;
+
+  bool found_pt_load = false;
+  for (size_t i = 0; i < phdr_count; ++i) {
+    const ElfW(Phdr)* phdr = &phdr_table[i];
+
+    if (phdr->p_type != PT_LOAD) {
+      continue;
+    }
+    found_pt_load = true;
+
+    if (phdr->p_vaddr < min_vaddr) {
+      min_vaddr = phdr->p_vaddr;
+    }
+
+    if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
+      max_vaddr = phdr->p_vaddr + phdr->p_memsz;
+    }
+  }
+  if (!found_pt_load) {
+    min_vaddr = 0;
+  }
+
+  min_vaddr = PAGE_START(min_vaddr);
+  max_vaddr = PAGE_END(max_vaddr);
+
+  if (out_min_vaddr != nullptr) {
+    *out_min_vaddr = min_vaddr;
+  }
+  if (out_max_vaddr != nullptr) {
+    *out_max_vaddr = max_vaddr;
+  }
+  return max_vaddr - min_vaddr;
+}
+
+// Reserve a virtual address range big enough to hold all loadable
+// segments of a program header table. This is done by creating a
+// private anonymous mmap() with PROT_NONE.
+bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
+  ElfW(Addr) min_vaddr;
+  load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
+  if (load_size_ == 0) {
+    DL_ERR("\"%s\" has no loadable segments", name_);
+    return false;
+  }
+
+  uint8_t* addr = reinterpret_cast<uint8_t*>(min_vaddr);
+  void* start;
+  size_t reserved_size = 0;
+  bool reserved_hint = true;
+  // Assume position independent executable by default.
+  uint8_t* mmap_hint = nullptr;
+
+  if (extinfo != nullptr) {
+    if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
+      reserved_size = extinfo->reserved_size;
+      reserved_hint = false;
+    } else if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS_HINT) {
+      reserved_size = extinfo->reserved_size;
+    }
+
+    if ((extinfo->flags & ANDROID_DLEXT_FORCE_FIXED_VADDR) != 0) {
+      mmap_hint = addr;
+    }
+  }
+
+  if (load_size_ > reserved_size) {
+    if (!reserved_hint) {
+      DL_ERR("reserved address space %zd smaller than %zd bytes needed for \"%s\"",
+             reserved_size - load_size_, load_size_, name_);
+      return false;
+    }
+    int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
+    start = mmap(mmap_hint, load_size_, PROT_NONE, mmap_flags, -1, 0);
+    if (start == MAP_FAILED) {
+      DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_);
+      return false;
+    }
+  } else {
+    start = extinfo->reserved_addr;
+  }
+
+  load_start_ = start;
+  load_bias_ = reinterpret_cast<uint8_t*>(start) - addr;
+  return true;
+}
+
+bool ElfReader::LoadSegments() {
+  for (size_t i = 0; i < phdr_num_; ++i) {
+    const ElfW(Phdr)* phdr = &phdr_table_[i];
+
+    if (phdr->p_type != PT_LOAD) {
+      continue;
+    }
+
+    // Segment addresses in memory.
+    ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
+    ElfW(Addr) seg_end   = seg_start + phdr->p_memsz;
+
+    ElfW(Addr) seg_page_start = PAGE_START(seg_start);
+    ElfW(Addr) seg_page_end   = PAGE_END(seg_end);
+
+    ElfW(Addr) seg_file_end   = seg_start + phdr->p_filesz;
+
+    // File offsets.
+    ElfW(Addr) file_start = phdr->p_offset;
+    ElfW(Addr) file_end   = file_start + phdr->p_filesz;
+
+    ElfW(Addr) file_page_start = PAGE_START(file_start);
+    ElfW(Addr) file_length = file_end - file_page_start;
+
+    if (file_size_ <= 0) {
+      DL_ERR("\"%s\" invalid file size: %" PRId64, name_, file_size_);
+      return false;
+    }
+
+    if (file_end >= static_cast<size_t>(file_size_)) {
+      DL_ERR("invalid ELF file \"%s\" load segment[%zd]:"
+          " p_offset (%p) + p_filesz (%p) ( = %p) past end of file (0x%" PRIx64 ")",
+          name_, i, reinterpret_cast<void*>(phdr->p_offset),
+          reinterpret_cast<void*>(phdr->p_filesz),
+          reinterpret_cast<void*>(file_end), file_size_);
+      return false;
+    }
+
+    if (file_length != 0) {
+      void* seg_addr = mmap64(reinterpret_cast<void*>(seg_page_start),
+                            file_length,
+                            PFLAGS_TO_PROT(phdr->p_flags),
+                            MAP_FIXED|MAP_PRIVATE,
+                            fd_,
+                            file_offset_ + file_page_start);
+      if (seg_addr == MAP_FAILED) {
+        DL_ERR("couldn't map \"%s\" segment %zd: %s", name_, i, strerror(errno));
+        return false;
+      }
+    }
+
+    // if the segment is writable, and does not end on a page boundary,
+    // zero-fill it until the page limit.
+    if ((phdr->p_flags & PF_W) != 0 && PAGE_OFFSET(seg_file_end) > 0) {
+      memset(reinterpret_cast<void*>(seg_file_end), 0, PAGE_SIZE - PAGE_OFFSET(seg_file_end));
+    }
+
+    seg_file_end = PAGE_END(seg_file_end);
+
+    // seg_file_end is now the first page address after the file
+    // content. If seg_end is larger, we need to zero anything
+    // between them. This is done by using a private anonymous
+    // map for all extra pages.
+    if (seg_page_end > seg_file_end) {
+      void* zeromap = mmap(reinterpret_cast<void*>(seg_file_end),
+                           seg_page_end - seg_file_end,
+                           PFLAGS_TO_PROT(phdr->p_flags),
+                           MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
+                           -1,
+                           0);
+      if (zeromap == MAP_FAILED) {
+        DL_ERR("couldn't zero fill \"%s\" gap: %s", name_, strerror(errno));
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+/* Used internally. Used to set the protection bits of all loaded segments
+ * with optional extra flags (i.e. really PROT_WRITE). Used by
+ * phdr_table_protect_segments and phdr_table_unprotect_segments.
+ */
+static int _phdr_table_set_load_prot(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                     ElfW(Addr) load_bias, int extra_prot_flags) {
+  const ElfW(Phdr)* phdr = phdr_table;
+  const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
+
+  for (; phdr < phdr_limit; phdr++) {
+    if (phdr->p_type != PT_LOAD || (phdr->p_flags & PF_W) != 0) {
+      continue;
+    }
+
+    ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
+    ElfW(Addr) seg_page_end   = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
+
+    int prot = PFLAGS_TO_PROT(phdr->p_flags);
+    if ((extra_prot_flags & PROT_WRITE) != 0) {
+      // make sure we're never simultaneously writable / executable
+      prot &= ~PROT_EXEC;
+    }
+
+    int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
+                       seg_page_end - seg_page_start,
+                       prot | extra_prot_flags);
+    if (ret < 0) {
+      return -1;
+    }
+  }
+  return 0;
+}
+
+/* Restore the original protection modes for all loadable segments.
+ * You should only call this after phdr_table_unprotect_segments and
+ * applying all relocations.
+ *
+ * Input:
+ *   phdr_table  -> program header table
+ *   phdr_count  -> number of entries in tables
+ *   load_bias   -> load bias
+ * Return:
+ *   0 on error, -1 on failure (error code in errno).
+ */
+int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table,
+                                size_t phdr_count, ElfW(Addr) load_bias) {
+  return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, 0);
+}
+
+/* Change the protection of all loaded segments in memory to writable.
+ * This is useful before performing relocations. Once completed, you
+ * will have to call phdr_table_protect_segments to restore the original
+ * protection flags on all segments.
+ *
+ * Note that some writable segments can also have their content turned
+ * to read-only by calling phdr_table_protect_gnu_relro. This is no
+ * performed here.
+ *
+ * Input:
+ *   phdr_table  -> program header table
+ *   phdr_count  -> number of entries in tables
+ *   load_bias   -> load bias
+ * Return:
+ *   0 on error, -1 on failure (error code in errno).
+ */
+int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table,
+                                  size_t phdr_count, ElfW(Addr) load_bias) {
+  return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, PROT_WRITE);
+}
+
+/* Used internally by phdr_table_protect_gnu_relro and
+ * phdr_table_unprotect_gnu_relro.
+ */
+static int _phdr_table_set_gnu_relro_prot(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                          ElfW(Addr) load_bias, int prot_flags) {
+  const ElfW(Phdr)* phdr = phdr_table;
+  const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
+
+  for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
+    if (phdr->p_type != PT_GNU_RELRO) {
+      continue;
+    }
+
+    // Tricky: what happens when the relro segment does not start
+    // or end at page boundaries? We're going to be over-protective
+    // here and put every page touched by the segment as read-only.
+
+    // This seems to match Ian Lance Taylor's description of the
+    // feature at http://www.airs.com/blog/archives/189.
+
+    //    Extract:
+    //       Note that the current dynamic linker code will only work
+    //       correctly if the PT_GNU_RELRO segment starts on a page
+    //       boundary. This is because the dynamic linker rounds the
+    //       p_vaddr field down to the previous page boundary. If
+    //       there is anything on the page which should not be read-only,
+    //       the program is likely to fail at runtime. So in effect the
+    //       linker must only emit a PT_GNU_RELRO segment if it ensures
+    //       that it starts on a page boundary.
+    ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
+    ElfW(Addr) seg_page_end   = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
+
+    int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
+                       seg_page_end - seg_page_start,
+                       prot_flags);
+    if (ret < 0) {
+      return -1;
+    }
+  }
+  return 0;
+}
+
+/* Apply GNU relro protection if specified by the program header. This will
+ * turn some of the pages of a writable PT_LOAD segment to read-only, as
+ * specified by one or more PT_GNU_RELRO segments. This must be always
+ * performed after relocations.
+ *
+ * The areas typically covered are .got and .data.rel.ro, these are
+ * read-only from the program's POV, but contain absolute addresses
+ * that need to be relocated before use.
+ *
+ * Input:
+ *   phdr_table  -> program header table
+ *   phdr_count  -> number of entries in tables
+ *   load_bias   -> load bias
+ * Return:
+ *   0 on error, -1 on failure (error code in errno).
+ */
+int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table,
+                                 size_t phdr_count, ElfW(Addr) load_bias) {
+  return _phdr_table_set_gnu_relro_prot(phdr_table, phdr_count, load_bias, PROT_READ);
+}
+
+/* Serialize the GNU relro segments to the given file descriptor. This can be
+ * performed after relocations to allow another process to later share the
+ * relocated segment, if it was loaded at the same address.
+ *
+ * Input:
+ *   phdr_table  -> program header table
+ *   phdr_count  -> number of entries in tables
+ *   load_bias   -> load bias
+ *   fd          -> writable file descriptor to use
+ * Return:
+ *   0 on error, -1 on failure (error code in errno).
+ */
+int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table,
+                                   size_t phdr_count,
+                                   ElfW(Addr) load_bias,
+                                   int fd) {
+  const ElfW(Phdr)* phdr = phdr_table;
+  const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
+  ssize_t file_offset = 0;
+
+  for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
+    if (phdr->p_type != PT_GNU_RELRO) {
+      continue;
+    }
+
+    ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
+    ElfW(Addr) seg_page_end   = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
+    ssize_t size = seg_page_end - seg_page_start;
+
+    ssize_t written = TEMP_FAILURE_RETRY(write(fd, reinterpret_cast<void*>(seg_page_start), size));
+    if (written != size) {
+      return -1;
+    }
+    void* map = mmap(reinterpret_cast<void*>(seg_page_start), size, PROT_READ,
+                     MAP_PRIVATE|MAP_FIXED, fd, file_offset);
+    if (map == MAP_FAILED) {
+      return -1;
+    }
+    file_offset += size;
+  }
+  return 0;
+}
+
+/* Where possible, replace the GNU relro segments with mappings of the given
+ * file descriptor. This can be performed after relocations to allow a file
+ * previously created by phdr_table_serialize_gnu_relro in another process to
+ * replace the dirty relocated pages, saving memory, if it was loaded at the
+ * same address. We have to compare the data before we map over it, since some
+ * parts of the relro segment may not be identical due to other libraries in
+ * the process being loaded at different addresses.
+ *
+ * Input:
+ *   phdr_table  -> program header table
+ *   phdr_count  -> number of entries in tables
+ *   load_bias   -> load bias
+ *   fd          -> readable file descriptor to use
+ * Return:
+ *   0 on error, -1 on failure (error code in errno).
+ */
+int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table,
+                             size_t phdr_count,
+                             ElfW(Addr) load_bias,
+                             int fd) {
+  // Map the file at a temporary location so we can compare its contents.
+  struct stat file_stat;
+  if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
+    return -1;
+  }
+  off_t file_size = file_stat.st_size;
+  void* temp_mapping = nullptr;
+  if (file_size > 0) {
+    temp_mapping = mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (temp_mapping == MAP_FAILED) {
+      return -1;
+    }
+  }
+  size_t file_offset = 0;
+
+  // Iterate over the relro segments and compare/remap the pages.
+  const ElfW(Phdr)* phdr = phdr_table;
+  const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
+
+  for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
+    if (phdr->p_type != PT_GNU_RELRO) {
+      continue;
+    }
+
+    ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
+    ElfW(Addr) seg_page_end   = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
+
+    char* file_base = static_cast<char*>(temp_mapping) + file_offset;
+    char* mem_base = reinterpret_cast<char*>(seg_page_start);
+    size_t match_offset = 0;
+    size_t size = seg_page_end - seg_page_start;
+
+    if (file_size - file_offset < size) {
+      // File is too short to compare to this segment. The contents are likely
+      // different as well (it's probably for a different library version) so
+      // just don't bother checking.
+      break;
+    }
+
+    while (match_offset < size) {
+      // Skip over dissimilar pages.
+      while (match_offset < size &&
+             memcmp(mem_base + match_offset, file_base + match_offset, PAGE_SIZE) != 0) {
+        match_offset += PAGE_SIZE;
+      }
+
+      // Count similar pages.
+      size_t mismatch_offset = match_offset;
+      while (mismatch_offset < size &&
+             memcmp(mem_base + mismatch_offset, file_base + mismatch_offset, PAGE_SIZE) == 0) {
+        mismatch_offset += PAGE_SIZE;
+      }
+
+      // Map over similar pages.
+      if (mismatch_offset > match_offset) {
+        void* map = mmap(mem_base + match_offset, mismatch_offset - match_offset,
+                         PROT_READ, MAP_PRIVATE|MAP_FIXED, fd, match_offset);
+        if (map == MAP_FAILED) {
+          munmap(temp_mapping, file_size);
+          return -1;
+        }
+      }
+
+      match_offset = mismatch_offset;
+    }
+
+    // Add to the base file offset in case there are multiple relro segments.
+    file_offset += size;
+  }
+  munmap(temp_mapping, file_size);
+  return 0;
+}
+
+
+#if defined(__arm__)
+
+#  ifndef PT_ARM_EXIDX
+#    define PT_ARM_EXIDX    0x70000001      /* .ARM.exidx segment */
+#  endif
+
+/* Return the address and size of the .ARM.exidx section in memory,
+ * if present.
+ *
+ * Input:
+ *   phdr_table  -> program header table
+ *   phdr_count  -> number of entries in tables
+ *   load_bias   -> load bias
+ * Output:
+ *   arm_exidx       -> address of table in memory (null on failure).
+ *   arm_exidx_count -> number of items in table (0 on failure).
+ * Return:
+ *   0 on error, -1 on failure (_no_ error code in errno)
+ */
+int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                             ElfW(Addr) load_bias,
+                             ElfW(Addr)** arm_exidx, size_t* arm_exidx_count) {
+  const ElfW(Phdr)* phdr = phdr_table;
+  const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
+
+  for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
+    if (phdr->p_type != PT_ARM_EXIDX) {
+      continue;
+    }
+
+    *arm_exidx = reinterpret_cast<ElfW(Addr)*>(load_bias + phdr->p_vaddr);
+    *arm_exidx_count = phdr->p_memsz / 8;
+    return 0;
+  }
+  *arm_exidx = nullptr;
+  *arm_exidx_count = 0;
+  return -1;
+}
+#endif
+
+/* Return the address and size of the ELF file's .dynamic section in memory,
+ * or null if missing.
+ *
+ * Input:
+ *   phdr_table  -> program header table
+ *   phdr_count  -> number of entries in tables
+ *   load_bias   -> load bias
+ * Output:
+ *   dynamic       -> address of table in memory (null on failure).
+ *   dynamic_flags -> protection flags for section (unset on failure)
+ * Return:
+ *   void
+ */
+void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                    ElfW(Addr) load_bias, ElfW(Dyn)** dynamic,
+                                    ElfW(Word)* dynamic_flags) {
+  *dynamic = nullptr;
+  for (size_t i = 0; i<phdr_count; ++i) {
+    const ElfW(Phdr)& phdr = phdr_table[i];
+    if (phdr.p_type == PT_DYNAMIC) {
+      *dynamic = reinterpret_cast<ElfW(Dyn)*>(load_bias + phdr.p_vaddr);
+      if (dynamic_flags) {
+        *dynamic_flags = phdr.p_flags;
+      }
+      return;
+    }
+  }
+}
+
+// Sets loaded_phdr_ to the address of the program header table as it appears
+// in the loaded segments in memory. This is in contrast with phdr_table_,
+// which is temporary and will be released before the library is relocated.
+bool ElfReader::FindPhdr() {
+  const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
+
+  // If there is a PT_PHDR, use it directly.
+  for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
+    if (phdr->p_type == PT_PHDR) {
+      return CheckPhdr(load_bias_ + phdr->p_vaddr);
+    }
+  }
+
+  // Otherwise, check the first loadable segment. If its file offset
+  // is 0, it starts with the ELF header, and we can trivially find the
+  // loaded program header from it.
+  for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
+    if (phdr->p_type == PT_LOAD) {
+      if (phdr->p_offset == 0) {
+        ElfW(Addr)  elf_addr = load_bias_ + phdr->p_vaddr;
+        const ElfW(Ehdr)* ehdr = reinterpret_cast<const ElfW(Ehdr)*>(elf_addr);
+        ElfW(Addr)  offset = ehdr->e_phoff;
+        return CheckPhdr(reinterpret_cast<ElfW(Addr)>(ehdr) + offset);
+      }
+      break;
+    }
+  }
+
+  DL_ERR("can't find loaded phdr for \"%s\"", name_);
+  return false;
+}
+
+// Ensures that our program header is actually within a loadable
+// segment. This should help catch badly-formed ELF files that
+// would cause the linker to crash later when trying to access it.
+bool ElfReader::CheckPhdr(ElfW(Addr) loaded) {
+  const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
+  ElfW(Addr) loaded_end = loaded + (phdr_num_ * sizeof(ElfW(Phdr)));
+  for (ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
+    if (phdr->p_type != PT_LOAD) {
+      continue;
+    }
+    ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
+    ElfW(Addr) seg_end = phdr->p_filesz + seg_start;
+    if (seg_start <= loaded && loaded_end <= seg_end) {
+      loaded_phdr_ = reinterpret_cast<const ElfW(Phdr)*>(loaded);
+      return true;
+    }
+  }
+  DL_ERR("\"%s\" loaded phdr %p not in loadable segment", name_, reinterpret_cast<void*>(loaded));
+  return false;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker_phdr.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef LINKER_PHDR_H
+#define LINKER_PHDR_H
+
+/* Declarations related to the ELF program header table and segments.
+ *
+ * The design goal is to provide an API that is as close as possible
+ * to the ELF spec, and does not depend on linker-specific data
+ * structures (e.g. the exact layout of struct soinfo).
+ */
+
+#include "linker.h"
+
+class ElfReader {
+ public:
+  ElfReader(const char* name, int fd, off64_t file_offset, off64_t file_size);
+  ~ElfReader();
+
+  bool Load(const android_dlextinfo* extinfo);
+
+  size_t phdr_count() { return phdr_num_; }
+  ElfW(Addr) load_start() { return reinterpret_cast<ElfW(Addr)>(load_start_); }
+  size_t load_size() { return load_size_; }
+  ElfW(Addr) load_bias() { return load_bias_; }
+  const ElfW(Phdr)* loaded_phdr() { return loaded_phdr_; }
+
+ private:
+  bool ReadElfHeader();
+  bool VerifyElfHeader();
+  bool ReadProgramHeader();
+  bool ReserveAddressSpace(const android_dlextinfo* extinfo);
+  bool LoadSegments();
+  bool FindPhdr();
+  bool CheckPhdr(ElfW(Addr));
+
+  const char* name_;
+  int fd_;
+  off64_t file_offset_;
+  off64_t file_size_;
+
+  ElfW(Ehdr) header_;
+  size_t phdr_num_;
+
+  void* phdr_mmap_;
+  ElfW(Phdr)* phdr_table_;
+  ElfW(Addr) phdr_size_;
+
+  // First page of reserved address space.
+  void* load_start_;
+  // Size in bytes of reserved address space.
+  size_t load_size_;
+  // Load bias.
+  ElfW(Addr) load_bias_;
+
+  // Loaded phdr.
+  const ElfW(Phdr)* loaded_phdr_;
+};
+
+size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                ElfW(Addr)* min_vaddr = nullptr, ElfW(Addr)* max_vaddr = nullptr);
+
+int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table,
+                                size_t phdr_count, ElfW(Addr) load_bias);
+
+int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                  ElfW(Addr) load_bias);
+
+int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                 ElfW(Addr) load_bias);
+
+int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                   ElfW(Addr) load_bias, int fd);
+
+int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                             ElfW(Addr) load_bias, int fd);
+
+#if defined(__arm__)
+int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias,
+                             ElfW(Addr)** arm_exidx, size_t* arm_exidix_count);
+#endif
+
+void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                    ElfW(Addr) load_bias, ElfW(Dyn)** dynamic,
+                                    ElfW(Word)* dynamic_flags);
+
+#endif /* LINKER_PHDR_H */
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker_reloc_iterators.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.
+ */
+
+#ifndef __LINKER_RELOC_ITERATORS_H
+#define __LINKER_RELOC_ITERATORS_H
+
+#include "linker.h"
+
+#include <string.h>
+
+const size_t RELOCATION_GROUPED_BY_INFO_FLAG = 1;
+const size_t RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2;
+const size_t RELOCATION_GROUPED_BY_ADDEND_FLAG = 4;
+const size_t RELOCATION_GROUP_HAS_ADDEND_FLAG = 8;
+
+class plain_reloc_iterator {
+#if defined(USE_RELA)
+  typedef ElfW(Rela) rel_t;
+#else
+  typedef ElfW(Rel) rel_t;
+#endif
+ public:
+  plain_reloc_iterator(rel_t* rel_array, size_t count)
+      : begin_(rel_array), end_(begin_ + count), current_(begin_) {}
+
+  bool has_next() {
+    return current_ < end_;
+  }
+
+  rel_t* next() {
+    return current_++;
+  }
+ private:
+  rel_t* const begin_;
+  rel_t* const end_;
+  rel_t* current_;
+
+  DISALLOW_COPY_AND_ASSIGN(plain_reloc_iterator);
+};
+
+template <typename decoder_t>
+class packed_reloc_iterator {
+#if defined(USE_RELA)
+  typedef ElfW(Rela) rel_t;
+#else
+  typedef ElfW(Rel) rel_t;
+#endif
+ public:
+  explicit packed_reloc_iterator(decoder_t&& decoder)
+      : decoder_(decoder) {
+    // initialize fields
+    memset(&reloc_, 0, sizeof(reloc_));
+    relocation_count_ = decoder_.pop_front();
+    reloc_.r_offset = decoder_.pop_front();
+    relocation_index_ = 0;
+    relocation_group_index_ = 0;
+    group_size_ = 0;
+  }
+
+  bool has_next() const {
+    return relocation_index_ < relocation_count_;
+  }
+
+  rel_t* next() {
+    if (relocation_group_index_ == group_size_) {
+      if (!read_group_fields()) {
+        // Iterator is inconsistent state; it should not be called again
+        // but in case it is let's make sure has_next() returns false.
+        relocation_index_ = relocation_count_ = 0;
+        return nullptr;
+      }
+    }
+
+    if (is_relocation_grouped_by_offset_delta()) {
+      reloc_.r_offset += group_r_offset_delta_;
+    } else {
+      reloc_.r_offset += decoder_.pop_front();
+    }
+
+    if (!is_relocation_grouped_by_info()) {
+      reloc_.r_info = decoder_.pop_front();
+    }
+
+#if defined(USE_RELA)
+    if (is_relocation_group_has_addend() &&
+        !is_relocation_grouped_by_addend()) {
+      reloc_.r_addend += decoder_.pop_front();
+    }
+#endif
+
+    relocation_index_++;
+    relocation_group_index_++;
+
+    return &reloc_;
+  }
+ private:
+  bool read_group_fields() {
+    group_size_ = decoder_.pop_front();
+    group_flags_ = decoder_.pop_front();
+
+    if (is_relocation_grouped_by_offset_delta()) {
+      group_r_offset_delta_ = decoder_.pop_front();
+    }
+
+    if (is_relocation_grouped_by_info()) {
+      reloc_.r_info = decoder_.pop_front();
+    }
+
+    if (is_relocation_group_has_addend() &&
+        is_relocation_grouped_by_addend()) {
+#if !defined(USE_RELA)
+      // This platform does not support rela, and yet we have it encoded in android_rel section.
+      DL_ERR("unexpected r_addend in android.rel section");
+      return false;
+#else
+      reloc_.r_addend += decoder_.pop_front();
+    } else if (!is_relocation_group_has_addend()) {
+      reloc_.r_addend = 0;
+#endif
+    }
+
+    relocation_group_index_ = 0;
+    return true;
+  }
+
+  bool is_relocation_grouped_by_info() {
+    return (group_flags_ & RELOCATION_GROUPED_BY_INFO_FLAG) != 0;
+  }
+
+  bool is_relocation_grouped_by_offset_delta() {
+    return (group_flags_ & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) != 0;
+  }
+
+  bool is_relocation_grouped_by_addend() {
+    return (group_flags_ & RELOCATION_GROUPED_BY_ADDEND_FLAG) != 0;
+  }
+
+  bool is_relocation_group_has_addend() {
+    return (group_flags_ & RELOCATION_GROUP_HAS_ADDEND_FLAG) != 0;
+  }
+
+  decoder_t decoder_;
+  size_t relocation_count_;
+  size_t group_size_;
+  size_t group_flags_;
+  size_t group_r_offset_delta_;
+  size_t relocation_index_;
+  size_t relocation_group_index_;
+  rel_t reloc_;
+};
+
+#endif  // __LINKER_RELOC_ITERATORS_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker_relocs.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.
+ */
+
+#ifndef __LINKER_RELOCS_H
+#define __LINKER_RELOCS_H
+
+#include <elf.h>
+
+#define R_GENERIC_NONE 0 // R_*_NONE is always 0
+
+#if defined (__aarch64__)
+
+#define R_GENERIC_JUMP_SLOT R_AARCH64_JUMP_SLOT
+#define R_GENERIC_GLOB_DAT  R_AARCH64_GLOB_DAT
+#define R_GENERIC_RELATIVE  R_AARCH64_RELATIVE
+#define R_GENERIC_IRELATIVE R_AARCH64_IRELATIVE
+
+#elif defined (__arm__)
+
+#define R_GENERIC_JUMP_SLOT R_ARM_JUMP_SLOT
+#define R_GENERIC_GLOB_DAT  R_ARM_GLOB_DAT
+#define R_GENERIC_RELATIVE  R_ARM_RELATIVE
+#define R_GENERIC_IRELATIVE R_ARM_IRELATIVE
+
+#elif defined (__i386__)
+
+#define R_GENERIC_JUMP_SLOT R_386_JMP_SLOT
+#define R_GENERIC_GLOB_DAT  R_386_GLOB_DAT
+#define R_GENERIC_RELATIVE  R_386_RELATIVE
+#define R_GENERIC_IRELATIVE R_386_IRELATIVE
+
+#elif defined (__x86_64__)
+
+#define R_GENERIC_JUMP_SLOT R_X86_64_JUMP_SLOT
+#define R_GENERIC_GLOB_DAT  R_X86_64_GLOB_DAT
+#define R_GENERIC_RELATIVE  R_X86_64_RELATIVE
+#define R_GENERIC_IRELATIVE R_X86_64_IRELATIVE
+
+#endif
+
+#endif // __LINKER_RELOCS_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker_sdk_versions.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.
+ */
+
+#include "linker.h"
+#include <android/api-level.h>
+#include <atomic>
+
+static std::atomic<uint32_t> g_target_sdk_version(__ANDROID_API__);
+
+void set_application_target_sdk_version(uint32_t target) {
+  // translate current sdk_version to platform sdk_version
+  if (target == 0) {
+    target = __ANDROID_API__;
+  }
+  g_target_sdk_version = target;
+}
+
+uint32_t get_application_target_sdk_version() {
+  return g_target_sdk_version;
+}
+
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/linker_sleb128.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.
+ */
+
+#ifndef _LINKER_SLEB128_H
+#define _LINKER_SLEB128_H
+
+#include <stdint.h>
+
+// Helper classes for decoding LEB128, used in packed relocation data.
+// http://en.wikipedia.org/wiki/LEB128
+
+class sleb128_decoder {
+ public:
+  sleb128_decoder(const uint8_t* buffer, size_t count)
+      : current_(buffer), end_(buffer+count) { }
+
+  size_t pop_front() {
+    size_t value = 0;
+    static const size_t size = CHAR_BIT * sizeof(value);
+
+    size_t shift = 0;
+    uint8_t byte;
+
+    do {
+      if (current_ >= end_) {
+        __libc_fatal("sleb128_decoder ran out of bounds");
+      }
+      byte = *current_++;
+      value |= (static_cast<size_t>(byte & 127) << shift);
+      shift += 7;
+    } while (byte & 128);
+
+    if (shift < size && (byte & 64)) {
+      value |= -(static_cast<size_t>(1) << shift);
+    }
+
+    return value;
+  }
+
+ private:
+  const uint8_t* current_;
+  const uint8_t* const end_;
+};
+
+#endif // __LINKER_SLEB128_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/mm/rt.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This function is an empty stub where GDB locates a breakpoint to get notified
+ * about linker activity.  It canʼt be inlined away, can't be hidden.
+ */
+extern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity() {
+}
+
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/strlcat.c
@@ -0,0 +1,59 @@
+/*	$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $	*/
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+	register char *d = dst;
+	register const char *s = src;
+	register size_t n = siz;
+	size_t dlen;
+
+	/* Find the end of dst and adjust bytes left but don't go past end */
+	while (n-- != 0 && *d != '\0')
+		d++;
+	dlen = d - dst;
+	n = siz - dlen;
+
+	if (n == 0)
+		return(dlen + strlen(s));
+	while (*s != '\0') {
+		if (n != 1) {
+			*d++ = *s;
+			n--;
+		}
+		s++;
+	}
+	*d = '\0';
+
+	return(dlen + (s - src));	/* count does not include NUL */
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/stub/Makefile.am
@@ -0,0 +1,4 @@
+noinst_LTLIBRARIES = \
+	libstub-linker.la
+libstub_linker_la_SOURCES = \
+	linker.c
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/stub/linker.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+void *android_dlopen(const char *filename, int flag)
+{
+    fprintf(stderr, "%s called but not implemented!\n", __func__);
+    return NULL;
+}
+
+void *android_dlsym(void *name, const char *symbol)
+{
+    fprintf(stderr, "%s called but not implemented!\n", __func__);
+    return NULL;
+}
+
+int android_dlclose(void *handle)
+{
+    fprintf(stderr, "%s called but not implemented!\n", __func__);
+    return -1;
+}
+
+const char *android_dlerror(void)
+{
+    fprintf(stderr, "%s called but not implemented!\n", __func__);
+    return NULL;
+}
+
+int android_dladdr(const void *addr, void *info)
+{
+    fprintf(stderr, "%s called but not implemented!\n", __func__);
+    return -1;
+}
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/sysconf.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/sysconf.c
@@ -1,8 +1,27 @@
+/*
+ * Copyright (c) 2013 Adrian Negreanu <adrian.m.negreanu@intel.com>
+ *
+ * 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.
+ *
+ */
+
 #include <unistd.h>
 
 /*
- * bionic/libc/include/sys/sysconf.h processed with s/define _\(\w*\)\(.*\)/define \1\2\r#ifdef _\1\rMAP_TO_UNISTD(\1),\r#endif/g
+ * bionic/libc/include/sys/sysconf.h processed with:
+ * s/define _\(\w*\)\(.*\)/define \1\2\r#ifdef _\1\rMAP_TO_UNISTD(\1),\r#endif/g
  */
+
 #define MAP_TO_UNISTD(a) [a]=_##a
 static int sysconf_map[]= {
 #define SC_ARG_MAX             0x0000
@@ -321,7 +340,6 @@ MAP_TO_UNISTD(SC_THREAD_THREADS_MAX),
 #ifdef _SC_TTY_NAME_MAX
 MAP_TO_UNISTD(SC_TTY_NAME_MAX),
 #endif
-
 #define SC_THREADS                     0x004f
 #ifdef _SC_THREADS
 MAP_TO_UNISTD(SC_THREADS),
@@ -350,7 +368,6 @@ MAP_TO_UNISTD(SC_THREAD_PRIO_PROTECT),
 #ifdef _SC_THREAD_SAFE_FUNCTIONS
 MAP_TO_UNISTD(SC_THREAD_SAFE_FUNCTIONS),
 #endif
-
 #define SC_NPROCESSORS_CONF            0x0060
 #ifdef _SC_NPROCESSORS_CONF
 MAP_TO_UNISTD(SC_NPROCESSORS_CONF),
@@ -367,10 +384,242 @@ MAP_TO_UNISTD(SC_PHYS_PAGES),
 #ifdef _SC_AVPHYS_PAGES
 MAP_TO_UNISTD(SC_AVPHYS_PAGES),
 #endif
+#define SC_MONOTONIC_CLOCK             0x0064
+#ifdef _SC_MONOTONIC_CLOCK
+MAP_TO_UNISTD(SC_MONOTONIC_CLOCK),
+#endif
+#define SC_2_PBS               0x0065
+#ifdef _SC_2_PBS
+MAP_TO_UNISTD(SC_2_PBS),
+#endif
+#define SC_2_PBS_ACCOUNTING    0x0066
+#ifdef _SC_2_PBS_ACCOUNTING
+MAP_TO_UNISTD(SC_2_PBS_ACCOUNTING),
+#endif
+#define SC_2_PBS_CHECKPOINT    0x0067
+#ifdef _SC_2_PBS_CHECKPOINT
+MAP_TO_UNISTD(SC_2_PBS_CHECKPOINT),
+#endif
+#define SC_2_PBS_LOCATE        0x0068
+#ifdef _SC_2_PBS_LOCATE
+MAP_TO_UNISTD(SC_2_PBS_LOCATE),
+#endif
+#define SC_2_PBS_MESSAGE       0x0069
+#ifdef _SC_2_PBS_MESSAGE
+MAP_TO_UNISTD(SC_2_PBS_MESSAGE),
+#endif
+#define SC_2_PBS_TRACK         0x006a
+#ifdef _SC_2_PBS_TRACK
+MAP_TO_UNISTD(SC_2_PBS_TRACK),
+#endif
+#define SC_ADVISORY_INFO       0x006b
+#ifdef _SC_ADVISORY_INFO
+MAP_TO_UNISTD(SC_ADVISORY_INFO),
+#endif
+#define SC_BARRIERS            0x006c
+#ifdef _SC_BARRIERS
+MAP_TO_UNISTD(SC_BARRIERS),
+#endif
+#define SC_CLOCK_SELECTION     0x006d
+#ifdef _SC_CLOCK_SELECTION
+MAP_TO_UNISTD(SC_CLOCK_SELECTION),
+#endif
+#define SC_CPUTIME             0x006e
+#ifdef _SC_CPUTIME
+MAP_TO_UNISTD(SC_CPUTIME),
+#endif
+#define SC_HOST_NAME_MAX       0x006f
+#ifdef _SC_HOST_NAME_MAX
+MAP_TO_UNISTD(SC_HOST_NAME_MAX),
+#endif
+#define SC_IPV6                0x0070
+#ifdef _SC_IPV6
+MAP_TO_UNISTD(SC_IPV6),
+#endif
+#define SC_RAW_SOCKETS         0x0071
+#ifdef _SC_RAW_SOCKETS
+MAP_TO_UNISTD(SC_RAW_SOCKETS),
+#endif
+#define SC_READER_WRITER_LOCKS 0x0072
+#ifdef _SC_READER_WRITER_LOCKS
+MAP_TO_UNISTD(SC_READER_WRITER_LOCKS),
+#endif
+#define SC_REGEXP              0x0073
+#ifdef _SC_REGEXP
+MAP_TO_UNISTD(SC_REGEXP),
+#endif
+#define SC_SHELL               0x0074
+#ifdef _SC_SHELL
+MAP_TO_UNISTD(SC_SHELL),
+#endif
+#define SC_SPAWN               0x0075
+#ifdef _SC_SPAWN
+MAP_TO_UNISTD(SC_SPAWN),
+#endif
+#define SC_SPIN_LOCKS          0x0076
+#ifdef _SC_SPIN_LOCKS
+MAP_TO_UNISTD(SC_SPIN_LOCKS),
+#endif
+#define SC_SPORADIC_SERVER     0x0077
+#ifdef _SC_SPORADIC_SERVER
+MAP_TO_UNISTD(SC_SPORADIC_SERVER),
+#endif
+#define SC_SS_REPL_MAX         0x0078
+#ifdef _SC_SS_REPL_MAX
+MAP_TO_UNISTD(SC_SS_REPL_MAX),
+#endif
+#define SC_SYMLOOP_MAX         0x0079
+#ifdef _SC_SYMLOOP_MAX
+MAP_TO_UNISTD(SC_SYMLOOP_MAX),
+#endif
+#define SC_THREAD_CPUTIME      0x007a
+#ifdef _SC_THREAD_CPUTIME
+MAP_TO_UNISTD(SC_THREAD_CPUTIME),
+#endif
+#define SC_THREAD_PROCESS_SHARED       0x007b
+#ifdef _SC_THREAD_PROCESS_SHARED
+MAP_TO_UNISTD(SC_THREAD_PROCESS_SHARED),
+#endif
+#define SC_THREAD_ROBUST_PRIO_INHERIT  0x007c
+#ifdef _SC_THREAD_ROBUST_PRIO_INHERIT
+MAP_TO_UNISTD(SC_THREAD_ROBUST_PRIO_INHERIT),
+#endif
+#define SC_THREAD_ROBUST_PRIO_PROTECT  0x007d
+#ifdef _SC_THREAD_ROBUST_PRIO_PROTECT
+MAP_TO_UNISTD(SC_THREAD_ROBUST_PRIO_PROTECT),
+#endif
+#define SC_THREAD_SPORADIC_SERVER      0x007e
+#ifdef _SC_THREAD_SPORADIC_SERVER
+MAP_TO_UNISTD(SC_THREAD_SPORADIC_SERVER),
+#endif
+#define SC_TIMEOUTS            0x007f
+#ifdef _SC_TIMEOUTS
+MAP_TO_UNISTD(SC_TIMEOUTS),
+#endif
+#define SC_TRACE               0x0080
+#ifdef _SC_TRACE
+MAP_TO_UNISTD(SC_TRACE),
+#endif
+#define SC_TRACE_EVENT_FILTER  0x0081
+#ifdef _SC_TRACE_EVENT_FILTER
+MAP_TO_UNISTD(SC_TRACE_EVENT_FILTER),
+#endif
+#define SC_TRACE_EVENT_NAME_MAX  0x0082
+#ifdef _SC_TRACE_EVENT_NAME_MAX
+MAP_TO_UNISTD(SC_TRACE_EVENT_NAME_MAX),
+#endif
+#define SC_TRACE_INHERIT       0x0083
+#ifdef _SC_TRACE_INHERIT
+MAP_TO_UNISTD(SC_TRACE_INHERIT),
+#endif
+#define SC_TRACE_LOG           0x0084
+#ifdef _SC_TRACE_LOG
+MAP_TO_UNISTD(SC_TRACE_LOG),
+#endif
+#define SC_TRACE_NAME_MAX      0x0085
+#ifdef _SC_TRACE_NAME_MAX
+MAP_TO_UNISTD(SC_TRACE_NAME_MAX),
+#endif
+#define SC_TRACE_SYS_MAX       0x0086
+#ifdef _SC_TRACE_SYS_MAX
+MAP_TO_UNISTD(SC_TRACE_SYS_MAX),
+#endif
+#define SC_TRACE_USER_EVENT_MAX  0x0087
+#ifdef _SC_TRACE_USER_EVENT_MAX
+MAP_TO_UNISTD(SC_TRACE_USER_EVENT_MAX),
+#endif
+#define SC_TYPED_MEMORY_OBJECTS  0x0088
+#ifdef _SC_TYPED_MEMORY_OBJECTS
+MAP_TO_UNISTD(SC_TYPED_MEMORY_OBJECTS),
+#endif
+#define SC_V7_ILP32_OFF32      0x0089
+#ifdef _SC_V7_ILP32_OFF32
+MAP_TO_UNISTD(SC_V7_ILP32_OFF32),
+#endif
+#define SC_V7_ILP32_OFFBIG     0x008a
+#ifdef _SC_V7_ILP32_OFFBIG
+MAP_TO_UNISTD(SC_V7_ILP32_OFFBIG),
+#endif
+#define SC_V7_LP64_OFF64       0x008b
+#ifdef _SC_V7_LP64_OFF64
+MAP_TO_UNISTD(SC_V7_LP64_OFF64),
+#endif
+#define SC_V7_LPBIG_OFFBIG     0x008c
+#ifdef _SC_V7_LPBIG_OFFBIG
+MAP_TO_UNISTD(SC_V7_LPBIG_OFFBIG),
+#endif
+#define SC_XOPEN_STREAMS       0x008d
+#ifdef _SC_XOPEN_STREAMS
+MAP_TO_UNISTD(SC_XOPEN_STREAMS),
+#endif
+#define SC_XOPEN_UUCP          0x008e
+#ifdef _SC_XOPEN_UUCP
+MAP_TO_UNISTD(SC_XOPEN_UUCP),
+#endif
+#define SC_LEVEL1_ICACHE_SIZE      0x008f
+#ifdef _SC_LEVEL1_ICACHE_SIZE
+MAP_TO_UNISTD(SC_LEVEL1_ICACHE_SIZE),
+#endif
+#define SC_LEVEL1_ICACHE_ASSOC     0x0090
+#ifdef _SC_LEVEL1_ICACHE_ASSOC
+MAP_TO_UNISTD(SC_LEVEL1_ICACHE_ASSOC),
+#endif
+#define SC_LEVEL1_ICACHE_LINESIZE  0x0091
+#ifdef _SC_LEVEL1_ICACHE_LINESIZE
+MAP_TO_UNISTD(SC_LEVEL1_ICACHE_LINESIZE),
+#endif
+#define SC_LEVEL1_DCACHE_SIZE      0x0092
+#ifdef _SC_LEVEL1_DCACHE_SIZE
+MAP_TO_UNISTD(SC_LEVEL1_DCACHE_SIZE),
+#endif
+#define SC_LEVEL1_DCACHE_ASSOC     0x0093
+#ifdef _SC_LEVEL1_DCACHE_ASSOC
+MAP_TO_UNISTD(SC_LEVEL1_DCACHE_ASSOC),
+#endif
+#define SC_LEVEL1_DCACHE_LINESIZE  0x0094
+#ifdef _SC_LEVEL1_DCACHE_LINESIZE
+MAP_TO_UNISTD(SC_LEVEL1_DCACHE_LINESIZE),
+#endif
+#define SC_LEVEL2_CACHE_SIZE       0x0095
+#ifdef _SC_LEVEL2_CACHE_SIZE
+MAP_TO_UNISTD(SC_LEVEL2_CACHE_SIZE),
+#endif
+#define SC_LEVEL2_CACHE_ASSOC      0x0096
+#ifdef _SC_LEVEL2_CACHE_ASSOC
+MAP_TO_UNISTD(SC_LEVEL2_CACHE_ASSOC),
+#endif
+#define SC_LEVEL2_CACHE_LINESIZE   0x0097
+#ifdef _SC_LEVEL2_CACHE_LINESIZE
+MAP_TO_UNISTD(SC_LEVEL2_CACHE_LINESIZE),
+#endif
+#define SC_LEVEL3_CACHE_SIZE       0x0098
+#ifdef _SC_LEVEL3_CACHE_SIZE
+MAP_TO_UNISTD(SC_LEVEL3_CACHE_SIZE),
+#endif
+#define SC_LEVEL3_CACHE_ASSOC      0x0099
+#ifdef _SC_LEVEL3_CACHE_ASSOC
+MAP_TO_UNISTD(SC_LEVEL3_CACHE_ASSOC),
+#endif
+#define SC_LEVEL3_CACHE_LINESIZE   0x009a
+#ifdef _SC_LEVEL3_CACHE_LINESIZE
+MAP_TO_UNISTD(SC_LEVEL3_CACHE_LINESIZE),
+#endif
+#define SC_LEVEL4_CACHE_SIZE       0x009b
+#ifdef _SC_LEVEL4_CACHE_SIZE
+MAP_TO_UNISTD(SC_LEVEL4_CACHE_SIZE),
+#endif
+#define SC_LEVEL4_CACHE_ASSOC      0x009c
+#ifdef _SC_LEVEL4_CACHE_ASSOC
+MAP_TO_UNISTD(SC_LEVEL4_CACHE_ASSOC),
+#endif
+#define SC_LEVEL4_CACHE_LINESIZE   0x009d
+#ifdef _SC_LEVEL4_CACHE_LINESIZE
+MAP_TO_UNISTD(SC_LEVEL4_CACHE_LINESIZE),
+#endif
 };
 #undef MAP_TO_UNISTD
 
-long my_sysconf(int name)
+long _hybris_map_sysconf(int name)
 {
 	return sysconf(sysconf_map[name]);
 }
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/configure.ac
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/configure.ac
@@ -42,6 +42,12 @@ AC_ARG_ENABLE(debug,
   [debug="no"])
 AM_CONDITIONAL( [WANT_DEBUG], [test x"$debug" = x"yes"])
 
+AC_ARG_ENABLE(experimental,
+  [  --enable-experimental     Enable experimental features (default=disabled)],
+  [experimental=$enableval],
+  [experimental="no"])
+AM_CONDITIONAL( [WANT_EXPERIMENTAL], [test x"$experimental" = x"yes"])
+
 AC_ARG_ENABLE(trace,
   [  --enable-trace            Enable TRACE statements (default=disabled)],
   [trace=$enableval],
@@ -67,20 +73,47 @@ AC_ARG_ENABLE(wayland,
   [wayland="no"])
 AM_CONDITIONAL( [WANT_WAYLAND], [test x"$wayland" = x"yes"])
 
+AC_ARG_ENABLE(mir,
+  [  --enable-mir            Enable mir support (default=disabled)],
+  [mir=$enableval
+	PKG_CHECK_MODULES(MIR_CLIENT, mirclient,, exit)
+	MIR_PREFIX=`$PKG_CONFIG --variable=prefix mirclient`
+
+	AC_DEFINE(WANT_MIR, [], [We want Mir support])
+],
+  [mir="no"])
+AM_CONDITIONAL( [WANT_MIR], [test x"$mir" = x"yes"])
+
 AC_ARG_ENABLE(wayland_serverside_buffers,
   [  --enable-wayland_serverside_buffers            Enable serverside buffer allocation for wayland (default=enabled)],
   [wayland_serverside_buffers=$enableval],
   [wayland_serverside_buffers=yes])
 AM_CONDITIONAL( [WANT_WL_SERVERSIDE_BUFFERS], [test x"$wayland_serverside_buffers" = x"yes"])
 
+AC_ARG_ENABLE(property_cache,
+  [  --enable-property-cache      Enable runtime android property cache (default=disabled)],
+  [property_cache=$enableval],
+  [property_cache=no])
+AM_CONDITIONAL( [WANT_RUNTIME_PROPERTY_CACHE], [test x"$property_cache" = x"yes"])
+
+AC_ARG_ENABLE(ubuntu-linker-overrides,
+  [  --enable-ubuntu-linker-overrides  Enable Ubuntu linker overrides (default=disabled)],
+  [ubuntu_linker_overrides=$enableval],
+  [ubuntu_linker_overrides=no])
+AM_CONDITIONAL([WANT_UBUNTU_LINKER_OVERRIDES], [test x"$ubuntu_linker_overrides" = x"yes"])
+
 AC_ARG_ENABLE(arch,
   [  --enable-arch[=arch]     Compile specific CPU target(default=arm)
                               arm: compile for ARM
                               x86: Compile for x86],
   [ if   test "x$enableval" = "xarm" ; then
       arch="arm"
+   elif test "x$enableval" = "xarm64" ; then
+      arch="arm64"
    elif test "x$enableval" = "xx86" ; then
       arch="x86"
+   elif test "x$enableval" = "xx86-64" ; then
+      arch="x86-64"
    else
       echo
       echo "Error!"
@@ -91,7 +124,9 @@ AC_ARG_ENABLE(arch,
   [arch="arm"]
   )
 AM_CONDITIONAL([WANT_ARCH_ARM], [test x$arch = xarm])
+AM_CONDITIONAL([WANT_ARCH_ARM64], [test x$arch = xarm64])
 AM_CONDITIONAL([WANT_ARCH_X86], [test x$arch = xx86])
+AM_CONDITIONAL([WANT_ARCH_X86_64], [test x$arch = xx86-64])
 
 DEFAULT_EGL_PLATFORM="null"
 AC_ARG_WITH(default-egl-platform,
@@ -100,7 +135,11 @@ AC_ARG_WITH(default-egl-platform,
   [ ])
 AC_SUBST(DEFAULT_EGL_PLATFORM)
 
-DEFAULT_HYBRIS_LD_LIBRARY_PATH="/vendor/lib:/system/lib"
+if test "x$arch" = "xarm" -o "x$arch" = "xx86"; then
+  DEFAULT_HYBRIS_LD_LIBRARY_PATH="/vendor/lib:/system/lib"
+else
+  DEFAULT_HYBRIS_LD_LIBRARY_PATH="/vendor/lib64:/system/lib64"
+fi
 AC_ARG_WITH(default-hybris-ld-library-path,
   [  --with-default-hybris-ld-library-path=PATH1:PATH2:...     Use PATH1:PATH2 for default HYBRIS_LD_LIBRARY_PATH if not specified by environment ],
   [ DEFAULT_HYBRIS_LD_LIBRARY_PATH="$withval" ],
@@ -114,7 +153,10 @@ AC_ARG_WITH(android-headers,
     AS_IF([test -f $withval/libnfc-nxp/phLibNfc.h], [ANDROID_HEADERS_CFLAGS="-I$withval -I$withval/libnfc-nxp"],[ANDROID_HEADERS_CFLAGS="-I$withval"])
     AC_SUBST([ANDROID_HEADERS_CFLAGS])
   ],
-  [ PKG_CHECK_MODULES(ANDROID_HEADERS, android-headers,, exit) ]
+  [
+    PKG_CHECK_MODULES(ANDROID_HEADERS, android-headers,, exit)
+    AM_CONDITIONAL([HAS_LIBNFC_NXP_HEADERS], [false])
+  ]
 )
 CPPFLAGS="$CPPFLAGS $ANDROID_HEADERS_CFLAGS"
 
@@ -177,15 +219,26 @@ AM_CONDITIONAL([HAS_ANDROID_4_1_0], [tes
 AM_CONDITIONAL([HAS_ANDROID_4_0_0], [test $android_headers_major -ge 4 -a $android_headers_minor -ge 0 ])
 AM_CONDITIONAL([HAS_ANDROID_2_3_0], [test $android_headers_major -ge 2 -a $android_headers_minor -ge 3 ])
 
+AC_ARG_ENABLE(mali-quirks,
+  [  --enable-mali-quirks            Enable Mali GPU driver quirks (default=disabled)],
+  [mali_quirks=$enableval],
+  [mali_quirks="no"])
+AM_CONDITIONAL([WANT_MALI_QUIRKS], [test x"$mali_quirks" = x"yes"])
+
+AC_ARG_ENABLE(stub-linker,
+  [  --enable-stub-linker            Enable a stub linker which does nothing (default=disabled)],
+  [stub_linker=$enableval],
+  [stub_linker="no"])
+AM_CONDITIONAL([WANT_STUB_LINKER], [test x"$stub_linker" = x"yes"])
 
 AC_CONFIG_FILES([
 	Makefile
 	properties/Makefile
 	properties/libandroid-properties.pc
 	common/Makefile
-	common/gingerbread/Makefile
-	common/ics/Makefile
 	common/jb/Makefile
+	common/stub/Makefile
+	common/mm/Makefile
 	egl/egl.pc
 	egl/Makefile
 	egl/platforms/Makefile
@@ -194,6 +247,7 @@ AC_CONFIG_FILES([
 	egl/platforms/null/Makefile
 	egl/platforms/fbdev/Makefile
 	egl/platforms/wayland/Makefile
+	egl/platforms/mir/Makefile
 	egl/platforms/hwcomposer/Makefile
 	egl/platforms/hwcomposer/hwcomposer-egl.pc
 	glesv1/glesv1_cm.pc
@@ -217,6 +271,10 @@ AC_CONFIG_FILES([
 	camera/libcamera.pc
 	vibrator/Makefile
 	vibrator/libvibrator.pc
+	media/Makefile
+	media/libmedia.pc
+	wifi/Makefile
+	wifi/libwifi.pc
 	include/Makefile
 	utils/Makefile
 	tests/Makefile
@@ -236,16 +294,26 @@ echo "  debug build.............: $debug
 echo
 echo "  trace...................: $trace"
 echo
+echo "  experimental features...: $experimental"
+echo
 echo "  prefix..................: $prefix"
 echo
 echo "  arch  ..................: $arch"
 echo
 echo "  headers path ...........: $android_headers_path"
 echo
+echo "  Android version.........: $android_headers_major.$android_headers_minor.$android_headers_patch"
+echo
 echo "  default egl platform ...: $DEFAULT_EGL_PLATFORM"
 echo
 echo "  default ld_library_path.: $DEFAULT_HYBRIS_LD_LIBRARY_PATH"
 echo
+echo "Features:"
+echo
+echo "  stub linker.............: $stub_linker"
+echo
+echo "  Ubuntu linker overrides.: $ubuntu_linker_overrides"
+echo
 echo "------------------------------------------------------------------------"
 echo
 echo "Now type 'make' to compile and 'make install' to install this package."
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/egl/egl.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/egl.c
@@ -15,10 +15,10 @@
  *
  */
 
+#include "config.h"
+
 /* EGL function pointers */
 #define EGL_EGLEXT_PROTOTYPES
-/* For RTLD_DEFAULT */
-#define _GNU_SOURCE
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <GLES2/gl2.h>
@@ -260,14 +260,17 @@ EGLSurface eglCreateWindowSurface(EGLDis
 
 	HYBRIS_TRACE_BEGIN("hybris-egl", "eglCreateWindowSurface", "");
 	struct _EGLDisplay *display = hybris_egl_display_get_mapping(dpy);
-	win = ws_CreateWindow(win, display);
+	struct _EGLNativeWindowType* window = ws_CreateWindow(win, display, config);
 
-	assert(((struct ANativeWindowBuffer *) win)->common.magic == ANDROID_NATIVE_WINDOW_MAGIC);
+	assert(((struct ANativeWindowBuffer *) window->win)->common.magic == ANDROID_NATIVE_WINDOW_MAGIC);
 
 	HYBRIS_TRACE_BEGIN("native-egl", "eglCreateWindowSurface", "");
-	EGLSurface result = (*_eglCreateWindowSurface)(dpy, config, win, attrib_list);
+	EGLSurface result = (*_eglCreateWindowSurface)(dpy, config, window->win, attrib_list);
+
 	HYBRIS_TRACE_END("native-egl", "eglCreateWindowSurface", "");
-	egl_helper_push_mapping(result, win);
+
+	if (result != EGL_NO_SURFACE)
+		egl_helper_push_mapping(result, window);
 
 	HYBRIS_TRACE_END("hybris-egl", "eglCreateWindowSurface", "");
 	return result;
@@ -367,7 +370,6 @@ EGLBoolean eglSwapInterval(EGLDisplay dp
 {
 	EGLBoolean ret;
 	EGLSurface surface;
-	EGLNativeWindowType win;
 	HYBRIS_TRACE_BEGIN("hybris-egl", "eglSwapInterval", "=%d", interval);
 
 	/* Some egl implementations don't pass through the setSwapInterval
@@ -393,7 +395,7 @@ EGLContext eglCreateContext(EGLDisplay d
 {
 	EGL_DLSYM(&_eglCreateContext, "eglCreateContext");
 
-	EGLint *p = attrib_list;
+	const EGLint *p = attrib_list;
 	while (p != NULL && *p != EGL_NONE) {
 		if (*p == EGL_CONTEXT_CLIENT_VERSION) {
 			_egl_context_client_version = p[1];
@@ -456,7 +458,7 @@ EGLBoolean eglWaitNative(EGLint engine)
 
 EGLBoolean _my_eglSwapBuffersWithDamageEXT(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects)
 {
-	EGLNativeWindowType win;
+	struct _EGLNativeWindowType* win;
 	EGLBoolean ret;
 	HYBRIS_TRACE_BEGIN("hybris-egl", "eglSwapBuffersWithDamageEXT", "");
 	EGL_DLSYM(&_eglSwapBuffers, "eglSwapBuffers");
@@ -498,7 +500,8 @@ static EGLImageKHR _my_eglCreateImageKHR
 	EGLClientBuffer newbuffer = buffer;
 	const EGLint *newattrib_list = attrib_list;
 
-	ws_passthroughImageKHR(&newctx, &newtarget, &newbuffer, &newattrib_list);
+	struct _EGLDisplay *display = hybris_egl_display_get_mapping(dpy);
+	ws_passthroughImageKHR(display, &newctx, &newtarget, &newbuffer, &newattrib_list);
 
 	EGLImageKHR eik = (*_eglCreateImageKHR)(dpy, newctx, newtarget, newbuffer, newattrib_list);
 
@@ -527,19 +530,19 @@ __eglMustCastToProperFunctionPointerType
 	EGL_DLSYM(&_eglGetProcAddress, "eglGetProcAddress");
 	if (strcmp(procname, "eglCreateImageKHR") == 0)
 	{
-		return _my_eglCreateImageKHR;
+		return (__eglMustCastToProperFunctionPointerType) _my_eglCreateImageKHR;
 	}
 	else if (strcmp(procname, "eglDestroyImageKHR") == 0)
 	{
-		return eglDestroyImageKHR;
+		return (__eglMustCastToProperFunctionPointerType) eglDestroyImageKHR;
 	}
 	else if (strcmp(procname, "eglSwapBuffersWithDamageEXT") == 0)
 	{
-		return _my_eglSwapBuffersWithDamageEXT;
+		return (__eglMustCastToProperFunctionPointerType) _my_eglSwapBuffersWithDamageEXT;
 	}
 	else if (strcmp(procname, "glEGLImageTargetTexture2DOES") == 0)
 	{
-		return _my_glEGLImageTargetTexture2DOES;
+		return (__eglMustCastToProperFunctionPointerType) _my_glEGLImageTargetTexture2DOES;
 	}
 
 	__eglMustCastToProperFunctionPointerType ret = NULL;
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/egl/helper.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/helper.cpp
@@ -25,10 +25,10 @@
 
 
 /* Keep track of active EGL window surfaces */
-static std::map<EGLSurface,EGLNativeWindowType> _surface_window_map;
+static std::map<EGLSurface, _EGLNativeWindowType*> _surface_window_map;
 
 
-void egl_helper_push_mapping(EGLSurface surface, EGLNativeWindowType window)
+void egl_helper_push_mapping(EGLSurface surface, _EGLNativeWindowType* window)
 {
     assert(!egl_helper_has_mapping(surface));
 
@@ -40,9 +40,9 @@ int egl_helper_has_mapping(EGLSurface su
     return (_surface_window_map.find(surface) != _surface_window_map.end());
 }
 
-EGLNativeWindowType egl_helper_get_mapping(EGLSurface surface)
+_EGLNativeWindowType* egl_helper_get_mapping(EGLSurface surface)
 {
-    std::map<EGLSurface,EGLNativeWindowType>::iterator it;
+    std::map<EGLSurface,_EGLNativeWindowType*>::iterator it;
     it = _surface_window_map.find(surface);
 
     /* Caller must check with egl_helper_has_mapping() before */
@@ -51,15 +51,15 @@ EGLNativeWindowType egl_helper_get_mappi
     return it->second;
 }
 
-EGLNativeWindowType egl_helper_pop_mapping(EGLSurface surface)
+_EGLNativeWindowType* egl_helper_pop_mapping(EGLSurface surface)
 {
-    std::map<EGLSurface,EGLNativeWindowType>::iterator it;
+    std::map<EGLSurface,_EGLNativeWindowType*>::iterator it;
     it = _surface_window_map.find(surface);
 
     /* Caller must check with egl_helper_has_mapping() before */
     assert(it != _surface_window_map.end());
 
-    EGLNativeWindowType result = it->second;
+    _EGLNativeWindowType* result = it->second;
     _surface_window_map.erase(it);
     return result;
 }
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/egl/helper.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/helper.h
@@ -23,7 +23,7 @@
 
 
 #include <EGL/egl.h>
-
+#include "ws.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -31,16 +31,16 @@ extern "C" {
 
 
 /* Add new mapping from surface to window */
-void egl_helper_push_mapping(EGLSurface surface, EGLNativeWindowType window);
+void egl_helper_push_mapping(EGLSurface surface, struct _EGLNativeWindowType* window);
 
 /* Check if a mapping for a surface exist */
 int egl_helper_has_mapping(EGLSurface surface);
 
 /* Return (without removing) the mapping for a surface */
-EGLNativeWindowType egl_helper_get_mapping(EGLSurface surface);
+struct _EGLNativeWindowType* egl_helper_get_mapping(EGLSurface surface);
 
 /* Return and remove the mapping for a surface */
-EGLNativeWindowType egl_helper_pop_mapping(EGLSurface surface);
+struct _EGLNativeWindowType* egl_helper_pop_mapping(EGLSurface surface);
 
 
 #ifdef __cplusplus
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/egl/platforms/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/platforms/Makefile.am
@@ -11,4 +11,8 @@ if WANT_WAYLAND
 SUBDIRS += wayland
 endif
 
+if WANT_MIR
+SUBDIRS += mir
+endif
+
 
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/egl/platforms/common/eglplatformcommon.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/platforms/common/eglplatformcommon.cpp
@@ -43,7 +43,7 @@ extern "C" int hybris_egl_has_mapping(EG
 	return (*my_egl_interface->has_mapping)(surface);
 }
 
-EGLNativeWindowType hybris_egl_get_mapping(EGLSurface surface)
+struct _EGLNativeWindowType* hybris_egl_get_mapping(EGLSurface surface)
 {
 	return (*my_egl_interface->get_mapping)(surface);
 }
@@ -265,7 +265,7 @@ extern "C" EGLBoolean eglplatformcommon_
 
 
 extern "C" void
-eglplatformcommon_passthroughImageKHR(EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list)
+eglplatformcommon_passthroughImageKHR(struct _EGLDisplay*, EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list)
 {
 #ifdef WANT_WAYLAND
 	static int debugenvchecked = 0;
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/egl/platforms/common/eglplatformcommon.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/platforms/common/eglplatformcommon.h
@@ -6,6 +6,6 @@
 
 void eglplatformcommon_init(struct ws_egl_interface *egl_iface, gralloc_module_t *gralloc, alloc_device_t *allocdevice);
 __eglMustCastToProperFunctionPointerType eglplatformcommon_eglGetProcAddress(const char *procname);
-void eglplatformcommon_passthroughImageKHR(EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list);
+void eglplatformcommon_passthroughImageKHR(struct _EGLDisplay*, EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list);
 const char *eglplatformcommon_eglQueryString(EGLDisplay dpy, EGLint name, const char *(*real_eglQueryString)(EGLDisplay dpy, EGLint name));
 #endif
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/egl/platforms/fbdev/eglplatform_fbdev.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/platforms/fbdev/eglplatform_fbdev.cpp
@@ -60,17 +60,19 @@ extern "C" void fbdevws_Terminate(_EGLDi
 	delete dpy;
 }
 
-extern "C" EGLNativeWindowType fbdevws_CreateWindow(EGLNativeWindowType win, _EGLDisplay *display)
+extern "C" struct _EGLNativeWindowType *fbdevws_CreateWindow(EGLNativeWindowType win, _EGLDisplay *display, EGLConfig)
 {
 	assert (gralloc != NULL);
 	assert (_nativewindow == NULL);
 
 	_nativewindow = new FbDevNativeWindow(alloc, framebuffer);
 	_nativewindow->common.incRef(&_nativewindow->common);
-	return (EGLNativeWindowType) static_cast<struct ANativeWindow *>(_nativewindow);
+    struct _EGLNativeWindowType* type = new struct _EGLNativeWindowType;
+	type->win = (EGLNativeWindowType) static_cast<struct ANativeWindow *>(_nativewindow);
+	return type;
 }
 
-extern "C" void fbdevws_DestroyWindow(EGLNativeWindowType win)
+extern "C" void fbdevws_DestroyWindow(struct _EGLNativeWindowType *win)
 {
 	assert (_nativewindow != NULL);
 	assert (static_cast<FbDevNativeWindow *>((struct ANativeWindow *)win) == _nativewindow);
@@ -78,6 +80,7 @@ extern "C" void fbdevws_DestroyWindow(EG
 	_nativewindow->common.decRef(&_nativewindow->common);
 	/* We are done with it, refcounting will delete the window when appropriate */
 	_nativewindow = NULL;
+	delete win;
 }
 
 extern "C" __eglMustCastToProperFunctionPointerType fbdevws_eglGetProcAddress(const char *procname) 
@@ -85,14 +88,14 @@ extern "C" __eglMustCastToProperFunction
 	return eglplatformcommon_eglGetProcAddress(procname);
 }
 
-extern "C" void fbdevws_passthroughImageKHR(EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list)
+extern "C" void fbdevws_passthroughImageKHR(_EGLDisplay* display, EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list)
 {
-	eglplatformcommon_passthroughImageKHR(ctx, target, buffer, attrib_list);
+	eglplatformcommon_passthroughImageKHR(display, ctx, target, buffer, attrib_list);
 }
 
-extern "C" void fbdevws_setSwapInterval(EGLDisplay dpy, EGLNativeWindowType win, EGLint interval)
+extern "C" void fbdevws_setSwapInterval(EGLDisplay dpy, _EGLNativeWindowType* win, EGLint interval)
 {
-	FbDevNativeWindow *window = static_cast<FbDevNativeWindow *>((struct ANativeWindow *)win);
+	FbDevNativeWindow *window = static_cast<FbDevNativeWindow *>((struct ANativeWindow *)win->win);
 	window->setSwapInterval(interval);
 }
 
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/egl/platforms/hwcomposer/eglplatform_hwcomposer.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/platforms/hwcomposer/eglplatform_hwcomposer.cpp
@@ -51,7 +51,7 @@ extern "C" void hwcomposerws_Terminate(_
 	delete dpy;
 }
 
-extern "C" EGLNativeWindowType hwcomposerws_CreateWindow(EGLNativeWindowType win, _EGLDisplay *display)
+extern "C" struct _EGLNativeWindowType *hwcomposerws_CreateWindow(EGLNativeWindowType win, _EGLDisplay *display, EGLConfig)
 {
 	assert (gralloc != NULL);
 	assert (_nativewindow == NULL);
@@ -60,10 +60,13 @@ extern "C" EGLNativeWindowType hwcompose
 	window->setup(gralloc, alloc);
 	_nativewindow = window;
 	_nativewindow->common.incRef(&_nativewindow->common);
-	return (EGLNativeWindowType) static_cast<struct ANativeWindow *>(_nativewindow);
+    struct _EGLNativeWindowType* type = new struct _EGLNativeWindowType;
+	type->win = (EGLNativeWindowType) static_cast<struct ANativeWindow *>(_nativewindow);
+	return type;
+
 }
 
-extern "C" void hwcomposerws_DestroyWindow(EGLNativeWindowType win)
+extern "C" void hwcomposerws_DestroyWindow(struct _EGLNativeWindowType* win)
 {
 	assert (_nativewindow != NULL);
 	assert (static_cast<HWComposerNativeWindow *>((struct ANativeWindow *)win) == _nativewindow);
@@ -71,6 +74,7 @@ extern "C" void hwcomposerws_DestroyWind
 	_nativewindow->common.decRef(&_nativewindow->common);
 	/* We are done with it, refcounting will delete the window when appropriate */
 	_nativewindow = NULL;
+	delete win;
 }
 
 extern "C" __eglMustCastToProperFunctionPointerType hwcomposerws_eglGetProcAddress(const char *procname) 
@@ -78,9 +82,9 @@ extern "C" __eglMustCastToProperFunction
 	return eglplatformcommon_eglGetProcAddress(procname);
 }
 
-extern "C" void hwcomposerws_passthroughImageKHR(EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list)
+extern "C" void hwcomposerws_passthroughImageKHR(_EGLDisplay* dpy, EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list)
 {
-	eglplatformcommon_passthroughImageKHR(ctx, target, buffer, attrib_list);
+	eglplatformcommon_passthroughImageKHR(dpy, ctx, target, buffer, attrib_list);
 }
 
 struct ws_module ws_module_info = {
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/platforms/mir/Makefile.am
@@ -0,0 +1,17 @@
+pkglib_LTLIBRARIES = eglplatform_mir.la
+
+eglplatform_mir_la_SOURCES = eglplatform_mir.cpp
+eglplatform_mir_la_CXXFLAGS = \
+	-I$(top_srcdir)/egl \
+	-I$(top_srcdir)/include \
+	-I$(top_srcdir)/common \
+	-I$(top_srcdir)/include \
+	-I$(top_srcdir)/egl \
+	-I$(top_srcdir)/egl/platforms/common \
+	$(ANDROID_HEADERS_CFLAGS) \
+	$(MIR_CLIENT_CFLAGS)
+	
+eglplatform_mir_la_LDFLAGS = \
+	-avoid-version -module -shared -export-dynamic \
+	$(top_builddir)/egl/platforms/common/libhybris-eglplatformcommon.la \
+	$(top_builddir)/hardware/libhardware.la
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/platforms/mir/eglplatform_mir.cpp
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2017 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
+ */
+
+#define ANDROID
+#include <EGL/eglplatform.h>
+#include <mir_toolkit/mir_extension_core.h>
+#include <mir_toolkit/extensions/android_egl.h>
+#include <mir_toolkit/mir_client_library.h>
+#include <mir_toolkit/rs/mir_render_surface.h>
+#include <android-config.h>
+#include <ws.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <hybris/common/binding.h>
+#include <stdlib.h>
+#include "logging.h"
+
+extern "C" {
+#include <eglplatformcommon.h>
+}
+
+static gralloc_module_t *gralloc = 0;
+static alloc_device_t *alloc = 0;
+static unsigned int const usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER;
+
+struct MirNativeWindowBase : _EGLNativeWindowType
+{
+    virtual ~MirNativeWindowBase() {};
+    virtual void prepareSwap() = 0;
+    virtual void setSwapInterval(EGLint interval) = 0;
+protected:
+    MirNativeWindowBase() {};
+private:
+    MirNativeWindowBase(MirNativeWindowBase const&);
+    MirNativeWindowBase& operator=(MirNativeWindowBase const&);
+};
+
+struct MirBaseDisplay : _EGLDisplay
+{
+    MirBaseDisplay(EGLDisplay display)
+    {
+        dpy = display;
+    }
+
+    virtual struct _EGLNativeWindowType* create_window(
+        EGLNativeWindowType win, EGLConfig config) = 0;
+    virtual void destroy_window(ANativeWindow* window) = 0;
+    virtual void passthrough_img(EGLContext *ctx, EGLenum *target, EGLClientBuffer *b, const EGLint **attrib_list) = 0;
+
+protected:
+    MirBaseDisplay() {}
+private:
+    MirBaseDisplay(MirBaseDisplay const&);
+    MirBaseDisplay& operator=(MirBaseDisplay const&);
+};
+
+
+struct MirNativeWindowType : MirNativeWindowBase
+{
+    MirNativeWindowType(
+        MirExtensionAndroidEGLV1 const* ext,
+        MirRenderSurface* surface, EGLint format)
+    {
+        int width = -1;
+        int height = -1;
+        mir_render_surface_get_size(surface, &width, &height);
+        win = ext->create_window(surface, width, height, format, usage);
+        rs = surface;
+    }
+
+    ~MirNativeWindowType()
+    {
+        ext->destroy_window(win);
+    }
+
+    void prepareSwap()
+    {
+        int w = -1;
+        int h = -1;
+        mir_render_surface_get_size(rs, &w, &h);
+        if (w != width || h != height)
+        {
+            native_window_set_buffers_dimensions(win, w, h);
+            width = w;
+            height = h;
+        }
+    }
+
+    void setSwapInterval(EGLint interval)
+    {
+        ANativeWindow* anw = win;
+        anw->setSwapInterval(anw, interval);
+    }
+
+    MirExtensionAndroidEGLV1 const* ext;
+    MirRenderSurface * rs;
+    int width;
+    int height;
+};
+
+struct NullNativeWindowType : MirNativeWindowBase
+{
+    NullNativeWindowType(EGLNativeWindowType t)
+    {
+        win = t;
+    }
+
+    void prepareSwap()
+    {
+    }
+
+    void setSwapInterval(EGLint interval)
+    {
+    }
+};
+
+struct MirDisplay : MirBaseDisplay
+{
+    MirDisplay(MirConnection* con, MirExtensionAndroidEGLV1 const* ext) :
+        MirBaseDisplay(ext->to_display(connection)),
+        connection(con),
+        ext(ext)
+    {
+    }
+
+    struct _EGLNativeWindowType* create_window(
+        EGLNativeWindowType win, EGLConfig config)
+    {
+        EGLint format = 0;
+        eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &format);
+        return new MirNativeWindowType(ext, (MirRenderSurface*) win, format);
+    }
+
+    void destroy_window(ANativeWindow* window)
+    {
+        ext->destroy_window(window);
+    }
+
+    void passthrough_img(EGLContext *ctx, EGLenum *target, EGLClientBuffer *b, const EGLint **attrib_list)
+    {
+        MirBuffer* buffer = (MirBuffer*) *b;
+        *b = create_buffer(buffer);
+        *target = EGL_NATIVE_BUFFER_ANDROID;
+    }
+
+    ANativeWindowBuffer* create_buffer(MirBuffer* buffer)
+    {
+        return ext->create_buffer(buffer);
+    }
+
+    void destroy_buffer(ANativeWindowBuffer* buffer)
+    {
+        return ext->destroy_buffer(buffer);
+    }
+
+private:
+    MirConnection* connection;
+    MirExtensionAndroidEGLV1 const* ext;
+};
+
+struct ErrorDisplay : MirBaseDisplay
+{
+    ErrorDisplay() :
+        MirBaseDisplay(EGL_NO_DISPLAY)
+    {
+    }
+
+    struct _EGLNativeWindowType* create_window(
+        EGLNativeWindowType win, EGLConfig config)
+    {
+        return NULL;
+    }
+
+    void destroy_window(ANativeWindow* window)
+    {
+    }
+
+    void passthrough_img(EGLContext *ctx, EGLenum *target, EGLClientBuffer *b, const EGLint **attrib_list)
+    {
+    }
+};
+
+static int const legacy_dpy = 12345;
+struct NullDisplay : MirBaseDisplay
+{
+    NullDisplay() :
+        MirBaseDisplay((EGLDisplay)&legacy_dpy)
+    {
+    }
+
+    struct _EGLNativeWindowType* create_window(EGLNativeWindowType win, EGLConfig config)
+    {
+        return new NullNativeWindowType(win);
+    }
+
+    void destroy_window(ANativeWindow* window)
+    {
+    }
+
+    void passthrough_img(EGLContext *ctx, EGLenum *target, EGLClientBuffer *b, const EGLint **attrib_list)
+    {
+    }
+};
+
+extern "C" void mir_init_module(struct ws_egl_interface *egl_iface)
+{
+    int err;
+    hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const hw_module_t **) &gralloc);
+    err = gralloc_open((const hw_module_t *) gralloc, &alloc);
+    TRACE("++ %lu mir: got gralloc %p err:%s", pthread_self(), gralloc, strerror(-err));
+    eglplatformcommon_init(egl_iface, gralloc, alloc);
+}
+
+extern "C" _EGLDisplay *mir_GetDisplay(EGLNativeDisplayType display)
+{
+    if (display == EGL_DEFAULT_DISPLAY)
+    {
+        TRACE("++ %lu mir: using null mir platform", pthread_self());
+        return new NullDisplay;
+    }
+
+    MirConnection* connection = static_cast<MirConnection*>(display);
+    MirExtensionAndroidEGLV1 const* ext =  mir_extension_android_egl_v1(connection);
+    if (!ext)
+    {
+        HYBRIS_ERROR("could not access android extensions from mir library");
+        return new ErrorDisplay;
+    }
+    TRACE("++ %lu mir: using mir platform", pthread_self());
+    return new MirDisplay(connection, ext);
+}
+
+extern "C" void mir_Terminate(_EGLDisplay *dpy)
+{
+    MirBaseDisplay* d = (MirBaseDisplay*) dpy;
+    delete d;
+}
+
+extern "C" struct _EGLNativeWindowType *mir_CreateWindow(EGLNativeWindowType win, _EGLDisplay *dis, EGLConfig config)
+{
+    MirBaseDisplay* d = (MirBaseDisplay*) dis;
+    return d->create_window(win, config);
+}
+
+extern "C" void mir_DestroyWindow(struct _EGLNativeWindowType * t)
+{
+    MirNativeWindowType* native_win = (MirNativeWindowType*) t;
+    delete native_win;
+}
+
+extern "C" void mir_prepareSwap(
+    EGLDisplay dpy, _EGLNativeWindowType* win, EGLint *damage_rects, EGLint damage_n_rects)
+{
+    MirNativeWindowType* type = (MirNativeWindowType*)win;
+    type->prepareSwap();
+}
+
+extern "C" void mir_setSwapInterval(
+    EGLDisplay dpy, struct _EGLNativeWindowType* win, EGLint interval)
+{
+    MirNativeWindowType* type = (MirNativeWindowType*)win;
+    type->setSwapInterval(interval);
+}
+
+extern "C" void
+mir_passthroughImageKHR(_EGLDisplay* disp, EGLContext *ctx,
+    EGLenum *target, EGLClientBuffer *b, const EGLint **attrib_list)
+{
+    MirBaseDisplay* d = (MirBaseDisplay*) disp;
+    d->passthrough_img(ctx, target, b, attrib_list);
+}
+
+struct ws_module ws_module_info = {
+    mir_init_module,
+    mir_GetDisplay,
+    mir_Terminate,
+    mir_CreateWindow,
+    mir_DestroyWindow,
+    eglplatformcommon_eglGetProcAddress,
+    mir_passthroughImageKHR,
+    eglplatformcommon_eglQueryString,
+    mir_prepareSwap,
+    NULL,
+    mir_setSwapInterval
+};
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/egl/platforms/null/eglplatform_null.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/platforms/null/eglplatform_null.c
@@ -16,7 +16,7 @@ static alloc_device_t *alloc = 0;
 
 static void _init_androidui()
 {
-       _libui = (void *) android_dlopen("/system/lib/libui.so", RTLD_LAZY);
+       _libui = (void *) android_dlopen("libui.so", RTLD_LAZY);
 }
 
 #define UI_DLSYM(fptr, sym) do { if (_libui == NULL) { _init_androidui(); }; if (*(fptr) == NULL) { *(fptr) = (void *) android_dlsym(_libui, sym); } } while (0) 
@@ -48,19 +48,20 @@ static void nullws_Terminate(struct _EGL
 	free(dpy);
 }
 
-static EGLNativeWindowType nullws_CreateWindow(EGLNativeWindowType win, struct _EGLDisplay *display)
+static struct _EGLNativeWindowType *nullws_CreateWindow(EGLNativeWindowType win, struct _EGLDisplay *display, EGLConfig config)
 {
+    struct _EGLNativeWindowType* type = malloc(sizeof(struct _EGLNativeWindowType));
 	if (win == 0)
-	{
-		return android_createDisplaySurface();
-	}
+        type->win = android_createDisplaySurface();
 	else
-		return win;
+		type->win = win;
+    return type;
 }
 
-static void nullws_DestroyWindow(EGLNativeWindowType win)
+static void nullws_DestroyWindow(struct _EGLNativeWindowType *win)
 {
 	// TODO: Cleanup?
+    free(win);
 }
 
 struct ws_module ws_module_info = {
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/egl/platforms/wayland/eglplatform_wayland.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/platforms/wayland/eglplatform_wayland.cpp
@@ -168,8 +168,9 @@ extern "C" void waylandws_Terminate(_EGL
 	delete wdpy;
 }
 
-extern "C" EGLNativeWindowType waylandws_CreateWindow(EGLNativeWindowType win, _EGLDisplay *display)
+extern "C" struct _EGLNativeWindowType* waylandws_CreateWindow(EGLNativeWindowType win, _EGLDisplay *display, EGLConfig)
 {
+    struct _EGLNativeWindowType* type = (struct _EGLNativeWindowType*) malloc(sizeof(struct _EGLNativeWindowType));
 	struct wl_egl_window *wl_window = (struct wl_egl_window*) win;
 	struct wl_display *wl_display = (struct wl_display*) display;
 
@@ -191,10 +192,11 @@ extern "C" EGLNativeWindowType waylandws
 
 	WaylandNativeWindow *window = new WaylandNativeWindow((struct wl_egl_window *) win, wdpy->wl_dpy, wdpy->wlegl, alloc, gralloc);
 	window->common.incRef(&window->common);
-	return (EGLNativeWindowType) static_cast<struct ANativeWindow *>(window);
+    type->win = (EGLNativeWindowType) static_cast<struct ANativeWindow *>(window);
+    return type;
 }
 
-extern "C" void waylandws_DestroyWindow(EGLNativeWindowType win)
+extern "C" void waylandws_DestroyWindow(struct _EGLNativeWindowType* win)
 {
 	WaylandNativeWindow *window = static_cast<WaylandNativeWindow *>((struct ANativeWindow *)win);
 	window->common.decRef(&window->common);
@@ -242,9 +244,9 @@ extern "C" __eglMustCastToProperFunction
 	return eglplatformcommon_eglGetProcAddress(procname);
 }
 
-extern "C" void waylandws_passthroughImageKHR(EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list)
+extern "C" void waylandws_passthroughImageKHR(struct _EGLDisplay* dpy, EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list)
 {
-	eglplatformcommon_passthroughImageKHR(ctx, target, buffer, attrib_list);
+	eglplatformcommon_passthroughImageKHR(dpy, ctx, target, buffer, attrib_list);
 }
 
 extern "C" const char *waylandws_eglQueryString(EGLDisplay dpy, EGLint name, const char *(*real_eglQueryString)(EGLDisplay dpy, EGLint name))
@@ -261,16 +263,16 @@ extern "C" const char *waylandws_eglQuer
 	return ret;
 }
 
-extern "C" void waylandws_prepareSwap(EGLDisplay dpy, EGLNativeWindowType win, EGLint *damage_rects, EGLint damage_n_rects)
+extern "C" void waylandws_prepareSwap(EGLDisplay dpy, _EGLNativeWindowType* win, EGLint *damage_rects, EGLint damage_n_rects)
 {
-	WaylandNativeWindow *window = static_cast<WaylandNativeWindow *>((struct ANativeWindow *)win);
+	WaylandNativeWindow *window = static_cast<WaylandNativeWindow *>((struct ANativeWindow *)win->win);
 	window->prepareSwap(damage_rects, damage_n_rects);
 }
 
-extern "C" void waylandws_finishSwap(EGLDisplay dpy, EGLNativeWindowType win)
+extern "C" void waylandws_finishSwap(EGLDisplay dpy, _EGLNativeWindowType* win)
 {
 	_init_egl_funcs(dpy);
-	WaylandNativeWindow *window = static_cast<WaylandNativeWindow *>((struct ANativeWindow *)win);
+	WaylandNativeWindow *window = static_cast<WaylandNativeWindow *>((struct ANativeWindow *)win->win);
 	if (_eglCreateSyncKHR) {
 		EGLSyncKHR sync = (*_eglCreateSyncKHR)(dpy, EGL_SYNC_FENCE_KHR, NULL);
 		(*_eglClientWaitSyncKHR)(dpy, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR);
@@ -279,9 +281,9 @@ extern "C" void waylandws_finishSwap(EGL
 	window->finishSwap();
 }
 
-extern "C" void waylandws_setSwapInterval(EGLDisplay dpy, EGLNativeWindowType win, EGLint interval)
+extern "C" void waylandws_setSwapInterval(EGLDisplay dpy, _EGLNativeWindowType* win, EGLint interval)
 {
-	WaylandNativeWindow *window = static_cast<WaylandNativeWindow *>((struct ANativeWindow *)win);
+	WaylandNativeWindow *window = static_cast<WaylandNativeWindow *>((struct ANativeWindow *)win->win);
 	window->setSwapInterval(interval);
 }
 
@@ -301,7 +303,6 @@ struct ws_module ws_module_info = {
 
 
 
-
 
 
 
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/egl/ws.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/ws.c
@@ -67,13 +67,13 @@ void ws_Terminate(struct _EGLDisplay *dp
 	ws->Terminate(dpy);
 }
 
-EGLNativeWindowType ws_CreateWindow(EGLNativeWindowType win, struct _EGLDisplay *display)
+struct _EGLNativeWindowType* ws_CreateWindow(EGLNativeWindowType win, struct _EGLDisplay *display, EGLConfig config)
 {
 	_init_ws();
-	return ws->CreateWindow(win, display);
+	return ws->CreateWindow(win, display, config);
 }
 
-void ws_DestroyWindow(EGLNativeWindowType win)
+void ws_DestroyWindow(struct _EGLNativeWindowType* win)
 {
 	_init_ws();
 	return ws->DestroyWindow(win);
@@ -85,10 +85,10 @@ __eglMustCastToProperFunctionPointerType
 	return ws->eglGetProcAddress(procname);
 }
 
-void ws_passthroughImageKHR(EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list)
+void ws_passthroughImageKHR(struct _EGLDisplay* dpy, EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list)
 {
 	_init_ws();
-	return ws->passthroughImageKHR(ctx, target, buffer, attrib_list);
+	return ws->passthroughImageKHR(dpy, ctx, target, buffer, attrib_list);
 }
 
 const char *ws_eglQueryString(EGLDisplay dpy, EGLint name, const char *(*real_eglQueryString)(EGLDisplay dpy, EGLint name))
@@ -97,21 +97,21 @@ const char *ws_eglQueryString(EGLDisplay
 	return ws->eglQueryString(dpy, name, real_eglQueryString);
 }
 
-void ws_prepareSwap(EGLDisplay dpy, EGLNativeWindowType win, EGLint *damage_rects, EGLint damage_n_rects)
+void ws_prepareSwap(EGLDisplay dpy, struct _EGLNativeWindowType* win, EGLint *damage_rects, EGLint damage_n_rects)
 {
 	_init_ws();
 	if (ws->prepareSwap)
 		ws->prepareSwap(dpy, win, damage_rects, damage_n_rects);
 }
 
-void ws_finishSwap(EGLDisplay dpy, EGLNativeWindowType win)
+void ws_finishSwap(EGLDisplay dpy, struct _EGLNativeWindowType* win)
 {
 	_init_ws();
 	if (ws->finishSwap)
 		ws->finishSwap(dpy, win);
 }
 
-void ws_setSwapInterval(EGLDisplay dpy, EGLNativeWindowType win, EGLint interval)
+void ws_setSwapInterval(EGLDisplay dpy, struct _EGLNativeWindowType* win, EGLint interval)
 {
 	_init_ws();
 	if (ws->setSwapInterval)
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/egl/ws.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/egl/ws.h
@@ -7,7 +7,7 @@ struct ws_egl_interface {
 	void * (*android_egl_dlsym)(const char *symbol);
 
 	int (*has_mapping)(EGLSurface surface);
-	EGLNativeWindowType (*get_mapping)(EGLSurface surface);
+	struct _EGLNativeWindowType* (*get_mapping)(EGLSurface surface);
 };
 
 struct egl_image
@@ -24,30 +24,38 @@ struct _EGLDisplay {
 	EGLDisplay dpy;
 };
 
+struct _EGLNativeWindowType {
+	EGLNativeWindowType win;
+};
+
+struct _EGLClientBuffer {
+    EGLClientBuffer buf;
+};
+
 struct ws_module {
 	void (*init_module)(struct ws_egl_interface *egl_interface);
 
 	struct _EGLDisplay *(*GetDisplay)(EGLNativeDisplayType native);
 	void (*Terminate)(struct _EGLDisplay *display);
-	EGLNativeWindowType (*CreateWindow)(EGLNativeWindowType win, struct _EGLDisplay *display);
-	void (*DestroyWindow)(EGLNativeWindowType win);
+	struct _EGLNativeWindowType *(*CreateWindow)(EGLNativeWindowType win, struct _EGLDisplay *display, EGLConfig config);
+	void (*DestroyWindow)(struct _EGLNativeWindowType* win);
 	__eglMustCastToProperFunctionPointerType (*eglGetProcAddress)(const char *procname);
-	void (*passthroughImageKHR)(EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list);
+	void (*passthroughImageKHR)(struct _EGLDisplay* dpy, EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list);
 	const char *(*eglQueryString)(EGLDisplay dpy, EGLint name, const char *(*real_eglQueryString)(EGLDisplay dpy, EGLint name));
-	void (*prepareSwap)(EGLDisplay dpy, EGLNativeWindowType win, EGLint *damage_rects, EGLint damage_n_rects);
-	void (*finishSwap)(EGLDisplay dpy, EGLNativeWindowType win);
-	void (*setSwapInterval)(EGLDisplay dpy, EGLNativeWindowType win, EGLint interval);
+	void (*prepareSwap)(EGLDisplay dpy, struct _EGLNativeWindowType* win, EGLint *damage_rects, EGLint damage_n_rects);
+	void (*finishSwap)(EGLDisplay dpy, struct _EGLNativeWindowType* win);
+	void (*setSwapInterval)(EGLDisplay dpy, struct _EGLNativeWindowType* win, EGLint interval);
 };
 
 struct _EGLDisplay *ws_GetDisplay(EGLNativeDisplayType native);
 void ws_Terminate(struct _EGLDisplay *dpy);
-EGLNativeWindowType ws_CreateWindow(EGLNativeWindowType win, struct _EGLDisplay *display);
-void ws_DestroyWindow(EGLNativeWindowType win);
+struct _EGLNativeWindowType *ws_CreateWindow(EGLNativeWindowType win, struct _EGLDisplay *display, EGLConfig);
+void ws_DestroyWindow(struct _EGLNativeWindowType* win);
 __eglMustCastToProperFunctionPointerType ws_eglGetProcAddress(const char *procname);
-void ws_passthroughImageKHR(EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list);
+void ws_passthroughImageKHR(struct _EGLDisplay* dpy, EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list);
 const char *ws_eglQueryString(EGLDisplay dpy, EGLint name, const char *(*real_eglQueryString)(EGLDisplay dpy, EGLint name));
-void ws_prepareSwap(EGLDisplay dpy, EGLNativeWindowType win, EGLint *damage_rects, EGLint damage_n_rects);
-void ws_finishSwap(EGLDisplay dpy, EGLNativeWindowType win);
-void ws_setSwapInterval(EGLDisplay dpy, EGLNativeWindowType win, EGLint interval);
+void ws_prepareSwap(EGLDisplay dpy, struct _EGLNativeWindowType* win, EGLint *damage_rects, EGLint damage_n_rects);
+void ws_finishSwap(EGLDisplay dpy, struct _EGLNativeWindowType* win);
+void ws_setSwapInterval(EGLDisplay dpy, struct _EGLNativeWindowType* win, EGLint interval);
 
 #endif
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/glesv1/glesv1_cm.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/glesv1/glesv1_cm.c
@@ -26,7 +26,7 @@
 
 #include <hybris/common/binding.h>
 
-#define GLESV1_CM_LIBRARY_PATH "/system/lib/libGLESv1_CM.so"
+#define GLESV1_CM_LIBRARY_PATH "libGLESv1_CM.so"
 
 HYBRIS_LIBRARY_INITIALIZE(glesv1_cm, GLESV1_CM_LIBRARY_PATH);
 
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/glesv2/glesv2.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/glesv2/glesv2.c
@@ -21,405 +21,1030 @@
 #include <dlfcn.h>
 #include <stddef.h>
 #include <stdlib.h>
+#include <stdio.h>
 
-#include <egl/ws.h>
 #include <hybris/common/binding.h>
-#include <hybris/common/floating_point_abi.h>
 
 static void *_libglesv2 = NULL;
 
-/* Only functions with floating point argument need a wrapper to change the call convention correctly */
-
+static void         (*_glActiveTexture)(GLenum texture) = NULL;
+static void         (*_glAttachShader)(GLuint program, GLuint shader) = NULL;
+static void         (*_glBindAttribLocation)(GLuint program, GLuint index, const GLchar* name) = NULL;
+static void         (*_glBindBuffer)(GLenum target, GLuint buffer) = NULL;
+static void         (*_glBindFramebuffer)(GLenum target, GLuint framebuffer) = NULL;
+static void         (*_glBindRenderbuffer)(GLenum target, GLuint renderbuffer) = NULL;
+static void         (*_glBindTexture)(GLenum target, GLuint texture) = NULL;
 static void         (*_glBlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) FP_ATTRIB = NULL;
+static void         (*_glBlendEquation)(GLenum mode ) = NULL;
+static void         (*_glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha) = NULL;
+static void         (*_glBlendFunc)(GLenum sfactor, GLenum dfactor) = NULL;
+static void         (*_glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) = NULL;
+static void         (*_glBufferData)(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) = NULL;
+static void         (*_glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) = NULL;
+static GLenum       (*_glCheckFramebufferStatus)(GLenum target) = NULL;
+static void         (*_glClear)(GLbitfield mask) = NULL;
 static void         (*_glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) FP_ATTRIB = NULL;
 static void         (*_glClearDepthf)(GLclampf depth) FP_ATTRIB = NULL;
+static void         (*_glClearStencil)(GLint s) = NULL;
+static void         (*_glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) = NULL;
+static void         (*_glCompileShader)(GLuint shader) = NULL;
+static void         (*_glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) = NULL;
+static void         (*_glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) = NULL;
+static void         (*_glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) = NULL;
+static void         (*_glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) = NULL;
+static GLuint       (*_glCreateProgram)(void) = NULL;
+static GLuint       (*_glCreateShader)(GLenum type) = NULL;
+static void         (*_glCullFace)(GLenum mode) = NULL;
+static void         (*_glDeleteBuffers)(GLsizei n, const GLuint* buffers) = NULL;
+static void         (*_glDeleteFramebuffers)(GLsizei n, const GLuint* framebuffers) = NULL;
+static void         (*_glDeleteProgram)(GLuint program) = NULL;
+static void         (*_glDeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers) = NULL;
+static void         (*_glDeleteShader)(GLuint shader) = NULL;
+static void         (*_glDeleteTextures)(GLsizei n, const GLuint* textures) = NULL;
+static void         (*_glDepthFunc)(GLenum func) = NULL;
+static void         (*_glDepthMask)(GLboolean flag) = NULL;
 static void         (*_glDepthRangef)(GLclampf zNear, GLclampf zFar) FP_ATTRIB = NULL;
+static void         (*_glDetachShader)(GLuint program, GLuint shader) = NULL;
+static void         (*_glDisable)(GLenum cap) = NULL;
+static void         (*_glDisableVertexAttribArray)(GLuint index) = NULL;
+static void         (*_glDrawArrays)(GLenum mode, GLint first, GLsizei count) = NULL;
+static void         (*_glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) = NULL;
+static void         (*_glEnable)(GLenum cap) = NULL;
+static void         (*_glEnableVertexAttribArray)(GLuint index) = NULL;
+static void         (*_glFinish)(void) = NULL;
+static void         (*_glFlush)(void) = NULL;
+static void         (*_glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) = NULL;
+static void         (*_glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) = NULL;
+static void         (*_glFrontFace)(GLenum mode) = NULL;
+static void         (*_glGenBuffers)(GLsizei n, GLuint* buffers) = NULL;
+static void         (*_glGenerateMipmap)(GLenum target) = NULL;
+static void         (*_glGenFramebuffers)(GLsizei n, GLuint* framebuffers) = NULL;
+static void         (*_glGenRenderbuffers)(GLsizei n, GLuint* renderbuffers) = NULL;
+static void         (*_glGenTextures)(GLsizei n, GLuint* textures) = NULL;
+static void         (*_glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) = NULL;
+static void         (*_glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) = NULL;
+static void         (*_glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) = NULL;
+static int          (*_glGetAttribLocation)(GLuint program, const GLchar* name) = NULL;
+static void         (*_glGetBooleanv)(GLenum pname, GLboolean* params) = NULL;
+static void         (*_glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params) = NULL;
+static GLenum       (*_glGetError)(void) = NULL;
+static void         (*_glGetFloatv)(GLenum pname, GLfloat* params) = NULL;
+static void         (*_glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params) = NULL;
+static void         (*_glGetIntegerv)(GLenum pname, GLint* params) = NULL;
+static void         (*_glGetProgramiv)(GLuint program, GLenum pname, GLint* params) = NULL;
+static void         (*_glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) = NULL;
+static void         (*_glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params) = NULL;
+static void         (*_glGetShaderiv)(GLuint shader, GLenum pname, GLint* params) = NULL;
+static void         (*_glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) = NULL;
+static void         (*_glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) = NULL;
+static void         (*_glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) = NULL;
+static const GLubyte* (*_glGetString)(GLenum name) = NULL;
+static void         (*_glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params) = NULL;
+static void         (*_glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params) = NULL;
+static void         (*_glGetUniformfv)(GLuint program, GLint location, GLfloat* params) = NULL;
+static void         (*_glGetUniformiv)(GLuint program, GLint location, GLint* params) = NULL;
+static int          (*_glGetUniformLocation)(GLuint program, const GLchar* name) = NULL;
+static void         (*_glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params) = NULL;
+static void         (*_glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params) = NULL;
+static void         (*_glGetVertexAttribPointerv)(GLuint index, GLenum pname, GLvoid** pointer) = NULL;
+static void         (*_glHint)(GLenum target, GLenum mode) = NULL;
+static GLboolean    (*_glIsBuffer)(GLuint buffer) = NULL;
+static GLboolean    (*_glIsEnabled)(GLenum cap) = NULL;
+static GLboolean    (*_glIsFramebuffer)(GLuint framebuffer) = NULL;
+static GLboolean    (*_glIsProgram)(GLuint program) = NULL;
+static GLboolean    (*_glIsRenderbuffer)(GLuint renderbuffer) = NULL;
+static GLboolean    (*_glIsShader)(GLuint shader) = NULL;
+static GLboolean    (*_glIsTexture)(GLuint texture) = NULL;
 static void         (*_glLineWidth)(GLfloat width) FP_ATTRIB = NULL;
+static void         (*_glLinkProgram)(GLuint program) = NULL;
+static void         (*_glPixelStorei)(GLenum pname, GLint param) = NULL;
 static void         (*_glPolygonOffset)(GLfloat factor, GLfloat units) FP_ATTRIB = NULL;
+static void         (*_glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) = NULL;
+static void         (*_glReleaseShaderCompiler)(void) = NULL;
+static void         (*_glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) = NULL;
 static void         (*_glSampleCoverage)(GLclampf value, GLboolean invert) FP_ATTRIB = NULL;
+static void         (*_glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) = NULL;
+static void         (*_glShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) = NULL;
+static void         (*_glShaderSource)(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) = NULL;
+static void         (*_glStencilFunc)(GLenum func, GLint ref, GLuint mask) = NULL;
+static void         (*_glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask) = NULL;
+static void         (*_glStencilMask)(GLuint mask) = NULL;
+static void         (*_glStencilMaskSeparate)(GLenum face, GLuint mask) = NULL;
+static void         (*_glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) = NULL;
+static void         (*_glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) = NULL;
+static void         (*_glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) = NULL;
 static void         (*_glTexParameterf)(GLenum target, GLenum pname, GLfloat param) FP_ATTRIB = NULL;
+static void         (*_glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params) = NULL;
+static void         (*_glTexParameteri)(GLenum target, GLenum pname, GLint param) = NULL;
+static void         (*_glTexParameteriv)(GLenum target, GLenum pname, const GLint* params) = NULL;
+static void         (*_glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) = NULL;
 static void         (*_glUniform1f)(GLint location, GLfloat x) FP_ATTRIB = NULL;
+static void         (*_glUniform1fv)(GLint location, GLsizei count, const GLfloat* v) = NULL;
+static void         (*_glUniform1i)(GLint location, GLint x) = NULL;
+static void         (*_glUniform1iv)(GLint location, GLsizei count, const GLint* v) = NULL;
 static void         (*_glUniform2f)(GLint location, GLfloat x, GLfloat y) FP_ATTRIB = NULL;
+static void         (*_glUniform2fv)(GLint location, GLsizei count, const GLfloat* v) = NULL;
+static void         (*_glUniform2i)(GLint location, GLint x, GLint y) = NULL;
+static void         (*_glUniform2iv)(GLint location, GLsizei count, const GLint* v) = NULL;
 static void         (*_glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z) FP_ATTRIB = NULL;
+static void         (*_glUniform3fv)(GLint location, GLsizei count, const GLfloat* v) = NULL;
+static void         (*_glUniform3i)(GLint location, GLint x, GLint y, GLint z) = NULL;
+static void         (*_glUniform3iv)(GLint location, GLsizei count, const GLint* v) = NULL;
 static void         (*_glUniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) FP_ATTRIB = NULL;
+static void         (*_glUniform4fv)(GLint location, GLsizei count, const GLfloat* v) = NULL;
+static void         (*_glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w) = NULL;
+static void         (*_glUniform4iv)(GLint location, GLsizei count, const GLint* v) = NULL;
+static void         (*_glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) = NULL;
+static void         (*_glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) = NULL;
+static void         (*_glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) = NULL;
+static void         (*_glUseProgram)(GLuint program) = NULL;
+static void         (*_glValidateProgram)(GLuint program) = NULL;
 static void         (*_glVertexAttrib1f)(GLuint indx, GLfloat x) FP_ATTRIB = NULL;
+static void         (*_glVertexAttrib1fv)(GLuint indx, const GLfloat* values) = NULL;
 static void         (*_glVertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y) FP_ATTRIB = NULL;
+static void         (*_glVertexAttrib2fv)(GLuint indx, const GLfloat* values) = NULL;
 static void         (*_glVertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z) FP_ATTRIB = NULL;
+static void         (*_glVertexAttrib3fv)(GLuint indx, const GLfloat* values) = NULL;
 static void         (*_glVertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) FP_ATTRIB = NULL;
-static void         (*_glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) = NULL;
+static void         (*_glVertexAttrib4fv)(GLuint indx, const GLfloat* values) = NULL;
+static void         (*_glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) = NULL;
+static void         (*_glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) = NULL;
+static void         (*_glEGLImageTargetTexture2DOES) (GLenum target, GLeglImageOES image) = NULL;
 
 
 #define GLES2_LOAD(sym)  { *(&_ ## sym) = (void *) android_dlsym(_libglesv2, #sym);  } 
 
-/*
-This generates a function that when first called overwrites it's plt entry with new address. Subsequent calls jump directly at the target function in the android library. This means effectively 0 call overhead after the first call.
-*/
-
-#define GLES2_IDLOAD(sym) \
- __asm__ (".type " #sym ", %gnu_indirect_function"); \
-typeof(sym) * sym ## _dispatch (void) __asm__ (#sym);\
-typeof(sym) * sym ## _dispatch (void) \
-{ \
-	return (void *) android_dlsym(_libglesv2, #sym); \
-} 
-
 static void  __attribute__((constructor)) _init_androidglesv2()  {
 	_libglesv2 = (void *) android_dlopen(getenv("LIBGLESV2") ? getenv("LIBGLESV2") : "libGLESv2.so", RTLD_NOW);
+	GLES2_LOAD(glActiveTexture);
+	GLES2_LOAD(glAttachShader);
+	GLES2_LOAD(glBindAttribLocation);
+	GLES2_LOAD(glBindBuffer);
+	GLES2_LOAD(glBindFramebuffer);
+	GLES2_LOAD(glBindRenderbuffer);
+	GLES2_LOAD(glBindTexture);
 	GLES2_LOAD(glBlendColor);
+	GLES2_LOAD(glBlendEquation);
+	GLES2_LOAD(glBlendEquationSeparate);
+	GLES2_LOAD(glBlendFunc);
+	GLES2_LOAD(glBlendFuncSeparate);
+	GLES2_LOAD(glBufferData);
+	GLES2_LOAD(glBufferSubData);
+	GLES2_LOAD(glCheckFramebufferStatus);
+	GLES2_LOAD(glClear);
 	GLES2_LOAD(glClearColor);
 	GLES2_LOAD(glClearDepthf);
+	GLES2_LOAD(glClearStencil);
+	GLES2_LOAD(glColorMask);
+	GLES2_LOAD(glCompileShader);
+	GLES2_LOAD(glCompressedTexImage2D);
+	GLES2_LOAD(glCompressedTexSubImage2D);
+	GLES2_LOAD(glCopyTexImage2D);
+	GLES2_LOAD(glCopyTexSubImage2D);
+	GLES2_LOAD(glCreateProgram);
+	GLES2_LOAD(glCreateShader);
+	GLES2_LOAD(glCullFace);
+	GLES2_LOAD(glDeleteBuffers);
+	GLES2_LOAD(glDeleteFramebuffers);
+	GLES2_LOAD(glDeleteProgram);
+	GLES2_LOAD(glDeleteRenderbuffers);
+	GLES2_LOAD(glDeleteShader);
+	GLES2_LOAD(glDeleteTextures);
+	GLES2_LOAD(glDepthFunc);
+	GLES2_LOAD(glDepthMask);
 	GLES2_LOAD(glDepthRangef);
+	GLES2_LOAD(glDetachShader);
+	GLES2_LOAD(glDisable);
+	GLES2_LOAD(glDisableVertexAttribArray);
+	GLES2_LOAD(glDrawArrays);
+	GLES2_LOAD(glDrawElements);
+	GLES2_LOAD(glEnable);
+	GLES2_LOAD(glEnableVertexAttribArray);
+	GLES2_LOAD(glFinish);
+	GLES2_LOAD(glFlush);
+	GLES2_LOAD(glFramebufferRenderbuffer);
+	GLES2_LOAD(glFramebufferTexture2D);
+	GLES2_LOAD(glFrontFace);
+	GLES2_LOAD(glGenBuffers);
+	GLES2_LOAD(glGenerateMipmap);
+	GLES2_LOAD(glGenFramebuffers);
+	GLES2_LOAD(glGenRenderbuffers);
+	GLES2_LOAD(glGenTextures);
+	GLES2_LOAD(glGetActiveAttrib);
+	GLES2_LOAD(glGetActiveUniform);
+	GLES2_LOAD(glGetAttachedShaders);
+	GLES2_LOAD(glGetAttribLocation);
+	GLES2_LOAD(glGetBooleanv);
+	GLES2_LOAD(glGetBufferParameteriv);
+	GLES2_LOAD(glGetError);
+	GLES2_LOAD(glGetFloatv);
+	GLES2_LOAD(glGetFramebufferAttachmentParameteriv);
+	GLES2_LOAD(glGetIntegerv);
+	GLES2_LOAD(glGetProgramiv);
+	GLES2_LOAD(glGetProgramInfoLog);
+	GLES2_LOAD(glGetRenderbufferParameteriv);
+	GLES2_LOAD(glGetShaderiv);
+	GLES2_LOAD(glGetShaderInfoLog);
+	GLES2_LOAD(glGetShaderPrecisionFormat);
+	GLES2_LOAD(glGetShaderSource);
+	GLES2_LOAD(glGetString);
+	GLES2_LOAD(glGetTexParameterfv);
+	GLES2_LOAD(glGetTexParameteriv);
+	GLES2_LOAD(glGetUniformfv);
+	GLES2_LOAD(glGetUniformiv);
+	GLES2_LOAD(glGetUniformLocation);
+	GLES2_LOAD(glGetVertexAttribfv);
+	GLES2_LOAD(glGetVertexAttribiv);
+	GLES2_LOAD(glGetVertexAttribPointerv);
+	GLES2_LOAD(glHint);
+	GLES2_LOAD(glIsBuffer);
+	GLES2_LOAD(glIsEnabled);
+	GLES2_LOAD(glIsFramebuffer);
+	GLES2_LOAD(glIsProgram);
+	GLES2_LOAD(glIsRenderbuffer);
+	GLES2_LOAD(glIsShader);
+	GLES2_LOAD(glIsTexture);
 	GLES2_LOAD(glLineWidth);
+	GLES2_LOAD(glLinkProgram);
+	GLES2_LOAD(glPixelStorei);
 	GLES2_LOAD(glPolygonOffset);
+	GLES2_LOAD(glReadPixels);
+	GLES2_LOAD(glReleaseShaderCompiler);
+	GLES2_LOAD(glRenderbufferStorage);
 	GLES2_LOAD(glSampleCoverage);
+	GLES2_LOAD(glScissor);
+	GLES2_LOAD(glShaderBinary);
+	GLES2_LOAD(glShaderSource);
+	GLES2_LOAD(glStencilFunc);
+	GLES2_LOAD(glStencilFuncSeparate);
+	GLES2_LOAD(glStencilMask);
+	GLES2_LOAD(glStencilMaskSeparate);
+	GLES2_LOAD(glStencilOp);
+	GLES2_LOAD(glStencilOpSeparate);
+	GLES2_LOAD(glTexImage2D);
 	GLES2_LOAD(glTexParameterf);
+	GLES2_LOAD(glTexParameterfv);
+	GLES2_LOAD(glTexParameteri);
+	GLES2_LOAD(glTexParameteriv);
+	GLES2_LOAD(glTexSubImage2D);
 	GLES2_LOAD(glUniform1f);
+	GLES2_LOAD(glUniform1fv);
+	GLES2_LOAD(glUniform1i);
+	GLES2_LOAD(glUniform1iv);
 	GLES2_LOAD(glUniform2f);
+	GLES2_LOAD(glUniform2fv);
+	GLES2_LOAD(glUniform2i);
+	GLES2_LOAD(glUniform2iv);
 	GLES2_LOAD(glUniform3f);
+	GLES2_LOAD(glUniform3fv);
+	GLES2_LOAD(glUniform3i);
+	GLES2_LOAD(glUniform3iv);
 	GLES2_LOAD(glUniform4f);
+	GLES2_LOAD(glUniform4fv);
+	GLES2_LOAD(glUniform4i);
+	GLES2_LOAD(glUniform4iv);
+	GLES2_LOAD(glUniformMatrix2fv);
+	GLES2_LOAD(glUniformMatrix3fv);
+	GLES2_LOAD(glUniformMatrix4fv);
+	GLES2_LOAD(glUseProgram);
+	GLES2_LOAD(glValidateProgram);
 	GLES2_LOAD(glVertexAttrib1f);
+	GLES2_LOAD(glVertexAttrib1fv);
 	GLES2_LOAD(glVertexAttrib2f);
+	GLES2_LOAD(glVertexAttrib2fv);
 	GLES2_LOAD(glVertexAttrib3f);
+	GLES2_LOAD(glVertexAttrib3fv);
 	GLES2_LOAD(glVertexAttrib4f);
+	GLES2_LOAD(glVertexAttrib4fv);
+	GLES2_LOAD(glVertexAttribPointer);
+	GLES2_LOAD(glViewport);
 	GLES2_LOAD(glEGLImageTargetTexture2DOES);
+	
 }
 
 
-GLES2_IDLOAD(glActiveTexture);
+void glActiveTexture (GLenum texture)
+{
+	(*_glActiveTexture)(texture);
+}
 
-GLES2_IDLOAD(glAttachShader);
+void glAttachShader (GLuint program, GLuint shader)
+{
+	(*_glAttachShader)(program, shader);
+}
 
-GLES2_IDLOAD(glBindAttribLocation);
+void glBindAttribLocation (GLuint program, GLuint index, const GLchar* name)
+{
+	(*_glBindAttribLocation)(program, index, name);
+}
 
-GLES2_IDLOAD(glBindBuffer);
+void glBindBuffer (GLenum target, GLuint buffer)
+{
+	(*_glBindBuffer)(target, buffer);
+}
 
-GLES2_IDLOAD(glBindFramebuffer);
+void glBindFramebuffer (GLenum target, GLuint framebuffer)
+{
+	(*_glBindFramebuffer)(target, framebuffer);
+}
 
-GLES2_IDLOAD(glBindRenderbuffer);
+void glBindRenderbuffer (GLenum target, GLuint renderbuffer)
+{
+	(*_glBindRenderbuffer)(target, renderbuffer);
+}
 
-GLES2_IDLOAD(glBindTexture);
+void glBindTexture (GLenum target, GLuint texture)
+{
+	(*_glBindTexture)(target, texture);
+}
 
-GLES2_IDLOAD(glBlendEquation);
+void glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+	(*_glBlendColor)(red, green, blue, alpha);
+}
 
-GLES2_IDLOAD(glBlendEquationSeparate);
+void glBlendEquation ( GLenum mode )
+{
+	(*_glBlendEquation)(mode);
+}
 
-GLES2_IDLOAD(glBlendFunc);
+void glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha)
+{
+	(*_glBlendEquationSeparate)(modeRGB, modeAlpha);
+}
 
-GLES2_IDLOAD(glBlendFuncSeparate);
+void glBlendFunc (GLenum sfactor, GLenum dfactor)
+{
+	(*_glBlendFunc)(sfactor, dfactor);
+}
 
-GLES2_IDLOAD(glBufferData);
+void glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+{
+	(*_glBlendFuncSeparate)(srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
 
-GLES2_IDLOAD(glBufferSubData);
+void glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
+{
+	(*_glBufferData)(target, size, data, usage);
+}
 
-GLES2_IDLOAD(glCheckFramebufferStatus);
+void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
+{
+	(*_glBufferSubData)(target, offset, size, data);
+}
 
-GLES2_IDLOAD(glClear);
+GLenum glCheckFramebufferStatus (GLenum target)
+{
+	return (*_glCheckFramebufferStatus)(target);
+}
 
-GLES2_IDLOAD(glClearStencil);
+void glClear (GLbitfield mask)
+{
+	(*_glClear)(mask);
+}
 
-GLES2_IDLOAD(glColorMask);
+void glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+	(*_glClearColor)(red, green, blue, alpha);
+}
 
-GLES2_IDLOAD(glCompileShader);
+void glClearDepthf (GLclampf depth)
+{
+	(*_glClearDepthf)(depth);
+}
 
-GLES2_IDLOAD(glCompressedTexImage2D);
+void glClearStencil (GLint s)
+{
+	(*_glClearStencil)(s);
+}
 
-GLES2_IDLOAD(glCompressedTexSubImage2D);
+void glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+{
+	(*_glColorMask)(red, green, blue, alpha);
+}
 
-GLES2_IDLOAD(glCopyTexImage2D);
+void glCompileShader (GLuint shader)
+{
+	(*_glCompileShader)(shader);
+}
 
-GLES2_IDLOAD(glCopyTexSubImage2D);
+void glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data)
+{
+	(*_glCompressedTexImage2D)(target, level, internalformat, width, height, border, imageSize, data);
+}
 
-GLES2_IDLOAD(glCreateProgram);
+void glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data)
+{
+	(*_glCompressedTexSubImage2D)(target, level, xoffset, yoffset, width, height, format, imageSize, data);
+}
 
-GLES2_IDLOAD(glCreateShader);
+void glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+{
+	(*_glCopyTexImage2D)(target, level, internalformat, x, y, width, height, border);
+}
 
-GLES2_IDLOAD(glCullFace);
+void glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	(*_glCopyTexSubImage2D)(target, level, xoffset, yoffset, x, y, width, height);
+}
 
-GLES2_IDLOAD(glDeleteBuffers);
+GLuint glCreateProgram (void)
+{
+	return (*_glCreateProgram)();
+}
 
-GLES2_IDLOAD(glDeleteFramebuffers);
+GLuint glCreateShader (GLenum type)
+{
+	return (*_glCreateShader)(type);
+}
 
-GLES2_IDLOAD(glDeleteProgram);
+void glCullFace (GLenum mode)
+{
+	(*_glCullFace)(mode);
+}
 
-GLES2_IDLOAD(glDeleteRenderbuffers);
+void glDeleteBuffers (GLsizei n, const GLuint* buffers)
+{
+	(*_glDeleteBuffers)(n, buffers);
+}
 
-GLES2_IDLOAD(glDeleteShader);
+void glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers)
+{
+	(*_glDeleteFramebuffers)(n, framebuffers);
+}
 
-GLES2_IDLOAD(glDeleteTextures);
+void glDeleteProgram (GLuint program)
+{
+	(*_glDeleteProgram)(program);
+}
 
-GLES2_IDLOAD(glDepthFunc);
+void glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers)
+{
+	(*_glDeleteRenderbuffers)(n, renderbuffers);
+}
 
-GLES2_IDLOAD(glDepthMask);
+void glDeleteShader (GLuint shader)
+{
+	(*_glDeleteShader)(shader);
+}
 
-GLES2_IDLOAD(glDetachShader);
+void glDeleteTextures (GLsizei n, const GLuint* textures)
+{
+	(*_glDeleteTextures)(n, textures);
+}
 
-GLES2_IDLOAD(glDisable);
+void glDepthFunc (GLenum func)
+{
+	(*_glDepthFunc)(func);
+}
 
-GLES2_IDLOAD(glDisableVertexAttribArray);
+void glDepthMask (GLboolean flag)
+{
+	(*_glDepthMask)(flag);
+}
 
-GLES2_IDLOAD(glDrawArrays);
+void glDepthRangef (GLclampf zNear, GLclampf zFar)
+{
+	(*_glDepthRangef)(zNear, zFar);
+}
 
-GLES2_IDLOAD(glDrawElements);
+void glDetachShader (GLuint program, GLuint shader)
+{
+	(*_glDetachShader)(program, shader);
+}
 
-GLES2_IDLOAD(glEnable);
+void glDisable (GLenum cap)
+{
+	(*_glDisable)(cap);
+}
 
-GLES2_IDLOAD(glEnableVertexAttribArray);
+void glDisableVertexAttribArray (GLuint index)
+{
+	(*_glDisableVertexAttribArray)(index);
+}
 
-GLES2_IDLOAD(glFinish);
+void glDrawArrays (GLenum mode, GLint first, GLsizei count)
+{
+	(*_glDrawArrays)(mode, first, count);
+}
 
-GLES2_IDLOAD(glFlush);
+void glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
+{
+	(*_glDrawElements)(mode, count, type, indices);
+}
 
-GLES2_IDLOAD(glFramebufferRenderbuffer);
+void glEnable (GLenum cap)
+{
+	(*_glEnable)(cap);
+}
 
-GLES2_IDLOAD(glFramebufferTexture2D);
+void glEnableVertexAttribArray (GLuint index)
+{
+	(*_glEnableVertexAttribArray)(index);
+}
 
-GLES2_IDLOAD(glFrontFace);
+void glFinish (void)
+{
+	(*_glFinish)();
+}
 
-GLES2_IDLOAD(glGenBuffers);
+void glFlush (void)
+{
+	(*_glFlush)();
+}
 
-GLES2_IDLOAD(glGenerateMipmap);
+void glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+	(*_glFramebufferRenderbuffer)(target, attachment, renderbuffertarget, renderbuffer);
+}
 
-GLES2_IDLOAD(glGenFramebuffers);
+void glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+	(*_glFramebufferTexture2D)(target, attachment, textarget, texture, level);
+}
 
-GLES2_IDLOAD(glGenRenderbuffers);
+void glFrontFace (GLenum mode)
+{
+	(*_glFrontFace)(mode);
+}
 
-GLES2_IDLOAD(glGenTextures);
+void glGenBuffers (GLsizei n, GLuint* buffers)
+{
+	(*_glGenBuffers)(n, buffers);
+}
 
-GLES2_IDLOAD(glGetActiveAttrib);
+void glGenerateMipmap (GLenum target)
+{
+	(*_glGenerateMipmap)(target);
+}
 
-GLES2_IDLOAD(glGetActiveUniform);
+void glGenFramebuffers (GLsizei n, GLuint* framebuffers)
+{
+	(*_glGenFramebuffers)(n, framebuffers);
+}
 
-GLES2_IDLOAD(glGetAttachedShaders);
+void glGenRenderbuffers (GLsizei n, GLuint* renderbuffers)
+{
+	(*_glGenRenderbuffers)(n, renderbuffers);
+}
 
-GLES2_IDLOAD(glGetAttribLocation);
+void glGenTextures (GLsizei n, GLuint* textures)
+{
+	(*_glGenTextures)(n, textures);
+}
 
-GLES2_IDLOAD(glGetBooleanv);
+void glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+{
+	(*_glGetActiveAttrib)(program, index, bufsize, length, size, type, name);
+}
 
-GLES2_IDLOAD(glGetBufferParameteriv);
+void glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+{
+	(*_glGetActiveUniform)(program, index, bufsize, length, size, type, name);
+}
 
-GLES2_IDLOAD(glGetError);
+void glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+{
+	(*_glGetAttachedShaders)(program, maxcount, count, shaders);
+}
 
-GLES2_IDLOAD(glGetFloatv);
+int glGetAttribLocation (GLuint program, const GLchar* name)
+{
+	return (*_glGetAttribLocation)(program, name);
+}
 
-GLES2_IDLOAD(glGetFramebufferAttachmentParameteriv);
+void glGetBooleanv (GLenum pname, GLboolean* params)
+{
+	(*_glGetBooleanv)(pname, params);
+}
 
-GLES2_IDLOAD(glGetIntegerv);
+void glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params)
+{
+	(*_glGetBufferParameteriv)(target, pname, params);
+}
 
-GLES2_IDLOAD(glGetProgramiv);
+GLenum glGetError (void)
+{
+	return (*_glGetError)();
+}
 
-GLES2_IDLOAD(glGetProgramInfoLog);
+void glGetFloatv (GLenum pname, GLfloat* params)
+{
+	(*_glGetFloatv)(pname, params);
+}
 
-GLES2_IDLOAD(glGetRenderbufferParameteriv);
+void glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params)
+{
+	(*_glGetFramebufferAttachmentParameteriv)(target, attachment, pname, params);
+}
 
-GLES2_IDLOAD(glGetShaderiv);
+void glGetIntegerv (GLenum pname, GLint* params)
+{
+	(*_glGetIntegerv)(pname, params);
+}
 
-GLES2_IDLOAD(glGetShaderInfoLog);
+void glGetProgramiv (GLuint program, GLenum pname, GLint* params)
+{
+	(*_glGetProgramiv)(program, pname, params);
+}
 
-GLES2_IDLOAD(glGetShaderPrecisionFormat);
+void glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+	(*_glGetProgramInfoLog)(program, bufsize, length, infolog);
+}
 
-GLES2_IDLOAD(glGetShaderSource);
+void glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params)
+{
+	(*_glGetRenderbufferParameteriv)(target, pname, params);
+}
 
-GLES2_IDLOAD(glGetString);
+void glGetShaderiv (GLuint shader, GLenum pname, GLint* params)
+{
+	(*_glGetShaderiv)(shader, pname, params);
+}
 
-GLES2_IDLOAD(glGetTexParameterfv);
+void glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+	(*_glGetShaderInfoLog)(shader, bufsize, length, infolog);
+}
 
-GLES2_IDLOAD(glGetTexParameteriv);
+void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+{
+	(*_glGetShaderPrecisionFormat)(shadertype, precisiontype, range, precision);
+}
 
-GLES2_IDLOAD(glGetUniformfv);
+void glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
+{
+	(*_glGetShaderSource)(shader, bufsize, length, source);
+}
 
-GLES2_IDLOAD(glGetUniformiv);
+const GLubyte* glGetString (GLenum name)
+{
+	// Return 2.0 even though drivers might actually support 3.0 or higher,
+	// because libhybris does not provide any 3.0+ symbols.
+	if (name == GL_VERSION) {
+		static GLubyte glGetString_versionString[64];
+		snprintf((char *)glGetString_versionString, sizeof(glGetString_versionString), "OpenGL ES 2.0 (%s)", (*_glGetString)(name));
+		return glGetString_versionString;
+	}
 
-GLES2_IDLOAD(glGetUniformLocation);
+	return (*_glGetString)(name);
+}
 
-GLES2_IDLOAD(glGetVertexAttribfv);
+void glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params)
+{
+	(*_glGetTexParameterfv)(target, pname, params);
+}
 
-GLES2_IDLOAD(glGetVertexAttribiv);
+void glGetTexParameteriv (GLenum target, GLenum pname, GLint* params)
+{
+	(*_glGetTexParameteriv)(target, pname, params);
+}
 
-GLES2_IDLOAD(glGetVertexAttribPointerv);
+void glGetUniformfv (GLuint program, GLint location, GLfloat* params)
+{
+	(*_glGetUniformfv)(program, location, params);
+}
 
-GLES2_IDLOAD(glHint);
+void glGetUniformiv (GLuint program, GLint location, GLint* params)
+{
+	(*_glGetUniformiv)(program, location, params);
+}
 
-GLES2_IDLOAD(glIsBuffer);
+int glGetUniformLocation (GLuint program, const GLchar* name)
+{
+	return (*_glGetUniformLocation)(program, name);
+}
 
-GLES2_IDLOAD(glIsEnabled);
+void glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params)
+{
+	(*_glGetVertexAttribfv)(index, pname, params);
+}
 
-GLES2_IDLOAD(glIsFramebuffer);
+void glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params)
+{
+	(*_glGetVertexAttribiv)(index, pname, params);
+}
 
-GLES2_IDLOAD(glIsProgram);
+void glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer)
+{
+	(*_glGetVertexAttribPointerv)(index, pname, pointer);
+}
 
-GLES2_IDLOAD(glIsRenderbuffer);
+void glHint (GLenum target, GLenum mode)
+{
+	(*_glHint)(target, mode);
+}
 
-GLES2_IDLOAD(glIsShader);
+GLboolean glIsBuffer (GLuint buffer)
+{
+	return (*_glIsBuffer)(buffer);
+}
 
-GLES2_IDLOAD(glIsTexture);
+GLboolean glIsEnabled (GLenum cap)
+{
+	return (*_glIsEnabled)(cap);
+}
 
-GLES2_IDLOAD(glLinkProgram);
+GLboolean glIsFramebuffer (GLuint framebuffer)
+{
+	return (*_glIsFramebuffer)(framebuffer);
+}
 
-GLES2_IDLOAD(glPixelStorei);
+GLboolean glIsProgram (GLuint program)
+{
+	return (*_glIsProgram)(program);
+}
 
-GLES2_IDLOAD(glReadPixels);
+GLboolean glIsRenderbuffer (GLuint renderbuffer)
+{
+	return (*_glIsRenderbuffer)(renderbuffer);
+}
 
-GLES2_IDLOAD(glReleaseShaderCompiler);
+GLboolean glIsShader (GLuint shader)
+{
+	return (*_glIsShader)(shader);
+}
 
-GLES2_IDLOAD(glRenderbufferStorage);
+GLboolean glIsTexture (GLuint texture)
+{
+	return (*_glIsTexture)(texture);
+}
 
-GLES2_IDLOAD(glScissor);
+void glLineWidth (GLfloat width)
+{
+	(*_glLineWidth)(width);
+}
 
-GLES2_IDLOAD(glShaderBinary);
+void glLinkProgram (GLuint program)
+{
+	(*_glLinkProgram)(program);
+}
 
-GLES2_IDLOAD(glShaderSource);
+void glPixelStorei (GLenum pname, GLint param)
+{
+	(*_glPixelStorei)(pname, param);
+}
 
-GLES2_IDLOAD(glStencilFunc);
+void glPolygonOffset (GLfloat factor, GLfloat units)
+{
+	(*_glPolygonOffset)(factor, units);
+}
 
-GLES2_IDLOAD(glStencilFuncSeparate);
+void glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
+{
+	(*_glReadPixels)(x, y, width, height, format, type, pixels);
 
-GLES2_IDLOAD(glStencilMask);
+}
 
-GLES2_IDLOAD(glStencilMaskSeparate);
+void glReleaseShaderCompiler (void)
+{
+	(*_glReleaseShaderCompiler)();
+}
 
-GLES2_IDLOAD(glStencilOp);
+void glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+	(*_glRenderbufferStorage)(target, internalformat, width, height);
+}
 
-GLES2_IDLOAD(glStencilOpSeparate);
+void glSampleCoverage (GLclampf value, GLboolean invert)
+{
+	(*_glSampleCoverage)(value, invert);
+}
 
-GLES2_IDLOAD(glTexImage2D);
+void glScissor (GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	(*_glScissor)(x, y, width, height);
+}
 
-GLES2_IDLOAD(glTexParameterfv);
+void glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
+{
+	(*_glShaderBinary)(n, shaders, binaryformat, binary, length);
+}
 
-GLES2_IDLOAD(glTexParameteri);
+void glShaderSource (GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
+{
+	(*_glShaderSource)(shader, count, string, length);
+}
 
-GLES2_IDLOAD(glTexParameteriv);
+void glStencilFunc (GLenum func, GLint ref, GLuint mask)
+{
+	(*_glStencilFunc)(func, ref, mask);
+}
 
-GLES2_IDLOAD(glTexSubImage2D);
+void glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask)
+{
+	(*_glStencilFuncSeparate)(face, func, ref, mask);
+}
 
-GLES2_IDLOAD(glUniform1fv);
+void glStencilMask (GLuint mask)
+{
+	(*_glStencilMask)(mask);
+}
 
-GLES2_IDLOAD(glUniform1i);
+void glStencilMaskSeparate (GLenum face, GLuint mask)
+{
+	(*_glStencilMaskSeparate)(face, mask);
+}
 
-GLES2_IDLOAD(glUniform1iv);
+void glStencilOp (GLenum fail, GLenum zfail, GLenum zpass)
+{
+	(*_glStencilOp)(fail, zfail, zpass);
+}
 
-GLES2_IDLOAD(glUniform2fv);
+void glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+{
+	(*_glStencilOpSeparate)(face, fail, zfail, zpass);
+}
 
-GLES2_IDLOAD(glUniform2i);
+void glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+{
+	(*_glTexImage2D)(target, level, internalformat, width, height, border, format, type, pixels);
+}
 
-GLES2_IDLOAD(glUniform2iv);
+void glTexParameterf (GLenum target, GLenum pname, GLfloat param)
+{
+	(*_glTexParameterf)(target, pname, param);
+}
 
-GLES2_IDLOAD(glUniform3fv);
+void glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params)
+{
+	(*_glTexParameterfv)(target, pname, params);
+}
 
-GLES2_IDLOAD(glUniform3i);
+void glTexParameteri (GLenum target, GLenum pname, GLint param)
+{
+	(*_glTexParameteri)(target, pname, param);
+}
 
-GLES2_IDLOAD(glUniform3iv);
+void glTexParameteriv (GLenum target, GLenum pname, const GLint* params)
+{
+	(*_glTexParameteriv)(target, pname, params);
+}
 
-GLES2_IDLOAD(glUniform4fv);
+void glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
+{
+	(*_glTexSubImage2D)(target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
 
-GLES2_IDLOAD(glUniform4i);
+void glUniform1f (GLint location, GLfloat x)
+{
+	(*_glUniform1f)(location, x);
+}
 
-GLES2_IDLOAD(glUniform4iv);
+void glUniform1fv (GLint location, GLsizei count, const GLfloat* v)
+{
+	(*_glUniform1fv)(location, count, v);
+}
 
-GLES2_IDLOAD(glUniformMatrix2fv);
+void glUniform1i (GLint location, GLint x)
+{
+	(*_glUniform1i)(location, x);
+}
 
-GLES2_IDLOAD(glUniformMatrix3fv);
+void glUniform1iv (GLint location, GLsizei count, const GLint* v)
+{
+	(*_glUniform1iv)(location, count, v);
+}
 
-GLES2_IDLOAD(glUniformMatrix4fv);
+void glUniform2f (GLint location, GLfloat x, GLfloat y)
+{
+	(*_glUniform2f)(location, x, y);
+}
 
-GLES2_IDLOAD(glUseProgram);
+void glUniform2fv (GLint location, GLsizei count, const GLfloat* v)
+{
+	(*_glUniform2fv)(location, count, v);
+}
 
-GLES2_IDLOAD(glValidateProgram);
+void glUniform2i (GLint location, GLint x, GLint y)
+{
+	(*_glUniform2i)(location, x, y);
+}
 
-GLES2_IDLOAD(glVertexAttrib1fv);
+void glUniform2iv (GLint location, GLsizei count, const GLint* v)
+{
+	(*_glUniform2iv)(location, count, v);
+}
 
-GLES2_IDLOAD(glVertexAttrib2fv);
+void glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z)
+{
+	(*_glUniform3f)(location, x, y, z);
+}
 
-GLES2_IDLOAD(glVertexAttrib3fv);
+void glUniform3fv (GLint location, GLsizei count, const GLfloat* v)
+{
+	(*_glUniform3fv)(location, count, v);
+}
 
-GLES2_IDLOAD(glVertexAttrib4fv);
+void glUniform3i (GLint location, GLint x, GLint y, GLint z)
+{
+	(*_glUniform3i)(location, x, y, z);
+}
 
-GLES2_IDLOAD(glVertexAttribPointer);
+void glUniform3iv (GLint location, GLsizei count, const GLint* v)
+{
+	(*_glUniform3iv)(location, count, v);
+}
 
-GLES2_IDLOAD(glViewport);
+void glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+	(*_glUniform4f)(location, x, y, z, w);
+}
 
-void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
+void glUniform4fv (GLint location, GLsizei count, const GLfloat* v)
 {
-	struct egl_image *img = image;
-	return (*_glEGLImageTargetTexture2DOES)(target, img ? img->egl_image : NULL);
+	(*_glUniform4fv)(location, count, v);
 }
 
-void glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+void glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w)
 {
-	return (*_glBlendColor)(red, green, blue, alpha);
+	(*_glUniform4i)(location, x, y, z, w);
 }
 
-void glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+void glUniform4iv (GLint location, GLsizei count, const GLint* v)
 {
-	return (*_glVertexAttrib4f)(indx, x, y, z, w);
+	(*_glUniform4iv)(location, count, v);
 }
 
-void glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y)
+void glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
 {
-	return (*_glVertexAttrib2f)(indx, x, y);
+	(*_glUniformMatrix2fv)(location, count, transpose, value);
 }
 
-void glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+void glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
 {
-	return (*_glVertexAttrib3f)(indx, x, y, z);
+	(*_glUniformMatrix3fv)(location, count, transpose, value);
 }
 
+void glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+	(*_glUniformMatrix4fv)(location, count, transpose, value);
+}
 
-void glVertexAttrib1f (GLuint indx, GLfloat x)
+void glUseProgram (GLuint program)
 {
-	return (*_glVertexAttrib1f)(indx, x);
+	(*_glUseProgram)(program);
 }
 
-void glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+void glValidateProgram (GLuint program)
 {
-	return (*_glUniform4f)(location, x, y, z, w);
+	(*_glValidateProgram)(program);
 }
 
-void glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z)
+void glVertexAttrib1f (GLuint indx, GLfloat x)
 {
-	return (*_glUniform3f)(location, x, y, z);
+	(*_glVertexAttrib1f)(indx, x);
 }
 
-void glUniform2f (GLint location, GLfloat x, GLfloat y)
+void glVertexAttrib1fv (GLuint indx, const GLfloat* values)
 {
-	return (*_glUniform2f)(location, x, y);
+	(*_glVertexAttrib1fv)(indx, values);
 }
 
-void glUniform1f (GLint location, GLfloat x)
+void glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y)
 {
-	return (*_glUniform1f)(location, x);
+	(*_glVertexAttrib2f)(indx, x, y);
 }
 
-void glTexParameterf (GLenum target, GLenum pname, GLfloat param)
+void glVertexAttrib2fv (GLuint indx, const GLfloat* values)
 {
-	return (*_glTexParameterf)(target, pname, param);
+	(*_glVertexAttrib2fv)(indx, values);
 }
 
-void glSampleCoverage (GLclampf value, GLboolean invert)
+void glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z)
 {
-	return (*_glSampleCoverage)(value, invert);
+	(*_glVertexAttrib3f)(indx, x, y, z);
 }
-void glPolygonOffset (GLfloat factor, GLfloat units)
+
+void glVertexAttrib3fv (GLuint indx, const GLfloat* values)
 {
-	return (*_glPolygonOffset)(factor, units);
+	(*_glVertexAttrib3fv)(indx, values);
 }
-void glDepthRangef (GLclampf zNear, GLclampf zFar)
+
+void glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
 {
-	return (*_glDepthRangef)(zNear, zFar);
+	(*_glVertexAttrib4f)(indx, x, y, z, w);
 }
 
+void glVertexAttrib4fv (GLuint indx, const GLfloat* values)
+{
+	(*_glVertexAttrib4fv)(indx, values);
+}
 
-void glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+void glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
 {
-	return (*_glClearColor)(red, green, blue, alpha);
+	(*_glVertexAttribPointer)(indx, size, type, normalized, stride, ptr);
 }
 
-void glClearDepthf (GLclampf depth)
+void glViewport (GLint x, GLint y, GLsizei width, GLsizei height)
 {
-	return (*_glClearDepthf)(depth);
+	(*_glViewport)(x, y, width, height);
 }
-void glLineWidth (GLfloat width)
+
+void glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
 {
-	return (*_glLineWidth)(width);
+	(*_glEGLImageTargetTexture2DOES)(target, image);
 }
 
 
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/hardware/hardware.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/hardware/hardware.c
@@ -18,6 +18,7 @@
 #include <android-config.h>
 #include <dlfcn.h>
 #include <stddef.h>
+#include <errno.h>
 #include <hardware/hardware.h>
 #include <hybris/common/binding.h>
 
@@ -27,15 +28,20 @@ static int (*_hw_get_module)(const char
 
 static int (*_hw_get_module_by_class)(const char *class_id, const char *inst, const struct hw_module_t **module) = NULL;
 
-#define HARDWARE_DLSYM(fptr, sym) do { if (_libhardware == NULL) { _init_lib_hardware(); }; if (*(fptr) == NULL) { *(fptr) = (void *) android_dlsym(_libhardware, sym); } } while (0) 
+#define HARDWARE_DLSYM(fptr, sym) do { if (*(fptr) == NULL) { *(fptr) = (void *) android_dlsym(_libhardware, sym); } } while (0)
 
-static void _init_lib_hardware()
+static void *_init_lib_hardware()
 {
-	_libhardware = (void *) android_dlopen("libhardware.so", RTLD_LAZY);
+	if (!_libhardware)
+		_libhardware = (void *) android_dlopen("libhardware.so", RTLD_LAZY);
+	return _libhardware;
 }
 
 int hw_get_module(const char *id, const struct hw_module_t **module)
 {
+	if (!_init_lib_hardware())
+		return -EINVAL;
+
 	HARDWARE_DLSYM(&_hw_get_module, "hw_get_module");
 	return (*_hw_get_module)(id, module);
 }
@@ -43,6 +49,9 @@ int hw_get_module(const char *id, const
 int hw_get_module_by_class(const char *class_id, const char *inst,
                            const struct hw_module_t **module)
 {
+	if (!_init_lib_hardware())
+		return -EINVAL;
+
 	HARDWARE_DLSYM(&_hw_get_module_by_class, "hw_get_module_by_class");
 	return (*_hw_get_module_by_class)(class_id, inst, module);
 }
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/Makefile.am
@@ -65,6 +65,20 @@ propertiesincludedir = $(includedir)/hyb
 propertiesinclude_HEADERS = \
 	hybris/properties/properties.h
 
+mediaincludedir = $(includedir)/hybris/media
+mediainclude_HEADERS = \
+	hybris/media/media_compatibility_layer.h \
+	hybris/media/media_codec_layer.h \
+	hybris/media/media_codec_list.h \
+	hybris/media/media_format_layer.h \
+	hybris/media/media_recorder_layer.h \
+	hybris/media/surface_texture_client_hybris.h \
+	hybris/media/recorder_compatibility_layer.h \
+	hybris/media/media_codec_source_layer.h \
+	hybris/media/media_message_layer.h \
+	hybris/media/media_buffer_layer.h \
+	hybris/media/media_meta_data_layer.h
+
 dlfcnincludedir = $(includedir)/hybris/dlfcn
 dlfcninclude_HEADERS = \
 	hybris/dlfcn/dlfcn.h
@@ -73,4 +87,5 @@ commonincludedir = $(includedir)/hybris/
 commoninclude_HEADERS = \
 	hybris/common/binding.h \
 	hybris/common/floating_point_abi.h \
-	hybris/common/dlfcn.h
+	hybris/common/dlfcn.h \
+	hybris/common/hooks.h
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/camera/camera_compatibility_layer.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/camera/camera_compatibility_layer.h
@@ -37,6 +37,12 @@ extern "C" {
         FRONT_FACING_CAMERA_TYPE
     } CameraType;
 
+    typedef enum
+    {
+        PREVIEW_CALLBACK_DISABLED,
+        PREVIEW_CALLBACK_ENABLED
+    } PreviewCallbackMode;
+
     struct CameraControl;
 
     typedef void (*on_msg_error)(void* context);
@@ -47,6 +53,7 @@ extern "C" {
     typedef void (*on_data_raw_image)(void* data, uint32_t data_size, void* context);
     typedef void (*on_data_compressed_image)(void* data, uint32_t data_size, void* context);
     typedef void (*on_preview_texture_needs_update)(void* context);
+    typedef void (*on_preview_frame)(void* data, uint32_t data_size, void* context);
 
     struct CameraControlListener
     {
@@ -73,10 +80,14 @@ extern "C" {
         on_preview_texture_needs_update on_preview_texture_needs_update_cb;
 
         void* context;
+
+        // Called when there is a new preview frame
+        on_preview_frame on_preview_frame_cb;
     };
 
     // Initializes a connection to the camera, returns NULL on error.
     struct CameraControl* android_camera_connect_to(CameraType camera_type, struct CameraControlListener* listener);
+    struct CameraControl* android_camera_connect_by_id(int32_t camera_id, struct CameraControlListener* listener);
 
     // Disconnects the camera and deletes the pointer
     void android_camera_disconnect(struct CameraControl* control);
@@ -135,6 +146,9 @@ extern "C" {
     // completed. Ideally, this is done from the raw data callback.
     void android_camera_take_snapshot(struct CameraControl* control);
 
+    // Enable or disable the preview callback for clients that want software frames
+    int android_camera_set_preview_callback_mode(struct CameraControl* control, PreviewCallbackMode mode);
+
 #ifdef __cplusplus
 }
 #endif
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/camera/camera_compatibility_layer_capabilities.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/camera/camera_compatibility_layer_capabilities.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Canonical Ltd
+ * Copyright (C) 2013-2014 Canonical Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -30,7 +30,8 @@ extern "C" {
         FLASH_MODE_OFF,
         FLASH_MODE_AUTO,
         FLASH_MODE_ON,
-        FLASH_MODE_TORCH
+        FLASH_MODE_TORCH,
+        FLASH_MODE_RED_EYE
     } FlashMode;
 
     typedef enum
@@ -48,7 +49,8 @@ extern "C" {
         SCENE_MODE_ACTION,
         SCENE_MODE_NIGHT,
         SCENE_MODE_PARTY,
-        SCENE_MODE_SUNSET
+        SCENE_MODE_SUNSET,
+        SCENE_MODE_HDR
     } SceneMode;
 
     typedef enum
@@ -92,28 +94,36 @@ extern "C" {
         int bottom;
         int right;
         int weight;
-    } FocusRegion;
+    } FocusRegion, MeteringRegion;
 
     typedef void (*size_callback)(void* ctx, int width, int height);
+    typedef void (*scene_mode_callback)(void* ctx, SceneMode mode);
+    typedef void (*flash_mode_callback)(void* ctx, FlashMode mode);
 
     // Dumps the camera parameters to stdout.
     void android_camera_dump_parameters(struct CameraControl* control);
 
     // Query camera parameters
     int android_camera_get_number_of_devices();
+    int android_camera_get_device_info(int32_t camera_id, int* facing, int* orientation);
     void android_camera_enumerate_supported_preview_sizes(struct CameraControl* control, size_callback cb, void* ctx);
     void android_camera_get_preview_fps_range(struct CameraControl* control, int* min, int* max);
     void android_camera_get_preview_fps(struct CameraControl* control, int* fps);
     void android_camera_enumerate_supported_picture_sizes(struct CameraControl* control, size_callback cb, void* ctx);
+    void android_camera_enumerate_supported_thumbnail_sizes(struct CameraControl* control, size_callback cb, void* ctx);
     void android_camera_get_preview_size(struct CameraControl* control, int* width, int* height);
     void android_camera_get_picture_size(struct CameraControl* control, int* width, int* height);
+    void android_camera_get_thumbnail_size(struct CameraControl* control, int* width, int* height);
+    void android_camera_get_jpeg_quality(struct CameraControl* control, int* quality);
 
     void android_camera_get_current_zoom(struct CameraControl* control, int* zoom);
     void android_camera_get_max_zoom(struct CameraControl* control, int* max_zoom);
 
     void android_camera_get_effect_mode(struct CameraControl* control, EffectMode* mode);
     void android_camera_get_flash_mode(struct CameraControl* control, FlashMode* mode);
+    void android_camera_enumerate_supported_flash_modes(struct CameraControl* control, flash_mode_callback cb, void* ctx);
     void android_camera_get_white_balance_mode(struct CameraControl* control, WhiteBalanceMode* mode);
+    void android_camera_enumerate_supported_scene_modes(struct CameraControl* control, scene_mode_callback cb, void* ctx);
     void android_camera_get_scene_mode(struct CameraControl* control, SceneMode* mode);
     void android_camera_get_auto_focus_mode(struct CameraControl* control, AutoFocusMode* mode);
     void android_camera_get_preview_format(struct CameraControl* control, CameraPixelFormat* format);
@@ -122,18 +132,24 @@ extern "C" {
     void android_camera_set_preview_size(struct CameraControl* control, int width, int height);
     void android_camera_set_preview_fps(struct CameraControl* control, int fps);
     void android_camera_set_picture_size(struct CameraControl* control, int width, int height);
+    void android_camera_set_thumbnail_size(struct CameraControl* control, int width, int height);
     void android_camera_set_effect_mode(struct CameraControl* control, EffectMode mode);
     void android_camera_set_flash_mode(struct CameraControl* control, FlashMode mode);
     void android_camera_set_white_balance_mode(struct CameraControl* control, WhiteBalanceMode mode);
     void android_camera_set_scene_mode(struct CameraControl* control, SceneMode mode);
     void android_camera_set_auto_focus_mode(struct CameraControl* control, AutoFocusMode mode);
     void android_camera_set_preview_format(struct CameraControl* control, CameraPixelFormat format);
+    void android_camera_set_jpeg_quality(struct CameraControl* control, int quality);
 
     void android_camera_set_focus_region(struct CameraControl* control, FocusRegion* region);
     void android_camera_reset_focus_region(struct CameraControl* control);
 
+    void android_camera_set_metering_region(struct CameraControl* control, MeteringRegion* region);
+    void android_camera_reset_metering_region(struct CameraControl* control);
+
     // Set photo metadata
     void android_camera_set_rotation(struct CameraControl* control, int rotation);
+    void android_camera_set_location(struct CameraControl* control, const float* latitude, const float* longitude, const float* altitude, int timestamp, const char* method);
 
     // Video support
     void android_camera_enumerate_supported_video_sizes(struct CameraControl* control, size_callback cb, void* ctx);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/camera/camera_compatibility_layer_configuration_translator.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/camera/camera_compatibility_layer_configuration_translator.h
@@ -96,6 +96,7 @@ extern "C" {
         m.add(android::String8(android::CameraParameters::FLASH_MODE_AUTO), FLASH_MODE_AUTO);
         m.add(android::String8(android::CameraParameters::FLASH_MODE_ON), FLASH_MODE_ON);
         m.add(android::String8(android::CameraParameters::FLASH_MODE_TORCH), FLASH_MODE_TORCH);
+        m.add(android::String8(android::CameraParameters::FLASH_MODE_RED_EYE), FLASH_MODE_RED_EYE);
 
         return m;
     }
@@ -108,22 +109,24 @@ extern "C" {
         android::CameraParameters::SCENE_MODE_ACTION,
         android::CameraParameters::SCENE_MODE_NIGHT,
         android::CameraParameters::SCENE_MODE_PARTY,
-        android::CameraParameters::SCENE_MODE_SUNSET
+        android::CameraParameters::SCENE_MODE_SUNSET,
+        android::CameraParameters::SCENE_MODE_HDR
     };
 
-    static android::KeyedVector<android::String8, SceneMode> init_scene_modes_lut()
+    static android::DefaultKeyedVector<android::String8, SceneMode> init_scene_modes_lut()
     {
-        android::KeyedVector<android::String8, SceneMode> m;
+        android::DefaultKeyedVector<android::String8, SceneMode> m(SCENE_MODE_AUTO);
         m.add(android::String8(android::CameraParameters::SCENE_MODE_AUTO), SCENE_MODE_AUTO);
         m.add(android::String8(android::CameraParameters::SCENE_MODE_ACTION), SCENE_MODE_ACTION);
         m.add(android::String8(android::CameraParameters::SCENE_MODE_NIGHT), SCENE_MODE_NIGHT);
         m.add(android::String8(android::CameraParameters::SCENE_MODE_PARTY), SCENE_MODE_PARTY);
         m.add(android::String8(android::CameraParameters::SCENE_MODE_SUNSET), SCENE_MODE_SUNSET);
+        m.add(android::String8(android::CameraParameters::SCENE_MODE_HDR), SCENE_MODE_HDR);
 
         return m;
     }
 
-    static android::KeyedVector<android::String8, SceneMode> scene_modes_lut = init_scene_modes_lut();
+    static android::DefaultKeyedVector<android::String8, SceneMode> scene_modes_lut = init_scene_modes_lut();
 
     static const char* auto_focus_modes[] =
     {
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/common/binding.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/common/binding.h
@@ -32,7 +32,6 @@ const char *android_dlerror(void);
 int android_dladdr(const void *addr, void *info);
 
 
-
 /**
  *         XXX AUTO-GENERATED FILE XXX
  *
@@ -41,7 +40,7 @@ int android_dladdr(const void *addr, voi
  * an updated version of this header file:
  *
  *    python utils/generate_wrapper_macros.py > \
- *       hybris/include/hybris/common/binding.h
+ *       hybris/include/hybris/internal/binding.h
  *
  * If you need macros with more arguments, just customize the
  * MAX_ARGS variable in generate_wrapper_macros.py.
@@ -65,6 +64,12 @@ int android_dladdr(const void *addr, voi
         name##_handle = android_dlopen(path, RTLD_LAZY); \
     }
 
+#define HYBRIS_LIRBARY_CHECK_SYMBOL(name) \
+    bool hybris_##name##_check_for_symbol(const char *sym) \
+    { \
+        return android_dlsym(name##_handle, sym) != NULL; \
+    }
+
 
 
 #define HYBRIS_IMPLEMENT_FUNCTION0(name, return_type, symbol) \
@@ -435,7 +440,7 @@ int android_dladdr(const void *addr, voi
  * an updated version of this header file:
  *
  *    python utils/generate_wrapper_macros.py > \
- *       hybris/include/hybris/common/binding.h
+ *       hybris/include/hybris/internal/binding.h
  *
  * If you need macros with more arguments, just customize the
  * MAX_ARGS variable in generate_wrapper_macros.py.
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/common/dlfcn.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/common/dlfcn.h
@@ -25,7 +25,7 @@ extern "C" {
 void *hybris_dlopen(const char *filename, int flag);
 void *hybris_dlsym(void *handle, const char *symbol);
 int   hybris_dlclose(void *handle);
-char *hybris_dlerror(void);
+const char *hybris_dlerror(void);
 
 #ifdef __cplusplus
 }
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/common/hooks.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ */
+
+#ifndef _HYBRIS_HOOKS_H_
+#define _HYBRIS_HOOKS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void* (*hybris_hook_cb)(const char *symbol_name, const char *requester);
+
+void hybris_set_hook_callback(hybris_hook_cb callback);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/input/input_stack_compatibility_layer.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/input/input_stack_compatibility_layer.h
@@ -109,6 +109,7 @@ extern "C" {
         int input_area_height;
     };
 
+    int android_input_check_availability();
     void android_input_stack_initialize(
         struct AndroidEventListener* listener,
         struct InputStackConfiguration* input_stack_configuration);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/internal/camera_control.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/internal/camera_control.h
@@ -19,7 +19,11 @@
 
 #include <camera/Camera.h>
 #include <camera/CameraParameters.h>
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
 #include <gui/SurfaceTexture.h>
+#else
+#include <gui/GLConsumer.h>
+#endif
 
 #include <stdint.h>
 #include <unistd.h>
@@ -31,16 +35,27 @@ extern "C" {
 struct CameraControlListener;
 
 struct CameraControl : public android::CameraListener,
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
     public android::SurfaceTexture::FrameAvailableListener
+#else
+    public android::GLConsumer::FrameAvailableListener
+#endif
 {
     android::Mutex guard;
     CameraControlListener* listener;
     android::sp<android::Camera> camera;
     android::CameraParameters camera_parameters;
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
     android::sp<android::SurfaceTexture> preview_texture;
-
-    // From android::SurfaceTexture::FrameAvailableListener
+#else
+    android::sp<android::GLConsumer> preview_texture;
+#endif
+    // From android::SurfaceTexture/GLConsumer::FrameAvailableListener
+#if ANDROID_VERSION_MAJOR==5 && ANDROID_VERSION_MINOR>=1 || ANDROID_VERSION_MAJOR>=6
+    void onFrameAvailable(const android::BufferItem& item);
+#else
     void onFrameAvailable();
+#endif
 
     // From android::CameraListener
     void notify(int32_t msg_type, int32_t ext1, int32_t ext2);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/internal/surface_flinger_compatibility_layer_internal.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/internal/surface_flinger_compatibility_layer_internal.h
@@ -25,6 +25,7 @@
 
 #include <utils/misc.h>
 
+#include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <ui/PixelFormat.h>
 #include <ui/Region.h>
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/decoding_service.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef DECODING_SERVICE_H_
+#define DECODING_SERVICE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <unistd.h>
+
+// TODO: This file is empty for now but will have the decoding_service_* functions
+// from media_codec_layer.cpp after it's figured out why these functions crash when located
+// in decoding_service.cpp
+
+//void decoding_service_init();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_buffer_layer.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Simon Fels <simon.fels@canonical.com>
+ */
+
+#ifndef MEDIA_BUFFER_LAYER_H_
+#define MEDIA_BUFFER_LAYER_H_
+
+#include <stdint.h>
+#include <memory.h>
+
+#include <hybris/media/media_message_layer.h>
+#include <hybris/media/media_meta_data_layer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void MediaBufferWrapper;
+typedef void (*MediaBufferReturnCallback)(MediaBufferWrapper *buffer, void *user_data);
+
+MediaBufferWrapper* media_buffer_create(size_t size);
+void media_buffer_destroy(MediaBufferWrapper *buffer);
+void media_buffer_release(MediaBufferWrapper *buffer);
+void media_buffer_ref(MediaBufferWrapper *buffer);
+
+int media_buffer_get_refcount(MediaBufferWrapper *buffer);
+
+void* media_buffer_get_data(MediaBufferWrapper *buffer);
+size_t media_buffer_get_size(MediaBufferWrapper *buffer);
+size_t media_buffer_get_range_offset(MediaBufferWrapper *buffer);
+size_t media_buffer_get_range_length(MediaBufferWrapper *buffer);
+MediaMetaDataWrapper* media_buffer_get_meta_data(MediaBufferWrapper *buffer);
+
+void media_buffer_set_return_callback(MediaBufferWrapper *buffer,
+    MediaBufferReturnCallback callback, void *user_data);
+
+typedef void MediaABufferWrapper;
+
+MediaABufferWrapper* media_abuffer_create(size_t capacity);
+MediaABufferWrapper* media_abuffer_create_with_data(uint8_t *data, size_t size);
+
+void media_abuffer_set_range(MediaABufferWrapper *buffer, size_t offset, size_t size);
+void media_abuffer_set_media_buffer_base(MediaABufferWrapper *buffer, MediaBufferWrapper *mbuf);
+MediaBufferWrapper* media_abuffer_get_media_buffer_base(MediaABufferWrapper *buffer);
+
+void* media_abuffer_get_data(MediaABufferWrapper *buffer);
+size_t media_abuffer_get_size(MediaABufferWrapper *buffer);
+size_t media_abuffer_get_range_offset(MediaABufferWrapper *buffer);
+size_t media_abuffer_get_capacity(MediaABufferWrapper *buffer);
+MediaMessageWrapper* media_abuffer_get_meta(MediaABufferWrapper *buffer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_codec_layer.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_CODEC_LAYER_H_
+#define MEDIA_CODEC_LAYER_H_
+
+#include <stdint.h>
+#include <unistd.h>
+
+#ifdef SIMPLE_PLAYER
+#include <media/stagefright/MediaCodec.h>
+#endif
+
+#include <hybris/media/media_message_layer.h>
+#include <hybris/media/media_buffer_layer.h>
+#include <hybris/media/media_format_layer.h>
+#include <hybris/media/surface_texture_client_hybris.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    typedef void* MediaCodecDelegate;
+    typedef void* DSSessionWrapperHybris;
+
+    typedef void (*on_texture_needs_update)(void *context);
+    void media_codec_set_texture_needs_update_cb(MediaCodecDelegate delegate, on_texture_needs_update cb, void *context);
+
+    // DecodingService API
+    void decoding_service_init();
+
+    IGBCWrapperHybris decoding_service_get_igraphicbufferconsumer();
+    IGBPWrapperHybris decoding_service_get_igraphicbufferproducer();
+    DSSessionWrapperHybris decoding_service_create_session(uint32_t handle);
+    void decoding_service_set_client_death_cb(DecodingClientDeathCbHybris cb, uint32_t handle, void *context);
+
+    MediaCodecDelegate media_codec_create_by_codec_name(const char *name);
+    MediaCodecDelegate media_codec_create_by_codec_type(const char *type);
+
+#ifdef SIMPLE_PLAYER
+    android::MediaCodec* media_codec_get(MediaCodecDelegate delegate);
+#endif
+
+    void media_codec_delegate_destroy(MediaCodecDelegate delegate);
+    void media_codec_delegate_ref(MediaCodecDelegate delegate);
+    void media_codec_delegate_unref(MediaCodecDelegate delegate);
+
+#ifdef SIMPLE_PLAYER
+    int media_codec_configure(MediaCodecDelegate delegate, MediaFormat format, void *nativeWindow, uint32_t flags);
+#else
+    int media_codec_configure(MediaCodecDelegate delegate, MediaFormat format, SurfaceTextureClientHybris stc, uint32_t flags);
+#endif
+    int media_codec_set_surface_texture_client(MediaCodecDelegate delegate, SurfaceTextureClientHybris stc);
+
+    int media_codec_queue_csd(MediaCodecDelegate delegate, MediaFormat format);
+    int media_codec_start(MediaCodecDelegate delegate);
+    int media_codec_stop(MediaCodecDelegate delegate);
+    int media_codec_release(MediaCodecDelegate delegate);
+    int media_codec_flush(MediaCodecDelegate delegate);
+
+    size_t media_codec_get_input_buffers_size(MediaCodecDelegate delegate);
+    uint8_t *media_codec_get_nth_input_buffer(MediaCodecDelegate delegate, size_t n);
+    MediaABufferWrapper* media_codec_get_nth_input_buffer_as_abuffer(MediaCodecDelegate delegate, size_t n);
+
+    size_t media_codec_get_nth_input_buffer_capacity(MediaCodecDelegate delegate, size_t n);
+    size_t media_codec_get_output_buffers_size(MediaCodecDelegate delegate);
+    uint8_t *media_codec_get_nth_output_buffer(MediaCodecDelegate delegate, size_t n);
+    size_t media_codec_get_nth_output_buffer_capacity(MediaCodecDelegate delegate, size_t n);
+
+    struct _MediaCodecBufferInfo
+    {
+        size_t index;
+        size_t offset;
+        size_t size;
+        int64_t presentation_time_us;
+        uint32_t flags;
+        uint8_t render_retries;
+    };
+    typedef struct _MediaCodecBufferInfo MediaCodecBufferInfo;
+
+    int media_codec_dequeue_output_buffer(MediaCodecDelegate delegate, MediaCodecBufferInfo *info, int64_t timeout_us);
+    int media_codec_queue_input_buffer(MediaCodecDelegate delegate, const MediaCodecBufferInfo *info);
+    int media_codec_dequeue_input_buffer(MediaCodecDelegate delegate, size_t *index, int64_t timeout_us);
+    int media_codec_release_output_buffer(MediaCodecDelegate delegate, size_t index, uint8_t render);
+
+    MediaFormat media_codec_get_output_format(MediaCodecDelegate delegate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MEDIA_CODEC_LAYER_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_codec_list.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_CODEC_LIST_PRIV_H_
+#define MEDIA_CODEC_LIST_PRIV_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    ssize_t media_codec_list_find_codec_by_type(const char *type, bool encoder, size_t startIndex);
+    ssize_t media_codec_list_find_codec_by_name(const char *name);
+    size_t media_codec_list_count_codecs();
+    void media_codec_list_get_codec_info_at_id(size_t index);
+    const char *media_codec_list_get_codec_name(size_t index);
+    bool media_codec_list_is_encoder(size_t index);
+    size_t media_codec_list_get_num_supported_types(size_t index);
+    size_t media_codec_list_get_nth_supported_type_len(size_t index, size_t n);
+    int media_codec_list_get_nth_supported_type(size_t index, char *type, size_t n);
+
+    struct _profile_level
+    {
+        uint32_t profile;
+        uint32_t level;
+    };
+    typedef struct _profile_level profile_level;
+
+    size_t media_codec_list_get_num_profile_levels(size_t index, const char*);
+    size_t media_codec_list_get_num_color_formats(size_t index, const char*);
+    int media_codec_list_get_nth_codec_profile_level(size_t index, const char *type, profile_level *pro_level, size_t n);
+    int media_codec_list_get_codec_color_formats(size_t index, const char *type, uint32_t *color_formats);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MEDIA_CODEC_LIST_PRIV_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_codec_source_layer.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Simon Fels <simon.fels@canonical.com>
+ */
+
+#ifndef MEDIA_CODEC_SOURCE_LAYER_H_
+#define MEDIA_CODEC_SOURCE_LAYER_H_
+
+#include <stdint.h>
+
+#include <hybris/media/media_format_layer.h>
+#include <hybris/media/media_message_layer.h>
+#include <hybris/media/media_buffer_layer.h>
+#include <hybris/media/media_meta_data_layer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void MediaSourceWrapper;
+
+typedef int (*MediaSourceStartCallback)(MediaMetaDataWrapper *meta, void *user_data);
+typedef int (*MediaSourceStopCallback)(void *user_data);
+typedef int (*MediaSourceReadCallback)(MediaBufferWrapper **buffer, void *user_data);
+typedef int (*MediaSourcePauseCallback)(void *user_data);
+
+MediaSourceWrapper* media_source_create(void);
+void media_source_release(MediaSourceWrapper *source);
+void media_source_set_format(MediaSourceWrapper *source, MediaMetaDataWrapper *meta);
+void media_source_set_start_callback(MediaSourceWrapper *source, MediaSourceStartCallback callback, void *user_data);
+void media_source_set_stop_callback(MediaSourceWrapper *source, MediaSourceStopCallback callback, void *user_data);
+void media_source_set_read_callback(MediaSourceWrapper *source, MediaSourceReadCallback callback, void *user_data);
+void media_source_set_pause_callback(MediaSourceWrapper *source, MediaSourcePauseCallback callback, void *user_data);
+
+enum MediaCodecSourceFlags
+{
+    MEDIA_CODEC_SOURCE_FLAG_USE_SURFACE_INPUT = 1,
+    MEDIA_CODEC_SOURCE_FLAG_USE_METADATA_INPUT = 2,
+};
+
+typedef void MediaCodecSourceWrapper;
+typedef void MediaNativeWindowHandle;
+
+MediaCodecSourceWrapper* media_codec_source_create(MediaMessageWrapper *format, MediaSourceWrapper *source, int flags);
+void media_codec_source_release(MediaCodecSourceWrapper *source);
+
+MediaNativeWindowHandle* media_codec_source_get_native_window_handle(MediaCodecSourceWrapper *source);
+
+// Returned instance is owned by the caller and must be freed
+MediaMetaDataWrapper* media_codec_source_get_format(MediaCodecSourceWrapper *source);
+
+bool media_codec_source_start(MediaCodecSourceWrapper *source);
+bool media_codec_source_stop(MediaCodecSourceWrapper *source);
+bool media_codec_source_pause(MediaCodecSourceWrapper *source);
+
+bool media_codec_source_read(MediaCodecSourceWrapper *source, MediaBufferWrapper **buffer);
+
+bool media_codec_source_request_idr_frame(MediaBufferWrapper *source);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_compatibility_layer.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_COMPATIBILITY_LAYER_H_
+#define MEDIA_COMPATIBILITY_LAYER_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include <GLES2/gl2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    // Common compat calls
+    int media_compat_check_availability();
+
+    unsigned int hybris_media_get_version();
+
+    // Callback types
+    typedef void (*on_msg_set_video_size)(int height, int width, void *context);
+    typedef void (*on_video_texture_needs_update)(void *context);
+    typedef void (*on_msg_error)(void *context);
+    typedef void (*on_playback_complete)(void *context);
+    typedef void (*on_media_prepared)(void *context);
+
+    struct MediaPlayerWrapper;
+
+    // ----- Start of C API ----- //
+
+    // Callback setters
+    void android_media_set_video_size_cb(struct MediaPlayerWrapper *mp, on_msg_set_video_size cb, void *context);
+    void android_media_set_video_texture_needs_update_cb(struct MediaPlayerWrapper *mp, on_video_texture_needs_update cb, void *context);
+    void android_media_set_error_cb(struct MediaPlayerWrapper *mp, on_msg_error cb, void *context);
+    void android_media_set_playback_complete_cb(struct MediaPlayerWrapper *mp, on_playback_complete cb, void *context);
+    void android_media_set_media_prepared_cb(struct MediaPlayerWrapper *mp, on_media_prepared cb, void *context);
+
+    // Main player control API
+    struct MediaPlayerWrapper *android_media_new_player();
+    int android_media_set_data_source(struct MediaPlayerWrapper *mp, const char* url);
+    int android_media_set_preview_texture(struct MediaPlayerWrapper *mp, int texture_id);
+    void android_media_update_surface_texture(struct MediaPlayerWrapper *mp);
+    void android_media_surface_texture_get_transformation_matrix(struct MediaPlayerWrapper *mp, GLfloat*matrix);
+    int android_media_play(struct MediaPlayerWrapper *mp);
+    int android_media_pause(struct MediaPlayerWrapper *mp);
+    int android_media_stop(struct MediaPlayerWrapper *mp);
+    bool android_media_is_playing(struct MediaPlayerWrapper *mp);
+
+    int android_media_seek_to(struct MediaPlayerWrapper *mp, int msec);
+    int android_media_get_current_position(struct MediaPlayerWrapper *mp, int *msec);
+    int android_media_get_duration(struct MediaPlayerWrapper *mp, int *msec);
+
+    int android_media_get_volume(struct MediaPlayerWrapper *mp, int *volume);
+    int android_media_set_volume(struct MediaPlayerWrapper *mp, int volume);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MEDIA_COMPATIBILITY_LAYER_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_format_layer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_FORMAT_LAYER_H_
+#define MEDIA_FORMAT_LAYER_H_
+
+#include <stddef.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    typedef void* MediaFormat;
+
+    MediaFormat media_format_create_video_format(const char *mime, int32_t width, int32_t height, int64_t duration_us, int32_t max_input_size);
+
+    void media_format_destroy(MediaFormat format);
+    void media_format_ref(MediaFormat format);
+    void media_format_unref(MediaFormat format);
+
+    void media_format_set_byte_buffer(MediaFormat format, const char *key, uint8_t *data, size_t size);
+
+    const char* media_format_get_mime(MediaFormat format);
+    int64_t media_format_get_duration_us(MediaFormat format);
+    int32_t media_format_get_width(MediaFormat format);
+    int32_t media_format_get_height(MediaFormat format);
+    int32_t media_format_get_max_input_size(MediaFormat format);
+    int32_t media_format_get_stride(MediaFormat format);
+    int32_t media_format_get_slice_height(MediaFormat format);
+    int32_t media_format_get_color_format(MediaFormat format);
+    int32_t media_format_get_crop_left(MediaFormat format);
+    int32_t media_format_get_crop_right(MediaFormat format);
+    int32_t media_format_get_crop_top(MediaFormat format);
+    int32_t media_format_get_crop_bottom(MediaFormat format);
+
+    // TODO: Add getter for CSD buffer
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MEDIA_FORMAT_LAYER_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_message_layer.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Simon Fels <simon.fels@canonical.com>
+ */
+
+#ifndef MEDIA_MESSAGE_LAYER_H_
+#define MEDIA_MESSAGE_LAYER_H_
+
+#include <sys/types.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <memory.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void MediaMessageWrapper;
+
+MediaMessageWrapper* media_message_create();
+void media_message_release(MediaMessageWrapper *msg);
+
+void media_message_clear(MediaMessageWrapper *msg);
+const char* media_message_dump(MediaMessageWrapper *msg);
+
+void media_message_set_int32(MediaMessageWrapper *msg, const char *name, int32_t value);
+void media_message_set_int64(MediaMessageWrapper *msg, const char *name, int64_t value);
+void media_message_set_size(MediaMessageWrapper *msg, const char *name, size_t value);
+void media_message_set_float(MediaMessageWrapper *msg, const char *name, float value);
+void media_message_set_double(MediaMessageWrapper *msg, const char *name, double value);
+void media_message_set_string(MediaMessageWrapper *msg, const char *name, const char *value, ssize_t len);
+
+bool media_message_find_int32(MediaMessageWrapper *msg, const char *name, int32_t *value);
+bool media_message_find_int64(MediaMessageWrapper *msg, const char *name, int64_t *value);
+bool media_message_find_size(MediaMessageWrapper *msg, const char *name, size_t *value);
+bool media_message_find_float(MediaMessageWrapper *msg, const char *name, float *value);
+bool media_message_find_double(MediaMessageWrapper *msg, const char *name, double *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_meta_data_layer.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Simon Fels <simon.fels@canonical.com>
+ */
+
+#ifndef MEDIA_META_DATA_LAYER_H_
+#define MEDIA_META_DATA_LAYER_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void MediaMetaDataWrapper;
+
+enum {
+    MEDIA_META_DATA_KEY_TIME = 1,
+    MEDIA_META_DATA_KEY_IS_CODEC_CONFIG = 2,
+    MEDIA_META_DATA_KEY_MIME = 3,
+    MEDIA_META_DATA_KEY_NUM_BUFFERS = 4,
+    MEDIA_META_DATA_KEY_WIDTH = 5,
+    MEDIA_META_DATA_KEY_HEIGHT = 6,
+    MEDIA_META_DATA_KEY_STRIDE = 7,
+    MEDIA_META_DATA_KEY_COLOR_FORMAT = 8,
+    MEDIA_META_DATA_KEY_SLICE_HEIGHT = 9,
+    MEDIA_META_DATA_KEY_FRAMERATE = 10,
+    MEDIA_META_DATA_KEY_MEDIA_BUFFER = 11
+};
+
+uint32_t media_meta_data_get_key_id(int key);
+
+MediaMetaDataWrapper* media_meta_data_create();
+void media_meta_data_release(MediaMetaDataWrapper *meta_data);
+
+void media_meta_data_clear(MediaMetaDataWrapper *meta_data);
+bool media_meta_data_remove(MediaMetaDataWrapper *meta_data, uint32_t key);
+
+bool media_meta_data_set_cstring(MediaMetaDataWrapper *meta_data, uint32_t key, const char *value);
+bool media_meta_data_set_int32(MediaMetaDataWrapper *meta_data, uint32_t key, int32_t value);
+bool media_meta_data_set_int64(MediaMetaDataWrapper *meta_data, uint32_t key, int64_t value);
+bool media_meta_data_set_float(MediaMetaDataWrapper *meta_data, uint32_t key, float value);
+bool media_meta_data_set_pointer(MediaMetaDataWrapper *meta_data, uint32_t key, void *value);
+
+bool media_meta_data_find_cstring(MediaMetaDataWrapper *meta_data, uint32_t key, const char **value);
+bool media_meta_data_find_int32(MediaMetaDataWrapper *meta_data, uint32_t key, int32_t *value);
+bool media_meta_data_find_int64(MediaMetaDataWrapper *meta_data, uint32_t key, int64_t *value);
+bool media_meta_data_find_float(MediaMetaDataWrapper *meta_data, uint32_t key, float *value);
+bool media_meta_data_find_double(MediaMetaDataWrapper *meta_data, uint32_t key, double *value);
+bool media_meta_data_find_pointer(MediaMetaDataWrapper *meta_data, uint32_t key, void **value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_recorder_layer.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2013-2014 Canonical Ltd
+ *
+ * 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.
+ */
+
+#ifndef MEDIA_RECORDER_LAYER_H_
+#define MEDIA_RECORDER_LAYER_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    // Media Recorder Observer API
+    struct MediaRecorderObserver;
+    struct MediaRecorderObserver *android_media_recorder_observer_new();
+
+    typedef void (*media_recording_started_cb)(bool started, void *context);
+    void android_media_recorder_observer_set_cb(struct MediaRecorderObserver *observer, media_recording_started_cb cb, void *context);
+
+    struct MediaRecorderWrapper;
+    struct CameraControl;
+
+    // Values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_VIDEO_SOURCE_DEFAULT = 0,
+        ANDROID_VIDEO_SOURCE_CAMERA = 1,
+        ANDROID_VIDEO_SOURCE_GRALLOC_BUFFER = 2
+    } VideoSource;
+
+    // Values are from andoid /system/core/include/system/audio.h
+    typedef enum
+    {
+        ANDROID_AUDIO_SOURCE_DEFAULT             = 0,
+        ANDROID_AUDIO_SOURCE_MIC                 = 1,
+        ANDROID_AUDIO_SOURCE_VOICE_UPLINK        = 2,
+        ANDROID_AUDIO_SOURCE_VOICE_DOWNLINK      = 3,
+        ANDROID_AUDIO_SOURCE_VOICE_CALL          = 4,
+        ANDROID_AUDIO_SOURCE_CAMCORDER           = 5,
+        ANDROID_AUDIO_SOURCE_VOICE_RECOGNITION   = 6,
+        ANDROID_AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
+        ANDROID_AUDIO_SOURCE_REMOTE_SUBMIX       = 8,
+        ANDROID_AUDIO_SOURCE_CNT,
+        ANDROID_AUDIO_SOURCE_MAX                 = ANDROID_AUDIO_SOURCE_CNT - 1
+    } AudioSource;
+
+    // Values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_OUTPUT_FORMAT_DEFAULT = 0,
+        ANDROID_OUTPUT_FORMAT_THREE_GPP = 1,
+        ANDROID_OUTPUT_FORMAT_MPEG_4 = 2,
+        ANDROID_OUTPUT_FORMAT_AUDIO_ONLY_START = 3,
+        /* These are audio only file formats */
+        ANDROID_OUTPUT_FORMAT_RAW_AMR = 3, // to be backward compatible
+        ANDROID_OUTPUT_FORMAT_AMR_NB = 3,
+        ANDROID_OUTPUT_FORMAT_AMR_WB = 4,
+        ANDROID_OUTPUT_FORMAT_AAC_ADIF = 5,
+        ANDROID_OUTPUT_FORMAT_AAC_ADTS = 6,
+        /* Stream over a socket, limited to a single stream */
+        ANDROID_OUTPUT_FORMAT_RTP_AVP = 7,
+        /* H.264/AAC data encapsulated in MPEG2/TS */
+        ANDROID_OUTPUT_FORMAT_MPEG2TS = 8
+    } OutputFormat;
+
+    // Values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_VIDEO_ENCODER_DEFAULT = 0,
+        ANDROID_VIDEO_ENCODER_H263 = 1,
+        ANDROID_VIDEO_ENCODER_H264 = 2,
+        ANDROID_VIDEO_ENCODER_MPEG_4_SP = 3
+    } VideoEncoder;
+
+    // Values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_AUDIO_ENCODER_DEFAULT = 0,
+        ANDROID_AUDIO_ENCODER_AMR_NB = 1,
+        ANDROID_AUDIO_ENCODER_AMR_WB = 2,
+        ANDROID_AUDIO_ENCODER_AAC = 3,
+        ANDROID_AUDIO_ENCODER_HE_AAC = 4,
+        ANDROID_AUDIO_ENCODER_AAC_ELD = 5
+    } AudioEncoder;
+
+    /* Defines how many bytes to read of the microphone at a time. This value
+       is how many bytes AudioFlinger would read max at a time from the microphone,
+       so duplicate using that value here since that code is well tested. */
+    #define MIC_READ_BUF_SIZE 960
+
+    // Callback types
+    typedef void (*on_recorder_msg_error)(void *context);
+    typedef void (*on_recorder_read_audio)(void *context);
+
+    // Callback setters
+    void android_recorder_set_error_cb(struct MediaRecorderWrapper *mr, on_recorder_msg_error cb,
+                                       void *context);
+    void android_recorder_set_audio_read_cb(struct MediaRecorderWrapper *mr, on_recorder_read_audio cb,
+                                       void *context);
+
+    // Main recorder control API
+    struct MediaRecorderWrapper *android_media_new_recorder();
+    int android_recorder_initCheck(struct MediaRecorderWrapper *mr);
+    int android_recorder_setCamera(struct MediaRecorderWrapper *mr, struct CameraControl* control);
+    int android_recorder_setVideoSource(struct MediaRecorderWrapper *mr, VideoSource vs);
+    int android_recorder_setAudioSource(struct MediaRecorderWrapper *mr, AudioSource as);
+    int android_recorder_setOutputFormat(struct MediaRecorderWrapper *mr, OutputFormat of);
+    int android_recorder_setVideoEncoder(struct MediaRecorderWrapper *mr, VideoEncoder ve);
+    int android_recorder_setAudioEncoder(struct MediaRecorderWrapper *mr, AudioEncoder ae);
+    int android_recorder_setOutputFile(struct MediaRecorderWrapper *mr, int fd);
+    int android_recorder_setVideoSize(struct MediaRecorderWrapper *mr, int width, int height);
+    int android_recorder_setVideoFrameRate(struct MediaRecorderWrapper *mr, int frames_per_second);
+    int android_recorder_setParameters(struct MediaRecorderWrapper *mr, const char* parameters);
+    int android_recorder_start(struct MediaRecorderWrapper *mr);
+    int android_recorder_stop(struct MediaRecorderWrapper *mr);
+    int android_recorder_prepare(struct MediaRecorderWrapper *mr);
+    int android_recorder_reset(struct MediaRecorderWrapper *mr);
+    int android_recorder_close(struct MediaRecorderWrapper *mr);
+    int android_recorder_release(struct MediaRecorderWrapper *mr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/recorder_compatibility_layer.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ */
+
+#ifndef RECORDER_COMPATIBILITY_LAYER_H_
+#define RECORDER_COMPATIBILITY_LAYER_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    struct MediaRecorderWrapper;
+    struct CameraControl;
+
+    // values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_VIDEO_SOURCE_DEFAULT = 0,
+        ANDROID_VIDEO_SOURCE_CAMERA = 1,
+        ANDROID_VIDEO_SOURCE_GRALLOC_BUFFER = 2
+    } VideoSource;
+
+    // values are from andoid /system/core/include/system/audio.h
+    typedef enum
+    {
+        ANDROID_AUDIO_SOURCE_DEFAULT             = 0,
+        ANDROID_AUDIO_SOURCE_MIC                 = 1,
+        ANDROID_AUDIO_SOURCE_VOICE_UPLINK        = 2,
+        ANDROID_AUDIO_SOURCE_VOICE_DOWNLINK      = 3,
+        ANDROID_AUDIO_SOURCE_VOICE_CALL          = 4,
+        ANDROID_AUDIO_SOURCE_CAMCORDER           = 5,
+        ANDROID_AUDIO_SOURCE_VOICE_RECOGNITION   = 6,
+        ANDROID_AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
+        ANDROID_AUDIO_SOURCE_REMOTE_SUBMIX       = 8,
+        ANDROID_AUDIO_SOURCE_CNT,
+        ANDROID_AUDIO_SOURCE_MAX                 = ANDROID_AUDIO_SOURCE_CNT - 1
+    } AudioSource;
+
+    // values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_OUTPUT_FORMAT_DEFAULT = 0,
+        ANDROID_OUTPUT_FORMAT_THREE_GPP = 1,
+        ANDROID_OUTPUT_FORMAT_MPEG_4 = 2,
+        ANDROID_OUTPUT_FORMAT_AUDIO_ONLY_START = 3,
+        /* These are audio only file formats */
+        ANDROID_OUTPUT_FORMAT_RAW_AMR = 3, //to be backward compatible
+        ANDROID_OUTPUT_FORMAT_AMR_NB = 3,
+        ANDROID_OUTPUT_FORMAT_AMR_WB = 4,
+        ANDROID_OUTPUT_FORMAT_AAC_ADIF = 5,
+        ANDROID_OUTPUT_FORMAT_AAC_ADTS = 6,
+        /* Stream over a socket, limited to a single stream */
+        ANDROID_OUTPUT_FORMAT_RTP_AVP = 7,
+        /* H.264/AAC data encapsulated in MPEG2/TS */
+        ANDROID_OUTPUT_FORMAT_MPEG2TS = 8
+    } OutputFormat;
+
+    // values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_VIDEO_ENCODER_DEFAULT = 0,
+        ANDROID_VIDEO_ENCODER_H263 = 1,
+        ANDROID_VIDEO_ENCODER_H264 = 2,
+        ANDROID_VIDEO_ENCODER_MPEG_4_SP = 3
+    } VideoEncoder;
+
+    // values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_AUDIO_ENCODER_DEFAULT = 0,
+        ANDROID_AUDIO_ENCODER_AMR_NB = 1,
+        ANDROID_AUDIO_ENCODER_AMR_WB = 2,
+        ANDROID_AUDIO_ENCODER_AAC = 3,
+        ANDROID_AUDIO_ENCODER_HE_AAC = 4,
+        ANDROID_AUDIO_ENCODER_AAC_ELD = 5
+    } AudioEncoder;
+
+    // Callback types
+    typedef void (*on_recorder_msg_error)(void *context);
+
+    // Callback setters
+    void android_recorder_set_error_cb(struct MediaRecorderWrapper *mr, on_recorder_msg_error cb,
+                                       void *context);
+
+    // Main recorder control API
+    struct MediaRecorderWrapper *android_media_new_recorder();
+    int android_recorder_initCheck(struct MediaRecorderWrapper *mr);
+    int android_recorder_setCamera(struct MediaRecorderWrapper *mr, struct CameraControl* control);
+    int android_recorder_setVideoSource(struct MediaRecorderWrapper *mr, VideoSource vs);
+    int android_recorder_setAudioSource(struct MediaRecorderWrapper *mr, AudioSource as);
+    int android_recorder_setOutputFormat(struct MediaRecorderWrapper *mr, OutputFormat of);
+    int android_recorder_setVideoEncoder(struct MediaRecorderWrapper *mr, VideoEncoder ve);
+    int android_recorder_setAudioEncoder(struct MediaRecorderWrapper *mr, AudioEncoder ae);
+    int android_recorder_setOutputFile(struct MediaRecorderWrapper *mr, int fd);
+    int android_recorder_setVideoSize(struct MediaRecorderWrapper *mr, int width, int height);
+    int android_recorder_setVideoFrameRate(struct MediaRecorderWrapper *mr, int frames_per_second);
+    int android_recorder_setParameters(struct MediaRecorderWrapper *mr, const char* parameters);
+    int android_recorder_start(struct MediaRecorderWrapper *mr);
+    int android_recorder_stop(struct MediaRecorderWrapper *mr);
+    int android_recorder_prepare(struct MediaRecorderWrapper *mr);
+    int android_recorder_reset(struct MediaRecorderWrapper *mr);
+    int android_recorder_close(struct MediaRecorderWrapper *mr);
+    int android_recorder_release(struct MediaRecorderWrapper *mr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/surface_texture_client_hybris.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef SURFACE_TEXTURE_CLIENT_HYBRIS_H_
+#define SURFACE_TEXTURE_CLIENT_HYBRIS_H_
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <EGL/egl.h>
+
+#ifdef __ARM_PCS_VFP
+#define FP_ATTRIB __attribute__((pcs("aapcs")))
+#else
+#define FP_ATTRIB
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    // Taken from native_window.h
+    enum {
+        WINDOW_FORMAT_RGBA_8888     = 1,
+        WINDOW_FORMAT_RGBX_8888     = 2,
+        WINDOW_FORMAT_RGB_565       = 4,
+    };
+
+    typedef void* SurfaceTextureClientHybris;
+    typedef void* GLConsumerHybris;
+    typedef void* GLConsumerWrapperHybris;
+    typedef void* IGraphicBufferConsumerHybris;
+    typedef void* IGraphicBufferProducerHybris;
+    typedef void* IGBCWrapperHybris;
+    typedef void* IGBPWrapperHybris;
+
+    /** Used to set a callback function to be called when a frame is ready to be rendered **/
+    typedef void (*FrameAvailableCbHybris)(GLConsumerWrapperHybris wrapper, void *context);
+    typedef void (*DecodingClientDeathCbHybris)(void *context);
+
+    //SurfaceTextureClientHybris surface_texture_client_get_instance();
+    SurfaceTextureClientHybris surface_texture_client_create(EGLNativeWindowType native_window);
+    SurfaceTextureClientHybris surface_texture_client_create_by_id(unsigned int texture_id);
+    SurfaceTextureClientHybris surface_texture_client_create_by_igbp(IGBPWrapperHybris wrapper);
+    GLConsumerWrapperHybris gl_consumer_create_by_id_with_igbc(unsigned int texture_id, IGBCWrapperHybris wrapper);
+    int gl_consumer_set_frame_available_cb(GLConsumerWrapperHybris wrapper, FrameAvailableCbHybris cb, void *context);
+    void gl_consumer_get_transformation_matrix(GLConsumerWrapperHybris wrapper, float *matrix) FP_ATTRIB;
+    void gl_consumer_update_texture(GLConsumerWrapperHybris wrapper);
+    uint8_t surface_texture_client_is_ready_for_rendering(SurfaceTextureClientHybris stc);
+    uint8_t surface_texture_client_hardware_rendering(SurfaceTextureClientHybris stc);
+    void surface_texture_client_set_hardware_rendering(SurfaceTextureClientHybris stc, uint8_t hardware_rendering);
+    void surface_texture_client_get_transformation_matrix(SurfaceTextureClientHybris stc, float *matrix) FP_ATTRIB;
+    void surface_texture_client_update_texture(SurfaceTextureClientHybris stc);
+    void surface_texture_client_destroy(SurfaceTextureClientHybris stc);
+    void surface_texture_client_ref(SurfaceTextureClientHybris stc);
+    void surface_texture_client_unref(SurfaceTextureClientHybris stc);
+    void surface_texture_client_set_surface_texture(SurfaceTextureClientHybris stc, EGLNativeWindowType native_window);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SURFACE_TEXTURE_CLIENT_HYBRIS_H_
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/ui/ui_compatibility_layer.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/ui/ui_compatibility_layer.h
@@ -50,8 +50,10 @@ extern "C" {
 
     void* graphic_buffer_get_native_buffer(struct graphic_buffer *buffer);
 
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
     void graphic_buffer_set_index(struct graphic_buffer *buffer, int index);
     int graphic_buffer_get_index(struct graphic_buffer *buffer);
+#endif
 
     int graphic_buffer_init_check(struct graphic_buffer *buffer);
 
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/input/is.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/input/is.c
@@ -24,10 +24,18 @@
 #include <hybris/common/binding.h>
 #include <hybris/input/input_stack_compatibility_layer.h>
 
-#define COMPAT_LIBRARY_PATH "/system/lib/libis_compat_layer.so"
+#define COMPAT_LIBRARY_PATH "libis_compat_layer.so"
 
 HYBRIS_LIBRARY_INITIALIZE(is, COMPAT_LIBRARY_PATH);
 
+int android_input_check_availability()
+{
+	/* Both are defined via HYBRIS_LIBRARY_INITIALIZE */
+	if (!is_handle)
+		hybris_is_initialize();
+	return is_handle ? 1 : 0;
+}
+
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(is, android_input_stack_initialize,
 	struct AndroidEventListener*, struct InputStackConfiguration*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION0(is, android_input_stack_start);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/libnfc_ndef_nxp/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/libnfc_ndef_nxp/Makefile.am
@@ -2,7 +2,10 @@ lib_LTLIBRARIES = \
 	libnfc_ndef_nxp.la
 
 libnfc_ndef_nxp_la_SOURCES = libnfc_ndef_nxp.c
-libnfc_ndef_nxp_la_CFLAGS = -I$(top_srcdir)/include $(ANDROID_HEADERS_CFLAGS)
+libnfc_ndef_nxp_la_CFLAGS = \
+	-I$(top_srcdir)/include \
+	$(ANDROID_HEADERS_CFLAGS) \
+	-Wno-error=unused-function
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libnfc_ndef_nxp.pc
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/libnfc_ndef_nxp/libnfc_ndef_nxp.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/libnfc_ndef_nxp/libnfc_ndef_nxp.c
@@ -34,7 +34,7 @@
 
 #include <hybris/common/binding.h>
 
-HYBRIS_LIBRARY_INITIALIZE(libnfc_ndef_so, "/system/lib/libnfc_ndef.so");
+HYBRIS_LIBRARY_INITIALIZE(libnfc_ndef_so, "libnfc_ndef.so");
 
 HYBRIS_IMPLEMENT_FUNCTION5(libnfc_ndef_so, NFCSTATUS, phFriNfc_NdefRecord_GetRecords, uint8_t *, uint32_t, uint8_t **, uint8_t *, uint32_t *);
 HYBRIS_IMPLEMENT_FUNCTION1(libnfc_ndef_so, uint32_t, phFriNfc_NdefRecord_GetLength, phFriNfc_NdefRecord_t *);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/libnfc_nxp/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/libnfc_nxp/Makefile.am
@@ -2,7 +2,10 @@ lib_LTLIBRARIES = \
 	libnfc_nxp.la
 
 libnfc_nxp_la_SOURCES = libnfc_nxp.c
-libnfc_nxp_la_CFLAGS = -I$(top_srcdir)/include $(ANDROID_HEADERS_CFLAGS)
+libnfc_nxp_la_CFLAGS = \
+	-I$(top_srcdir)/include \
+	$(ANDROID_HEADERS_CFLAGS) \
+	-Wno-error=unused-function
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libnfc_nxp.pc
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/libnfc_nxp/libnfc_nxp.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/libnfc_nxp/libnfc_nxp.c
@@ -56,7 +56,7 @@ typedef void   (*pphDal4Nfc_DeferFuncPoi
 
 #include <hybris/common/binding.h>
 
-HYBRIS_LIBRARY_INITIALIZE(libnfc_so, "/system/lib/libnfc.so");
+HYBRIS_LIBRARY_INITIALIZE(libnfc_so, "libnfc.so");
 
 HYBRIS_IMPLEMENT_FUNCTION2(libnfc_so, NFCSTATUS, phLibNfc_Mgt_ConfigureDriver, pphLibNfc_sConfig_t, void **);
 HYBRIS_IMPLEMENT_FUNCTION2(libnfc_so, NFCSTATUS, phDal4Nfc_Config, pphDal4Nfc_sConfig_t, void **);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/libsync/sync.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/libsync/sync.c
@@ -28,6 +28,8 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+extern size_t strlcpy(char *dst, const char *src, size_t siz);
+
 int sync_wait(int fd, int timeout)
 {
     __s32 to = timeout;
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/media/Makefile.am
@@ -0,0 +1,17 @@
+lib_LTLIBRARIES = \
+	libmedia.la
+
+libmedia_la_SOURCES = media.c
+libmedia_la_CFLAGS = -I$(top_srcdir)/include
+if WANT_TRACE
+libmedia_la_CFLAGS += -DDEBUG
+endif
+if WANT_DEBUG
+libmedia_la_CFLAGS += -ggdb -O0
+endif
+libmedia_la_LDFLAGS = \
+	$(top_builddir)/common/libhybris-common.la \
+	-version-info "1":"0":"0"
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libmedia.pc
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/media/libmedia.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=@libdir@
+includedir=@includedir@
+
+Name: hybris-media
+Description: libhybris media library
+Version: @VERSION@
+Libs: -L${libdir} -lhybris-common -lmedia
+Cflags: -I${includedir}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/media/media.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2013-2014 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#include <hybris/common/binding.h>
+#include <hybris/media/decoding_service.h>
+#include <hybris/media/media_compatibility_layer.h>
+#include <hybris/media/media_codec_layer.h>
+#include <hybris/media/media_codec_list.h>
+#include <hybris/media/media_format_layer.h>
+#include <hybris/media/media_recorder_layer.h>
+#include <hybris/media/surface_texture_client_hybris.h>
+#include <hybris/media/media_codec_source_layer.h>
+#include <hybris/media/media_buffer_layer.h>
+
+#define COMPAT_LIBRARY_PATH "libmedia_compat_layer.so"
+
+#ifdef __ARM_PCS_VFP
+#define FP_ATTRIB __attribute__((pcs("aapcs")))
+#else
+#define FP_ATTRIB
+#endif
+
+HYBRIS_LIBRARY_INITIALIZE(media, COMPAT_LIBRARY_PATH);
+
+int media_compat_check_availability()
+{
+	/* Both are defined via HYBRIS_LIBRARY_INITIALIZE */
+	hybris_media_initialize();
+	return media_handle ? 1 : 0;
+}
+
+unsigned int hybris_media_get_version()
+{
+	static unsigned int (*f)() FP_ATTRIB = NULL;
+	HYBRIS_DLSYSM(media, &f, "hybris_media_get_version");
+
+	/* When the method is not available we return zero here
+	 * rather than crashing to indicate the client the
+	 * Android side implementation is not versioned yet. */
+	if (!f)
+		return 0;
+
+	return f();
+}
+
+HYBRIS_IMPLEMENT_FUNCTION0(media, struct MediaPlayerWrapper*,
+	android_media_new_player);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, android_media_update_surface_texture,
+	struct MediaPlayerWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_media_play,
+	struct MediaPlayerWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_media_pause,
+	struct MediaPlayerWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_media_stop,
+	struct MediaPlayerWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, android_media_is_playing,
+	struct MediaPlayerWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_seek_to,
+	struct MediaPlayerWrapper*, int);
+
+// Setters
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_set_data_source,
+	struct MediaPlayerWrapper*, const char*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_set_preview_texture,
+	struct MediaPlayerWrapper*, int);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_set_volume,
+	struct MediaPlayerWrapper*, int);
+
+// Getters
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, android_media_surface_texture_get_transformation_matrix,
+	struct MediaPlayerWrapper*, float*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_get_current_position,
+	struct MediaPlayerWrapper*, int*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_get_duration,
+	struct MediaPlayerWrapper*, int*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_get_volume,
+	struct MediaPlayerWrapper*, int*);
+
+// Callbacks
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_video_size_cb,
+	struct MediaPlayerWrapper*, on_msg_set_video_size, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_video_texture_needs_update_cb,
+	struct MediaPlayerWrapper*, on_video_texture_needs_update, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_error_cb,
+	struct MediaPlayerWrapper*, on_msg_error, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_playback_complete_cb,
+	struct MediaPlayerWrapper*, on_playback_complete, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_media_prepared_cb,
+	struct MediaPlayerWrapper*, on_media_prepared, void*);
+
+// DecodingService
+HYBRIS_IMPLEMENT_VOID_FUNCTION0(media, decoding_service_init);
+HYBRIS_IMPLEMENT_FUNCTION0(media, IGBCWrapperHybris,
+	decoding_service_get_igraphicbufferconsumer);
+HYBRIS_IMPLEMENT_FUNCTION0(media, IGraphicBufferProducerHybris,
+	decoding_service_get_igraphicbufferproducer);
+HYBRIS_IMPLEMENT_FUNCTION1(media, DSSessionWrapperHybris,
+	decoding_service_create_session, uint32_t);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, decoding_service_set_client_death_cb,
+	DecodingClientDeathCbHybris, uint32_t, void*);
+
+// Media Codecs
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaCodecDelegate,
+	media_codec_create_by_codec_name, const char*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_delegate_destroy,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_delegate_ref,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_delegate_unref,
+	MediaCodecDelegate);
+
+#ifdef SIMPLE_PLAYER
+HYBRIS_IMPLEMENT_FUNCTION4(media, int, media_codec_configure,
+	MediaCodecDelegate, MediaFormat, void*, uint32_t);
+#else
+HYBRIS_IMPLEMENT_FUNCTION4(media, int, media_codec_configure,
+	MediaCodecDelegate, MediaFormat, SurfaceTextureClientHybris, uint32_t);
+#endif
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, media_codec_set_surface_texture_client,
+	MediaCodecDelegate, SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, media_codec_queue_csd,
+	MediaCodecDelegate, MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_start,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_stop,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_release,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_flush,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_codec_get_input_buffers_size,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_FUNCTION2(media, uint8_t*, media_codec_get_nth_input_buffer,
+	MediaCodecDelegate, size_t);
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_get_nth_input_buffer_capacity,
+	MediaCodecDelegate, size_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_codec_get_output_buffers_size,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_FUNCTION2(media, uint8_t*, media_codec_get_nth_output_buffer,
+	MediaCodecDelegate, size_t);
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_get_nth_output_buffer_capacity,
+	MediaCodecDelegate, size_t);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_dequeue_output_buffer,
+	MediaCodecDelegate, MediaCodecBufferInfo*, int64_t);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, media_codec_queue_input_buffer,
+	MediaCodecDelegate, const MediaCodecBufferInfo*);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_dequeue_input_buffer,
+	MediaCodecDelegate, size_t*, int64_t);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_release_output_buffer,
+	MediaCodecDelegate, size_t, uint8_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaFormat, media_codec_get_output_format,
+	MediaCodecDelegate);
+
+HYBRIS_IMPLEMENT_FUNCTION3(media, ssize_t, media_codec_list_find_codec_by_type,
+	const char*, bool, size_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, ssize_t, media_codec_list_find_codec_by_name,
+	const char *);
+HYBRIS_IMPLEMENT_FUNCTION0(media, size_t, media_codec_list_count_codecs);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_list_get_codec_info_at_id,
+	size_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, const char*, media_codec_list_get_codec_name,
+	size_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, media_codec_list_is_encoder,
+	size_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_codec_list_get_num_supported_types,
+	size_t);
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_list_get_nth_supported_type_len,
+	size_t, size_t);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_list_get_nth_supported_type,
+	size_t, char *, size_t);
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_list_get_num_profile_levels,
+	size_t, const char*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_list_get_num_color_formats,
+	size_t, const char*);
+HYBRIS_IMPLEMENT_FUNCTION4(media, int, media_codec_list_get_nth_codec_profile_level,
+	size_t, const char*, profile_level*, size_t);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_list_get_codec_color_formats,
+	size_t, const char*, uint32_t*);
+
+HYBRIS_IMPLEMENT_FUNCTION5(media, MediaFormat, media_format_create_video_format,
+	const char*, int32_t, int32_t, int64_t, int32_t);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_format_destroy,
+	MediaFormat);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_format_ref,
+	MediaFormat);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_format_unref,
+	MediaFormat);
+HYBRIS_IMPLEMENT_VOID_FUNCTION4(media, media_format_set_byte_buffer,
+	MediaFormat, const char*, uint8_t*, size_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, const char*, media_format_get_mime,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int64_t, media_format_get_duration_us,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_width,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_height,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_max_input_size,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_stride,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_slice_height,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_color_format,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_left,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_right,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_top,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_bottom,
+	MediaFormat);
+
+// SurfaceTextureClientHybris
+HYBRIS_IMPLEMENT_FUNCTION1(media, SurfaceTextureClientHybris,
+	surface_texture_client_create, EGLNativeWindowType);
+HYBRIS_IMPLEMENT_FUNCTION1(media, SurfaceTextureClientHybris,
+	surface_texture_client_create_by_id, unsigned int);
+HYBRIS_IMPLEMENT_FUNCTION1(media, SurfaceTextureClientHybris,
+	surface_texture_client_create_by_igbp, IGBPWrapperHybris);
+HYBRIS_IMPLEMENT_FUNCTION2(media, GLConsumerWrapperHybris,
+	gl_consumer_create_by_id_with_igbc, unsigned int, IGBCWrapperHybris);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int,
+	gl_consumer_set_frame_available_cb, GLConsumerWrapperHybris, FrameAvailableCbHybris, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, gl_consumer_get_transformation_matrix,
+	GLConsumerWrapperHybris, GLfloat*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, gl_consumer_update_texture,
+	GLConsumerWrapperHybris);
+HYBRIS_IMPLEMENT_FUNCTION1(media, uint8_t,
+	surface_texture_client_is_ready_for_rendering, SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_FUNCTION1(media, uint8_t,
+	surface_texture_client_hardware_rendering, SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, surface_texture_client_set_hardware_rendering,
+	SurfaceTextureClientHybris, uint8_t);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, surface_texture_client_get_transformation_matrix,
+	SurfaceTextureClientHybris, GLfloat*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_update_texture,
+	SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_destroy,
+	SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_ref,
+	SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_unref,
+	SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, surface_texture_client_set_surface_texture,
+	SurfaceTextureClientHybris, EGLNativeWindowType);
+
+// Recorder Observer
+HYBRIS_IMPLEMENT_FUNCTION0(media, struct MediaRecorderObserver*,
+	android_media_recorder_observer_new);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_recorder_observer_set_cb,
+	struct MediaRecorderObserver*, media_recording_started_cb, void*);
+
+// Recorder
+HYBRIS_IMPLEMENT_FUNCTION0(media, struct MediaRecorderWrapper*,
+	android_media_new_recorder);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_initCheck,
+	struct MediaRecorderWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setCamera,
+	struct MediaRecorderWrapper*, struct CameraControl*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setVideoSource,
+	struct MediaRecorderWrapper*, VideoSource);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setAudioSource,
+	struct MediaRecorderWrapper*, AudioSource);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setOutputFormat,
+	struct MediaRecorderWrapper*, OutputFormat);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setVideoEncoder,
+	struct MediaRecorderWrapper*, VideoEncoder);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setAudioEncoder,
+	struct MediaRecorderWrapper*, AudioEncoder);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setOutputFile,
+	struct MediaRecorderWrapper*, int);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, android_recorder_setVideoSize,
+	struct MediaRecorderWrapper*, int, int);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setVideoFrameRate,
+	struct MediaRecorderWrapper*, int);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setParameters,
+	struct MediaRecorderWrapper*, const char*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_start,
+	struct MediaRecorderWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_stop,
+	struct MediaRecorderWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_prepare,
+	struct MediaRecorderWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_reset,
+	struct MediaRecorderWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_close,
+	struct MediaRecorderWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_release,
+	struct MediaRecorderWrapper*);
+
+// Recorder Callbacks
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_recorder_set_error_cb,
+	struct MediaRecorderWrapper*, on_recorder_msg_error, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_recorder_set_audio_read_cb,
+	struct MediaRecorderWrapper*, on_recorder_read_audio, void*);
+
+// Media Message
+HYBRIS_IMPLEMENT_FUNCTION0(media, MediaMessageWrapper*, media_message_create);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_message_release, MediaMessageWrapper*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_message_clear, MediaMessageWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, const char*, media_message_dump, MediaMessageWrapper*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_message_set_int32, MediaMessageWrapper*,
+	const char*, int32_t);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_message_set_int64, MediaMessageWrapper*,
+	const char*, int64_t);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_message_set_size, MediaMessageWrapper*,
+	const char*, size_t);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_message_set_float, MediaMessageWrapper*,
+	const char*, float);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_message_set_double, MediaMessageWrapper*,
+	const char*, double);
+HYBRIS_IMPLEMENT_VOID_FUNCTION4(media, media_message_set_string, MediaMessageWrapper*,
+	const char*, const char*, ssize_t);
+HYBRIS_IMPLEMENT_FUNCTION2(media, bool, media_message_contains, MediaMessageWrapper*,
+	const char*);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_message_find_int32, MediaMessageWrapper*,
+	const char*, int32_t*);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_message_find_int64, MediaMessageWrapper*,
+	const char*, int64_t*);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_message_find_size, MediaMessageWrapper*,
+	const char*, size_t*);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_message_find_float, MediaMessageWrapper*,
+	const char*, float*);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_message_find_double, MediaMessageWrapper*,
+	const char*, double*);
+
+// Media Meta Data
+HYBRIS_IMPLEMENT_FUNCTION1(media, uint32_t, media_meta_data_get_key_id, int);
+HYBRIS_IMPLEMENT_FUNCTION0(media, MediaMetaDataWrapper*, media_meta_data_create);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_meta_data_release, MediaMetaDataWrapper*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_meta_data_clear, MediaMetaDataWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, bool, media_meta_data_remove, MediaMetaDataWrapper*,
+	uint32_t);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_set_cstring, MediaMetaDataWrapper*,
+	uint32_t, const char*);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_set_int32, MediaMetaDataWrapper*,
+	uint32_t, int32_t);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_set_int64, MediaMetaDataWrapper*,
+	uint32_t, int64_t);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_set_float, MediaMetaDataWrapper*,
+	uint32_t, float);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_set_pointer, MediaMetaDataWrapper*,
+	uint32_t, void*);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_find_cstring, MediaMetaDataWrapper*,
+	uint32_t, const char**);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_find_int32, MediaMetaDataWrapper*,
+	uint32_t, int32_t*);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_find_int64, MediaMetaDataWrapper*,
+	uint32_t, int64_t*);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_find_float, MediaMetaDataWrapper*,
+	uint32_t, float*);
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_find_pointer, MediaMetaDataWrapper*,
+	uint32_t, void**);
+
+// Media Buffer
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaBufferWrapper*, media_buffer_create, size_t);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_buffer_destroy, MediaBufferWrapper*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_buffer_release, MediaBufferWrapper*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_buffer_ref, MediaBufferWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_buffer_get_refcount, MediaBufferWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, void*, media_buffer_get_data, MediaBufferWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_buffer_get_size, MediaBufferWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_buffer_get_range_offset, MediaBufferWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_buffer_get_range_length, MediaBufferWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaMetaDataWrapper*, media_buffer_get_meta_data, MediaBufferWrapper*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_buffer_set_return_callback, MediaBufferWrapper*,
+	MediaBufferReturnCallback, void*);
+
+// Media ABuffer
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaABufferWrapper*, media_abuffer_create,
+	size_t);
+HYBRIS_IMPLEMENT_FUNCTION2(media, MediaABufferWrapper*, media_abuffer_create_with_data,
+	uint8_t*, size_t);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_abuffer_set_range,
+	MediaABufferWrapper*, size_t, size_t);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, media_abuffer_set_media_buffer_base,
+	MediaABufferWrapper*, MediaBufferWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaBufferWrapper*, media_abuffer_get_media_buffer_base,
+	MediaABufferWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, void*, media_abuffer_get_data,
+	MediaABufferWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_abuffer_get_size,
+	MediaABufferWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_abuffer_get_range_offset,
+	MediaABufferWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_abuffer_get_capacity,
+	MediaABufferWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaMessageWrapper*, media_abuffer_get_meta,
+	MediaABufferWrapper*);
+
+// Media Codec Source
+HYBRIS_IMPLEMENT_FUNCTION3(media, MediaCodecSourceWrapper*, media_codec_source_create,
+	MediaMessageWrapper*, MediaSourceWrapper*, int);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_source_release, MediaCodecSourceWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, void*, media_codec_source_get_native_window_handle,
+	MediaCodecSourceWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaMetaDataWrapper*, media_codec_source_get_format,
+	MediaCodecSourceWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, media_codec_source_start, MediaCodecSourceWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, media_codec_source_stop, MediaCodecSourceWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, media_codec_source_pause, MediaCodecSourceWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, bool, media_codec_source_read, MediaCodecSourceWrapper*,
+	MediaBufferWrapper**);
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, media_codec_source_request_idr_frame,
+	MediaCodecSourceWrapper*);
+
+// Media Source
+HYBRIS_IMPLEMENT_FUNCTION0(media, MediaSourceWrapper*, media_source_create);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_source_release, MediaSourceWrapper*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, media_source_set_format, MediaSourceWrapper*,
+	MediaMetaDataWrapper*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_source_set_start_callback,
+	MediaSourceWrapper*, MediaSourceStartCallback, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_source_set_stop_callback,
+	MediaSourceWrapper*, MediaSourceStopCallback, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_source_set_read_callback,
+	MediaSourceWrapper*, MediaSourceReadCallback, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_source_set_pause_callback,
+	MediaSourceWrapper*, MediaSourcePauseCallback, void*);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/properties/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/properties/Makefile.am
@@ -3,6 +3,12 @@ lib_LTLIBRARIES = \
 
 libandroid_properties_la_SOURCES = properties.c cache.c
 libandroid_properties_la_CFLAGS = -I$(top_srcdir)/include $(ANDROID_HEADERS_CFLAGS)
+if WANT_RUNTIME_PROPERTY_CACHE
+libandroid_properties_la_SOURCES += runtime_cache.c
+else
+libandroid_properties_la_CFLAGS += -DNO_RUNTIME_PROPERTY_CACHE
+endif
+
 if WANT_DEBUG
 libandroid_properties_la_CFLAGS += -ggdb -O0
 endif
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/properties/cache.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/properties/cache.c
@@ -75,7 +75,6 @@ char *hybris_propcache_find(const char *
 	if (prop)
 		return prop->value;
 
-out:
 	return ret;
 }
 
@@ -99,10 +98,9 @@ static void cache_update()
 {
 	struct stat st;
 	FILE *f = fopen("/system/build.prop", "r");
-	char *ret = NULL;
 
 	if (!f)
-		return NULL;
+		return;
 
 	/* before searching, we must first determine whether our cache is valid. if
 	 * it isn't, we must discard our results and re-create the cache.
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/properties/properties.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/properties/properties.c
@@ -47,7 +47,6 @@ static int send_prop_msg(prop_msg_t *msg
 		void (*propfn)(const char *, const char *, void *),
 		void *cookie)
 {
-	struct pollfd pollfds[1];
 	union {
 		struct sockaddr_un addr;
 		struct sockaddr addr_g;
@@ -86,8 +85,6 @@ static int send_prop_msg(prop_msg_t *msg
 	r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg_t), 0));
 
 	if (r == sizeof(prop_msg_t)) {
-		pollfds[0].fd = s;
-		pollfds[0].events = 0;
 		// We successfully wrote to the property server, so use recv
 		// in case we need to get a property. Once the other side is
 		// finished, the socket is closed.
@@ -151,7 +148,7 @@ static int property_get_socket(const cha
 
 	/* In case it's null, just use the default */
 	if ((strlen(msg.value) == 0) && (default_value)) {
-		if (strlen(default_value) >= PROP_VALUE_MAX -1)	return -1;
+		if (strlen(default_value) > PROP_VALUE_MAX -1)	return -1;
 		strcpy(msg.value, default_value);
 	}
 
@@ -164,11 +161,26 @@ int property_get(const char *key, char *
 {
 	char *ret = NULL;
 
-	if ((key) && (strlen(key) >= PROP_NAME_MAX -1)) return -1;
+	if ((key) && (strlen(key) > PROP_NAME_MAX -1)) return -1;
 	if (value == NULL) return -1;
 
-	if (property_get_socket(key, value, default_value) == 0)
-		return strlen(value);
+
+	// Runtime cache will serialize property lookups within the process.
+	// This will increase latency if multiple threads are doing many
+	// parallel lookups to new properties, but the overhead should
+	// be offset with the caching eventually.
+	runtime_cache_lock();
+	if (runtime_cache_get(key, value) == 0) {
+		ret = value;
+	} else if (property_get_socket(key, value, default_value) == 0) {
+		runtime_cache_insert(key, value);
+		ret = value;
+	}
+	runtime_cache_unlock();
+
+	if (ret)
+		return strlen(ret);
+
 
 	/* In case the socket is not available, search the property file cache by hand */
 	ret = hybris_propcache_find(key);
@@ -193,8 +205,12 @@ int property_set(const char *key, const
 
 	if (key == 0) return -1;
 	if (value == 0) value = "";
-	if (strlen(key) >= PROP_NAME_MAX -1) return -1;
-	if (strlen(value) >= PROP_VALUE_MAX -1) return -1;
+	if (strlen(key) > PROP_NAME_MAX -1) return -1;
+	if (strlen(value) > PROP_VALUE_MAX -1) return -1;
+
+	runtime_cache_lock();
+	runtime_cache_remove(key);
+	runtime_cache_unlock();
 
 	memset(&msg, 0, sizeof(msg));
 	msg.cmd = PROP_MSG_SETPROP;
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/properties/properties_p.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/properties/properties_p.h
@@ -23,4 +23,18 @@ typedef void (*hybris_propcache_list_cb)
 void hybris_propcache_list(hybris_propcache_list_cb cb, void *cookie);
 char *hybris_propcache_find(const char *key);
 
+#ifndef NO_RUNTIME_PROPERTY_CACHE
+void runtime_cache_lock();
+void runtime_cache_unlock();
+int  runtime_cache_get(const char *key, char *value);
+void runtime_cache_insert(const char *key, char *value);
+void runtime_cache_remove(const char *key);
+#else
+#define runtime_cache_lock()
+#define runtime_cache_unlock()
+#define runtime_cache_get(K,V) (-1)
+#define runtime_cache_insert(K,V)
+#define runtime_cache_remove(K)
+#endif
+
 #endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/properties/runtime_cache.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2012 Carsten Munk <carsten.munk@gmail.com>
+ * Copyright (c) 2008 The Android Open Source Project
+ * Copyright (c) 2013 Simon Busch <morphis@gravedo.de>
+ * Copyright (c) 2013 Canonical Ltd
+ * Copyright (c) 2013 Jolla Ltd. <robin.burchell@jollamobile.com>
+ * Copyright (c) 2015 Jolla Ltd. <mikko.harju@jollamobile.com>
+ *
+ * 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.
+ *
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+
+
+#define HYBRIS_PROPERTY_CACHE_DEFAULT_TIMEOUT_SECS 10
+
+/** Maximum allowed time to return stale data from the cache. Override
+	with HYBRIS_PROPERTY_CACHE_TIMEOUT_SECS environment variable.
+*/
+static time_t runtime_cache_timeout_secs = HYBRIS_PROPERTY_CACHE_DEFAULT_TIMEOUT_SECS;
+
+
+/** Key, value pair and the time of previous update (in seconds) */
+struct hybris_prop_value
+{
+	char *key;
+	char *value;
+	time_t last_update;
+};
+
+static struct hybris_prop_value * prop_array = 0;
+static int num_prop = 0;
+static int num_alloc = 0;
+
+/** Protect access to statics */
+static pthread_mutex_t array_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* private:
+ * compares two hybris_prop_value by key, so as to maintain a qsorted array of
+ * props, and search the array.
+ */
+static int prop_qcmp(const void *a, const void *b)
+{
+	struct hybris_prop_value *aa = (struct hybris_prop_value *)a;
+	struct hybris_prop_value *bb = (struct hybris_prop_value *)b;
+
+	return strcmp(aa->key, bb->key);
+}
+
+static struct hybris_prop_value *cache_find_internal(const char *key)
+{
+	struct hybris_prop_value prop_key;
+	prop_key.key = (char*)key;
+
+	return bsearch(&prop_key, prop_array, num_prop, sizeof(struct hybris_prop_value), prop_qcmp);
+}
+
+static void runtime_cache_init()
+{
+	num_alloc = 8;
+	prop_array = malloc(num_alloc * sizeof(struct hybris_prop_value));
+
+	const char *timeout_str = getenv("HYBRIS_PROPERTY_CACHE_TIMEOUT_SECS");
+	if (timeout_str) {
+		runtime_cache_timeout_secs = atoi(timeout_str);
+	}
+}
+
+static void runtime_cache_ensure_initialized()
+{
+	if (!prop_array) {
+		runtime_cache_init();
+	}
+}
+
+/** Invalidate an entry in the cache
+  *
+  * Cache will never shrink. Instead, assume that the same key
+  * will be queried soon after invalidation and reuse the entry.
+  */
+static void runtime_cache_invalidate_entry(struct hybris_prop_value *entry)
+{
+	free(entry->value);
+	entry->value = NULL;
+}
+
+static int runtime_cache_get_impl(const char *key, char *value)
+{
+	int ret = -ENOENT;
+
+	struct hybris_prop_value *entry = cache_find_internal(key);
+	if (entry != NULL && entry->value != NULL) {
+		struct timespec now;
+		clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
+		time_t delta_secs = now.tv_sec - entry->last_update;
+		if (delta_secs > runtime_cache_timeout_secs) {
+			// assume the data in cache is stale, and force refresh
+			runtime_cache_invalidate_entry(entry);
+		} else {
+			// success, return value from cache
+			strcpy(value, entry->value);
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+static void runtime_cache_insert_impl(const char *key, char *value)
+{
+	struct timespec now;
+	clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
+
+	struct hybris_prop_value *entry = cache_find_internal(key);
+	if (entry) {
+		assert(entry->value == NULL);
+		// key,value pair was invalidated earlier,
+		// reuse entry in the property array
+		entry->value = strdup(value);
+		entry->last_update = now.tv_sec;
+	} else {
+		if (num_alloc == num_prop) {
+			num_alloc = 3 * num_alloc / 2;
+			prop_array = realloc(prop_array, num_alloc * sizeof(struct hybris_prop_value));
+		}
+
+		struct hybris_prop_value new_entry = { strdup(key), strdup(value), now.tv_sec };
+		prop_array[num_prop++] = new_entry;
+
+		qsort(prop_array, num_prop, sizeof(struct hybris_prop_value), prop_qcmp);
+	}
+}
+
+
+void runtime_cache_lock()
+{
+	pthread_mutex_lock(&array_mutex);
+}
+
+void runtime_cache_unlock()
+{
+	pthread_mutex_unlock(&array_mutex);
+}
+
+void runtime_cache_remove(const char *key)
+{
+	runtime_cache_ensure_initialized();
+	struct hybris_prop_value *entry = cache_find_internal(key);
+	if (entry) {
+		runtime_cache_invalidate_entry(entry);
+	}
+}
+
+int runtime_cache_get(const char *key, char *value)
+{
+	runtime_cache_ensure_initialized();
+	return runtime_cache_get_impl(key, value);
+}
+
+void runtime_cache_insert(const char *key, char *value)
+{
+	runtime_cache_ensure_initialized();
+	runtime_cache_insert_impl(key, value);
+}
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/sf/sf.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/sf/sf.c
@@ -24,7 +24,7 @@
 #include <hybris/common/binding.h>
 #include <hybris/surface_flinger/surface_flinger_compatibility_layer.h>
 
-#define COMPAT_LIBRARY_PATH "/system/lib/libsf_compat_layer.so"
+#define COMPAT_LIBRARY_PATH "libsf_compat_layer.so"
 
 HYBRIS_LIBRARY_INITIALIZE(sf, COMPAT_LIBRARY_PATH);
 
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/tests/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/Makefile.am
@@ -1,4 +1,5 @@
 bin_PROGRAMS = \
+	test_audio \
 	test_egl \
 	test_egl_configs \
 	test_glesv2 \
@@ -6,9 +7,13 @@ bin_PROGRAMS = \
 	test_sf \
 	test_sensors \
 	test_input \
+	test_lights \
 	test_camera \
 	test_vibrator \
-	test_gps
+	test_media \
+	test_recorder \
+	test_gps \
+	test_wifi
 
 if HAS_ANDROID_4_2_0
 bin_PROGRAMS += test_hwcomposer
@@ -23,14 +28,10 @@ if HAS_LIBNFC_NXP_HEADERS
 bin_PROGRAMS += test_nfc
 endif
 
-# Please re-enable your test programs according to android
-# if HAS_ANDROID_X_Y_Z
-# bin_PROGRAMS += test_audio 
-# endif
-
 test_audio_SOURCES = test_audio.c
 test_audio_CFLAGS = \
-	-I$(top_srcdir)/include
+	-I$(top_srcdir)/include \
+	-I$(top_srcdir)/include/android
 test_audio_LDADD = \
 	$(top_builddir)/common/libhybris-common.la \
 	$(top_builddir)/hardware/libhardware.la
@@ -146,8 +147,30 @@ test_camera_LDADD = \
 	$(top_builddir)/camera/libcamera.la \
 	$(top_builddir)/input/libis.la
 
+test_media_SOURCES = test_media.c
+test_media_CFLAGS = \
+	-I$(top_srcdir)/include
+test_media_LDADD = \
+	$(top_builddir)/common/libhybris-common.la \
+	$(top_builddir)/egl/libEGL.la \
+	$(top_builddir)/glesv2/libGLESv2.la \
+	$(top_builddir)/media/libmedia.la \
+	$(top_builddir)/sf/libsf.la
+
+test_recorder_SOURCES = test_recorder.c
+test_recorder_CFLAGS = \
+	-I$(top_srcdir)/include
+test_recorder_LDADD = \
+	$(top_builddir)/common/libhybris-common.la \
+	$(top_builddir)/egl/libEGL.la \
+	$(top_builddir)/glesv2/libGLESv2.la \
+	$(top_builddir)/media/libmedia.la \
+	$(top_builddir)/camera/libcamera.la \
+	$(top_builddir)/input/libis.la \
+	$(top_builddir)/sf/libsf.la
+
 test_gps_SOURCES = test_gps.c
-test_gps_CFLAGS = -pthread \
+test_gps_CFLAGS = \
 	-I$(top_srcdir)/include \
 	$(ANDROID_HEADERS_CFLAGS)
 
@@ -165,10 +188,11 @@ test_gps_LDADD =  \
 test_nfc_SOURCES = test_nfc.c
 test_nfc_CFLAGS = \
 	-I$(top_srcdir)/include \
-	$(ANDROID_HEADERS_CFLAGS)
-
-test_nfc_LDFLAGS =
+	$(ANDROID_HEADERS_CFLAGS) \
+	-Wno-error=unused-function
+test_nfc_LDFLAGS = -pthread
 test_nfc_LDADD = \
+	$(top_builddir)/common/libhybris-common.la \
 	$(top_builddir)/libnfc_nxp/libnfc_nxp.la \
 	$(top_builddir)/hardware/libhardware.la
 
@@ -180,3 +204,10 @@ test_vibrator_LDADD = \
 	$(top_builddir)/common/libhybris-common.la \
 	$(top_builddir)/vibrator/libvibrator.la
 
+test_wifi_SOURCES = test_wifi.c
+test_wifi_CFLAGS = \
+	-I$(top_srcdir)/include \
+	$(ANDROID_HEADERS_CFLAGS)
+test_wifi_LDADD = \
+	$(top_builddir)/wifi/libwifi.la
+
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/tests/test_audio.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_audio.c
@@ -25,32 +25,115 @@
 #include <hardware/audio.h>
 #include <hardware/hardware.h>
 
+/* Workaround for MTK */
+#define AUDIO_HARDWARE_MODULE_ID2 "libaudio"
+
 int main(int argc, char **argv)
 {
 	struct hw_module_t *hwmod = 0;
 	struct audio_hw_device *audiohw;
 
+	/* Initializing HAL */
 	hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID,
 					AUDIO_HARDWARE_MODULE_ID_PRIMARY,
 					(const hw_module_t**) &hwmod);
+	if (!hwmod) {
+		fprintf(stderr, "Failed to get hw module id: %s name: %s, trying alternative.",
+				AUDIO_HARDWARE_MODULE_ID, AUDIO_HARDWARE_MODULE_ID_PRIMARY);
+		hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID2,
+				AUDIO_HARDWARE_MODULE_ID_PRIMARY,
+				(const hw_module_t**) &hwmod);
+	}
+
 	assert(hwmod != NULL);
 
 	assert(audio_hw_device_open(hwmod, &audiohw) == 0);
+	do {
+#if defined(AUDIO_DEVICE_API_VERSION_MIN)
+		if (audiohw->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
+			fprintf(stderr, "Audio device API version %04x failed to meet minimum requirement %0x4.",
+					audiohw->common.version, AUDIO_DEVICE_API_VERSION_MIN);
+		} else
+#endif
+		if (audiohw->common.version != AUDIO_DEVICE_API_VERSION_CURRENT) {
+			fprintf(stderr, "Audio device API version %04x doesn't match platform current %0x4.",
+					audiohw->common.version, AUDIO_DEVICE_API_VERSION_CURRENT);
+		} else
+			break;
+
+#if defined(AUDIO_DEVICE_API_VERSION_MIN)
+		assert(audiohw->common.version >= AUDIO_DEVICE_API_VERSION_MIN);
+#endif
+		assert(audiohw->common.version == AUDIO_DEVICE_API_VERSION_CURRENT);
+	} while(0);
+
 	assert(audiohw->init_check(audiohw) == 0);
-	printf("Audio Hardware Interface initialized.\n");
+	fprintf(stdout, "Audio Hardware Interface initialized.\n");
 
+	/* Check volume function calls */
 	if (audiohw->get_master_volume) {
 		float volume;
 		audiohw->get_master_volume(audiohw, &volume);
-		printf("Master Volume: %f\n", volume);
+		fprintf(stdout, "Master Volume: %f\n", volume);
 	}
 
 	if (audiohw->get_master_mute) {
 		bool mute;
 		audiohw->get_master_mute(audiohw, &mute);
-		printf("Master Mute: %d\n", mute);
+		fprintf(stdout, "Master Mute: %d\n", mute);
 	}
 
+	/* Check output and input streams */
+	struct audio_config config_out = {
+		.sample_rate = 44100,
+		.channel_mask = AUDIO_CHANNEL_OUT_STEREO,
+		.format = AUDIO_FORMAT_PCM_16_BIT
+	};
+	struct audio_stream_out *stream_out = NULL;
+
+	audiohw->open_output_stream(audiohw, 0, AUDIO_DEVICE_OUT_DEFAULT,
+			AUDIO_OUTPUT_FLAG_PRIMARY, &config_out, &stream_out
+#if ANDROID_VERSION_MAJOR >= 5
+			, NULL
+#endif
+			);
+
+	/* Try it again */
+	if (!stream_out)
+		audiohw->open_output_stream(audiohw, 0, AUDIO_DEVICE_OUT_DEFAULT,
+				AUDIO_OUTPUT_FLAG_PRIMARY, &config_out, &stream_out
+#if ANDROID_VERSION_MAJOR >= 5
+				, NULL
+#endif
+				);
+
+	assert(stream_out != NULL);
+
+	fprintf(stdout, "Successfully created audio output stream: sample rate: %u, channel_mask: %u, format: %u\n",
+			config_out.sample_rate, config_out.channel_mask, config_out.format);
+
+	struct audio_config config_in = {
+		.sample_rate = 48000,
+		.channel_mask = AUDIO_CHANNEL_IN_STEREO,
+		.format = AUDIO_FORMAT_PCM_16_BIT
+	};
+	struct audio_stream_in *stream_in = NULL;
+
+	audiohw->open_input_stream(audiohw, 0, AUDIO_DEVICE_IN_DEFAULT,
+			&config_in, &stream_in
+#if ANDROID_VERSION_MAJOR >= 5
+			, AUDIO_INPUT_FLAG_NONE, NULL, AUDIO_SOURCE_DEFAULT
+#endif
+			);
+	assert(stream_in != NULL);
+
+	fprintf(stdout, "Successfully created audio input stream: sample rate: %u, channel_mask: %u, format: %u\n",
+			config_in.sample_rate, config_in.channel_mask, config_in.format);
+
+	/* Close streams and device */
+	audiohw->close_output_stream(audiohw, stream_out);
+	audiohw->close_input_stream(audiohw, stream_in);
+
 	audio_hw_device_close(audiohw);
 
 	return 0;
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/tests/test_camera.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_camera.c
@@ -15,6 +15,8 @@
  *
  */
 
+#include "config.h"
+
 #include <hybris/camera/camera_compatibility_layer.h>
 #include <hybris/camera/camera_compatibility_layer_capabilities.h>
 
@@ -28,6 +30,7 @@
 #include <GLES2/gl2ext.h>
 
 #include <assert.h>
+#include <errno.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -98,8 +101,6 @@ void zoom_msg_cb(void* context, int32_t
 {
 	printf("%s \n", __PRETTY_FUNCTION__);
 
-	struct CameraControl* cc = (struct CameraControl*) context;
-	static int zoom;
 	current_zoom_level = new_zoom_level;
 }
 
@@ -122,7 +123,7 @@ void jpeg_data_cb(void* data, uint32_t d
 	int fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
 	if(fd < 0)
 	    return;
-	ssize_t ret = write(fd, data, data_size);
+	TEMP_FAILURE_RETRY(write(fd, data, data_size));
 	close(fd);
 	shot_counter++;
 
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/tests/test_glesv2.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_glesv2.c
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <math.h>
 #include <stddef.h>
+#include <stdlib.h>
 
 const char vertex_src [] =
 "                                        \
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/tests/test_gps.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_gps.c
@@ -102,17 +102,6 @@ static const GpsNiInterface* get_gps_ni_
   return interface;
 }
 
-static const GpsDebugInterface* get_gps_debug_interface(const GpsInterface *gps)
-{
-  const GpsDebugInterface* interface = NULL;
-
-  if(gps)
-  {
-    interface = (const GpsDebugInterface*)gps->get_extension(GPS_DEBUG_INTERFACE);
-  }
-  return interface;
-}
-
 static const GpsXtraInterface* get_gps_extra_interface(const GpsInterface *gps)
 {
   const GpsXtraInterface* interface = NULL;
@@ -431,7 +420,10 @@ void sigint_handler(int signum)
 int main(int argc, char *argv[])
 {
   int sleeptime = 6000, opt, initok = 0;
-  int coldstart = 0, extra = 0, ulp = 0;
+  int coldstart = 0, extra = 0;
+#ifdef HAVE_ULP
+  int ulp = 0;
+#endif
   struct timeval tv;
   int agps = 0, agpsril = 0, injecttime = 0, injectlocation = 0;
   char *location = 0, *longitude, *latitude;
@@ -468,7 +460,9 @@ int main(int argc, char *argv[])
 		   agps_server = optarg;
 		   break;
 		case 'u':
+#ifdef HAVE_ULP
 		   ulp = 1;
+#endif
 		   break;
 		case 'x':
                    extra = 1;
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/tests/test_input.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_input.c
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <stdbool.h>
 #include <signal.h>
+#include <inttypes.h>
 
 #include <hybris/input/input_stack_compatibility_layer.h>
 
@@ -45,7 +46,7 @@ void on_new_event(struct Event* event, v
 
 	switch (event->type) {
 	case MOTION_EVENT_TYPE:
-		printf("\tdetails.motion.event_time: %lld\n",
+		printf("\tdetails.motion.event_time: %" PRId64 "\n",
 				event->details.motion.event_time);
 		printf("\tdetails.motion.pointer_coords.x: %f\n",
 				event->details.motion.pointer_coordinates[0].x);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/tests/test_lights.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_lights.c
@@ -30,19 +30,18 @@ int main(int argc, char **argv)
 	hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (const hw_module_t**) &hwmod);
 	assert(hwmod != NULL);
 
-	assert(light_device_open(hwmod, LIGHT_ID_NOTIFICATIONS, &notifications) == 0);
-	assert(notifications != 0);
+	hwmod->methods->open(hwmod, LIGHT_ID_NOTIFICATIONS, (hw_device_t **) &notifications);
+	assert(notifications != NULL);
 
 	memset(&notification_state, 0, sizeof(struct light_state_t));
 	notification_state.color = 0xffffffff;
 	notification_state.flashMode = LIGHT_FLASH_TIMED;
-	notification_state.flashOnMS = 1000;
+	notification_state.flashOnMS = 2000;
 	notification_state.flashOffMS = 1000;
+	notification_state.brightnessMode = BRIGHTNESS_MODE_USER;
 
 	assert(notifications->set_light(notifications, &notification_state) == 0);
 
-	light_device_close(notifications);
-
 	return 0;
 }
 
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_media.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ */
+
+#include <hybris/media/media_compatibility_layer.h>
+#include <hybris/surface_flinger/surface_flinger_compatibility_layer.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+enum {
+	OK          = 0,
+	NO_ERROR    = 0,
+};
+
+static float DestWidth = 0.0, DestHeight = 0.0;
+// Actual video dimmensions
+static int Width = 0, Height = 0;
+
+static GLuint gProgram;
+static GLuint gaPositionHandle, gaTexHandle, gsTextureHandle, gmTexMatrix;
+
+static GLfloat positionCoordinates[8];
+
+struct MediaPlayerWrapper *player = NULL;
+
+void calculate_position_coordinates()
+{
+	// Assuming cropping output for now
+	float x = 1, y = 1;
+
+	// Black borders
+	x = (float) (Width / DestWidth);
+	y = (float) (Height / DestHeight);
+
+	// Make the larger side be 1
+	if (x > y) {
+		y /= x;
+		x = 1;
+	} else {
+		x /= y;
+		y = 1;
+	}
+
+	positionCoordinates[0] = -x;
+	positionCoordinates[1] = y;
+	positionCoordinates[2] = -x;
+	positionCoordinates[3] = -y;
+	positionCoordinates[4] = x;
+	positionCoordinates[5] = -y;
+	positionCoordinates[6] = x;
+	positionCoordinates[7] = y;
+}
+
+struct ClientWithSurface
+{
+	struct SfClient* client;
+	struct SfSurface* surface;
+};
+
+struct ClientWithSurface client_with_surface(bool setup_surface_with_egl)
+{
+	struct ClientWithSurface cs;
+
+	cs.client = sf_client_create();
+
+	if (!cs.client) {
+		printf("Problem creating client ... aborting now.");
+		return cs;
+	}
+
+	static const size_t primary_display = 0;
+
+	DestWidth = sf_get_display_width(primary_display);
+	DestHeight = sf_get_display_height(primary_display);
+	printf("Primary display width: %f, height: %f\n", DestWidth, DestHeight);
+
+	SfSurfaceCreationParameters params = {
+		0,
+		0,
+		DestWidth,
+		DestHeight,
+		-1, //PIXEL_FORMAT_RGBA_8888,
+		15000,
+		0.5f,
+		setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL
+		"MediaCompatLayerTestSurface"
+	};
+
+	cs.surface = sf_surface_create(cs.client, &params);
+
+	if (!cs.surface) {
+		printf("Problem creating surface ... aborting now.");
+		return cs;
+	}
+
+	sf_surface_make_current(cs.surface);
+
+	return cs;
+}
+
+static const char *vertex_shader()
+{
+	return
+		"attribute vec4 a_position;                                  \n"
+		"attribute vec2 a_texCoord;                                  \n"
+		"uniform mat4 m_texMatrix;                                   \n"
+		"varying vec2 v_texCoord;                                    \n"
+		"varying float topDown;                                      \n"
+		"void main()                                                 \n"
+		"{                                                           \n"
+		"   gl_Position = a_position;                                \n"
+		"   v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n"
+		"}                                                           \n";
+}
+
+static const char *fragment_shader()
+{
+	return
+		"#extension GL_OES_EGL_image_external : require      \n"
+		"precision mediump float;                            \n"
+		"varying vec2 v_texCoord;                            \n"
+		"uniform samplerExternalOES s_texture;               \n"
+		"void main()                                         \n"
+		"{                                                   \n"
+		"  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
+		"}                                                   \n";
+}
+
+static GLuint loadShader(GLenum shaderType, const char* pSource)
+{
+	GLuint shader = glCreateShader(shaderType);
+
+	if (shader) {
+		glShaderSource(shader, 1, &pSource, NULL);
+		glCompileShader(shader);
+		GLint compiled = 0;
+		glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+
+		if (!compiled) {
+			GLint infoLen = 0;
+			glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+			if (infoLen) {
+				char* buf = (char*) malloc(infoLen);
+				if (buf) {
+					glGetShaderInfoLog(shader, infoLen, NULL, buf);
+					fprintf(stderr, "Could not compile shader %d:\n%s\n",
+							shaderType, buf);
+					free(buf);
+				}
+				glDeleteShader(shader);
+				shader = 0;
+			}
+		}
+	} else {
+		printf("Error, during shader creation: %i\n", glGetError());
+	}
+
+	return shader;
+}
+
+static GLuint create_program(const char* pVertexSource, const char* pFragmentSource)
+{
+	GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+	if (!vertexShader) {
+		printf("vertex shader not compiled\n");
+		return 0;
+	}
+
+	GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+	if (!pixelShader) {
+		printf("frag shader not compiled\n");
+		return 0;
+	}
+
+	GLuint program = glCreateProgram();
+	if (program) {
+		glAttachShader(program, vertexShader);
+		glAttachShader(program, pixelShader);
+		glLinkProgram(program);
+		GLint linkStatus = GL_FALSE;
+
+		glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+		if (linkStatus != GL_TRUE) {
+			GLint bufLength = 0;
+			glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+			if (bufLength) {
+				char* buf = (char*) malloc(bufLength);
+				if (buf) {
+					glGetProgramInfoLog(program, bufLength, NULL, buf);
+					fprintf(stderr, "Could not link program:\n%s\n", buf);
+					free(buf);
+				}
+			}
+			glDeleteProgram(program);
+			program = 0;
+		}
+	}
+
+	return program;
+}
+
+static int setup_video_texture(struct ClientWithSurface *cs, GLuint *preview_texture_id)
+{
+	assert(cs != NULL);
+	assert(preview_texture_id != NULL);
+
+	sf_surface_make_current(cs->surface);
+
+	glGenTextures(1, preview_texture_id);
+	glClearColor(0, 0, 0, 0);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+	android_media_set_preview_texture(player, *preview_texture_id);
+
+	return 0;
+}
+
+void set_video_size_cb(int height, int width, void *context)
+{
+	printf("Video height: %d, width: %d\n", height, width);
+	printf("Video dest height: %f, width: %f\n", DestHeight, DestWidth);
+
+	Height = height;
+	Width = width;
+}
+
+void media_prepared_cb(void *context)
+{
+	printf("Media is prepared for playback.\n");
+}
+
+int main(int argc, char **argv)
+{
+	if (argc < 2) {
+		printf("Usage: test_media <video_to_play>\n");
+		return EXIT_FAILURE;
+	}
+
+	player = android_media_new_player();
+	if (player == NULL) {
+		printf("Problem creating new media player.\n");
+		return EXIT_FAILURE;
+	}
+
+	// Set player event cb for when the video size is known:
+	android_media_set_video_size_cb(player, set_video_size_cb, NULL);
+	android_media_set_media_prepared_cb(player, media_prepared_cb, NULL);
+
+	printf("Setting data source to: %s.\n", argv[1]);
+
+	if (android_media_set_data_source(player, argv[1]) != OK) {
+		printf("Failed to set data source: %s\n", argv[1]);
+		return EXIT_FAILURE;
+	}
+
+	printf("Creating EGL surface.\n");
+	struct ClientWithSurface cs = client_with_surface(true /* Associate surface with egl. */);
+	if (!cs.surface) {
+		printf("Problem acquiring surface for preview");
+		return EXIT_FAILURE;
+	}
+
+	printf("Creating GL texture.\n");
+
+	GLuint preview_texture_id;
+	EGLDisplay disp = sf_client_get_egl_display(cs.client);
+	EGLSurface surface = sf_surface_get_egl_surface(cs.surface);
+
+	sf_surface_make_current(cs.surface);
+
+	if (setup_video_texture(&cs, &preview_texture_id) != OK) {
+		printf("Problem setting up GL texture for video surface.\n");
+		return EXIT_FAILURE;
+	}
+
+	printf("Starting video playback.\n");
+	android_media_play(player);
+
+	while (android_media_is_playing(player)) {
+		const GLfloat textureCoordinates[] = {
+			1.0f,  1.0f,
+			0.0f,  1.0f,
+			0.0f,  0.0f,
+			1.0f,  0.0f
+		};
+
+		android_media_update_surface_texture(player);
+
+		calculate_position_coordinates();
+
+		gProgram = create_program(vertex_shader(), fragment_shader());
+		gaPositionHandle = glGetAttribLocation(gProgram, "a_position");
+		gaTexHandle = glGetAttribLocation(gProgram, "a_texCoord");
+		gsTextureHandle = glGetUniformLocation(gProgram, "s_texture");
+		gmTexMatrix = glGetUniformLocation(gProgram, "m_texMatrix");
+
+		glClear(GL_COLOR_BUFFER_BIT);
+
+		// Use the program object
+		glUseProgram(gProgram);
+		// Enable attributes
+		glEnableVertexAttribArray(gaPositionHandle);
+		glEnableVertexAttribArray(gaTexHandle);
+		// Load the vertex position
+		glVertexAttribPointer(gaPositionHandle,
+				2,
+				GL_FLOAT,
+				GL_FALSE,
+				0,
+				positionCoordinates);
+		// Load the texture coordinate
+		glVertexAttribPointer(gaTexHandle,
+				2,
+				GL_FLOAT,
+				GL_FALSE,
+				0,
+				textureCoordinates);
+
+		GLfloat matrix[16];
+		android_media_surface_texture_get_transformation_matrix(player, matrix);
+
+		glUniformMatrix4fv(gmTexMatrix, 1, GL_FALSE, matrix);
+
+		glActiveTexture(GL_TEXTURE0);
+		// Set the sampler texture unit to 0
+		glUniform1i(gsTextureHandle, 0);
+		glUniform1i(gmTexMatrix, 0);
+		android_media_update_surface_texture(player);
+		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+		glDisableVertexAttribArray(gaPositionHandle);
+		glDisableVertexAttribArray(gaTexHandle);
+
+		eglSwapBuffers(disp, surface);
+	}
+
+	android_media_stop(player);
+
+	return EXIT_SUCCESS;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_recorder.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ *              Guenter Schwann <guenter.schwann@canonical.com>
+ *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ */
+
+#include <hybris/camera/camera_compatibility_layer.h>
+#include <hybris/camera/camera_compatibility_layer_capabilities.h>
+
+#include <hybris/media/recorder_compatibility_layer.h>
+
+#include <hybris/input/input_stack_compatibility_layer.h>
+#include <hybris/input/input_stack_compatibility_layer_codes_key.h>
+#include <hybris/input/input_stack_compatibility_layer_flags_key.h>
+
+#include <hybris/surface_flinger/surface_flinger_compatibility_layer.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+int shot_counter = 1;
+int32_t current_zoom_level = 1;
+bool new_camera_frame_available = true;
+struct MediaRecorderWrapper *mr = 0;
+GLuint preview_texture_id = 0;
+
+static GLuint gProgram;
+static GLuint gaPositionHandle, gaTexHandle, gsTextureHandle, gmTexMatrix;
+
+void error_msg_cb(void* context)
+{
+	printf("%s \n", __PRETTY_FUNCTION__);
+}
+
+void shutter_msg_cb(void* context)
+{
+	printf("%s \n", __PRETTY_FUNCTION__);
+}
+
+void zoom_msg_cb(void* context, int32_t new_zoom_level)
+{
+	printf("%s \n", __PRETTY_FUNCTION__);
+
+	current_zoom_level = new_zoom_level;
+}
+
+void autofocus_msg_cb(void* context)
+{
+	printf("%s \n", __PRETTY_FUNCTION__);
+}
+
+void raw_data_cb(void* data, uint32_t data_size, void* context)
+{
+	printf("%s: %d \n", __PRETTY_FUNCTION__, data_size);
+}
+
+void jpeg_data_cb(void* data, uint32_t data_size, void* context)
+{
+	printf("%s: %d \n", __PRETTY_FUNCTION__, data_size);
+	struct CameraControl* cc = (struct CameraControl*) context;
+	android_camera_start_preview(cc);
+}
+
+void size_cb(void* ctx, int width, int height)
+{
+	printf("Supported size: [%d,%d]\n", width, height);
+}
+
+void preview_texture_needs_update_cb(void* ctx)
+{
+	new_camera_frame_available = true;
+}
+
+void on_new_input_event(struct Event* event, void* context)
+{
+	assert(context);
+
+	if (event->type == KEY_EVENT_TYPE && event->action == ISCL_KEY_EVENT_ACTION_UP) {
+		printf("We have got a key event: %d \n", event->details.key.key_code);
+
+		struct CameraControl* cc = (struct CameraControl*) context;
+
+		int ret;
+		switch (event->details.key.key_code) {
+		case ISCL_KEYCODE_VOLUME_UP:
+			printf("Starting video recording\n");
+
+			android_camera_unlock(cc);
+
+			ret = android_recorder_setCamera(mr, cc);
+			if (ret < 0) {
+				printf("android_recorder_setCamera() failed\n");
+				return;
+			}
+			//state initial / idle
+			ret = android_recorder_setAudioSource(mr, ANDROID_AUDIO_SOURCE_CAMCORDER);
+			if (ret < 0) {
+				printf("android_recorder_setAudioSource() failed\n");
+				return;
+			}
+			ret = android_recorder_setVideoSource(mr, ANDROID_VIDEO_SOURCE_CAMERA);
+			if (ret < 0) {
+				printf("android_recorder_setVideoSource() failed\n");
+				return;
+			}
+			//state initialized
+			ret = android_recorder_setOutputFormat(mr, ANDROID_OUTPUT_FORMAT_MPEG_4);
+			if (ret < 0) {
+				printf("android_recorder_setOutputFormat() failed\n");
+				return;
+			}
+			//state DataSourceConfigured
+			ret = android_recorder_setAudioEncoder(mr, ANDROID_AUDIO_ENCODER_AAC);
+			if (ret < 0) {
+				printf("android_recorder_setAudioEncoder() failed\n");
+				return;
+			}
+			ret = android_recorder_setVideoEncoder(mr, ANDROID_VIDEO_ENCODER_H264);
+			if (ret < 0) {
+				printf("android_recorder_setVideoEncoder() failed\n");
+				return;
+			}
+
+			int fd;
+			fd = open("/tmp/test_video_recorder.avi", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+			if (fd < 0) {
+				printf("Could not open file for video recording\n");
+				printf("FD: %i\n", fd);
+				return;
+			}
+			ret = android_recorder_setOutputFile(mr, fd);
+			if (ret < 0) {
+				printf("android_recorder_setOutputFile() failed\n");
+				return;
+			}
+
+			ret = android_recorder_setVideoSize(mr, 1280, 720);
+			if (ret < 0) {
+				printf("android_recorder_setVideoSize() failed\n");
+				return;
+			}
+			ret = android_recorder_setVideoFrameRate(mr, 30);
+			if (ret < 0) {
+				printf("android_recorder_setVideoFrameRate() failed\n");
+				return;
+			}
+
+			ret = android_recorder_prepare(mr);
+			if (ret < 0) {
+				printf("android_recorder_prepare() failed\n");
+				return;
+			}
+			//state prepared
+			ret = android_recorder_start(mr);
+			if (ret < 0) {
+				printf("android_recorder_start() failed\n");
+				return;
+			}
+			break;
+		case ISCL_KEYCODE_VOLUME_DOWN:
+			printf("Stoping video recording\n");
+			ret = android_recorder_stop(mr);
+
+			printf("Stoping video recording returned\n");
+			if (ret < 0) {
+				printf("android_recorder_stop() failed\n");
+				return;
+			}
+			printf("Stopped video recording\n");
+			ret = android_recorder_reset(mr);
+			if (ret < 0) {
+				printf("android_recorder_reset() failed\n");
+				return;
+			}
+			printf("Reset video recorder\n");
+			break;
+		}
+	}
+}
+
+struct ClientWithSurface
+{
+	struct SfClient* client;
+	struct SfSurface* surface;
+};
+
+struct ClientWithSurface client_with_surface(bool setup_surface_with_egl)
+{
+	struct ClientWithSurface cs;
+
+	cs.client = sf_client_create();
+
+	if (!cs.client) {
+		printf("Problem creating client ... aborting now.");
+		return cs;
+	}
+
+	static const size_t primary_display = 0;
+
+	SfSurfaceCreationParameters params = {
+		0,
+		0,
+		sf_get_display_width(primary_display),
+		sf_get_display_height(primary_display),
+		-1, //PIXEL_FORMAT_RGBA_8888,
+		15000,
+		0.5f,
+		setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL
+		"CameraCompatLayerTestSurface"
+	};
+
+	cs.surface = sf_surface_create(cs.client, &params);
+
+	if (!cs.surface) {
+		printf("Problem creating surface ... aborting now.");
+		return cs;
+	}
+
+	sf_surface_make_current(cs.surface);
+
+	return cs;
+}
+
+static const char* vertex_shader()
+{
+	return
+		"#extension GL_OES_EGL_image_external : require              \n"
+		"attribute vec4 a_position;                                  \n"
+		"attribute vec2 a_texCoord;                                  \n"
+		"uniform mat4 m_texMatrix;                                   \n"
+		"varying vec2 v_texCoord;                                    \n"
+		"varying float topDown;                                      \n"
+		"void main()                                                 \n"
+		"{                                                           \n"
+		"   gl_Position = a_position;                                \n"
+		"   v_texCoord = a_texCoord;                                 \n"
+		//                "   v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n"
+		//"   topDown = v_texCoord.y;                                  \n"
+		"}                                                           \n";
+}
+
+static const char* fragment_shader()
+{
+	return
+		"#extension GL_OES_EGL_image_external : require      \n"
+		"precision mediump float;                            \n"
+		"varying vec2 v_texCoord;                            \n"
+		"uniform samplerExternalOES s_texture;               \n"
+		"void main()                                         \n"
+		"{                                                   \n"
+		"  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
+		"}                                                   \n";
+}
+
+static GLuint loadShader(GLenum shaderType, const char* pSource) {
+	GLuint shader = glCreateShader(shaderType);
+
+	if (shader) {
+		glShaderSource(shader, 1, &pSource, NULL);
+		glCompileShader(shader);
+		GLint compiled = 0;
+		glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+
+		if (!compiled) {
+			GLint infoLen = 0;
+			glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+			if (infoLen) {
+				char* buf = (char*) malloc(infoLen);
+				if (buf) {
+					glGetShaderInfoLog(shader, infoLen, NULL, buf);
+					fprintf(stderr, "Could not compile shader %d:\n%s\n",
+							shaderType, buf);
+					free(buf);
+				}
+				glDeleteShader(shader);
+				shader = 0;
+			}
+		}
+	} else {
+		printf("Error, during shader creation: %i\n", glGetError());
+	}
+
+	return shader;
+}
+
+static GLuint create_program(const char* pVertexSource, const char* pFragmentSource) {
+	GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+	if (!vertexShader) {
+		printf("vertex shader not compiled\n");
+		return 0;
+	}
+
+	GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+	if (!pixelShader) {
+		printf("frag shader not compiled\n");
+		return 0;
+	}
+
+	GLuint program = glCreateProgram();
+	if (program) {
+		glAttachShader(program, vertexShader);
+		glAttachShader(program, pixelShader);
+		glLinkProgram(program);
+		GLint linkStatus = GL_FALSE;
+
+		glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+		if (linkStatus != GL_TRUE) {
+			GLint bufLength = 0;
+			glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+			if (bufLength) {
+				char* buf = (char*) malloc(bufLength);
+				if (buf) {
+					glGetProgramInfoLog(program, bufLength, NULL, buf);
+					fprintf(stderr, "Could not link program:\n%s\n", buf);
+					free(buf);
+				}
+			}
+			glDeleteProgram(program);
+			program = 0;
+		}
+	}
+
+	return program;
+}
+
+int main(int argc, char** argv)
+{
+	printf("Test application for video recording using the camera\n");
+	printf("Recording start with volume up button. And stops with volume down.\n");
+	printf("The result is stored to /root/test_video.avi\n\n");
+
+	struct CameraControlListener listener;
+	memset(&listener, 0, sizeof(listener));
+	listener.on_msg_error_cb = error_msg_cb;
+	listener.on_msg_shutter_cb = shutter_msg_cb;
+	listener.on_msg_focus_cb = autofocus_msg_cb;
+	listener.on_msg_zoom_cb = zoom_msg_cb;
+
+	listener.on_data_raw_image_cb = raw_data_cb;
+	listener.on_data_compressed_image_cb = jpeg_data_cb;
+	listener.on_preview_texture_needs_update_cb = preview_texture_needs_update_cb;
+	struct CameraControl* cc = android_camera_connect_to(BACK_FACING_CAMERA_TYPE,
+			&listener);
+	if (cc == NULL) {
+		printf("Problem connecting to camera");
+		return 1;
+	}
+
+	listener.context = cc;
+
+	mr = android_media_new_recorder();
+
+	struct AndroidEventListener event_listener;
+	event_listener.on_new_event = on_new_input_event;
+	event_listener.context = cc;
+
+	struct InputStackConfiguration input_configuration = { false, 25000 };
+
+	android_input_stack_initialize(&event_listener, &input_configuration);
+	android_input_stack_start();
+
+	android_camera_dump_parameters(cc);
+
+	printf("Supported video sizes:\n");
+	android_camera_enumerate_supported_video_sizes(cc, size_cb, NULL);
+
+	android_camera_set_preview_size(cc, 1280, 720);
+
+	int width, height;
+	android_camera_get_video_size(cc, &width, &height);
+	printf("Current video size: [%d,%d]\n", width, height);
+
+	struct ClientWithSurface cs = client_with_surface(true /* Associate surface with egl. */);
+
+	if (!cs.surface) {
+		printf("Problem acquiring surface for preview");
+		return 1;
+	}
+
+	EGLDisplay disp = sf_client_get_egl_display(cs.client);
+	EGLSurface surface = sf_surface_get_egl_surface(cs.surface);
+
+	sf_surface_make_current(cs.surface);
+
+	gProgram = create_program(vertex_shader(), fragment_shader());
+	gaPositionHandle = glGetAttribLocation(gProgram, "a_position");
+	gaTexHandle = glGetAttribLocation(gProgram, "a_texCoord");
+	gsTextureHandle = glGetUniformLocation(gProgram, "s_texture");
+	gmTexMatrix = glGetUniformLocation(gProgram, "m_texMatrix");
+
+	glGenTextures(1, &preview_texture_id);
+	glClearColor(1.0, 0., 0.5, 1.);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri(
+			GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(
+			GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	android_camera_set_preview_texture(cc, preview_texture_id);
+	android_camera_start_preview(cc);
+
+	GLfloat transformation_matrix[16];
+	android_camera_get_preview_texture_transformation(cc, transformation_matrix);
+	glUniformMatrix4fv(gmTexMatrix, 1, GL_FALSE, transformation_matrix);
+
+	printf("Started camera preview.\n");
+
+	while (true) {
+		/*if (new_camera_frame_available)
+		  {
+		  printf("Updating texture");
+		  new_camera_frame_available = false;
+		  }*/
+		static GLfloat vVertices[] = { 0.0f, 0.0f, 0.0f, // Position 0
+			0.0f, 0.0f, // TexCoord 0
+			0.0f, 1.0f, 0.0f, // Position 1
+			0.0f, 1.0f, // TexCoord 1
+			1.0f, 1.0f, 0.0f, // Position 2
+			1.0f, 1.0f, // TexCoord 2
+			1.0f, 0.0f, 0.0f, // Position 3
+			1.0f, 0.0f // TexCoord 3
+		};
+
+		GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+		// Set the viewport
+		// Clear the color buffer
+		glClear(GL_COLOR_BUFFER_BIT);
+		// Use the program object
+		glUseProgram(gProgram);
+		// Enable attributes
+		glEnableVertexAttribArray(gaPositionHandle);
+		glEnableVertexAttribArray(gaTexHandle);
+		// Load the vertex position
+		glVertexAttribPointer(gaPositionHandle,
+				3,
+				GL_FLOAT,
+				GL_FALSE,
+				5 * sizeof(GLfloat),
+				vVertices);
+		// Load the texture coordinate
+		glVertexAttribPointer(gaTexHandle,
+				2,
+				GL_FLOAT,
+				GL_FALSE,
+				5 * sizeof(GLfloat),
+				vVertices+3);
+
+		glActiveTexture(GL_TEXTURE0);
+		// Set the sampler texture unit to 0
+		glUniform1i(gsTextureHandle, 0);
+		glUniform1i(gmTexMatrix, 0);
+		android_camera_update_preview_texture(cc);
+		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+		glDisableVertexAttribArray(gaPositionHandle);
+		glDisableVertexAttribArray(gaTexHandle);
+
+		eglSwapBuffers(disp, surface);
+	}
+}
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/tests/test_sensors.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_sensors.c
@@ -19,6 +19,7 @@
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <hardware/sensors.h>
 
 static void process_event(sensors_event_t *data)
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/tests/test_ui.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_ui.c
@@ -53,8 +53,10 @@ int main(int argc, char **argv)
 	graphic_buffer_lock(buffer, GRALLOC_USAGE_HW_RENDER, &vaddr);
 	graphic_buffer_unlock(buffer);
 
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
 	graphic_buffer_set_index(buffer, 11);
 	assert(graphic_buffer_get_index(buffer) == 11);
+#endif
 
 	graphic_buffer_free(buffer);
 
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_wifi.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014 Canonical Ltd
+ *
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <android-config.h>
+#include <hardware_legacy/wifi.h>
+
+#define COMMAND_LOAD_WIFI "1"
+#define COMMAND_UNLOAD_WIFI "0"
+
+int main(int argc, char **argv)
+{
+	if (argc < 2) {
+		fprintf(stdout, "To load driver: %s " COMMAND_LOAD_WIFI "\n", argv[0]);
+		fprintf(stdout, "To unload driver: %s " COMMAND_UNLOAD_WIFI "\n", argv[0]);
+	} else {
+		int ret;
+
+		if (strcmp(argv[1], COMMAND_LOAD_WIFI) == 0) {
+			if ((ret = wifi_load_driver()) < 0)
+				fprintf(stderr, "Cannot load driver (err %d)\n", ret);
+			else
+				fprintf(stdout, "Driver loaded\n");
+		} else if (strcmp(argv[1], COMMAND_UNLOAD_WIFI) == 0) {
+			if ((ret = wifi_unload_driver()) < 0)
+				fprintf(stderr, "Cannot unload driver (err %d)\n", ret);
+			else
+				fprintf(stdout, "Driver unloaded\n");
+		} else {
+			fprintf(stderr, "Wrong command\n");
+			return 1;
+		}
+	}
+
+	fprintf(stdout, "WiFi driver load state: %d\n", is_wifi_driver_loaded());
+
+	return 0;
+}
+
+// vim:ts=4:sw=4:noexpandtab
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/ui/ui.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/ui/ui.c
@@ -20,7 +20,7 @@
 #include <hybris/common/binding.h>
 #include <hybris/ui/ui_compatibility_layer.h>
 
-#define COMPAT_LIBRARY_PATH		"/system/lib/libui_compat_layer.so"
+#define COMPAT_LIBRARY_PATH		"libui_compat_layer.so"
 
 HYBRIS_LIBRARY_INITIALIZE(ui, COMPAT_LIBRARY_PATH);
 
@@ -48,9 +48,11 @@ HYBRIS_IMPLEMENT_FUNCTION1(ui, uint32_t,
 	struct graphic_buffer*);
 HYBRIS_IMPLEMENT_FUNCTION1(ui, void*, graphic_buffer_get_native_buffer,
 	struct graphic_buffer*);
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(ui, graphic_buffer_set_index,
 	struct graphic_buffer*, int);
 HYBRIS_IMPLEMENT_FUNCTION1(ui, int, graphic_buffer_get_index,
 	struct graphic_buffer*);
+#endif
 HYBRIS_IMPLEMENT_FUNCTION1(ui, int, graphic_buffer_init_check,
 	struct graphic_buffer*);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/utils/getprop.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/utils/getprop.c
@@ -55,8 +55,6 @@ static void list_properties(void)
 
 int main(int argc, char *argv[])
 {
-	int n = 0;
-
 	if (argc == 1) {
 		list_properties();
 	} else {
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/vibrator/vibrator.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/vibrator/vibrator.c
@@ -22,7 +22,7 @@
 
 #include <hybris/common/binding.h>
 
-HYBRIS_LIBRARY_INITIALIZE(vibrator, "/system/lib/libhardware_legacy.so");
+HYBRIS_LIBRARY_INITIALIZE(vibrator, "libhardware_legacy.so");
 
 HYBRIS_IMPLEMENT_FUNCTION0(vibrator, int, vibrator_exists);
 HYBRIS_IMPLEMENT_FUNCTION1(vibrator, int, vibrator_on, int);
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/wifi/Makefile.am
@@ -0,0 +1,17 @@
+lib_LTLIBRARIES = \
+	libwifi.la
+
+libwifi_la_SOURCES = wifi.c
+libwifi_la_CFLAGS = -I$(top_srcdir)/include
+if WANT_TRACE
+libwifi_la_CFLAGS += -DDEBUG
+endif
+if WANT_DEBUG
+libwifi_la_CFLAGS += -ggdb -O0
+endif
+libwifi_la_LDFLAGS = \
+	$(top_builddir)/common/libhybris-common.la \
+	-version-info "1":"0":"0"
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libwifi.pc
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/wifi/libwifi.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=@libdir@
+includedir=@includedir@
+
+Name: hybris-wifi
+Description: libhybris wifi library
+Version: @VERSION@
+Libs: -L${libdir} -lhybris-common -lwifi
+Cflags: -I${includedir}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/wifi/wifi.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * 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.
+ *
+ * Authored by: Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com>
+ */
+
+#include <dlfcn.h>
+#include <stddef.h>
+
+#include <hybris/common/binding.h>
+#include <hardware_legacy/wifi.h>
+
+#define COMPAT_LIBRARY_PATH "libhardware_legacy.so"
+
+HYBRIS_LIBRARY_INITIALIZE(wifi, COMPAT_LIBRARY_PATH);
+
+int wifi_compat_check_availability()
+{
+    /* Both are defined via HYBRIS_LIBRARY_INITIALIZE */
+    hybris_wifi_initialize();
+    return wifi_handle ? 1 : 0;
+}
+
+HYBRIS_IMPLEMENT_FUNCTION0(wifi, int, wifi_load_driver);
+HYBRIS_IMPLEMENT_FUNCTION0(wifi, int, wifi_unload_driver);
+HYBRIS_IMPLEMENT_FUNCTION0(wifi, int, is_wifi_driver_loaded);
+HYBRIS_IMPLEMENT_FUNCTION1(wifi, int, wifi_start_supplicant, int);
+HYBRIS_IMPLEMENT_FUNCTION1(wifi, int, wifi_stop_supplicant, int);
+HYBRIS_IMPLEMENT_FUNCTION0(wifi, int, wifi_connect_to_supplicant);
+HYBRIS_IMPLEMENT_VOID_FUNCTION0(wifi, wifi_close_supplicant_connection);
+HYBRIS_IMPLEMENT_FUNCTION2(wifi, int, wifi_wait_for_event, char *, size_t);
+HYBRIS_IMPLEMENT_FUNCTION3(wifi, int, wifi_command,
+				const char *, char *, size_t *);
+HYBRIS_IMPLEMENT_FUNCTION7(wifi, int, do_dhcp_request, int *, int *, int *,
+				int *, int *, int *, int *);
+HYBRIS_IMPLEMENT_FUNCTION0(wifi, const char *, get_dhcp_error_string);
+HYBRIS_IMPLEMENT_FUNCTION1(wifi, const char *, wifi_get_fw_path, int);
+HYBRIS_IMPLEMENT_FUNCTION1(wifi, int, wifi_change_fw_path, const char *);
+HYBRIS_IMPLEMENT_FUNCTION0(wifi, int, ensure_entropy_file_exists);
+HYBRIS_IMPLEMENT_FUNCTION4(wifi, int, wifi_send_driver_command,
+				char*, char*, char*, size_t);
--- libhybris-0.1.0+git20151016+6d424c9.orig/utils/generate_wrapper_macros.py
+++ libhybris-0.1.0+git20151016+6d424c9/utils/generate_wrapper_macros.py
@@ -104,6 +104,12 @@ print """
         name##_handle = android_dlopen(path, RTLD_LAZY); \\
     }
 
+#define HYBRIS_LIRBARY_CHECK_SYMBOL(name) \\
+    bool hybris_##name##_check_for_symbol(const char *sym) \\
+    { \\
+        return android_dlsym(name##_handle, sym) != NULL; \\
+    }
+
 """
 
 for count in range(MAX_ARGS):
--- libhybris-0.1.0+git20151016+6d424c9.orig/utils/load_sym_files.py
+++ libhybris-0.1.0+git20151016+6d424c9/utils/load_sym_files.py
@@ -37,19 +37,22 @@ class LoadSymFiles(gdb.Command):
         symdir = "/system/symbols"
         libdir = "/system/lib"
 
-        if len(arg_list) == 1:
+        if len(arg_list) >= 1:
             symdir = arg_list[0]
+
         if not os.path.isdir(symdir):
-            print "error: invalid symbol directory(%s)"%symdir
-            print "usage: load-sym-files [symbols-dir] [lib-dir]"
+            print("error: invalid symbol directory '%s'" % symdir)
+            print("usage: load-sym-files [symbols-dir] [lib-dir]")
             return
 
         if len(arg_list) == 2:
             libdir = arg_list[1]
+
         if not os.path.isdir(libdir):
-            print "error: invalid library directory(%s)"%libdir
-            print "usage: load-sym-files [symbols-dir] [lib-dir]"
+            print("error: invalid library directory '%s'" % libdir)
+            print("usage: load-sym-files [symbols-dir] [lib-dir]")
             return
+
         try:
             pid = gdb.selected_inferior().pid
         except AttributeError:
@@ -59,34 +62,38 @@ class LoadSymFiles(gdb.Command):
             if len(gdb.inferiors()) == 1:
                 pid = gdb.inferiors()[0].pid
             else:
-                print "error: no gdb support for more than 1 inferior"
+                print("error: no gdb support for more than 1 inferior")
                 return
 
         if pid == 0:
-            print "error: debugee not started yet"
+            print("error: debugee not started yet")
             return
 
         maps = open("/proc/%d/maps"%pid,"rb")
         for line in maps:
             # b7fc9000-b7fcf000 r-xp 00000000 08:01 1311443    /system/lib/liblog.so
-            m = re.match("([0-9A-Fa-f]+)-[0-9A-Fa-f]+\s+r-xp.*(%s.*)"%libdir,line)
+            # m = re.match("([0-9A-Fa-f]+)-[0-9A-Fa-f]+\s+r-xp.*(%s.*)" % libdir, str(line))
+            m = re.match("([0-9A-Fa-f]+)-[0-9A-Fa-f]+\sr-xp\s.*\s(.*)\\n", line.decode('ascii'))
             if not m:
                 continue
 
-            start_addr = int(m.group(1),16)
+            start_addr = int(m.group(1), 16)
             lib        = m.group(2)
             text_addr  = 0
 
-            p = subprocess.Popen("objdump -h "+lib , shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
-            for header in  p.stdout.read().split("\n"):
+            if not lib.startswith(libdir):
+                continue
+
+            p = subprocess.Popen("objdump -h " + lib , shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+            for header in p.stdout.read().decode('ascii').split("\n"):
                 #6 .text         00044ef7  00017f80  00017f80  00017f80  2**4
-                t = re.match("\s*[0-9]+\s+\.text\s+([0-9A-Fa-f]+\s+){3}([0-9A-Fa-f]+)",header)
+                t = re.match("\s*[0-9]+\s+\.text\s+([0-9A-Fa-f]+\s+){3}([0-9A-Fa-f]+)", header)
                 if t:
                     text_addr = int(t.group(2),16)
                     break
+
             symfile = symdir + lib
             if os.path.isfile(symfile):
                 gdb.execute("add-symbol-file %s 0x%X" % (symfile, start_addr+text_addr))
 
-
 LoadSymFiles()
